pax_global_header00006660000000000000000000000064141512050300014501gustar00rootroot0000000000000052 comment=41cb3bfe820ba47b41c8b3adf360bfac4b306b10 crystal-facet-uml-1.34.1/000077500000000000000000000000001415120503000151235ustar00rootroot00000000000000crystal-facet-uml-1.34.1/.gitignore000066400000000000000000000001441415120503000171120ustar00rootroot00000000000000# do not report untraced files in the build directory: /build/ # ignore temporary swap files: *.swp crystal-facet-uml-1.34.1/CMakeLists.txt000066400000000000000000000170301415120503000176640ustar00rootroot00000000000000PROJECT(crystal-facet-uml LANGUAGES C) CMAKE_MINIMUM_REQUIRED(VERSION 3.0) #helper to find include directories and libraries: FIND_PACKAGE(PkgConfig REQUIRED) # ==== ==== ==== ==== ==== ==== ==== ==== Build Environment Settings ==== ==== ==== ==== ==== ==== ==== ==== SET(COMPILE_IN_INCLUDE_DIR "" CACHE FILEPATH "Path to additional include directory") SET(COMPILE_IN_SOURCE_FILE "" CACHE FILEPATH "Path to additional source file, e.g. sqlite3.c") INCLUDE_DIRECTORIES(${COMPILE_IN_INCLUDE_DIR}) # crystal-facet-uml INCLUDE_DIRECTORIES(gui/include) INCLUDE_DIRECTORIES(main/include) INCLUDE_DIRECTORIES(tslog/include) INCLUDE_DIRECTORIES(trace/include) INCLUDE_DIRECTORIES(ctrl/include) INCLUDE_DIRECTORIES(data/include) INCLUDE_DIRECTORIES(utf8stringbuf/include) INCLUDE_DIRECTORIES(pencil/include) INCLUDE_DIRECTORIES(io/include) INCLUDE_DIRECTORIES(universal/include) #sqlite3 dependencies PKG_SEARCH_MODULE(SQLITE3 REQUIRED sqlite3) INCLUDE_DIRECTORIES(${SQLITE3_INCLUDE_DIRS}) #MESSAGE("SQLITE3: ${SQLITE3_INCLUDE_DIRS}") #gtk3 dependencies PKG_SEARCH_MODULE(GLIB2 REQUIRED glib-2.0) INCLUDE_DIRECTORIES(${GLIB2_INCLUDE_DIRS}) #MESSAGE("GLIB2: ${GLIB2_INCLUDE_DIRS}") PKG_SEARCH_MODULE(GTK3 REQUIRED gtk+-3.0) INCLUDE_DIRECTORIES(${GTK3_INCLUDE_DIRS}) #MESSAGE("GTK3: ${GTK3_INCLUDE_DIRS}") #MESSAGE("GTK3: ${GTK3_FOUND}") #MESSAGE("GTK3: ${GTK3_LIBRARIES}") #MESSAGE("GTK3: ${GTK3_LIBRARY_DIRS}") #MESSAGE("GTK3: ${GTK3_LDFLAGS}") #MESSAGE("GTK3: ${GTK3_LDFLAGS_OTHER}") #MESSAGE("GTK3: ${GTK3_CFLAGS}") #MESSAGE("GTK3: ${GTK3_CFLAGS_OTHER}") PKG_SEARCH_MODULE(PANGOCAIRO REQUIRED pangocairo) INCLUDE_DIRECTORIES(${PANGOCAIRO_INCLUDE_DIRS}) #MESSAGE("PANGOCAIRO: ${PANGOCAIRO_INCLUDE_DIRS}") FILE(GLOB commonSource gui/source/*.c gui/source/sketch_area/*.c trace/source/*.c ctrl/source/*.c data/source/*.c data/source/storage/*.c data/source/set/*.c utf8stringbuf/source/util/string/*.c universal/source/*.c universal/source/stream/*.c pencil/source/*.c pencil/source/util/geometry/*.c pencil/source/draw/*.c io/source/*.c io/source/image/*.c io/source/json/*.c io/source/xml/*.c io/source/txt/*.c io/source/xhtml/*.c io/source/xmi/*.c io/source/md/*.c) FILE(GLOB appSource main/source/*.c) FILE(GLOB utestSource main/test/*.c data/test/unit/*.c data/test/integration/*.c ctrl/test/unit/*.c ctrl/test/integration/*.c gui/test/unit/*.c io/test/unit/*.c io/test/integration/*.c pencil/test/unit/*.c pencil/test/integration/*.c universal/test/unit/*.c utf8stringbuf/test/unit/*.c) # ==== ==== ==== ==== ==== ==== ==== ==== Check if CMAKE_BUILD_TYPE is set ==== ==== ==== ==== ==== ==== ==== ==== IF(NOT CMAKE_BUILD_TYPE) MESSAGE( "Warn: CMAKE_BUILD_TYPE no set! setting(CMAKE_BUILD_TYPE \"Release\")") SET(CMAKE_BUILD_TYPE "Release") ENDIF(NOT CMAKE_BUILD_TYPE) MESSAGE( "Note: CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}" ) MESSAGE( "Note: to build a release, run cmake -DCMAKE_BUILD_TYPE=Release " ${CMAKE_CURRENT_SOURCE_DIR} ) MESSAGE( "Note: to build with asserts and traces, run cmake -DCMAKE_BUILD_TYPE=Debug " ${CMAKE_CURRENT_SOURCE_DIR} ) # ==== ==== ==== ==== ==== ==== ==== ==== Common Settings ==== ==== ==== ==== ==== ==== ==== ==== SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_XOPEN_SOURCE=700 -O2 -pedantic -g -Wall -Wno-overlength-strings ${GTK3_CFLAGS_OTHER}" ) # Note: The GIMP-generated images are longer that 4095 characters, therefore -Wno-overlength-strings is required here. # ==== ==== ==== ==== ==== ==== ==== ==== EXE Target Settings ==== ==== ==== ==== ==== ==== ==== ==== ADD_EXECUTABLE(crystal-facet-uml ${appSource} ${commonSource} ${COMPILE_IN_SOURCE_FILE}) TARGET_LINK_LIBRARIES(crystal-facet-uml ${GTK3_LIBRARIES} ${GLIB2_LIBRARIES} ${PANGOCAIRO_LIBRARIES} ${SQLITE3_LIBRARIES} m) SET_TARGET_PROPERTIES(crystal-facet-uml PROPERTIES LINKER_LANGUAGE C) # ==== ==== ==== ==== ==== ==== ==== ==== test Target Settings ==== ==== ==== ==== ==== ==== ==== ==== ADD_EXECUTABLE(test_crystal-facet-uml ${utestSource} ${commonSource} ${COMPILE_IN_SOURCE_FILE}) TARGET_INCLUDE_DIRECTORIES(test_crystal-facet-uml PUBLIC test_fw/include) TARGET_INCLUDE_DIRECTORIES(test_crystal-facet-uml PUBLIC data/test) TARGET_INCLUDE_DIRECTORIES(test_crystal-facet-uml PUBLIC ctrl/test) TARGET_INCLUDE_DIRECTORIES(test_crystal-facet-uml PUBLIC gui/test) TARGET_INCLUDE_DIRECTORIES(test_crystal-facet-uml PUBLIC io/test) TARGET_INCLUDE_DIRECTORIES(test_crystal-facet-uml PUBLIC pencil/test) TARGET_INCLUDE_DIRECTORIES(test_crystal-facet-uml PUBLIC universal/test) TARGET_INCLUDE_DIRECTORIES(test_crystal-facet-uml PUBLIC utf8stringbuf/test) TARGET_LINK_LIBRARIES(test_crystal-facet-uml ${GTK3_LIBRARIES} ${GLIB2_LIBRARIES} ${PANGOCAIRO_LIBRARIES} ${SQLITE3_LIBRARIES} m) SET_TARGET_PROPERTIES(test_crystal-facet-uml PROPERTIES LINKER_LANGUAGE C) # ==== ==== ==== ==== ==== ==== ==== ==== Install Settings ==== ==== ==== ==== ==== ==== ==== ==== INSTALL(TARGETS crystal-facet-uml DESTINATION "/usr/bin/") INSTALL(FILES "${CMAKE_CURRENT_SOURCE_DIR}/installation_linux/crystal-facet-uml.desktop" DESTINATION "/usr/share/applications/") INSTALL(FILES "${CMAKE_CURRENT_SOURCE_DIR}/installation_linux/crystal-facet-uml.metainfo.xml" DESTINATION "/usr/share/metainfo/") INSTALL(FILES "${CMAKE_CURRENT_SOURCE_DIR}/gui/source/resources/crystal_facet_uml_80x80.png" DESTINATION "/usr/share/pixmaps/" RENAME "crystal-facet-uml.png") INSTALL(FILES "${CMAKE_CURRENT_SOURCE_DIR}/user_doc/crystal-facet-uml.1.gz" DESTINATION "/usr/share/man/man1/") # ==== ==== ==== ==== ==== ==== ==== ==== gcov Target Settings ==== ==== ==== ==== ==== ==== ==== ==== if(CFU_ADD_GCOV_TARGET) if(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage" ) SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs" ) ADD_EXECUTABLE(gcov_crystal-facet-uml ${utestSource} ${commonSource} ${COMPILE_IN_SOURCE_FILE}) TARGET_INCLUDE_DIRECTORIES(gcov_crystal-facet-uml PUBLIC test_fw/include) TARGET_INCLUDE_DIRECTORIES(gcov_crystal-facet-uml PUBLIC data/test) TARGET_INCLUDE_DIRECTORIES(gcov_crystal-facet-uml PUBLIC ctrl/test) TARGET_INCLUDE_DIRECTORIES(gcov_crystal-facet-uml PUBLIC gui/test) TARGET_INCLUDE_DIRECTORIES(gcov_crystal-facet-uml PUBLIC io/test) TARGET_INCLUDE_DIRECTORIES(gcov_crystal-facet-uml PUBLIC pencil/test) TARGET_INCLUDE_DIRECTORIES(gcov_crystal-facet-uml PUBLIC universal/test) TARGET_INCLUDE_DIRECTORIES(gcov_crystal-facet-uml PUBLIC utf8stringbuf/test) TARGET_LINK_LIBRARIES(gcov_crystal-facet-uml ${GTK3_LIBRARIES} ${GLIB2_LIBRARIES} ${PANGOCAIRO_LIBRARIES} ${SQLITE3_LIBRARIES} m) SET_TARGET_PROPERTIES(gcov_crystal-facet-uml PROPERTIES LINKER_LANGUAGE C) SET_TARGET_PROPERTIES(gcov_crystal-facet-uml PROPERTIES EXCLUDE_FROM_ALL TRUE) endif(CMAKE_COMPILER_IS_GNUCC) endif(CFU_ADD_GCOV_TARGET) crystal-facet-uml-1.34.1/ChangeLog000066400000000000000000000717371415120503000167140ustar00rootroot00000000000000crystal-facet-uml (1.34.1) UNRELEASED; urgency=medium [ Andreas Warnke ] * no error if gtk_init_check fails - otherwise tests would fail -- Andreas Warnke Mon, 29 Nov 2021 20:00:00 +0200 crystal-facet-uml (1.34.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * export in json format contains also uuids as links (for auto-merging) * export in json format nicer for humans to read (for diff and merge) * export in json format contains also lifelines -- Andreas Warnke Sun, 28 Nov 2021 21:00:00 +0200 crystal-facet-uml (1.33.1) UNRELEASED; urgency=medium [ Andreas Warnke ] * fix: When cutting a diagram, one can immediately paste it to the previous position; also paste it immediately after opening a new db. * Layouting of lines prefers connector types Z over S, N over L7 -- Andreas Warnke Sat, 23 Oct 2021 18:00:00 +0200 crystal-facet-uml (1.33.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * The database has new fields uuid and diagram.display_flags * fix: when copying objects via clipboard, the last characters are not dropped if escape-sequences cause exceeding maximum string length * json export (experimental) -- Andreas Warnke Sat, 16 Oct 2021 08:00:00 +0200 crystal-facet-uml (1.32.1) UNRELEASED; urgency=medium [ Andreas Warnke ] * test_expand_space is now more robust against unexpected installed fonts -- Andreas Warnke Sun, 29 Aug 2021 19:00:00 +0200 crystal-facet-uml (1.32.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * overlaps between relationships with identical type, source and destination are avoided. * good default size of classifiers in case classifiers share same location * less overlaps to labels below actor, fork/join, start/end, h, time * nicer relationships to comments and requirements in sequences and timing -- Andreas Warnke Sun, 29 Aug 2021 16:00:00 +0200 crystal-facet-uml (1.31.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * component titles do not touch the type icon anymore * icon alignment in classifiers is not rounded to int anymore * use case circles do not cut into label texts * decision/choice rhombus do not cut into label texts * send signal arrows do not cut into label texts * accept event flags do not cut into label texts -- Andreas Warnke Sat, 31 Jul 2021 16:00:00 +0200 crystal-facet-uml (1.30.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * in search mode, objects are highlighted individually (not all per diagram) * in search result list, long names have nice linebreaks * in navigation tree, long names have nice linebreaks * Guillements characters surround stereoptypes -- Andreas Warnke Sat, 05 Jun 2021 08:00:00 +0200 crystal-facet-uml (1.29.1) UNRELEASED; urgency=medium [ Andreas Warnke ] * newly created classifiers are placed to clicked location (bugfix, bug introduced on Fri Mar 26, affecting v1.28.0 and v1.29.0) -- Andreas Warnke Sun, 02 May 2021 16:00:00 +0200 crystal-facet-uml (1.29.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * return arrows in sequences have filled arrow tips, distinguishable from dependencies * stereotypes are xmi-exported to LocalProfile namespace * valuetypes are xmi-exported to DataTypes * merainfo.xml references homepage which is now tls/https authenticated * nav-tree and search result lists draw a bit more space around texts * A white line is drawn around highlighted diagrams (additional to green marker) -- Andreas Warnke Sat, 01 May 2021 22:00:00 +0200 crystal-facet-uml (1.28.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * gcov target is only build if -DCFU_ADD_GCOV_TARGET=ON (Closes: #983836) * test coverage on pencil package increased * exporting image-file types shows statistics on exported elements * list layout improved, golden ratio is applied * timing and sequence diagram layouting improved; special handling for comments/reqs in timing and sequence diagrams * version compatibility also in debug mode: newer database-files can be opened with older programs; asserts removed * Messages are not cut off after 255 characters (511 now) * When resetting selection, diagram is redrawn -- Andreas Warnke Fri, 02 Apr 2021 08:00:00 +0200 crystal-facet-uml (1.27.3) UNRELEASED; urgency=medium [ Andreas Warnke ] * fixed most metainfo.xml warnings * build target for gcov measurement added * auto-delete relationships between classifiers that have no common diagram * when opening the second database, view switches back to navigation mode * when opening the second database, search entry field is cleared * when opening the second database, set of marked elements is cleared * search result view is updated when changing the database (e.g. by undo) * search result view stays when database update is triggered by a 2nd window * when clicking on a search result, the element is focused -- Andreas Warnke Tue, 09 Feb 2021 21:30:00 +0100 crystal-facet-uml (1.27.2) UNRELEASED; urgency=medium [ Andreas Warnke ] * compiler switch Werror removed; warnings should not cause build-breaks -- Andreas Warnke Sun, 03 Jan 2021 15:00:00 +0100 crystal-facet-uml (1.27.1) UNRELEASED; urgency=medium [ Andreas Warnke ] * compiler warning fixed: conversions from unsigned int to size_t explicit -- Andreas Warnke Sun, 03 Jan 2021 09:00:00 +0100 crystal-facet-uml (1.27.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * Tx/Rx for component ports and activity pins introduced * control flow pseudostate for state entry and state exit added * risk of nullpointer errors reduced when opening new db with old program * test case added to check for upwards compatibility of types at xmi export * XMI Export: use cases have uml:ExtensionPoints now * XMI Export: Requirement property base_Class renamed to base_NamedElement * notifying user if trying to change a read-only database file * in create mode, the mouse-tip-icon changes depending on users options * redesign of marker-icons for focused and selected elements -- Andreas Warnke Sat, 02 Jan 2021 19:00:00 +0100 crystal-facet-uml (1.26.1) UNRELEASED; urgency=medium [ Andreas Warnke ] * XMI Export: destination end of messages had fix enclosingInteraction=90001 * XMI Export: Properties have attributes class and interface if applicable * XMI Export: Warnings are issued at illegal relationship end types * XMI Export: dependencies of comments to annotatedElements conform to spec * XMI Export: associations and communication paths can connect to ports * XMI Export: nested activities are exported as StructuredActivityNode * icons beautified * program renamed from crystal_facet_uml to crystal-facet-uml -- Andreas Warnke Sat, 19 Dec 2020 21:30:00 +0100 crystal-facet-uml (1.26.0) UNRELEASED; urgency=medium [ Olaf Hering ] * CMakeLists adapted to find pangocairo (Closes: #2) [ Mike Gabriel ] * Grammar fixes in applicatenclosingInteractionion messages [ Andreas Warnke ] * xmi export exports sequence, timing, communication and interaction overview * xmi export creates property-elements at association-member-ends * system boundary renamed to subsystem (to match uml 2.5.1 spec) * The default relationship type between lifelines is a synchronous call -- Andreas Warnke Sun, 22 Nov 2020 16:30:00 +0100 crystal-facet-uml (1.25.1) UNRELEASED; urgency=medium [ Andreas Warnke ] * cmake does not depend on c++ compiler anymore -- Andreas Warnke Thu, 29 Oct 2020 20:30:00 +0100 crystal-facet-uml (1.25.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * moving ports follow the cursor more accurate * Constraint Blocks show their ports completely inside * Artifacts and Components do not waste space for contained children * Comment titles do not overlap with the comment-corner * packages containing children display their title in the tab-symbol * layouting containments does not reserve columns/rows for the container * Feature/Composite Requirement does not exist anymore, data from older versions is auto-converted to Requirement * Requirements are displyed as box-with-label omitting the description * Interaction Overview Diagram is redesigned, data from older versions is auto-converted to Activity Diagram -- Andreas Warnke Sun, 18 Oct 2020 20:30:00 +0200 crystal-facet-uml (1.24.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * XMI(TM) export reflects containment-hierarcy of elements * XMI(TM) export automatically disambiguates between activity/state contexts * warnings are printed to xml export if model is not uml compliant * no arrow tip at communication path * export shows statistics on diagrams or classifiers * internal: messages to user user are typesafe for their parameters -- Andreas Warnke Thu, 08 Oct 2020 20:30:00 +0200 crystal-facet-uml (1.23.1) UNRELEASED; urgency=medium [ Andreas Warnke ] * XMI(TM) export good enough to be checked by NIST validator -- Andreas Warnke Sun, 06 Sep 2020 11:30:00 +0200 crystal-facet-uml (1.23.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * at operations cut, copy, paste and delete: print understandable statistics * at operations undo, redo: print understandable statistics * layouting of classifiers improved * experimental xmi export -- Andreas Warnke Mon, 15 Jun 2020 11:30:00 +0200 crystal-facet-uml (1.22.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * the xhtml export produces a table-of-contents * the xhtml+db exports generate links to diagrams by D0001#name. * the element configuration area on the right does not take space needed by the drawing area * yellow highlighted names are drawn behind the classifier-contour-line -- Andreas Warnke Fri, 01 May 2020 17:30:00 +0200 crystal-facet-uml (1.21.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * containers embrace their children keeping wider gaps -- Andreas Warnke Sun, 12 Apr 2020 16:30:00 +0200 crystal-facet-uml (1.20.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * xhtml output generates a css file to allow defining own color schemes * xhtml output keeps linebreaks in selected (md) cases * bugfix: exporting docbook and xhtml via command line arguments works again, as in 1.16.1 (Closes: #1) * exported xhtml passes https://validator.w3.org/check (for quality.cfu1) * exported xhtml/css shows chapter numbers -- Andreas Warnke Mon, 23 Mar 2020 18:30:00 +0100 crystal-facet-uml (1.19.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * free text search * small memory leak in nav-tree-view fixed -- Andreas Warnke Sat, 14 Mar 2020 12:30:00 +0100 crystal-facet-uml (1.18.2) UNRELEASED; urgency=medium [ Andreas Warnke ] * internal: utf8 handling is limited to 21 bits (0-0x10ffff) (2003 standard) * internal: all error codes are positive bitmasks now * text entry reworked to not loose entered text at remote-xserver usage * name entry is immediately possible after object creation -- Andreas Warnke Mon, 03 Feb 2020 21:30:00 +0100 crystal-facet-uml (1.18.1) UNRELEASED; urgency=medium [ Andreas Warnke ] * when exporting xhtml and docbook files, windows pathnames are supported -- Andreas Warnke Mon, 20 Jan 2020 21:30:00 +0100 crystal-facet-uml (1.18.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * the search view allows one to search for object ids * bugfix: when changing type of an object, lastest changes to name or description are not lost * pressing enter in name or stereotype field causes a save action -- Andreas Warnke Sun, 19 Jan 2020 20:30:00 +0100 crystal-facet-uml (1.17.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * cmake build config is less platform dependent * nav-tree: dragging diagrams shows a tree-depth aware insert line * while dragging, grid lines are displayed * the description text-view has scrollbars * in nav view, a click into the current diagram zooms to edit mode * in create view, an icon next to the mouse cursor shows options * fix: type dropdown box does not change DB automatically if unknown type id * the type drop down box shows icons to faster find the right type * an icon grid allows one to change types quickly -- Andreas Warnke Sun, 05 Jan 2020 20:30:00 +0100 crystal-facet-uml (1.16.2) UNRELEASED; urgency=medium [ Andreas Warnke ] * relationships may overlap if same type and same direction * title and filename of exported docbook and xhtml equals database file name -- Andreas Warnke Sun, 08 Dec 2019 11:30:00 +0100 crystal-facet-uml (1.16.1) UNRELEASED; urgency=medium [ Andreas Warnke ] * rpm package build scripts beautified, doc installation excluded from cmake -- Andreas Warnke Tue, 26 Nov 2019 19:30:00 +0100 crystal-facet-uml (1.16.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * Diagram exports can be triggered from command line * Cut + paste of relationships is possible * Json format in clipboard slightly modified (set renamed to data, order required, relationship src/dst names added) * The default classifier size is calculated based on the grid-distances * Fix: Scenario based diagrams showing multiple identical classifier instances show not too many relationships -- Andreas Warnke Sat, 16 Nov 2019 19:30:00 +0100 crystal-facet-uml (1.15.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * The id of selected objects is displayed in the edit area * Child diagrams are layouted in a grid (in navigation view) -- Andreas Warnke Sun, 20 Oct 2019 12:30:00 +0200 crystal-facet-uml (1.14.2) UNRELEASED; urgency=medium [ Andreas Warnke ] * gtk is initialized before data and ctrl packages --> fix for wine -- Andreas Warnke Fri, 06 Sep 2019 19:30:00 +0200 crystal-facet-uml (1.14.1) UNRELEASED; urgency=medium [ Andreas Warnke ] * background image added to intro screen. * compatibility to GTK 3.6 established, newer features replaced * pthread dependency replaced by glib functions * build for wine using mingw -- Andreas Warnke Mon, 02 Sep 2019 21:30:00 +0200 crystal-facet-uml (1.14.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * all features (except lifelines) are hidden in scenario-based and box/list diagrams * non-global relationships are hidden in scenario-based and all in box/list diagrams * exporting descriptions of hidden relationships and features is suppressed * any classifier can be displayed as named instance or as anonymous instance. -- Andreas Warnke Sun, 14 Jul 2019 11:30:00 +0200 crystal-facet-uml (1.13.1) UNRELEASED; urgency=medium [ Andreas Warnke ] * sqlite3_db_cacheflush() is only called if on the build system and on the target system available. This is a bugfix for the sudden termination on older linuxes when clicking on the commit (Ctrl-S) button. -- Andreas Warnke Sun, 23 Jun 2019 15:30:00 +0200 crystal-facet-uml (1.13.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * improved auto-layout of relationship labels * call/transition to self is layouted nicely in sequence/timing diagrams * automatically grey out arrows if source or destination classifier is greyed out * prevent creation of relationships if unsuitable diagram type * prevent creation of features if unsuitable diagram type * prevent creation of features if unsuitable classifier type -- Andreas Warnke Fri, 21 Jun 2019 15:30:00 +0200 crystal-facet-uml (1.12.1) UNRELEASED; urgency=medium [ Andreas Warnke ] * Packageing warnings of lintian addressed -- Andreas Warnke Wed, 15 May 2019 20:30:00 +0200 crystal-facet-uml (1.12.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * operations and properites do not overlap with class/interface compartments * linebreaks in classifier names are possible * component and artifact icons do not overlap with the label * activities and states better embrace their children classifiers * labels of ports and interfaces and relationships are layouted avoiding overlaps -- Andreas Warnke Fri Apr 26 20:17:44 2019 +0200 crystal-facet-uml (1.11.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * export dialog allows to select multiple file formats simultaneously * docbook export * html export * embunit replaced by own test functions to comply to debian packaging rules -- Andreas Warnke Sun Mar 10 12:29:16 2019 +0100 crystal-facet-uml (1.10.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * new classifier types for activity, state, Interaction-Overview and parametric diagrams * part, artifact, node and object are automatically underlined as instance * objects and parts are always instances * sqlite3 is linked dynamically * symbols for interruptable region, diagram reference, decision, fork, join, timeout, send-sig, rcv-event, history -- Andreas Warnke Sun Feb 3 17:26:24 2019 +0100 crystal-facet-uml (1.9.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * the database check can repair circular diagram-parent references * user experience improvements at using text-edit widgets * communication diagram does select/highlight classifiers in edit mode but lifelines in create mode * lifeline properties cannot be changed anymore * include, extends, deploy, manifest relationships show their stereotype * refine and trace relations exist for requirements * component interfaces are rendered as circle and half-circle * new label-positioning of ports -- Andreas Warnke Thu Jan 17 18:21:15 2019 +0100 crystal-facet-uml (1.8.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * in navigation mode, diagrams can be re-ordered by dragging their names in the tree view * F7 workaround removed, key F7 is without function now * in edit mode, features can be re-ordered, ports can be moved along the classifier border * ids of diagrams and classifiers are shown -- Andreas Warnke Tue Jan 1 09:02:30 2019 +0100 crystal-facet-uml (1.7.1) UNRELEASED; urgency=medium [ Andreas Warnke ] * user-doc and manpages are generated from docbook now * doubleclick on .cfu1 files starts crystal_facet_uml -- Andreas Warnke Wed Nov 21 19:30:59 2018 +0100 crystal-facet-uml (1.7.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * tree view allows to navigate interactively * new sibling and new child diagrams can be created in tree view * when deleting a diagram, unfocused windows show parent diagram * only local-scenario relationships are shown in timing, sequence and communication diagrams -- Andreas Warnke Thu Nov 1 16:08:58 2018 +0100 crystal-facet-uml (1.6.1) UNRELEASED; urgency=medium [ Andreas Warnke ] * debian archives are now build by dh_make and debuild * fix for only partly visible background text -- Andreas Warnke Mon Oct 15 23:42:16 2018 +0200 crystal-facet-uml (1.6.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * element configuration moved from bottom area to the right of the window * tree view shows current diagram in hierarchy -- Andreas Warnke Mon Oct 1 20:41:27 2018 +0200 crystal-facet-uml (1.5.1) UNRELEASED; urgency=medium [ Andreas Warnke ] * no automatic database upgrades anymore, use -f parameter * fix for persisting moved relationships in sequence and timing diagrams -- Andreas Warnke Sun Aug 26 20:10:58 2018 +0200 crystal-facet-uml (1.5.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * Sequence and timing diagrams show messages/transitions * In sequence and timing diagrams, messages/transitions can be moved * Box and list diagrams hide all relationships * List diagrams soft the classifiers by list_order now * Database format changed (list_oder field for classifiers), up- and downwards compatible. -- Andreas Warnke Sat Aug 25 15:06:01 2018 +0200 crystal-facet-uml (1.4.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * relationships can connect to ports * the repair-database function can detect and repair broken focused_feature keys in diagramelements * the repair-database function can detect and repair broken from/to_feature keys in relationships -- Andreas Warnke Fri May 11 10:32:23 2018 +0200 crystal-facet-uml (1.3.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * lifelines are created and removed automatically for timing, sequence and communication diagrams * lifelines are drawn and can be selected/edited * ports can be created/selected/edited and are drawn -- Andreas Warnke Sun Apr 1 11:22:16 2018 +0200 crystal-facet-uml (1.2.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * all relations to/from multiple classifier instances are drawn -- Andreas Warnke Sun Mar 4 13:34:26 2018 +0100 crystal-facet-uml (1.1.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * greyed-out classifiers also grey-out their contained features * sqlite updated from 3.10.2 to 3.21.0 * Database format changed. * A newer crystal_facet_uml can still open older database files (and immediately update the file format). * Older crystal_facet_uml cannot open database files created or opened by a newer crystal_facet_uml! * relations where source and destination are identical are beautified * for comments and requirements, the description is shown -- Andreas Warnke Tue Jan 23 20:58:34 2018 +0100 crystal-facet-uml (1.0.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * F7 in navigation view moves child diagram up and parent down * The text export contains IDs -- Andreas Warnke Wed Jan 3 17:58:38 2018 +0100 crystal-facet-uml (0.20.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * navigation mode: a newly initialized database shows a quick guide * navigation mode: root diagram has sky-blue background * orange background color marks new-object and new-diagram modes * link to the home page is added in the man page and on the startup screen * The 2nd click on the about button removes the about message * Ctrl-X/C/V,DEL work as expected during text editing * edit mode: Pink-selects elements only at the second click -- Andreas Warnke Tue Dec 26 17:11:33 2017 +0100 crystal-facet-uml (0.19.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * The default-names of new classifiers match their type * default-types of new objects fit to the diagram type and to the origin-classifier type now. * default-names of new objects are unique, no duplicate name errors unless forced * In new object mode, clicking into a possible parent classifiers creates a new child (depending on type) * children of CONTAINMENT relations are automatically embraced by _any_ ancestor * nicer layout when parents embrace CONTAINED children * Easier selection of the right relation in GUI_SKETCH_TOOLS_EDIT mode * Easier selection of classifiers in GUI_SKETCH_TOOLS_CREATE_OBJECT mode * Nicer layout: space area shall depend on the classifier type -- Andreas Warnke Sun Dec 10 11:36:30 2017 +0100 crystal-facet-uml (0.18.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * parent classifiers can contain children -- Andreas Warnke Sat Nov 4 18:55:43 2017 +0100 crystal-facet-uml (0.17.1) UNRELEASED; urgency=medium [ Andreas Warnke ] * fix for include paths on openSuSE Tumbleweed i586 -- Andreas Warnke Sat Oct 28 17:55:54 2017 +0200 crystal-facet-uml (0.17.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * Key control is possible: CTRL+C,V,X,Y,Z * Layout of relationships improved * Man page added -- Andreas Warnke Mon Oct 2 08:46:58 2017 +0200 crystal-facet-uml (0.16.2) UNRELEASED; urgency=medium [ Andreas Warnke ] * fix: install uses less global paths for app icon -- Andreas Warnke Mon Sep 11 16:30:00 2017 +0200 crystal-facet-uml (0.16.1) UNRELEASED; urgency=medium [ Andreas Warnke ] * fix: desktop file is included in src distribution -- Andreas Warnke Sun Sep 10 17:35:06 2017 +0200 crystal-facet-uml (0.16.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * Classifier drawings represent the classifier type -- Andreas Warnke Wed May 24 20:48:00 2017 +0200 crystal-facet-uml (0.15.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * Arrow, line and feather types of connectors are determined by relation type * A reset button clears the current selection * Relations are auto-layouted in a nicer way -- Andreas Warnke Fri Apr 14 18:03:58 2017 +0200 crystal-facet-uml (0.14.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * Classifiers are layouted avoiding overlaps -- Andreas Warnke Sat Mar 18 10:40:48 2017 +0100 crystal-facet-uml (0.13.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * The txt-file export contains features and relationships * The user can export pdf and ps formats * The user is able to import features from the clipboard * The user is able to export relationships and features to the clipboard -- Andreas Warnke Sat Feb 25 14:15:36 2017 +0100 crystal-facet-uml (0.12.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * Features can be created, modified, deleted (incl. undo/redo) -- Andreas Warnke Sun Feb 12 16:11:30 2017 +0100 crystal-facet-uml (0.11.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * Align objects vertically and horizontally (snap) * Edit new classifiers or relationships immediately -- Andreas Warnke Sun Feb 5 22:13:05 2017 +0100 crystal-facet-uml (0.10.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * Relationships can be created, modified, deleted (incl. undo/redo) * DB format changed: features.key is not UNIQUE anymore (compatible change) -- Andreas Warnke Sat Jan 28 07:32:48 2017 +0100 crystal-facet-uml (0.9.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * Mark and instantiate classifiers * Test the database for errors and fix them * Diagrams show also non-ascii names now -- Andreas Warnke Thu Dec 22 21:38:24 2016 +0100 crystal-facet-uml (0.8.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * Export of png and svg diagrams and txt descriptions * DB format changed: classifier.name is UNIQUE, features.key is UNIQUE (compatible change) -- Andreas Warnke Sun Dec 11 00:08:44 2016 +0100 crystal-facet-uml (0.7.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * The user can move classifiers -- Andreas Warnke Sat Nov 26 20:49:29 2016 +0100 crystal-facet-uml (0.6.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * cut+copy+paste allow to copy diagrams and classifiers to and from the clipboard -- Andreas Warnke Thu Oct 6 21:27:21 2016 +0200 crystal-facet-uml (0.5.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * The program integrates into a freedesktop.org desktop * rpm and deb installers are generated * undo/redo works for creating, modifying and deleting objects -- Andreas Warnke Fri Aug 12 05:56:31 2016 +0200 crystal-facet-uml (0.4.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * The user can delete classifiers and diagrams * DB format incompatible to version 0.3.0 (todo: in diagramelements, manually create the column "display_flags" as INTEGER) -- Andreas Warnke Sun Jul 3 11:52:47 2016 +0200 crystal-facet-uml (0.3.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * The user can select and switch the database file -- Andreas Warnke Sun May 22 15:22:46 2016 +0200 crystal-facet-uml (0.2.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * The user can create and rename classifiers like classes * DB format incompatible to version 0.01 -- Andreas Warnke Sun May 1 22:51:16 2016 +0200 crystal-facet-uml (0.1.0) UNRELEASED; urgency=medium [ Andreas Warnke ] * The user can create, rename and navigate diagrams -- Andreas Warnke Thu Mar 31 20:28:08 2016 +0200 crystal-facet-uml-1.34.1/architecture/000077500000000000000000000000001415120503000176055ustar00rootroot00000000000000crystal-facet-uml-1.34.1/architecture/doc/000077500000000000000000000000001415120503000203525ustar00rootroot00000000000000crystal-facet-uml-1.34.1/architecture/doc/programming_guidelines.txt000066400000000000000000000234501415120503000256510ustar00rootroot00000000000000/*! * \page cfu-programming-guidelines-page crystal-facet-uml programming guidelines * * \image html crystal_facet_uml.png * \image latex crystal_facet_uml.pdf "" width=3cm * * \section cfu-modules Software Modules * * The software consists of several modules. * \n Some are external modules and may therefore not follow the rules listed below. * \n The others belong to the crystal-facet-uml application. * * \subsection cfu-folder-structure Folder Structure * * Each module consists of the following top-level folders: * - include/ * \n contains all public interfaces of the module * \n as well as private interfaces+inline functions on which the public interfaces depend. * - source/ * \n contains all module-internal interfaces, source codes and resources. * - test/ * \n contains test cases for that software module * . * * \subsection cfu-namespaces Namespaces * * Since ANSI-C 99 does not provide namespaces, all file names, functions, types, enumeration-constants shall have a prefix. * \n If a module has sub-modules, these may have different prefixes. * * \subsection cfu-files Files * * - Every compilation unit file (.c) shall have one header file (.h) with the same name. * - Every header file (.h) may have one inline file (.inl) with the same name. * \n This inline file contains inline definitions of functions. * . * * \subsection cfu-coupling Loose Coupling * Independant software modules shall provide loose coupling and depencendy injection. * This is especially important when lower-layer modules broadcast messages to e.g. upper layer modules. * To allow loose coupling, glib signals shall be emitted. * Dependencies between these modules can be injected from outside. * * Within a software module, other ways of messaging is preferred, e.g. listener concepts, * where the compiler can check types of parameters (of function pointers). * * \section cfu-classes Classes and Objects * * All files shall follow object-oriented design patterns in the following way: * - Each header file declares one main type, a struct, with the same name as the file (postfixed by _t). * \n This struct is used like a class. * . * Even functions that do not share a data-object shall declare such a class-like struct. * Besides conformity of style, this guideline makes dependencies between classes explicit. * * \subsection cfu-attributes Attributes * * - All struct elements are private and shall be accessed via "_get_", "_is_" and "_set_" functions. * \n To achieve good runtime-performance, these may be declared as "static inline". * - Attributes that have a shorter lifetime than the parent object shall be perfixed by "temp_". * . * * \subsection cfu-methods Methods * * - All function names are pre-fixed by the main type name. * - The first parameter of each function is a pointer to an instance of the main type. * \n The name of the first parameter is "this_". * \n This first parameter must not be NULL and needs not be checked for NULL. * - Functions that shall not be accessed from outside are in-fixed by "_private_". * - Functions that expose pointers or accessors to internal data shall be post-fixed by "_ptr". * \n If the exposed member is const, "_const" may alternatively be used as postfix. * \n Care needs to be taken when changing internal data from outside * and when reading data from outside while it may be changed from inside. * - All functions may assume (unless explicitly documented) that they are only called * \n after an init call and * \n before a destroy call * . * * \subsection cfu-create-destroy Constructors, Copy-Constructors, Move-Constructors and Destructors * * Similar to classes, at least one constructor and a destructor shall be provided. * - Any constructor starts with the type-name and "_init" as prefix. * \n A constructor shall initialize the struct in a way that all functions can be called without causing harm. * - Any copy/move constructor (if provided) starts with the type-name and "_copy"/"_move" as prefix. * \n If no copy constructor is provided, the assignment "=" and memcpy may be used. * - The destructor starts with the type-name and ends with "_destroy". * \n The destructor shall free any occupied resources (e.g. mutexes) and may set all references to * external objects to NULL. It shall not do more: E.g. zero-ing the memory is not necessary. * - Optionally, a "_reinit" de+constructor may be provided. * \n This constructor shall re-initialize the struct that was already initialized before. * - Optionally, "_replace"/"_replacemove" de+constructors may be provided for copying/moving objects into already initialized ones. * \n This constructor shall re-initialize the struct that was already initialized before the copy/move of the provided object. * . * * \subsection cfu-lifecycle Responsabilities for Creation and Destruction * * The general guideline is: who creates the object is responsible for destroying it. * * Special Considerations: * - Functions may return objects only if the assignment via memcpy is a valid move-operation. * The caller is responsible for destroying it. * \n Rationale: The caller will most likely do an assignment like result_object=function(x); * Only result_object can be destroyed by the caller, not the copy on the stack. * - Functions may accept object-parameters (non-pointer) only if the assignment via memcpy is a valid copy-operation. * \n Rationale: The caller will do an assignment like function(object_parameter); which produces a copy. * Note that the caller is still responsible to destroy object_parameter and the callee to destroy the copy. * - Functions may define memory locations for result-objects as "out_"-parameter. The caller shall pre-initialize these. * \n Rationale: This allows to stick to the followin rule: Who creates an object is responsible for destroying it. * - Arrays: Objects in arrays shall be destroyed as all other objects. * - Exceptions shall be documented. * - Avoid using NULL pointers, prefer using pointers to void objects. * \n Rationale: This avoids segmentation faults in case of not checking for NULL, software gets more robust. * . * * \subsection cfu-interfaces Implementing Abstract Interfaces * * How to define an abstract interface, implement it and then pass an instance of the abstract interface to clients, * see universal_output_stream_t. * \see universal_output_stream_t * \see universal_output_stream_if_t * \see universal_file_output_stream_t * \see universal_memory_output_stream_t * * Note: there is also a more typesafe but less nice variant, \see io_element_writer_t . * * \section cfu-error Error Handling * * This section explains the detection of faults and anomalies, the propagation from detection to error handler and * how an error handler shall react. Small anomalies shall be logged but need not be handled. * * \subsection cfu-error-handling Technical Concepts * * The following mechanisms shall be used for detection, propagation and handling of errors: * - assert * \n assert statements shall be used to validate that a function is called under appropriate conditions. * \n assert statements shall have no effect in NDEBUG mode, stop the program otherwise. * - logging * \n Faults and anomalies shall be logged when they occur. * - error_codes * \n The return parameter of a function shall be the error code. Futher return values shall be declared as *out_xy parmeter. * \n Exception to this rule are helper and utility functions which do not report errors (only perform asserts). * - error handling * \n Errors shall be reported to the user: in GUI mode, a message shall be shown in a window, in console mode, it shall be * shown on std_err. * \n If possible, the program shall continue running. * . * * \section cfu-types Types (Declarations and Operators) * * Avoid implicit type conversions. Perform explicit type conversions instead. * * \subsection cfu-implicit-type-conversions Implicit Type Conversions * * Especially on arrays, one can get confused easily. While implicit type conversions are helpful as long as things are simple, * one gets confused when looking at pointer-to-array-of-pointers and array-of-pointers-to-arrays. * * The term \c ((char*)buf)+len looks simple - but adds value \c len*sizeof(char) to the pointer \c buf and returns a pointer of type \c char*. * These c-magic pointer-to-array conversions get confusing if types are more complicated than a simple char, e.g. \c ((char(*)[][7])buf)+len . * * In crystal-facet-uml, the preferred term is \c &((*((char(*)[])buf))[len]) - which is identical to \c ((char*)buf)+len. * There is no magic: \c buf is cast to pointer-to-array \c char(*)[] . The pointer is dereferenced, the array-element \c len is selected, * the address of that element is determined. * * Hints on C-Pitfalls: * - An array is an array. * \n to get a pointer onto the first element, call \c &(my_array[0]). * \n to get a pointer onto the array, call \c &(my_array). * - A pointer is a pointer. * \n to get an array, cast the pointer-to-base-type to a pointer-to-array-of-base-type and dereference it: \c *((char(*)[])my_ptr) * \n to get a function, dereference the pointer: *(my_func_ptr) * \n avoid the + operator on pointers, dereference the pointer and access the array element instead: \c (*(array_ptr))[n] * - A function is a function. * \n to get a pointer to a function, write \c &(my_func). * - A c-string is a char-array. * \n to pass a c-string to a function, use a pointer on the array: \c &(my_string) of type \c char(*)[]. * . * * \section cfu-programming-guidelines-apx Appendix * \author Copyright 2016-2021 Andreas Warnke; Email-contact: cfu-at-andreaswarnke-dot-de */ crystal-facet-uml-1.34.1/architecture/doc/self_architecture.cfu1000066400000000000000000004740001415120503000246320ustar00rootroot00000000000000SQLite format 3@ #i #i.Kn/tablefeaturesfeaturesCREATE TABLE features ( id INTEGER PRIMARY KEY ASC, main_type INTEGER, classifier_id INTEGER, key TEXT, value TEXT, description TEXT, list_order INTEGER, FOREIGN KEY(classifier_id) REFERENCES classifiers(id) )P''_tablerelationshipsrelationshipsCREATE TABLE relationships ( id INTEGER PRIMARY KEY ASC, main_type INTEGER, from_classifier_id INTEGER, to_classifier_id INTEGER, name TEXT, description TEXT, list_order INTEGER, FOREIGN KEY(from_classifier_id) REFERENCES classifiers(id), FOREIGN KEY(to_classifier_id) REFERENCES classifiers(id) )=##AtableclassifiersclassifiersCREATE TABLE classifiers ( id INTEGER PRIMARY KEY ASC, main_type INTEGER, stereotype TEXT, name TEXT, description TEXT, x_order INTEGER, y_order:uFzoic]WQ@:4K.(" The data layer provides - read access to ctrl, pencil and gui components - write acccess to ctrl component - low-level consistency of database, ensuring that all referenced objects exist.  Zcairo   Zgdk   Zglib / Zcrystal facet uml  Zdoxygen ' Zcmake (+make)   Zgit   Zmain  Ztrace   Zlog$ C Zunittest(s) + unittest_main  Zembunit" ? ZDiagrams are hierarchical( K ZClassifier is implicit instance( K ZClassifier is explicit instance'  I bClassifier marked inzqZdI^1b*Q{Ky;5T0z9,yhxc{VzQfMc?_:Z#VUSJu8@`IpHh]`FYCNAA=;4"G\<85)\:1.%[ 1*q)b&_OY"VNNJ5'"B  E{uoic]WQKEh%' 2what to test?'! 0depends on! /depends on!$1 1what to integrate?# .creates") !"asks for sizes !! -*has (1..4)  ! +,has (1..n) *+has ()has! '%depends on ! &%depends on '&uses "#requires "$requires  "uses  !uses !$modifies  $#extends!  depends onV!  depends on !  depends on!  depends on6n!  depends on=4!  depends onm! depends on{ !  depends on  uses x  uses    uses (vxujtZr<[ XjRKM)mDs>R/,ihfgF5sKe.qpxoYn:lkcj?('V%Y+s\K3nV' #/ Tdescri# Tdescription\ TnameX % Tdiagram_typeenumT# SdescriptionL SvalueH SkeyD Smain_typeenum@# Qdescription8 Qname4  Qmain_typeenum0# Pdescription$ Pname ! Pstereotype  Pmain_typeenum Ridint64_t Tidint64_t  Qidint64_t   Sidint64_t  Pidint64_t. )7 (undo_redo_listctrl_undo_redo_list_t ,  ? (diagramsctrl_diagram_controller_t2  #E (classifiersctrl_classifier_controller_t   grey out    highlight#0U Consistent relations between objectsx 7 c Consistent locations of objects in diagrams(E Consistent naming of objects|/ Cgcccompileruint32_t get_state() is ...< +Crpm buildpackage manageruint32_t get_state() is ...@ =Cmakebuild dependency handlerui~T|Gw5 ) C {guiThis diagram shows the main classes in the gui package.E }ctrlThis diagram shows the main classes in the ctrl package.E }dataThis diagram shows the main classes in the data package.JpencilThis diagram shows the main classes in the pencil package.  9g Arc+Build+Config ToolsThis diagram shows the tools for designing, implementing, documenting, configuring and building the software.;_UtilitiesThis diagram shows small utility modules.Q Unit-TestThis diagram shows the sw-components involved in unit-testing.K  FeaturesThis diagram lists the main features of crystal facet uml.A1YExternal LibrariesThis diagram shows the base libraries.N LayersThis diagram shows the layering of the main software modules.T OverviewThis diXD9!NY.,63E& A QA mtablefeaturesfeaturesCREATE TABLE features ( id INTEGER PRIMARY KEY ASC, main_type INTEGER, classifier_id INTEGER, key TEXT, value TEXT, description TEXT, list_order INTEGER, uuid TEXT NOT NULL DEFAULT '', FOREIGN KEY(classifier_id) REFERENCES classifiers(id) )9''1tablerelationshipsrelationshipsCREATE TABLE relationships ( id INTEGER PRIMARY KEY ASC, main_type INTEGER, from_classifier_id INTEGER, to_classifier_id INTEGER, name TEXT, description TEXT, list_order INTEGER, from_feature_id INTEGER DEFAULT NULL, to_feature_id INTEGER DEFAULT NULL, uuid TEXT NOT NULL DEFAULT '', FOREIGN KEY(from_classifier_id) REFERENCES classifiers(id), FOREIGN KEY(to_classifier_id) REFERENCES classifiers(id) )p##'tableclassifiersclassifiersCREATE TABLE classifiers ( id INTEGER PRIMARY KEY ASC, main_type INTEGER, stereotype TEXT, name TEXT, description TEXT, x_order INTEGER, y_order INTEGER , list_order INTEGER, uuid TEXT NOT NULL DEFAULT '')gysmg|sj]TKB5-% ~ulcVM@7.%UQTPS O R N Q M P LO K N JMILHKGJFIE H DG C F BE AD @C?B>A=@<?;>:=9<8;7:695847365  4 3 2 21 10 0/ /. . - -, ,+ +* * ) )( (' '& &% %$$##""!!    >(nQ?}WZGPv?F-7k+:P,n&ac% nX++gtablediagramelementsdiagramelementsCREATE TABLE diagramelements ( id INTEGER PRIMARY KEY ASC, diagram_id INTEGER, classifier_id INTEGER, display_flags INTEGER, focused_feature_id INTEGER DEFAULT NULL, uuid TEXT NOT NULL DEFAULT '', FOREIGN KEY(diagram_id) REFERENCES diagrams(id), FOREIGN KEY(classifier_id) REFERENCES classifiers(id) )$tablediagramsdiagramsCREATE TABLE diagrams ( id INTEGER PRIMARY KEY ASC, parent_id INTEGER, diagram_type INTEGER, name TEXT, description TEXT, list_order INTEGER, display_flags INTEGER NOT NULL DEFAULT 0, uuid TEXT NOT NULL DEFAULT '', FOREIGN KEY(parent_id) REFERENCES diagrams(id) )g3#indexmanual_unique_indexclassifiers CREATE UNIQUE INDEX manual_unique_index ON classifiers(name) y,,}}p cUysw-modulectrl- provides write access to the database - ensures consistency of the uml-model, e.g. no circular contains-relations, no lifelines if no corresponding diagramelement existsjH/906d936b-c68c-4592-b5c7-610e29065707, WUysw-modulepencil- renders diagrams to cairo drawing contexts - highlights uml-elements as requested by the gui moduleNXv0849c4fd-bf4c-475a-8b87-599cb051b9d1( UUysw-modulegui- allows a user - to select the database - to export diagrams - to modify the uml-model5  387eaa1b-44bb-4017-83a8-ec3cd6f211e7^& %?Uysw-moduledata/storage- provides read access to ctrl, pencil and gui components - provides write acccess to only the ctrl component - ensures low-level consistency of database: all referenced objects exist. - sends notifications on changes5 H/e7fae2ab-8508-49fd-8d5b-f02d853776cf &v&+  K5UeClassifier is contained (child)A Classifier can either exist stand-alone or be a sub-element of another classifier.j^EC]bc276dd3-66d3-4cdc-95ef-44052042a5d7  -;UeShow ClassifiersClassifiers are drawn to diagrams one classifier is visible in one or multiple diagrams`3b65c75a-8370-45a6-a8d3-358f22936d1e  U|gtk3Toolkit which provides - Windows and Widgets - User Input handling\?O3c504335-5769-43f7-8af2-782e18d9bb138  [?UeDesign consistent architecture diagramsThe main goal of crystal facet uml is to create a set of consistent uml diagrams. Diagrams help in desinging a system that satisfies a set of requirements and decomposes the system into smaller entities. Consistency encompasses: - Consistent relations between objects - Consistent naming of objects - Consistent locations of objects in diagramsAd9c938d1-8956-4317-aa77-d0d31689c669J  %U|sqlite3SQL databasef?Oc8894da1-0fe1-44de-aa0d-f9e4bd286462 -?~Y+$1pencil::activities8"GPerformance of User Interface;UML::RedefinableElement~ 2 tracing -Interoperability@?r1 :data_data base_reader#+gui_main_window*LStack Mem"Gcrystal_facet_uml application +[Design consistent architecture diagrams ]L}pb.rL!LsG, pc#CompartmentL?Degradation Mode Scenario ?Check and Repair Database_'Compatibility$-Degradation Mode')Database Terms!EData migration at SW Updates&7Crosscutting Concepts+YCreate an new "Interaction" Classifier<'SCopy of the OMG UML Defintion ModelY1ConstraintProperty7Configuration Manager/$KCompatibility of Export-Formats%!Code Terms*YClassifier+Lifeline solution is chosena%OClassifier selection defines viewZ2iClassifier or Relationship selection def. view\#KClassifier is implicit instance#KClassifier is explicit instance#KClassifier is contained (child) =Classifier has relations 3kClassifier and port/lifeline selection def viewj Bool List9 Bitmask-Begin (function)E#Assert-Goal!Array List 1Array Index Sorter: Anomaly6)UAesthetics of Auto-layouted diagrams# _g5{_kY@( a2 9Escaping Output Stream|2gDisambiguation of non-unique IDs of relationso%Input Streamw4kDisambiguation of non-unique IDs of diagelementp Int Pair8InfoGAImprovement on Error Masks._How to traverse the model for XMI export?*%OHow to structure persistent data?V#KHow to store data persistently?K&OHow to generate the Interactions?;.aHow can diagrams select the parts to show?W Heap GUI-modeGUI Terms1File Output Stream/3External Data Check%Export model?+Export document@+Export diagrams#IExport (Model and/or Diagrams)[ Event7#Error Codes Error4)End (function)F'Draw Diagrams1eDisambiguation of non-unique IDs of featuresn1eDisambiguation of non-unique IDs of diagramsl4kDisambiguation of non-unique IDs of classifiersm7Diagrams have filters`?Diagrams are hierarchical/File input streamy Owxj]H9(^rKO4kOutput: png, svg, pdf, ps, txt / db, xhtml, xmi'Linux/Win: OS3iModify / Create / Delete Diagrams and Elements]3Memory Input Streamx1Key-Value Pairs DBN+YJson as second/optional storage formath Json DBL2gModify / Create / Delete Diagrams and Element`5Memory Output Stream0-Mark Classifiers %MOF::Featuret!MOF::Classs-MOF::Associationu MOF (M3)o Log-GoalLog%Local Assert CLimited dynamic allocations)3Layouting Algorithmf/Label CompartmentK7Performace Efficiency!PC'Output Stream10cOther operations shall work reliable if OOMX&OOrdering by Use Cases / ScenariosU#IOrdering by Quality AttributesT7Open a Model DatabaseZ;Objects of Reality (M0)r2gNavigate and Search and Open multiple Windows\ h4   KUeClassifier is explicit instanceA classifier can be an explicitly modelled instance of another classifierj^363fa977-5fff-4023-be87-536458e9f68aI  [aUeShow multiple instances in same diagramOne and the same classifier can be shown in a diagram multiple times (either as class/type or as instance)`Nj0115c08b8-4c03-45ef-b75e-5705f2cf3f16Z  -1UeMark ClassifiersA classifier can be highlighted in one or several diagrams. The highlighting may be different in different diagrams where the classifier is shown.MEC]99594f21-40df-4690-a441-ad31ce670112l  =EUeClassifier has relationsA classifier can have zero, one or many relations; these may be of one or of differnet types. Circular dependencies may be forbidden if semantics undefined.[ %bc509c46e-bbf7-45e5-a301-e445f34fedf3 ;{AAt A  #U|trace- provides trace macros - traces allow to reconstruct/follow the program flow The macros shall be typesafe; The compiler shall complain if using wrong-typed parameters. The trace functions are intended for debugging purposes only. They are disabled in RELEASE/NDEBUG code. Therefore it is valid to trace confidential information./fL}X6ad0dea96-6d0c-4975-8449-9bce5308c324B  U|tslog- provides macros for event-logging and error-logging - macros are typesafe (ts) so that e.g. integers are not acidentially passed to char* parameters Logging functionality may be enabled even in RELEASE/NDEBUG code. Logs must not contain confidential data: These may be forwarded to syslog or the filesystem where access rights differ from the OS-process in which crystal_facet_uml runs./fLo0c398a27-2f8e-410c-96a3-cf8f0119651d ){`  UU|cairoLibrary providing drawing primitives\S`c9f00068-311d-4cfe-9405-acd2ea4656f1K  +U|gdkDrawing library\m8a41cc50-8094-4b98-92cf-945929c10ad8U  AU|glibPlatform abstraction layerlS`98c69d6b-e2a8-40a5-a493-7c2037c14e16/ /EUndesigncrystal facet uml- drafts the software design (using this crystal facet uml tool which is under construction)MPߐfa0cbd72-e543-4a96-9944-7bcfcda8c6531 Q7 Unsource code and user documentationc + doxygen + docbookc code and doxygen are the source code and documentation formats_G kr73518f23-8ab4-4889-87a8-b74032072d85! KUnbuildcmakecmake and cpack are meta-build files which generate e.g. make files, rpm and deb package files.Da kr50139969-a782-4b59-a8a3-67ff27892afa_ +9Unversion controlgitversion control system_GO̬8decd03ad-d767-479e-8df8-b9c6f868b17et  U|main- starts the software - evaluates command line parameterst}X6b5818e0b-68af-4241-a1ea-346fd8266164 I)g!)*Iu  5_U}pencil_diagram_maker- coordinates layouting and drawing of a diagram - implements kind of front controller pattern: all requests from gui to pencil are addressed to the pencil_diagram_makerNXv3aee0e6f-157d-4694-9db0-1a965a0b4cf9D  ' UeDraw DiagramsD6a0dda46-ab61-448d-b0d8-c00d53818789   #U|universalprovides small, generic utility classes that are independant of the projectƵr^fa5f17e6-4ccd-4838-84a1-2c6536c29679Q  7U|pangoFont rendering engine!S`7ebb03d4-a8ee-40f0-9aa4-d1b6bb902afc=!" 1+U|abstractpencil_xxx_painter- knows the bounding boxes of single elements - draws single graphical elements䞸ca49bd993-9c84-44a1-8eef-457a2986a266S! 3 U|abstractpencil_xxx_layouter- layouts multiple elements within the bounds of a diagram - can convert abstract order-values to x/y coordinates and vice versa/cea96c81c-b70e-4b57-95b7-982ef79af8dc d9* Introduction and GoalsThis diagram shows the use-cases that crystal facet uml addresses.d3*Building Block ViewThis diagram shows the layering of the main software modules. Concept for Multithreading: In general, all modules shall work in a multithreaded environment. - The gui module requires own data structures in order to be thread-safe and relies on the base libraries gtk, gdk which need to support multi-threading, - The pencil module requires own data structures in oder to be thread safe and relies on the base libraries pango and cairo which need to support muq 9cU* Introduction and Goalscrystal_facet_uml creates sysml/uml diagrams to document system and software architecture. As software architect, you create a set of diagrams describing use-cases, requirements, structural views, behavioral and deployment views. This diagram shows the use-cases that crystal facet uml addresses.7ffb648b-2a4c-46ce-918e-96fc2d76b747 uu{e 3U*Building Block ViewThis diagram shows the layering of the main software modules. Concept for Multithreading: In general, all modules shall work in a multithreaded environment. - The gui module requires own data structures in order to be thread-safe and relies on the base libraries gtk, gdk which need to support multi-threading, - The pencil module requires own data structures in order to be thread safe and relies on the base libraries pango and cairo which need to support multi-threading. - The data module does not need own data structures, it comes with a module-wide lock in the database_t structure. - The ctrl module requires own data structures in order to be thread safe. This limitation would need to be changed if a multi-threaded gui should access a single ctrl and data instance. (Currently, the software is single-threaded) 07d64a06-b201-4ea8-8c7b-c43f69186e0b  oO[n2oo4{gTAAB;=  U!$modifies b169f1db-e279-4a56-80bb-23dfc7677dd2? ! U$#referencesb19c9310-47df-4335-907e-5670eeef04fbA # U<>{3868eee9-33cb-49b5-ba98-74a2570ec3a1:  Uuses x5131b2ca-9cb8-452f-94b6-af29b1379aa9:  Uuses 345c2bec-c607-46c2-a074-e60499714c8b9   Uuses 3d91e559-2721-453d-a35b-e694e45306759   Uuses 94ecd8de-e9da-4ace-bd9d-037057062e42;8  Ufeedsef03f06e-272b-4606-9920-568cd2c41915:  Udefines8280aab2-5b7a-48df-b4e6-36922368f6c7= ! Udepends ona4a27fdb-ffb0-4b3b-ae43-293ab21663ed= ! Udepends on2140a021-4dad-4dcc-8b88-fa204ef7a1f87  Uuses3279667b-b4ef-44bf-918b-bd3fb33e2ca77  Uuses6c4025bc-9614-427b-a4bc-c12f19903936= ! Udepends on215cd3a2-53d4-4f91-a290-b149f19abe34 # UKUGGGscQ??V7&&S$ G U1check what items to integrate7ec7b765-df12-4d81-b3a7-515fe0bde279<#  U.createb18a7af9-8856-429b-a91d-9a7a76601ad99  U !usesfa3788b8-9e47-4a5d-970a-c18eca4d2145"$S% G U2understand interfaces to testb81fbaa2-ad50-4d3d-bcf6-79d3ab7c4985C" ) U!"asks for sizes 3ad001d0-ad68-44ad-b7ae-c00910bba954?! ! U-*has (1..3) 353abd37-cc9f-4cf7-87fe-e9693b911561{8  U()has6574593a-21e0-478b-8409-e8502474007d8  U'%has 989c477b-f957-466a-8e76-1bcc24b33c258  U&%hasf159ef8b-8425-40bf-9e47-fa971619f6359  U'&uses0edc8c01-0085-4c66-98f7-3e8de2df4f2a=  U"$requires6df3522e-ee6b-474d-8cd2-fba6edb34c5a9  U "usesee7c7eb1-36c9-4963-a3e4-d7708582a95b -s<-"'  7/U}data_database _writer- writes changes to the database - ensures low-level consistency of the database, e.g. all foreign keys point to existing rows (referential integrity) - retrieves the old, changed values for the undo/redo list <4Kce7afac4-eb3b-44b3-8ee0-ebd565aa11a0n&  7IU}data_database _reader- reads data from the database <>Aq?R2b77c382-5a04-4472-8698-5d89b844fd20#  -}U}data_visible_set- caches data from the database needed to draw a diagramHkc1eed88d-16ed-4b44-a4e9-e5aa5b085a31ba%  '=U}data_database- wraps the sqlite database - knows the current status and filename - opens and closes the database - manages the list of listeners and notifies changes/9H/[fd1e6739-5f96-4444-9401-5cee6ef54d03 $  1 U}pencil_layout_data- stores locations of layouted elements (in the current diagram)NX16c48ca2-f721-454c-874d-0547ee6f1ace '{mbR* udP5{hYE35Stream Output Stream}7Standards: UML, SysML'UML::PropertyUML::Port;UML::PackageableElement%UML::Package)UML::OperationUML::Node)UML::Namespace|/UML::NamedElement'UML::LifeLine)UML::Interface%UML::Feature CUML::EncapsulatedClassifier%UML::Elementv?UML::DirectedRelationshipy7UML::DeploymentTarget7UML::DeployedArtifact)UML::Component%UML::Commentw+UML::Classifier}!UML::Class?UML::BehavioredClassifier9UML::BehavioralFeature'UML::Behavior'UML::Artifact!UML::Actor'UML::Activity UML (M2)p'QTraverse the corresponding diagram=!Trace-Goal Trace TimestampH'This Document;Test Environment Assert!SysML (M2)Structure=Static Memory Allocation1Static Allocations !W jCmWR]Q~ng, if l>3iWhen navigating, if low-mem, show placeholdersV2gWhen opening a new window, if low-mem, cancelP cmake._When starting, if not enough memory, stopO #classifiersP3iWhen undoing, allow at least 3 undo operationsWUsability"0cWhen searching, if low-mem, show only partsQ=configuration management cairo7c + doxygen + docbookatk!assertions XML DBJ'Widget StatesA Warning5+User Model (M1)q2gUse identical classifier in multiple diagrams create contourH1Understand Problem%UML::UseCase UML::Type{=UML::TemplateableElementz?UML::StructuredClassifier9UML::StructuralFeature!UML::State/UML::RelationshipxM#Utf8 Writerz/crystal_facet_uml'Undo and Redo^/crystal facet uml*Wclassifier list is iterated in 1.24.0:  [i!T[5  U}WarningA warning is issued when a condition may possibly lead to a malfunction./fLK1ef76eb8-985e-4e2c-89e7-18411aba8c4bG0  %UdSW DeveloperA software developer understands the requirements and architecture; creates the software parts and performs reviews and unit-tests.sH381398d09d-a6cb-422d-a405-31edaa2e2c44o-  1YUZgui_window_manager- starts and stops application windowsl b86507f3-7836-43c3-a8a2-3acea4ec34ea4}4   U}ErrorAn error is a condition that leads to an observalbe malfunction./fL56dc6265-21e0-441e-8f7f-643b2d4785edL2  7 UdSW Integration Testers 4ca140c0-490f-4c2e-8f5d-e66e49b38aa7D1  ' UdSW Integrator_@NDdbfcadf0-e441-4db1-8742-79f84a56c58eL/  7 UdConfiguration Manager_@380384d730-8c0d-4ce3-a841-33ffe8e1445cG.  % UdSW ArchitectsH ׬vvc87cd518-84ef-43b2-aeb3-85ef8499a7a4 #|aN#;N  1oUcKey-Value Pairs DBThe database is stored as key-value pairs. pro: allows automatic merges by git and svn con: all data needs to fit to RAM (or complex data handling), difficult to express complex data entries or relations between theseO*rXd06a9bfb1-4184-40a2-aa48-c74e43de74c0jL  cUcJson DBThe database is stored in Json format. pro: text based, fits to svn and git repositories con: all data needs to fit to RAM (or complex data handling)0';0Z91f3b543-21a1-4076-a6e0-8840d699ddaf+M  aUcSQLite DBThe database is stored in sqlite3 format. pro: the database cares on handling big amounts of data the database cares on reliability and consistency of data con: binary files are not suitable for git repositoriesO*r;0Z81606f73-4796-4885-9fcc-407903edd478K  KcUeHow to store data persistently?The UML Model shall be stored persistently.4yJ &%804d1c5b-317a-40cb-98b0-f570d389335f h5vCLa2F^-Ue897cb9d-cc81-46f5-ae31-0d91a5b8292f-Uf06e8d08-c6ef-46e1-8099-eed41bdfeadc-U41b3755d-c948-4dc1-8f80-b70211dea3f3-Ufc5bda21-b0f4-42af-a320-df03b5fc13bb1Uf763d14f-05e9-4350-91b6-4e9dd71beb07-U27aaa2f4-02f4-4d7a-9185-0b06777a7d621 U e754ca30-70e8-4c4e-baab-d977d40cd7ca1 U 81b4e172-66f5-4f8c-a0a0-fb35a81f3bd9- U 523dd3c6-786f-4aee-8343-01d29fb692091 U 526f9c0a-4018-48d9-b4bc-261903c2ee431 U 12df149b-74cf-4101-9f1e-1aa9c7c745db, U4af0f1de-f31f-46a9-9369-50d741925d94-Ue0b88dfc-894f-4623-aa71-44de1635fb68-U0bec4e17-e2a1-417c-bc37-f3fce62428f11Ubfaea5e2-cc3d-4d21-b45d-740c9911bb771Uce40b121-55ff-47f5-ae05-a3faf596e5dd1U4b4b73d0-7c2a-4176-96f4-c828fbced0030 U0a82074e-ee64-4c44-a298-75d06d6379a2 sDM^/sD ^-%U %53a0b57f-b3a5-40d4-8d9a-027f318f938e-$U$b9a24b09-ca12-4658-a023-a9600430958b-#U#8cffd841-ecef-42ae-9ea2-4ed321310e39-"U"f39be626-6dde-44a4-83f6-25b8adf19956-!U!33bdcdff-b02c-4235-bfa8-d1bf9843c352- U 4099df12-db5d-468d-a7cf-1f8f7d310e01-Uc76004d3-e353-44a9-ba07-316b53937657-U97d18164-65a9-49bf-a890-6024f9e2bc411Ucb6fad3b-250d-43ba-8eb4-30630a5f98c91U2ec0da53-5ef9-4045-8263-0b1ec19902b21U8e742e13-cc20-4a3b-9b4b-c22cc59e3b531U454b4d13-1b26-455a-a7e9-a07afe44ea20-U5bd078ec-74db-4e0c-b427-26fc4ce10c62-Uf77d0fb9-3d23-486a-bd8c-04a7fd78e5a9-U0b0fee45-228a-4579-ab65-aa1199494398-Uf6419621-ccea-4ab3-816f-4df06f9091a4-Ue2d5847f-324c-4525-be64-52ab435074fe-Uf44f3239-7cf7-40be-bd9f-a0949b4a5354 B[#{XCzB   64  U,# 673f587d-c8cb-4652-9252-1159632c80f063  U," ad34b5fb-4e0e-4d09-86fc-42e3b83912526,  U,) xa7b80a05-b64f-40ce-9f16-048b36ad5865n5.   U,* 1105ef49-4c09-4ccb-99d3-73cfbb5020525-   U,- 62a77f17-67a2-4dbf-9e99-eb0ac443b4e1E65  U,$ ff3870d9-afdf-463c-a6aa-3e9af4d7b60561  U, 6bcba44a-838f-4401-97f6-1a553f5f28006+  U,( x87d27c35-6f31-493c-a31d-64c91061618b6*  U,% 3816cc4a-58a8-4507-8133-0f253eaafadb6)  U,& 82cfa2ad-7ddb-4042-880b-52f9ad63bdd66(  U,' 292e95b6-120a-49bc-b6f4-78d6ed431b4cL' 9 U0discuss what to createb4b7594b-f90c-431d-b096-4143e22b4f40U& K U/cluster items of same lifecycle8433815e-1d9a-47ca-a278-c20b58d213e3 mn2F Um06=4  UQname4f6de0649-6062-4d1b-82bb-18845702569a=  UQmain_typeenum05ef81d82-bd1c-4a22-b8c8-44cb62cb2acb; # UPdescription$de7d2009-2af0-4d7e-af96-e2cc8ec5f7d74  UPname cd6055bf-85da-4310-a5d8-5222fcb37bf7: ! UPstereotyped0c6eb28-5da2-45bd-bc1d-ec98aef14a65=  UPmain_typeenumfb41a280-e17d-40d0-a3a8-eeb94d0db30d9  URidint64_tebef8134-b52a-4ad8-8af5-335efbaeec089  UTidint64_tbcbb17b9-c758-42b6-aa25-f3fc6952c9829  UQidint64_t ac165666-6757-4da3-abe3-ec657308e7659  USidint64_tf92d91cb-1382-44c9-9ae4-1fe1b9ee1bda9  UPidint64_t2ab974bb-04d6-41f8-b746-3d8fd7e705659  U grey out 85cb2ea6-12b7-44fa-8875-61aacaf5db4b:  U highlight#6b5bbbd7-3329-406b-9e74-b7fc245e5c0bA  Ugcc/mingwcompiler6bd8e92e-b9ed-49cf-bed3-e64b14658adbM = Umakebuild dependency handler66578aed-d19b-47ab-b72a-63f44a8d679d kG UNk@#M( )' Utype_combo_boxGtU) 7) Udescription_text_view GtkTextView * ^c5d2b9de-8a29-4c16-a146-b2937d471631; # UQdescription8996f9781-1282-4e7a-9b06-58f03bbf3adfM( )' Utype_combo_boxGtkComboBox * f2d7bebe-b683-4baa-8c98-b22d4c808b93F' !! Uname_entryGtkEntry * ^5482330e-d688-4f51-967e-b034d6e7dd62@# ' Udisplay_flagsR v793d6722-c8f6-4728-8ccf-532cc4cde000<"  Uidint64_tRvb3e91289-a1d8-451f-82a9-531c53f47a82= ' URdisplay_flagsh03757602-df6d-4349-a1ce-f9f5afa63e7a; # UTdescription\4534b3e4-da04-42b8-b0f8-f55a9735d2b84  UTnameXbcb642db-fd1f-4d16-a536-760dee66e3c7@ % UTdiagram_typeenumT305eac6b-cd52-4ea6-8f4d-2fd11347a9f2; # USdescriptionL0d0d52c7-8bed-43d1-8646-d22147d15af8< % USvalue (type)H31ea72dc-199e-4d15-86ca-72a733428635: ! USkey (name)Dd0ea89c1-ea44-4f61-8575-4e5a308527a4=  USmain_typeenum@d98e8511-09d1-44a2-9391-adb41bf28982 w\ tJ ; Utest_fw: Black Box ViewThis diagram shows the sw-components involved in unit-testing.b4a55650-1547-4136-9d2f-aa6924be7cb1} 5U Use cases to addressThis diagram lists the main features of crystal facet uml.cb08e0fd-c85d-4b18-9b2f-182bcec59743 15U!External LibrariesThis diagram shows the base libraries. crystal_facet_uml links to these dynamically.f65d283c-dd79-41cd-93fd-ea5670d560e4d4 ;gU( Development View: ToolsThis diagram shows the tools for designing, implementing, documenting, configuring and building the software.98f4858e-6052-4a1c-8204-071423c9a25el 1_U!Utilities OverviewThis diagram shows small utility modules.xf596d365-dc16-48ca-9be1-d6ede80ae10a -_FS-3V  OAUeHow to structure persistent data?The database structure shall be simple but also close to UML in oder to store an UML-Model4y(,ff27b854-ecb7-44cc-b470-f50289acc19eaU  _ UQuestion, Alternatives, selected Decision(~iw0f08e5a2-2e86-4555-802d-aae3c3275735FR  + U}diagramelements5 M%;ba6f1629-9d3d-45ae-b827-aed9b71a91da?T   U}diagrams5 JfW7671f0cf-fae4-4efd-88df-947f35d44466?S   U}features qFSaee054f9f-24f3-4f07-a0cd-b181c9e1f6fcDQ  ' U}relationships;6JfWe339bf98-9123-4d61-bee7-82df8a043c0fBP  # U}classifiers qFM%;2b5d830c-bb05-41b2-85f2-3917fbce9339O  -7USQLite is chosenRationale: This alternative is most future-proof in case the database becomes large.O*rRٕc0e87c40-fefe-4878-aeb8-709cd52edacc ,y`CudQ?%  vld5W1yp#git supports(Sdata exchange with external scriptsr7gui_attributes_editor=gui/io select operations guigtk3glib9git mergetool (manual)j envelopeM=ctrl_consistency_checker)Actrl_classifier_controller%Mctrl_classifier _policy_enforcer)ctrl/test/unit<ctrl?crystal_facet_uml processgit blamekgitgiogdk+diagramelementsR%end of list?g%Mfocused element (yellow corners) featuresSendC edit documents2 diagramsT5diagramrelationships_9diagramelements_simplegit mergei deb, rpm-data_visible_set# data_id7data_database _writer'7data_database _reader&'data_database%)data/test/unit;%data/storage)data availableC data3ctrl_undo_redo_list;ctrl_diagram_controller"Gctrl_diagram _policy_enforcer+ctrl_controller( I-oo_%4hTL=NlXJ5(~I%gui_nav_treev/io_element_writeru;line-based data entriest-layouting:finishb navigate mode?@md_filter7)md/txt/xmi/xml main/test main.cImain logging+layouting:starta layoutedD)layout_feature)layout_diagramAlayout _visible_classifier5layout _relationship labelI json -io_format_writer?io_export_model_traversal Cio_export_diagram_traversal31gui_search_requestio/test/*io)invalid layoutF3image_format_writer iconG&Ohighlighted element (green color)(Shigh quality layouted documentation1gui_window_manager-#gui_toolbox+gui_sketch_area+;gui_sketch _result_list-gui_sketch _card,w#io_exporter1gui_search _runner'pencil/test/*>'pencil.layout#pencil.draw pencil pango-not-yet-layoutedE Chuman readable foreign keysq y O#|Classifier selection defines viewDiagramelements define which classM[  AUSimple structure is chosenThe OMG UML definition model is quite complex and exceeds the possibilities of a small OSS program like crystal_facet_uml.T!(,a2e32503-3b07-48e7-93fb-077d96679fd7Z  OcU|Classifier selection defines viewDiagramelements define which classifiers are visible in which diagram. All features of a visible classifier are shown. All relationships are shown that have visible classifiers at both ends. pro: simple selection rule con: Problematic for diagrams that show possible scenarios and alternatives (e.g sequences). This solution assumes that the model is invariant for all diagrams, therefore all diagrams showing examples/scenarios have to show own instances of classes, not generic classes that are used in other diagrams.9L!Ka8836688-972f-4d8b-bfdc-859d23c99b2b X+x+XK_  5 U}diagramrelationships 5Kӆ5ad8077b-8e07-40c9-8223-4e7ee01fb4bd]\  i{U|Classifier or Relationship selection def. viewDepending on the diagram type, either classifiers determine what is visble or relationships determine what is visible. pro: similar concept for diagrams that show options/alternatives/scenarios to diagrams that show invariants. con: Bigger extension to existing structure in version 1.0.0 Algorithm to distinguish used from unused elements gets complicated9KaC74715f02-68c4-452f-b176-0b9eebca88e1 x](N>x?97V  U,E53371796-1660-42fe-b776-dacff138016fFU / UBCreport and finish7e8f1172-7bba-4e02-8776-282a710c0590CS ) UDDswitch DB file48710ee2-b8f6-4618-8968-0cab29512276CR ) UADselect DB file f94da223-d1db-4fb5-9b4c-0d18300fa1ad>Q  U@Astart GUI72103fb3-d78a-4f69-9fbe-7215884968b8RP G U@Bstart repair via command line8a813295-ccf7-47a2-8355-f0828b4766655O  U< 5886cd15-c3ed-4db0-b82d-39b8deabd5235N  U?520ff1bb-c041-45d3-9856-009dd61b200f5M  U>c7694764-cfac-440d-a815-7f816f087f105L  U;8590c686-c1d9-4877-83b0-b95a867fe6e03K  U;4b43ad87-8ecd-4042-94f7-c912187937dc3J  U> 7b802a01-8615-4492-96a2-a6c5e266e09e3I  U?cfed15f2-2dfc-4f69-ad29-1497920b2a3a3H  U<4b6cb650-e4a6-4b4a-ae6e-55794677a5057G  U,=ҿFf246141d-b494-437d-9190-668636a92f0e ka*BWk11 :7  U,\Ra808d144-2c6b-4094-8cc6-2c5c8f8db9f67  U_T14caa851-c8aa-4ebf-a501-2ac779c70c51=  U`Wsolves55aa8e10-4ae1-426e-870f-503d901205d37~  U_Q9f7bb66c-348f-4770-8603-54f05be9caf87y  U,\_ɞc488b2c8-60ed-43ce-912f-08761cbd6047 % U* Runtime View12c299c9-5ca3-472a-ace6-8be7e6655402{ 5}U3"ctrl: White Box ViewThis diagram shows the main classes in the ctrl package.3cc02c8c-3095-4aae-a240-98efa54401bf{ 5}U2data: White Box ViewThis diagram shows the main classes in the data package.bde61698-bfa0-4e2d-94ca-2ad90837d9ba z]J-!xml_writer61xmi_element_writer41visible_classifier9version control system;utf8stringbuf/test/unit'utf8stringbuf;user interface strategy1user documentation3universal/test/unit? universal'uninitializedB!txt_writer5 tslog7traverse diagram tree, *sV 9 U}metaclassUML::BehavioralFeature^LL8fb3b9c34-ec88-4650-ad38-9bd580d23806V 9 U}metaclassUML::StructuralFeature\]LL8c353614e-e20f-44ad-9643-899e04e61e3aL % U}metaclassUML::FeatureH30dc088d71-b668-4b3d-9f36-1e2caa6a04f5 ;mU}metaclassUML::PackageableElementdescription: see http://www.omg.org/spec/UML/2.534579718-81a3-4a26-83a7-69527e2ad6ee /mU}metaclassUML::NamedElementdescription: see http://www.omg.org/spec/UML/2.5Ĕdv6f230d94-c7a3-421f-9bf8-9647bdd95883~ ;mU}metaclassUML::RedefinableElementdescription: see http://www.omg.org/spec/UML/2.5{Ϗ86d58980-6494-4a00-a796-63149a6852a4O} + U}metaclassUML::Classifier03b60bb03-fbc6-4d17-8db5-0b18654d9ebb~| )mU}metaclassUML::Namespacedescription: see http://www.omg.org/spec/UML/2.5Ĕ<f6b8f687-d3b4-43c1-8364-4824d7f2451ey{ mU}metaclassUML::Typedescription: see http://www.omg.org/spec/UML/2.5ߐ<50daa637-cd60-45a3-a59e-3623a9f6a5ca X>TT x>lXXX7*  Uzv<&f7f490cb-1a80-45a7-af2a-8461bd8eec8d5)  U~cceea2b7-9a21-406f-8ca4-74e28edd20c35&  U}zbaf0e92f-5da9-4abc-9ad1-73aa342a87cb5%  U}|f763adb7-b3bd-47f7-b69e-6b99e3eba1cd5'  U}{ 9de866fe-5496-42ea-a106-239a15f530847+  Uv<&0cfbdb48-6184-4bdd-a6e8-215ee271e8b17$  Uyx<&0010a260-e93a-4d41-879e-662a8517eaf37#  Uxv<&a3a63685-9697-4a01-91e1-b3f6fc25eb617"  Uwv<&4608bc53-2755-464c-a1b8-4dd5575ca40dC! % UvvownedElement<&6712e3e9-dbd8-489e-b0ca-dea294ede578C % UvwownedComment<&e6414773-5fb4-4576-857b-7d7aa69f13537  U,py< λ7956e39a-ba4a-4d2d-8c2a-ce10bf825a0d7  U,px;180c88b7-d852-44c9-a910-83bc0f08618b7  U,pw983ee93c2-3876-4963-9eeb-642da9d6abbb7,  U|<&217ac4b0-962a-4e75-984d-6e703da307865(  U}~107fa7a9-6ea2-4145-b05f-3159ba23602c l - d -z =mU}metaclassUML::TemplateableElementdescription: see http://www.omg.org/spec/UML/2.5;Lcc9be65d-2a4a-4f1f-b8ca-ecdcade620a2Qx / U}metaclassUML::RelationshipL{60482d32-1464-486b-b267-63e2fbfc1cd4u  - U}MOF::AssociationThis diagram shows some example classes of the MOF Meta Model.7 5de2ff80f-3bd8-49db-9ff2-d3076839d541Ct  % U}MOF::Feature冻.5d4d6ce3f-ccf4-45f2-936b-a81d3a2af544As  ! U}MOF::Class1 51c66f470-01dd-440c-81b1-53004ec47074Nr  ; U|Objects of Reality (M0)jpw.8bc8fcc6-7e86-4ac3-94ff-c26c896c000bYy ? U}metaclassUML::DirectedRelationshipL01101a827-1ef8-4c22-b9c6-9a5934a558dcLv % U}metaclassUML::Element7358a681b6-bb7b-4527-bb88-487131cfbb98Lw % U}metaclassUML::CommentH3{8c1cc3fe-8570-44dc-a6f5-76198e6270d1 q_rkqh??>{N ) U}metaclJ ! U}metaclassUML::State{4&߀eb023887-89d7-42e5-ae79-e3e76421b304N ) U}metaclassUML::ComponentW,86e1e49f-19fe-4fda-8318-bd0092306abeY ? U}metaclassUML::BehavioredClassifier3xNAea3cf661-b9f8-4474-a916-844ff884d11eJ ! U}metaclassUML::Class1d6[a227e3ff-e0db-40ee-aa31-2bb5083cb7d6[ C U}metaclassUML::EncapsulatedClassifier}4&߀875b86c9-365b-47e5-92d9-fef352b33392Y ? U}metaclassUML::StructuredClassifier}3xNAa24141cb-bc5b-44e5-bd6f-de0721b4caeaN ) U}metaclassUML::InterfaceT6[7f9432a0-93a4-4921-93fe-f07c9091484dI  U}metaclassUML::Portp`S146314570-5ae4-42eb-abb2-264e3492a6abM ' U}metaclassUML::LifeLinep00e917eb4-edd1-4c74-8c2f-bcbfda370a40N ) U}metaclassUML::Operation^`S105caf1e0-8218-41c5-a1d8-888da9bc9df2M ' U}metaclassUML::Property\]`S14d7035a2-59e1-4227-9372-ef139c18a898 #dhZ."^?3(|nd trace  trace thread-2 thread-1 tests!test_suite#test_runner#test_result test_main= test_fw%test_fixture#test_assert1technical strategy stream. start sqlite3?source code documentation*Wsort classifiers by number of parents-#sketch_area;show GUI, show+alter DBD!Gshow GUI, no DB file selectedA$Kselected element (pink corners)'see Todo list%search_entry search+Ysame as doc export is chosen in 1.23.0+ runmodes9$Mrun test /repair /export via CLIB row_id+risk management=requirements engineering'relationshipsQ?r2 :data_data base_reader+select solutione spaceN symbolJ @x^@ SU"Details on Classifier Selected ViewThe simple solution is to not implement special mechanisms for scenario-based diagrams but to require that all shown classifiers in a scenario based diagram are explicit instances of the model-class.ffcec292-1dc6-4c62-82db-bd804179110c! M/U"Details on simple data structureThis diagram shows the data structure of the "Simple data structure" alternative.eec8d608-0557-4d88-9d03-c66eb87709047 aGU"Details on Classifier or Relationship Sel.Depending on the diagram type, selection of contents is done on classifiers or relationships.252b7e60-c8cb-4e78-850b-5bb225070f14^ k U!Alternatives on UML-Model selection for Diagrame726a661-5f5f-43bf-baf2-6d6b6f139822Z c U"Alternatives on data structure of UML-Modelb1387e29-2183-4441-abaa-e8e522f5e35f ;U*"Architectural DecisionsThis diagram shows which major design decisions were taken.cdc0dce1-2144-4ecf-8f3b-456e24e22e34 FF"  71UcStandards: UML, SysMLcrystal_facet_uml shall draw diagrams that are compliant (subset) to UML or SysML.60a2f14ff-a321-4cfe-a6ec-a5860a82b4a94!  'aUThis Documentdescribes - the challenge to be solved - the selected solution - the decisions and considered alternativesƠҁ6ҁ695d53726-7ba7-423a-973f-e8bb7d1a877bZ  7U}gui_attributes_editorThis class manages 5 widgets. It reads the data of the currently focused object into cache, it writes back changes to the database (via the controller), it updates the visible widgets when the focused object or the data changes. A challenge for implementation is, that on one hand, it implements the callback functions for 5 gtk widgets (which look independant if ignoring the internal implementation), on the other hand, it manages just one cached focused object (update on user-interaction, reload on change events). ̎&i35820ebc-1688-437b-9bfc-c8ca1b26c59e $|v]$>U( 1 U|externaluser documentationM\'ND 64c99c2f-0a02-40c7-ab74-49ec79a5bf58]#  kUcOutput: png, svg, pdf, ps, txt / db, xhtml, xmicrystal_facet_uml shall produce output suitable to be processed by text layout engines: - latex - docbook - doxygen - htmlz~aabee0934-65af-4f26-b102-4d706c5b2f58\' ? U|externalsource code documentationNDҚ&406f51ef-e236-4621-b8f4-a5255ad5b530[& = U|externalrequirements engineeringߤoS6d45438e-85e9-429f-b359-e22708b4ae4cY% 9 U|externalversion control systemzܜ38vf430c8d2-cd7f-4aed-987e-9f71761a2230L$  / U|crystal_facet_uml6׉;Қ&1d35e126-5cce-40e2-b188-ed310d95d865y>) S;U|externalhigh quality layouted documentationThere are good layout engines to create high quality pdf pages, like: - latex - docbookT_߸866a0a36-c0cb-4549-a02c-b71843bc4f83 k(Cyr 5kU"Base classes of UML This diagram shows the base classes of the UML 5aed7cea-ac4a-44e9-b7de-67311bbe2e8fn %sU"MOF OverviewThis diagram shows a selection of MOF meta classes.3cc7f9dc-745a-4bfa-a54f-66d48bd8abc1c 1OU!!UML/SysML OverviewThis diagram shows an overview on UML and aims to explain what parts are available in crystal_facet_uml and how this is mapped to the crystal_facet_uml database.3318bd97-bfe4-4788-9ae8-0c57640fadaeH k_U"Classifier and Port/Lifeline selection def viewThis (finally chosen and implemented) solution selects timing and sequence lifelines by a focused_feature link. To enhance usability, this cannot be selected but the program creates an own lifeline for every scenario-based diagram.58294240-54a7-4a7b-b1af-bf7bc8452d51H ? U"pencil detailed structure191fed1b-7cd5-4cbd-b9e7-69e36793de19 Ag4h5yJuA1UP5de15ac6-67ce-44ce-b1d1-1b3ef106642e1UQ38aee3d9-93ce-4dde-b11f-79f288fbe2dc1US3351d4fe-74e2-4f76-be20-ab58199adf5c1UT3d6ae564-1b4d-429a-8f29-c532b99d3e011~UZ4754ea0c-bac1-4e7d-8197-b251eda68ab9-}UX1e166927-f1fc-4e4f-a59f-48360052679a-|US1630d101-5ccc-4f4d-a390-ef7494540282-{UP0db169a6-0e50-4320-ac49-b636da9116a1-zUQ3fb089bf-d9c3-4459-8fa1-23871f5f9ca6-yU\ad365271-316b-4003-a6dd-fdc3d00fb9171xU_e6314629-ab7b-4454-87a6-f52b1a27d8c21uURa4ffc42c-c22e-468c-91e6-e27a5b3481b51tUT4d07dd12-f98b-4342-b89d-5f071746a1511sUS3b605f55-b5aa-4172-8fee-80321b834ea81rUP9971446d-ad9d-4122-9ec0-839b1f2716871qUQ2ef21f77-10f3-4035-b4e7-f32df4d4335d1pUa6364470b-8900-4098-ab39-935e9a9c81ec1oU`cc311aa5-e2ba-4613-8973-acda93f57bfc-U"07eff8fb-ab6f-4977-92a3-f7d69e2f24e8 GEu3ZGJ?  3 Uyuni=@   Umode?9=04e97427-c28f-45df-8eb2-db1c2b414aeeJ?  3 Uyuniversal/test/unitL1{1b6f61b9-eb19-4dd2-9b22-01a449ad066aD>  ' Uypencil/test/*L1ƽKg6bdb27c7-e737-408b-88f4-b610db435f88@=   U}test_mainW+3bd89b1c-4625-48d1-a928-9128ef51b31fE<  ) Uyctrl/test/unitSG{83d5eeaf-6c88-449c-8f71-8f0cc4863fdbE;  ) Uydata/test/unitSGƽKgb2cde3e3-25b2-4316-ba0d-d4a7f7606a5fI:  1 U}Array Index SorterƵr^9344e517-dfca-446c-9129-93c1d9d93b73@9   U}Bool ListƵr^Kfb44f164-0d3d-4382-82e0-d2b806d596f4?8   U}Int PairtK1de7fe75-aaec-4f28-94e8-e1f72326f26d 7  +U}Event An event is a signal that is send to or received from external software parts.d2e6a45191-0ec1-4076-adbe-4c102259376286  U}AnomalyAn anomaly is a condition that is expected to not cause a malfunction but that should be logged to easier analyze issues.d2Kaa1a2d4a-bfd0-4340-9817-890fe21133d1 xdg Gg,  -UZgui_sketch _card- maintains the data of one diagram - displays one diagramڪ%PFM'091e9bb0-dd72-4b0c-894e-ca86b34b0e07n)  =KU}ctrl_consistency_checker- checks and repairs a databasevLP*~60910235-8098-4c7b-a914-39704fd3f678(  + U}ctrl_controller- changes the database contents - maintains the undo redo listJ0jHe39be61c-4aff-4cf2-a979-832b1d0b9bd6c/+  +]UZgui_sketch_areaManages the main drawing area: - layouts its subwidgets, - loads data-sets from the database, - reacts on key+button events, - handles data-change events, - controls selection-set - encapsulates quite complex logic for mouse eventsڪ%̎&f208b8bc-a0ff-4536-8bb2-80edff271f58h*  +QUZgui_main_window- represents an application windowlv39538dfa-3b4a-42b1-9762-3809528bbee9 odh  H0  ' UxLinux/Win: OS5 sj Tm3247c991-db58-47c6-adbf-24bf365357b4=/   UxPC5 p{<810d2b60-5f5d-44ad-af3c-4d8df369525beT1  ? Uxcrystal_facet_uml process5 :Yǡ35f2ce1e-9555-4251-b4c1-a2c87db2341f[- = U|externalconfiguration managementzܜNDOd8d4b105-eb7a-400c-add9-af6f13bcb1bbR, + U|externalrisk management_@oYb5070360-0098-4bf1-a651-20667cb03123U+ 1 U|externalproject managementM\'oh1c71bbc5d-116d-4b56-9ff6-a930bc725018 * U|externaltestsunit-tests, integration tests, qualification tests, regression testszܜod260f4f0a-cd0e-4a7a-8ea2-947ebae9315a v?-c?E  !j5  O-Uhighlighted element (green color)the highlightes element is the one on which the mouse arrow hovers. In case of a mouse click, the highlighted elements gets the focused element.zß52358c4b-9c2f-4236-a70f-ca4d77fd96bej3  M/Ufocused element (yellow corners)a focused element is the one element to which input is directed: - changing name, stereotype, type or description is done on the focused element.H023a538170-60c2-4f8f-8cdd-a66939d3b472X2  G Uycrystal_facet_uml application5 \#9\beb18a0a-8d7c-465c-bff1-b011cb0190a44  KUselected element (pink corners)a selected element is an element that belongs to the selected setyuTb1759c94-6253-4f06-8e77-305a7aefb53e TT`8  !GUassertions- assert() from assert.h checks during runtime (in DEBUG-mode) if assumptions on the code are valid. - TEST_ASSERT() checks during and after a test case execution if the test result fits the expectations. - PROG_ASSERT() checks during a test case for errors in the testing environment.{u0d7bbf32-7d1d-492f-9d44-e0e5d6069ec9b7  QUtracingIn DEBUG mode, the program writes abundant information to a trace channel. Goal of tracing is to follow the program flow as well as to visualize the data changes.z;Ikfe2b51d68-8051-45a9-84d2-1f5246113108^6  IUloggingIn RELEASE/NDEBUG mode, the program logs only important events, anomalies, warnings and errors. These shall be as sparse as possible to not slow down performance or consume too much memory. Goal of logging is to be able to help analyze or reproduce a bug that occurred during operation.yuT-{u88445578-6c44-41c8-a3a7-0d046ece7a73 y99 ;  '!Usee Todo listA Todo-list exists in the git repository for things that shall be changed.̟ce01e09a-990b-4dc2-bd7b-a7c5113be468,:  ;=Uuser interface strategyThe user shall - focus on the semantics of the diagrams, not on the layout - be able to order classifiers left-to-right and top-to-bottom - be forced to use the same elements in different diagrams crystal_facet_uml shall - auto-layout classifier locations and sizes, - auto-layout features and relationships - hide the meta-model from the userf\#9Odcbd8bc9-776d-4bd3-a76f-d1bd97eb6105j9  1!Utechnical strategycrystal_facet_uml shall be portable, therefore as few as possible 3rd party libraries shall be linked against: - To store the data, the sqlite database is used. - To interact with the user, gtk is used.5 !Ҹjf7f1c101-5148-4385-8c01-2619170347db Ag+J|A\8P  UPRva12b6c10-a62f-48c6-9183-ed3c2eb23737qL +cURSfocused_featureto select one of possibly several lifelinesRv1947e50c-37c6-4b4b-99eb-e8a94ce120e48C  U~<'786e6400-7379-4fa3-8826-c1e4a9cbc2179B  U<'dddd4157-506b-4622-9872-4d35d1db2b448A  U}<&2dc077ae-73c0-4d2a-aa94-0aece983e95a8O  UTR v1e270a64-0d79-4bab-a1de-b8750efec2c28Q  U,ZRv2792f2e5-c475-4098-9502-87844defa4129@  U<&e13baf96-abf5-4fbb-854e-aa90701214027R  UPSRv9c73ee21-71d4-4bc7-9413-6e767dcd62a49N  UQStoRv37faebe2-0fa4-4745-b81f-6a42fa203f739G  U<'2e7fdb0f-8990-4974-a970-c3a858ef71839F  U<'c7f093e4-11e9-4b9f-b0ad-89fa5d444cc89E  U<'5f956077-3f80-412a-95f8-e670768688d39D  U<' af74e6cc-ae50-498a-91b0-24a0db121eb3;M  UQSfromRv63cd6419-d5b4-4f38-b475-4e696c9b381b @g3m8l8u@'2FUdb32dce2-cf00-4ff8-9d01-fe4c0a5637a8.EUdc360155-a71a-4bb1-9d09-5ab18d890e8c-BU}6dfc24fe-0b87-4654-8de1-3b2fc4329807.>Ub56a6ac1-46e2-43d8-8b92-d123437e7e1f.=Udc21fd8e-7f4b-4b52-bb91-db69b3dd50971<U43e28cd7-580e-443f-9152-4d71ae1a2525.;U3503b77b-de47-48c2-b361-5f57075b9a4b.:U60fabb1e-5a4c-456e-ac9e-1a84193e0c6829U78670d3f-02b2-4e57-8398-9d753bfb7da828U7961b916-7fe3-44db-b582-a2965203dec427U1efa5fe4-909a-47db-96d5-a4e5a02c8385.6U137ac134-db5e-4e2f-bf68-5558cb1445ee15U}0d3e94c1-3249-4122-bba9-92daf49af017.3U538afe5b-3f60-4750-94c9-e19b24371c49-2U}6d9d1aa2-8298-4a8c-897a-3e38ed02e3bb11U83791e2d-2f67-4a09-b29d-fb61d314e7d110U~2aa09c30-899e-43f9-ba12-059197718270-/Uv054a2a54-62db-4180-8ad4-ca4967f0de602.Uce0c03e3-a7f5-4cd8-a545-803082b39e6f ]iJ }`6 iya4l_feature_lal_feature_layout ;pencil_feature_layouterd9pencil_diagram_painterg5pencil_diagram_maker Apencil_classifier_layoutercApencil_classifier_composerf'pencil::start +Ypencil::relationship_layouter layout_*)Upencil::rel_label_layouter do_layout;pencil::layout elements)pencil::finish'Qpencil::feature_layouter do_layout*Wpencil::feat_label_layouter do_layout#pencil::end%pencil::draw3pencil::define grid)Upencil::classifier_layouter layout_*'pencil::beginc=propose processing orderc/propose solutionsdJ1pencil_xxx_painter"1project management-planned solution>3pencil_xxx_layouter!Cpencil_relationship_painteri Epencil_relationship_layoutere+pencil_layouterb1pencil_layout_data$9pencil_feature_painterh  ':m' CA   UnGUI-mode"KP161b4bcf-890c-4b0e-a134-39acc694bbbeV? 1 U}metaclassConstraintProperty4ɕ鲕18dfe2c4-97ea-4568-8bec-5ae9ddfdfe86A@   Ustartޥ=]30f294b8-0e06-4149-9228-0c8b356c5f3e0E>  ! U|SysML (M2)Cf!%67c2bc6d-ddc7-458a-80f1-be353c197381*=  -QUcInteroperabilitycrystal_facet_uml has its strenghts. Providing a full-featured text layout engine is not one of them. Therefore it is important to be interoperable with text layout engines like - latex - docbook - markdown, asciidoc, doxygen,؇53b5fc45-b794-4ceb-815f-3b9fdb15e5e4L<  = UStatic Memory AllocationExcept for the libraries gtk and sqlite (sqlite is configured for dynamic allocations), crystal_facet_uml holds fixed-size arrays and strings for all displayed data. One could change this - but for most use cases, valid upper memory limits can be stated./@79013639-336a-429b-b986-354414644c7f  FFb:A  KaUeClassifier is implicit instanceA classifier can represent an anonymous (implicit) instance without defining an explicit instance relationj^D4757ab5b-9087-400c-864d-cc3cc67e04dcb-.  gUymain/testEach SW-moldule may have a subfolder named unittest which contains a set of tests; these - test the SW-moduleW+997c7a9e-e746-4413-a983-7ec023cc36f7u  {U|test_fwTest framework - runs test cases - reports test resultsұW!98f153cf3-6c93-4434-9ae7-891eee7af28e  ?!UeDiagrams are hierarchicalThere is one root diagram. All other diagrams shall have a parent diagram. %bcf50ef62-2be9-4d39-bbae-bc09eed474dd ] 5v_ 5]NN  3 U}image_format_writerb50 jc9762ae37-4a86-46ab-9bc0-e4184c208c8aM  #'U|pencil.drawEncapulates drawing routines for - geometric objects - labels - symbols/iconsHkvDzv69e149fc-cee2-4251-a589-8e7d9904a1cdUJ  A U}layout _visible_classifierӛL eb36f603f-b3dd-4b56-8554-e957b6af7253HD  ' U|pencil.layout &L eD07d75be7-fc42-4f61-87b5-c1861aa79bd8FC  Uysw-moduleioϫ Ԑ9a93182d-56f8-4865-a642-24d997264063PK  5U}layout _relationship &JfWԲDa372226d-373f-4bca-b48c-d5a9f6480050fML  1 U}visible_classifier qFKћO373338600-d624-43f6-9d30-55cb003e1f56II  ) U}layout_feature &Sa̱.eje0ce0921-4c9e-4b11-bbbd-5e2209715115IH  ) U}layout_diagramӛJfWԲDa17e7252-9d30-44b4-96a4-4c46278cf393RB  ')U|utf8stringbufString librarytϓcbc36e4e-9c3a-453a-931f-541ef71bdc24 ,LCSh,,,rr9s  U,T!1eada1bd-da07-4665-b4f0-8c4c53437d348r  U,T!9a3d4619e-9d82-4336-b179-6c6907b511488q  U,T 6be352bc-94bc-4aa8-8118-2e4d59178fd68p  U,T 9e9ab0565-7a9a-408a-8d6d-1c253263891b7o  U,T8eca08ca-7a69-4ee7-9dd9-6511608560c89n  U,ǡ4d163437-2cfe-4da8-9db7-fbefcc9453e69m  U, Tm235857a2-2304-4e06-a73c-d1c306e842b3x9j  U2do Leb7d4c75-21d4-4dae-ad6f-c1cd86a45ef29i  U0do̴edf4fa48-bb16-4f15-9d11-55b0236ae79cFh + U.create diagramsLc6a8661f-81f7-4f30-ae6b-e97106a23a84Eg ' Uprovide input̴969cd64c-1ea8-452a-89c1-0fa0c55a78949f  U/doLbcaff38c-9758-4b8f-a1c5-69492ebee4b38e  U,a132ca5a-b42a-4ee3-ae09-23e594bbffe9:d  U*has 0e60cf1a-b912-4c05-85dd-5d07594e4fee  7bab&7F& 5 U* Quality Requirements8d612afa-14be-462b-84b4-5fc77dabe59eV W U"UML Structure: Classifier Descendants@aefaa7d7-9bb3-450e-bb33-94a2bed422e1F ; U"UML Feature Descendants6cbe76aa-2809-4bf9-a195-2a84bc8c4a5eA# + U*Deployment View@53743108-08bb-4793-8772-6ac378e71648C" / U*!Context And Scoped776efeb-0a6e-4ad0-ac24-fa03f6abecdaň[e0a4e8bf-6e53-468e-89b5-fad5a073d2f1lw  gUcHeapOnly the external libraries may use the heap.@PY0a54ecb2-41e3-48f2-a858-7a1c13e4a458 &qK=(r&X9'Simple Random{ASimple structure is chosen[7Simple data structureX+[Show multiple instances in same diagram -Show Classifiers &OSearch Classifiers, find diagrams'SW Integrator17SW Integration Tester2%SW Developer0%SW Architect.-SQLite is chosenO SQLite DBM%MReliability of Program operation-_Question, Alternatives, selected DecisionU%Quality TreeR/Quality ScenariosS#IProgram Start and About WindowY)Program Assert 6J]oa#!66'  U2bb5f39f-55a1-4a2d-b5b9-aa7a11882a4a9  UT&9a02c6366-a2db-47f8-bf03-79012a0256b79  U,Ќz:f91dbae7-23a0-411b-a374-bc0524d2f1519  U,΋jcede2497e-dec3-4249-9565-4b48fa5835dc;%  UtoT/55a6cad2-ff44-4813-9263-54c4c1c630f15$  U 458b4cf1-77b9-4665-9a16-18a349e522ba5#  Uac239964-7129-4c67-b13f-2af8a1a956b16(  U8fbd734b-2de9-4707-b7ba-ffb7a09845069&  UT09a6addf8b-4fb4-4852-8169-d7adb15f7cb78  U,Ͳv9108d2bf-d507-4039-b1a7-cbcb4e4336dd8  UST-269fe3f8-6fa5-4a38-8cae-2e70e109b5639  UT-9a5d09859-057e-4192-9958-1ba0c849ca298  URT,33a37ec5-3cce-4cdc-9071-0a9068b8e0538  UPT,9b417edc9-38d4-4d89-9b4b-63181b8b827f8  U,T+3223214b-27b4-4bd1-97bf-3ce0dd6013ab6)  U34283ca6-a4ea-47af-90a7-5099a69b9deb =VvB=6J  }UcXML DBThe database is stored in XML format. pro: text based, fits to svn and git repositories con: all data needs to fit to RAM (or complex data handling), difficult to read for humans, especially for relations between data entries.0'Xd12a105a1-053d-43cb-9992-907956bd3b91EF  ) U}End (function)/fLϓ48f35ea9-1c31-4f0f-80db-185658692381GE  - U}Begin (function)/fL}X657a14a78-2131-4f24-959e-7ddf906177f1ND  ; Unshow GUI, show+alter DB"KX0eac94b1-5844-4971-b647-09af82a53f65WB  M Unrun test /repair /export via CLI޹Pa3bc34c7-37a1-4140-acb9-174be445378aTA  G Unshow GUI, no DB file selected"KP49ab27f6-5e51-4a93-9a76-708862cacc8a;C   UendXb162d0e5-f79d-47ed-ac3c-fec3ec5e6cca@H   U}Timestampd2ϓe844e4e3-cc17-496b-b4d0-1928485c3423;G   U}Infod2}X691695419-65f4-4e23-bd86-65647c666111=I   U}main.cƵr^ϓ13c52421-6a05-42c7-82b0-a7575a4061ac cctY  S?U|Copy of the OMG UML Defintion ModelThe data is structured according to the UML meta model defined by OMG. pro: allows to model all UML elements easy conversion to XMI and back con: the UML meta model is complex. Not suitable for a small diagram-drawing application like crystal_facet_uml. QppOMb7a59392-c195-4070-bbc7-b7b7470643f29X  7eU|Simple data structureThe data is structured with focus on simplicity. pro: Simple data structure. There are similarities to UML (M2 Meta-Model) and MOF (M3 Meta-Model). con: takes into account that some things of UML cannot be represented Qp@܈0c75b866-1bbe-4f9e-8d36-7a1d7fc6f8e0gW  aUeHow can diagrams select the parts to show?Each diagram shall show selected parts of the UML-Model, especially the scenario-based sequence, communication and timing diagrams. 4yR~\ded5ef91-bdfd-421a-b5ee-d334c9547a3c 3o?}LX(d33.U,7f7f7980-8e99-4137-b64c-a0fe8e4dec1c.U+1f10dd99-2d37-412a-85e3-3c3e5fbb21ad. U(2f0008fa-0c73-4d1f-b11a-ff5c07397ff0. U(4023c60e-0d1d-47ce-b492-8c6112acf626.U+823caba9-052f-47a2-9b25-801572994e27- U(d6c8f276-900b-45cb-a32b-03926e0681c3- U(3d20615d-d5f6-44fa-9829-31119d07084a. U(bfb6def8-303d-4d0a-b8a5-10d4da30de2b.U#227e1b15-e77c-4624-8553-e8162e066b2e.Ue65aa639-e176-4f18-a3fe-0aeaa38c5b9d.U#a414a6e5-0299-4445-91b3-ae496674ea5b.U#1e89ec6b-1a99-4695-9c74-49ee7fa97007.~U#28039aa5-6b5a-4c62-bb50-20ad91e7a0801-|U"2232ce2ea-3597-402a-bc70-6a0f2ee2b663-{U"1fb543de8-5239-4423-90d7-8822e3009d0f-zU"0989bb7ca-8ec2-4911-8109-9d2e71c692a8-yU"/429b334a-a7e1-4bab-8471-e72f5edd683a-xU".11ac2dff-afb5-492a-b78a-c501587756dd.U+45fa8512-d6f5-4714-a53d-273b4113f6be l9{  AmUImprovement on Error MasksThe next time implemementing error codes, one may reconsider that error codes are negative. This makes the program logic harder to read and the error logs harder to interpret.{Oێ z0e2819058-fc2f-4088-9d80-39f991d2af61 z  GUcBitmaskThe error bitmask shall be designed in a way that a zero represents no error, that the bits define the error cause/type, that two errors can be merged into one error code using a bitwise or, that error codes are negative.QX z0 z031c90a45-9457-4af8-8a06-36e47ddf7dca 5O<T5IK ) Uget_classifierAc ;Bd0701c51-1728-41f5-bc02-c3f67aaee2e5FJ # Uget_diagramرX;B8e32335f-e3ef-4cb7-a35e-151d54a8d6f3BI  UdestroydX :A0e6a2cc0-d58b-4b34-b631-0874409182d2BH  UdestroyTF;Bc50e3404-0359-40b2-a6c3-a082aa8e9fa4OG 5 Uinit(:data_database);B15471687-a436-4aff-8b0d-aa8d9bec885aOF 5 Uinit(:data_database)4:A4b573fc6-614c-42c0-b59a-2e853c2e33edAE  U'destroy\O:?090a4d1a-58de-4585-9da4-0f21dcb01179RD = U'init(:data_database, r1)Ҡ S:?2047e1a7-c09f-4d72-bb1a-f2da63ff016d?A  U%closek_+:=8b75bf1e-18a0-4cca-810f-cf4bbc04f436>@  U%openA:=be00672d-602b-42a2-8e52-6540389f07728?  UT%8fa95037-9d2f-4464-bf85-3e73f848b7e98>  UT%9627f7681-0f3d-4a4e-89e5-47ccc14f44cf8=  UT$aa8f1770-7f18-4c5b-a9d1-5747d11bfdf78<  UT$980e1540a-e55e-473b-a692-63f0d387f5d8 `hX `G  % Uysearch_entry rd1b9fa38-a6f5-4a18-9d51-ca1e21b475f7\  O UeSearch Classifiers, find diagramsCӇ42420c96fafd-795b-4fd2-8e15-75ebe7013d0c  1Uygui_search_requestThis class manages - a text entry widget so that the user can enter a search text - a button that starts the search. When a search is started, the gui_search_runner is triggered to execute it.  a10bc1db-02b2-4557-8e21-fbc9f2653ebfI  U}metaclassUML::NodeW16[46384c26-8252-4a73-b150-cd4ef6df949bU~ 7 U}metaclassUML::DeployedArtifact{0d03f3c95-222e-46ed-9005-37e1dbbdf086L| % U}metaclassUML::Package702bfbaca4-3a81-4f92-be9f-995408bf2efbF  # Uysketch_areaXׂ̍1l68e0aff6-2f79-4b8e-9230-841aca0ac135U 7 U}metaclassUML::DeploymentTargetĔ3gd837aa09-095a-48ce-a2a8-b33ab20fb66cM} ' U}metaclassUML::Artifact{6[17624fe0-8eae-4623-a0a2-232f9b503ae4 w'a~5  GMU}ctrl_diagram _policy_enforcerensures that application level policies on the model are adhered whenever diagrams are modified.tF452b9ab17-176a-46ed-965b-3dc7f891b7d7M  9 U}diagramelements_simpleS2M%;bb8772d1-69bf-49fe-8240-8a3c3c1371d8M ' U}metaclassUML::Activity]<6bf188ef-dc36-4255-9466-99eb654cba06M ' U}metaclassUML::BehaviorSRb03ad124-4116-4fe9-8b65-5f0f4e58ffa4MJ ! U}metaclassUML::Actor4&߀af0c84d6-3563-418d-a7ff-7f215786351dL % U}metaclassUML::UseCaseཝ4&߀6ec0698e-cf05-4a95-ba27-b66eff9031349  A U}ctrl_classifier_controllerperforms changes on classifier, feature and relationship tablest7Xdfcb73da-8cda-499e-b269-c63c02706a8d  3wU}ctrl_undo_redo_listmanages a list of actions to be undone or/and redone.+P*~d028bc79-6057-4743-b9b5-cd28b10a2102 ?[Ku+?2yGu  ;SUnpencil::layout elementsimplemented in pencil_diagram_maker*34TX1F33cc2efd-592e-4ab2-b54e-14ace3c245dbq  3SUnpencil::define gridimplemented in pencil_diagram_maker>SS55e2fdc9-716c-4822-8e81-aa32d8dc5c05G  % Unpencil::draw^DDd1d820be-87bb-4521-b622-14870b06500dI  ' Upencil::start7Y.14.14dd61e5b5-efad-4f64-8f77-b3b6bf90ad82?   U|jsonb5fcfb422f-51e0-442f-ad0b-92ba43fe0776E  ! U}Array Listt031856b489-e7c7-4fe2-8ec9-e1623aa5ba51A   Uncreate'x~3 waa788489-bbec-4f4b-b74b-4cd114dbe390?   Unedit'x _~361415f02-f0d8-4d92-b952-e41f3e26969fC   Unnavigate閲~3=33579675-87fa-4c62-b132-f131576f669eA   Unsearch閷 _ _687cc351-64e4-493d-9141-ec06b23b9431R  ; Uygui_sketch _result_listclnY|7bf16398-7bc1-47a6-bfe1-0902338e1fd0M  1 Uygui_search _runnercl^]v!330fd818-d38a-4267-86a1-13846247fee2 (<(-q\'5  oUdata_idA data-id is an identifier that refers to a table and a row-id in the database. It is unique within one database.!!17b6fb60-319b-40db-ba72-f090bbcf6f31^ M UcfeatureReliability of Program operationc]]181dd4a9-2960-46b3-bc3f-c31e202318a5X  G UcPerformance of User Interfacec׸h382d998e-bbcc-446e-a208-107d7e5668edT  )+UpDatabase Termssee D0066#name.0Be1a2e06a6-cb74-4a6c-9310-255ad0ce28f94  oUrow_idA row-id is an identifier for a data row within one table. It is unique within a table but not within a database.S SǦǦ622ad561-6cfc-44c3-bb4f-ca7e973be69aO ) U|writermd/txt/xmi/xmlX0Jr+7ff0038a-c68a-4814-baaf-e22ec543e9car [n>~MT#[.XU 81f4fe2ZUa83b0896-836c-4943-a374-988930fa11b9.YU23a6ac2f4-dc2c-4d00-8126-9f1611beb311.XU 81f4fe32-3bc3-454d-9ff4-da30788b4775.WUe7485e2c-da7a-479d-bc2d-29e18611ecb2.VU8fc27cea2-fc07-4cfa-9fc3-903ceaa79936.UU8497d6d7b-0e55-4f2b-a557-1c78989e87772TU70fa22a75-7315-4d07-ab35-d55626c35595.SU7c7974c91-5dbd-4fe4-bbfb-9c3732bfacc8.RU73fee5f18-1bf7-4a4a-b773-d0bf5ad302da.QU72b0dac64-a4fc-4e02-a85a-c1291d266b73.PU7ab8b5f2f-174e-48f4-beb7-b4a60f0445a0-OU7a66a667c-6aa2-4cbc-97a1-6b602b5e1403,N U4cf031cf7-9044-4afa-8291-9155f03fe0f9.MU50fbc6792-ffde-4ace-aa63-97a63d05ae71-LU6801fc618-d4c1-415a-b789-05e49c754e61-KU33a54cd0f-bb57-4573-946c-3104b0826c72-JU2dbc4b4fd-2423-4cac-b818-3630400993b7.IU054df05ba-9897-4448-bd0e-fbe37c82a0aa.HU006709202-b77d-41c5-825c-c3cf2f658cec 0-Vi|0VcAAIf / Uactivate_callback00b270ce-b7f0-466a-81fc-7dc5547906218e  U,f81cc903-022e-46f1-8d33-15d49515e4207a   U,1793d0ab-f2f7-4d1b-b2fb-0eedfd3421949\  U<'f5fd7bd1-ab5a-4269-bab7-8c3de019b89f8Z  U<'"a1cc036a-6266-4dab-9e22-9c4186a388018b  U*T&d5ca3b6c-1989-4cbf-a5b5-a55bb27fe8c48[  U<'3783f406-6e22-462a-8709-aa07f268406e8d  Ucfad0dcc-9db1-488e-a5e5-a9f529449355A<8_  U,,T%776026a1-f329-4228-a8ba-245ad9797f928^  U,+T%9ee402790-eeec-4382-a8f8-f510f78120f17]   U,db52b94be-199c-4a21-8b1d-4d0aa099f0de8c  Uf80ef904-c269-4bf0-967a-2eeec408f362Oi 7 U.search_start_callbackOjpGD733d794d-76c1-4d6c-87ee-d14ccc72f507Mj 3 U.enter search string,8GD9a7123e6-cda8-46de-a5bc-2f6dce8066e0 KbCK. 1CU5io: White Box ViewThis component implements input output functionality, currently: - Export of diagram imagese4a25d23-ba14-4306-8c80-a5eea2434497* I}U"crystal_facet_uml ArchitectureAbout this Document: (C) We acknowledge that this document uses material from the arc 42 architecture template, http://www.arc42.de. Created by Dr. Peter Hruschka & Dr. Gernot Starke.7a8e4585-27c6-413c-ae8f-fcbd4c5d7a43K- ? U"Selected classes of SysML49bb1750-aa7a-4f4c-839d-ac7299961944;, ! U$Code Termsa9f41539-d59a-46f4-a7ae-d2c474a45f39:+  U$GUI Termseddcb13a-f4f8-41a3-b58c-d802404fbe47#( /KU*Solution StrategyDuring operation, crystal_facet_uml runs as application based on the libraries sqlite and gtk.9694172d-ba45-4020-b1ff-c3331748bb5a'  75U*Crosscutting ConceptsThis chapter shows concepts that shall be applied through all parts of the software.6dd1a3b5-f259-4db7-bd9d-c5685f15712c **"e" 1+UpSW-product-qualityUsabilitysee D0068#name.ǛkGb6ce1cb0-2ee1-4dd1-b9e6-ce77327d925dq! 17+UpSW-product-qualityPerformace Efficiencysee D0067#name.M8:/0b14453d-8dd8-4a24-a1bf-c32bde77b537  ?sUDegradation Mode ScenarioIf memory resources are low, a degradation mode is acceptable if - no data from the database is lost - the focused diagram is displayed correctly - the data export is works reliably - 3 undo operations are possible In degradation mode, the following shortcomings are acceptable: - not all diagrams on a screen are drawn completely - the list of search results may be truncated - the number of simultaneous open windows may be limited/v)7Va55964c1-4f62-4821-b69f-bd34131d07a3[#  U UcAesthetics of Auto-layouted diagramsRhb47e7da1-5f0b-446d-bc9e-7b123f8d953a 9M^#p5x9<  UusesT-9447164c2-7a1c-41e1-a218-7c197b0eb00f8  Ue3092da3-4c06-4b77-bbb0-12eb955286c8 9  U,i0d3059e5-e6c2-4d75-b2ad-42f574d597d08  U37ce6809-22f8-49c6-bbbd-880b661a95538  U604a8b8b-b7e3-4ae1-a412-e56698facabb9  U,%P7ec2a0ed-f9f5-4ffa-b44c-e13e2b2b54b29  U,,af4b4a38-e97b-4301-bebf-2f07d1aee0a98  U237e8aaa-5b7d-44da-87ec-e8bcc18ea1bc8  U5eae44e4-9177-4aa1-bed5-357fcf5d14a78  Uee68eed7-41a6-460d-b76f-409201e5cc7a9~  U,0^A2fcf09b8-ac54-4516-a6ee-aef20e758a499}  U,qZ49573e6d-5743-44cd-8151-d157039e0a439|  U,&bcfe5b5d-10e7-43bb-9695-6fb8643912249{  U,3581d6bb-f4b3-4d50-9aee-6497bb056e679z  U,2e24eb072-8ef9-4039-8288-8463f3fc87808y  Ucfeb670d-71d4-445e-bbaa-5c9ad2d8ec01 Hz;  MSU}ctrl_classifier _policy_enforcerensures that application level policies on the model are adhered whenever classifiers are modified.vL7X7b221c35-a87f-4e56-834f-9d58c6d4aa83  ;wU}ctrl_diagram_controllerperforms changes on diagram and diagramelement tablesvLF46b9cd882-b492-4dfe-90ef-cded80288acbO_  #=Uygui_toolboxcontroller for the buttons in the tool bar: - performs the callbacks when the user presses buttons - switches between search, nav, edit and create mode 5  ϙj4fee1430-f181-4761-9e89-e8e42a9f389c  1wUeUnderstand ProblemUnderstand - Use Cases - Requirements - Quality GoalsH_x_x056d2b28-ae9a-4fcf-99d0-e996dfb28d38 +_+I`  %UcLocal AssertUse "assert(COND);" statements to ensure code+data consistency within one software module, These are executed in DEBUG mode only.,a038f519e9-4312-4509-9095-801aa0025a923_  !eUTrace-GoalTrace messages shall be activated for debugging to follow the program flow and visualize the processed data.61@g04f43ab8-6226-4a7a-a1df-42c9ca521b61,^  [ULog-GoalLog Messages are written during operation to be able to analyze important events, anomalies and faults.61@4!7bb75c8e2-37a5-4686-8bd3-e6e20124485c]  #7UAssert-GoalMaintainability: - When modifying code, illegal modifcations shall be detected early Analyzability: - When receiving bug reports, an anomaly in the program/data flow shall be detected early Reliability: - Errors in one SW module shall not cause errors in other modules Testability: - Assert-paths in code shall be testable3vW[JcL2dce9493-d549-4f21-901a-477b34b24ef8 !Rl!yNH1  ' U{Output Streamqy>Aqh1c5bd3a42-7b69-4357-bc3a-85e6796bf969O0  5 U}Memory Output Streamt>Aq23e4b07f-2d1d-432b-912b-d37012355cdeM/  1 U}File Output StreamƵr^>Aq =40642860-97d2-4734-987a-9bab181888b4A.   U|streamtKtddc6286f-31b7-49a0-a9bf-79bcb3fee57b>-  WGUcsort classifiers by number of parentstraverse the list of classifiers, not the diagrams; export each classifier together with all children pro: allows to export the expected xmi structure con: difficult to implement, diagram descriptions are lostSɱcO 7fa00851-3ed7-4f78-a2b2-8ef0ca33d1b9,  7qUctraverse diagram treeas for other document exports, simply traverse the diagram tree in depth first order. pro: simple to implement con: the hierarchical xmi structure cannot be producedU>jƒU&ƒU&bc624098-b90b-4e1c-9012-df77dbd8cc40b+  Y Usame as doc export is chosen in 1.23.0h3]F6fda34d8-d2de-4482-892e-b14cbd1c2b54 [2Ab[E=:  WCUclass=:  WCUclassifier list is iterated in 1.24.0classifier list is - sorted, - iterated, - containment parents are descended to childrenh3˒@Wd13c4d3b-e42d-48d2-bc3a-7e5f730e1e6cC9   UnrunmodesO(ٳ(5ccad7c2-c35e-4cf6-9a9c-226e65c4eae2M8  1 Unpencil::activitiest cb465a20-f803-409c-8ba7-ca4a2d11563fD7   U}md_filterX}+ef415086-85ec-446b-8a84-deb484e8393eE6  ! U}xml_writerqyb5960f34-5328-438f-a755-418e58dee838E5  ! U}txt_writerTV5d2dae5c-4cd3-4d91-9b9e-a889920affd1M4  1 U}xmi_element_writerqy͍26dcb480-f664-470d-8295-6c5e2a62fdb9V3  C U}io_export_diagram_traversalTV0 r`5d65a7bb-a999-4b8c-822e-6b57bd71ef7fJ2  Uydocumentsdocuments implements several strategies to traverse the model and diagram trees. For each found element, an element writer is called.X0 z rc86fdef5-cb67-4564-80dc-501c5ebc0035 B 00G~LsB}}G0J  ) Upencil::finish>xx3fd34e00-857d-4102-ab89-69afd3cac1cfa  Y Unpencil::relationship_layouter layout_*e5b0&8872f06c-e059-49d5-b58a-2eef13044458]  Q Unpencil::feature_layouter do_layoute5b'r08f63e9af-5744-4f8a-9d07-dd19359f4e231`  W Unpencil::feat_label_layouter do_layoutۿ)(%P28192b4c-1328-441e-80ad-6eeb236ee4b5v_  U Unpencil::rel_label_layouter do_layoutۿ0^A,1d425581-9a8a-47ff-bf3d-7d4578c45889G  # Upencil::end*300^A1626a838-e9d4-4f8e-ab3b-20e59b72bd0eI  ' Upencil::beginqZa7a5cc9a-fa22-437d-ba75-5e7cef2c4b46_  U Unpencil::classifier_layouter layout_*ۿ2c45c0b81-44e6-451a-baf1-54ad5be08e86T  = Ugui/io select operationsϤznSS573662cd-6bb8-4c11-ac26-d5e7e6c751e5 pe4h3l8p?1.cU 3033077a-fcee-4bf1-86a2-53673f40e63a.bU e33da6f5-d1f5-47f5-8a09-381e97a7a40d2aUf887851c-6a50-4eb8-be60-6c2d0acb0a43.`U e23fda63-a6ca-43d5-80d1-f3572dc27ad51_U ~c320db30-ee2f-4114-952b-c09efe2dc513.^U d3319ddc-c34d-47b0-8d39-ad40fb134450.]U 31713fbc-65ac-40d4-917a-879202f355d1-\U }70b1099b-0879-4a0e-9226-1f2f3e89209e2[U 551198d3-a553-4936-9b29-723cde0952f82ZU a1c461b5-2e34-4d7f-97ae-c87ef6af77bf2YU 65d3f4f4-0de4-4570-a312-5021f74d985e.XU 5c0bd246-3c08-4e84-9212-ed8d0f493bab2WU cc49069e-0fd5-46ec-98b7-796992c6124a.VU bad5cd13-edd4-42ec-b2f8-01fe9b223af3.JU2ffd5de7-c526-4261-9563-70d3e33d232a2IUe16ae345-a161-4a56-9be2-0c402e7fec32.HU4e368edd-bffb-4283-8a20-4fb305d380262GU3f19a76e-c385-4088-b323-7953fab17a73 /B8/-) -CIUcfuture extensionLimited dynamic allocationsMemory may be dynamically allocated from heap for non-base use cases. The program shall continue operation if no memorry is available anymore. See D0067#name.NLŕH89bc59431-fde6-44e0-a341-dd5df458b93a)'  -GUeDegradation ModeIn case of low memory, the base functionality of crystal_facet_uml shall still work reliably.4]]օb26ddaa3-7edf-4d43-adc5-9b34ceb3c95fZ%  K UcCompatibility of Export-Formatsn2n2fab9acff-877c-44be-8a70-8e24617fa96eW&  E UcData migration at SW Updatesvicd8ef8e06-aa6d-4f55-ae1c-460f1835cb5fd*  _ UeHow to traverse the model for XMI export? ˒@W˒@W18214a24-7e32-4d13-8023-8ab20dcba3bci$ 1'+UpSW-product-qualityCompatibilitysee D0069#name.1@,g9e108bf1-e923-4a5d-b68b-998aeb42ba52 C?Lr%%C?  % UeExport modelCu99d03c55-2113-44e9-a536-60e3273d5735o>  -QUplanned solutionpro: - simpler to implement - less redundancy in database con: - less UML like - no clear separation of model and diagrams - no solution for interaction fragmentsgɱTE8b9221a3-4e16-422c-9f27-d4094fe5ccc2=  Q UcTraverse the corresponding diagramTraverse the corresponding diagram when encountering lifelines[['_,?'_,?4aed4e01-b787-4f8d-a486-b6b0e6dd9eb0a<  Y UcCreate an new "Interaction" Classifier[[**dec9b675-14b1-40f8-906d-f918555a47db9;  OEUeHow to generate the Interactions?Interactions are - Sequence, - Timing, - Communication and - Interaction Overview DiagramsS*0@Eaeba770d-7997-4d8f-89df-d3394cd0ee82 l!A  U f5df24c7-d6f6-48e0-9ecf-1e69fd6e84366=  U 060477fb-eb59-481d-955b-bf069c146d4c6<  U  d3395df5-52a4-4611-8f24-627648f6fdce6;  U  81020e47-7106-4bc7-8466-d206e908553b6:  U 7d1e4c9a-ae24-4f79-a945-ada4c0bd389869  U 42beb51a-6270-4724-bed1-46f5658e979868  U,! #0d4c01bc-41c4-4389-bbe9-4e03c723228a hUa,{D h~nV>>tt5jf 1SUDAselect non-DB fileTry to open a non-sqlite 3 DB file.c728c184-fd4b-4894-bc75-29f1110c53e47W  U,F 9cfafe5f-a716-4321-9083-ba6d3c825f395e  URPd737020c3-1d40-4200-aefa-b7e3851ff0695d  URT`78413280-d358-46b0-89cf-e5ca1a4185c6;c  UTTparentPc78b70bb-7942-4197-8527-9896966380037a  UQPto,aa56d14a-e3ce-4ca9-97d9-cacc49fd7fb19`  UQPfrom(3c38c01c-4452-44e7-a949-6116d1167e553_  UOMa9f6ca93-407a-4e27-8233-13e8dc47e628;^  UJKsolves3b8a13bc-58df-4120-afac-f4ba91882d48;]  ULKsolves 04de34a8-48b6-4eeb-b4f3-69257ccdbcc4;\  UNKsolves73622463-5ce5-492b-9a17-4c1b7d22ebc2;[  UMKsolves350be467-74fb-478c-bcd0-17a3a376f72e7Z  U,I3239ef59-8bfe-47e1-940d-367686496d877Y  U,HP7aeee17d-f20e-4a09-8c66-004c38f3ad937X  U,GD27b0c65e-dd4e-4e37-a72e-7472c2f51c54 .Rj*Jh.7  U,pv<&299247d4-6a91-410d-a301-9031b5237d9e5  U,ou4288f1bf-7741-4534-ba7d-f14c0039767e5  U,otafe254bb-4af6-4d23-8705-5fa4db495ccf7  U,!bO11cf2b4b-722a-4216-9bfa-bc2689647c0c5  U,osa5dba126-bfa2-423a-be07-eb31a59adac45  Upo 3592750d-fa2b-43bf-b936-4f9b1a35ae235  Uqp1a0117f0-cb75-4e81-912e-aafad44afe6d5  Urqe95bff86-140f-4ca6-b0d7-c5979c1bd2405  Uaja8e9ad88-4e4c-4130-814b-d89a3f7e3589=  UjWsolves68ebd2a8-d49f-4de3-8504-9dd0451643987  U,"i֖ b33a3b26-aa59-4d09-8b58-4a78793ddfca7  U,"h֑v[4b74972e-6432-4dc3-b9e6-809098cfe5357  U,"g֎=Ab133dd80-17dc-4738-a41e-272fd47a2dd97  U,"fj52feb3f8-bd18-4de5-a1fa-233735f490987  U,!eI9a2dcb5a2-5eeb-48c4-8eaf-f8544f39c7c17  U,!dV07fcad04-4b42-4a4a-be8a-1efe861d85b67  U,!cI8654776c-0e12-404a-8e67-b74551e7ba64 7OPa%s7p9?  U<&a51ff05c-d472-422f-bb09-7e5b3f9ae97c9>  U<&7e688e04-8c49-49c3-b1dc-0e28be81daca8=  U}<&f3b796fe-e7db-4bc6-ab57-6f0b46f730ea8<  U}<&e80947b6-d013-4d0a-9d96-7659bf348b7798  U<&13377695-31eb-4799-aa28-ab6581cbeb5587  U<&f589a477-3533-4ba6-988f-072b0f0fd45c96  U<&3da6ac77-b077-41e7-98c7-81ec4935b8ed95  U<&18a0f68a-9932-4677-b81d-1e42cf631aef94  U<&2a0496ee-3110-47e1-8ebd-73047018d28193  U<&4d5a9aee-f151-4df3-b292-cec8fadbee0782  U,p<&20a1d03e-8947-4cae-abb8-f8222b2a6ea271  U,p}<&db6c1143-72e3-4670-bcf3-a9fb7d89c157K0 3 U}featuringClassifier<&27d8eb32-11f2-4608-a957-d54ae9103dc68/  U~<&700fff45-0d0f-4bae-8e51-f672bf0c2a3a8.  U<&44a684f5-d546-44d6-bff7-23865874e0898-  U{<&38b81b4c-e464-4502-a74c-a8bee0981e7b (LWYb(7c   U,ib1ba7ba9-ab9c-4d41-9cfd-8302f7edbe18:b  U*has 9b44a063-93c1-48d8-ada0-1aaa694aa5178]  U,/'157ef5c2-9797-4285-a121-b50273d1f016>[  UcallsTM49ec8f92-bb63-49fc-a975-d657016d70ea;Z  U(hasTId1ff7361-4151-4dbb-bf11-3fed7c45375f>`  U.analyze̴19bb5e06-f2e6-4534-ab89-b5b5b10c59bb>_  UcallsTY35036a67-ac18-4f3c-a870-6b4e26d0f5b47a   U,ϙj1a269448-a8b5-43a4-9fe7-3794311cc7a7>^  UcallsTU8df989ba-dccc-46e7-8d81-0a099e4c1cd5>\  UcallsTQc7814d42-b75a-4f56-a80d-29412044d8ea8Y  U,H %2a025529-3836-49d6-866d-8d5e382465ed;X  U(hasTEba92acdd-b494-40dd-9278-b5df85da3e418W  U,L8912224f-e0c8-49bb-a0ed-8d0b11d6c83a;U  U(hasT=4a6e85a6-37a8-4bea-ae76-584b77f86e638T  U,T9271fe82e-9cd8-4f9c-9bf8-e0ddb0957d958S  U,P*~fbc7af29-14da-4068-a6c9-3a08a960120b vT]#qv222>9  U,T$93da24585-fe6c-4175-a51a-bb64d8863a07<  UusesT%9e94b6f0-d96e-4048-bdca-3be073438bc8;~  UCquit6e0c22d9-5d6a-4ab1-81db-3f3cd050eec77}  U,D543d38c7-aecc-458b-8a81-b0a20c039dd87|  U,A9a01fbd6-daee-46c4-9d17-b26bbe68a9467{  U@fa454d03-2b2a-446e-a8df-ef374680a0569z  U,b9336134-ede4-4390-9a35-8a315e64c575Cy # Up<><'41266707-cfa3-43b7-be26-58eef00d0f8e8x  Uo<'^429fc16a-50d3-4541-b5a1-077381b55f027w  UT#b3f31b27-e34b-4e72-9f81-0ccb2c2d80c76v  UT#9268386a6-fbbe-4c7f-b656-fa0ee500ff4a6u  UT"5ac6414f-d2dc-4da4-bac3-26cbb1d7465b7t  UT"9669b3fd0-cb1e-4302-901c-67fe1c0c175f wLc)q1wqZDDS=  UfromT*4e84bfc9-5bbd-4d12-b748-c8fce27b11c29  U,ȲDd82a1a51-ea5d-4b65-a194-ae1fdb7d9684;  UtoT*976339a77-9622-4c9e-8fe2-b17e7d257c41=  UfromT)d6142909-7e3b-4588-9770-4427c6112a2b<  UQdataT)9824f7c1e-421f-40d5-8ab7-806256c9f1ae<  UTdataT(d8f6664a-d072-404c-a183-ad8e43274e707  U,ST(91c890479-4c4b-4efc-99d7-b9b31a2637f57  U,QT'9e34fc1f-6cd8-4177-87d4-544cf357439c7  U,PT'92ac8008c-d24f-4e79-906f-109eb6c005607  U,RT&0164589d-a5c6-47b7-9431-c400ab6e0b857  U,TT&939814d9a-1abc-4622-8554-22833a61a6f28  U,T%3a50f7d4-d125-46a3-ab6e-2607486804c79  U,˲D67c70287-a27b-42e4-8bd6-782ac7650a039  U,ʲ16790374-70c7-48b1-b0ea-e6b6b5d33db69  U,ɱ.ejfb49a824-fa2c-4ec4-ba97-d7c663e41f02 2Ui.s2n2S===9:  U,T,5cdf2d26-3d78-458b-9211-17cf6586bb8489  U,T,96f20ff18-b545-4f34-b677-42e344096cc0A8 ! Upack itemsf8d71cea-58bd-4091-8201-abab653b4d41B7  Urun_suite;Ư3e3e82d3-a6cd-43db-ab79-eb262665a01c>5  Ucall:F66fbeb592-686a-4220-b85e-5c6db896dd55B4  Uaggregate9Ư4f2a6418-1a5a-48f8-a6ad-a701bae9fee083  U9F8c25d6b3f-59aa-4416-99bf-41c3f701985c82  U8Ư7b6c1330b-8171-4f38-b4c6-fe9f2370b74781  U,ﲉ23ae543d-6ac8-4632-b86e-96a87588423b80  U,r11244bda2-1c09-4942-b234-1a90e0dfab708/  U,6Ưd4da44a5-5280-4719-8a02-c7d5d7efecbe8.  U,93562dfb-bbee-4795-93f0-37f70ff01a058-  U,O fabb6e93-7be7-45f7-9177-5d533489f7ae6,  U1a3b751d-06d5-4ce0-a4d9-42230fe937646+  Uc1ef0d42-10a9-4187-b76f-7523014d8dcd6*  Ucfa8a10a-5102-4b9f-bc2d-2517e99b4d6b Tk#a{BTooo8V  U|<&4b497e2b-9Y  U<'&78fa7e42-4a99-4c29-bd64-6cd668aa015c8X  Uz<&558fea03-8cb6-4655-b0b1-77dfe623d6899W  U<&32cff7b5-b243-4dd9-bc1b-f31e1ca101f28V  U|<&4b497e2b-0282-49a4-806d-c569c3fd9a166U  U9d24b9ab-f176-44a2-bcc1-03a17d14c19aIT - U'%get_database_ptr)"?=af4c7224-ed2c-49c3-bf7a-118273525b3dJS - U%get_database_ptrk  UrunǂDE7e3375ce-9528-4704-8b16-c30aa947ba42 *KdH( |*O 5 U16.) character stream^iNO4a593b8f-5941-43c8-8354-d70f40b049adQ 9 U5.) document artifactsJZMNc8d97c97-9455-4402-ac40-ead7fb59e13a9  U01u 6a2394f5-3f7b-4903-96b5-70231f004c919  U,.13ece0f65f-3286-4468-b7b9-c98e911acb329  U,./ =04c6c1ef-bd02-4dcf-bdde-60511cbba2d68  U,.t7ebc4b07-f020-4381-95db-9dea1a59faba9  U/1uc749a22c-0acf-45bb-a47d-c0dd7866a97b-9  U,.00200b1d0-aaf1-4c42-aa01-4df2753e4c908  U-*8624217d-f2f1-4af4-85d2-a03d48a110e48  U,*3d0081dc-62e1-4a1d-8cbd-506caff291176  U+,9f858043-0ad7-4322-b213-abbcc902e59b5  UU*0d4210d8-d84e-4502-9f94-fa862247be5a8  U'a4dadf28-7924-449c-8284-44d1684b22ff>  U 'explainsd7895f61-a149-4628-9d95-c7afa1b313216  U 8dd98887-cebe-4550-bd80-24d48694e6c5 K7CUvK8<  U,8e9cd6383-94a8-45cf-bf52-a9dc8dabb87d8;  U,81831a6ad-8fc8-4cb3-81ae-d78656f28eab89  U,8 32eabc48-35d0-4b02-87cf-cc99747d85e688  U,833b70482-62fe-435b-8a6f-6f6207125502=d9eddd34-68fa-4e59-b6af-dcd04d9d2a568F  U=;f226ccc7-f1ef-415d-80ca-5e7422c69c3d8E  U<;5837eb1a-6b9b-48ec-9cd8-d1a5ec6edab38D  U;-301a6308-7baf-4e89-b299-e140fbf1e5746C  U:-ad04b376-0b4a-4708-9d51-93285c7d97d28B  U,9c9c54762-862d-4d2f-ba95-ae812069ba8c7A  U,9C8686a9ab-d982-4554-9e2c-9b7f3e545a847@  U,9B4cb95c1c-8613-42d3-8d66-2fb52d8266008?  U,96bcb8ab4-6fec-4722-a06d-56379717c31b7>  U,9@b42c8f35-f85b-46d4-9bfe-2b732b4653cd8=  U,84fcc4bf1-7d51-4078-b52e-8e60e0dd469a m2s80u:2mm8Y  UGJ5ac787c5-bc82-4e77-8ed6-2f7d428d8a0bN8Z  UHJ352fbfea-8565-4484-8763-fecc91f2069eAL  UBCload data785b1a6c-b7aa-4366-a916-dbbdeb67dad48X  U)'344782e7-0c0b-4cbc-94e6-19db4442b4388W  U'5c403eb3-4d00-4936-b157-bac28568479c8V  U'18081db6-2b01-4508-abfd-cfd0e94e898fBU ! UCBinvalidatee1828cfb-eb76-4ed6-8ce7-e88d242a275cST C UEDdo layout (drawing context)7e1001f2-9f8e-48e6-8795-73387e81a84c8S  UFEa08c8cb2-c74c-49db-a14d-d24ca4adf5449R  U,CF}(aeef42fe-c8fa-4131-a81e-ebe36102e2f58Q  U,CE33ec9f33-8310-4c04-a9de-75f5c46fa2e08P  U,CD77c53030-9a01-4011-b86a-3489274044229O  U,AEWa846ca20-d857-4416-9225-9bbb2717d687NN 9 UDDdraw (drawing context)74283763-e0f9-495f-a9a7-a51be4586a2b 7u:F ^#r7H2228j  UYO94ad0bc1-a321-4aa4-89d6-89484a57cf588i  UX2d2789de-c6be-4906-8f51-71522ed071dd8[  UKLff92ae39-cfad-4415-8908-b384e51c40aa8h  UW296fea19-15d9-40b8-995b-67cb0a8965ee8g  UV7edf954b-2dc9-4a8c-a7f1-e6d610e4fbb86f  UUS6da54af8-df1d-4b8e-bf3f-bbd0f0fa3d0c6e  UTRaf9e0553-68d0-4b8d-8878-2769eb45c2b58d  UQ46dc0b41-6ebf-44a3-92fc-73fca162fb838c  UP82d6d9b3-59a6-4307-a5e6-6300017801508b  UOa450019a-a0ab-4f32-a83c-475510b97985@a  UNLhas 1..n15278a05-67e2-4386-bff8-edd0b04ed1a98`  UMI232889c1-a8e9-47da-9875-398b581de0018_  UMN926186b5-7697-4ee1-9e55-ce737a6436b28^  UMJ655d35a5-f866-402e-9e9e-efb7d57b7b2a@]  UKIhas 1..11ad4beb2-252e-49f3-bb1a-bdbaa2d44f69E\ ' UKGmay have 0..1cced21ee-4779-4b26-993d-d5bc8bab125b  Oc(w<PG$waK55588x  U,fe3228f70a-bbc8-49ed-b34a-eee3c94f61f38w  U,fd1f0ceebe-e1f7-4b80-8dc0-60b230b6702a8v  U,fc13d72bf6-ed09-4c4c-9c0e-73a15853da318u  Ucd58ddcacd-77bb-4ee4-96c3-3b6bb85ba5448s  Udeb39635c9-613b-4535-aaf9-05559c8cc9f38r  Uac136a98af-25b5-4e8e-acee-292fd297651c8q  U[?ca36c108-073b-48fd-9f62-94a4bb3a436e8p  U[@e643ca42-c3ef-4bb0-8dad-db8414a775a08o  U[e07466b4-db6c-4016-9fd8-52c29efa6a748n  U^W7a00b927-0d56-4589-8bc0-8c88a9d7c85e8m  U\V78a9b2ef-5025-495d-8723-ac33ed380e138l  U\Qe0e47f48-5f1a-4c17-8218-7bc38200423d; l.l.q/m-vj@5  Ulabel_boxrectT/9fe0f53aa-578e-4898-9d69-ce79923cc0e0@4  Ulabel_boxrectT.75bd95ef-bbc0-4a26-8f44-5f9c8ca9d99d@3  Ulabel_boxrectT.96d6ab182-bae7-47b1-a781-6c438e6169e6;2  Uspacerectf1b86d6d-654c-4658-a7f8-7deca94f7538<1  Uboundsrect40f7bf26-7e5f-4fc9-9d3b-f0b462bd974a<0  Uboundsrect7d042899-fe73-48d4-8fdc-fb19af86a0d5@/  Ushapeconnector74e09c43-1f98-431e-8277-8899ef6c173c=.  Uvisibleenum7b36181c-e1ed-451b-b70e-6cac8e710050?-  Udraw_arearectcac5bc7d-59fa-4487-b2eb-e8211fe3aa6d<,  Uboundsrect82523e4c-bd64-4efe-b930-7d484c5c348eJ+ '# Ucommit_buttonGtkButton * 591d65f7-a4f9-4cae-9519-0b77a24c849dF* !! UstereotypeGtkEntry * 41613598-cdc9-4351-ad06-af2ea1e918c0 J#Vc  =Unpropose processing orderFor the list of elements to be layouted, define the processing order.ڇaDIa2fc4ae1-af84-4ee6-a10e-db6e918c6237h`  g UeModify / Create / Delete Diagrams and ElementH8Uff6ef959-86bd-4278-b913-58ce7a7f53f4i]  i UeModify / Create / Delete Diagrams and ElementsH8U3d33680a-516b-4c0f-a0bc-8fd6ccb437e0Y[  I UeExport (Model and/or Diagrams)-IcO~+ 7db4676c-d805-4532-925b-9df162f9cadfLb  - Ulayouting:finishG }180d3987-cafc-4293-8757-a01046aa11e0Ka  + Ulayouting:start'aDIb61ef4cc-717b-4113-9ae7-ecf5f0e594ffT_  ? UeCheck and Repair Database#8wd9c05256-16cd-4208-8acd-8b449df3d412H^  ' UeUndo and Redo#e8e8197f-7ce6-4e0c-8743-841e75b7b0efh\  g UeNavigate and Search and Open multiple WindowsH 6dc4f9c3-0912-4d41-9072-1e98705d7e8c hh2!Gd  /#Unpropose solutionsThis step creates a set of possible solutions for 1 element to be layouted.QϖaDI#Lada01cf2-9948-4467-a97f-7be8413a7ff8h  YUUJson as second/optional storage formatRationale: A human-readable JSON based storage format allows to support the following use cases: - git blame shall show who changed model elements - git merge shall allow to automatically merge models - git mergetool shall allow to manually merge models - Data exchange with external scripts0'ƱRٕcecc002c-4646-4010-ba10-fff38ad176ceHg  % Uend of list?QG a L85264a07-34e5-4810-a3a8-e9b3e0393671Uf 3 UnconceptLayouting Algorithm>0^A+sc298116d-781a-4e45-a87e-e24be984fbfae  ++Unselect solutionThis step selects the most promising of solutions for 1 element to be layouted.Qϙ}З5a488c58d-781d-4848-96d3-0c03284ddae5/ wgw-J)Q +csUcReliability-ReqWhen searching, if low-mem, show only partsWhen searching, if not enough memory available for storing the search result list, the program shall indicate that some results are omitted and show only parts of the result list.!66457e0ab9-3a66-452e-b6a0-fa5b6473de6c_P +g[UcReliability-ReqWhen opening a new window, if low-mem, cancelWhen opening a new main window, if low-mem, the program shall inform the user and cancel the operation.!dixdec275c2-e994-45bd-b9b9-2572ffdbf76f\O +_]UcReliability-ReqWhen starting, if not enough memory, stopWhen starting, if not enough memory is available to operate, the program shall inform the user and stop.bRj2u26eada05-fc48-4a41-ae08-8aa42eb4f301N  3Uspacethe rectangular area of all contained compartments (except the label-compartment) g›ʡϯ5aa14d2a-6ab4-4843-98c5-9fdc05badd67 #//pV +i{UcReliability-ReqWhen navigating, if low-mem, show placeholdersWhen navigating, if low-mem, the program shall show placeholder rectangles where rendering of diagrams is not possible.!u`qod291f910-2e85-462d-ba2f-9dacdde2f25fGR  % UpQuality TreeTbb6fe156-8db4-4066-8e0c-d2961eeb02adEU  O[UOrdering by Use Cases / ScenariosThis section shows the quality requirement on crystal-facet-uml ordered by use cases / usage scenarios.6RS648e219a-74aa-4b7f-830a-93cf554436d5KT  ImUOrdering by Quality AttributesThis section shows the quality requirement on crystal-facet-uml ordered by quality characteristics / attributes.6Rba0c3f46-8956-45e7-9665-709f24a895e4LS  / UpQuality ScenariosTarc076f5da-39f7-4897-a107-921e44dacaf4 Hd3l::ll2/G  U.c506b0f9-87b9-488d-9b8b-102ea3a154ac>8 # Utear_down()8F40a36ae8-3b45-43dd-a150-8890a898facc:7  Usetup()7Ư979a25be-b1bf-46ab-a12f-431df6724c4eB6  Utest_case[list]7F88a4a83e-147f-456e-ae35-70c59fc5593e0F  U4cf05fc6-ee5c-4242-b64b-6c0bfd19188f0E  U54ba6927-a21c-42ca-9108-4d7eb19442490D  Uc2118a74-95f1-4a02-9a99-8a7d2517c1f20B  Ue938d652-cad1-44d0-bea5-bf45cecd0f4a0A  Ubf31f6da-e033-4f2c-8036-243f330bb02a/?  U'32e71cf6-be4e-413e-bf1b-3321ef52c0d1/=  U%04f7aa39-343d-4054-9ef4-6b679740e3ca0;  U11558b49-bc22-42b4-9782-efb857a1464d0:  U50f36ca0-773e-4884-ad8b-65074c2c996d69  Usigne24b0823-2f09-4901-8beb-983e4046273b ~j9uCB~sM1.UAe6e322f5-b165-45ff-96e9-2bd5b266d3fd.U@37f27e9c-6e02-4a44-ac5a-30e7dbdef775.U@fa6daef4-72e8-4e69-8cda-ef824975991b. U@4c0c4e42-7228-4130-b1cf-635e42558ae8.U@bdd94c16-10af-47ff-8b5a-07477eb08864.UA00524a56-13d8-4cc1-a816-7aca94add654 . U@ 8d46e2c7-42a1-4c8a-9487-d9ea70f8278e. U. 05909ffd-0145-424b-854a-e90553572689. U?,I5624a079-1ae9-4b18-968f-52db0ebba9c6/U?H486dedbc-b81b-4ca4-a2c7-c7812143cb9c.U> 386810e4-1e33-468a-868a-bc9e3f29dd5f.U> 33f34709-2b0d-4d7e-b80e-7900c549b34b.U>b7effe8c-4815-42b8-bb43-8dd54ad00ee5.U>8ba13210-5876-4739-8793-f347e379309b.U?.G0cdea500-4eea-490c-b7cd-fb0a60c406ca/U?F0776bd9e-0019-4570-b922-589cc38ee5c0.UA41eb3da2-c6ab-4a37-972c-48b1d6dc653f.U@ed48d711-20f8-41a8-9da8-430b7665c629  l$}K`ILGT 5 Upencil_diagram_makerhf6ef3b4d-ca9e-4866-98e1-3a96c109ac1bSS '3 Usearch_runnergui_search_runner_t PY47a256c5-ca55-46d1-b6f4-45c4ef7e97f30Q  U46eac473-636d-490a-a4a5-102c984e3a02/P  U&ef1ca5dc-361c-4ee8-a299-9c975d60610d0O  U1e24ebbb4-2e68-4390-9414-b5601178cbc60R  U31d5d8c36-04c2-40c3-a724-38bf291c9e790N  Uc662f6d9-856e-44b8-a03a-40441130c5c50M  U8011e15e-717f-4b81-88fe-7b15d1e59097AK # Ufile outputIFG3bb09b27-9dbe-4e87-9a8c-c5acd0836ccbFJ - Uclipboard in/outIF<ue2686347-6780-4e1b-ab4e-044dea0da234/I  U,87538a0b-c268-4bfe-a436-fde819fc84690H  U8b15d401-b02f-4dd9-91e4-833c3fe3fb481  '{4{6']|8 AoUNewly identified Use-CasesDuring development, new use cases are identified.77b03775-f77a-4870-98b6-ad3a46484fd0G6 9 Upencil: Black Box View 3cacdd57-770f-42fd-926a-b54e9f7839b9D4 3 Ugui: Black Box ViewPd0781a12-5f3c-4f27-beb1-304e32682578E2 5 Udata: Black Box View7e5ba474-3f2c-4b62-88a8-7fce5f67c4d980  U' Asserta569296d-b46a-4ba3-9969-a5db59cf5f38G/ 7 Upencil.layout packagefa9e0025-7987-4167-849f-299b9153dafeD9 1 U2 data: Runtime View421ef34b-ca30-41f8-a510-214266c7bdffI7 ; U"test_fw: White Box Viewdfa7b5f0-3a26-4ed7-89e7-b9283bc2293cC5 1 Uio: Black Box ViewH17db0a4f-717f-4b58-b3d5-a9b1a50bfdf4E3 5 Uctrl: Black Box Viewc5f05d88-8a15-4c05-b647-3d2416204a8f<1 ! U' Log, Trace93407042-9c6a-468a-b12e-03d9fcaddf28 v *1Mj*g>A + U@ Layouting Steps0bf50c19-6908-41d5-ab3d-bc1f56cb0eb5@ 55U6 pencil: Runtime ViewThis diagram shows the different entry points for layouting and rendering a diagram.a2f918c1-8bd8-4f9a-9d3e-3026a52c3b55C> / U4 gui: Runtime View65463912-947e-4e45-9d91-38b47fae6ae9C= / U gui search blocks77a82e54-c06c-4307-9287-66e22349c95dX< _ U"UML Structural Elements (Non-Classifiers)64660a21-d0c7-4482-8e8f-dffa10b9900fC; / U' Error Propagation1585cfe2-15e5-4a7e-ab71-ca5b20be6b82C: / U' Memory Management8b510983-9213-4d2c-891f-0a6947bd8549&VC Y UL Performance Efficiency (Time+Resource)1b36439c-7eb8-4b02-99ba-0afbaddde7f4?B ) U$Database Terms405c2e26-ec11-4011-9cf9-2b093720f675APD G UL Usability (Attactiveness,...)@1675441e-78ea-4406-a734-e0d68892b2f3E? 3 U> gui search sequence273a647b-6b6d-43ac-bc1d-d5887858da16 $-|l.w$QN I UM Program Start and About Window@a196f249-3f5f-49d4-bc73-1a358174f6fc4M /mU&Quality ScenariosThis section shows scenarios which are of special importance for the quallity requirements stated in D0076#name.3e1a17dc-0cfc-456f-834f-7973b5819d9aLK A U4 gui: Crosscutting Conceptsd37c5796-4375-4905-bb42-bca10099e020FI 5 U.io_export componentse7eda656-ea48-4f05-97ff-6266c7aebdb5gG -WU5io: Runtime ViewThe io_exporter sets up the data pipe55e179de-6342-443a-a830-1befe0620e8dWE U UL Compatibility (Replace,Interop.,...)@aa6a269a-4e7e-427a-a334-276ef4dc0fa0[F _ U Alternatives on XMI export/model traverse6b4f7663-f052-4cae-9659-d6a3f1f05cb4L %U&Quality TreeThis section shows quality requirements (structured into a quality tree)dbe52abe-e4b8-46fa-a96b-b0676b3d60a1FJ 5 UF Interaction Diagramsb637548b-18cb-4b1f-bd7e-9c43b582815aJH = Uuniversal: WhiteBox View2fd5e775-4030-4379-b909-8f2f42d400e6 QJ$a''wuuX +c UcReliability-ReqOther operations shall work reliable if OOMWhen the user operates the program, if low-mem, the program shall work reliably for all use cases where no exception is stated.&c&cfb8355f1-fd1a-4a6d-b333-e978b55ce208W +iIUcReliability-ReqWhen undoing, allow at least 3 undo operationsWhen undoing/redoing past actions, the program shall perform at least 3 undo/redo operations before informing the user that undo/redo is not possible anymore./l^x2a56adb0-aa50-4a1d-b6c3-9aedcde7fd7aAPZ  7 UeOpen a Model Database-IcO8Bs01b9d514-5bf8-4678-8ca3-1db7f63f5781YY  I UeProgram Start and About Window-IcOyo70e8a90f-ec3c-41a1-aa56-4c504998ffd5  3t 3Ngn  e UcDisambiguation of non-unique IDs of featuresM&9(1468f356-53aa-4aa8-b7e2-495530d37ee3jm  k UcDisambiguation of non-unique IDs of classifiersM섧xxfd3f8abe-3058-426e-9c3e-006595dae4fdgl  e UcDisambiguation of non-unique IDs of diagramsւ*܄xܮdcb310526-bad0-4ea2-b316-ca10d304a924Dk   Uegit blame-IcO톳See0e7dae-e437-45d3-be71-1b305ff6c842Qj  9 Uegit mergetool (manual)r2#퇕4be8010eb-d263-453f-9ce9-a93120bc35b4yVq  C Uchuman readable foreign keys bxUcka07ba393-d568-4445-ae94-ecb2d4c92564jp  k UcDisambiguation of non-unique IDs of diagelementւ*܆UckH641415eb5-5698-4dbe-a29e-79cbe2cbb488ho  g UcDisambiguation of non-unique IDs of relationsMUcke7af10c3a-0986-46b8-b0f5-731028d49572Di   Uegit mergedԀ!5d3968aa-9451-4730-a152-8c649a00afda 0AsDY*npA;000-OU Ke6ce2ba4-c25f-463a-8db7-53f42f672d8d1NU Jd862b18e-8388-4542-9197-e9d4e3e7d710-KUG0bc204af-7920-4842-9c6d-0e762a23bf38-JUF884f380b-49f3-4d79-a93f-0d707f634a44-LUHe5d0f33d-2861-48d0-85b1-41b00e0abc8e 1PU Le9c0b2c0-2edf-41a0-9625-bfed2d7651eb-IUE9339e3b7-14e8-4eaf-9490-7aafa05e7322-HU D21775342-36ec-4d1f-b02d-4e87145a395f-GU C427d41ee-f31e-467c-a7ce-01a02d5538e3-FU B9502e71d-12cd-46ba-8c67-7f84c2118ebf-EU A059224b2-1285-459e-b6e9-6ad8c91c1522-DU @c1f3a71e-3221-41dc-8f29-410d5bc0a410-CU?276e2d00-5aa4-4849-9db2-a6a519d53f8b-BU>dd72aeed-3989-4f08-a786-b16d2cb50a99-AU=3f0ef268-a76d-4353-9304-2b55da389987-@U<1b1d6da4-5b7a-4803-9f04-4f5a3b695159-?U;bf458a75-4a61-4985-9d0a-cbc288aee1be-;U794197942-b208-433e-a6fe-58e81a31c8b6/-MUI36bee925-12fd-472a-a7e2-b9253ef85d86 [g4pAV#[aTG::w1kU\2540efaf-4449-4f23-bc13-88fc9f04a47b1jU[627244d7-22a1-4d7e-b924-3707d6111cc5-QU M25e89bf1-e6ff-44d3-9eed-69008a25751a1iUZ1422a69d-2451-4c92-b5de-d1ce6386f9d71cUYf07c3d29-b88d-4873-89e9-9433116d701e-bUX90a18eb7-16fe-48b2-b6b5-90e1f4038aee-aUV8e08d66b-ab24-4822-aac4-a300bc589919-`UWfc0c3696-51d4-41b8-90f0-db87a593b7c9-_UWdb842840-0712-416b-bcef-a97b69009558-[UK15105a30-ce50-4e74-b3d4-46084fb4c08a-ZUV6b1a16f5-a9d6-47ba-9cec-17a19df68f3b1YUUeca3509d-628f-4382-bb61-8eeff1552d5e-XUTc2418424-971e-498f-8daa-1133cbe766721WUS67248af1-d809-4bb8-8a9f-127a8a5bd98d-VURacd512b3-04bc-4916-93a8-b4d5a34626851UUQa1192a3b-ef39-4cec-b1c3-1c04fde687701TUP7923ca70-634b-43f2-a9c0-0168083e5d5a1SU O59adb6b9-cbb7-45eb-8eca-66dc8006559e1RU N873e1630-4b66-49b3-a6df-c4cb53784c8f `8l< |L0h8`-Uo22e090a4-fad5-4ca9-b3df-c7d3be2b7c761UR2d02f8e7-5003-48b6-86e9-b794dd148b461UPb5e54644-0cb5-4f4b-ad33-ebfb4079e904-US6ace80a2-6716-4f57-b27c-24c237505b6b-Uja18910bc-53a8-4529-9ef9-a1132f13cd2b-Ui7d49b1ab-6cd7-422e-97fd-0c514a6db2f801UT0fa7bb55-302b-4769-8f36-a7047c9fe71b-UQ24ed4f1e-614b-4c96-aa92-f013e87ae134(-Uh7c03a6ef-002e-4f90-98a1-a00e7f4d4bcd- Ugeab11581-44f8-49f6-b03d-dbefcc3efc9d- Uf2c9b5d00-1d8a-4182-bc51-cb8b5f69de6d- Ue055f2a8e-b985-405a-8806-1d1862eb6bff- Ud0bc42d1e-fdbf-419d-bfcb-986cdbda7690- Uca43b072b-6642-4c18-97de-c086e7d68f55-Ub735be989-0900-4c42-abae-682645fd2d541U#c552b182-be84-4b4a-93ae-7d964e632a6b-U$498389aa-7a0e-4462-a979-9987509ff90c-U!347e78d7-17c8-45c7-9480-d240c6dded99 Th8xHLTxm^OO'--Uvadd304a5-3e45-4c20-a459-e9504a5b1a181,U2331f805-7733-4e0b-98e3-df71db7471f31+U~9683ddd3-0d60-4488-9f8f-f735d45ad072-Up9c398172-645e-4c0c-a154-5add1e44d783-*U}47fe9918-1dc6-4897-a7b5-53e5d244b2dd1)U|bc28c482-9bbb-461c-aaab-6806cea5e7891(U{36c5d2d7-3c25-42c7-888e-057ace7fb3c71'Uzc80d1aba-05ca-493b-9f35-4d000eb9421e-&Uye33259a5-e5b9-4dd5-94bf-8900ef7aac81-%Uxf0572cb9-49f6-404d-a514-c6c6c14edd0a-$Uw9758362f-e29c-4b83-ab90-7c74985bdc36-#Uvcffd06e9-7bbd-45f7-8b4c-641f5773c396-"Upd9038186-29b6-4ed2-a04e-42b23b1af43a-!Uo032fd8e2-a1bc-4e6f-8271-4a131b7a57d2- Uuc2f970fb-72d1-4e98-9aaa-fa5a4d5fe95d-Utf4ec33bd-2c8b-4ee3-9a28-4e339c4a33ed-Usf06af169-5139-4211-b646-1fc0d9f5e47e1Urec6deaae-d49d-4f70-912a-c4651c5b74f21Uq45c8e12c-9b07-4a08-ae42-2aabc994ac0f ^n= yHS"^~rfZNN.vU"8ea321dd-65a3-43ef-9e38-dca6e0c1a3ad.uU"f1ac68d1-48bd-4318-b4a9-6d4d6f5b0f13.dU a93bf079-148a-456b-b979-e4d61037ea68.tU"f82ca5a6-04f0-4ce7-ac5b-1ea35449dc5d.sU"36899349-e49b-466f-9330-23ad36096702.rU"6edde2f2-7194-4c87-bdec-a73e3695eb1c.qU"4cf92ff3-72a5-4776-8655-fe7b23eb8810.pU"e1bc8cd0-7da7-4c97-9c61-d29cfe3193f4.oU"6f41c6c7-f3b6-4b85-a07a-eb55550da893.nU"7eeaf22b-1ee8-4ccb-906f-d38d415b41c9.mU"9676e9d5-8ba3-4e3a-8aa0-c47cc5a25ee2.lU!17076127-dc01-453e-8b21-56d00bf05c06.kU!c67cd938-439f-4098-8b03-cbfaec7b3f3c.jU*300a389f-5699-40e9-9be8-9b5465ff55c8.iU 8fa46b82-cddf-40c6-b809-09fde0927c30.hU bdcd93b3-6721-46b5-8e96-fbdd91c74085-g U1264ec37-5d65-4d5c-b164-82a0c6976c91.fU 19dc324f-0ad4-4c36-b699-8a32f044bd1a.eU c63e48ff-ac27-4dba-b48a-817437fb5b69  "js"UNx  3 UyMemory Input Streamta e"d33c57ae0-ab84-4308-90f0-96a1de9cf49dGw  % UyInput Streamqya ^fe45b491-ff33-4c10-aa40-b5afd0affcd5Gv  % Uygui_nav_treelP(P237119b0-bcbb-4b6c-ba00-a7d6db75f73fu /U}abstractio_element_writerThis is the abstract base class of different writer objects.X6gҍb34ed24f-5b72-498f-b48a-24276e340253^r  S Uedata exchange with external scripts b42 ]42a10aba-e450-4749-8543-0340f33ba69bLy  / UyFile input streamƵr^a a 49625329-ee5b-434e-93cc-6e2b4fbe24bbRt  ; Ucline-based data entries-IcOxxef416f1b-e7fd-4fb9-bf5a-30ba84134de5ds  #GUegit supportThe model shall be stored in git in a way that git blame shows changed data entries, git merge can automatically merge git mergetool allows to manually merge-IcO42 PyFa3574e32-b14d-4816-8d57-9a083d9cec70Fz  # UyUtf8 Writerqy4bdb311e-f904-48b1-a6e9-e9e2b0972ca5 4n4?8[  UHStream101301fe-e0ab-4ba4-a899-ec9edcb615beIZ ; U gui event notifications60eb3b2a-f8c8-4874-84fc-dca0cd7e8d7fEY 3 U JSON Storage Format65f3b5b5-0e8f-428a-bfa0-e9cead826b18 Am< xG: rAk .%U/245a8c37-27d7-4ba3-b664-e322ec3761d4.$U/b8076ec4-eb1a-4b73-994c-986994d380692Uda1b48a9-77f0-4f87-9f28-b7d6629d9099.U.9960eb20-0069-428c-ad18-d8cfd51bc835.Ucd509846-0902-49f4-a565-d1ad083969f3.U f0952538-c0ba-49dc-96b4-a42aa7167ce6.&U/fe1e7b2f-91b1-4ba8-a4cf-15e90a8b741b.#U/6acab614-e9fd-4be9-be9a-d7e78becac38.U/75a99553-46a5-43f7-a895-1403d70503d7I.U e8ce932a-d5b8-4fbe-83ad-1e6fe7f08716.U-57ae94b8-de24-41f6-bcd0-c2f341b059a0.U-f2c286f0-9402-4a5a-93ed-7433a964ccaa.U6fb3f5b8-29a8-4a37-9882-096dae520a42.U!62b8ef81-069d-454e-969a-2c1af621419e.U%98cd77aa-2986-4ca7-bfc5-492ed46d6663.U%5119a3b8-0600-4de8-9077-8fdb0f79b089.U,926226ce-dc92-46d3-a961-eb10afe2f3f7.U,c48d20e8-3ce9-46b4-b2b0-bc016f6dd729  =IAx`H00k8  Umi4bca6bd1-8ff1-4470-beaa-754bd837341b8  Unia3f7b8eb-ee88-4d66-9ebe-562038bd770b5  UhL01ed715d-3bac-4126-94c9-7397034d4645@~  Ugbfinished2f5dab00-66ef-4436-8aa6-f993ed37dfa38}  Uegffdea0eb-fd13-4cbf-9c29-94d1c484c01e8{  Uf87461be5-c067-41ae-a5d1-eb2e1ee3b91d8z  U,fae316ba32-002e-4adb-a7e9-b4d9890048008y  U,fbdf33bb83-82ab-4e36-9b44-6139474559068  Upi36873021-2d66-4451-a45b-506ac2e5245fS8  Uli1e0186f4-be03-4ab8-9c62-c99b2e1b4b5bE ' Ugdmore elements4d92aa67-0797-49ee-9c50-c0d0a43e42d69|  U,fga L7a64cc98-002a-43e8-98d4-80236e8114a2; n $C3 $n/X GKU6 pencil: Crosscutting ConceptsWhenever one of several layouting solutions shall be selected, the following algorithm applies.5d1cd0c8-fa3a-47f1-9f39-ff1740a4a074HW 7 UMOpen a Model Databaseke2c3aebd-70f4-4d71-a2e6-bc48c70d8d62LV ? UMCheck and Repair Database@?e69ec7a4-07df-4d94-9c9f-dea24f531e59!@U ' UMUndo and Redo@?265fac05-4f62-47bc-8980-84c28d9cd97f`T g UMNavigate and Search and Open multiple Windows/2bdd3766-2cad-4dc2-9e2d-161c6d7791f6SS M UMExport Database Model / DiagramsW4f252669-28fb-4cba-bf83-ea328ec874c8aR i UMModify / Create / Delete Diagrams and Elements b55ea0cb-9581-40a5-a983-877243c8c6ddVQ U UC Reliability in Low-Memory Situations94d2390a-b71b-4748-96df-54e6b4941e7bBP - U+"GUI/Pencil Termsc775592f-0fb4-4afe-9094-20f2b08210f6wO %U+"Pencil TermsThis diagram explains terms used mainly in pencil module.eb0a4fbf-6907-4092-91ac-502bb1ca8aa3 Ed0d3o> vE|qfZPEEww.GU018d30360-e056-4397-9eb3-ce6759165382.FU1081b5b50-c616-4b22-84be-70f3c345a674.EU11f9af90a-cd24-42e1-b948-c03516e438892'U45bd84ea-34a5-449c-9cde-e0ec7743c992.DU1abebf73d-c694-47f2-8318-c413ce25f79e.CU1ff99141b-049c-4433-b26f-a5c92d70754a.@U043840c8f-8c08-4ee8-b8a0-6d51f84df16a.?U01fa01228-c9f6-40db-8ec7-fa54151d06b1.<U'1b6602ef-8ea6-4270-8d6b-b00407e9b0bc.6U6106ec35-5840-41cb-9398-edb1ad06f1f1.5U85269941-a7ea-4dfb-b14e-8dddf0075c86.3U.723102b5-0d9a-40fc-9318-0ab0515dd381.1U.4824e752-9035-48b4-ad3f-cfd8fcb8d3b920Ubd82ccd1-5a46-4225-a635-77b676b3755f2/U/a05fc5ef-7c2c-45d7-97ca-aaee406fb8151.U/Q307674fe-27ff-42bc-b360-1b17c047f4641-U/Se3bb19e2-7855-4766-974c-1783b1acf0681,U/Pf6718e34-bb8e-484f-b63b-549a530e7a4b1(U113fda34-0fe8-4c12-b307-17a10cd8d502 e4e3i8p< i.nU;7402b01e-8211-42ad-bf8e-db056f91ccaa.mU;9ba5c223-6dcd-4eb6-8d71-39780f3056d7.lU;45944ed1-72c4-4afa-9e83-ddf2c3358659.kU:c87ccdaf-9d21-45da-a0af-7ee97b328223.jU:f2c521bf-d5e4-435e-bdee-51b861e880a5.iU:17f120fd-4f74-45b0-9f0d-f02c6bf55f2d3hU9B092b843c-35b9-4f10-b40a-ff40c64415e3/g U9Aaffcf6b9-2403-4c50-8826-aff3f3efaac3/eU9'?50b0cb8a-37bf-4bf0-b4d0-d37b139a345c/cU9%=18ce1079-4254-4655-9526-bedec445c19a3aU9;f2e00de6-2795-4011-85b1-c57ebf9e7792/`U9:cfe485a3-6240-4aa6-8eca-3df09862b9032_U$0d090b1c-e721-45bf-bacf-df2dd59f996b.^U$eca644ad-b167-40d5-8646-4268c1c9afd4.]U$81cf1a5b-b4b0-442f-af57-1cd6ea7c25aa2\Ud391dc0a-ac20-4750-8478-f014afbcde9c2[Ud4790210-37a6-466b-ac66-a3ff69592952 Fg6j9uDxF~rfZNBB/U?Edd5866ad-4547-494d-a7f4-c20c39ff258e/U?Dc3c08ca0-184a-4919-b95c-6c4150aa52cf1pU<|e3a04d61-84dc-4975-8923-a3f8eae3860b2oU<6e6b8888-5391-4b87-8858-998b2293c768.U=c7434a9f-a6b4-4323-8ece-d3769cfba7de.~U=efde5c3b-8199-476b-9466-d5ba3b1810bf.}U=997a0398-9bbf-44f8-b48b-907d68c73c56.|U=f410468b-2cd8-4271-a237-47b39ddcdf82.{U=2f13114d-96d4-48a5-804b-1d32251eaf4a.zU813f5dc7f-3b87-406f-ab99-d995dacf15c5.yU 4df10bab-be37-4dea-a842-38e52e5edcb6.xU b78ec82c-21a0-43d5-8d0a-c14540b19878.wU<e5f52b74-d666-4d96-a2ca-f5e1226307992vU<e239e03f-2aca-42d1-b850-5ad2d214a3592uU<308ce11a-a2dd-4dff-a3e6-e7ff5849980e.tU<50a24404-59a6-46fd-a000-c50bd15d6da31sU<707da392-c0f4-49d8-9fc5-7724ac42adc4.rU<47d652d2-eb24-4877-b194-476b768b38651qUUGQ44163c01-c7bc-4358-a768-e27586ee7df7.=UG&Pa31a16a4-3b08-4d38-bb6c-9114f7f3f2ce/<UG1Od93ac678-31dd-4d7e-944d-8df33c2117ddP .?U.29cf0b6ed-c782-4759-93c4-3c7a0ff0979a.;UH127aa0a3b-e177-4f63-8833-3d11f5998b87b.8UH.75f5b520-db4c-4a29-8706-f6b6c0bc831e-7UH:032d0e2b-10bf-4bc6-a04e-9cd449a91e24-6UH94951570a-51ab-4aaf-9d7e-ecd73429338f-5UH8167c7068-e34c-4d1c-b3cc-179ab9b1fee9.4UH 2b5dfeb6-7836-4904-9f8d-4d6e192cadb1-3UH3d810960-2a8b-4ae7-b26e-76742c424692/2UGN44e5ca77-aba8-43ef-a928-48c325d05b62/1UGM925cbe6b-886f-4e4b-b496-7526ec0c4065./UF-e0113d37-b863-4a25-a542-3ae62ca806f8..UF,f33f8534-02d6-44ae-a695-d0069fa4dbf12-UF+42c386bd-ed90-43f1-8be5-c4d3d6f8c81d1 m< xFrAyHznbVJ>>|f.QUJ=01806bad-6858-4f1a-a4ad-f4f49c71e02c.AUI367a29c0d-1f05-49c9-a30a-7fe231013e54.PUJ<7c7ddc1e-b909-428f-8701-74c52e43f8e0.OUJ;bd947e2b-2cca-46c8-9f74-2cd1c005a6ac2NUJ-9ab6e2ef-fbb7-4374-82e5-04a3d05bf0ca2MUF:6a3b6350-ade9-4e35-9a83-f7720e34698a2LU 9601d7265-d927-4460-a56f-3e80be8f74842KU@8ec7b1655-0b5f-49d7-9d59-82078bec51fa/JUG3Rf52f6e2c-1846-4a0a-bfcb-47cd579e94b4.IUI77bf11274-cbcd-4907-977e-b8e28b72f756.HUI67924c4a7-6d01-405e-800a-eca381c359f5.GUI507ff49a8-c994-42cf-a912-ff32d1867a57.FUI4da17d740-9126-4e97-8225-e7b8ccffa98e.EUI254f7a5f-59ba-4249-88a2-c17171b3fbf1.DUIb7b069d3-ec08-43f0-86cd-68fae37760f3.CUI42860eeb-b328-4f19-ba54-a69d897e95be.BUI2cebf084c-33a6-4330-9742-e8f2a020e74a m< xGR!Y.oUP1.nUPKae0d5c3a-205d-40c4-9ac4-5d43666ffc88.SU8?1377cc59-7cf0-415b-92e7-eaa9dd9fc8442RUJ>d1363b76-7583-4b39-a6f5-35320a73d275.mUOJ83985c69-f8a0-41f4-905f-50182d904adb.lUOIba274f45-fcb0-4ce0-a0d4-14d82331c804.kUOH6d2a54ba-7b88-4a54-9492-784061311434.jUOGa82feba9-5769-46ae-8c7f-935f4477930c.eU:'ae6ce3a7-9357-439e-adbb-141a872efc8b.dUL!956423c7-5bcf-4a8f-8f33-f6b8870712b6.cUL"42532882-79bd-4f46-9498-9a638e42e483.bUL$320ff6b7-e1d0-4c43-8cae-1d4b36020f88.ZUKF9239a3c5-73b3-46cd-b211-6678a5803ec3.YUKE90509ee6-1758-4116-8b8d-4ed87cbe64f7.XUKD5f69dd13-ddf0-430a-b013-0cb8ad3b457c.WUKC382b695e-cee8-42a2-85ca-54bc71e27092.VUKB44839b51-1218-4ec1-ad55-ad2f73bf3c38.UUKAd43d8f01-2124-4390-b1de-4755eab3ca68.TU8@1e4cfa49-2ff5-4cbc-a5bb-1a9fd6971d76 e4h7sBzIf.UQW97046daf-b521-40e2-be41-08e594c2649b.oUPL1ecbf4b6-21c3-4e72-aee5-5a8c547d0629.~UQVb577bab7-f764-4459-97ba-664aba0c4b23.}U&Uf8ffc9cc-d116-434e-a65f-1960e7adeb5e.|U&T2d62121c-50a2-4989-a4d8-9ca9e340c3f0.{U&S4c7340e5-3a3b-4cac-b187-1a5164780e6f.zU&R2cf2bf15-6e09-4a29-929b-6f231d1a4281.yUQQaab2d0ab-4555-44d2-8b64-dad64a429db2.xUQP9c3f7046-0aaf-43f8-acaf-f24c923f8cc6.wUQO1a3e4d06-f1cc-49fd-8628-e7ab80902f902vUQ ba392681-e74a-488e-ae9f-90720bd218a7.uUQa30e89b5-719e-46df-bad7-79980682d9f22tUPNbf8f553f-6fcd-469d-8735-95cdcb292ddc.sUON3380a90d-86bc-4870-83ed-7a5c522c394a.rUOM483e3b0d-c04a-43a6-9de4-33bd8ad3fbb72qUPId5780b8c-eca7-4706-b385-435df9424e4b2pUPG13a4ba3f-6c38-43f0-b685-55f5655c37e2 qm< xGqN<{5.UU^0bac6930-f5be-4547-91ed-dea729bb6379. US[8b6375df-113a-4ab4-9fc3-2726c63968afJ.UNO0ffdef0a-488f-4c1c-b18b-04d16f113f87.UV_fee80236-9fc3-4016-94c3-d60f70be0038.UMZ3d3bf71b-dc6b-49b7-acbb-ea70a0102fbf1.UMYba7eec29-e299-4e72-a19a-9b49ec8f0a682UQX52cadfc8-6a1f-4228-b890-b10324fc4280. UWZ8a469092-e8c9-4af0-a41d-798d1b8f2cab.UNY4352bee7-cffe-4def-b187-11a77fbf01d2.UM_f1e1c79b-19ef-4d51-b8bd-ef882c68ad5f.UM^9213d48f-63aa-4db1-b170-9e7e9691266f.UM]6e3d544f-ed97-4634-9f44-ece8376ad6bc.UM\5591b6a6-aeaa-49e7-a6b5-6b308e85a38b.UM[2feee508-d856-4805-9da2-2039f5a295ca.UR`aca15075-eab1-4239-b7fe-e260951a23e1.UT\eae97edc-4c23-4c26-a2ef-679b6c287cae Gmm< 6b1xG.(UYn18926a7f-2f0c-475b-aef5-544a0779965c.'UYm82f7123d-dd0f-4964-a919-77766dab0274.!UXgde9d99a9-7ffb-4f13-93a9-78ca9caae46d.UXfdd9f7ee1-87ea-4910-b877-624de7a388a3.UXe0450e72b-94ea-4a09-a87b-a50f83963f29.UXdd03e4457-2a9b-4bf7-9fe6-6d2a0d9fd1a1.UXcca58acdc-f1fe-42f7-be56-528bcfc5b7e5.UXad716c2c3-28d3-426d-bcd0-b9ddae66468d.UTVdfd1bb62-133b-4ec7-9625-472a5034c10b.UTQ4936b651-3e08-45c6-9ad2-ee8a3cef1770.#UYid2d109a8-9304-4ab3-9677-c3acce8467362"U he152965c-d256-4849-bec2-f4b8fe65a296.$UYjf50b4d6c-0058-4c4c-9e8c-41c762c9b1f42U8[c0a81a34-aa3f-4dad-9f05-160cccdcb6f2.UUW38d8e588-5abc-4e6c-a8f2-5f0722ba1e512 UAf17a2f987-1000-4d36-82b8-f600674f1d9c.UXb6474b48f-1d08-47d3-a839-e53d013077e1.&UYlc9ca1321-2247-4be2-b930-2233ae241e1f.%UYka9a4a85a-f5de-41c2-b38f-abbf63c9a310 `xGS"m<`/ 1.<UHwfaa9ab7a-5b9e-449a-ba11-cdba5d4129a6-;UZ+08952f8d-fc51-4e3e-a461-c13c184bf95e-:UZ,8a1b0dbc-1c7b-40be-9d14-fd49f08c59eb.2UTP3a6d72a4-fd24-43f6-a4a2-1b1b2ede6977.1UIu4db58daf-112d-4e08-b546-14b599ff7327.0UYt1fdbcec0-5a37-4e65-a0b1-759d76671b0c./U8rfa97686b-8f1a-4fc3-a37e-4ca13b22431c..UYs1c4415aa-b99f-4caa-86de-f8000a662c7d.-U8se6975482-b792-4421-bec5-7b9bc0f987f8 0.,UYr215f2864-b30f-41d9-8831-dad15dc7e395.+UYq77cd2e5a-d06f-413b-8da1-cc3b7e628703.*UYp595f441e-82b2-459f-b12f-d678b6bb015f.)UYo18733233-ef1a-4b16-92fb-3a319a2363841.7UZ95c8c9e8-f1aa-4184-968f-a1a43186ffb4.6UZ1c33240e-2cce-469a-bf8e-b70b74d5e6ac.9UZv2260123d-72ce-4cc3-ae3f-7870e06d607d.8UZfc23874d-aeab-41f1-8874-87f438e81408 dOb&l1d>   UexportT.U80828908-fce0-4d1d-ab31-d4ebedb4762dD # Ulayout/drawT.9T7a39ace7-77fb-46b7-b545-d9024ad1f849B  # Ulayout/drawT-T966fdc04-fe3f-49b0-8686-f47af317d83f8  U\P510c6b2e-9d46-4b54-8b02-3f3c703a402d<  UuuseT3945c561a8-a2b9-437f-a2a1-5f6215b1e965<  U3uuseT2ee7ab815-4567-402e-8a7e-18aa3edee8e99  UuT29d8be9df0-53f7-4837-8ccf-d76ba8a707e69  U4uT1dfd89efd-0604-41dc-9b96-5c5c383158aa9  U,ugҍf6ae8f8a-6816-4334-9919-69b1ecaad82c8  Uts219ee04e-8621-4ffa-988d-5f4da20c34a08  Usjcb688245-d9d8-4923-a2d1-f0df61a713c28  Usi50aff5c6-ec1c-483f-a85e-e07287f41e718  Uske9333bf3-4877-4c6b-96c9-f9feb4de76b18  Uqj35135e53-46cf-4f3a-8185-c3f2881401eb8  Uoia5bda443-a225-4095-924c-37dee3094f28 <IWh ,x<9(  Uywe"da4793475-4912-41c6-a2b7-c5a05bfaf1d89'  Uxwede4ec566b-847b-485e-b982-78da25ea51139%  U,.ya 8b0a370c-fd37-4ae7-b80b-d66399e7dfc39$  U,.xe"d0a3219b2-89b1-4403-95bb-25a267daabc99#  U,.w^b6495e34-8e51-4a69-934c-42bc1b4e6980:  U+T,9^Xaaf0fca9-08e7-496e-8854-00c3c47fb1e78  U++T+^17de3d15-3714-4619-8262-dacdf203cfc48&  U,z8e773e76-cf35-4743-ab00-d7df8cfce1e59  U+T*V6977bafe-5bdf-4bf2-8dbc-bb2bf06b708c:  U+T)W[c302d4e6-fef6-4b4f-9392-a6002565aafc8  U++T)9[b6cb47aa-94c2-48de-a800-0f672c458ce29"  U,vT,e11d14c0-4c32-42a5-ac5f-68786a7c0cc7;!  U*hasT,868d2a07-f32f-4871-bf20-63eb3fb1ddae:  UT'Xb0a47c48-a31c-4ec6-bd84-4698db0a06c7:  UT'9Wa4019e8d-6bef-46f0-8f00-096239568255:  UT&Vad0d9f94-f8ca-4fa0-b369-88a223887947 :hv:@:J:BBX ) Uobject_changed'4a470190-0362-4699-b039-fdc69e8a7d15L^ - U+notify_listenersIP-socketa d5e4682e-ee02-4e8f-b40b-24085c06a957{EV / Uset_selected_toolU^270acb9a-d2be-457c-bd70-b535046fb0f9?U # Uio_exporterq o8dc6fd34-f206-4450-9e0c-d8445897032dH[ 7 U+tool_changed_callbackڬ~d373144e-c420-4c92-8390-3ffa8dae30fbDW - Unotify_listeners1'7d60442d-eed7-4e1e-a264-e31f17b052ff m< xG.JU.e5e7c431-382a-4b23-b70b-04745d636dcc.IU[}256cb543-6056-47e5-a2e2-2c385f0d1b1f.HU[|4688b09c-f2e0-4a10-87a8-d3a13a68f6c5.GU[wd94a4170-43a0-4e1b-b63f-ed5ad5fea2cd.FU[x17525400-6f05-4e6f-b15a-2c6aee6e5bbd.EU[yface016b-31f1-4eed-a28a-82fc62438f28.DU[/a2ab8c39-bbd8-4818-8897-bddcdce41690.CU[0046434f4-e880-4807-a9f4-346c1a32610a.BU[1b85730b3-1b88-4696-a825-6594efb3bb16.AU[.e986948d-b180-4830-8e70-9ebf97f32775.@UH{de939efc-85c9-42f6-8bf4-80303c95f7d2.?UHz3957f9dc-dfb5-4a5a-ab9b-f571f1330799 M9.  U}1e"d405c8e88-3c28-4162-8f98-beee351605b39-  U|1ed3daa94b5-6d70-4a88-9b65-252b55d081499,  U,.}T9eef5320-ab39-4607-aaa7-bc3aefd8abb19+  U,.|Rcd74b409-6a2f-4ab6-a573-191e830df8f28*  U,{%4f92c733-53f5-4d49-9af7-e10d9a6856dd9)  Uz1ed0a42cbd0-df7e-4ed4-8ee7-db13e10ea8bd nr}  5SUyStream Output StreamWrapper around posix output streamsƵr^SWT64c320ad-1d4e-40ff-bc29-27c74f9d7c25Q|  9 UyEscaping Output StreamtSWRda6a331a-0977-4a4e-9a90-d6fd3ab64231{  'UySimple RandomPseudo random number generator, not suitable for security appliances.K%7ca62e35-60cd-4e00-8176-8c2113cebe8acrystal-facet-uml-1.34.1/architecture/gui_design/000077500000000000000000000000001415120503000217225ustar00rootroot00000000000000crystal-facet-uml-1.34.1/architecture/gui_design/Moving_Objects_v001.png000066400000000000000000001143331415120503000261130ustar00rootroot00000000000000PNG  IHDRUPbKGD pHYs+tIME  .QmGiTXtCommentCreated with GIMPd.e IDATxwxT߳=Z(.Ho"(MivE:HPұ xKB  s n6!;=gf~3s7iѝr^˄ZMu-:z@ @ P*AZB,/NBwxaTt:dY9%@ J% IBmkD#"O,Ȳ$IH$JK @ K v)a[[[.k4:N3y9±paSTRRRc5jo˗MfԪUsĉKkxCMY(a4+W0;(zu뒚3 .4+LY 6zayԪU.]h'j5֚swzҮ][~m!'>v^yl5k5+c勱t>c RMa,E] -o>ڵˬ4cohР>}&~,˔,YR#OHOK5,?nӧM+b.ڻw/ǏcS3wm\`(===پm;w~`˶mTT@a4 G}>-9ys寿hP*pLqT*תɕ+5oƞ{z6,&MsxV8ǚ5kp%* IBs ƍI /_ARvٷ=r5kѾ};ڴmg07'\ -P84ʗ/jn}4X-f̘1kמ|h5kpefMpI׳06+{_-iL)GO//Y[ ^{]lprv7{.nnl߶FCZjٶK^a6lD&MW^e <uFXȑ#h٢%ÇG|6 +ɿѣ%RBLQüVVVo60juLTL v OnlT84ʗW(Yqdffh*c.z`3=;;w7 ==5k[7S끙+Ɓ/:t!M)knܸʩ o^t=1<M[~4bN4ɇٳgGrrK.N:(]}$!>K^a? AXX[(C{*]m۷{P*ؾJ+,ls3ΎGN[_u$j2ȐuxXTTϟ&~l66;=n(JQBtӦEHHڒK.3ugwꔩTJ:w̻k׍g|t܉%Kǔ8y$4h ={xh޼Yy`*i6WѨQ|zת;NTϾр0jժɨQpҳgOCϚǹpi2/y3 uV3b,ŭ=]OLթ<:jcy1]ްX($VINJG /vy~$@|||7/,#vvv R @ H\T*qrrz @ J xև%?(> @ )@ BC,a<3,L&MdF+##Ço>BCC&&&YڵkG6mprr*j9}4o6$RJI*Uhժ 6D*F޽ׯItt4$IҥV:tiӦXYY πHI Z6wldţ?WAJ BG!x9IKK9rǎnGɸ7*Tۛe2dȐy@oCȐQZS۹p/_&--³ߟuҭ[`ԩBR|HPPvvtޝ RlYʔ)$IDEEٶmNE?"cvIÆ +Ǐl2كݺuA+Wem6_N.](QstyÜ9sغu+ժUk׮&ul߾k׮o_PdbQ-CQ=xv÷5)=m _ʔq*43㶕:b_2xkײuV?+]ZjG[%ݻǽ{ aܹyf\\\D/^ xZ]\,g@?~#FPn]ZlI@@frr2Ν\v%KXcLGQegϢT*]6J[ff&IIIȲ̭[hڴ KWZZgfÆ |G9l#*999sСC&Os5z{j5+V`Æ 6QFHKzz:oφ_~&ǽ=bZ~?ӧˀT,XիWu :>f$-c\vzF8s~aCٟu,BQ俽_Ȏ^gM&gR(iSVE-[ҩS'ٳg7o~@ (bԩS 4~vJw!CXn]5rz*>>>ٳC?iiihZcXX///z=W^ۛׯ,xo6kfܹ)SIHH`ڴi姟~f͚/Ԁ|1Çr,\0ЬY3VZ{ÆtR FbbbY0>S"##Yp3F>ÀΥ <#֮]g#q*Tc0%/ׯPg߈\h}.$E: π,h$>>P[YmZq藼,:]ޑk- KUWQֹgCǏٽI9s&k׮~\rW/`73|pV\Yh#@׮]Yz5Ç'==ᛣkXt ]veʕ|GIMMhZ^:ܼywR\9=z 3Ϟ=KxX~3,X z޽{_X޸q^zѣG6mڔ~=uCt!Ґ6:sW,gf֭tܙ^zqƍ#44mҭ[\: ۷m۶?NWt.]]vD%1cʕ[n^³լI|F"eZ6BthZ%''{aaalݺ3g2bf̘gp[n_~|G9BQ~^gӦMԩSooo .]J ([,3f ))XK^INNW^ܭW+-*i@dm6!25 k׮eݴ3Iʪ&L`Ĉt҅۷o^@ys.]йsgzmpQфݼMRڵ+:uxZV}l&MT3HHHkkkz=666ԭ[j5W^TRҺuk6l ؿpZ5S=B+I-8#Y{,6c׮],Zׯ~bѬY3MFQ8x WܹsӰaC<==y1W\ѣ9JMMjժx{{'|!:}ҫW/\]]?~<;w6'nbܹK[o~ˠic5uၜj2zDFF{nvŁc@׫f~`رlܸѫ '39'$$6mڼiӆ7ppvu!-#'Uk --J >j2-=Q=8NjDF!d:~8CXz8zx6mōG zjȾ}*XT2ëV>|8C5jy"eK^ҙҥ1qqyۿܹȑ#Yn]yiUռ; 2@cXXVVV{xxǠAزeK,._#*U^ƍ?%KBŊu>>>(JCy|`,ҡ%R&X.dPt,X_~ 4imׯUVڵ "q%NJxx8oʕ+8pBA%ѣG  EVcmm]:x>}ݻpBoV^˗i۶-tڵXK^H.ݡ!@B9.Խє/_={k.MtڕoTށ3\HiSӦӇ?M6 R xyp?˱urg[M}EZ~ԩSiٲ%~Y׮]|2#F_-8VXA2eNc|3WJ{֑#ᐦ̙3_~%!!!,_?Pt,X2eʘԑޜ={PZh1PRR$''„ 8s ,`̘1EC$ ҥKTX___BsPB8|Z<1Çy15kرclٲ;w999VڵkfAҥ{ul$::ڬ{ݱ-:suVZő#GvQT)>3\\\1bcpu/|WԪUT~WZh믿Μ9sƍ4m4qxQP*899q…\ C9;O?ѹs眿! g9֪UM6ѽ{wbccMĔ(JOqurQXWXx1׀<ԓS s}[xD*+cDiRhٲ / Y~~RV:_/--˾en}Hk\i`W(dhd&( bæeF}JIWwLΛo rrrznx7WɘٗA~Ċ,6yA:5?tKs=*vTP%=X),7,ٵk7o,|=z4k֬رc4oܢa?~_~sΙ4[Ow,{%!4Sp%5j,\zmqt=2,a3w"##_>>TVJ*j~:<|M"I-" AY| xb#J;;;dYϏ\QX:'{ Lۙ2e Ɍ9Ν;3w\>ܹoѣup^t8`׳V2D8{,oJ2y_\\ӦMsRGvKΝ̙3|MbРA|W$&&y\Aaصk}UT!""uQ~<UeY&&&&#ӧOHJb޽y}diϯ][.+ sGT.^3հaCRRRWc:LQT:pyJ&=0{ F_"O+\#ɓִ!Kq;%%u:q-ZBVZS/@,-&&julTBV*U` Kf޶O2xDYYhV( A{n?{thZt:Z^^rK$IT+`uM#sB@tH&坨+7LERr7L>cVjeeٳ:uj}::t(F_#11 E)W2K:ߏf%/tN7}5z4 B 8˗3qD7oA/'h}%yLYnܹMzz:V$&'s)eBo\q\ ¦[W˟aC2p@͛GPPPx۷AwywWw&OLΝ~k׎={81Lf嚕jjլ͑'[lJߟW^y`~\X;rqx@#wg0uԯ_۷oԨQ^ܹcԝLD2+*'Bdd$$QR%޽ktvagذahZڷoϸqr.>m@DGG ȫWr 5kZiΎ7ҳgOW^:y'k4RSS ]so-e޾}h[T#?Zǹsзy_ ᪻<~3eWo|ʕ+/9rXR{Y0 HFyzޱcܹJ*+ I-̂AT)Ѱn޼INXYYT*2QKMMŶrdU`S:G8{a#TrKh.~֔mBR5 X?ԩSlٲ{RSSY~=;wad e'7d„ \p:um4ZvaCVSn,3ĤYG{w3:{kΝ;&GZGE57nBj4~7%+'eD3g ۸ W3X~#_'<ʒj_LaqaCt̘1b{8wI\H^j^;i T [<C*vgoW7#{װaIƨ^:...P;v֭[ >G>qr_J';czTv1) ;|?666Mbb".!!!R =IIIk׎QFgYԯ_;2~x/^9bQӇl!%Z 2]ŋ^^ zq,A[MΪ^W=kfn'pI/Y0 Y0jt4cǎ/,Cܞߋ)WSVu۶~ȚALY:?b{n0x뭷>|8>`qdHQ=UkeB~Ϟ=& PjUn߾MX7!3& ߼WIƌ͛X"_Qݻw蹐G70Çѷo9bbAR{ 35dT@[Ν|޽{.[tN_WL`u,zྔFmOƝيV%20-ѡdOkH\UeBHT3b3.Cvٷo::rNGjjV+00suRSS{.~!GÇ Ej@6oޜS}ر___+J%9rHɉÇ|7sTe,c̙3u3gd߾}EŋؕrUrE!IDet0zﯤ$kFԡS׸x( PE+zȭ'#OC;p3BP䭧WCdЗC?NbbU-W}HfJ|dl=]aro>sw۬Yd^uZ%fPIiJ իK}ϝ;w bdRYGsIݻwٱc1iҤ\#=͛&ϗh4J"hm@R{NC5޽{qڵiC&[!26xlXMZ|gP4S/[n+\ s#|ui/]իWgϞ"QZ5TqEQpG}ggg2 >L(s9fΜI˖-)WV·jUJF"$$DA`%N&cH'> 8q\q) *%;"pwG+os_lq,;ƏB2Dl$@HL#S]9j$0הƲe˨Z*jf kjab[$GGG8@L42}t Be8pۺUPtF 笑myH$?b#Z*˖-/dر1w\ÙWvvv'ȧui@*hUf@JY2Z`@"ݦ([ %4\^Ih` X_IŸL}ӌc׮]iӆeaz]Ghh(+p`z?wt4VJD5x\NTZ^oQy lذڵks=6l#))?4j(Q#b^.Rq}<<' UŨ3舝 ̚5UVs\;m=Yŀq9g8uÇcpEDEEQL(Q*{eX>T\QDOfI/T*\rf-u-AoJwۚo'b&TzxˊQ2pS|G߿ի[ʮ#""*Z>n=Z7+5J]"25(rR [.gΜa̙4iVKJJJ V40&...\~2**ؤdɒ8tzԤ&'G])Y$QF4i҄F1j(777o7 waҡCJR<'=B[RMNNNJrA+{._LժUz/ b}zz!X60yS0rqm&}zgRx޸iءIX{Q,Q쐐݋7mڴUy:u_:=9ƾHo:}fu'00)SpyHttE_D,Qדe sς?Z2{0tCuhSyg,GXek:aݥKZmPΑwߨho` 9[f$ɔqKJLq(ZhUdȑjߏUI;)({r=!!i O|"V&K,eyVVVN[݄j2nU7Ρ+6'rѾ_FFemp-+LGqe1xP5#w(m5P<\"t ApE5+Vpy<==ytxyy ^:ig-v3t1k)YnxxE>f4Uz2qWRfއN(s=g%<<ܢ:ԩSy;0tP*U΅ ?DSh4/l+IIIfﯓ$X-h4|\~%A߄_XeJGPPV'[74JkUKͯvvs%)7j@u… ԬYS]d*z"tp:(6BPhuT@ж|űY(""w_RٖS7]y/5xxxID>} W^ٓ:m6h\wh% b&1o,|||sCΝ߿? իI̴xҥM.]trrpʀ5اk߸4>:Kmor8WbժU3`&Nȁ πa,$43`P_\fXiݺ5111=zԠ]v̝;:ɠe˲mFjSn4K\~ 2uZn$?LzBBBAa=fѠES2UJ}GIe W0?8_h>/,CSdA w"!.mE|͢"=߄/ΝbVT 2o1|> })ӧOw4h@xx8k֬aՔ.]{:^ҥKr2߲jժqUQSW hd?:X̉_:Lvnҡ/XsDx^ϊuRoeԨQ|wlݺ> /W`f6d|TxU{Ilق5Ν֡ȓǰ>q`Er\pv6JTT&2Aر#AAA~G6m8|p}:z:Þz_jnߎ}%\Hs\k$BCC @PDX| ;[[oG_=!KWkAcbPZ&`;A}Pr|(]8:WGڟR]`QiɜC6Y:u<_~=z{cԩC͚5};ucޔhTß3gRbE֭Kll,vɓ 4(ϳ9mFv,}l۶5 kֆ+f8eQk1ٺu#%ر(LlB텎|5GP7˺u=z4N7ES2$~PGۖEp\;w vڦb#ϴ~q?tg`kkOhhHOOGPViNLLyۗ9slO0`ڵ+qM@R\2[W< gxx(l8t\A?k36VP ܝ&C\Jֲ6rHMMP|!:wG.6_O/$C>.32P*TL2F9mZiT0&Q,HN B՚>>ߟSbEfmf0KDy^F箬ؗmdH?|]GDDp-ׯoX4k֌aÆtX!d^m9t4kbgaggÐ~+:SbՈg4$QjU6nb( ݍJ ++;wbPy^#?Lz19RuRdIĉiݺ5&Ls){ӕ|\Xª!j1B크#2}M={Qe|e0f;NYg5!],EϞ=cN7 IDATNȵT.];籸SLjԨ?ͺߣGgСCh44h`1z={2o}VNCբjr ]M3!~.k0R4Z8{HuȀ?ѫi?g6C ~ϼL>RRDR]d ]t1\ommM@z@RT(QXP*iRD:Fdds(=!Y@DR!=Jꊛ=z0qqqE3?y$VMIIB }7 UvjLpRb#;ue l' !mJ֓O>M>˿M7ݤ;C>l]xᅚK2 H#;t7vBzzn~z=eoל9s߻'G ^6pĈZ|y͛p#?III֑[ux@MMMe΍>&e= bŊ.K};ƍ'|_li4U|||k<_tEm6>'j=$11QaJ--- r}n_Klںu:}w۶m0k3QܴW76i:A|4Um_ĉ__,;Y-VўKeZv]QwZ0b}m&,K^{Z۷O|~=__uuujr)1)QIIIJMNљ&nӄ :?TaaaDURRw}UoN-x-[fCFݩ:8 ^Gp}K.(|륗^o۶nV͘1C>KϒQ0pBԎ;hѢI-#ou=ǡxG5N}& 9Rpw"^x=JMMUii rTZZzD4Çןc&~Wuj'r=.rգ>7|YWW[oUaYTYYH$a@ZhlwGG%_~ꫯԩS|O?T\r.\s]%G[^wrKk{_ y4i~覇Ԉ)j>m.Hk{\b]gƀ,**K/~O>˺:_s;ѣGkպ;\fϾ*9/W_UZZ֬Y1cfm…@ff?k֬Y۷Ǝۥ֭+cumᰞ~i4hfΜr9rl={1?QzE_|XZW_}U111Ǒv$yg￯Kah…*++w߭3g{-ҺSO=YLVY$ujs~ Z..KO>nf-YDss7oꫯ06O#99dGqro߾G/yᇵ`9R7tnVeffYXtR=裺kN~㱇Qz|5oI d4J}6.]yXL:U~ONs7,O\FyWO?} SWxgk׮n9uei7ogLny e=zWO'a@Օ=ZXXGyDӧO?3暇+Wjٺ{t6׹^W\[;<<MSFSOMoLGx=zrdv^^?Ӛ={vq,SO=-]ŋ+ޓ_~9sNwy2MSSLUW]_~YUUUn[=+?]ߙx< ѯ_?oӛoosqhrgh޼y4h)G71 -Rcclۖiݺ/~W-СCaÆE%%%rGsբExjw|8_'#Ue)"OnESߜ;WK᤭DZ6m~ iV70u_ 9Xmcbb#;B뮻v˻wܡkF˖-kwo_9 ͞=[?կ_S ?" sիuw ---zH _F7|SfG}z)8U5jvFHTewءo]zvOȺ1B+Vе^kjѢE|*ю;tmiϞ=zNH<}k+11 d6nܨQF7ʕ+dz뭺K;j֣$i tq jhhPEEѨiCzڷou=:_2x`=Zhl٢Rn9RyyyG}3Kg=\nFuJַP(]Aoo꛸p 3F/Νw2e@@~V\)qtR :o޽{5zh{:4d!qTVV+W{_>UVu{GOS͙3ӿѨy͟?_ +r?v_֢E4f˿~*55U7Ү3IZb\.,KkSrrۧ_Wz't7OX<e˖iѢE=znC?Qs?~Rv\zz>u6@ m۶^aÆK]SNԩSۏך{cH%ztzs{nm߾][nΝ;UUU`0xpe[8CטoڴI6m:%Kzz3g* {j  8 : \ߒHD>cmڴ鸯x<*((иqtEɲ2(}-Z?X Sss4vX)qyo~z?ڵk5m4]y7n[ҢJ[N_l2km#w-[v GgWcc|A=*,,Է-=Z999ɑ8*//מ={_Ԇ ZOC|jllsgZm޽{_R/ 5cƌ# / 6+#^v".=~/լY zW_}U\rIm<.^9z %ڑTk.4H{i̡x|4 ~H_c 6iv@ko0:u/^|euֿo޼Y999~0//O۶mk= qEH$:?z!޽[PHWUW]պ5\nMwݻum/KKKӦMg[u7jӦMjiiuWzM6)0  F NN6ٴ2KUq W+e# 2DY\RK"mC򻤼X)bdJ5I[s[$H9)Keq2 /c$u,Wb# rEuҾ"RM^e *mV8Ŕ3\-˒nH$"08Ѩv4 C.KH<6 Yciqn52'-4[$]GMN L`. ߑ89$6JHQG՘ޤ=}ZOڨL@ E"_\vr)!!An[0emmrdF_>a BjhhPbb\.8D]8?]}!),)dK~Ԝ,5Xq钌HKLŞb cJ:%KsG\K2:y!dLL>C-^X>5>l8p@*((PrrѨlۖi2MSZt.bHlۖa2MS.o۶$461i۶,REE֬Y)S|!!ȉ:)JF܆d2dɰR(u8vN (}#]Ř_K ~ :T^{bcN! 6(77WpXuʚ+77W111ڹs*..Niii BR>}{nYIW$pJd;*2J+πXc8P6770 ٶDUUUɲ,}gS\\%I ѣFrgV.K#GK/<577I999:U[[kתZ~_ڻw,j=B =ے&$!]co8AlT{͟~#HDZfbcct+!!AwV0Ԙ1c4x`Lk=嵱QժѾ}D]vi>|~z >\jhh@ X=WmLޡIs3& N:C&:vmۊFrr\zru4"?^cǎU0TCC$) i޽rɑiڷoUXXkʔ)2 C׎;)S3СC zFwH K)$ĩ1$^[/\./PǑRZZZ뵉.KeNS__u)//OÇWSS Pbb222$}1mۊD"mn# IDATxx^hFT g8Ht~#9tKp8-4zCG mV8V4UVVLTUUU_=x(Hӵk.mܸQIIIZf˹@t;8-%''kGq˲{O JIIф TYY)0r6?^>O~_n[,Kz 8+>>䴻Q^^$)55Uܣ>֗1YX$@@HH $! E@H $8  $ Ht*  $@@H bQ $%$$0 rGƍSii5b\lHm۪сT\\~Xz'5~xH`\ بիWkڵw]護g}&۶$#NY㨥E4e]~߿}YmܸQ]w>$B||5g=2 Cw}?NH 0uy)''G˗/ /͘1CnA  ij3grssHPHf""Hh3f( iDD>ۭYfI @@ @@ @@ @@ @@ ID@Dt+! ` @D@g8)9 HzxHjeo8술#2jӹ+#1ǣf^dp*0Qy? +ɤ 9vXeddh͚5  p,TrsTx d5:4^Z I~~fϞŋkƍ*//msB*SiH0%|"@AAIHHФI$IߴpB30Q~@}>44fҍ$M btL7z}~ - a6lfϞ^{MZ~0tYZQ5M6dYz<&#H[$Z+A&ٲڻw*++%Iӻnq4h ͙3G7o_g6lt4L_eTH-d;O*IIQ tλݬhd0]ϒ-ɱ]!5jCB>KRKLT:$JLL? [ڵk,bnbiL}_e7WF% kJ![vJr3Hn@OZ'Ε7F z[ɱOjts^\{$]}ǰm[UUUO`M8Q7?$e#*"qDI_lv>)P@?!J/.Y4zI}MʎVȶKG~LGJr9JYSz8IRvv-ѯ_?;Vi'?4f+!!7/C{́Q6gcJIvh¡bٮ I z '-E.hzIfY/C_!{7˲df럻R˲t54M͟?_={&MaÆ$,4%"Me ɎiŅ@@]ǰd;O䎝*O$An[fR^^֬YgyF|Mo}[gz8qT[[u)9߁a4MY%08"l0 Yh4z\?+$ :T IH%|}͙3Ggq 5w\^㈞/jΝzꩧrG Ðm jllT$eYJLLm Cz W?m+W^p:3 CW_M@pbA+==]fRQQ(˲^111էOvhLTCCJJJn:Ys9GCULLLku6ڋ_y睧v-Qβ,mذA|NX7Nƍ믿"&VBB󕙙y;4:p.ReggkJJJRjjj0mhhPKKFDvTYYP(tKZZZo>(55UQnnۧ~) FiiianpdCC>k$8ahРAtwk3g~? )}\GmVKKԿ4MmڴI;vЈ#d>EQ]pD"z&ܹS҄ >H[lQUU\.TRRz%%%iر+lA3 pݜ]A@ɉ"]y_S饎wxh۶mjnnVRR%I6mRvv"8 "˥O?T.K%%%JKKSrrvڥ|>}JIIQ>}TUUP(&[N`P)))UiiqF%&&*''G@@W||93F3gƍ|rvXJMMmw"͜9S/VXp8tSXX 3hӦM?:DŽp я~#B!nGЃÇֲeTQQq2a/wܡ]C'sJMMU}}iwjmڴIgyz,͜9S۷o/|ĉrLTjj6mĵ$^|JO?JKK= n& JHHФI$IVj(ۅ)##Ck֬$0 6LgK/tuk=r+$$$믗ռy󔟟 & ba( j7n|>Ǒa-5c B!-X@Hq +^$##C7w^X8n͚5K,Xŋs:+8 ꌬs&LpQȯF$'?QAAH{Igfdm/"{920 2D^z,Y;wkn ަY*((Ν;eff;矯[oU|Iٶ={h׮]ڶm^~eB!ZL1MSeĉէOI8jjjR]]y ѪU3h " m[͊aڱc6lؠ۷?VEEz-M2E)))JNN%\Л8߿_+VozK1b5m4͛7O999_z,͜9S~^}Us9=zΝQF4`4M. ZiHwSOnS~~/˲ oQӧOא!CrI8b@:^0 ~ >.@@H X  Gڊjnn& Gv$Ȃ" 82Nat :SX)NV@\.Nat ]qH@@@H $$t! C@H $tblA@p@irz۶~}'JIIarSeY*++Scc#I@pb!ۭH$_]nAS|]__X1 $'˥aÆiܹF Qllrrr jذamӄi, 88ucy@@0 Щ@@H  $@@H $C@:@@NE.[8@ ۷+qc^iʲ,9H$C;U||<B@pbض]v' Yn[>ar2MNԤD}VAAB@pb8`0F]|JMMa_ĨDK/Ta4Mx<2d~lfR! 8i5l0edd0uaQ WbbZZZ4~x7*%%E#GSMMB|>RRRFUYY$)11Q;JPSSd۶\.bcc  #/qF#qdYjkk/)NXqFUVVr$'o$66V瘿Qjj ;wjԨQz em۶MHD*((Ѐo*''GҠAݻwkӦM4i~TWWLk޽z̔iɓ%IpX6l Gz\p :۶+u4}v)+裏>RMM>UVV4M}gڱc~z^Z[nU$G}z߿_;wԎ;vZ]V*--Uuu$O?͛ y@GDRVV7j޽m[eiz o~S&LPMM߯P(!Cy睧T߿_eeeڵk,Ҏ;TSSɶmn+ Z͛[#+--w$۶B%&&X`Pa( К ˲DۜbZ+99Y\rݫrzܬ{guA=Wp@!EPL(f-f)I^X첩妒ۯ4i+WۼԟnjKT` 33s~C8?x,YիWwL{<ÇC S^^qeРA?~|~${TWWgʕI}}}ƎjOz444tnС:thcǎرc7y>u/G_.s9nnYMMMY`A6lؐ? JYY' oF7nLkkk2i$G^@@ׯ_L2%Iһwo[敗w,% @@  H$  @@MH$ @@@@ H$@7$ @@ F@@ X IDATH$H$ @@ @@ H$( . NYYY TWW zJ#ͤ#k׮͒%KАE***t477m,YfMnPz+WLyyy Hv***2jԨxiooK@ hooO>}2b픕6'NLGG ]DdMMA_QXH$   ȢН4$ @@ @@ H$  @@ HE @H$ @@ @@ H$ IyES  @@ H#@@ H$$ @@  H$  @@ yH$ @@@@zd N@ @@  H$  @@ H$HGMGGA$eee! ={!( _RSSY{6-Ţ>}@78 + @@  V76[ZZR^Q'|2˗/OKK@ ( 6lXv}$u.?:S(K~:k׮; ӂޞe˖_~Ib_~O>)OMMMv92B!/seĉׯ_ #UUUY`AXC=4UUUimm5pUUUyߞ[o5$Ȗ 80)++3-(b1Yttt =TuuuVTB!|B ԯh^ K@VUU.h^ŢP: P`X$zGJ* mɀ֝uz6lؐlذu^ lof w޽{gS;y}>UW_/[ Ixb&]Cgwe<c>C9xݲe9_̙I{x$氹PܚxLGߟ$Y~}|‹2.-osW/gϙ}&Ṇ ~\zх._g>}v{YbE;9x&~bѢ\xWn#wu 휓Inܹsn_~hѢ>QGv! 9#/v{Y6l'?ir%x2xSdw/Ivڬ]69-rw??>)y>򉏟n!'㉙}ޞs97Y \lkk۪Yfm.[3evaHw-y睹А}k9Ssnrߣ>:^zieÆ g?;/W^yeuE婧ʂ R,s7 _ܜy=,cs͓OO렽=m:'OgB[[[gfޏ~o}߯_6n n|몹W?p|f|ȿjva7<]~a$fW.kݻw/f^_'6lX_z&LIn8=]u7^1+VH߾]۷6/XK\o~Ѓ) ol6"O?} $ ugK$555inn}̙3' .̪U$^˳.t~=rHOoZ[Gy5˾K/UА+VdРA]qPC}b jh>9=?_/v7^kkk>p|ഓOQG|(--- ۑsgss19ss7Yzue 6,2f̘$ҥK9$ߚ.G?p[/xccO*r+ښv{F y13r?K׸ybѢ\ss%wəgg jժ\㼜uimḿTUU瞗/|܌/yMefo笳Gw1fʏn?~Μ95kV&L̚5+wu" a^r=*te|y˰a9w\~ynaCs9a:O1lМwΜ\~ŕfA9c7ּsTUUt&Nzcnl,o̙3MJu]$a(uc|֖ۓdʕI^:N޽SQQ477or.تԤ"inn}n:Gcqy!P( =l\񊣦ny 6l[ZvwAt`;b`$@ =? : Y@^3 B֯_SԔB$a(u%z2zΟS+w˺u~O>&%LmmmX^x!GYxq ]FHPs@ͯ~,[,---%P(d7n\X: SMu CIX"B!) )7x wuW z7ŋ;sV{.}{S]] 6Po,) ZZZR]]ÀX,g (uH$뭀@@eVH9[ A@|qdcERVNŎ>$)v޺!e2Cjݺu馛_2=X֯_y[kevyɤ[E}/w#IRSS &dĉ9SSSc^-=}ݗN;-{wN3gSyxS,k|+2O'_vm}|͹袋rWdɆ- @@N5\>xy۞?ny!?ٱap>uzϙg[n%3g̵^+"$RܜSN9%sb<&]vM_ߞ-?}\}9Srwކ_4o޼3&vثoĈ^o؞h~W]3f̘tM_"l`Z`A:$Ikkk 4(Bal_?~ev3&;SuMMMill̪U:/A 裏6| ,Z('pB~uN?$IښkKݠ 48fI/NQuϳɧ2lݲvUc֯ZTOYq|crډyyMHԴo߾ISO>%׮͗/$̊/$/I&I['7xPVrHVMjiU+үq}oWeƌYpa ^@TO4^xLzU޵_TTk?ͩ'ν%} 7{>~1R_H?$cҽRvʕژ|rgkD9 +E2jԨ^Cɘ1cҧOx9zYzk\ve^%At-?>?o9?|dɒ\{4iR:| D 6gkS+һw,Y$UW]N8!ϨQ2p 80 H{{{VZUVeʕyS[[ɓ'΄ 2u,\0&LΡw1gqF8$ŋdɒ466v^*++3r 0 ̞{vء&L{wD@fT:.L2%b1~z$=ztF,[,6'|ׄ7uuuw\z9C2eʔL2%[gPRGGGOߟ΀2bĈTUUts99csg=ܓ?W\qE-[ե.mmmYbE֬Y}f=;x≹k3`~3gzMHԤ,_n)/ R4jԨvm'>sȤIR[[7-wڵyGr=$I :4mmm^]Hem>{Оlƍiroϣ>k&r{qeٙ6mZqF/!V^/e͚59w;UUU[nܸ1k֬1S,S)x#ވRZ[[-l?m g xވz ⾴ ntސ7@@НtBਞP"ZZZR(ԏE`>|x|Ɍ=:z2Z[[x >i,lKƍˢEp´PB!#Fرcn$IOVw5KCX[paGbni]hNѥ#+p=!@ ?+<+K'T*ujk$$$&+W`Z"$klуӢ*˺ [e033\8<~Ewq̢pf{tHT$h9.8:/&'DK J1z`N;@Vy<y;SJeʕ)51h&}Q30_ojTebP2ccimn,[ժp}b-ӽ m[5'$T([+Wq&}ˣV'II7Wi,\V-u^m- ^G[)1R~(hz۱ 6Un)N|+p{* +>D뢤i ЗZWg|:gω|JʑV`wn~%}u@aH ((u|jz]J~NIMcw?zjr倫|&~4NJSͻ7o.M VN: Ґg|oeXPСAΛB#~Je|r JL&[W$''ڇ(r*eADV9ɟG<1\Lfp9%0Vʥ?l+ƮV#ymy{ڌT*iiiyXm|ƚG&d,> &m2?V/}d3Mѕjޕ9u<*JwM,^аR3^ś&GCR^muwQ3nf?%#o*U(JxQ՛4ܻ_0X5̻h_7(Y*G7d/#V%5[ FS>pT8X .Ej:iZ S1"7npmwOu܌Gh$MPb\6n݉[}!"Iz\DBʖaw"55u|.%\]>]J{B&q=(?LbbKfֹ6քED~6[Tl ' L g*%G<;t75_~P(c._o',h4۸DiR1;;j]򮬻~͆-ܽwr9ڵfox,s^>rMn/+W4J?Oe,]0U71|JzI'N3:M9~,C~ZhP6ukPrE{[?Qp~ӴQd2}X[YLP gP>zmaւ%f̼/GG0a]C5V#y)^~0oj!+烡yT4k7Q13㗶<޸!.>S?e(Cyj53<éΘ)ΝsF%{1qlzvÞ[we)c!Νį{{;%I"]VB&e<`V7AJjj~ÍƖ![;rڱgѮ^qy%I5G*%nj [f@0z`]@qRf 1hEn9~Wv,! 3SByʢ̘7ZjrCcr-<#BKlOOOϞ\J:Ŕ<2I燭;7r%3{bEt LF ص,[fuf_LZMN/Lؑ|KEPA כ7n}SI:{>/?'3orWqQlml3m??^Ore1y"'Μ#*:RIfMrBK>ݙ67\ؑsJ{9&}%2~Ξ#vv\dyL&cȡܾwWT*0@BBT2bۼu4{!N+˕ỵ]Uh4\]#]*V(ǯUWNc=柝ۇ))eNK':&Fo-;v5Ǎ@|a dT)ԿR+AFՔz,GcFvV~(W{QjeΙOjj=vbLILǗm2,ƚmZB~<!O /cIKOSKWxQ/W鷸rѶx=GQ^{^2rb6ƓOդ,mweh֤!wZkqq9b˘-0Կ2ƌ…;臅9<R%͗K?5^ H`l˜CXaKR,ٰOt^a,_cz-h\zƎ+_aJ_>ɕXyxF%۪9rw'Bw{ЩS'P(4oSҳ3r+mʱgC{8L=ֆY&J4Ij$ .^IeJj%{FP(t?u45\ νZ_`an5%\])_֋7n^VVܹjU ,ظQ'QIR'lw{an%ZD:'$2 b27^}^^=eA5$'f tuxh9{%=($Az1DD<ڊ`aaH)Ye.gn7o1r}f?fCvk -FRǰ駟qI'ϐV+q(%=quq1ߔo?^[ .\d̝eJεL1曼I}X,NuԤA}\ $!!ɤ4jO^ gկ2:iIV)rIQ_[lEa.pwcx>1p|o(CvKfM-_Gѫr2*{QY%p#&6vv$rΞbfQP4kܐs/IOX]+MINF.$hoOBbb8yF]9^&pvt@+I ;KO$O&ѻ{Z5g< @TdYVv;;II~\tL̫^$[=gϞM7W_8:d䗜|S]7i_vlߵ$Zn]:llyv0̣)$ѽs{zu^9Kl,C?mޥCNVi,oj+3-CqS*\XYZd٪x*Ʉ#P$LdZgAb#zڍ[Pϙj|f Q1737/ :۶b7_˵73beO_t k6lfthI8|OJՐo.^@JN/ @jj**uq F}[yF`iߺ%J.A$8ͰAع{o%ܘ4a, ɶɸѰ^~wk80Ve?q9l+Ӳlߵ1#вYRS8|OzW+21TVS۝XGϚJ-;:3vpoL7} <ף 5ս07'9%33ⲿOOCj%ۤ83]s6|6ulHW/g|n @&^•FѐN3( L&Б&bK-0;]<~0Nm[h8 nnۤX2733#1(Ȭ=37n{TX!cՉJɧRz֫],f&żSw 4I*p -e{`9l0ifZ+MB!_Hə(hzVDL&Ζ$uϖظ}+KKra7o/^bccb+-ׇZy_HII!I:s,-/Re?mؽ~߷5V#Ej/doQzOlQ(d1M~ט=E}o-FlmY!!1)˦#N&agkK\|<ժTfiK|$[pwcɺW L%1)_-o.{ (P r ҇|7L: [{GQXceełYSe~N "xcJ95? ѽ/㿽eU5tM*: @+ل&$|[w:_(TԩI\~vFsmv]=A(-S'}L 8w6nOQjF τ` ƨTyeݦMY = G0JDt3"h?çF}ŲR@PD&$!33666DEE gDLF4lP**䔱3**;p2oqea+3ga$Mpy>3HX-FrFJR=^ao1׾c^%"t C qZǼ=SOfz8-( 7M"怗 IJJӜ8':IV"#PlPӓ#F`ii)&/}\ ʵH*OMjשM= !Ɔ>5UV:%Dvl;DrJ2* o2pssmb`YxzzRT"E$G{1RݧCzaQ*U%K" #$$vKOĹfsJ3ҕ_k}GpBK*ҿ?}٤I(QPM,>yԬY=z0ry>x-Z`ix{W)D!9(d?tzF8ʠaW[P(OZhѢuƦ@is=Jp-V^EF І-< Hl|-1r(zI,Ɛf#8(˗/ƖgLT^лOƔH5IZLğ;pX>cMkgE8k{Q~FZ[䫬))),[ 70r&Njd혛g622%Ka5O?Xd3/IJJbؾ1cyŋб#3gRւh @8 ɼpS"a=3卜ؼ {WhZF[._! ^B[[2%`;Ж(سwŃ4gDZLQ-3_gqɜRث1OjTrmKcWmzVEtܙXߞ uŢ2x?glqkyn޼y+Lj#iիfZ%3g?t={ r9´ԫ=zrժBop&{_U,_ %KW111L9mG[)SHcDx8˫4˗/$9sM~Fʕ+9r$9nF=⣏&-[ }%f͚,^@={6{;^z!Ǡ2 ^-HSYݳQ^K)[+-|{ccc yBŊ><*XB`PoW'1!bݨֽ_CwnPK(/#Pv" Ѩp1~-hvY)a|VLJJ G7 h],xVg*8՜2e C&1|6m}DĢ9).jqƱ~"ƍZ.R{i3 ֤RţL(39uxɳIag}Ae2YE6>bo_.Lv؞o1Xl#wKAAAiӚn|ٽ{whߩ#Ǐˑ o~Z~ؼ)GZ^^^۷:жMk /]}5~]l .G*W5'qv\FL7},MOO'66_l}{e޼|4CΙ7{2?F K*N0"*Uð._߮@j n^=ȞoD t؂;wp±7S?mv"ˌy%\Lҫ|٬MiZvMZ>cʕԯ_RJ1o<8ٛxۇkFr[$72urŴ46mh 8hԩL;uݻBaܲe 9́^]v/(2{=TpݹG%K׮3]2Փ:0`+6wMZٍ<:^vs%s҃B}Jc&(FCrkF7v;-/^]箔 E2N6Y`UVќ4YD:0*3ytmԩS9zx4>xN;yskW_v3uɿ%ҫXgY*Kb='d 34=p`?sW|;Z,-hҬK;P;zsehРnnn<{7np,i%&&R|9͍?O,VpZtk(OcuKL{+.z oYmzXz2ei,N)ytԙj^!m(ّ,vƐ0{' ᨇ;>/3wxwppp`ʔ)t%}ݻ|8p+Wҷo7:>+NfIKgXHhv)UZ2j,<}CqA=.ӆPN 5'Of_J5!fS m۶}mƶmۖ|7pSs'O ^_GW*^v%U k%u2<k6Wx\RR @hhhfHzRbم.f4hM?0pP?{KIIcz"Hz[*U7/\kcsm*Wֿ)>̯/;qqq ߏٳο?r1=uzlm .IHEbo"륋vfWGּXM.=,?7a*VT^v3ɓCzuqGE.LTTTN< nnnX[[Djj*fff&&ΚNʌbә}Xd{_q۷Ŝç a'6V 1q=iii$$$˷O{`G;^,T$spdamszׯs*V?i׮YqWZ-QHs WkagpJ.Gm___VZEbb"w<{Ԛ4,O?e?  XfP#7؈8<uK|L,1(Juё5jҪqS7nLխ[?\$|:8V_?˗aݯbӴ_rv$(Z^~g/+f$:xMMMYd$x{{s)GڥlR^..xxtYy7%9urrڛ[n.EjgbGfjoXN/j ޟ~9s^: ڵ-ZУg/YnߺEƍr'Obmm B֖4hذ QQQ\<{Y({5 pA͙̩D'sst-MƐ&5MG_`ޚ 11c7yGk^3EcWnL /YNҥK6m,!ϦRkԨݻѣϟ?3cu۷oaW2m4N5hη~Cq܅'{sH*e?`@ Md݃+LH T*iٲeRB0 ,SRRr|!))W1b$G4*Ը!l;I~X>dh&~fΡO>YmWgoaZ`GcYdbg3|U13ؾ%qPYveԀc|r*`7_U>ҏ00`,~9քN׋F0f9b.dW'\?}Yfyr 1hڷ1cʗf.{L&cŊԭ[C{i[8p`?w)rN47r)7og!Yd;wf7>u7ѥKW-\'Q^}UNƍzZ`S|R^|`ыA+׺bytڛ?hz6W;8w ˱P*H$c:pwOݎ0=p`?O@  eWއ$eÊ /dMTrPXT͍jW(ﶿ {Ϟ='zG$YE2cI\2DzFbǑxAUGG8;NJd_nBk'R*c3+x'88GG+dr6 `0Emnv %nGrV_#UJC,|TyS<,w:s}VX\.Fo\,f*h.o@[) +>< |)Jf]-^6G/1l4]͹?֍Q\!&Fw?ZZFѠѤhIOOGѠjPBd.OR.[dXG]xwi/*$Vx◣v|91U_nw,/@Jy^~ [EVcyLEW*ef8o1//SNbcc9"/@-h&y$7W3gcee72e0d`YE57fϞɓ \WT|̚9{lV^?c޽?'O歷bϞ= 4M sg{1Hwr zsA}ޗܸԦ^).rNl]hzM2Jr}ސF Nzz:;vbԩYf F0`y3۷oѴiS݃GKKKvI߾}ZZڛvKˆlm7CҹsyF{6?,A?w a$v FEN4wՆԮ="^0>5k)߄W,DcI% =]ZMZZC><##N}8*|K;3x(jٛ+m[^mws yE7`0݉bt9U[1n8FqswMoNm䅙S'N#{&b~'BDŽ ͛zV @&#a,[Fc0;oSjԮEƍhٲ%;GnՓ.;Vu=&`"&ܾ5߭ Wiiib`9`ؾOI^lRtNȴ5iZL$7QvMLLdݺutޝ: 3zh.\@zzID]6/;qDOOOsnعظYE+sҭt\XaY2 W{߿o4ω'{.%/>0ڽr5R|YMoBB2UVޞ˗c:wBfpXOy;4_U6ԪUaom]~Y!Gk. %%I>gY"KnԱ#>>>(geeEZj*ڶe%EX> 5دmdX}Y_L¢ɽ{N7~gC2r~>-(nB!SW J#M5˳X|)ƣ>իGN2e ihD׉Eҟ˼ekS>|8K^CfI>j_WxRƙ%u1=>c[w +&M5`#W1<~ƍżٲ`,<2pKNESbGm[[Ju|Xt OUe +ֱ!Zҷop}nݺA\ #Ţ"ǒ#;=ç]I#}:kF̙3Tf`630 fE3QӪMK  PzunI)H@VZժON?C.inϽ%0QFZe W7ԅyc6&&&޽{1aXYYx7ɢB {3\J90r@#JqDGG9C%,hY-,RӯWw^xSR%ݻG1k^FZ: AsrKݕ?_~eW_|Ѿo$gw={4'OP UeO" X mJe\HtU0ٓ&,!ݻ&O!uP:EҪkvkI81;W&5MѣG1Ж7~zܺLRR"߿ر8yI3G`Zy6mE GG_\r( ,,,8qD?w\D%!xmΞ9CllVȑzRBsql#3DδS'g|Aܻ{ 6Y O|tls˥}yJlunݺubMxLFr@۶m0`>>>ܿ oo$o1H4i^x5ٿ?'!!!x{{3}t_n]bTn v~ ^FI'5)`oE&߰aC޽x_7 xmÀw%7R5(_29ߺur޽B͕+WXpӦNE>}Vb͚ŋ;E/GC&o|#!!<~8n!c'ދ.~~XO$HkkΚ"ի,'la@^445Ӆ׊ChT́ڕ_{&0OxcIi DP`nnN^(Wh4z(Y$O}Y,f qX'GTM{ 6o̬Yr}ʕ{T24 c7M]2v#9Պg)I/nW\ahOOO6l@Jp^s7$՘ *.0.fL4ׄc.4K'wGil n@J@QT 2g;poOA `ʘ'k0/ В$e݉\g#{6$}c_7|?mvOT\-e~]ɲEteUփ_C`ʰik=ZCBBM2kY>cOαcǘ3gCE.xrQ,jW imݖ&oAֲ:I|8q<@JXz53f`x{{xbw,--Fʇ}<`IS6`el, T `Dt3FR s<73#'4m۶ջewZ^}-OˋP+#养4UWo5b̙3d3ny|Q$jժʹZT/d-FvMBֺ3yop^)W {nEqm޼͍֯O>T9R"= V*0:8:ٳ\gϏ; zy{QeXĭ07t `xuYHVWڅs'QfUz>?~~xhc2ߖ]GpWѩ%%rsu.ɕ4F|;+}'bv8Шn=: gMdY,Tfz'h֭˱cLjDR1{]\\mw#KN^JܴR6XԫJҤ-ŃҶǴɔ2իT!^.'ϲgE U0]j7jo=hK@[mɾ]$ VJ/~JEQUkEШTi?DNA3?4ӌlURk^2gνsϽs>]ڵqw@={ѹc 6a`B˖-;v,֭ٳTTw:$5En9d/[훑X=zM]YxKdܩ\ҳ}6|8GܼySnLZZF)*RJh4/gNllbEP\3E0!#`:?R8CpdLQ}sxKGýkbkiS'qrK˱C tkYI}~= )(z|EŊZZ}KRRR9r$,]yfuFxxxw޼yv{+Y[gl&Up6,Is9*e)_٩c^S~EVIi$h*!3y:BE=j iv6Юα<؀bDڀKMM :thy^g@N\ìYL~]JUTγ`46V<<ެ033̼,܍BWV3Ӻ}3beeqqqo!l;LNgW\ễ ԫ;GvIII*K?n|yeS9ϽITEX<{P(0{^fw_~a\),jժŔz;@NLas![ɩ\R޶Xl_Hj ~$?{->mxGwAթ]ێ=zV3ڴiãG8zoߞ СC2j/cv 3P&YŚMJ9 i\}oWs\l] ]mDҼ;899Ӧm<%^oNǎ7o^P///>}GRJbo.ԨQ[v#w7O䉒PKGGXbRQpa17SOmW&7zw(k G5dB=H!A$8{QkkwQ0\Hc\ct̽;,>StH!>νC៎K;|wf䇡!^^^=z_~(4hw]dzSW6.̙3ZjѰaCٵk훑:gϞ,=@w|===RSS9tv.8dB\TS>ٓ/{_%cT,7l???Ͼ=x5EMo[ե|2#}6.i͊3gIMM###ʔܰϝ;GjjjB^> ei֓h 6"0$˔)CLloġ/(OcSt~"͌h3uS~C7i[v"HLL -Zӓgw駟ҿڷoZnhco"e{7nC5}0zɷD}+C~6 i܍yud. qW3g!EhJ`;e񽚢?e]AiʚP~( FiU?#Ы:kH Oǧп'ax^gH~np27|4:Vv\O|Ho?ᅪ+7*-ZR0*פ#5V^z,[(=ʀHKKc߾}Çy!K,1š}wQ+HEU$]_tt4OcSQ(lx,?&6>-mKjX>VN4kւZ{-ɓiӦ _}Uu'MD͚57o^1It$.;Q%:uv#/ob}Zͳxl*Opr*ZwԼ.QEc~3j# *g3 %g /WFa_>v7xeF,^IdLL͟zgQQQ(ԃ>mSC##*fn3ӷkY*m`ZÑM73d`6Y&5k?W,!уsf+Fxj W`7xx\|9={Ҿ}3Preؼy3sh5Ko{'nk'?l33Eꬮ|Ӊ{i߼l0MIIoJ~ERR*UkqyΟ?[v|A֬^MXX(.ߠ  BYp!]v-kXN8AjZ*iʥK?ظi3͛LNE˘4HUBJ*({z0p@xbiȖ<7ӧL /}02c#lgT*hIf͋Ďnwߥw>\r},^;w`k[G'Gqrr1SEz㔉9u$o ӧOӍ& v AvM-q^F<"UQN:Ѿ;u+HR2TN=K ze˖СC}]Ƭ oKe0Eڛ3~kNJjpE Mb㠮Rcй8"^um͋H~f, U0Ν6͓f f/_5rHȑ ~xN5oYǏjUR0黔aGED+)CzQ_GP)7?a5kƧ~J*Yg.]6;@8< 2Ix-s<8~x3߯9.[wɘVw&/5C(L IkZ f f-~{9q:mZEE=&X9 z~]ˈkλiӆӵkW:uµ_.`_߉uY4W-qn>C -eff!ӧOGWW==]EOW+WҥKu}CC6Bϗu裧cD"7#,P~RJ>?ʈ3{ #-*֩1ǎR9dQ ۷n JM6 ݻwٵ{vv K\x=wsMptt 'g'pppА6-vKLLw70bT=Mt:ۏAPֶΫGOX1EOXf͚/_^mjԨA2e^K&d a,"B7]x4k7#l )c0j/sҏC-otJŽgłW͋iM-eRʕ#R(۷o/fb !(m⟔榐gq8/D/.\ǵ.::etttruA"ɪ 3xBMzcdY… ꘕ,;`!dk Smܾ)fe73@T>u PR% ѣ˶:wL,K1Gf谡T,@WWW}]Ν̙ٷ떯C<{ H|C̟:>}:a OwTm$zغUzȲnNvzܜ> -_7gЏ=8:)'ЯZoonnN|Ua؛w\m&Bխur eZ4%ʴ4ʐP 7 uӽZ,r=Ԯ]͉rʡP($99%ۇzzzܺuH-8eҰaCVZ HKKW?~]3O%vvv7*._̡ /ZݻwyXÆ 8{2n-Jb^P)D`dlF#l*W})?]LtCW*>ј(O%,#kƍk͛7RϢJAg{!L8Ck^'aڛg쯨?q4 =NcS萦ً89ċEmd^Dګ.іq%NOH7<~'Np\ygψ&6:]==ʙK܄G&MMI~iwɷ\|ƍg[(|]d߾}$ӥ~}vڕ1~ٱ̙UlD Ƭ_b4}1݊h6ĉ0_*ƌCNrmmaփ=]#M(rV\U>Yssqƹz 4jԈ;$=eUZIط/0vm$Y$kN,Y%aaԭ[===h@ ^=Glޔ aI>[]upZ?{OBq.fff<|IjJJ1ed ޟ~ݻwCݺnz̙34n҄{|H142bΝ|ڴiiӰze 9z_V ڵu+p惎0022###*3gU뢴tCghG, JK|"cŊxxxжm[q_ḻ`lrGZmCLėL9P5)S`~ٛWZh_NcY8ߜkšG7h]*z&Ƥ{PI% ߾i7b|Y~^Bt U~Wz(oАSN1plSaeeӧi0s,…gժUѻw-,4f#Chذaƍt!V×aPٮȘm۶ֶm[b%FV:/cVXjz8X`mmO۶QT]1C?1MÞ^qVF_s 3g?3yd  _W2k`#JqzB~;6X,"{^q{1RZ;R1QTa/2У/F|R cJ fxQAhXaaԨQ4%ѭ[7ݙ?oӔ &2t0,,̉~`,K2hܤI*x%&+`:3*2*"Ѩ*'Td|l2k>|8#GX .h"Xr%E6>U˖c׬q{>=[k RmQEno~hƪdF^1:w Zs:IV֫3" I0+W`9^/wޥknG׮]qoߎcfdd`qcqssrrb='*i|Gܸq' @C~l~ =w/ 1unoWԬDXn"- #3Ϟ=5kְǷ@ʕر#k֬{.JIHPSҦMBh?3ޙEBJJ >>;%zm5kҫgO&M]]]Zxzf~>[Y^W>.B{kԨoqyfyۿ{sܜP%..RNo98h\kI_JXX(aali+DEEaooOzݻaaܽ{ss \[L IDATWSKLV#ghL:?*^٬Y߿?K,J*QN|2*>%KKajo'TdIbR1|T|K/r{KǎX̘U H]q:̬8r.YT%3}޴"X^={]AXn_}~?c``ԪU/ƎӋ}X1s ϛ~BR8q5jx-'gR٩/CgΜaɒ%yvgʕ,Yׯ>NNNT^=^=}=ނЭ{w?]p͛s 섏6u:mmv߭훞YR6lހ> k׮ߧQF^x>}`T@`~|~y7`ƌjՊz BJ⯿"883g2p@ZN!Q^چxboH,zјz]c|_6gLc!ZϘH`K{ѯX ].fݾÆ /Ғڵj_k>顧g?,,,x1 .3tP֮[W(n9L+:u*Ch_EJٶI'ЯE0Al 6$snܸ?\n2e[77ںe=( zɊ%Pbo-gNhܤ ֭[ܸ~;wIBB=dOklٲݴil= #c6h4)oUX'fQ0Šu|V-}xĄɓXoQD& SQx6,:Pnٳg #99`7zC9֣QFk>̙3,Yg)񘛛c$VSGVo߿ϹsصkWSu+ȗkp"Q iZWK|YڻwoRreJNN&22/ @RMIfZXm 磇7ovřݻS~}TB*UPTYo^rܸ,gۋK.1s Μ>M3ݹkYSMq`A$׵iƌ>FAPhwt&N5YtDQ$l-އRz5KNN&ն![ -;?VTn)%?1XX#&vMEi6{ n%ω|(_Ř-)_Xuh042\9yR:n>eʔkkksCǎ{7ς yGĝ;p'021EGWL-0bnquGB<B!F#%cǎq`~ˆ|@dd$ "}cqP  BAn1^(;:rEyteԒIgAXzeGIdoX(8.S03AGK$t`fCqAAx#EŒ4&0̱ byOdIy$:Jܬ  /^" aM^ c  yJƗ9#.ByBz]  BAP$7MMAAD0 P4  2+_ƶ"AAAXL7ƏVue*>|kۏ  8KZo/x/3BAAf%"R}3  BъFo`LAA(qųyBw6BD   `^aԓ&ÇkR&׮]+& , 6%U(vѨXAAAFAAAD0*.OAAA7B4* ('\AAD0 ")+;aҤIԫWlll߿?7nܐAAAciڔh7nʕ+С-bС:t peix-΋t  B!jA* T*UvZ""" ]v#Gĸq8p@|ǔd  #2 4޹swyGrxyyQèQĄ-[i۷oYfbeeEv8qD&G}1gVɐ!Clٲ4k֌fV^8::}v5jĊ+  7W4WWW.]+V'&&ҪU+oÙ={6mۖϫ͟?///,,,?>_~%׮]m۶ic۶m<}Eѹsg(m֬~~~ 8YfJǎ駟4ߵkg̞=dŋuJ%J򵟿XFMj022Ņgw9Zj16667'J[AAAqIB4'ͫ 0[_w^H^Xb/˜:uJ-4 =sٲez>gggv34kPP겹srMBBBh֬#FaÆ̚5}뚛si,--hӦ 6dݸ&]l2bjժݻ:t(cڴiܾ}֭[R/T[l  #3yVzz/,ZG1j(*WL׮]3%AT\H"##Օcǎ;vL-J%? 6ggg {n\]]bАooo[Vܽ{DŋsymҥK=z4cǎ̜9So%&&fϞNHHՓ/  "ƌ͛79q}GI&=zT]/""3g`ccڿ??֭CCC*V"Ԯ];SyN2eJۦϔ;vޞ={j:ydJ%v (('''Zlq~ׯ/UAAA\RDRZlBiӦ4mڔ?ƍ_r)h޼ymʔ)̙3www>sקcǎZ١T*sze*O޽{tI:   `|4iWWW֮]Q^V-}eժU#&&:ϵk;d47jԨv͛7yjiAT[YAA_%T۷oWpV[n\|[n%88X^P`ddQ'} m\Rvӧ9y,-- OOOX*֖LejAAAc)HEallLƍ3f k֬aܹܼyS#)SU|'^aÆѿ<==9rg͚5|駴oBӧOsiҤIT^W_|rZnͩSo߿ZQ^gΝmңG9ږ%"ӫ   '[oťKo `XZZҠAVZE-u---9~8'OΎ+W2rHu `ff֭[~ܹe˖Ǚ4i֭#>> o߾|13~"kpVX֖N:1n8dĈÇ>}zqܸqlٲΝ;gQbE6oޜ)c   (EǨ˕ЦrISoTxϜڿ[n޽(Lݻ1c0`mΟ?ΩS077ۛc9  1 yhBBѣb͚5Y&z 4X^+WN[AAFo(O\cyVA(ѹsgiAC,:Fckq]l|,f/YAA4q21[(&oCAAY0zyyѣE>|HJ EJŊٶm4  F`~~gӧOnܸmrz>/^ȵkrիW Gr"EĢ   1$''š5k>#$$CCCܽ{LLLY&[<}R ԬYrʡR|i?׬Y1_֭[DFFuVHKKB ӹsg~W<<<[dAAR° r"0,c\\gΜv.vvv2{{{5}9sЦMΜ9C^7i҄lŋ/3jQ@ DFPP|yLLLPo( PsN]Ƅ 2}vE\\\Cr&[/Lp.!7r R0aaaQFhS+RZ5~bbbP(b``PNz_m۶`eeU<{:u꨷)-ő@ 2=TAA(ǫbzUHH={OҒϟCz-]FΝ\~]-=΢ӧ>>>|wɓ'<=:(`,Ĕj&ăZ4  m°lmm5¨CҽΟ?mPzϝ;*WLZUz?e˖EWW5۰a,&s "󄩩R!qqq  paFtYq2s Bܻw/z˗Wcmm-g( B&66e˖Pð:zU^k~-SY&M  &ΝKr(Wf͒ECժU~ٽJ[SAA(m$''k.>C5W(Wzh.\X}|( =m&M`ddDttt8x _}͚5ߟ?0~+=a vc4Ǐi߾ƺ _FPR<,,K˳g㧚7oСCQ*ܹs-[ハz ʊ+ ؿ/_/-[͛79}4zܼPY\/q\cUtttӾ}{sl2z/{ϏGѽ{wvͨQrǥKHHH- Qb1DwOOO5k8p С\rTg3JƍSNYlY& @~ œ'Ozxj?ц./~7ms'UV-%OzJ%AAZ,T6rH߿ϲexw tLccc֯_Oll,V^@) ~ cDzj*066ё۷g:i֬XYYѮ];N8黎33gRV- qpp`$%%1ydW ...< E&ɐ!Clٲ4k֌cǎe,};f{̘F5&&&lْfBPp-uYTT?^c_ޘx.66ѣGSZ5pqqafƍ꿳W}壏>ؘٳgX[^@*o=)Nڵ͎O ^@LP`eeE֭1cu)a4hЀݻ 7fޑvvv4lؐfϞM=1bni܃6l@r1b^}舋 g„ tԉs֬YC۶m9}VI&;ϟj*ȪUb#55kၽ= 4{ЬY3O᧟~cǎlݺ}f7SLϏVZ˯_ٳg5jT3^jՊ;w駟baaMh۶-'NA3uT9@T;vmڴx1Zj{nʽ{6m<aÆB;۶mM6,ZƍX9WIϩRX=%KkNoTqtt4cee%W/2d(J_ի9x ǏѱD?c   QBN=V\9:t\r(JO֭5~8}4iӆ {n` ۛ-[pvvfǎ̘1C]ȑ#GU}5kƭ[W/FFسgOqܹܼy#hذ!fV0V^VZerKMwG߿xb._̩Spuu`ذa3g|}}iܸ1q߾}NDDvvvܺu;w0a„wy~gz g}F.]9s&֖rBBBr5MHH 222SFWWWըU_A׮]믿qXZZbhhHTT#66[[[*T@HH)U~GRRR000Ot'00Pٳg#%%ǃHIIϏg/H? ޽?'O{nF???x~~~\t x((((=nʕ+rŖ8p fلɓ YR;dj_ؘX{OOORRRĉ<~>Hc֭["qp]uٱcbQTcs\\\4IR֭5wN*wUcahhw}w1[/oovРA*WLdd$vq͍#GJPPSNlٲݻwwlc m IDAT@WWɓ'T*ٵkW/666^&=tvvReU[ۯ 䞞FJ -- sssT*:::biiIZPT$&&VvjqTPk׮aoo ?NjjƏUΝ5f?ͳѨ֭[SD^YM]6kr۷Ҟ5k\gD֭K˖-?˹p'ˋdDŽ >}:ꫯߟX7nܹsi޼_|kfҥܹs[[[LFt6mĦMnj5bРA|r2RÝjԨAN?~<+V,W]_xArt邩)x{{.=zq?,J '55U㳜Hw444#*3Un߾M.]2wԉN:x^z駟ODDϟuˆ㱱ɶm >>>ܺu۷oC=& /Gfsdu<77,[͍cf*YfXQ*QfM\\\HHH`̙ow/U_~Ņ~I=+fffiFy)N#tI74hPTJR)'Q(ud/^X___.\E_Qzu ߥKC||<{䎪-SLaΜ9cmm:qLQT*ܥlٲt/_ "יɤ$7oΔ)Sr>kx\BƍT]veРA<{]Atv1Ӆt~R :t(Q Bn3iҤ7*xС7}'O*>}TXٳgsEڋ9ѭ[7._F֭[ (swwgϞ=͛7gԫW/ٹsLR`4*^ {055-cUZ?q2[DI[4-- ҈imqQ}}}5f ܹs5< oǰdEV?pe5.ΝM6ԭ[3fϪUx8yz>K yDD7n$55ׯyfپ}{% ѣ6lm۶TP!_dߟf͚qe6l؀BӧE]'M۷gԨQǩSرcG-==<==Yt)FFFdŔ)Sسg 6 gggΞ=?~twwgѢET\Y퍒.twZlk8θqӓ#F`kkK@@fK'Y啯ࢲU&M,"ܹW^޽{.pԩ10J/{]\z|f ggLO om dL۟>~xȠAP(8::R4^A{>x]]]>Cj!gfiʳWJ6oޜmԨQg֬_>}ŋLkӹb͚5Y&z7nvְ0SNkckQ) ›02JC›'׬YcbbB }6UVRY"fA%%x_o6幽$Ɓ8pziΜ9i=cuѣGƐ!C_~kEr.u'$ ߿"zFldggSGPhUʢ/"N>_|_5c)"֬YX-[ 99FHRTUUA& dYhx<vڅ p8/wXr%HYѣaggw۷Q^^o3,, p8Arr2PYY GGGrHRLAxx8V\Yfahhh#GE\?SbšC~6B$&&b u'%%Æ M& Wݻ\S% _)Sti`0b ͷkkk!( deeA(B,32ͩe 5+++`Xd!bhhRGzz:&L+WcǎдIY;Sr_KKKp8( C(c:ΝgyxfSb XXX ""aaa066 f>HR~F#AW\!)) cƌ~W^y͗W[IIks1c 2!:ʆ 뼯.]5k`~[[ xxb42JVVVc$H"A=EJJ rGaī/_ZKMQ\BDFF"&&1113gNݸq#.]!q޽n@E 2{"Aݲ:og4AgallT :@:J'''ܹMQ(bٲe:ךZg;\[]~~~Xx1n޼+"IӦM P`6Ξ=<~# Z/|||cLLL0ydw|7x l6>6Wall 777um^ ooolx<",,LD|.\.LLL0m4$''wٱl>|طo_Vرcjo0yd <֘5kZhYf666W#W. ^n*++r`j.۷oڵk۷ɓ'8pfΜ˗/knի1cƌ7B*b߾}2e RRRF7*A(n޼'d2Ξ=ӧGLL fx!233xo߾ &&&&A||:"8#Gȑ# ;;;x{{wK988ٳ`٘:u*֬Yɓ'(--; r\|ǎk3_MMFWkkkbHLLT m)?Gzz:[,Xcܹشi,Y ~Vh[m Hp2$$*q b`899a˖-8yd}јsʙ˗Xx1"##9sظq 矙\pqqcT z%5::[j2 ͆ y,_*aff#F ##zzz022رcpzČ=Z%>mF}G No...vXnرc1x.y8ƕ s,Y3f`ɒ%m=y$x<_VVoMprrb 7I3<<r}vD:⢲&_Aې^xAqѶ΢"[rrr JԾAjXXXti _~%ك,P*­^.][o?g1oqaׇ rhNkjfDts4ɔ'?) BIII f͚*\t 666ZFu\.WqgU4FÀжN1_KWWW///[۷Uua˖-ŪUrahh_|Qr믿"%%_pB#11Qk ` TK{pBf{„ muV\~l!~_gҤI5Oɏ"ONRAhCee%|}}q=;wW:::"33S-]`9bf87|pH$ni uis=6#dggĦM `Ϟ=m'Cr=>}III_ԩSH$H$8u4?~\cy-ǚo9yyy*93g`߾}TlذgΜAjj*e9̂:u U\5ܹsӕ ;K_3<++Kz!))IuNBII q)f!11k׮ɇmɔf:@1P9sp aĉڞ "++KeIB;qFOtgf}}=^R͛7nSI?qD,_fffxw:\{ łJuqI={6D"r9(//z3[ -c*555/̤iRTbooϸ"lذy񏌌Dqq1 777fQVVDEE!** "\.NNN8q;y$8rss7oB$Ի<==b!-- gϞE@@ X̼+G 3gslg^SVV1oJJ S.~a;zhnJ,}moov|+yFiK;VF$ b`\t /ݻ북&펌ԩSxGGG8{,6lСƬ,ݻW-ZHD":t(?7n6֭[ӧO#00puuEZZ>>3fX礱8~8***7`[("117oFXX cϞ= ɓq 9r,yцp\fЀ#G@__$J:9 Zr=f0磱QkR?8zzz* ---QSSL@JfŹ\.Y;)sssܹQP(All, JJJxb\pS$`jjN2os DP0oݘmK;VF$ b?hYk@ܪ;d0ŋXnbbb H쌣Gbҥ:Ɣϛ7Z9|p?VŽ;0d,^BPE]|;7B! @]Pf~Q׺oߎ`ݻ}`ǎ033É'pI<3ſ/^WX DDD ,, _|4D_e˖-HNN dgg]1NJ7д1::WCBBooFG9 TTT#GłLLLuVjjjwJM?Jz!DfϞC.G:?RF]IK˗/b$I .tq~kkkkk8p;R'ŋ*i* r8|pukhSs4h>3|gjV4^kF7$鶴L&B@YYoԨQZF#lsW_UI+**3x4'X ΝÔ)Sb 98t,--DwKMYʨ9AA+cMM ίi֯b\x'O ,,,p3o Bwww\vy_b"""[ouY;Vcz؄XeeeaôF˗a|xK/aӦM1b>d;6ei+NATVVܜ: 2 8w\kW\ www;Xhx<vڅ%K())a>+G _5 p}}:1dL8GmSbaٲe=N777ڵGLHH'|ɓ'/jי]Ɇ fA{bXXXhwb>2wޭS QXX;.\>8q"ߧ RE;NOϺv5-ۿ|rq:@wDt[芊z<yG KOOnqq1= Tx7n,&CuA?`u:[RYYիWc066uW^7l6x<BCC V,㭷˅9&OU8 mbpQsg]1׮] {޽, )))LD" .ˈ%''o͚5طof1n8|7jm?vXX,xWfUL<5f͚?CW^f͂%lll+W`ӦMpppAǏ᰷s^ZΦQ'0??Se8;;wiR. cNN,,,`ooU+N1k 222p"??|>@mm-Μ9I&...*<8::"22@S8˗7nٳg1zhXXX… Xbݑ)]ff&n޼ HVfź### %b@TpJx JJJ7_~?N][[ ooodff"$$o"_PPP( o-"##f'OFII 򗿀믿Ƌ/'N7T9 j!00۷oGll,׿2qqq}x`iicǎa̙?UBn9r !ߏ7xƍc}mҨ(̘1G۱vZcx 83gˌz*f̘1c`ƍJطoLw}aĉXf uvUD HHHyWO!JqΝNs0` F.AuHQtsscT.ߏ2 ** QQQDrprr‰'@7n`Dq(..F]] pY`X̍U\\ &ˌ1Ǝ 61)**"T gDDNo ,:w\lڴ K,#mD .0n!!!lh֭{.1ydf?|駭ڶkٲeߐKfMMZ54[k``8;;HJJ‡~Ҿ7n 55Ǐ [lɓ'fff|28`ƌ@\\cH)ۮ{?*3?#/^ 9sh7gmZόkp@@\\\p1!q~c&Oɓ'#??YYY2d&}k955@(\KKK^ RUUU k5f8c.666:0jͭDOOOER 0l62 @E)S9zxL`عs'#"P(ccc( `ʔ)&?UΫW2rrr`dd+W"66aaat88DFF޽{X~=nݺŴ/44.]¶m_6!155uAE̙38pƍ^uh8991FФ\5FFFxg,?..ǏgE4hv܉ŋw]rIx<,&k$>Q7ncTTi>>>Hرc&Pȼ/C(咱8Lk Q o&`„ F@@U\YCBBoI%uΜ9̏?***PZZ#Gb&&&fO>zzzmsjn, EEE022BMM T9<|||z022i2_o,*VW AM8::2X*Fp\xe^hd(W.\~AAΝfyڶKW^xYF;_6mB\\VX85 *Jxje'׮%B/{AVVUӵWƥK[o?ٳ1|̛7]Z岓nhUSbl6[{3 bHM4 jU{|8$ֿ}JVannOOOxzzbӦMł glڴndx B0e;HO+#qƵ֭[ΎY|\q=>}6668wN>pwwGVVR)fϞ'B.c͚5ǏCdff>FGG3>-Yhx<vڅ 7Ą pB?k׮(  ?Rf-YyyLGYp!r/3};v쀾>^z%MBp{Arr24zj`׮]HIIaǏƍmԩS={6}]x<:u nu?mۥ+999j3J-Z,qppIUV]nN>@iii8|0> B$&&b 6سg0ydܸqGBYY兇cʕ5kϟ9rFя F]$%%L[j,cj.$ɘc[```e˖022BAA}]@c`'AӧٳX~=6li#G0iҤ6MIIQ 6d޼y).^u!&&8z(.]>|8Ο?UVaǎ2d/^ Pئp?ơC Jၟ~Mmۥ+LZKϟ4{}:uADGURuyjC :TAO>666Dqq1 777orؿ?(DEEA$ 'N`>>B@II /^ .@.ߚ!##Cc{mll>xr[+Hf{MMM1sL 3f yfC&~){9 wg[ 7 L\RfTmÛo 0a1rHh Qۿs(--ȑ#blݺUekހϏ1x% SL鲸}A6 gg^mGvv6jjj4p z&0/ɓ'UTal+ӌX`` e* BVvSޮVUU^AA HHHݻuW*Ν;}4]>= SSS|())oL86m]\r4iJJJcΜ9m0sL`С~.ܢ" _Vy;&E%  ]Yd *++?-͛KKK^ RUUU {>n1ݥ͛7L(!Cf_l>eň#VVVxS> 33BtvvnsF,==OMZ m2ho{݋` 4HvO AA466Vi5+W;yfu׮]*S%%%g]VVB(//ŋ!! 1m4L Á+BCCaggǏÇ̄PvΝ-^yAAAt1zeP(īrPmbVVV,  զr0,\\.!!!p8EFF`ddcbȐ!ugtttmbkrCuu5֮]ɓ'TGp]   iwСCӮQDke er6DFFB,#,, "SNʕ+TD"$''bׯG`` ƌ E@@O[!3331&U. SSS)ףh  IHOO*v5Ǐ`VVV011Ф+˙4>KC__666(((` Fr|RUUծѪF+AAAO(؄ 5tCOR__###TVV?`ee!CãGPUUGGGTUUѣGr066F~~>^xX[[3!. ǏKKKX[[yyy055СC!Q[[[Ç[mr}@ n޼ ccc=U;=ZYY:]MAAa0fddMv(cfddʕ+E~~>|>Z9s&Mˆ#P]]̂5/'22*H$JGAA.]󨩩?R)#d23&H`ddL>e`РA(//gJ B,磱LrX,MUUU:cСo=(//Lj#}6*JÇxcǎe>6 Æ &y柛qZ{eW {"jVVFu?d2߿˗/;   6e+Tֶ X(((%l6d2ʺ8IUaff@tlܹ@B###%%%2e ~o RY5KX,(sssuʯOOO,#" Ƣ"8;;\ȓ&MBccc^2MMM!H`ff1c@,"j ===PWE2eSQJ$X[[ϰaPZZJw4AA|l8;;xِJ*KBkʅۜ~~ >':Qڕ( kjj:lQD"133cܖ  |>IR)u>qW.<쳽mffd-*b8"u$Ç!i  %KPYY GGGrHR|8ɓ'8u&5GaذaPkgFF4n9yyyNFF\[[[C&GFFjkkqL4 pqqay9www$%%Gnn.GF||78~x&ř3g=~ƍФڼ?pww;   @~L==YN@즥%l6d2 )$~STT[@ @zz:l6v( (  %%%2e * o6DrA/ .Kw4AB6AABaLHHEUg 74۫̚lΙ3ň?***PZZ#Gb&&&쩒w1&XZZ2Ad4*bX$ ^?zyyK%M[%WmIKKcʴ-l6{AP0u_>^EH$ >unݺ{Y  9=94aWx_xӦMФVMcOJ5KF$>###^;XXX4r466ғ  ~AON8<($k֬ݻӧOΝӧЀ*=5!lXn+;;;}Ĵ6ԢZIƍ&8DAA]͈#|uF:Bpܧ*>xaI|MS!!!8pV'$$ !!wn5ի[~ҥ155e[)StKDFFB,#,, "SNʕ+TD"\t &&&X~=1f@hh( ^߿K*AAѭZj@o5"qǏ3mxصk͛Po˖-HNN+JJJ׿RUUUxg`888`ĉiǏÇ̄6644t[B__VVV011466B.3i, >lllPPP00ѣG,AAD_,444А:b ^4z:jdB___mfcԨQdjjkkt}}}C(B,?drqqX,4} 6 FFF;vl>>>bF>Xp!=l0X֭[{z;vlm" kdggW9>u@41|pg S]]S~Me;66{jLߴiVuM>ӧOyZ9rd~[eeuuu;  ~CG9{ZRwܡ ͚5 2Snjiqqq())g_Mĥ;]R3Ç'u  NbPRRBBc)ZHcW^a>7W=z4F1_|Jy111`FJ"##Q\\2D"͍Qܿ?(DEEA$ 'NqIp8"((7oބH$۷QQQ􄷷7QWW4={(((@rr2JJJ4@)z }mfAA?N ThkESQZZZfC&A (M"7J+>333fcΝ(  %%%2e . 4iIJJŌXO_ڵkpфNTVVR'AA@@: & ::7$$Dm0-3g @ii)F ??? B竕q?~ s7!#T2|>=!Rn݊m۶6mw]-[cǎAPҥKqQD  T4,2B8N QfF:KWH?wtY ;;RCJ$l۶ OF~~>,,,0k,lذAچ wpssҥKf͚n.zΒO>~~~n:lb`mm lܸQ%l?wŵ(ˡCjɓ'? C >MCCCv χр?EEEoQFꫯ...*lܸK.K2cR=YWg8z(lmmxrbHHHqh;]q>ܪx-&JD'??l6Wb1*{{144 ݻuȨW `lgg>m,*ۨ`TMPt%++ AAA8~8`ѢExصk͛4Ϸe$''%%%sUU}Y,X娬Dhh(c<|:u DNN1k,&wށ BCC?ȹ6mZ]=YWg)--vE5|ٲe*i/;ש(]~NLMM7oj4> 333Ogc1v4>bGǟ6cܼW abb>Oz022c.-O,{ m7wUQnl5YG<_mm-d2@__rXZZ!##zzz022رcunޙEY5 ˀ&  ғIFVfiie, MsC"+3Tp MMA1QՁa^sA뺸.3g3}9G gئX5kЩS' **={T!ɪ|F7...tԉ~y7dU޺}gd2Ү[VII ǏGGGuFjjヒL&9[PPB`ʔ)UDFR&N?jm۲lٲ*eݞxuՆ-[ҭ[7~ZZ>˓O>ݻ OOOٿsMhմ/y888ƚ5k}dդ߿?k+W$&&Gٳ'W[qh@ x09r$* G/̚5&N(}6c E݀͛]vGVkR #==HKKCwη-k'6m… ={M˹P}bgƌ6]]gl>̝;7xhΝKYY9{f߾}lyT7AԩLJoj*}*iܹsٴiD@@uǢN{2aXb{fϞ=ӯ_?~m~Wiref3̝;WoΝ뺫q=J||<$%%1zh9s__}RFNU{^^z1o<ڵkի-[d֬YhZ/^L.]HKKך8Mpuu%>>JŒ%Kxg ʪ8MO?ʕ+m^%''s^x.]ZqGϞ=1L4 ooo[[/[i@ x0iذ!Ez.tt:i2ڴi#YTuIPK,W=co"=Dmڴ鎶p)KFF%##.uo-cǎq:`ѣo޲h"oڄu2bÇ[o]< {7,%55U t-[Z7o~5oҭ[7麠P(,ou˚3gEPX/Y-O>bXL&&SO=e'OZ,%;;X-Zt:Ι3X6l Fˀ,rܒ%Z~b[,m۶U{yFFFZFMKaGI&]N5Mw6զM4HaYfzմahytt%,,&d믿Jz%""f\o\^߇@ =;Nys ƍ4'ڲeeʕR{[CAUc]\B2[</ǏHII $&&%Y}7@VVP^^Nbb"III$&&b08w9sH@֭cڴip!&Mݻ)))aڴiX?ꫵ6KT*ٺu+… ?___̑#GjΝ;Yr%pŋ7m%))H:u$3bĈ{߹p?#&~i֭[Gxx8˗/Ν;+>P#,FRRRxqqq~k]x )LP0}tf3}]B?ٳgy饗j^+mڴcUyf`࣏>Jg]ҳgOmֳWoY8M裏ҪU++)ٳlݺQF8駟hݺ5ݻwT֖[m@ n^緢 Mz)ߢE O>;t m!l͚֬56VX###m>>>6|MQa6[[@- 0ڳc6jN:%m)`xyyqi7n@GyZnc|BxW8q"]e˖Ѿ}{nZ#%/ pqu999 4Jxtt4MٳIJJbر$%%JDDudffjbo߾[ӧOCII ?8?3L4~x>}T :Y~}li{ĉٹs'FbڴiۗC2dɒo}wUϯ>[Zqv} /0eΜ9? (Nj:Nrss8pmG@ Qpau^m]\r%Νyfڶm̙3>|8K,uֱzjV^&$$UVT*1_www9r$'ĉsc:t{;wJ8@@@۷og䐚J~~~T^Hi׮:7M;c ̙C~xFR1`:l6ש]-Zm۶lڴ{^sUq^u_?]vxyy1x`(**bǎ7u%c6Q*άBZ#<帹ѦMju{=\\\ضmiiil޼[2l0IIIӳ^g:ܑ#G2m4x뭷HHH`РAmwMljL&6^}Q}.A}UF݁\.l6ӰaC ӓܨd2@ii͊Nooo7nR$ Cs=\jXٳ'6mbPPP#رcfLPY0oߞH @z͛k_|>zC iӦܹs6[e̜9Doߟx~~~믿՝nG ѣU­au=w6Ԧ㯿Ez0{l6mO< k̩ugQ'= tԉSNU1.UqҴiSi[@ sv;E@@5bʔ)<dzvZL3g˗/GP/ `Ѽ1#F0|pygxX`<9 IDATk׮%::`.]DffҤI8;;н{w)_|:ˋ5kTYQQC׺Jz52*~u[RZ̾}$W&>|8ɓ'ӦMZjuC ȑ#lܸ&|ժU6aرc|^x'pB4iŽ;xg;w.r J+E}o&;v`ĉݻM61`ZmwwwvŐ!CXt)SLh4?SOݴmVG70ז5rH6lݻYh~MnݺPȐ!Cnz~߈cݺuL:/_.ֻԦ1vX֮]˗:u*>^^^Ҋa}nj:\BAll,2z'DDD{ѥKƏoߛoɤIHMMW^a۶m|嗸"?fs#%&&ډƬ^ZVKƍ;ݱcG3@ =ƍgsݽ{|f5pIBBB$kwwlÝMX]Ėzڵkk2T۸w #I@ ;v;WpW0Zn}hܟrJ:u*k׮7~IMMZM~~ڢe˖?3ilLJ@z=vvvK\,,\K݀Jё3ge;::bggWv#xOQYYyތ ڥ-\9dumaJlnA.Exx@ Hc':AAA7=|{GGǛZxWѥK/_ &鮩B9:uSNRX,r)ָeee$&&Ʌ xmfY@ xa}-DvӼysi j]x l[k`ghҤM-< =#6 ))vvvݓ@p]$ID'!!nT^!$})W^-zF !iXSv;]];Vt@PF>čO tR @p Wq67kqs@p/Ú+5@!+*.+?7YT D{1 @ 5?=8P\RjsIHpP @EAP%xorBP @Lz m?@ @F@ @ ݻ˗/}Ucǎq!zꅇz^gΝT*iԨ*JF@p`ݕV1 ,LB˗/Z Q uVqvv Byy9d2T*?RIpp02rrrf3YYYP(PTQVVFff&jGGGJJJ$44T(Jiel6P(8vOFPP(jզk1>}Lj1h}Iee%wt}II ~!=OՕ(y۾wgСRX۶m^S Q \}( \\\>|"  4YfKϞ=dٳD(..̙3z.]^ܹs;w|ZjbAf(**bʕzJ%rF#jo?v۷o硇",,LE@p?bqq1۷=PΞ=W_}ERRvueϚ5XpZ$ B0 92 }Q2228|0J777r9t:\]]%c6zrL&fJrb._Lqq1eee!ɨa0hذ!(J),,FaXӖѫJ믜={֭[6_IJJ QQQR/H֭>>| 0UV@\\;wfmGO`` III=SV^Nc˖-ҋӺukVX'|~ʑ#GHOO1c aΜ9_>lRSSԩDDDJѺGpppV>S:Ć x'x饗4hg瞓(l߾] cؼy3qqqd20 6/:׭[Gxx8KᑑܹSNJJ"22R|8pNXv-!!!X+OΖ-[$={"@6m+.jf@F@< #00!@ cꫯ2qDYv-˖-}lݺ 4k֌m۶I'NdΝ5iӦѷo_ʐ!ClSff&Z*y*  T%Ntt4usff&}nMk`u!ͶQ@ 42:СC^~eڵk믿NzzzomŅm۶͛ٺu+Æ #<<Rvee%;wrZ5ٌRYuJl=_[W6  5@ @ cڷoϸq㪄ңG2220;;;ղڒM@@t_q9:tٳIKKcƍ:t H)))Yiڴ)N]vթAAA=zJ5>kf%%%L6VZ舏#GG|;xwHJJ k۶tX @^^^Yʊ :$Y4hҤسgOڵ V+]зo_)o߾ 8iΝ(**† ‘#GظqMV̾}HKKL&111Q*7=l0?ΦM0G}BU״BӾ}{Ο?ѣ ٳ|W$%%k׮:)f"66CJa .[ @ yѵkWڵkG\\͛7իWͪU111 >=zҥKGǎy(..fh4@ 7n `0B`R3f3|pƌC6m8p˖-cʔ) iӦH߾}?~<>>>$&&J2%88{=NZɓ'HLL ywj=iwTp /LRRR_|EZnɓٲe?ޘ:-@pÇINNfɒ%ŋڵ7Dղ~z;Zlɗ_~رc;~x裏((( ""+;v,̛7SV`ѢEҪ;vblذ`-Zċ/X%޴iXt)Z~j̝;1cưpBLRm8;;o1c ֭[GII ͛7gֺkxFyz w ;ύx&?~</T2le„ ߿ݻwKa%%%lܸRڵk|`gl޼rZnomw7\Weglܸ/+¨Ql4i͚5cČ3)kݼ۷RIywyᇥ8?0qqqL0Akzݻ7m۶iӦ4lPt@ IMM+ F游8=|uهbÆ 3֗^zA1{l{9i_Fa߾}3^zARR$W^Nc˖-xyyW_nݚ+VHw<(F@ #X,._Liixqu RDg0VNޯV0*JnʢE?>Ǐ_&::9sYn/GFFsN:))HI,Z1S֮]KHH$ኃӧe;`vϞ=%̙3Ru͛C&`X]1(--%//\.IL&CP`X0LU>W(dZ%r\L&܊N,u:*@ݱF MF}+ኟW_}'J-[Fٺud&33VO +999U΂DGGW{&dffҧO*V1xyv/'sNFŴi۷/CeȐ!B0 ;l̙38qRVGR]WĩT[r $tM&-_&!(,,шJC @ûBD x@С:t_]v뤧PYYIΝunS7 \dڊ<mFZZ7of֭ 6pRRR#J Qz=vvvx{{- .łL&ggg Xp!aaa 8LRD&QYYɪU(//7JRځj8::b4mt:t:JTG`` ;w&""JUvd2I|a4U@ !oW(c퉌/  Gl޼Y iu4mڔSNU ܹs6[UkJPPGn _ I Ϟ=M6O`fϞ-F@  GGG\]]Y]t?~\:H~~>EEEj6mѣG9qݻw@yy9 N< #hҤWPPĉuFjU bC!`b͚5L<`)C/ 2>7ڜ%\j#'F0LPXXȉ'l+T̰a$Q 棏>BPת}ݝ}IV EEEb4 VNX/QӱavAVV.\ɉJ.]/7'Od2q ^}UéԩS,Y .oSRR|2*zZo>tz=Ʉl9 !voKF=+͛G׮]i׮qqq4oޜ"V^Mvv6VΘ1Ç3fڴiÁXlSLiHLLo߾?LJJ SNvR4yd!>> پ};NWOθq㈊bС P( >\a`0믿ѣywQ*O?Z?:K/a~PըjJKKپ};Cg>`ǎȁP(8::Vh4r%Z4}W[dh4܄pb7m(/chh(?$99%KNxx8/k׮R\wwwvٰa_5,Z_|JiӦtRZ-;w.cƌa…L2z:;;o1c ֭[GII ͛7gֺcǎՕy1uTj5,ZHZi+@Fyz 61L( jdb3vcx!TġCp& \nnnI(J6lHqq1)))SaŋΦ\]ɞJB.k<9ZU(ҪrmP(Ҏ~JR{nYY 4iӦxxx(# kkO!`+A͛Ǽynۛe˖4|M4h<<|-[0qDZhA=82 IDAT<7n… ruɓ'Yn/^dҤI7֭[oAHHCPWTTͩSLVc N~"- rNB, NڮF.\K+FďEǽ*~E=/@``oo?NΝ|2!!!3n8z)j57NyDN'(//l۶2ZjE@@TVxx8<䓸{ODY}GIHHMUZ'N[o$uZ59Lkٳ۷ӡCF)taooL&шJ?%K0rH:u$FzR멬D&a0(((`ٳ'''{9tByyy) :RaB(`"\vflCCC a  e˖g-ZТE{r9NNNI[Rk… yG RINNz&M@QQyyyErr2{Aqq ߟ|1ʹjՊ EII صk?<ǎFOjj*F???#wVQd⩧BTra0L!0,ɋ@ ܎.klyBJŋ7oAAA4m'''RSS)++CCZZ!!!?{INN_5۶mɉ3av_|AYY>$$$ANNN:ŧ~ӧ׿x뭷d|b `a  @PX,IJJbh4^{55keee 8իWrYqpp 33r,X@JJ cƌARQQQAff&/_^z >J%gϞ%%%JEQQh4ŀXf M׮]b `&@ L&JJJ8::booO^^j'''._Q*x{{#(--6&2X/_.:C cm\N quuE'ʠAPTlٲNG~pttرcӇ^zqQL&0|:t(jɄ3jٳ' 8;;#e_,ǥg{VVIIIڵ-Z&{@YQ(4nܘ^z1ydsuw!<̟)3\|3gػw/Ν`0pEǥխ )^GJ>333)--EדKzz:bΝlܸ4~)++@q!:ÇIII'##?cǎq )((|jZJJJjqIt:|wo?|Ws@]~Xl,^5kЩS' **={T;XbE1P<ݙ3gҸqcj5;vdU4ݻw%CfU╔0~xqtt[n!\CRog'u?)++c޽ܹGGGP*TTTpi4iBdd$Μ9s$),,? ;;^ɓ'xzzIEE-[Gߟ}w^j5F h4p9bccqqqԩS 4gϲ}vQZZʖ-[djՊ=zVѣʤh$""ݻr 7oNLL ѨQ#;? }NNM6뷦 $DDDܹsy7fܹӻwo'yLHH ..Njy_-[2yd Y`QQQ;v ZwAzE˖-5kZŋӥKh۶{2aXb{fϞ=!Է`k'-!h4RPP@vv6ΨT*qvvFa4Q(K4o LQQ...J%ߪL&QʫJt:yyyc0سg:N W| ._^m۶xxx޽{I[Vu:d|4hDEE/^Dqh4Jh駟dFʕ+{6mڰvZf͚ moݵy{niر#O?U~WFӱej T̺׺ٳx{{t2[XX˱7/^LzaP^^7:t]t ;;;Ξ=˩Sb'''iu:hР2RSS1jOpwp 4i"]Ϙ19sЯ_?^~eQT 0yj&NMsqqa۶myfnʰa'%%OOO*++ܹ33f@ Q&ﺆmۖX^{51 }daÆ4lP zORvGbs- ukm?!Xt: rBV YUdddPZZ#<\.'//'OҪU+0 8;;\.X{)%qyIN>\.㔗ӢE ?N&M$xECÆ 믿'''d2j<<jsj: :t@={66m'`̞=A Ix7pBDl6+.\ 11'O"%Ξ={ ȑ#\tQT߿_Zܹ3ڵC3gΠV1͔puu%''FC||</^DRCbb"RsrrHNN&000jL&X,d2ѥKx i_Fظq#GEV -Z?Ļ2h46Ud~GJfhmصkZVZ}NOO?`ҤIίo߾o>i jΝ+ 2>7OHVח^z"<肱[nmb hppp@Vl9pZJE~~>Ѹqc ^`bPTTDNN 777*++m|e•NGYY=1#[{{{ZBcl6T*Q*Jrrr$w-pekV|x$9233Y|9F,Yf && 0rH:uđ#GHHH@&QXXX%`RRRx:u*JVyѱcG^xY`fXM>}:ƍ#**Cb0HHH@P0|p)ތ3>|8cƌM68pe˖1e!M0oqF.^Hhh( FwA&NHzz: 4`Ĉ( 6oj2I&ѬY3ϟOnn.AAA̘1:C &VCxxxၓ>>>4nF#Y=>#4 Vb# `ֺNcǎՕy1uTj5,ZHZipwwg׮]L> 6_̢ElV[ȊKls#%99~2FNGǎ9z(Ď;xw9s&peC=ba„ xyyrJ222PiǣRXd YYY:tHrZ xyyѻwoڶmKӦM?{oE߽wtBHMP]0ÌΌQ.wQqW@eEeEqd5 $vzG $"pzԩJW=u>spa0I$)((@PУGb2nѣ8bbb֭~)GA1uT"##q>|b0 $''?@CC$*++իTU&t:jJdeeQVVƱchjjjR]]F!11ٌNC.c"77"""0 x^ $''KŅNHLL`Ϟ=X,zIJJ W̵ o.-@ Hj_^xCK9_IKKGe̙$$$Oc믥tҹs2d:$ָ0c=z4lڴIҾ@ - 3rۍnرc8qW_}^\zɰajq9x UUUTWWSYYIII uuua4q\ՋDZ-{졺BnrR "//øq㨩1e>S:t(z#G_`ٰX, 6 BCCT*멨^gϞ 2Bydy&QF .1.ڵkIJJ pP(X`[n?c۶m7`ZBq1j(I,$''P\\! Agp8|>0 -Q\iY.S]]M]]/f xVNO?Dll,^{-W_}5jFeѻwo|>[lyȐ!RWWG޽ٹs'YYYDDD؈Q `l999;rXNM8q9kk\[{]\Ni_ :BAcc#'ODIsЮtXPP C#4MBZFTJ>K6tRFTTFI L&4 455D׮]%JL&.|>j5T*1 r%kaXHMMSL&w@PPkZAAAhZd2F8yBb`XP*j !B0յ#omy84n_ \NLL >'N6^ɂNM9ZtU:-U*DDDp z=&LK.RR>SL&ZJ(fd2$  q1tPinA&I)* ׋tbXcǎa٘3g$Xy Ĩ` 88P^/{/rFjr뭷RSSC}}=?#j'D@ vZ,/{%KgqKg/"V+ B^]IXXTt+ܯ CRqWp655aۑdbZun;za6mDTTTV B0JdffK/XĉٰaӧOgܹ$$$yfo΢E￟w}o;pрvwtv@ nod/b 4ϰNVСCőAee%ŔRRRСCEjj*}A׳m6N8Jf|>F< SL Ǵi裏FJJJ裏'&&cb6$##CJ'z( Ǝh0`FE^^}v222|;v DA7@+c߾}-O4'b0رc .dݺuvzU;X1o<}Y, 3f 11k׶;|@pizLzz:YYYL& _@?~ݎZMYYx<fqIJ^l6c6 ;;ZMPP 466b0l6SRRBMM 555vZ-L&ʤHFQT?~hi IDAT<)vvѣ LV%99|ڵ+{%''0 )2Q#dݝ?Ύ;DFF2vXtk'U׋L&:~C !55χBhUd2^/CPPvKViiiIo"GRzd z1c2LpIMMرcn@=ڵ4Qp񨮮nnW_ѵkNٳ'7n_lQi̜9S|@'##Kk.MFMM Gyq@ \7U`r9 V*$''c6q\'cII (BCC.~k X#|>t" ̳e J 2ppHqOX5Ҿ{RUO/Rp\t: d2"^3̤I⣏>b-bv;?ٸq# 8zJ*j*.x ?Hmܸ)SXg̙,X;w2rfq 7H|r222tcI62q֖8%$G_?΂ x< 2ŗF[:@ 2Q(l6wXl6莟0!^|>fΜΝ;y׸[8FIQQsVիW3fKJJ r seƍp(J&Og̘… ٰaC`}K%K0qD,YB]]*cƌ!==]>|8%$>~@ ? {j /ѣGٿ? `Μ9$%%O~zf3_=| vٌO>aԨQωcȑ-R騳f 3fwߕtM$''vZ/^|A-).1(rQ[[eoJ%: >e***ؾ}; q֭#%%(ʤ `ΝӧO磏>޽{)//緿Y1sLfϞPatޝKqRYY) Ѣ >m=N@F@ gtRUUEAAn[$L>}! ***6m]ws/ WnCCC-ٸq#3f`( n喳cʔ)s=lذ뮻:c=x7X|9uJ[S Q Y&++%_ z-(СCywPTرwy뮻+ Çp³DZZ} |gMGc2ٸq#˗/gݺud2f̘pB|I&Ly󈈈@RŹz}K.ӽ{w~3o޼V)mѢEqR@ ~\.. HTT]tt>^УGkFzz:snsןӧvZVX?ۦ̚5uֱc֯_ϵ^K.]b^{5juθ@p%j믧 3wO~|lڴI\@ hJFDD6N !$$͆NF4}>e#| ׯrm(4iGeƍۼ{|ˮz, /nS:O<Ç[^dhڀevD\\Xwq9Nufd̙;{w{w_|oo].0Ep8p̧ sp8444T*;}d׀B@N,[L'\p!}ӦMcΜ9$''sz-ϟѣ6j5r +Wd̘1^z3}tj[-3}t/_άY6lGeʕd2yǤ-FsĊ+P(wbrT*ŵZSqO⫯b\wuyl6v͂ xyILLdŊnƴiXr93g4fs>,F{ӿ>^|E?OX~=~!z7ha#Td5yicJJJHNNf"ǥjEKG};w `l?j:rưpt[S>rrr;vl"ֿ^ W7Ӌݴɓx^<Y0bbbl߿t֭AAAn, *bh4S\\L]]6X)#GS__O\\tN?V˅FP^.]`_gԨQB0Hθȑ#t:i~8_cX8sMlxVoP@KSUUŧ~ɓ'),,$33Nqq1sa„ r!UW]Ejj*^{-:7|;vHV/2=&MbƌJҥ SN%77M]]Hn \tk9teee-ѯ_?65}t$cضVna{&Z,/@p1ছn\βe8p FÄ ߿?NP oHLL$&&j>SrssTTT-ž={xy"$$ e„ B `XnN'-j/O/x6b O}v~VLJe)S| -|<2:N<:~#55ZM^^4jxx}:s%!!͛7}v-Z$F@pQ(++c˖-SXX}GSS& NGss3ǹp\8Nxhd̘1|w0`'8?~<Ǐk..]J׮]ټy3SNd2C 82;Cr`<-w޼ <|>z/̟vu.cةSÓO>Iee%,[K,aΜ9K̟?;Xp!֭nӣGVZw!@ \o~륩 .hh4=z4=z >> @TTGmm-:Xz3oҤI^h4qPYYITToĉ?>aaaҺ~qwtzEɓ)2#mmvθsFP(o~zZ͒%KXd9ʐ^}U^}Uquxԍ[DK^ J%ZlJ%J < NR#Gj8x`{V%::Zt:sRбtѣG۷uÇ:t^zדjॗ^E/^w!0*qݿCRĉ,uj*ƏOzz:V瞻?11;3`٨Q~o-(1B\,"1@ TT*III]Q>/(|9ذa{<ӭڊ`lBcc#}?8?O6nHmm-䩧bq{&==RɠAxǸꪫ+-tM_?xA~, 3f@P3ϴ|WXlEEE$$$pBOоիWz6:^0 cX@ \d2zC(V\j%--8^~enJZZZ q7l0***_Bdd$k֬nooW`ȑq=`ZYz5cƌa޽HlՋŋ/5\þ}ׯ_ѣGZ{᧰QF?Axx8.n_3w\T* ~;}rJ뮀48>m1s+@p[^(5n7r:sK׋Z*d2\.}dRt:qݨ3ׅf͚5L6 FիVj!z)ٵkÆ `ܹcIBq/Ge 09s搔ēO>S+[n%<<o}zj.]ڮhjjX455~ϟb{駱|Rܹs2d X,KFMjj*6mĞ?-j&{!'\Q KEff&qqqX,sss1 DGGP]]MYY}9gJBرcSZZJEEp[UU^{WVVFEE:{r1l2z=63 L&ܹ#Gpuב(7^|'"**m۶}mT߿`5jTLNNMՅ@ @  L㡲Ct:h4;qyyytMX,|>455o0 ݛ'OR\\LSSǏGRT*ڵ+R5SGss3 d2G,2Ӊo߾lٲ*=K.477cZQTvQT( 4 V*++9p:={ʑ#GA.={(//faل`Xr%qqqDGGSRR" z5k0o<)Ũ#ĉ8qbrrrhhh 22E#عs'g桇bLW2,G.ԩS̼(ܯ_ ^h6mW@ \QRI#ӭ[76LFxx82lV+6fr9DFFv1LĠP(Is & FC\\NoRÇy饗zR)@xx8d2"""K.X,Al6IDDjۍAO Z-F<.֬Y77oy8x`@xZݻnoOVV 2G}}qF:.\Hmm9''': _^+§~ݻ9oPVa*%p:Դ9uRBRKχF!((x eȐ!DFF@vv6RJg޽ҥ TUUa4 N'XVL&AAAT*L&iii466Dcc#6 ш墴rv;rG]]^|j5zСCq88p *|4}t駟7i$-[ƍ[}{DEE1zhƏf#==]z៏[]]-mָ0~x̿/1z„ ,_]vIr:u zؚ93HIIal%)J%ZDmm-$'')--ES[[Kcc#fDIJJbϞ=Fz᧟~ɓVAӡT*$%%P(fv؈DRYY)$fffrI, :ǃlFR?PSSC||iӦ1g9poϗ ӟĸqB(zbĈ|Wv;w}71bv#ɸoN'ٳqaZ eĉ|w-mvԝիWok>^~ezNO>?iqʘ={6L& Ƨ~"-\ZTU IDATUEvv6v]zpy~7Wb!hll~I^geٲe[nf?/_|| x?>K.gŊ<쳼R1*VZŊ+Xv-;w7g_歷رc ,}>}IM?8 ijjǯ#{?緿-|'l6vͤIxי?>nvmv퍛5k>ٳg+V駟?vZyy'/FV߿??Xѯ_?}Yx FpÒ%KRJyg@p!\7F!VCW8M3zhyi[;j{rJfY\;WpiIX,"UQ*q::tH .iz"1b۱X,HNѠP(8~8%%%466")**"??\J^` ǃ墬rj5Fz^/GUUGp?xp8FBVvS__Odd$W]u|8\.DvrrrGMM 8?Ncc#%= ~,[e˖5f̞=;`Ytt49ok\DDo9NԩS;,t-ZXcŽ;M0|}iyZZZȅ@pFI)im5tS=۶m (|mlh]̉'HJJBvh4t:, fC.jIJJbH /r\@ݥ.]h8qz(\.`0 % Pj5V`@VcZꪫTvJXX&vF@ee%< O?r;vpu׉$Bġ%//cǎh")ptb~ӎ0FmOb&KKSST\JTrF|>G|Ћ FsE GGPPZT*qqqL:^/]ӻwO>!44T+>ӦMvO~Pddd_`XHNNfРAdgg#(,,Appj%,, BArr2zr9o͝;rߎ@p9ҥKٵkӦMW^y#<"N@e-FF#O=T@Zg[ ]v15#׎6\Z( N'GBTSinn/h+u~n "##۷/111ٯ|TTT`X9r$ǏrZXVr911181 TUUT*l/%χxt:j0Z-ݺu . T': }(J"""0R@p3zhkq,XaȐ!_[.d.t*d;b'Nv #222 BAII Ǐ'))I?~E||[oe<]GTJU ~nZ-C !11X|>kt9ۺ:N9"K ?NYY477S\\Luu52*++튊  ŜZ);):N|>:NC/mg| Nۻ]k&K^.TVVrn7z0tn'??I׮]l|d2HHH@PCzٴi̜9L]]EEE?~bbbhhh&bbbB^';;;v0sLuFII .]`Zꫯ_׋B 88ݻSUUEII tRIffT2**iW(t9888na 9~qrhnnЗK?߇ʻqZJ @Ƌu$&&b ?s?fy|AZ-Xnɒ%̙3^zwHt.z!^uHMMo@ћޯ@Йddd0o|;vHM4 3j(q\&"Ջ"&&C.]8y$wFPtHz4h ÇP_^~@ @ 7rBAuu5h4r9vp8R_\\//PHϠAp88NF#E*"P__/JƠAغu+^&XN}}/ӉD3bؿ?U** RIn0 Ldv.zX_p\\]tAWG7u8t]| yg\?bqAg8q /EMM =5jVU23l6r0gԨQҳgOl Epp0QQQ466o>G+lڴ ox6l2j5ᄆRZZJaa!rX%^Bjҷo_=zo߾Ep Vbl6_(y jNڷX,-l J8|wAPP#F`׮]l?Æ C¸qػwo2fϞMDD&aÆjcָwϞ=7Jhh('N;8rB0 _˅Rc( Z- W_rj駟&88Xvر 0EDD2D|K k-ZZfСvm̚50V+ݺucر\.BBBhllDR!ɘ5kiiijBBBpݤt: #((xztqעh6lIII\.Q(t҅h_&S4SSS7nTbU0zh4oRRf Yh[/# 8FIQQsVիW3fKJJJ-Yx'dxW3f KwÆ /DFFfn{=nvŵdՋŋ/5\þ}ׯ_!JR^x3LBJJ ۶m'x|g,]P__OϼyŌr-ZDJJ 'O-rp:;vǏRC.K}g555\.t::R)>]N0k^iMMMv}t#JMUU> q0LhZj~jXVr9:ZdbQ6N'U]CףR0XVt:]@JRjl6cZJAk0NLxx8Dpp0AAA\AՊJ hd2_jp8h4md2V6? ~]b-:_{5jӉ'//|JKKԶƵYYYL& !CxG[Y|9>h!s=Y`r/ٳuwxTe$3I&3齒 J0\,6pvqY"XOtA , H%@@B@zO;ǐ3hjih'r0LR}899C ʕ+Ҝ#F{nJKK),,$44Nl;;;LMM >>>R!!!RdPP=߿?ұld5k_}cǎeԩt҅+Vꫯ607ŋ3aHMM%99LFIIo2d>,>>>_GvV9s&< fԨQ Q(;Vj ½涎]d >>[WEE/"888Ê+z饗;w'22UVQ__̙3 D} ^\&+tR"##QDGGf͚҂-){оO?f_SnwВs_ njjjزe -bٲeձ~{=vŖ-[Xl-bӦMl߾իWSZZL&ԩSlڴ5kְ}vҨEӧ9~8;v`ƍܹ/e˖J=+VbpEN:E\\ 4{N&u;L&}aX&<>>ٓH)..FVjt:nnnٳӧON}}͋sαgRSS)..FRIAA/^J%eeeҳgO|||(..^z' BϞ=FCnHHH $$=nnnуx@]E޽ G&0a6lF-Y7… y7ٻw//"?#_~%=}Q>^}UF#۶m}׻>Ӭ]*^u͛}ԃؚ^s[{{vd@͍jM&4͜n* IDAT8q#F?")Zˆ%** ^OJJ }aӦM̛7/___̙CYYo6ٳDEERby Ν;ǚ5k$@QQMk˗/h4FYYjf3Ӈ*++YnuuuҼXkaZٳgc8q:0rH>@ĉ޽իvvvs%j5 G222HNNŅ#FеkW9B?ʕ+h4 ť]qCCFY7k:Mm%ͨT*͛Ǽyl:Ѻ~~~6ҚZzcƌa̘1 BMyl† ?<#GdܹEGGg)vIHH ++KWSHwޝ&[Jr1HJJ"66͛77T mK Z{'OLXXXmrnDaa!EEE8::Jrrr' 26l *,,{{{<==el"g:|///x())Ϗ0 TUUG^(--N_|yah6JTTT`gg'OQ(Rc]#''zx"R,qttDCC\rh4J@.sEvڅByRX,TVV@ll, \p*f3r\)(++ܹsQ[[b`0$g`#. 'c]]Yv-6 3gdlڴIcSG 0@z04:v۷Ԁ K.7mi[Z5Z) @i=\r;_|G[n 6 .]O?=Ejךˋ={RYYIݱo%11ӥW^<WSפ1p@"##ŗwf&Rk\f3X,BCC1 닓JRJlܐ888+]fΜ9B<FQQQ(JvvvRFRVz^VڣGNN{dffb2prriaAAMR*Դx  h5&h 6X-{;o̓1\MJМmi!ָ%&Mqrrb̙L&PTѩS'-[Goᥗ^bKsll6T*ݷzK۷/BL&cڴiL&޳7x` lNOFZ+R1c@EE'N 77/Jݻ78qV+M̤nݺh}XKX<rʸx"AAAzL&\pB);ZTprrxٵkׯ'88777N#44vJ.]dr ݻw___OΪU8pzQLAA-sÞSNV ®g B--HBݷ_[S)GAbbԻѩS'~mi{Kڵo\[?7HjsݫՑOii)޽K.K||<;vD&It:ёK.IJF#.](d2a2(++RT޽;tЁD <==ٳ'"==///NJ%Mbb"/_~@Ν# {{{}X~=R(lbbb>}:K. 44Tv-;^Rh--HBq|½bHZVJki7ڗ2uwBrp PXXHUUFB 3tP~/3gϞё|?`Օ/P(BCuu5JRٌF!;;ݻcooOCC Riq{nRSSߟ( {%77Fh$??lkEPPrAJCz=Rdh4\]]vPo{{{z=j\JOAaweΜ9dff#ݻoӟg̘7nӦM#44[{nfϞ}n7o;sy>v{miAږµ cΝ_onN`4e޽/d2֭['̓СCѥKFE}}=}A .U*;wӓݻwsL&_|%::\NNN۶mޞXoLJėsFZ#ޘL&|}}uѵkWK}BV ,`ԩ|MnN`2|2:b!$$Ο?ǹ|2R0LKTVVӧdtؑN:!)**b׮]899F\\gΜ&,,޽{6S( W/˥yT BJBܶUUUTWWKA5qhD&a4T*)((… 899j bRwww)5P -"B "`loѺ|G|Gͮ\Ж.Xh-jtu<-)HۚB#G߁ ܫJ%TUUIC󼼼&h4h4rTFāZ^zHjɥK-;;;qww@Jf_`ޞFJǎ!6LOн{f ++ t:f4.\+W'''rss:t(C ={VKJJ yyytؑX,JF#T`0l01VA СSLJwf\, qqqL>]cood`0 qwwG3PSS#I_)Pd 8xJMY\;wܹZihʕ+`Νqrrٳ?˗/#˥dFC\\TUUk. jiJ"--Pz͹s&))+Wڼ;u#** oooj瓕%v[K1llق3}%,,'N7|/l&==vċA0 r9ZV賺:rrrС!!!tԉ\B0._LMM 6899ѹsgRhVL,ՔOǎٳ;wGGG.\FҥK:u ш+Vٙr>Lyy9*J*aa6QT*)**"rss1LTWWS[[b!77 ׯ444Fff&jZ@=8{,;vt:ΝݳguuuE^^յd2d2EEETTTH A9ֺt={$00HMMŅ$P(={$..???qpp@H-}ڗ5hQQ FW\+:IMM`0HhZj5uuujT*z^())!33)H5 d2j{{{S^^Ν;'%%'NNii)'NS[[KUU555S[[+CVhppp //K.T* z<%%%888T*ztK}xvv6b A& LFRRzd`@Ѡ餇 t:Fm.}gb0o߾hZ, vލ3QWWBJqXM;;;L&vvv(JJ&%%IbSqdd2aX̽{j氛f.^dB\.GTjd28q"Jgggd2}G}Rc2"$${AA  ,?ã:NNN899,X,z~ ر!<==஦rz=ݺuN*y(..ɉ`zT:fl^2I=7J6vm\.ŋRoghh(nnnKS T.h4JA5LKǧR(NW3\]]첂 AYm"joo?NHd T*זozC fM AAhf|L&cҤIᮒ?pDA~۷K=݂ p!22 ;;;y'9}tucbb5SLƲen^BBdegfBw ggg\]]!ZW\ 0շ|'L4{ңGmf|1cbŊf?;}4wlΜ9"`* RTh V+tAֺslz^{5 IKK}Sɉ#GFtttVR܅ 4㔗3p@1,UhH FZ͊+`ҥf:t₇Ç租~YG&k1c |}}qpp7=5k֐# -mŋ 0^~ex ûkϺ:ǚ5kx駙7o 8u.]Ν;yW={6555L4~i&^|EfϞMuu5cǎپ5iuHNN&99I _kn%S(gH%2 SHXX?uuul߾]JO#йsg>S9ݺuc߾}p$ ?flݺdzzjiو#ҥ k׮eΜ9t: 7|Cyy9:7|Ànblٲ\Zb oqYiZ;tޱl޼V7|ٻw4h޴GFFpȫbaٲe,^3gԧvȑ#qttdƍ?[P(xZtO>$*999B`t\M> Voz>TWW~ͱhm *=[OSArP<\NEE5558;;VܖZQhZ*++>>];喇[Ibj G dhZOzC ͍cǎICP(--mL&ݻIOO_l}L2kɆp ^gΜ9jSO1bO?Cmj7tP/^́m}Gyظq#Gg.ڏWB]|K.BxuVF.?'rJq^{;`ʕ,_7x;rIV^M@@@͜9Ǐ3x`/^̿/ B`ر6׏>7|QF+lƍcϞ=L0>{!C ())YWTcQSSC[=lذaIn85-moƌz~az-/^Lbb"6͚5Ǝ˟'>CNʄ عsg7k?aaaܹ"p NNNz1PhzjjjKA}&ܹsپ} ƶ;p'OfYaÆq1ynOvZxי7o^^^|wR՘1cHHHwaѢEDGGk.m…ݻ_|/zK[ IDATF[ԖdGB`ĉd2&O|u[{\7a…̛7~ަ=777<Ȅ ذa/bɒ%̟?۵  +66}B9sCd~~~ 6U_/..MGd25I(m?k?d26lШKszu!d2Y~w[mfS31ct[Rɂ X`AWT̛7y,onhAA wm:u+ֳܵ~3y{{bŊ6}Y~;3rHyp֡*,,ŋ} ~Gzm0^ bx0,Y[;Iqq1??K7++}ѿq ܥJ%bXb&MO?U1Z#Gh0&MqAw`0Ȯ]jݻ/_ 8ܹs:t(ǎaV׻݉'Xh}ao#!!o-nA?~}!BEFF w!C3<(ӧǏVZcܳ癔޽{j̜9ӱcG{p 8}6%,,LLJv CO ʠA8|0䐗' CRopfxۭ C&7BCRv~g9dzqF>sqFukkkE.%vc߾}9w ..#<"/ 0 """AfTVVҩS'(4:-]/?#~MF>}psskvuֱnݺFO:EΝԩ<;v`ggǐ!CsN)`A w L&,''"""D(4Z-o+zyydƎs=ǚ5k]wРAM>Ⱦ}X,@W3ڵ  AkfAhFp»hbKlbLkk)]Ѳm̘1lܸkڔøӇ͛7sIìYφʇ~ٳgIII7 mT^^oATT&L@ff]}ᬅb-[vd7L-ٳgyfq!{B~~>.\w[Çٶm[-]LJ01Y-]OOOOΕ+Wn-˗S]]åϒ?A_=eeeٓK.1e"""cl޼JV+V`ԩM~vii23g'NyA\p2p;dgraL&Fر#?#н{wjkk9s &I~kooO`` s!jjj@ꊯ/2˗/sI ! 2\]]BRI;;~!Gobccqtt?HiZx>sUA~?&##;w2x`iܹ33fNNN9r4 &ZY._˗Eh4ryV^dBӱi&HLLcǎl۶~;Iaa!6l@.ЀhёaÆN]]z۷jZjeŊt:{1ٵkgϞcǎ;v4,z\Ϟx J\;;x[FhݡCo>)A ͻSe'fyEE/"888Ê+linxe2 K.%22ZMtttO<ɀP߰aj`0zjƍk֬!!!GGG7}rFK/1w\BBBPTDFFj*9s&h4bbbX~}i~ZrÄ>S1K'h4ZPvvv(J)kjjBh:\br ԖbA.ɕ+Wʲo]] J\. VӢ"rrrD-OV\ZdI%<8ɓ3fejzpkFТu8L6ׯL66o̔)SntL6M?hihBnn. h4/Kow-GGGƌի?V `֭\|'|O>f k1|p,X@ee%}رctԩU.^ȀX,xyyzjN㭷b˖-L4OOFai?ȑ#;w. mZ-ǎ$%%͛ cgiӈ7SO=ٲeMV+VM|||mnYzlĈt҅k2gΜVCKۛ?>ݻ}ڜkJJwѣGԩ;?fϞ=OIHH ++3gH) Dꫯ@5iu0O<0hH'\*^m\rK.!J򨨨 ""$ pN:ɓ'qrr"!!#F` 44FCNر#p5M^^AAAٓXĉ:u gggbcciii:tRInHHHΎ<233!..A޻ [eeeՉ+Sh#.ٱc,Y¿o}Y^x;cfڵی3W(̜9۷iӦ&ȀlvZ/;wE| &&Ec޽bRǎ;Xpafa9sN:w,J]_|ݺuחBiy\\;bbb`Gq[EzwkӒ , уɓ'Iii)p}3X~=ƍcڴiuVvٳqcҿΟ?'|a@9ÇӓUV5y#Æ Ϗ f͚u!ƍcL0RSSINNF&QRRshi{3f`<<ҹڴ7k,+ƎԩSҥ ?3+VW_%))]۵0vw^u1GhHCCo$988PUUEII 2 łFТ:(T*~8h4rif  "`lN:ٺu+~!nnnt֍KJUطof/HV\ĉ|MYn6mSN,[~M˞={x_y'HLLwQ(L8L<.\Vg}ƺuڵ+_~%~zZ^@@=/ .D3~xXvd̙lذ#,,%K0}v?n~,XԩSxWOjb $&&\` ::UVQYYɛoImmmg}FBtj5 \x\ΤIxWr 555hZF#FΟ?ԩS5knnn|X:408p3gΈ! ܗD mFxx8-";;" DEEQRR^'""/^̮]Ύ~;pttO>899ѡCz) '""B\\\ׯ TTTP__Odjk233ԩ111JdԨQ899 111x{{! QAh^^^=ѣG7lʔ)6~nVYY۷o^OBBjf>}ЧOqہRdРAeIAA ]F1tPzlWWWqanJUA p7d6 (LNNqAAc#pB3 =zsΉ! ܗD  4bp%@HAoFAAhL& N'. p_=  {{{:w ;>=foi!@B l;q6.n4Kkvgcl>mNc؀9H!@uK;?N%@ 33;ٕ滿T*5 jADD!Z.]Ν;pe߿,""VXHDDtNN466yyyX,,""b`$""ƌK2,#QoE"\.x<ȲGRACeH@ X,@etvv"(5Z-Z e_џhOY@n5рg_`0fH4kMi諫#<(**Bcc#֮],?uƏ7bս:V9W~+***pY,_ԝ DDtl6#11}p8&t:T*ttth4"$AV+0C"-- ^0/ Q p8 Ijjjh8>|p0 B0jEJJ \.,jZVy殡PH HpjE3xGlFRRB~?OԩSضmq9رcPD"efO=Z[[ / 66-´ip466"##$aʕƯ~+477c֬YX~=:;wBE<O $&&BE?~Hp\X,G0dBaa!Z[[˗/#>>>-5M,~hM|]]ӡhxt:Vm0Vjqe##++ nFQYȰH DDDwNCZZnCV+7s:,+7tz:ZSNCף III0hooZd(|hhhJB$V`^ZVj # xy IDAT:::ЀfȲ ӉlhZHp8 AV ͦvөԜ ~X,L&~ ))5ǃcǎ)CP>yyyhDRR>77>f̘˅n`0"|4NY+:NKK |>ߠ`}/Qf`Yt" ;QPTö^:F?^W_ ݨT*B!`0`ԨQh4HMMŴi_@E׋$L&nx<jh4">>{/p8jQ\\rAdee!99H& &Lɓ!2331k,dddb@b֬YeYivjZ!"$"66 0 0^_ Vqqq㊊ "''g^SYYJJJIIIHOOe]QQZ%~^/ f`Yjj֭[x>ڵk}QkD"Ȱ $z=E^GnnM Bذa0eh4fV1-+))All,;)S )) ---p8;w.@qq1Y,999@VV֗_8ơC^-D"hhh@{{;<\. cjQK]Le O?4^x;|0^yo9WZZګ---[)_xwk׮>=h,0m~zwsfΜo}[,={6C pu40v}.=RRRj5cwl$&&f>t:7CDPXXf̛7>,Z-ʰ~Z AWP(ĉڵkhmRt V)/0dYVFԤv]plݺO>$Bj2ct>EFIyr_{/EQTqtJV{͹t:aݻ}jjj؈B,Yst:`s Bx<P_^fYtz0L3f୷bYXz5\.4 ]vʕ+dɒ^m{ġC-߽{7BL&vyM`4 }TgfMhZ$''f H7 ~xgvg? vFJJ ֆUVرcx饗+VE\$xG;`˖-?ޭuɓ'+cXj:>ϟ҂rFhZȲ@ Ʉ3f`͚5طov؁&\s >۷SLAee%Ii&>}k֬ANNx =zvk֬ p̜9VB -[{nL:C(h$IxqYdeea0|2yO>$AS~˖-Ò%Kp!lݺ,chkk{ァ ŋXr%l6^z%h4;3f\4(B!TUUql6u[ݪ`0\FȲrv$r(riM dYƅ `܌*+XdI^P(V`wJII 9ua֬YFܺg[o߯4ھ};RRRPTT;v'?IXTT7.Gtb(5l2vAx Q [W$ fyyyFkk+ƍdXVĉ8w@ z hiiQj;;;6ZѡLr}vBEE`ҥ8s p}ɓ8z(֬YÇcӦME9999r${nc„ 8z(Ν;ł,$&&b޽7oyfaĉ?~<>3~bvBbb"zV!"B***sN//s$ ]Cev#-- K,g}ӧOC?~oBF ͆Gbʔ)lӠu% fsSen7EG_z?ܓu~?Fͥ??} O=^> :9}v,XSNO?X,Ԡ?8߁tND" 6ѝR ^4:`GߣJ3P(iӦ?!رcHJJ$IHIIYt:kS#F`֬YBLb477###$ӧOO<5k~_3Ο?AP[[F7. mmmBEEXnDQѣс+V`Μ98x :;;QYY Y__FI&aҥ ڊףJ(6C pJYٌ"!;;[9w͆3g C3|,XeeePThllDMM F AYfaҤIzCV_y3eee,^_xWo%yc`Zzu| bvZl޼oV\e˖p{ ʠ ]1s=8F`0deeAL6 êUTUU. $!l6cʔ)8u4 Ə{v+799G̙3f͂U5vCR) [lQjF|nrb~e^II٩q) %&&b˖-JaN:TFCެcu uƞW37ؿ?`7o}R70zh$$$(oFI֎;hi$HLLVU H&& Fk.\4:… 8"55_W[={6h|FvRRRxbA7 (o0uT8NB!3f -- ,cܹ((( 3gV+~?a٠R0|XV`ʔ)uuuhkkØ1co|cƌlƣ>jɓ1bcZ˗/Gaa!RSS!Պ vc}ѢEʹT*,_ǏGrr2DQDaa!Z-Z-&Mz . 3f̀bOaL0og?Ek;)) <@~˿f͚nϗeWXɓArssQ1bΟ?jt:njׯg[Л>, jƮ3nܸe͛qkO쪷sIΞ=.N:O>?u ,/ 8qw#"4'n3ؚ}s܇ܢDf5awuMl"ƻK/{'ԩSok_>*^oo͛V_~`h@;QMMحMt x܌?UXXɄ 6p`:ł3f7e" =WV^u=#EJaj41cvխJԂ o>e",琈okc(^|E|'ם>8xul2%0WڵG?kh$a|x!g){&Nʔ12Jee%>cHOOGuu5*++1c" x'ܨfC}}-=zy<3]7yd!!GR! ۶mC(ҥKjЀwy-ĉQ__VoZZjEGGn7j5L&f3Z-n7;͛7c„ qI5 ÈD"e* * ,C@l6֓n IlnӉ@ GDtjp:8~8$IBJJ ۑIۍNȲw}.]BBBj5BtRݻ}l6PTTÁǏ̙3HOO (--Ň~FY??ʏh`@(Bll,1w\hZ^4""^Ao~m*sk"55W.hv~|>a޽zz ߏNHG$hnnF8pe3g &&8qZ-t:BZZZPSS VN8N\.K.ɓs}{tLn* H$QT$$$ ;w.B  2:;;1fL& L&`̙PTBLL +#Zc̘1PTt{Djhr`X`ޮZ(4hd2 q. ˘4i]n?ܳ!x8x =|̝;>cժU ӵ? PTJŮnj>Vռ`DD //o@bNn DD4j={|HLLDNNz=I`X0bh4JՖ7ގ'OO&L)S 11WWW̙3())U tDDw(ɹ}#??K=VǙ3gp#55O<RSSqq={. Xf uVzdddٳJ`n9Dt:a6F߿|D"HIIbs IV+u%" .\#10 hjj… pYf_t:qY\xxGЀz ;wDvv6A@YY1~xjbĉ(--ŤI Ǐc̘1XnDQDGGmF@ `0˗co ۍ"|k_;Y910QD"hjjB{{;Z-rrr$111p\HJJWU444(5~h4g" &&.]B}}=._4nTUUp  ^p8Fj\x` dB(,ZXYY ㈈Zfnjl6ǃ$L<V|e#G}dee)s(p @p8xzzKwO?=+//~NV# cǎeA30 }~;wDnnn1N >qqqHKKi4ѝ4}tL> n{7JJN\p$ YYYJ3ڡ.zfp[_YRVEpH555Gbb5}|*#{xVvj[͡5rnѾy,H)))PTʹ Ӊ n}O+5qW:X`p:zzl0ѰV DDDt#HOO h!4 jjj-,zttt lݶ[yߨvh(,F"""գE9N:QF >8x qD"eÁz9sn---D{{; .] 4ʊ QW`f)s Q!{ڲvB!Ӊ2%H\.8qDkk+^/T*#EUTTWٳFw0QvD"AA `ѰX,l$ UUUE|6 (`iXp8ɹveee,,b`$""'11.AoƏhl$I6RZVF(iرcM6˅M6qQRR @ DDDIe%h4կ7ZB+))܆QO?4^x?ooؼih̫|2lhhq>]b`$""nKh4x<TVV*SEDCBBA@0b&B$ hmmmpHOO& h=~? :;;a4aZ>$l6CVC$x^%\{yyy5+3//T֕Jd… 8}4j5rsszl2 Gŋ}ghmmҥKY-e_b~xK/!11z3f___o$IطoN8jԠK,Ii ͅh,(//Gnn.7oF||<z}W^ _c>}:zM6a֭=ۖҾK|ؿ?&Mtd2`6{\/I>L'ĿBR[}T*V+Ν;6\eeeFSL>}555Xlv؁C!&&˗/Gvvr?ƴi0gȑ#6m4jqIDAT F# PZZO?X`Aᅬlj466bĉL:puuu8x Z[[q555E111Gll,Ξ=zl?O;v,&NFH,^xXjz=qF\.`Ŋϟǖ-[ىsbƌ8p>#~;.]|b޽ýދlٲ1c&O7|Nb`@qq1N[ܹslXv-;?0te~& ǏGII >s=z---p8HJJNcM#ݲvu/\nf֭8rokݱc$I–-[ڊ+W?C|on7 DDDCeHǃRݻƍC @jj*B RRR "n7._LB!W&G0ĉ'p x<8̟?۶mlƊ+m6|رc F.\@EE:H$|%0666 {jŜ9sƺ:{$I3g+[nEss3Fq:W_}nV* :~azݻ.]B~~>,mۆp8466SNUHJJ |2 ,[ ؼy3V ߏ={`5j.] ^׋#G(}VXhkkÇr`Q\\\p Xp!N>'Nҿ:x1gL4I=vq9)SӧO㭷ܹsQ__v磾o>G @II M4МN'Ν;lܸ:$A$,[ KGcʕ7 |6th3b`$""t:e9r{'|H$z xjCNBkk+Ξ= Zl,^Ƕmى3gܹsE^^ӧOrֆիڊ@V#`ʔ)BD"F(P^^r=eVfCGG8͆u)p?ży#%%%x/W_Ecc# ,{Z-pe@aa!N< J_FJ@ VeBՊŋ[T,_MMM5j"F#0zh\(j.\ӧ1rH)_ ٳ/VAp)|ᇈ=:::P]] ǣ~@ff& pQgn+7^p?>N> J|ك#%%z =z4n݊ZB$#)) o0{l梣PpX611L+k.v;Fl۶ HLLDQQ~?n7t:"n7$IBJJ 222ӭ =, t:~?~?" 455!-- `P\l6# `0@$\.%|#>> eY DmŊ׌Ԫj殸/^ħ~zgFR)51c@*D "66,#..Ɂ 7n:::땑MA@{{;dYffCRRc?0{lbшD"7EEEJ|K5n8$&&*vlk%$$`֬Y=z4&N-[ ]QQBQXXJ/"66>,cԨQR bɨ@uu5JJJH$<,\IIIعs'Ν;,T*v<ؿ?|>0g1* 'NFAvvrӪjZ鐜AVcԩEԮΞ=j&Lڵk܌ɓ'jb6mbbb 2MA0vX,YtFqq1BF YD0feYfAettt ?? 4(yټwv_+dziɒ%A$''c?~<233iFFDwcǎw?laرc8y$BA@bb" qy!;;Ę1ciuhh'Oƍ&cƌWknnƶm{t7y}\z:ȱ2loMO;}4`t:q1޽E[n&M̙GyDY^ZZcȑp 豣{=|_sڰaCK7.{*#9]b #џ9=ҟPV+455Eaرx".^^Q..z}oύKo]ZZ~QWq!fu2)tjt/Pj]Ar!`] 111JЮp`8w$INŋa41vX466BHt[ W~eYFll3zΩHMM}}]6Udr[ Qydz >6 6mMj9r۷oܹsxbu`f0{_>l4CحEF555wF(***vݟn7v@c]ԚvL&L4IwʺJv:g 10mа[m6,\=3hmmŋ//yו#-PՈWFzl~H4@!vnzaQQQ{P^x=O$n"A梥ZFèQ;#M6_~K=jiP*^^""""""b`$""""""F""""""b`$""p @Vs PTPxED!""M,# jH3 T*aB!hZ 10  V J8c$B!"F""JEvtvvY*@ddn(#V FA;93 /ZHHH@GG#10 G @"-- ,Rp&i@p8h`e%//o@b DDDDÄ,lL4ȈğP""""""b`$""""""F""""""b`$""""""F""""""c8J* :PUUUCDQS+pY0Ѡs%TTT s۳g=ޤI Z͂ "A`a1$+++%F.Z pf"a#:::DX(}lǎ(//rriӦ5VWW@~ V;Yss3JJJHDItzg`$">(q ~i 7\'2&N'ORBXjՠ.R!a`$c$!&&ӧOG{{;t:Y0DDTgg'v;qHQY04`֯_ Z Iza27nbaA#Q|4x<|ghkkCss3Q&"dYFuu5, ~?4~ ͅh,(//Gnn.\inPUU5$#рExנRH鿨jYH]?~10hm]$"AJR~'"b`$A # WBҗo0JII#STpHD7uV~wUU`/UUU|˻#׀#V:y^8A9f2!F""""";v|нwminnFff&222AYؗ~[nL'xⶎ jժA[V8}/005֯_ Z IzRRR9FiRj`AFF8:ML||<9‚XHDDDDDfA a$""""""F""""""=6I%""""A) Wl6XV-b # Jն{a} a$""""Ap ''ەh8ٱco¦M())a`$"""""[==Nus=3gb7_ii)~?#Q1wXׯlZ$Iz0L6w`i`.8  p8|ǎ ddd(AP7nN< ga$""""v!I4GrUsT=6G?ϋHDDDDDwUVa˖-* p[ p;$4gLwAQ?j40["ff5N 0׵MRtYDDDDDDP556Ɔ6%ADDDDDDlڼ ÇR!"""""=,bU#sIENDB`crystal-facet-uml-1.34.1/architecture/gui_design/Navigation_View_v002.png000066400000000000000000002750131415120503000263000ustar00rootroot00000000000000PNG  IHDR\UEbKGD pHYs+tIME  IiTXtCommentCreated with GIMPd.e IDATxwtTEmI6="Az R# EiJQ@QD M)Q%(Azh#5Hl6 lvCQ9${gyܙN]~C\vĤd@ @ `JriEU&?N&<#@ @O &E @ @ oA$xՊ Ѐ\ c%q?1jGa@ @ /%2Qfuʗ)k䑸xgs 3YE֥`܏y@j=n:4|W]PDEE1m|ڶmK՘7>NW|&@ @PXxyN7)_?'*U+*U lɍ\ǑVkLIɓlڴZZз4 6DDDbc9)@ ॠ|Ҍ5 /ޞ|2z8j'T*j֨ƙsHNXBI2qxT˟u1igV\=N|oߏ Ɔ ~i9p9ፍ]pܾ ;b !D@o<=qss!11I'$˖f:v͛q:ٸ]]\ZKF w 0WvlT*MݨV"N/-o+#EGK?7֧|ٙd;2w̖o_L||<T*JrϓrK 2UѡxylmmQꍸ٨+2+OWA7Z@TlC:o#J@ zuB2R)_Z RI1gTSqrihF3ԬпW)*+CIo֠.K2u|VZE]yGK?.wԛ.3;+?ШA]}16o4@P F̀j~JoХ3Ŝ=ӡ/[*[eB AG/&aYRӸ􈃏때* ZmQmnq''| 9CƷ]:&dEl+ř˲쇟$ I["I666ԨTF R&CRe{^or6 9ڱ{ ii鹶{vvti&,do3wכШA];FRGR~@/|2ب\r}*WD^Ll^pi0g_::jdz|0t0~CS;F*=Sf .^bɱ SwHC}5t:izҍߺB4.]ĵkxP!*x2vP(X8k?WJ[lE VӰnm.\ #9沯bppp'--?ʵxyz0[+L.bV+M fNa]tlGbbXr z?T6*֬^JٲcwfGyשInP(ثʌ{t jpJ _ ~WggRZ8UܸWr9m[ms$evM^[닧.URCGYnfNaԯ7} БL?;ϲQEZ5HOK'19kSV jPB9ٕksE։F" `5ҕnYL9Hʼȡ5|k. E]Fr?0*}zvchRRd'`1DYϬ;oq|{s1šzm.]O)B&;CЦ%&N 'kD*+S ~R(&YT}o&%y?(|[nX.PY#Fdwǎbڵ"U)`` ^rI:?,YB@ ԟK:xs[;F6!dB2EGBF9}_~ JnXjѬY3`4R$#đA1bS&7oDV#hԠ.7o6VʤsHj9ʄi_!>®\coP(7}{vVg4J% fFCM9 }o4m[=rX`lw8{;ۋ#S?˝{8{InuI3搐Dҥ8n #6.RI b,tD|r9Ç3lھ ;[[Ǝ]2mGqsٙlM^d2|!1dndւE( l퐐P* Wνޤ_IҥvY0*j S ޞ'$r ʕ-֝!:lJ9g[PّӱnL!T8q&Ӆ,jzx+O{b *e>HJony"/#jзW7\ÐwL$zfJ%5SgKK.:?Gsy7vos96m߅Zm G^>+I OCSmI&'ḽXRO`7Lik,)?ִYtn9!11GDF>7@o+, ^Űo4xUز4x\w{/O$)CZ+l޾Q"=]!ԯS BCGѥv7<-xyzRU]\y**jG$$&6UGJbnq=pmjOl/㍏C~hHѦܾ( II&}oZ_xy_ҏ[vHMMe!nݾ`SǷxq$ ԭ͹ OH"&kvvvDF?D%Et\& 'tS> lM5Pe$WHe5tF8Ma4JlB xzxdc^׹7>ޙh4Z8#h Oꡩv0k}oyד~>,mǚvђl]wYיsX"C <0 afɊU9w!Nnuĥ&F[y(vM&6K:.]3IBr$\mش]lqz;~ ^X\.IŅd&^qqqr\y8KLL|>MFRr"pws(I-[ I9dtԞM^#&1(lMLF.I%qϽ-ѣ@Q9|oZ_fėj2oGf+%%?OIzq ի@ ؾ5gN߶{dMX$NZѵc{N>˒+mͅ[vj: cmh2U[ʜ "GT*%i $h$exd33g_yic>0dLFd#'?GT2pWgiOXT;9ECTt b9<|VۙZ_'&`o-5lOAܥߺsW—QCեm?Hl;xBfd6e?dՔ $2)G[Zvͥd3g'':mŁս3W ===,?9;;enggZM|bB6?ZaMZBzR I8jaxȌL]k;mIR):+˞Frf.rmǚv1 XLm5 IX{S!A^}`SҌ Hj3^f?r:s?$66͛f+PдQl=}>7i+[Y㆙{j8;씧oZ_DDDmZgL7%YKP;y^$I8!Gp$ MJ %JX@ZZiii'dJ_y[ǔlyZ52כ42]s- E]F0䝾;y?czv픯zf7~-cI}7"lǦ.k굹tGFq,7k$I( l(H?Vsk's~M~I~-/[[Kˏ5$I~>^fڬ`ﲞHE%u:<-cޢe=]~ .y߅+\~â0O:MvŤu#.g{ĩ3ť̏,Ir[J=L6#܆k=hTwB`;}XGΜ;L =Ϲ r=NR I:ztt. f}X8k* wcyh0`؏e զbkc7/Eڴh⯿".! /g(χov|0t0h$Ic?>>9l7'O"%z+&-- Jpf}W`0w3b;zJN_MA$8pzˆ͙f$k45l ψRvM6nʁ|4?O6m5nHZZ:{ϫ%Uvͥ\ק^|tQ"xZ:aWW$ c p cٛhHYS͖;%+V2r`ZΙ+k: O>ަ~l-/MkI~͜vQPЫ[gd2gq[k0Q{KھKqM*+ JG z9X1#G`0op54YnoPӧGuU2vF^҂ e`mprpW B+$T³Wۑ_ɆZ& Mtz|Bb#KBXs$~K}GG'3,Zތ/=N#Ef-j2˾ҕ;U.Ɍ$O0,#_P t,,Y[HbRu/UJWpѳkGM^$~2W_FS&Eyo#vɑdMJ+,ik7>,R4))Lr6Qݯ|ͫT(w$_D^r@oXof)/ZmgI$elO^hShSVƒ-Sޞnڳq#^OlltlYP$ҕ;` ..ꉹ4e,b4HHH^Rɗރ̽,} "T*7y6+H?/yh䷞XoyE|kiy7.&&&嫭-6F  (^G XthRR"#,GJ r;rz DJ.Tn@ -; er);!G"'۞%V S Ɩ7A:$%%_~VQ_I^w[@+ׯ3aLЏ˙,'g늜@ @DYdxxó@ @ ,r@ @ E.@ @ \@ @  YML8@ @ D @ @ D,)@ @ (`"@ @PE @ @ @ A#@ @ F)\ /nXv)qJ&gRB&2I @ Ec \v2^iCҍS*2I @ E%EGcU(e2@zI.$PdU @ bI?AQ%5@il$doj9p!!!\ #**$Iʕ+O֭iٲ%NN_^o/yvp|@7(/zKbp t̵qY@&eTL aqRgO~^a^@&{,˅ Ton։[i8NFle.M/:*@RRR8r0gQ%R߿Z Rcj4@ R`{h4n¹s\x³wpz@ukҩSёթXP,ҌK(U֬ށ^O;|X ~?c$nYͬYؼy3*U$((:uGΩSضmW^{||ܹs !ᣏ{FF}Xr!5s 2dw̘5ڭ3s^@p˿Z>}nZlmm Ϳ̙3Xv-Æ chw1gZiäI-.K+ۡb%֎w8df;)%WRk42N[4Cx)@{ߋ qolv'c!䯼-do0)b7"H./[g/ϗOǍ6 M<0jP*@zU&6mڔvڑ@HH۴OOO1:!N6Mu\{`N)xofe<7hdÆ ԨQ>c-ZD:u(QӧO'11蟽Lf%))7{t@_.5.DzQClIOOi9ƏϨQ#i׶ 7n#@ B3\VZaǎEblmYLAW#{&^^^ѾC|Ǚ_4nDR ,Zud< û4\>z]CWLt4o:3gΤo߾f) K.1st4m4kf׮]cU31:K͵ߪՉYJڴiSxIZ@qkp*[#׾53\ŋ9uH;&Piǥw/.XY[_sܾ}mZreC ~Wj֬7?o$e'Nкu+vXmiÌNet!%,P =q0sfNaػcv-;W#33M2QѰqcMaR-L{ػ+Vpi[.eⅬ]5kܹz'WgqHɛޡmvVB:'16%cK<3|0Ι8LF; ոvOgX 7Օ>gƍ|WرEѣG2ٛ-x`'aށR**5crdܹ{bggoSf5v7ƍc@ yٳghѢEۢE Bφiή.Dy1z8$γE.m۶ H< B^lqpPƍ`CѧO dVlaO:yj{=|}5ys=U^pIpzNڵt{E.Nlll<888FZZZf{[͋1'-Cls'eJw]ew nѵ܉LxX<pWbxҟVNrr2x 6'c; toF.ywN8AΝY`={4yOrx"-[ΎٛY4FBܤ̗Ñ#^є,Yv{wiuXx1:po ZC:jųwm^裏XBpr9, aݼAB|I hP(8:ꂫuUyF4hЀ%MSV-~B)d蕜>}6lP8pEGZ<8tQPZ(d$g8ۺ[hҤ 'OFVTˤI,wR;u+.۷a [=Nɯlfɒ%d2&Nٳ̛7q>|hBq _3N-2l{AAA|<"K29cbdilݜQ 2Dm5?R8y$x{{|>5Ťiڴ)Wx"6nWJ6h& /ʕ+gN99Rغe+3fD.bJ j{+ؠ^]j*11=[X1rE{xSo /Yz ߮y<- n:0pp5- ?iSRjU4d֯_OMܥ+_ϝ׮^A9ĔBɉsԭW쵆XN=qCRx,e_5/ ޽Sqh;qI;;1Knħx2c EL[< ح-ܙ-ϋ._z8>gm۶姟~}iKTjժa:wǏf^SOv*5*p*b߶}oC*>`B71OݴG"4,}Qeg~>k,J%͚5@ .:''lhbf̝戡~9REv;e^zR'86aa݆%ƌӵ'M{'':Д z#3z3`p]HZZZgӧ9y)0=`P\f>lNX{;v,SMgɒ%|9c"3gN[%dJƆ ٺNݛ1aSC y"PXpjf/}y^oIyp;JXRQM7.>.wp8!UOɓ8{g1|~#z*;vl߱c?p!4ib)OG9t}kי:99Vĉ4hкU2R>D dl{̜:}ݺWL6ӬyS+jGԍg~2Ȗf%$d.]E=<eˆD057LBBT ;3z(ʖ-KDDWd]vuuE$bbbmxyl)Jv!bǎZ~㖳6o#|8]pCC5C$u+1{E;ڔ: y{FgyRŖ8KH.;W\-xN*}9#JVDݺuINN5f9 ާ9sD=wYFwQ΢ zVr-_|^gLu .D.SZ51Jbj@X)0]h|rP(Jzfe n?I3o@gy)JA {/VV`0`01z FeZmL&Lٲ//EVpju[@P(toP81L65q|=g4nm\&1g~_:Od#p5TZ9̞3'_K|٧zRT̟'Lùڞon{ݜ={5kr/WtN`tY|9i &*U})S&3nܸÇ<&SRW_1yD?`umټys4mJ7{|E0:u>(utDЩSglbdj3&kaΝfљۺ|k,؎tp}ʥ[Hk S(PՋ͟6}V&ö/nʵ|{Ex+6t i^x>>>ݟmcY"dj1Cb }|?yA6z84oGilؒdAuH95O;|ydHv -`0kרR5kаA}5kF֭ܩ#ݺv}/EFmOhG+xg >l<4w$Mn6Xd,~vOOOgƍ3d\EMDl)H96*9x0qP)4vM_njÆ IOOh$\>޷8˗ӱS'j֭СC9qzޢwm>(Mi׹#~YGbBbƬ{[6ǯ<1۠] n2}N$?y]fo@)YUΞ=k -к3kl % dݺK lՊm[Y|Z K63'889RF #Κ'BL"ܹNر0i\[;;j5Q$$$ЩcGڶiC@@JۓF-7wn7!!Ȉ\ە'ߤɟN)'7oޤ~#Juo$]yS.y߲?BFۆtzvNyѳK5nlT^wڵi۶-}KA[F/Nyl1h Ay^|f4gϞ!>C@,N-7LEqڔ]3ǎKҍ8Uض{ѠA1E b/w &4D-ekVP+5;o.+*4:HoSFG$%%ql(7nk\FK GejFzܗÐ>89B*3g"(PϲKR~<emHE `װ|67{DPjD%JPlY9bޒ=odlp0sLVkq/M]e|p(MڶŅƍjժ:):ov +kԡmۂ!sd)S2[6gժU( T:i0qt֕QFcoo§&*߷S݃:⭎#dnt钿AAoh"\]Q|xw\$Sgg ls?`KXvuVC];zɓ'߿?˗͛TMjp} Ҽ0;{gO>6nȫʗ_~F}=v!%wkGbc@H1I-ޯX&ڕcMb#biޡ56l`e$/g]:-Vs7/F#+ٳfe\hߡ!C>uZ .M4aT˗YŶ[PB-ϣP(fӹ(ODN[1[)S<ˡC ׳,kMFJ.X,lbccک5wEzw*v̼gDٺ8Mg:tL&CT!(2NNN8pݲޚ}3a~嗗e˖1{\1c[{9^pUf,idD&gڛ{!W #11| N kЮ?^N$Bp1MXXqHX_׿@| Ҫ}H;Nßz݃CaH[N k6> o#GHHH(+ȚWC< ] Nۿg/l _dq?n޸App0IIIؼ\.Fɒ;w^srV?g;zeUu@Q 6Teʧ+(x(G%Nρ2u$;D웢zqef]œ| qOhh(-Zwp-f͚ŖHqkX~8$篿b߿p*VȄ HII~ZHxpEy7==I!CZ<\LŠK{Nvh,0>o) OI՜[$TKa[V-n޼Y[Rͷ߲d+;vlOb4qtt$99^="\R _p:l fnDs޽<HKKb{Hn3uí(dil@cjƗ5z*zwJ= nahѽ==Z2=wS+fu|Ч/3%󰂮f.ҵ+KxŋT/"flAY=#*6pvTYDɂl[2"b e=i۪f͚DD[Yj9s&1ׯ8!!!AaމbϪaժU?~>K7wW%<)ݱOFF ÈJz=2i(YdbfZmѽ2IO_8z(Sn9Ԟ)ShР>ݺvcӦۇ'ȝ۷)Uh ^:µkW3O,GeCxƱ Dۿ   *ФFtx1հ.hޡiӦEzJS ꃷmĚWӼV{.H؅xt(Aa-/Lo!J^Y<==95ũaUR0G=Fɒ%_J{Gzhذ!c̘1=zussch˄}[Ў8Jm;K̵ۄ^-jԩ.]:G8RsE*T,K&ٓY q1`n oSdg1ҟWavp^|1b]pɭcܦ&xF%J +kǼ#tyբgj__>AxHNNЬT\ʞ=g㣪7Ν4HNNH( *X@E]]e{XX{_UPDQQpU%A7:!$0I&!W^{Ϝܹs+5kƀ\rk׮쏉Nn$|wN洮݋I'Ľȑ#ꪫ/)[=Tǎ ye3lxpF0&wc"E )ܿѲeKZlKY͊8E i|N>1 Wf3݌y-jբ^z\pE/,Z8{g0RSSt{wΜ9shٲ%Gu3x.amq̸j<=:H7Șbi322h͒%Ky"" \k֗b??q`b!&һݝJ.[9.p٘[2}o'>> M) P։nޏ \аaClB6mJqnC :+6#>tHnٲ #333<ŋ3uTƎKyѣG}[jE .WCXD+ &m6^}U.R- rvЁ6zbJz>,(MwܩvE-ee1j쵬XˮັcB|/]0E#{iCӮ][222X|9~"-!U+tU{ xd12,+\{[SW;S4I{.faF5K2%+g7of 5 =Ag-|vFˆ.̅~pB ZRXvv6XjQBСC3gڵ}AÆ|:#~{W3{;x01όcwN&+n'Ǻ^D$.YJx.""ǒ͝d\Z4vf8'L }: u >Z7_(Οoaߎtn쯿g^oFksxIz4b֭e{)26aˁƍc\TU7.2V\%\°a4h3f-[ļ4_쫳8.zQr[˗_~ɹ˨QkHHH.Cff&{RJJ7::Z5`S2&]hzp)MWnۛʴ)SI$q O?%oyАBʕ+yjDfff{ ׯ_^~W_{o#>}h߾}l޼c Tjժ՗x,%,-ZE˙׹tm8ջM 9(=  +:5%4kY)mߙ1m>)o~AVex>ݼ=i&qٍؗ0pvMҪUk.B-{n޻g}6O>$ hE;׫y6wʲ'Cͩ?z?%ٵqYx$ȱ$#\{qz~*!>@oxIoh.|Om\?}\Пk \2avmOؕ҃߻sӠaCkо}{,YB߾}+u qq?3&i.\H|S@BBB=z4FbڴiL8ocrײzJ|>fMqٳ'[l77ޠQF\wu5r˖-#:H؁y 0M_$IPo~ڵ+Կծ]^Xf ]ǿ=|d~럜_w ?- ɶ EbYlYQ9S8xZ1ٵs''r Ӧ}DfF&wnV iӦ΂ 0ˍ&l"iP2]8Ǘ]vO?1gSc_6;qF o4HOO/h!zM޽y'=+ޘ:oy쮤|WX߷ҩUJiWhX;wBB.;!>YmWSgEg6gBwUH۶mDKU`[zks/4tȑڵ ѬY3>}/QCGTPaIJk/,lV\IFSzvҰaCED`^:o|!3߱|8na|ZjEDDc-~NQE33?àASsO>~ 4(=gE7<<#GW_L׮]gk1xO ;vGExܹ?kP0TzV{w.'+4f̘Q}&=7M6]N7BBB믿u|:{Hf+,v3f(S{ˣv:j? q 72is BWNsqGosXkVa:wRɟh Gķh?ǗYf#0w\rrr5jDU.^ŋÞ={_vv68CLLkoXXw>KW)hķDZJ[Tm;+)pb^?+֦8NQvf[9ԎiTt9={2ଳҞ={ӧ#F'(֍7ȕW^g}D@ڛ[ۺuk>}}}rӳ;u.y}IiN6lXa+퉈ȑ.5ά]V G?;UDChoZ}+՛̩a)8/_;=oラSKu5fdмys7oNlllއ9s~-y5#d L4Ӈ1GsNUG6`fm}ŵFMlݺիWӧOj35j'NED|ԫ:uy =ׯAJ,TmYJvmtfi7s;{=31"7is~ 1tؿGC8̡=ywSOM~ݺuiٲe*R?Ӧ}{ϫtr}6lx/SAxX ,)S޽;۷m+1 ex9{_zٲedffkdWp66ZQλQ>pWуr 'tr۱}v{mڴ!>;߉6m;z/#^ddžʹht_JJ ` ,Zc8k Juhְ:}F݆rJ~:ݺupy׏;0a2A&Y*]9Uڵg+osk>$/^IO ?w&fcKjqv^zroҽe>y(=P_Æ /r$ڍl֑6.2wܹNϢY\RRth`\{H>/ŜݵE6_{]7Xyw}K; R߻6xAr-S%O932;w.ի +IIIC+Bmڴcccҥ K.1o^~799~rrr|rSO˻ sBv,X <9q"C ǗW_Mtt4;q*}| tۖDbG]Xk96l{q's%rJ>syi6nH˖ߑ&cBSe{;/ĵ.vbCy௵9a5aYжie;9)g}AɴpsdTB˗Gc&MDn3fa`+߰XHި :N:W~_x1٤-7qIHo6ル%sNQ'"" \ɽyʝ1f@Ry?J(處jOSO;vS7 rT9^=})8Siܸqk˖-O?Ќ%wr]c9bD@LZ O͋'`Sa;鉧r .2Ϲ //xˠ~ Fп>i}7?`S=D2&jvi%{+mj-oO<ŋsq< ԬY={ݳsNjժU!m&<<GH_Ͽ~ޭ;=&'Sz1TJ?6ٲ+4h@XX!!!cJjժκsUkR ПZGpZN~m۶Mcذ~}u]y7ٺu+3g~ʦMn݊UXe˖1OXn!!!tؑOǎmۖpz]ΈKrlc SH\NV#/eaGm.yw>-Z5[ClK;H~P7Jͩ]vi֬QQQn YE"Ogg-_rۛ_nݘ$Fu3wfݯQ+ϕZeut8L'"" \V:)))y]fMV/O`ʔ)I ۑzr+ܸFdmemСK7P}j/]C޽xݩ2PF2q.7Lf(B^3‹yߥK/JeRoЀcFsM7Vn&ƌCR;Pm]כ~GzBƛoJlA.[0`̴1E.W4oQ''|2>(ժU#3#.{+z裏p]wcaHȠskg#ҵ2F ot쯿 jie>+Qjo~'uo?K1:c׿Jw~'":Q wqA5IѪUJkoIj֬-DVVv_HHׯ~;w.5jO_݆g?o?~g$&&RNZnbY|_Ϟ3O?ͦM3i[z--Yu؜CFe_۸5YiCDhZFe>.!2oi5%X2Ӄr~_VXv-iiiDF6-oݺu$'':TyiҴ팍Ld!)ng iGX^-'>UAۯaSɼ|. 6/ZF[ו;Ƴ`7}>FbԨQرy?|oNMJJ {S fԪU:19SON}ٳ%5,X@.ޖ-[bŊCy6-\gѲEo:w|}zC| hmK"';W,N6mbeҾ}RRRh߾<(3g~J=‹ҥ L>f=ޛWc(Q#K7z:l^y:W쁃 <<֭Tem-nP"F- .|;`ժU 8'|ؿ/3c{SKpª]x?Dk˘gcSٖYBWÿyw,pޣ;3>[o׫W?Po>2?K?>W_}uٲcL=u`XĉOSԉtD5}O֭K?_|oSl-.!1 ip\q|uN<Ġwڵ{EԽnaڿ7 t5 VG)OaFL~ F&otT4˯DiBŀC|!oа!u֑A6m v*郎o) 8}Jސ>|{2#^Æ~ ̎d/ڵTK..熿\_=oKv+} ikիIHL$11YbSOa5kw^';t`С 8'OmΘcEJb`o֭yg랇XH=:uN"N-Q㺭r~6i$n7n tR~ifΜ /#*p}qҿsݼ+UNc_ K$̜[-bv7$Ոm{n^u ө};D(p)hyoG@ IDAT2eJlM61d2ocȐ! <,nbGq[0`k֬aԩ|3gyqRv&)ϣMհa#C.֮]>ü|0?eRTf }>_{ / (;w..IۉtFD-NΝy9sx嗹0ks G﹇~S0.W\g[o1dPBBBW Uk ]GvQ.bJHQ}JvVX{5k_~÷~˒%KHٶm8м{wNqH{KRV-*uGjj*8NfT[ڴm[o-3#UFbb ?=HNN&..:p%MU+5<5P ]- $U g> W^y%>,m۶Ak׎,VX<%._Ҷ7kPv"|fry+3}[V3g2'yC>@lO?JDDr/a,qHyq|Ѵb D--0bH>l&.Dѿ'c?dȑ~5kvD^1cFo;70rH.\ȳ>[桲6l-[0g2%kWky|΀*++''>ͣO=C_$éJm;JTp?9K2ଳ6cF]>sCVF駟g7,Ӳ% Ȼ/)t9rkٗNüy?S~}}ٰ٩T~cWTLUp.^q߿Wq'&&lCRR~km^{"""ر};MFUJ{#"ҥ ]t)p޽{Yʄ?8ܹ]vU=CwyOjA ]-n !`Sgqqq <쳬YUVJ||wFc| |R /84}gk6a`ĭB/Xbv'YT. 9/2t>q϶ f hZB-"mi7{mX:'iuv[d[XBHl߬3׾J9idࣸϑ.. dgp8ؚ|[`;l`:6`" 槃i&`Lu-,fw pqC,D=v^He"TD8̲~VRsr/vq;+#` ձ l7 5Y|8x1sT9;n[ aYS|8RMn87L8b1eδ@t |_pV:%g 38[L283!n13 N7$ Yl0D2g䯃&gxoڙ%, aK0b‘""A\YLuYux`/ Ma17^Ym0 6 gFi{! (S5e7Ç3۶b-2*_5؝@ c fgŀwBӹ;)B[P*lT9+f`wI1L)N-k-ci̱PD /H[={ prYXfCcɁMe@O/1^8mw[|;}e;7, -m-2M')o3avNS@fۥ4{>?vrowJal~b6XA["""R*,p)xnE\X v; ^a,SDІXlܓj@ jm=bXX!w{0 Gm3hHp_m6bZoDU0fEq[5?{~LKbO^ݐ22~`9X43Ȏ2n&k{[fWյ)t_W1 F w3){?TХGz hb3-&x'- 4rO@W1񐍴 3~"o8u,.&@7[~e1 sW+VCމe;q+a1+5l=b8Sm\O⼰@!lt>FۉPB|VVDy購lqk:$}^pD=$7e~O5sayu[8._}Jsľ<,W|Y3N9bE;[L=߀󣃳ԁ K_Ff/+t>q毗4ȅ#K\O)pX;`7:Xŀ xlg \g~E,uWS\H'%ע훍[-fm b,&`Vx )-MS鱶nS<=ئMʭ@_DDDGzt w+R6Eqvs1xkp-5X9p‘? .ԣ0rZ.q^0x#.ōwCWv~nnI5z)G}cs뎄b:Q p۸\jsx x.wpqOs]Z@-nܾbj~mP/5VӳC#DDDDZRH% Nj99tV}mgrYTsGFGMs5Y{28k Ϲ5_9HՇgI ? \IK7t5 o$mX7T/0_7ؤ M t֔ro$zH[7Omr$w~Z.UbtKE2E!NTKZbUn+pdED$(?9aro0s`1}8˝bkw(**g57Gl.%?~b;k  =g ;.d~z{myPBNh #m}[EDDJd^-TUul='e+⾝rǹ•:l "k(kŞ[(q]6_rBju" G\DDXn7 Y\uu-t-,.phHQBJCL/:\R+h.Ybp[p {4V#2rG,2q.\…teQL;qtoYh-s^aa? pe{N>)AW w7 =j߰|SEDDDu.P)wGK^ŔX+o9^ZyCMVȷZI783\{2*]Bmn7x#;X]W8rSs>'߬uf|㹈HOS|ڵk,ӅUDD*㧈HZd ?dsnNEDDDDDDXwD%GhH`FDDDDDDD6G|"*"""""""rQ!"""""""d \DDDDDDDDLH)p 2.""""""""AEDDDDDDD$q:ADDDDP""""""""d!cs\h5k^|)D"""""""".""rԛ9s:ADDJW'HR"""DŽf͚ѻwnܸuRzu""/auT8.""rL8Әh""""UR] ""ǻ{1Ҹqc6nxaBBB?><ۗ'ҷo_yGӧ>ɓ'3vX/^={i&֭[.XM6Ѻukx""""UcfbzDFFg^y|A^x~'ԩ/)))?SO=y0tPo)@NN+W$**իWӡC2uJ 7P)MJJoQ""""r8ӆíڡU=Dx8ѯaÆ [DDDD"F ԩ_*A)C.};,"""""""EDX=k䞈ȑ;WQ.""""""" eRҷ ]DDDDDDD. ]DDDDDDDSHE8v^r W\;΅U|[x;.– .z`B ,7L{>o! Yl0{ ׽؅YD""""""ru5`B B~j4lmV` 6wq|}M-z`T[bOfYˀ8pU [`[lAI2Xc#"""""" *nzQ0ʭB/Xbv|I."PŴ4恳vNc f^3 ؐ=\l' u?l7|t3VN 9qZd݀ q.ֱ7_qǹb" vFbXL=Bp*92uAA87Q f^bkIaj!lb B v-r4`qtql <ִؚ]\@2^Q\l` Ldp;&7u-,fw pVFx'""""H%.gpp8 &` :[lmWWʹ_RKxmM?}Y`Y&`l$fsݼQ%fp0-fIpFW08+b6` tgB[RDDDDDh)EUIVc0)^:~@؈|;6*>0oo`Ȁp =kwx*sM,'`d4P~Ux5 ?0c6`l\=JDDDDDDwL.DJ{ek'MցYw~M ) [689{ŭ֫Rˀ*݇y [i`c_@Sns?qh""""""GzKYÖFbo/0!`>3z֛r0.L{_hK a£-Ga_45a?=]`RKx>Ui#""""""Ǿ6p)KR"6bL#Rz0v©-ng߯&R[ͥ\O<&z"] !7p`! | >CnwaM[bYY_|t IDATp,w\NV@+M9py{-pno 1- >7ō-[)g!@H 093 BABE(6bYL,atLl2z&wXl#""""""=.`[ \L=@M-&xK#MCWì7hFnW,1趘=_ÏY-.aV n?xxK@WRnvMic LZK,16;pmlS}%"""""".A Vk#=-6b:0MItp\1~|` . L{@;{@NB÷˅.1B5?l8 +d s*4`8oY?` ]L`/c:`*n^EDDDDD$p&}5Ni=m3`[BZ`/6WnKsx}K.Qmsq_EDDDDDj՜.ja$`(?""""""R:U"ٺŬ60W9&""""R5StA"['ze:;ۍ:HDDDDDDJE5\Drm)cvqw@MDDDD8GCDEQ%"""""G  S""""""""d \DDPTstuHp)p9`AH)p 2.""G\sEDDDDy@DDDDDDD$%T0WDDDDEDDDDDDD$ """""UR䋪)6](RHyi8GHy s5HDD ڵ+';;cUԮ]ڵkCՁR*iiiݻIMM{CCC"&&HTQ \ÎdQ!c""REzjV\IBBk֬!--;[w{ H Y eݺuXkby1 EtЁ;ҺukBB~z֯_φ HJJbXk; /(VZDGGOǡf͚~z\;' j7qqׯOÆ i޼9͛7Yf8:o=K t]]YED*Xv-? 7o&,,8:uĐ!ChժQQQAojj*k֬!!!w}?N8zE>}h֬^ļ0Clll^1x`bccW^~dO6l 裏غu+999ҼysڷoOZjzqEDKqTH,;΅U|[c݋] ee;Yc ?mbOP ,5{n8 ֗6B*yxUսڇccIDRU[j^E *UuC"Z@,(22 1 2dN9! 'Iy=O=ke &4ōqEQ "KJJ K,aɒ%$$$ЦMJ&MDˬXf fbϞ=jՊC2h """tCFf&7nd͚5|$''SfMtBN;iӦ >/hܸ17{y^מ={غu+K.ٳԫW=zpr%""pK6%ɬ4p_f`]l_ 3`p/yk49|jnyoҥ1( "RqË/ԩS ;?OEh߾=۷gĈO87|âEx'V]v{!Q"""%E \.4KI12K`ve9d6},ճĵsp1C 6b6s1bdIhiUǑ#Gx/6lO?4 4PТE ƏILLcȑ\qq4jH7|rs!.}GXXXEz:G9pR׫ǀl1WWXM\x {UO"RnN>ٿ?=]vگ_?w}ĉiٲ%SL%$99W_}KҿвeK&H-Z`„ L0}1{l|I̝wI:u$)\^A!(8rIIw&Bp6;8B 3^Nomp` `j98b{P84wgw<l BI*g rM71tPTdKN]vwꫯfԨQ|Ǫ p!?swҭ[7y衇l)VZ1i$-ZDΝ;x8t萂#""AS 4Zt)OZ֟`Y1^~HS@zd⟳I"!W l큟^/l  lz[) v97YCI7H{nœ v')4&OLXX'<<<+5\CDD)))r_S駟2cƌ*7Hq:u3f{n&N=){[5\ƍ{ر#'N,EDŝSV&tq۸CѾ_ (~0 fY *Q`omim-j2ԥ*u߲'z=sJdPɖ0bcci׮SL y! .}nݚgy&s5הI<Ù1c oV% ¢E馛KZZ?0oу;w9yd>C6n܈ 8FDD&M[n|}ѹsgNj׮M޽>|8o:t/~(6l=cǎ%99Y%)))s=Y п{o6;vd޼yݣ!@Nꫯ? qhٲ%w?'MĂ /Yxq@=X9gz\vm.r %\/<]fMw'q###ҥ >Zr'""" e_t)/{Q/!ɗPFYH}ok[+AduMYhl+F7;bX̷9w luPpRP7eP) WaSZID$33ӭ[Bˮ]xgYnɓ6m?RfM{`Νt҅/}wW^y]vW_>ۼk|rׯϺuضm/СC{ނ\r%L>9s3*$~r}$Z?κu7o=Q^'_c~޽:0{z>V٤IzΊ+ĉ4l0sgffvZe渮j*ڶm/k^ <[?8+V`ر曚TWDDS{3GK({~wL[RL$8 t[-~S]\f^3 xbuy[?kk#[i'P$!)R|<cƌ9/A.]wG81={6޳kƊ+뮻7oޜ7f;1&`9ܙ3gz$H5p]׿] *ѣZ:uc2mڴ-s!99_W^={ܣ_%\Bݺu5kg˖-ٱc{[o G+~uZj˝Ƙxqxޯ<#r->}ZUDDp)ƌsdkq; ]\n޲6B^=^z~26v.nWK2_s·@e{5W\ܫ\@ 9R0 {%L/^#]'NN; nђ. :O^uIDJŏ?Ⱦ}C$'^'` 8Yf1dzo(^zw}<3vm >ݻwop-йsgnqwзo_n`T^3gkƌՋ?OD;o0FŎ;ySUs=L6.]o|?Ȅ ${xWv'|ԩSٳY1bf(cegy&Bu)w9/`xUAu(s*N$%N`g\)|vŷm s!YL8_;H,Vw̹[*OKbd- w>b/؛-qa-D`-f̚5kٳ'we̘1ԨQo~)""]!PCFDDJ϶mܹQ;vdUsrZlI5J\OSիɓ]6O=y8xhР>(DDB9 -""R<u$$$Tk駟Yj۷ow =;w' xڵ+~;ݻwѣ\qy;h I`˖-Ԓ""R~4(%[DD4ddd(ECRSS&''bS\3f^`֬Y\?ujUj׮Mjj*'::ڿݻy73fn{r ,Y+xl{A!Pܧ  %͛77pvM>}B,7ndƌ>}jԨ_r^z%~>ի9{,[Ve 6nȈ#[=z4/.$%%pRSSIOO'22ּ;""@J8/9dXmۦ@-[˽ L49sPnR=י3gx'8y$_|mڴᗿ%gϞ-y\d={5kx˛'''3c Ì3hٲes!nV>ԩ*E )K>McTT۷oE!1;]ɖlC Xy7 /'NTa_;^d޽?6m{͛wDD$( ""R&Nc=@C&uVzY&Yyxlٲkתb5kְ}|'m۶mӧ~/"p)eѴmۖ?P¼y󈉉UV!Q U+Nߘ:u*6mR 17ndCҔT&Mć~Ȝ9s]vңHb<,ZHaѢEL69sRe FDD/W]uÇgҥaĈ 8T^\Q=jDDhphZmB]6cʕիWs7kZoYv-}C )򤧧릈v@DDl1c  #l/K2rH “O> dɔ)Sx?Q㏱!+!h"n&̙Ë/_jԨ#""ڔp)'C?dٲe3ʬ@aF|5\P M6e̙l߾뮻ӧo>ǴiӸٵkߙ9s& 6TpDD$hSF q>SO=ő#Gꪫ*uZkxWiԨ=M4Q(Akc͚5<9r믿-[*Hطo .O>I&z< ."""!I&̚5Dx fΜɐ!C[*tbO>o߾̚5F醗"c }O>|r|I;FDDJ."""!aÆ7t{/ez :CqFVX/Hzz:]vO>у TX;vuW_i&"""=z4ӧOWeHrPNMMeٲe<ٳ-ZpWһwoZjUeݷoWfʕݻ3d.u3CH\\qqqw}͛Yf ׿8vt| IDAT҅N:ѹsgڶm'##ݻwen͛IKKAٓoS*(""N Np^ ^{-^{-gժU<3$$$8۷stؑvQn/GRRvg֭رLի= @ǡ[ntZjj*7o7ddff8M4uִjՊVZѼys6lX大IHH`޽ݻCy_nUm۶tܙaÆ*'""B  e˖31cɮ]زe /fϞ=$''d\tE)֭1k-III?Oo۶-;vwmڴ'Cѣ=zxZˡCɍe˖qA;FZZZ5j 22:uEddd(.u/:udN<ɩSHMMZ_:<< ҴiSӧկhڴ"""@  CLL /{?%%Ǐs ?Njj*'O$33# WrF6c ͚5YfӧmSRR8u'O$99ٟ4ɖ]AZN:DFF "".""‹7EʢEDDTIxEDD.]!&Lq """"%C *lڵ H REDD2m4FKEDDDxp}] Fxx8SLa H Ѥ"""UT^h׮Vwԭ[WA)!U.Npj""R;66VA)!U*3ْ׿EDDDDDDDJx0%\DDD7|XW8̞=dU)U~aEEDD*1cPF ˴iԩz/?fҤI׏ o_~&6lGSNu]=%Ke~gV^͐!CԩSIJJs=G\\Gfɕ6N"""Rt2d)|.9>q]l-vs4VZ:F"".#**޽{M^f͚]z /_ *U>e˖1d~_l24i>~+"""Jǝ|.58ܱ.Ŭ=ar@8HF.u-&`1Pfܾn} 40?q'LD9ipv9e~6b{[h|`.pEf,jI&p;`!""mذa 6,߇R`DDD4(KI1?8DH,8{` #^d&#,Dl4p#݀r,v40Mf@<]6/9`};xҸVf7Zl[ 6}1r,H:{5`S- :FE-TN_C>KQ{dr4yuSVB0dLx?ZbYw {Ḋ?n\L}Lo0iY%Xhmm1M]BvG^jqov'ߐƨbpd؞~J "CDDDDDD*'p)"|w{'t0륾6"-h{$Kmi?ـyK59ğHx֟)km,'[d4p5F,8l0xCp*FE,TNUK|&AޮP]Mрn jb0sMv1 xɁ|Z-=Wk%[Q8~ʺŨJIC/9Ru٘=`lCo -&8 Lj=8r7j&-"#xeR)rHTe.$S t Q.Ŭ>I(8acPuxk[{ Qj1.Ƶ3^i&CJ"F椁zy^bN.ARr3KDDDDDBp)Etْ#M`6;bg^6q,c l^+{`V,.v` 1F.Jdg-ʹ=L""""""R)iHQv$717j>s:𙯍п]oRنfY~ F{9ClL0; Hl0ow g0`ÿ|cmw-O (G1bsjo5$iip:VrHT.B-Ͳ~2~p;R9i@,dYip;󽃛B7[Lc|`L8m`>p%Hv'%VfCo;)k%c`7qn~1089^ځ $K)xU.H?wDDDDD$$UKa-5v 2) qg _.s`?LHp/t-u,3>wcj0+ ,""""""R5K Tenq{DZh ѽ)måm`!&.f.pVMDD<`ӦM\s5 H  :T8GzeQ0kM+H[opBȲep_ H Q*ӄ,RrEDDΗܹs`„ \}Ռ3ϧ/bN8AtttkZĉ H Q%;ZnUDBDQ VÆ ٳg`$$$РAGDDD(ˀ-""R+<cxxWTpQEDDuK/qI^~e""""RªDy 袯$T1opa>cz)4i߯*Es+gƌ H SBDDJKKc٤)""""%L *j޼y 4y)""""%L *jܹ̝;W)aJ|ӱcG֭KǎY~""""Rp^~e&L x|={VABSED$Dw n֭[. NjԨ HUSDDB_y=Z^y&gΜQDDD-"+""BABSED$?ջE\޽͛+"""R H+xb3g[nQ DDD4HR))aaamۖڵk+5>|͛7ʱSRR+dddp֭[ 7@^TDDDДp)gEJc|gw'&&m۶ѹsg^~ex ƍǨQx뭷x'UsΥ[ngU.p)v]:_Uv4k֌jժѧONS}PDDʏ-RJ{233Yv-uaȑ|'|W;L<5kH||r+{i߾nT.""RE\N:a'OF7.Rjժ@jj*+V஻ ^DDDD.""夠-EJRff&_|1k׮vJ59rgynZj{)""""EHQEJZzzzSRRܱcGvvyۋH*d¥44HDDDD򨐓nlRc6[bNb\f`cV8YO^/`ֶmg1}N/RB)ydHr^t޽6 n.ym[F>0 6bVRvsؔ>v~kqw,vŜ1eWX5z꫘0Gy^M)ƙ[42.omjI0y's %w Y^¥`69B_0L ا1. -06. =xebXZs^obZd9f0k hH]/,4`: y .lRg gz7 `]I:1%~ZREE nX )`)]V\ۅYa1[$ٙ[ CuK66\c޶ Nb> |olŶPl{ 00?8XO\ 3]pֲc l1xɓbX_O{:Gl4B &lg`Ywr&X.tqʗHQEDDDDD*e¥ÊJz z=J2gbc-}m/?`Zo"ٞY  q hy"nIV F_>7w t]_+,Njk|/~-f\Wb6ؙ%-wixY0 <3wQjc0YO[,gLx?Z ;+fJ(""""""JTF\C`/pI(8GsL"̗fP%bĂ7E:^۬ ߩ ή"63.b޶g^Y+@;k0?;sܜ7+ĬAɖldciYE1I^zϐQ'\[&\ki5rQΡ>DzÎ;~1;˲}o O"hi5#k" 'Ylmk-vr;)M-sb[.,ߢ\Lٟo|@D6d-=nv oc\\#۷@obcĕYzHixוp)aKQ.t.N%[{V,looWoIB`=hBt|`;Z̮ Ͳ~2~p;޲*Cxɧc`lWPSi+xHvMX!k " J%Fiv/sj s`y_rъ8,>i TӔn""""%K!J"P{{)*ra>rKߟsu7o  &\ ƗHp^!<<$4hPnexW;v,cƌFۗiӦѩS'zԩSIJJs=GϞ=4hcΜ9nv맛*"""N=\Ը)碲%g.t=̐K.aÆ uRLFGxxx###-[Ν;iܸ1Vo߾p =z+uI7UDDDʝ9ls_cذaiq$RZU3'>> 0n8}]-[̙3iڴ)mڴ!<<G:uϳ皩Y&5j 66f͚)8RfW >R{D|J?H\Dh(JH8p ĉ8̙3С$"""E= r" գ^z D>|;E)"""R5.""(Hi}\%]D*&Mжm[222Q%ՠR#K |gv)D~.=zTsT A."UCYI ̙3q 11Qª)V-s%WD*HF͒%Kp]87oT A5 >D$4z||< H.!RbEDDJہشiݻwiӦ HΞ=?$%%ѿ>̪U 㢋.⢋.^zԬYSynǎ`8%\BDK%]4HDD뭷b… 87xn_ Ν;ٲe [ne׮]>}k-ԫWϟH Cݺuٳ'aaaٳk-iii8qŸ9s ԦM:uDΝi߾=ժ髙.['N ar'V*J)ܹs`„ \}Ռ3W{nK+Ctڕ#FЮ];"##KNb׮]lݺwy;vA-իW^y%ѪVDR%](钽HN8q^CUV8q TOIIaɒ%,YڴiÕW^ɤItH∋ xYYfgZjСC4hzns+"R)RtoHU|Kq4lؐ={~ZlIHHԍL/^ϩSsέOJJbرmʕ++w}tܙ;I&ѭ[7\%"""cdذa ;bk|Y=ɹ,&,v0ӱcG֭KǎY~}*ff&Ǐ[n>_c=d3L6 ɓ'Ibb"񤧧|r.=ιwҥK{r;66hL@IMMaN}}w K>}:wuznEDD )n2dkI2 fu큟`#ՀDMoh0IogW-[٬7#ˮEN`*5^eqouH '7Sl۔]Pe9%]g"_f„ L0_~BGa̘1[Z'O&,,Yf~eHMM^cŊu]ԨQ=wOds=\:9̙3Yz_c Ƙ}:V0=z?q$znEDhPXٮV)2 7tbfO嚣z֞`$2 W#^NVv.NLﲖ\n7)rq:Yc  QeXaQC6J* n֭[.T_ ~GW$Bff?{w$Wuֆ$$ƈ, !dCF` 8qWL`Sv/^쪄=1 ؘ0`Z@E B;BhҠ9zϫJ%h{Ͻ}gqwO9\u-1D9E wM/fМu%_G2dr $5zTߧO_ ǩF{~{M7M7ݔCOϧ?ve3dӦM%~~*~;7%\dKw~ .L7ICKJ d3 ;!Nddw†eLLyl*C"|5Ǟ&\rG3T@zW}M3dzw1bc] N,SAB 5MRu][Īd";466*4iK"""S MzJUx|)7^WxAB7eD^6̈ #qTbYZ)=$ +J1F?aw=Oo?{}0f㭎.wVTNzByH-,[ɓ'+U83Y|!""rKd ^ i_[j h?ӱF>%4dWy8ɡle^oUh.4hmmeK-ىWσ[5i^?ձqd6*g+ @aS6 pC$-}]uD1X>aܼ-6+%֣0`@apGN""G3p9-}iYotl5}xK蓝?eoasފ5-=`\>2  /v^ Oec=92nPږ)66`n9gr(blFOӶrSq8p6t."R{}ƪ&S<_ %YvL>uUTӧ77#VZ'Qh5^52Oe4CdԥH e˖3pw/}ɓ'׹>2f~Ĺʕ+2d3gdΜ9?#'OfȐ!%8p SNe׮]=zΧz*k֬ůªU=zC~i~ԩSYp!^{-? '? qXz ~:L+޾#ЇK>/IDDʧ!ExEDDzV۷onaÆq~ӟrwpBoS[oc=SO=ŰaӟĪU8Knׯ_sSS˖-ů믿g@\L0!TG|;<g?[naٲe<;L4_1cرcsco-(3SO=СCK>/IDD*h+"""ӡ.*_Ǽyrxp뭷ҷoܰR8pロ~wq1<ۚY'[)›o˗/gVC?s=Lj#ꫯ__6m %QN:$:|Or5/|keq XyN""R>p.-""ҕYfѿy'x ׯ_Nn& įroYfbmӾpmzH׾oo}K! bL4O9;o̘1?}c{\zKXWHl]kş/\9"rt>+{|n+pꩧ2yd6o|s3uԂ_{we˖կ~UŜ9s} zSCJDDC=WR׾/K^y]N,^_z n+uzal:rf/E}2 w}7v/.P /_W5wȑh+"""544_< HG}W&;9Bp^kȐ!{DDDqqo}M6|͛7/||#Gy;F~N>d"""uD ^,3NO>477s=}K/O}S:1i&'x /1B\DD)""""GÇs-nc\|\q7a͚5<< 6믿/~񋄠dH=SEDwQ]v]v'?!Wfٟ3gN;u]ngeڵ~\z|_~"""."""rL߿??y;ٰa!N?t&O̙gĉ9j^;w[otRx |MZ[[;v,3f[na̘1`"""."""rL3f 7x#7x#[<^]vi0tܟp '`f;;wl߾=g޽d2&L3sǏ~Jd2L4I&q5״}vv9pw例>}0a ).""""0`FbԨQ-HKK  PDDDq^DDww+5|뮻N%\DDDuO=Pwga֭_^9)"""r۷oPַ+׾p##""r 8.◿en%CpڵF9Yfn.c.u8ɢN{=я~DCC7x#{׿׾E/0}tnR·{gH?x{;q9)"""r=z4N]Σ3g2vXf̘/~ FŦMI'tDvZƌJDDDpg"""Å^#^cdʕ9{-[ pYg("""ǶO|\wuߟ+#G?ӹ_y啹;-믿~z+Q¥ś#.uDcfw}{~رw @q1\<ɓ;NKw !#97p7p!"""RW AS"FDDDDDDwQEDDDDDDDƔp%EDDDDDDP¥QEDDDDDDwP¥QEDDDDDD) )"""""""RߔpJ=p饔_} &W͑pWrf׉"bxc [`skފm5šUew8OFXar""""" A_l2Jwzx_'^a2xlᣝɈ=z~vu5S~=kJ@DDDDDz_^!%_* =ndeo‚@7Cб3lHuJ6O }4hxQC|cAkS7Np1emlj#\Vza0<:l|öZA}s 6:M04/@ x 8aQ;>ɱEVnǢlj?a 5-E1X!0e8>4>!, ؆ˎb]Fa0nKq~ݎ2O}08 ,\c6B;ěcÇZdͩS2fv O(n\:EJW B:C1I nʡ|c/ HCidgGUؒuUĢD8s"PT$=7WK'ewk=]` '79qjĖglx'ZA~a6 pb p>kMTV/13cNN8m75xq rÊlo#nC-[?\'a&|6F:!`2lBb4'Ţsly-ӎ7:<߆\*;ui f{i++va-yqS [M<86VgW+8*& %\&[԰}8;:bv5WL64 ,>Ғ{,2̰wUPӁm4& (h[s6\v6L^%8˾0ۭB-waKz0o$lڒYCz.%[HM""""""JH-T;ewG49Hx$`R֤%%o8-1|TgFlMى~K.xwy.CkĄ]+7&?'MhK"5Wv-[g}58<o8,K/UU D8~?<ǥ3@^aZ}h21 9PF ;C*wl]Ţ3~7,4WʑA9UqkK1;NHkJBJk#lLayP5$8;̫E4g҄>qJ$w†;sű(p&NhX:K0OwձUE +1[ V+Y6ҐBc$9m*Eӧ#cIRewk,8q*`h6wj%\DDDDD>KjrZʕ@&r@?7CV䆯vL{!B/":MiN[Y! qZ^JBKK .i[1C,:J)gGؔMIeDݩ-2|k󚧡=I0 J-2ΰ ݷ IDATZ:VUl*};(U7_QlSggؓYw7^=k"""""RmzN/]wiOMy+z.BQr-qZ?0˺mDDDDDDD:!Eu,Ѱ"""""""%\,j)Ԗ.""""""""5H)""""""""RcJԘ.""""""""5H)""""""""Rc}9JE|-"""""""GW[_!"""""""һ(""""""""RcJ"""""""{(ҋ:oě#nzukvVǏ)׻uz+qM~N|$^[ywȱF ^'z3;.;Ū.۞5le7?`{gC`$^2KżQDDDDDXK/Tˤ8v'nY!o ۧzO3_]T]GQW+-8~)l̛lmks4Iɚm^IfקgWmx4T3[b4$)Όz`4""""""N I FPe#;A}FHiJ=Rle3X|8ad-ZوÐpy7%†ڌ!)>` <1%[~?LKv>/ N,Lophk62X[D2 2zH}~>:PgEhxaӀ`/)"""i:Rt8-aY ?{H::l!82v/QQJ+f񅱉8x\#͉/ly4Ӳa]^N1&>ż*`(tձ&\>^oߔ˥Jo~N|$^[ghV⸢'cZg{*;HߴVEW{ꞒhOCx79;KGH ꨇY';·J)gGؔm|IK.` i{)a +\qiLOI[liI \lk(MFOmWyġD%ߎiyirY۝b#Np Ra~T$y ( i~orh^JDP?ѱݿS8`'Os|~fػ/]{BZQDEu{~@3]&»:׮ &>ʩ_gǩ<}?󳨣gEGAg?EsTQEDhMO+rAz|7&Z'8,oi8'li2[_}R#ʷI7.pp$c3.`op9`|W:vRZ^2L)Q$=o50>FW-I{4DӇzaRJOCd X]8Txg7S\~auW+*m񽈝jJJ MsK+rTu۲Z 3{:<_%iǁ=d;m_0)~SmÊ@<5¨ռYQʊA%\')""REec`<9s L–brgϋ3z4Щ2٘MsN3)p)\muxo0|)|[a¥{o-mC`^,CR[epjj4tk'=P ` Komk'CA=׎+~=TnYTm^QEX)VdHXoɘ䵖]֭×;>;eC3MKہ*l 7!ki847 hm>x[=b4\ecbAݯFxy\֧ƽr 4aqMYa!*CJ#nK02R'wS3l=r`=Vww,"~/B ""G&`s$+@kZ(g-0|4%] pn+-[!,󣶃me;ޚbRiïĻz'{E Q32k$zÆ[?̄Iv_elo~V: mh*` Zns?%TrOe 0KSc$59גóK wvoU[ww^,&5/2"""^2xZz4"'8>i|2ܷŰKTOHG:^ 9Rg^=l`ԯݭS/zUrKn{>Dc;v*D?,_~"#"R'uL\I ?I&[he2o'F4 {CÌDwzQ=]_ sߦn-ω3c +l5 MFB!"G"""Rⴘ Orēc'G0 [T`ycw}pWS]7Oc$l Cg&6ߪ^VDMa"rREDD^"oC6+""""~SDDDDDDDDjK u+"""R4HDDz a0nE*:M04/@y#8>섮!, ؆Ʊq|8`'Px.vY:Y}:~#Z޴vW,V滩u3ѱfʺ;]a,2 3WFĈ0 hۚ-cuYJQE FL;:QEDDf,-8AQmO `_05'W߶]dK_ǯu|cIq ' ; `7xf>رEm{@ǯt`K 7:6ºsq㰈_i8>gC:ƘWQG&`Sh(1~ ‡5`/׈#> lWu} J`_:6QEDDaE#nnK P'mنRp.$\946 '~2t`%m!&a^urǧ;ۓ;8 {'_0?יF 57<׷:'6`t*9<փ& =%%JԩkTb {rÒu'^SDDDD UAaԵWD6k=mN{;äx-=-$>ѱK /JI|*w 6'WK%j^cSGn'[jTm3e_\,)N5}6 f5_DDD.u8r5%]DDza!mg_zm[;N0lmsX`} o˶l]*vl]LqmfCVw#Ѝ:w Y {_DDpQEDD "+ـqkىGnwzY7n; lvXb`ZCvu!Ri4 8%Y9*g9ḷ:G.{*#"""SK^DD.T?dc 0#/#qTxH^аD|v^{04x?;A[[]aóK*?k?^xM鿭_HױT=)FܽqX"ްᖫGTD=\zr.` i{yAlF%4-! kLFOm؈#\V1bWv51Fr+]ߗ+ZLNJ=;jZי_&VexKVL8;&RB  83-tYp:MXxvud9@\ג#]RqyS}pdz9^ۊ\iH  vǧ{Uעs!-VNuS |F"yOwG9͊dBެ^{X"ɤK+?O{^x ~JQ#a1n[ ov8jǷyɱ:FG=%""Gpmڇ;|^ø/]B[h@FW^ diumW11/HKv|sW& jruHhK [>XOMEss*wƳbպ^eBٹϏ0 짆gX^+Ia0<%\9׭Uֺ8Vתcb\g׫U{ƛ#i2?n+u]uȏ}9uZ+s 7lR:7vbP/p| ߴ.tgejUwVyw*<_+k5QDzđHxg;a}fEc#qTQ=GgVa8%u|XmaÍ82os$jjU['pRClvxIg{uעv [< H J)gGؔMI *b' ])bc OG "X89ᾐ@78~r{> ɰBLLC`Uq-72O kiOD/̖h~7(]ˡcl hM^֥نg*nF 57gͳneƿ.Z{lH}鹔'<r:ǯs=߽{m ݸ!bWZZ[P9VF{nU߷MZgFpۄqcĮK+-گ {?/rOnrͧ9ad_{=] WYPֵ,J29T=Yܸ:(dKyFe{^iY/<@b=h"lZ"klQHݴ'>Rd8INTY6cПl 6?bgeWJZz}Zsn ?1ԅ't}c; RڒRj]ūZ+Oᶆi|x- 9 Y_m?%b-c@c9fwu+7(ZUtrR׸Ī9bZ]Q\x;кpU /g%X7:ڭjP\V85g'hH.rh;Htsۗ{nc9᝼z۪hW{/q*'KųfnܓUק:("]4yc {/sA'eEKz+KEv.* 3c>l޽?YyOJl% !\ ض'Ʀ7٘a7B 31ѱ;h_1nM{ڌm  @ n:I*RUOVe*ޯYO>L|\bV yr߆j.ݷ 5y׿"8 z']">$j\ϣYޫ~R{l>$,Àd)U }|\p=Sg7!iDr|ޅl',# rOWӉN rC3|+?z6S>wY^k]sݔ}^l^]ڶqbwBF͵MM =h$,X[^^}A 1b:$Yz ځx1'\t$vw8ttJIc*';vۆ j^^ɻ yX3_yծmne-\c>JZxe$Pi70;B-7!ٰƘ4._mw!,/]Y2jY''I~-{ʛǪ6.km^oo.;'{[Xa=_x-vmvuq'VMͽkVV{lGIˇ#\2oq}I*U_mwj ٠eAN]íu4foLȭ/ Zr1n;b׿\$%\DXvj׶ltPTkѻS.wQ\QI_%i_na5SfW]B6.gDm߶NB=Sa[BE3x# Zr1n;b׿9\f'ےXݽo(ĻC:Lowk[x/(+|L0_mwQ\ Q=fWw}"\ [$Myg|g~x$I#[5)I$IFSPyڐE$IeH$IH$-S{%In@$I$i \$IҲ+djIR$I҈MBl;[mn>9p hP~ߣ_uyMYeOmI1vfm:jafR~W&|$~ģA|{e[m$-}.$M#>ic/AYO^L!*XAy V۶AI"IZvR:d [FVw}|K懁$iIޙp-q YWx-IhR~Q7BZϭo֯d4S@ A3b7'ƚE+!3(/LMh㳭Ϧ JnMM}/椲OICy:ɻ>\oAy_Sf±g}cg-ɻVɏ%o:7zi; 5#|tܦNڶAtb{?ȽRuI~!@}g9@mumu{oYfIǷ$ii-%ߨp# @޻MnK$rWz%/pܣ/C=ޚ[+BN_Irq _>x<(; 6k\n7䵓CO67獝(=~=a $~xȕIi6Dz]17:ȃ'\g I'[WlF< l:ߨ=u/\hS'6ROdS? vE~<ٵYtmu{oYfI$i>ݩbjh[~ \|+wdoo _w Vy1eo)=׎3ABY( Dž(A^3uMӱCM!v\㖖ˇA4[lR}I|'(S oiϟB\ t򶄵P._5Wȷcv-pfQq$z>j 8WO&W'Ӕkg!beZ M{--}{ݷQP/'fזھg[ӵ{2K \$Ip˖P-hEP 7M=G3|ǒLksܞVuP Ic uuž VL4_ |4A x L !&Nwl&:bBtS6; M5_7MAF$ WA`pfB@q"ֶNjG-e6޷S\y,M8a?6ۖY4\E4\ާCx,Ntd&yC7'ɀN.<]-- >OWNݑSclck ^z`M(!W%r4.`c›]ݠwW`t7e̥kMmcMk[{m5.$E &EGtJ|'?ﮄۛ'+]6kF tYcAp d'N!fN42Eӡѷ?8 \J<mA^UYlzON*ƒ+ܟyww P~VV54,75ϳPwfQ ı3m;6|>i1i _ҦykfshrsJ)>Y/%fξiڴajq)|:[*>_oFͦ- gxmu{oYfI$I.p(ZL]DLIdn!%:ho'LU_J xk9 m ?Lq4Y;{I4a56>B}>OW[!Vy4)M E}BLⱠ渼[Dh,׼C4kLB>ewYo%ƺmxckQ'nG}mr ni7^&<ٝ0`޲̒=Ww}{%igCXe_J5kT ~ֻ|K4K<;Ux;T$iI6 >iwhFxg$i0pY ]$Im P= >-&,,z{"Ip$if  PoR޼0s9%8]$Ir`2z 2~ki/k|K{ $I$IC[rK$I4: \F֖\mO#wD$Iv棳5];ǒ^\s땕y#V^x.\q!$x5gxcѠ_oVe$Ia2y !`ԇK.NkV d&yU_ $~j2PV+usBYx80N-I$i4h)({e$9w}w''(\k;ݩaq: MJ$I2p99xejp|'~$ǹN.4Mh@wޞXC$c{L8LՐ/$Axp L @^o pޅk~x1W5#&yEү= ދmrS›Yfӌ|evت^gy%I$hneNA}p N_ dF j3!_>0qY E]AnlԻ+q0`?I!ZUAuo9oOЭ M $j̹= _|=)oMjc-u4kLy,p·~:+I$i0p!mB9yEI"E %uԑOUtW6Z^fû@m̏x8 Ls[/;o|M._m_ѷmAPčA>#@ZI{^epW$Iay>O5`]fJ?i*I< \nH8 xzϑsO6kPU:OvcIymD7y-!;?ɛxz9I۲M3"e$|);-D;$I|KY]e`]3zI~cI0py>]q>'<Ѥ`:ײͿcՄXMnԍuMɷ[}HӃ+^ 8 ln<`.+e&I1fn5v8+I$ipˈhCL IDATyK^u r# vus{f8ݭ檠l33>"hH6u\6e3mΗ7tvhWg_J x b$GI$I?q{_q}Y3 _krHZ%IG[_{wjFeK$I8$IU`K$I$ nH$I$ "vGGH$I-"0Sb"I$Ih1pY`B$I$Ic~I$IF_o,›b"I$IhImі$Ix"`"I$I[$I$Ie"IaH8I$i~ $I$IE$I$i \$I$IE$I$i \$I$IE$I$i \$I$IE$I$i \$I$IE$I$i \$I$IE$I$i \$I$IE$I$i \$I$IlUܿ˃fb$I${İK$Io7Z+$I$I-/Gq۫#]$I$I!.#E$I`"I$I4d.#f9r+ˎ$I$-~n =Ά.2:W& @\$^ ގf=PvV^7vq4(ʂe,ǒ 5G~]vߒ$IFw:%W&+| (K|Ǜ% 85zx80᱅(ˡnORr~Q_H$IҰa.yc >ϗ'/*tiF_X:()({ˢ)cF$I$i \F@yL;eSrMFo; 7dgeއܚȘKw$y}N;\{9fs%oNXA ތ)V[C~+3Z?']PL'Sє)m_p 役!>#~, W;Tgekȫ*qm*87fy=i I$iVhttCi:-^(t;"7WA<$ĊS_$v5ʄ{!C[*|,ڤ_ɵh vۚ|Ǻ /+u5h;$I$e ;t nvty_Lxʯ=c‚#Aps<4$ >f!Ζ$ǹlf͹QД̄2 .E43] 8 phNrVLy)\uߙPbR^H$I<1pQds/[gphnzlt$oHKXNSe;=C;aMǓα΢,@b-Ī :;ו$I$]@.#le"tG#Jϓw:yW6SK^fŻ@kd,cCX׆+P9Y;:F\$-hѡ#\*I$IZ \' [V8 Ct4n\=܏H!0t~%T e>cF/yϽL&I%.ىY[@`nԍs۴I$I#GnE/*+'f碋!>;l{ pC3e#/`{*K>O8 \J<};6[6dw7D9KϜ\/^f- 'qy_) T0B]t74 hlh$I4W.“yYTPBto x8 PeG!W$l8߁>5*<(ď9U_J x B\OJD{1g?,ιYO'`ez|l y2ǂٷ6`{[$Iˆ'Nt7z"h \vt9{[$IZv xf;c$I$iqqJhpii-I$Vf"^$I4z20I$I'{$I$ICf27-sI$ISI$Ia߭Y-$I$G,r,$I$`*X7ǰE$I[$I$IeXnĤ,n$I$it"b"I$I[$I$IEn?Ǒ1$I$-..lB7tg$Iet&E$Ie|_k$I$I ew(b"#$I攢6 $H9{7I$I., M`2]@2gm確h&H$I= 0)VϱS'I$I҅ |0F$I$I#\͜a4:eI$I#{U:k.$I$]U7`m"I$IpD$I  /`b"I$I[f'tqZ$I$IC[$I$IenSEe$Iҵ*&I$Ie$l۫U]UYf'ɠnT(/M/reRĵ#P-ɻVycIg<>zO%7%o 13AdI$I@ \F9 8O@c3";<5m@1+Ǔx%ɯ'\ |R/v 7&|6IWO8 ףo<΀}X-<߿$I*XzԲ>S_70_@o8/P~\5jr[B\ $o8{ ՐA^ӏ&).9 _L$ ySR_tnv* vOݠg4p$^1[> CJ^D x38i"I$Ie 1d\ w&J<A[RO2;Px%]s=\vfJtfw{-$It!hQ5yY)ŇAsS]6 nhy oM8 ql,qY%_OXUfFi+y}g`9񝀽@" ʯgx >|eRYw}0L U%I$-pYӀμ|6wx?>x5c\^/I$IkWzCI$I7{ Iچ.gf|ax#$I*Xs=׊$I$2pYD:pİE$I BVv*$q$I$I].!Lğ8EZ|J$Iˠo,P 2ըqn$I$i~è mGLWֹ$I$I>(_Q!I$IwZ0C;t$I$-]D&"N$I$i#}3 Hy9,1l$I$ia=&$I$`~)HQ"I$IF.).$I$BXvU ]$I$I||R^LWhG$IZa#I$I4K>8_e+/˩ֹ$I$ Г 2nX< ȭ7+쁲k\oBm p?O+?F.h&Kx dcwGr,{ܒ$I4"/L.Gx,%k$WHC<ľX\\p$>Qn[ 1^ۈ|%to%I$i[6Vsr |._'A|"ύHr8w)^yoA^$S{612ٶyCG 0OH[I$IpXN- .L]6`pxSCzC%%8K͕9a=0q4'x`׻*_xg]oEH4eϟ+3Z `=ByZ qw&ZƯerf-ɻVʏ%oSMIBd2D /+ySO@mMnw[:W/Sڥ6@$tsԠF$IA,s'%ɯ'lܝįV@4aIt|WzK@<\+{ܾko=nJdӱ'KRQF` @>ZX/ium-ل+ŕ*sM}ft+k`!Dp|Bw0>umB]_VOB<7v)I$I2piCfzQ^S)$o'{ˆmM`R_fBg_kMh87oX%A?^ ԡܔĮ)oAoZ qOW$ns]qy-;87%If<9ly t_ Bĉ$Ib| nPX-IJo&`-胿Pl#<&̄L$oN'{|7%Q,7#hF\ 6' sku|.Pݕ8b.\$I$ET?SBw ^sf rktЌ\1;mޕp{3%v T{;daqm{2u:7kLy͒:øVGl|m#뒬3)76ӈ8B=P)XW͡Ѭܢj ê(ܐ4+?zR~P ]t;I$I]2p: Ǻ'LtNym8!0t~;RbObsN]>O5D][+{hn].nROwz $^gt 삇'oCj ê\pYϦsOvׇc*';~J$I-?uVUN XMSTYv6zuY}AT8 eEc'.қI~cI쏡][q0w#:>X+LEl;j["{0S OZy*GH$IҰ-.-S_Q\}нPwf̆l;H/`{*$K4[NrfNȉBޙ쉀Gi5dkkS޽bJA!+Fٶ0Li/%GΑN5  u[dgڪk+>g \ږ턵붯3WîCI$I&ZV{3|%tfDEϵ\V 'I~-{;;Vǵ V$yOs`2t0P$IɖAC~kě;%cāfmL\9t/`{*Si%>iK߬9[5Ib_ ~\?@6YBs.C $KYzuBu5WsCI$IfA՝N @jqvǯ0a 8 oΞ;Pv ۚLb,(6vƀwP)ͶC(Cπ[S4ϝAי9ա4 I$IKϒ \棣S^.r&8Qx"I/' xt5_ex7?}=gS$I$aL!$oKsM!G$I<,] ZG~:Wb_zcu.#I$-*psP!pIF›OD$I$I @oCI$I5C>\E$I$-V#9¥Mb"I$I$I$IҐ--$I$i!䔢`Vd"I$IݥȐE$I$-V$I$ICf"I$I4d.$I$ICf"I$I4d.$I$ICf"I$I4d.4j%H$I˘$I$IҐH$I$ $]ȕ$IV$I$IpH$I$ $I$IҐŋ>v I$IK(3I$I !!$I$ICGH$I$GH$IdH$Ip%W$IB%I$IAK"pn;Q ]_[RJ\=_v$I$IيPȺNL&~PN7O'|P "rs;A<=@V$I$d`,?#BޘgN'bh/ ģA=KXiݲEyq'9p% 8E$IԐyZt |)' ;:P:93fEͷsa|;[=S8I~bp\kmI$I,)EӍt9lM']I YvB]΄k']P)6:+lseRĵ#PQBJޔ1~=/@ل\ɛcGx"7'MGZ_/$\ meڼN^Y}ȭI\IQ%;;:$N$I$c>$ 5C2Gy&F}\:_@s Y 7!?H #9sߏ@N+ >R$8J|nUǃkz%׎f^I|:]A<MHI] ـ'!VJz%7%y_B& Y'_ >뚘GMW0C@A~?+r*.""""""RqjR4>490,`l`H>qĄг_(~0:{.0iL̖&F>nA)yZNQ dS]0xQDDDDDDη*pcxڷ쓳1ުc,0-+pV|(űY#B`d^YpҞY88Wq:|e)GDDDDDDBR%.^ ƾ?8n|r&}ޙ ubFK43!|~q3n刈\h܍e =/X41ۘ&γ #yq;;q*[ɴM\cC 2;Γ/u^#p`&f &#""""""rR3\< iDgCg7pwX[ |60 9Y(l$M̂[p:  51b Y|$Z)(ř܏݌-x"s`X0=;fOT˅lo-Lhf/`l5>rMDχ>j V:$""""R$&&‹/2L̶&FzblBMJIDDDDDD[? H20 ͝`eG.>N]DDDDD.'_Vo \8lDDDDDDʪr3\l \Kל*𝠲U/0 ȅRE(lʠJD)l IT(""""""""J83`\*Sd """"""""^)""""""""e x.""""""""^)""""""""e x.""""""""^)""""""""e=혩fi9rvrrr R!wI,x5\'2aɇFJ-h3)"ÇȦqALSE-''mI; **8ԫ[___5T ޻jtQE.J6ou+""rN99YMظqqq H-[W nUEyb*""rʙ ~j%7/".Z4WDDDDDDDE 94EDDD"\DDDD"""R"/SEDDDDDDDtKWn)*H3\DDDDDDDDL*`RC\ tKH f#vv״iqAsLxA:MD*On(ЬYS5mF@:]9?cq[l0999|Ll6z+}dd .kzZO?cmP^=֕pW=Oۘ]UbNedդF۶tla~F$,c]NvNO@?֥uDҬN\ò+0j0NZHOOח7^yNde"=#5"ؼe+iz?fҙaZrj6oFX (u6g$wpK_:xZj1 ;vbkg+9?3r݄-vmWcEjՠT{.Ww/Tb%tw3d@cKיWNpP]J*VNdѽUԪUӕdʳ9l(7#>~DzvzvfcXp:婓E<1=OwfZpNݺ1w|6`t SNǃ)eKXh(wqONy믻7DLt[5ktyG7jXdq)))?^(ioukצA}-TR[4Sާ+GSbѲy3p:X,|O#779s瓕EVSRVǎTJ-5e.[dȠn⬯ZEdrmÆ " !`] "+;Mb*b9oamZ"44'mH\l,G_۫֠m]׬udIXh(Kl " 5la䧧cN, ~~~drz_ӓ_Ld9ðy)8#t r呕JߗjŦI\'NжM<ލ~Wau*I@?َӔVߜBތsc؟O<_on~W_zu'ms!9A2p[Zz p)Z ~Y__<;GyеފW^ҴI_‰' ?4$Jk~ b nKI9ba/oݲ5""|CGGvmGƓߎN;30B4H-MF`` 5d޽4)m4eK˖-hٲvfO7kۆ!gR\=0 C*2͜8v8m]_שۻu)֭bp05N[6j0F ʗ_}uMyǭ,^}u_sӍחX[@AeddhRzU֩3w>:'##gZV5mO?ϥe\OBT|  ^=3w}mScGDD.<-N]lq}S,77YY㧧@pO>=Ӊ#A^^k҄$%m?zG㜹ӱe(ڶ7p޽8r$Gh԰!G:YD/ث\VJt:ofs`2;v8miң[W׬ei2ztz2ebCFFk:8p[СCXM\qjQbeO>%#=$h*{_mԐvu2_ɩ:I~~>pA-DFFҪE |YףS 2$;ӓ',,-a<3q"=z#zu2On:?p'L$884EDŃ4;v`ԈaL}EN.Wg-V-Ba->>>rWj_|rEgxgU#))~`ޞ>Ǐgx3w~Jbc/;p8Ok 6kzڛoOחZVyƎHI {1!5kqe+˃iF`` g ΄Ηjf +tKҙ9~<-̵ GNiiiT)S;Td*Z^^>TDD䂰a&b")fT0|2-nm3!2:ID.exBCe#+/N.p[ zZ./ѧ*C;Td*BT7"""."""r^]h_}Vs^UneHeH%SY3F !"rApPESneHeH%X """""R(""""畩8DDD DDDDDDDDK/-ErQőCDr8r;kժ$"""R[gpRDxII;p8r""ÑCԈw8|ܼ<5Tyy$'"z0"cZN.:iBTrrt9N50 u=>L=MA4|VGpp TRˉTmII>±cp, Ԫ]ѮN """"""瘉AHH-7W "RI{^&'SfM״9fOSn[D*9___խK=k""""""rzijIMj-2pٷ'*ڽ*!ݎR9bP0nΝ=zA}Ш7B """R 㙼EnvaZXlxl2k֮+wҎqۀgx% Ui(g^,?-56*yn5mP=Wc*Cg^εz=(n)Y_|E;r%uXR3mL z;?ʤ/ϏY3?b9KI[ =wh"G=IIDATT3_9TO#ЧAw{F2ڞխJIuzv'Fiu[V'Q/rN\Ʌ^;=?5kٴyKӪ322Yf-SO;٬\=Ҏ:q}NmII۰"6(rrrشy 7l$_8t[ΙCIiGypnF%%:5)G|[Çp$%BtaOKcDrRa6ޜN';vNZٻϕ_I1ݰ ݠ. U5kiͪVr-Ǣż[DGa&n/Ǝ OxAڶo.~~~* JjǍ6'`r2Ӟy6yͷ^=}_}-?~QQdeesۀ}jժYj?TϒQٴy 8k"==___x%BCC :tcip?pCG?'F 阱㹺[W,M "" 7q pG}6Koo5Kcڋ/s7nc{=6nGX*oGkzznO1cӳGwX(oȍqs{_cv6Եo3Siܰ!sG{rNlڼ  0g{<{zōdz޾T^I냷 oxqfQff&gՉ[C7@Aޜ']rr%AAAj՚mp7F"pٷo?_|V2v#> Wֳ{>4ł$U{x2ru'i[Ӌ-Wۧ7V\z]w˖I]g d݃]y8c|~_HǢzM$Y-, .eٟ+Jt:Kڦ4FM7tȣnur:%mެ)Cd1㽷4nfڴnUa}}f}>>>ZȘ{׫U߿vڱcL~|b<|xXoH>]=ߢlٺY~wS=8ؕ'2!Ajex|yrv:L~9nw=#wΜP\-j ',}Yq4<>TĹ.\%>>]2d`O﾿?0 &_.7ޡaÂ4\_|~/Ʈʵxµj-մka>|-M 0 Tv܉bqu $':70 rf-Xh-}zʣ7},-Sz\͵@֭ }T $.6#GRŵعk7oɕ}8v8[nٴy lظ?.`\ޱaxť)emپc'a,MXβ+,rFO2F3lQ>WO|||h&ڵkz2׻*O[Iά^ҿE۫G|SΨW8†;͛5%<.ߓkܹwwj|gTĹj2bO_͸q+wm[Cgh5kDѿ{txWg1t}oזIxGۯ6[Xe:N^zu~}!MQ%8qT{Zzʔ)!MZݢt kǴ%0 ȘBHHuRUԮU5kY+:]촗dU tP\QֶII9ba/޺eBIZ2i<ȃVh-, ^zWx+ə7*-EDD,~=Ic/m@ƹEq]}~1ƌŋ1%x>t0M˯g}ر{{ʲ+3w>?| >&,zdpqBN~L;VxH0ʔoql`u׎ /Onnv""4ׯ;gu,MXf#.1;оP\'&=Zj=611Q8N7֕_q=t 49LdddO[qά'ٜPWŝe߳vӛO<gquȂ1c۱suek,ur^}nTD[H>ȅ/I&p %_>~?):]Ḳ_~|;[sOKG~eh԰!G[ڵjK1Mɿo9rփXkՌQl+/zoEAQUFּp:ɿ>Iu-X4S,ZT\ueg>|Mb]_=Cqi7ݖ 6mޢOY""F\Lmd[r%={,pp8ػwo' ,5mJӞY~= .#!!={z*}eڊ`kyxD_ύq;Y3NqЮm<;w憾}\2^ ޚ>F]:za<3q"=z#zu2On:eJofsn>3`аQ|5 N3plOO~rcUg3{.;o 'aٟf 1|6 à_L_UHS)ҭWڶi/xΏӾ>uG]y=+sÛ2h$N_DDJظq#G0'W#F85"4( 1{E޲MnO_+~Xm9tn2YPWr=[(zp2'5ՎJXhh iA4M $֋JRn+qNO6(Nvv6yy)Uxgwx:6[ko>ۙ\rRSlaNUm혯s(999F2"QqM,?=#p<ޒƟ'olT{4ݢ% &UWuO>!>>4yxzaFFrNn!S0` N[x2`2dP_IY֭ZVd>>>DF(=cs4pk,#_ MwCZ&~?Z'r @^ի/p'a@DDDDD3ULkf@iРk/&W ÿܚ[xhXlEjj*jBcD28q"k֬!66V+/O{?ې KˏWǹ|-1^|E֭Kի DDDDDDD|8~)v?}QKA VZ>,&L`dffl2,YŠ+HMMum3g$<<iժGu֮[>}:'NBp)#F0ydZ6mJPPݻw{ekΜ9j*FkZh.z-e]w}Ç=$fΜIv;[K4FZjH;ė_~ɻ ql6l6aaac۱vZԩ&L >>DոU."""""""e믿ruQfMƍǸqغu+III6JÆ fѲeKbbb򋏏WQEDDDDD|Ђִiܹ3i2vXW@ll,{nLŽ;=zHyҕWxx8|G+\{tܙΝ;ӨQ#WtN4֭[ǒ%KXx1 .$,,1Rh\24iC a֭Zk5k0x`jժ1114k֌X"""QFL8TFɮ]صk|gj*F3\DDDDDDDJHZZ@z:t(CuKjj*XVñlX,>qV-""""""""R9uVbD^2j<IENDB`crystal-facet-uml-1.34.1/architecture/gui_design/Search_v001.png000066400000000000000000002173011415120503000244070ustar00rootroot00000000000000PNG  IHDR\UEbKGD pHYs+tIME &63KpiTXtCommentCreated with GIMPd.e IDATxwxTEۇmI6="wP*BG(EWDQ:HS HPzBGj ٔ=ns{ {3ϔ3)oH~k7IHLB @ @`=jV,OMQPu3a @ @ 䑴t"EIFy S@ @  OL@ @ ( PJ[t)$$ڧyxR7mj)iP`*<,@ ?kIqLWTEҕV<Βŋ~SԎ.@ @ ^Id2U*'V *-kظ83|y"wEOrG? _Emyl{5{29LY8mҠRuΛ3)U^[T([}oŪ7تNƨ.cIQ7KJGFs)lG=jwhIC24lؐCy6j@ @ ^ *-ØQ^bn4[n4&8,\d241h9O/EB^im-Y kquqRr,'$IBz֖H iii5*^oPTٞA bccCzzzveckkCZZvΖ4g> &4jPisރT*œoLşW_T*d2ѼRդ~P(UJRS_ѲyNӐ%ܬeeJ9GS2sZe\zsKCQS熹d2llTʘ)?^Kun鲵acndWSɜߌ٘zo[[ci[}6ѹU+UT*oT(WKWzJs-53r ,YAVQvlרVW[Prgj嫹 . 8}4W'9Et#P>:K.q5t:.T Ǝ(^,z++ ̜k~FŖm;vunQ4ą$%\t)=iii,[+n}(W\+yM2sgLbخ5DFG|Zk~lT]Cý쏗;Jm̎կS:P(Wٵg[wm;{{5ze?ҕ@I <WggZ<qqrڶ|wsI|+S$Jf&ΘĢ+ԯ7} L΄1ۋ:kNBRkmn@j rVW֬Hf!.٭E&P֬^m2S2~e g!#ʖgeʮKCQSTj,4x{y2ӏ5<̵YwjGGbb~j=g k굹t= Id~B6-p֫>J z|x|5VEF4hB|3o ʏ5ZSrȡ3vpqq!:lUJ>6W!"ICԪAYxC7IlYA5.@&+˕(- <2jV{w2dv!r ±xeԦYfȵi$kSK,#+:֬gĐwNܺc7[w&J@ LFuٸu{)F5&LMVKy+|L&cwrsEP۳&!U*iP7q71eXΞxicʡa!v'GG&1;zQnu gH2jh=NLl,JfԙhSR9^;Ŕ+rySgز7lm3jv]ʴY/^ gg.^b7/ɬL&cĐwv&3/DT`gkRdp>,[;FF4~˓eJTTjU*1x{z7(_ t)rۆΎToޚ) '6.h.+o4jkR̺g@RfK󁤱dy1u@^Xj-Cy?d 3kT*yA]<Դ4ґ3nl~4Ǧ~^JWl\CL9 ڎO>R|dW$LCcmI&)MKIV??M&okKʏ5b:m>'$hr݃G^SE qXͰXbuزdj.^x<s˂5=b0,i.\IKMQәmB@s ~%1$,#u.[cٲ<).qK\KWXǁ#hH ='!-U5؍ cשB|~c~7 :-xyzR?.] {{߼MʕLI IMI%9Y{1̸^^c]tzRR2hyx[8v4~-^Iu8wqDG?vΎGQѦf"k:sƋI1c֗/^e)k* E]FrT(WQC`0H}l<6%AbۮJ#sem6xgh{Hp+A*0?)7f#X_O|ߖ5kEK곱v-7e?DD\^g]` #0 9{B7xs KRZ-Ӽ(v&&K)\rGggRRHrc1E  qi:]3[Ԕr9Hn..$i4"E.̓_BBBii$&%I!r w7W D^ݲ#d2ujO&GQ(lLFCjʋJb^!^z['O #Fen-~k}_JJѼ}(3]y,Mx^mDdT4fͧc̛1}we-u4a$:kE׎8y&We{ۚ Tr˶vj: iҲk.i4 E]Fr_ղ՝Yax%lޟM!Yɉhg k LH8fRd 'k*H?F,ɜ̥X4[O!O-mk%vX.fZc#\|bJbI@/&y/_!dA=w!VRl8Y]xsEGq?߳eKbb nIQVll쨗d?ܲ5WO&Bҳ^'&%;(y`   b*@ 3ϧO G[b0LՖ2n?xGT*%i $`$e1qqȀYegξU*f|2~I 2d#g'$`ooB@lbofBwRȨhש_w8rZmg6~k}}L!CG5l'NEܥoݹüEK+˨Ѧ=<1XرwvxBfd6S2LjIPe#--e4 E]Fr󙳓۶ޙ+oz2{l~(_šz]JEzR Y8j_{dOo3N[R.VνʲѲz7SX.fK[-/-r]3gϝgo[[әxïw,jg޸CpɺAsFYðpI=U>jٿ["fУyOVCj0|Ȼ,Z3a9vo#%.qլ^ܽ ^t m[ee2۴Ly2Of$ BA-'ST[>[n6\oROoZZ~i%I2fK|d%E/".qۯ3a登p)s.L|w .\}¯p >h^-w:=b~##a)Wd: O>~sm-7kI^͜vQPЫ[gd2oq[k0R{KWھKqM*/JF*9 #r7tEmm>jt踮J"@.-m S N.y SPaE rف$Z`٫툏OܯhC-&YKzb=>>!쑥Vg,HHLa9Xxó鹊l-hƗSqqv&55d6]8ث\.[e?/j*lFT'KCQk/|X2o&/ƭprt$!1W{s׹+k8ٵ#c'L-?iGsXk=O;LN$iXaI[[m@ }eINixen^BAE#wae,ytBj" c*]Fߩz=qEVO̥(ˈT>g ^O||JM{"2^sǃGRF׹mz|Fc&Ě|\@ (=dpE&9.ѣHQW^N _>ɞ HZ=݅-qc>br?u#Oɶg3fBMiPI8::l/y$|-E@ Ε?eۏJʛ,[3[#kݹW$6ZP:,H j52 Mrpq/ftݫJM&%zE(ƑdTRzu\Ŋ˕79y /_͓P-kݹgےē' am K)&oIXQª = sm\e P%>  'ev>snA{{<*ܟCpͿZeu-%993~: GYٳgӺM&LhqYPW-.VX;-\gwBK^a+m``Ƞqttb%KCffwvI;bKv:+Fz,=˿r9lXk#tm\A 2HD¦MҮ]; lSN@./8qOO?UVb;4h0k~Zdn^|yzP=!],&tޜT|bȩSamڶ+-QQ4,G0weԨHLL`ƌ)[ uS-\R?h^|o X(?v5տϜpQ5j+xo.\Ȑ!Cљ{.#GhV^Sh]߿O^=QgΗ'MĖ-[yzUbNɓ|:%幔|XA2X}fm%KpB?`o||<(_QU 'VvA|p9$ ^"HX} IncI3|0xl4F; . ^HgG```wʫ?{Jjj*C͒\iRWiF9?'4,!d2Oʕغm~~~AN)j1˗?`hB͙;Y|9ÆOJtTx3n^,UcDL M~M#9rdΛoAǎ-Xdsmʾ}h֬)W^͓MN vٸ~]WWW.ǒy:OOn|wӦM:oߦU6߿G6OeKaJmݺ5-|/gNU{y9s&;u"$dwڪbk2CѼYs eeV+Ot5,璭 otEgN#>>䕘{]nԩSLA6M\{`N)x@of1&7``ӦMԬY>.\H:u(QSN%!!蟽Jf%11zt@_.5.ڏaO *U+ؒʕ+nZ,sq1jHڵmÍ7E %kի=ܹHС-)h{*(^!q&QT vݲ9@y|7qpp"000'O<śo3of b7T>q۬bI'<sڷom7n_sN.\H=٫doڷそaxK)L܌UgѣG޽]vw^b%kUgw~9|1vX6nL@@?|BCҢE"3Eiή.DzѸ[YE.} @D^bmqpP͛`y#55~AIl.DA΀}U{Su ܚُS&Pn]֮ߥWxYkLl8}<ҘjKxtɳth@L=]FŊ7۷/nʓ@^=4+߯/{xiO$I 3NMڶmuJf'3:ͻE H6r4_y01ʰ빳v*RB֤*muιTa{&|%DУGwjs%݋\.ݝA:tqpp <<(''nb ;ɓtj﾿^ֲ[ΝGIc` _ XrIJJї85$?Sx<_S×Q\<%ɓ'ܹ3ϧgϞF)_nu#Ձ#s$dqQLb%+2DMhV'cpg,$Mq\TڶmO?D_Җ$/<իWgӦMtܙOy̜( {sUkV䢣ZU¾mur|nxsֻi+>԰YF̙3Q*4kLR.d.^9/OrrS敞#i"OcsoZ~H<]1kdwMpprr}7WHޛwGgٜyƜ9sSNTNw 7c _sƐ`˘1c|ouv~Pxzzp 4hh]*ɟY"fw=fN9Cn]sͫLJiּ)UJ?Iow73f=dЌϿY كK=tWQ_2Za@"iJO֚~&>>qaΝ;h(ʕ+ÇY'+$m˓'NfMT;dw;wD2T짘9n ]̷ǎ#cr7$Y:?__<\3D.^bn7f-Ƚ{wq69cvޞY!/|%3*f81oΕ+Wpss!^DB_Ë2Qn]LW3S}ٳg@䳿[{νp6Yu0O9*U/uI1|WnbrW.F)@_\ +Z=_@@)J%8AIό[ s. tGi`hk,2jhZz=zހNCc0(Wvd2ʖ+})PţWЯ|x%>DټljI\ey ?bV^ɏ̚=;OK|gzRT̛5O~8c2U*_5'|Ԇ͛7IӦ|˖SNh4:u̶m۬\ Z~`5(;w2(m]H:x@^8>ҭk5GH ɔq(ƚEOL8=C+a[Η[nl+coDD BѦM[>7.앗Lp]JF2{Z/B=RjKYc+I__Cy9Y3p@/6wUbQlY a Il5Ѹ_#00lܽ{+7PU&(Z%StU4ջjh2g_&w 4,"dtMƘQT=sCo_Tj).g}||ѻ?ۯǰX:*1bCex > qcѼU1bK^!L.=d?xw˗~Z b@&#[^o2׮QJej֤a4k֌6[ѹSGuBvm_6Cߎλqܑ4ټ˂c'ܶ65ǦMIOOh_>?8.FòeةaСxS^obF[-<>wWD۶mI D4zq>!A1knZ3 =K}Xѝn.1);3njã%q}ݣAbv@ 8^'L`)iH Z< $Oc=r7fNJǎٵ`OM+Y$/ӧMcѢپwrr+sY/n

K}$Şv>L~?|]2k U =)ڋ {Lrͽ&e Sr9Z&(|FeM1I?XŊ,9 vj~Î5=:T)ySOIg⌚˅tLRCp[e8x Kwc3WOߎ_^ {.]ʬYL7}t~"sX&ɈLIʴ7-!Lzh s_pjXvt"@ qÉEj4yb}鋵H#<^!GviH,4 oαG/+ȚWGb95>q_}e5oW'q VXAbb"66"K%Qd̙,7nX)kU}HC̯6Zoڵyf1Jŷ}EYv`0HRR:{{E$2t06|]]x{rw --S'O!!Yg4?[p1IJ S}'Hk^9ܕzFУ{{zLap{슠~UW+Uy|,$v_f,g]\ץkWʔ)+*|}}9u>a71in @1)aYj'N…  ){+Wa 3(J48eٙ3&?{5K={ӧӴiSXb+TZylJĒ"@ qL7,O:g{<,ٍ1Ol _U3D F'dBZAeXdI'Z;ڪufh +IҬ }Qrr2˖{{%3`ayڸ)в|r%=DݻwӡCz͍7O(VΝ.x:#ފx4v5ArXJRB/^ŋ>*UbC'j5j{gDFFfר"T&"ؘ  d%JؿY2koVħ}C5:9yg܌j5R΂hժ˖-e]\pÇVۓ۷)SxIV4K͍waf2ofH^1$cЌ-p1sqF#t4|K3H[O2Ï^ _vԫ/:oT+D񜻖H߶ښĒ lllppp[=)QOT3/^Syaȁ/^СCl߾O?4UV1g8Pd牓~$T]Dذajml2dn?o߾ЧOψbϞ=k:h\p ݍmhw % IDATN9"kW~T9p]47Cp1a=4yiJvS7;|_ GѥN)JJJ=ZM\\3f`Ŋ1ׯ8!>>3AaމbϪa՜8q?%Kw,Z .&wwwr">a$#"+.1PMIdɢ%~~~7+jdLbN-oC;Sb)=k >Zɓ)S&0B)=/^bŊ̒>@ ҫgOʨ0Bsly"m:gq:0bʿb0-EBEO-Y,JA,??-/L+y> cϞ=ӢE GN֬Yù۠7 #x<ޠ".QAFY~}&L@hh( ***#eI|V(hZJ?;R٬cQ.V)S~U'_쨺`Y3ǕtЁ$n߾MҥE/ ) W779{O~z|.[/oN>aKAS}[nvy饗K|޳zfϞ=ѣÁ;y8&7=glłq^eҴ+Xq=S_UӦr*vIvÍ5oOa'rWf7f x昘 .5i֒›dzn:.bƎѣ;w.o;/FKeXawѽ`>㬳bҤI\~_cvZ9\$D4k 1oBr&`ZlYfy333lO :.֭'`̸YlYuݤu׺uk^ze/&pS3g5(##ݻwc!"#NYf7<9syj syK:vO^Ym`ѯpӐ};xw~ߴ_gQ|^r,GstwRLmr5-Q/Ctڍ .@aK%0|pXlY;rH{1F]T^ߜg}\ yD/T[Fr]i^E\_- -"Ґ|!';[!1_(~?f1k\_k\y= 531/9|B&,muT2tr~GwQt#CV\IÆpW2i$fϞOr&7O>!t-~IM ibefXnq""ҠuM̅x;_Y_ݐW&S`=u0w9]v%$V hz=4ifh} yjA{ʙ=LF>SWL R ]ۥ"s|G=b/as|\vL8e˖矓̀c[0\~ǃ>HΝ9cٷo ,//x.MQ,q1|eD$'7?T~7z̝;m~Q® :W/;xbnydnNSciu?S.\1Ν[VG-mF|1+Vk / I(Ǵ;k_|ᨼ?׬^ڵkټe3;v_eOH=\תm:uQYp!> K.%??I&BxvIKK+q>z=60ޏ~I_ z+X&%ѻp=ݚ@Dٟ۟sְ4a$z=e!~ [*)--N: &裏:u]ɓ9rQ +RuݺuW|>xg %gW>kl=iˍwNָ[^!8;|ַ tx#4 \x[^`k";g xvȯvaK5ʴ[JrdǦKn8-7oEҵtasӇ~d-[Ɵg</[d ̘129s 4CN:$V^þ}gC3;QWYҙÝu,\Xvr)L8B&xnwkVvlٲM }<:yrw5Z[lI.]s{}x<znfZ~?G!!8(+Vλ2hРr@͛K/Qիq0yd<]Nz5Γyw~/GRR}zsqםw{v2o@Knї-<#t֭V/556𻽤gxF iAPFMKet'p'r ÆTw׿U~;:uGS݋s~,+Ty{_=opc)l[*9m=/s!EMBqR}?tMQȆ?\ <[D@H csr!; .-[cǎ-d- VؚHѵm;kMȕWNW_ =b3<رJIRjr17f+:uSN\xU.]JJv.BrC`\qD;f<7 3r@ۅ\qUt&&&8f͚e 3!KX:U2ߚLm5m~?NDm0SxwNĻtRrqvݯ_T9ڵ"/п~WF#{'?5k78a{s W@af6YcO<['>_SL!""}-ysJw2"K >t{bBMBBJuaeI'0zCrŗn:_SO>Ν;ҥ+qחbCermwޣ{߿}kΰ!9_&43oA$MƜ1#GѻOZy]bѹ,k֬?d駟fL:ܰJ*Ϭ$_|˵tA먖}/2{rZ+>bGfj,s=rpr ٙ39s  fAx޷m>8!Lrjc= ˯iӦ AAA޽{{3~x9:wRkkؽIdݺCam DT裸3Pxӿ-7k֌?R]/=&Z=ܟg}8~/1z_9_ {pu[o3ydy.rGhX7(6<+L KXȹY>ͤp]zy=<~)>1{y6Raa)Lzn@&[EDD :*\}صk_B}HMMw>|ロ-}ŴmKvvvUW_} g1W^z~罏eQc !88ZlUTm^ o@N$Z] \m[֭[3~xF hѢEڸq#F+VYy7N1u'}85j>Ct¦'uoklH .a%V4*FgO?4wuqqq\uU\}D1ϯʓO>ɼy9s&&LYy}ghq]w]W##hpD?xyb\^.>My&^yۻ"" \7"f>,n_l]vqyU{.F7Xj FN?tlK'5%?Eݖ۷knq^T. GOq3yRK.eDTy(Qi;ٺuk8Su'$b? 5Hc83y8yW~'NOg~)k۩)e rikqyʈE'=jMEOuw z L%LBgvؑ?/_~җwӠA w~T[f͚~zrݹurqǤٳ{͝~cÆlXw~דL?Ve IDATݧ_| 6g׮]4kEjj*mjLR߿׵ ]-d \kIV}v3ydf̘AϞ=iӦ z"77kbo3f(sr*[=UjK^n.kwoߘ7/oUyrrsfb +QrD#&(gg>Ǹcqe^z_|l|Ν;od„̟?֭ODoc?`ĉvt8S^Yo/X'Ndʕ̘1J]e˛ӥRKυs;\~|r m?Rnn.=$=-y>'bk~%> 4s>4/;?gϞ=,YԯaAq|ĤK'|rӤrssy'yꩧxVi/+t8RX᧝ʰa'ӪuklТLB~1佂j&t ?7qFQUj"//4x޽;3gdƌlٲ7H\\:t(w,ϪSހVyO;[7M^ǒN -}(p)'qݵ/rꩧ2h ëXgFF+V`ҥX`UW]{r =zM6tR>LR?.GItt[.\SO=E6m*7tSkNҡ7ww]y޻zny<fϞ N^.L[۵sgڲOv"( ޽{y'xW:m*/_-nݺ1}t,~M&NnY C?LkȾ@qxY|W_8N;ƾ/l緰}uoZe!V+Qt) 2ݻw}vnΝ;IHH ;;|u6mڔ?jDIIIyj׃)W7ɋ. ]-@m-I\>;oذ 6j:.d<7q;F&7;}!"" IIMK)??E>gժUlX\wJAàA8㌑N>XU+WdSOj* #++f͚1p@yM(U#g:f?DUu&^<SJ撐իy9̟76{OZ6qc9c9k-ٳ>uoIjҚ5k{YbGfزwG1<:u.shvw,5tgLB)9lI/͹)9DrТZ2MLH ==R'gAwPփ6b7mW&/ǵ)~dMO 1ժ>o孎G}G_ݟABbREDDKJMpH*jP^^_5.\Ȇ HH1DGGM>>L ǹKs[ᗚDϋabwn k!a8.YiE1ݠE`>G+?.G~}g|駬_Dq\ҪU+wΨѣ3,:tP#(}a$WT/t)+l +@EMsTt0T^Qxڗ!ص=O`2o +~A SС{i# ץNoe ."ӹKsHBRZ1p!@U A!Աxe $"""""8i NlGDc|?@DÉ40"´H i|?toݘ0nj Fs?S""""""""g \DDDDDDDD*Er3 P͈_~G+z?S""""""""g \DDDDDDDDL)p3.""""""""~EDDDDDDD?S""""""""g>josW#""""""" _-VHRT>EDDDD궀P#ot!B pGDDDD**> 5E7"Ri/RV#XZ7^"ϐi5t/jus0&` Yhp;8kGbu%!-"""Rԏ14 ]s]8K}b-d<~h;bYL¡aF>#""R(D, Zc}-aO0;ԖJX("""@ԏP${- &`W֫C"""u1RC9m^@oŽҷ},6,p0 f. zEDDjQQ}+2HCDDDNjin1yyV,#n-xP`Zؖ"""RW)Pn=/|ÅJc6^Hi /bXku{iIsEDD6ypQ#"""u_JSd- ]Yt|n}md  @:} ؐ{4"""5mny\DDDh3=\* :r[53h`99~DDDDD:pi7pJݧϒ:^׵ ]K"""(pMnzI# Bu?t-H}Eخ4NlE+I}llK#UGn԰gH|/{MDDDGCR_]i ^Ƥ^ A 59Zi ;D""" KpQBsc[׿H<=/ix4H}EDDDݾP?S""""""""g \DDDDDDDDL)p3.""""""""~EDDDDDDD?S""""""""g \DDDDDDDDL)p3.""""""""~EDDDDDDD?S""""""""g \DDDDDDDDL)pUWKo>"##IOOy2 0@ """"RA \D^2e AAA?ZDЩS'qvѯ_m7mDǎ &33pUh rssyU"""""ED굠 1bDϧI&rܹS """"RI \D^kժ:tPEHED|l۶H@||<&MR40 \DDj@rr2iiichӦ mڴ)]Nغu+Z6mJVTy""""" *r8p.]iF@@яPKW"""""@8[n>ߵk"aKZZ]}rrrT""""" zT&,,dvyyy 2N8_~,1q 'b f̘;-4, \DD*)''R?p_xb]veDEEEDDDDS""rRs9܍7ȑ# !11|v$""""R)pFk׮]^222 's{nŠmwwK<Վvˣ_~zEDDDDji>撐PlXQEرc."ҨnJ[n[n8ԩS<-wPi.0h֬ ݻ}BBB uZHDDDDHLnJ|nРA%>fwNRRySRR.i&bƒTe<ϤImܹ3;w,u#mݺUH)p!33J+Y884TEe>(++KH)pS}cccqݕ%رcTE"""""RԢ`K|.--CDDDDDn*E"["V~]oعs^ B=\DQs݄ѡC>vލ8 :q dٲe$$$0g&OLtt4ر'xjͯ"""""" i!** ӧ {֬YEKKK#;;0p-n!EoeEDDDDDG4ZZ[ڵkG~u>qqJ2l0ٷocƌ/ 44+WoDV:th4йsR_t)bbboc &&={B \Dڵ+.Kuq8Chhh۽+ꪫ߿?}98;J]hviYN:8:tЋ/""""R4i4j111N[4iBxxxaQDDDDRiԂ`^9==LM+"""""(pF/66́*_tttyreeeR*Oh"iݺ5~-ٳ?b . ?[, ` C^Y]sOIǯ C౐fl0iBe'88έسn:"""(u&'++JsȑC߾}ٹs'_.JPHe1)4C l*9Dit*6VybZbөVEvV˖-]p'_9sbjQ=-`{YFcLSil:U^}b+ᯋkt6RzsrrJ]=iĉL8c&L(sTTمK]#"""")piQ^Lk=Ƌn[ omB>Ct^^CmK^fd_/ 5E)^| Æ1u⏗y52Nb,f)VwbZhx$rI:b8R /D \0 X` EgXBGppU<ޫ+/8 3 ҁ-`ziJpok/뵘I?? @rr2^vڕ8pxDDDDDHM,a0GlhZlŬ$Şc-%;pN6b-pmo]oA m Ld| v0?LŞcq>t 瀱a{XX z O_aJE@,W` ^6`Z7Bs-&O` ā|/p?k֬o߾o}e΍R!C܉'X!<V,7k顺rv8bVº3!)dYcVEWdq9EzU<k {1c Dy` οb/_ow0惓/߰jv5o޼ĹQ C\\ U>FJJ 111DFFҪU+}(p \:ZLln:"""J<1G'++8"""""~}a #loB&T%hZq-RlU nC,U}8Q߁` VYSx#sK Zp|7G$S67M_ D낟|ó8~6uY֭Lv +2?ɓ3f _}IIIiӆ0ٳ'6mbDEE}vrss5IDDDD4&Ē7&x;`[ >x=Ë 6&<4MwK}CTTTf͚?**qUH)pi$ͽЊRWqr{"[+ K2koXKW|.. i@{bV>4.X2J9bz.[a0M a LVAp/$}B%Xk o{i^究UJvo~\ \z+xdddTi#瓓Chh^ *RXZFDbG` B8Ȑ{=B3eRÉ:l-fKC ώoYʐg;)y7,szo]+pr68xs7oHgITRZf͚@,Y8oݺ}|ٳN=j믿&44".ߕovčYZ^; fVmK )u)7NT+rˏpw o0ssr*V7KY7oN߾}%!!eKII!&&N;M/H5)pzb}άc,vph ɉ5v!!!5rܠ 222ؾ};9==LM+""""' \^g^ݙӶ^fjLX/pVh"Қv9p@ϥ_lPVKݻ7oߞt\. Ӷm["##Y~=[fԨQ:ollliر.?Q" W_wq=b$0MӖYnNPbxK9!C<PʠAtz͛7Ӷm[],"""""5Hknoh0 &MXX:t>cҥ2l0>eϞ=?{wu{խ}i H ! 0a^ep̐ 8qqT̒dR[$d^]5kְf͚~Ayx衇zGL:,"""""qED|N8A^^ިwsQ^^zaLs \DdZʢ1LQQ7|37|:UDDDDDLL^G=% :?""""""ED B:o̙̙3G("""""1EDd|ҥK]}٩H(pιs&4pyINN|M7DCCD"n7'N 99B9|0w}VP(H(pNJJ &%%eBʟ7o^׮] @iii狋}b &^!IDDDD$Nug"{KLi1.\PGLp8N%."2e-]*uDZDDDDDFΥ.-.""""""""1)E""2jUUU)ƾ}|z^r%pe{:::X~=©S """"S{c.K \)))Q' BLYDEsEDDDDDDDbLHiJLKZ~:brrr0ƌP(D{{MKK#99yB4zţ~""""2=iLK``08%z6y|1YMM ΝQ[>hhhСC1o[MM ǎU}3QK#\Dd!;;{¯c_o|D"֭[믿1'xŖ-[d߾}r V^ݻIJJ?9/2v;g\|RضmۘG PPPYt~("==gyK.f^}U 5k6mb|>(++{naŊx<x wM$aӦM׿@ ]wŁضm?0}ݼkcGSOiil'ҥK3"!w)%ӗNjg۷oت*SRR{ĩSO~"""" {^SDD) zO<ՙРN)ASDDb]5gё#G8{,<~:;;x<ٳ ֲpB|MnV.^Hzz:iiiXkq݄B!f̘1eT477STTzĤ^U~XDDDd_xכc{εgp _c.&A_6uرcD"^/˗/'--o^z3gD+{/pxXr%'pn&}v9)zP__?p# Q)D֯}L3 \7Ap^ V)}bڣiAA,e3`s,uvņ,&Yջ>K_gqΜ9mơCHJJbʕ=zuyyGZt--- Bc:̙̙3'5Ku8. v싆u7["`.>9?`:R]a5`[;lu L,q L:MʁT9,:s~ovA[l7Y{r&:z7Pq#m͵{1sbC25[` x _uNӟƢ N8Aqq1G?bŊan7 .ٳgK0l:::x衇tH$2ONNfhBq")KKKtMQ")ti1pԃx N}w nc H4x{a l1M,z3p-a1+!gG&bp;^pwUx2p贬Zs0isDշ#lM%.0 o11c]L,vςrf:::x",[W^y3f00k,͛wչ=ύvkpEMM 6ũv}|wjhhŋGDDDDL%`dR9jpHI wXLhzyބ w>^'pYb .lŮ,vFx WGqg`ሁE@)Q &. ˀemXH9{/- pYb]K<nTVVy~ϯ]vTdgg5:$P(Dzz:%%%q͛Yf .Z.]Ķmعs'<|_󑗗GYYݻw8+VpZZZx'q&n磾p8b ,kM~`H@o@So1ͦ70t 9h0: lFz^O]%]d1]B1 ~66dqߗRl6)}B ` 'F:ttt$«>oڴicn=qe.""""Ӕ$؎o f1wɒ>I7pj7h7>Kv0 jpt0 |#aiAc<t*f qd3,25/۫߇&{:ͽF2}sf ^uE6e0; 6?:%p.8„oXWQs kp\!ڄm_&:}3H5(q xXr݌$"""""Epl|0LB#_IZЈ40㋎1i<ݻ\0/3g=y2p;h9&[o-e]KW\4"`-3ڑhA믌t!dˇ|}$A\.W¬#""""2)p$]m1S3ͽޕ+9m`Ivl&ۻW.؈g,]aGx x@]-b06qh_8ݗ^ -Șz008eNdAALt*&y9DֽLئ)*3ׁ{* }EU)N:0vHw݇2:cr ~JHd~ӿ/}>6i1Ӗ~s/8G*m2Ѳd…aǡ~s=.ZE Zƿ˿PWWǷ~  Q"cR_hNWt[ႏ=ia>056;DGDmep]na.X"?`juąv`It1p\]sCm]UO `Y\b&sY'N0L4D6&Eˢ hF^{r`!؀żepxx"yyyN@ @0iPImWZZ 8pΝȑ#۷Q"Skk`737̎aEt\.=oBN`$獨}gm2YG{S7zt̛Z$u2;vÇS^^NNNδk_MM dff^Hצy 466RYYt-ͩS())74Ebz-mmB4EEP(ĪUmyٻw/;CUU@m6{9vO<~3),,ҥKl۶|;̛7-[sNn7oz+.EEE?7 w捻Rvڅ磳sꫯP<[];,]T=#c9ss`ppak4OIIɠ1jJJJ 3P]=WԤLD,WN:O~nIPUUUۿ"1jpa`6-X8fQ"qq'! D"8O:Yk# %/""""H̙s\YYY D"1 ~K"(|ɤ y̎;((( ==!4$??_h""""2$."2-c| [tT\\Ljj*C#*={Bu JHNTh)))cމh"477STTP]]EDDDDED$gٳz B^/ϟ~C`0Hkk+^W*+."" *'''ORPP@aa!uuu<|g< |ߥV HRRlܸq^QQA(}Rp̙̙3G&;.""7id?~ӟ{6m5kN&"$!33k4g,X0744ȢE """2)pC-Hn())2|n7]]]rm+Pt>臨2Ogg'O<;w[vZ^u1$%%9s&,_7uV1Xk  bgre֮]˛oIgg'seǎ|{ӛ""""2M)pK.H$tuuQWWǪU8z(O~~>mmm|+_ᥗ^vs ӧ[8v_z; L駟ࡇ۷=`]]]zsDDDD."" v8TVVRYY D\tg?1+VڿFk* MٵQ._4ED$AAo[㴴4222xɡcǎQ^^9y$^jnfyޑ.<Ȕst iooZKuu5/vsw ZӧimmOQ__ϝwީ4ED$D":D$S]]Mnn.III$%% ؾ};|nioo'd.\HSS_WXl~K*)niGU`&Syy9˖-_DDDd*pihhvm8~aohRVV61~;MMMYײʺ755B4IOO^DDDdhhhypI c|{'CCzP__?iu $l?1Q~ IDAT)p늵?2rrrzCXrV牐Ƶ ݧ=I#ZgA䆆N~EDDDdh \D  #ZΦ]vի F[nƢ=NJJP(D{{{~r>|Eѩ``0%;;b~6/^oPiD\wrrr _g֭r7SPP]w݅a޽9r#.G$a۶m=z˅;`ƍx< 5kְuoKUU?0/"6lvYj={H$Bee%]]]+ZjJ.++ G(w}{)--ĉ{~mm-s!99V222"""""2f \DdJz|ޯ1IMMUo>u)p))??u$$.""2&UUU.ҥKdgg UcxGMáC8wsK,}]F/ΥEDDZȘ ?pDRRHt:::[t? frJVXqձF76NR'Ȉ)piZWGRNNƘQ3&SԈs8;;@ 0)Ho5NDDD$(pi'  ʚrudggzmmmڵ|V^=k&_"'`0Hkk+z.+=."2-㗿%7D"[_c O<.-[PYYɾ}(--ĉ^ݻws^~evŝw˹|2>444m۶Q@CAAf͊xz{3gg>3\.`p=ݻ￟v… ̞=˗qƫ'""""SqOy{[j@`νhnn3Loyc{ FFׯtN Zi(1ae[[V׏$w}7HM6_*wu`۶mv~Orn7MMMdggjTqfϞ=1|Q {CƩ"rٳq3gpmq!Xr%Geݺua^|E}Qrss{Ͽ㖖)oiiiqx*mVΟ??kw̺uӟħ?A}뭷5l(uuu1/3//YOIDDD&'NP\\Lss3?яXbp… ` iii!;;z1];L~״iX ##c}e˖!zRuÇ+pqS""2NtttpEYl 3f `a֬Y̛7s{ px]>TۘJccN*((I&~8JҟG""")""c׳x͛=?pkBY`5/&cxB}}Í`0HkkkLGĢ^YRRRMDDDM8uX蘲7MMMCNW/_m  >gΜɜ9s^]?XR""2M)E3gΌ|LF{$''m>Pd"ź~iii^ZDDDbN$]N(cʕ*1&HIIIܮ QƁjjjL}?( xbpQ""2 `p=FzÙ<.-#)' r&e-3f\b…RXXHjj*p eee8qǏpB!zq_u$m(P>7of͚5\.jkkt۶mcΝTWW/G^^eeex<vލ8XÁhii'rMX}}>N7M$ɡRlBee%{ #<#G8{,<~:;;_7Mvɮ]hii!==J/c_[b7c-Zt¿pkNYb(;CYYeee Ykߓ66556)IYcgM6 {L}' \DDD$fLp88~=P}EwXD"D"iFI ""gPUV# NֿL>.""q3't]&CSS5͍˗/uaxQDDDD%L0$8~?!4k̜93כ#mJ(}R됖6)F;w#Go>~vzH$1xkll$nkmm ;;{ڶq0555dffyk@`L1hlltDp-ͩS())T3."2c| [_<͘1#כ-ƁBݻwޡ@ ]wŁضm=w'g?r%mw͛ǖ-[عs'nz[ow}"~ݻwSRRBii)vܹsyWo$kL5Pmmjjkre뇝Z/2w\># HII!Nkk+gԩSB|>6l 3gNc/}K<#<#|;߹}i&r{u@ or.(pI0``0)>gϞ&??իWu*H{ĉay??z]]]CP(HHɓPXXH]]O?4Y~=.> 9~8/w)((B?D{{;7nLv{x/ M>dRRR10Ο?ٳg),,TNJHݯ.tjjjx7;Z˂ hjj"%%/Fii)彏x4SR&cRRRƼDhnn()((Z$.""q|^z ͉'ػw/O[nرc|_O辘9sf\7cƻ  >9sC@DDD \DD&55q p%:糟lǬX"HIIIܮJ}}=vS\\L{{;@%KpBW e$\HKKzpI YYYA} HOO~jkk)++ctvvOsNyٺu+k׮_CRRp3gٸq#[n JKK9{,/_fڵtvv2w\v=)"""3 \Dy`::e|ᇽIYY٠~AEnne |-++kwL<_2mJ:::|5+۝|OC [Gtr@`Ko!9\]~b^5g\/0] ]-==c=ZOϟz+|Sqhmm|8PWWٳg)));=/^8l86hH ]lx2NmE5Gupz0iMi0{ 3.YJys.Z~ Eb][E81]h!{ス_/[;dn kȑ#83k-,^=çO5!y/"""EF~rUv520 ROfqDo5=rp]^T0$ xjMbmmmڵ|V^}-rcQz'%% [DiN1"r$n!_BÃ5 DDDD@&5c/qzNkotʕy`R9i->믜~ynJaa!7x#?<u]x<ˑ#G8r{D"mѣGq\x^6n܈㡠Yf [TUU/a~?:nUVQ__ٳgD"TVV+ªUhjj"=;?M6N%466Nz Lzz).9@>Xb.>xg,tu7["`.vq~@`]Uf#es-v`! 昁8[\oN]ah,p˕5bT %d x\'W&Yr @*klve|z05pX\sa}nos\ 4){aK~ւ A`[LAHnӣc m -6d1 8`+kf۟eq;@lŬ6 yߌZoq.' bjxlΆ<k- ,fϞ͂ l)))&:mL@ZB^(v_yGmjj*@vv6)د(pD1NpuDGGz vv+_R9jp.#6zrn[\t2\#\n 75y Ü7º[,&`^4wlF`ǝؿk.KlWQwW[:B-3g﫝a1a ;oxި755Jee%Ӯ3f̈&cxq B 9HNNwqa-ZDXȸf zdggS\\L ŋCIDDDl2o`ȋpVX,$=qM|߰%f^^ k5K.#-p \77s'ݧlzneltXߟ\})**?.{Jmm--zl2%gă㙶m@#eeeBw^08q~͛7ˣ ݻq+Vxx7SO {9hEVs9m#0<bYc8DsjiMSccG{= xc/u=gtvNϽq1 ər.[^^/`ҥW<:'6:::m<О={䥗^"33gϲ` eee8qǏpBaϠd-כ|>6l`Æ W^֮] EDDDÀ.i)/րsN ];İwX)ӻ~ wn0XgMR0<>g3lbf؟ mܬ1"=D;e'>q}q 7PWW;cΜ9|>ǡ2AC|r2OFN뮈HQr;\0/&g=Xd/?Ǒ-`0eu-WFĂ  /:͸ޟg:#XbMr'Dd㢥H$6a™`gΜիW /Liv"""2}(pXwm]9/ IDAT$p4!Qїs3hp1VȮ݋]vBGXwsD˿un{~b#B}F6}|v(71 "GMwmmmBuL:.׳QtBAn@188@0b@nt'zGI e9`p; !'#Þ7º*1PsF*3ׁ{_ }EcyFs[lP^Ͻ9}jjj"###nY4N6^ө`466渎Iuuąv`It=1p\]sWЛ=b#Dl\" f;O`e۔GȘhek g:3׸n =r =wKvхi5c~F} `95^>Pw[(2fΜMF6^^/---_s[AZ[[ʉ::x$(8e073og\gke/_#pgFAwH[Z_v{ބ -og`7YGWfS-bvk:LFJJJvV1݈O6 TTT hoo3g]YDDDd<H2L~[,W: v0xy`{G[-&`0Gě1cF\7[4ǻDDDdR)p $H2'`T8`5;ۂ"g 3m(""""A5\?X r5΃gTo6"p:\Hv}\pA).ADsjkk3gɴNc߾}1P""S}|PQQ1s;::X~=!(p."2DDDDD$h S""""""""c \DDDDDDDDbLH)p1.""""""""1EDDDDDDD$ƒ"r'윜1dA YYY~ {=\.Νcʕs 70o޼Au\dggEDDDD3 \DDD*vm~rrr-ҬMkعs'߿˗os]wQ]]͒%KN~\g>6mƍ)"""""2,w1."r݊D">Tg*)Y^T-RL1oUnYpxc$,.W)^$vT׫dNu9dcx$.E'NkHq7鹫ћO^\ߥ;O=T̙+2?>^{m0s}ݗ??YhQ6mڔiӦ>.bEs }iJLedžqIY"ņ"8r;=:>TdmXUbmLyѸN$Y>k}V7lY.Iq vޥhꫯmۧ>ޯ?Oe]D0$py)~pRZ3HvMv"Ռ*8)_YxHO-jku}[$+XIQ\_=;7rh?aK@`/Gy6WϮEV^_Q%$Ŋg]IʤzK߀^H5Ju\LrIR){.,~{o}Hz=ޏz!#؞.ȑ#}Ԕ+VdܹI>cǎ5@/KXLKQU/#2,Rܱ*Y4}  U]}iZӔgM\ 4i T9L5Jq_?@Jb ҁs#]sssy晬^:K.ͤIzζmrqGMQٰaCRUU~_ /s5pW,3q4\2/{rwgٙ={!%Kޞs9`\^Š'˲{rƎgFEr zst& kTz^/Z.7aD*Ŷ"P}zƌ+V39Se#]eg-HK7R<[w=N|'}BЇ"!ɫY$HҞ}a×/79Ve}L>=ISOe̙ + i,k$P},R,,/*],_UuEoN-goC 6,˽>jԨ_>I2vޯޞ'pb_uCPTήR+WdzpZ{󸭭æN`\`UrFRN+Su\~f 'f„ ϻsuGMHKKK^W+fܹr秹9-ʦM|&FO~_`h \|Ck'wve4)f#Ԛ5k2fC@pzޞɓ' p8͙3 2f`lذ!eYzL8 Ömmm50.C(8BYf \j&pf \j6{ Î8]:3  pXÑ5\j&pf \j&pf \j6PvL0!9ꨣ j?tuu _}YhQd֭1bDF;6[ng\`>ի^$ v+uּoѣ ~XbEm絯}ۺukpRUU6l0hc4a„lܸq8qb8)Sd;?۶m~w{=)rk40a7aDknn}'W(5kV=،1"o~_H{{{}ӟwߝ$yӛޔEDr… SEʲ̚5k2s̼/W\[}~. 2nܸTU{̡~e]_$kx#?0䪪TUe08":;;yw̘19rk`o7#Fڵkxi N.ak?~|Əgƍw[[6nܘ 6iV{13ʕ+IwI| 6,C֝f}'N pΌ;6_v\r%馛2}s1+sUW-&Mʜ9sܜo=eY .Hsss~|seq|Yg|3y_\yW?7n矟E;L2%~s7gر)"gΣ>}s/.uPu m[[[nHKnݚɟIK/O/~⥻Sם`nݚ~0aB>]~{_}Ih6nܘ[dz*3gH[[~ޞ$hH}G/؇+WA2f̘A`oE}8a @^z~inn71v[^wqPͲej?I`˂v" v$ƍ˸qܹskફ%\F%Kdڵr7'>\s5ikkˤI2gΜ477oOY ܜEeӦMg>FЭe֖˗kP,=>/ $wXe̙9s$7|sw樣>[.cƌ p[mW^yee.~Jmmmٲe˰ \fΜ9{AAQWUGakP>ѤQ~VU|R<]H#u=kmmMGwI2#IQWNRͫRZQOGYn>ͭӖ-[dP״>04.XUIc JJ2kT_Rl.#uL6mPcsiϓ,A#eӪ Q+S^%t'sEE/iR*+)I ǿ?)6)ɸh/{ҾFT^^%sN!IѾʩe$SRѾ~n qtvvfCچ1c ɥ*hѢ$ɳ>Gy$ .G>aѶUV ;::$&L8bPbS<$ \Ǐ7ЇoʕYjU;a9Ng}v&L+Vdy0l6yAo(n<}`h\8$Epi~STUNRܳ# 9J1H͢jqe)}ËH"E׎rOUYԵ3pYPwSxgVJ`UsdɎ脤h.Wɻ*]{ Nt?ZgggƎG{{?7n矟E׾~???3}]6]w]>ϵ^o1MMM;r9;̌3<_Wsg9~7mmmٶm[͛n)ǜnݺA Alْ˗{i7̛7/?xNQF+cǎMGGGfΜ+V'ܹsWbڼys.\N6@w~hᅠJSvˎ |fUڤjx""򢃮LomǿLvNR/zÖ$)RJ1"yc=3l E}@-_~y.p챽_'W_$re%I>vO}S__yI{}zwڸqr{IsssN8ᄌ=ze>V3c '%@!{gU[\UUSTW)&I./cdŁ5H4KkPv펲;)(Rͨe'xHR9`aˡVWUh1b},C`BRt=`^Q%$ŊgF?Te=jT}>|ۋ7\I.I5enst?\w_FQF 7ܐSfر7n\ΝrǏϔ)S>04.ԮPT*Y4} CM/:C^$m{3åh߱˄Hk4iJ~ڳL.Me~ڴ~~f͚ѣGgر{-:ի3dGxj}C1h. IDAThTR]\VXlg6Ȯʣ/O)%IUT&ଗeI<^U:J]x|G*՛>mVOtqF5MY~}Fɓ'쏩S;u-[d˖-GtfppZ2i(N,$%uX,HʋdUzBL˕E{"T>T,{bRu`Eqr^>;4HcaEI(E=8US\%;ھ7%WujooOGGGZZZ4mڴA3}`h\M5#];IOdҸs[qWj[d^"Uwe|ܐILҙIӳ~*iK#˫d^RT=wפXB4Rvɂf"y.iHvQ秳37ocuBU2{A#˗/Yoȑ#aÆL0anjժMorpl+˪k|~SGQ)|j+R7~Swuo{YHG6ׯǡ3rȃ^cŊCaP{{{֯_3永ɓ1cSOMss>m1=n pa7ŷLJuv'/VW%ӓt84Z0/{gRlܸϥO/~7'tտrʬZ*zue̘1V[ԡ5^.xj.䌤VxHR_&EҸǚ:;;3v<ٰaC,Y9s{ɶmO:7xc||>\z饹[REFL6-ׯ_\q>(RUUƍE;.dmlooOGGG qJUVeكVP`!p{!ؗ3f36l8twwyWW׀=ztʲʕ+3a„TU5,04.a͛mGy!?SO=5I<ƍgޞL0!fƍaÆ<9ӆ[nPCaUssG8bh wikkKgggO;3w}wrqeҥsUW-&Mʜ9sܜo=eY .Hsss~|sK1\x7AN ah֭ikk_/|׿/.K/Ma$?, Ύ>,[wvα$ikkKY3gN̙ٲeKoR70K0rY`Af̘1hmڴ)݃Ǯ.od8L|͹;ٶm[q}lmm2#C 04.秳37o}M{wdɃZPܢyƆbCiݺu\å#CC1A`-CGa,A# FWWנ}!p`T?#CCV~Y@B:3w8#Gfi{ ]F&^֮[3.lD---9~z礓N̈ pܜYfeɣK:~\ƍ{KQW׶ #[\ʹm4T2bDmߞ-[1ph.* `H.r9prI@.5sI0*G 3\j&p#SO-[ 0" N/϶SN9)voNCW]pvrA9Sr)'?aƌ^$n%Ox2mb]]]ۿRwLs9{h[:;;ݛnɒ_"MMM9n 3iQI'\K]e^s}ٴiS&N>3xٹ)"IsOm;ݦ]5jdfϚ38=:},w/'I>诽I%g~$wynmFٳfկ GO[;Əcgy|y\w`_p~IȖLjrJzj[n,]lw/i~;mw[nS~Ï Ӗ,_sͷd̙ښyW~ziii}4553_??˿JKKsN<[.)v?,^pE~;˸qcu|[^o2g̶m]rYgv7UO|?͛7甓NȨQ#ȣ?_ҧK,ɨQ#~|Mlp]>֡sε/kskfvѽV^QdIg'3jȜx}+3}ٴ#/_ys礵5eYfeٕOuWU_<493~8'8+r-b-U矗˖6|fUZpX3|җ!+|2_Am|kN!mS,8]}{2ozə4騜6,93$?~=w_>dڴmg,m<~չ3{C̙ N N?z.p}vu>ۿ/2wΜܻ\}K O=%W_yE>|OuƂ$_dĈڶ-WrŸ _{OWi4_˼윳y˖ҷ䮻W*Itٲ|￐,\|/eƌ,2'k[)2ۿˇ~'ʭ߽!F#eYfN20ĿT/(2_tQn֜| Io-ҫ9ka `Je ?Kߐv>}q+_{o ֪rͷ~u1{qݞ7^$M)'ohޥܾڻY~CNj~۷oOYIF2ضm[wٲuK:sAT;N;\uŻdw+g~A̷ öm۲e΀⚫ޝQF7l}Ǝ-[摟?{YiG9k_sQoX Z6=:'xb֬y^K>šs3t8aBܽL:gM$ϛH>{=xFZZZds/.JUUr/~PpWXV>*y߿_'޾}{l޽z2?`6oޜ:3y7rԟQFfk~쫽]]]moi}k7W]/^:5N!tj]}.w}!l9:p}x+^.I_~-o>|w,g#|R;l޼y'<"^Jsss_JĉY~}m=6F#l?Ӓ$'Mʗ|+_տy9g3y$'2Yy/.[emܹsr)]?Iĉ=zt?~^V@^^$ t:냁M]]zzvޚY~5k>X56`ێݠh0AO8IJͳB$x)e2 m߉mwЯO/ +Y08fۥSG6gkch4pw_^e琐ݫ'>[쾪;DDDԙw8 /c`4BVC"ݽ 2 ~uhR\V斤 \fZ_(zRP$ۛIQ;v"-&<$ܺ53nHqk`@vv6t:ris[hP*lP%Ã~cb%! 0k…>V6KiNϗDD+( ﬡ0s;e~OV,-.A͵Hu=doBWV)oN#}lv Kjj&"""G "e d j@ ٯQp…6b'\2r-"""rB. mq…xK=b4Z-bi4Z{EB!t:B%!"""Ǣ!= p'Gh Q hH:|>}HM^HK.ԙ\8FHPB QMU4ARs҅H(S H RL2.RFȎ%%tdffr™A@*"v0L_( DDDDDD5&D ty6RT5BDDDDDTTJy-DN$n:Pe^.DDDDDD5&F#$rt"[N]ۭq CGr|R(zr2327~nڢ55WO@DDD L|Z[:m&+"*7Hċ#F#;;&=ő|R_ċ/Ŕ7f")GkrΡCMs񈈈^R$ v؅P^la#۬ȑ8kؾk<~:_gOLٳM]J=琽ѣU]_”W&a+!@=M?׭ST.'' p'n _h4$ĝGvNe\|RSʼp}Rp.<.]Re998pi]_\ p6.YYY[wju&'`0ZR.\LN+Š8VťWD7ѪUޘsr+WIu99Gh#QHwk7|!!HJ 6_p&,ޙC~~>mL捩f⍩bǟAlSDn]p"4|r;ϝ]P(DZZjժo6X,6=/?TKepuuEjZ/y-#Z`5W.^ `/=8g_GƖ@pp~*t 6gj#;;"d%Yeeݻ)fbӗ駑r.FO!|}mާSD]pd  .&^«'`ԈV4g}a|[:?^+>ưG9Xk7 ܿg1xP4iܴfg8r8D fQo}ڴcM[dZKE+=g> -_Q|x+ʁ$-[gt|aX3.\b=8w..7} ZC!w[_pit[U4yH$ITiΝغ B1`Y4a,<<[s倹,_kYE,,qn:DDDѣ>}"""ХK3҇{oot=*p1$c-BBdggٳؿ?VX5k>G  {PX4WӺePLÐzr2\\\J| ]vӫzxx ._AllT(&%nSib=u53вEsx{{MVZ BCAU1())w|&yTv~•о]\|99x ;#GNǞEvm!,ꇊʘk?'C퍓1qt,]ђnj&2 &Og>V-#Pv0%Μ[eJ9X1Κ-ިeM/ծݻAz:.&^a<$յxwSӐ|#`]q~W%z5EUd̚X3>ܰu,MLIL8֭3fcǎ0mmE*%cСԩfΜ>cswUE._$A Pr8_nڈ-۶cЦu+}w|GVC,U.O¯Ex0ԯ_yyy32u_u_ Eq0 VŠ8  qwkf^^H@fMQ;8 "ۣ}6X|%rss{6cGlq?TT\;Mzz\\\)zfMے...=.;ބH$kV.ARYngK2ggMGmv%gn??3M~2]a-3LU}]MϬ5ロ {Ēș__l@^ItHDE_tv <¿ƍ_bqq^$NXDzs:&.ǟ˗.*A_"33t{NšƁTZ4~jʂןo0ՙeV[1 v *cTP(Z`QRo׶ _ɘS[3 9?mCEe}l;M`? ޞ1T_E,)Rz:L?؈Nu@@CWFϯoIUt,9s~/pUѹiMVgЯ_7գUd?~E9R 35u kMl=۟ロ {Ē>O;vDƍ1pJկ_ʟpߝȳ*#::ׯǞ{K#|fwKeehF[L 4xi|uF# rh5 NƜFR׃0|T]ߛmzԪU -#Z`_`0h4on: -Z41][;qJ [ҹclݶaݖ2h2ܴHnn.n߾cuYш>BΝ  /`[=pY~Dvv6ڵy_՜ιP^HL[ӿ2$ >_=u1]` qn؈Bhu:q=}]9~D.T[W.쌋lqgϢgϢ5 n߾] .?]9COEJJ ~w=zCLL zsqq#mkHgρTꁜ_&OgU*+cXp._}ܼ^Qki_/m*g`sÖc`_}s8)$&^ĤI_l^/z2|} ??x{Hw3xEێkݸ!Uj2"B ywAư1#ƤW} TS1RU^XXRHw5BR۫7Fjݷ^^/G?O.iIAE .W̕E;Jח \fZ{eէ sCTA.v;[W7y.GB΄ª[$dg*G&._k/%ロ [RTӈtNX.=z;w͛шV|V}FAЦ! cz&(  Md@2{+܏^#F >>cƌ#G|pwhެܡ+|[T;];rFGÆ!fbޚAEl’6+c2iMY{@ x- Kl_ݜ,&g[ߒVe&\Y2>ت_lKK4"".J wE=0Ph͇#!pAơu.?=_ysı `6m9h0%ﳗ'""""9aaaH*q ܲ[{NA0uD:`1c uBN52;dgdALZ.CPP 󟈈lUjj*"""УG$Ĝ3M,ë?6QkIѲ`ٳ[#P ,d3a'"""""̝;cƌmQ#G!)~@Fv?PB>>Dشi>:t@аaC j5.\'N8z(d2ׯHq2\4 sŘ1cpUšW^HHHѣ X@4iP(pssCÆ 1g(JL4 7n7PPPou2…jB@JJ nݺ;v,Ǝkz]ATBTB(r..eyͅJB0NVˋwp…Q093 66uŋѺuk߿%V$! hԨ Eɖ<^ԩkz-66͛5ci+p!""""""DV~̚5 鉸8|wXx1F֭[#22c+WK.ؽ{7ڶm[bCx'P3KLxJ="""""";:v"M3BբgTO̟7#F(zff&N>'OXhLVБhٲ%bqv܉-CTxJt-7+;^BDDDDDDT XUFqJ퍨(DEEUk?6lܹs;88BDDDDDDdFDD߽3OѵkWnRZfgg#66 F#݇0 """"""vD 4jGq8w./_VV}bhٲz WWW%^[F! ݧ/z˼JDDDDDDDD6 """""""" q """""GhjDΌW0P^@9^,p!"""""ar9RAI"둖vROixKQ @jZnݼI"& !B,yMRgA""""""""rih5{p """""""ԴT`0vP\\҅* RRqU2լlKIENDB`crystal-facet-uml-1.34.1/build/000077500000000000000000000000001415120503000162225ustar00rootroot00000000000000crystal-facet-uml-1.34.1/build/deb/000077500000000000000000000000001415120503000167545ustar00rootroot00000000000000crystal-facet-uml-1.34.1/build/deb/debian/000077500000000000000000000000001415120503000201765ustar00rootroot00000000000000crystal-facet-uml-1.34.1/build/deb/debian/changelog000066400000000000000000000426071415120503000220610ustar00rootroot00000000000000crystal-facet-uml (1.34.1-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * no error if gtk_init_check fails - otherwise tests would fail -- Andreas Warnke Mon, 29 Nov 2021 20:00:00 +0200 crystal-facet-uml (1.34.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * export in json format contains also uuids as links (for auto-merging) * export in json format nicer for humans to read (for diff and merge) * export in json format contains also lifelines -- Andreas Warnke Sun, 28 Nov 2021 21:00:00 +0200 crystal-facet-uml (1.33.1-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * fix: When cutting a diagram, one can immediately paste it to the previous position; also paste it immediately after opening a new db. * Layouting of lines prefers connector types Z over S, N over L7 -- Andreas Warnke Sat, 23 Oct 2021 18:00:00 +0200 crystal-facet-uml (1.33.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * The database has new fields uuid and diagram.display_flags * fix: when copying objects via clipboard, the last characters are not dropped if escape-sequences cause exceeding maximum string length * json export (experimental) -- Andreas Warnke Sat, 16 Oct 2021 08:00:00 +0200 crystal-facet-uml (1.32.1-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * test_expand_space is now more robust against unexpected installed fonts -- Andreas Warnke Sun, 29 Aug 2021 19:00:00 +0200 crystal-facet-uml (1.32.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * overlaps between relationships with identical type, source and destination are avoided. * good default size of classifiers in case classifiers share same location * less overlaps to labels below actor, fork/join, start/end, h, time * nicer relationships to comments and requirements in sequences and timing -- Andreas Warnke Sun, 29 Aug 2021 16:00:00 +0200 crystal-facet-uml (1.31.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * component titles do not touch the type icon anymore * icon alignment in classifiers is not rounded to int anymore * use case circles do not cut into label texts * decision/choice rhombus do not cut into label texts * send signal arrows do not cut into label texts * accept event flags do not cut into label texts -- Andreas Warnke Sat, 31 Jul 2021 16:00:00 +0200 crystal-facet-uml (1.30.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * in search mode, objects are highlighted individually (not all per diagram) * in search result list, long names have nice linebreaks * in navigation tree, long names have nice linebreaks * Guillements characters surround stereoptypes -- Andreas Warnke Sat, 05 Jun 2021 08:00:00 +0200 crystal-facet-uml (1.29.1-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * newly created classifiers are placed to clicked location (bugfix, bug introduced on Fri Mar 26, affecting v1.28.0 and v1.29.0) -- Andreas Warnke Sun, 02 May 2021 16:00:00 +0200 crystal-facet-uml (1.29.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * return arrows in sequences have filled arrow tips, distinguishable from dependencies * stereotypes are xmi-exported to LocalProfile namespace * valuetypes are xmi-exported to DataTypes * metainfo.xml references homepage which is now tls-authenticated * nav-tree and search result lists draw a bit more space around texts * A white line is drawn around highlighted diagrams (additional to green marker) -- Andreas Warnke Sat, 01 May 2021 22:00:00 +0200 crystal-facet-uml (1.28.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * gcov target is only build if -DCFU_ADD_GCOV_TARGET=ON (Closes: #983836) * test coverage on pencil package increased * exporting image-file types shows statistics on exported elements * list layout improved, golden ratio is applied * timing and sequence diagram layouting improved; special handling for comments/reqs in timing and sequence diagrams * version compatibility also in debug mode: newer database-files can be opened with older programs; asserts removed * Messages are not cut off after 255 characters (511 now) * When resetting selection, diagram is redrawn -- Andreas Warnke Fri, 02 Apr 2021 08:00:00 +0200 crystal-facet-uml (1.27.3-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * fixed most metainfo.xml warnings * build target for gcov measurement added * auto-delete relationships between classifiers that have no common diagram * when opening the second database, view switches back to navigation mode * when opening the second database, search entry field is cleared * when opening the second database, set of marked elements is cleared * search result view is updated when changing the database (e.g. by undo) * search result view stays when database update is triggered by a 2nd window * when clicking on a search result, the element is focused -- Andreas Warnke Tue, 09 Feb 2021 21:30:00 +0100 crystal-facet-uml (1.27.2-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * compiler switch Werror removed; warnings should not cause build-breaks -- Andreas Warnke Sun, 03 Jan 2021 15:00:00 +0100 crystal-facet-uml (1.27.1-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * compiler warning fixed: conversions from unsigned int to size_t explicit -- Andreas Warnke Sun, 03 Jan 2021 09:00:00 +0100 crystal-facet-uml (1.27.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * new upstream version 1.27.0 * metadata file has license MIT as requested by freedesktop.org * CMakeLists has no separate compiler flags for testing executable anymore -- Andreas Warnke Sat, 02 Jan 2021 19:00:00 +0100 crystal-facet-uml (1.26.1-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * XMI Export: destination end of messages had fix enclosingInteraction=90001 * XMI Export: Properties have attributes class and interface if applicable * XMI Export: Warnings are issued at illegal relationship end types * XMI Export: dependencies of comments to annotatedElements conform to spec * XMI Export: associations and communication paths can connect to ports * XMI Export: nested activities are exported as StructuredActivityNode * icons beautified * program renamed from crystal_facet_uml to crystal-facet-uml -- Andreas Warnke Sun, 20 Dec 2020 16:30:00 +0100 crystal-facet-uml (1.26.0-1) UNRELEASED; urgency=medium [ Helmut Grohne ] * debian/rules: + Fix FTCBFS: Let dh_auto_configure pass cross flags to cmake. (Closes: #973980). [ Olaf Hering ] * CMakeLists adapted to find pangocairo (Closes: #2) [ Mike Gabriel ] * Grammar fixes in application messages [ Andreas Warnke ] * xmi export exports sequence, timing, communication and interaction overview * xmi export creates property-elements at association-member-ends * system boundary renamed to subsystem (to match uml 2.5.1 spec) * The default relationship type between lifelines is a synchronous call -- Andreas Warnke Sun, 22 Nov 2020 16:30:00 +0100 crystal-facet-uml (1.25.1-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * cmake does not depend on c++ compiler anymore -- Andreas Warnke Thu, 29 Oct 2020 20:30:00 +0100 crystal-facet-uml (1.25.0-2) UNRELEASED; urgency=medium [ Andreas Warnke ] * yml script for ci added -- Andreas Warnke Wed, 28 Oct 2020 07:40:00 +0100 crystal-facet-uml (1.25.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * moving ports follow the cursor more accurate * Constraint Blocks show their ports completely inside * Artifacts and Components do not waste space for contained children * Comment titles do not overlap with the comment-corner * packages containing children display their title in the tab-symbol * layouting containments does not reserve columns/rows for the container * Feature/Composite Requirement does not exist anymore, data from older versions is auto-converted to Requirement * Requirements are displyed as box-with-label omitting the description * Interaction Overview Diagram is redesigned, data from older versions is auto-converted to Activity Diagram -- Andreas Warnke Sun, 18 Oct 2020 20:30:00 +0200 crystal-facet-uml (1.24.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * XMI(TM) export reflects containment-hierarcy of elements * XMI(TM) export automatically disambiguates between activity/state contexts * warnings are printed to xml export if model is not uml compliant * no arrow tip at communication path * export shows statistics on diagrams or classifiers * internal: messages to user are typesafe for their parameters -- Andreas Warnke Thu, 08 Oct 2020 20:30:00 +0200 crystal-facet-uml (1.23.1-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * XMI(TM) export good enough to be checked by NIST validator -- Andreas Warnke Sun, 06 Sep 2020 11:30:00 +0200 crystal-facet-uml (1.23.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * at operations cut, copy, paste and delete: print understandable statistics * at operations undo, redo: print understandable statistics * layouting of classifiers improved * experimental xmi export -- Andreas Warnke Sun, 14 Jun 2020 17:30:00 +0200 crystal-facet-uml (1.22.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * the xhtml export produces a table-of-contents * the xhtml+db exports generate links to diagrams by D0001#name. * the element configuration area on the right does not take space needed by the drawing area * yellow highlighted names are drawn behind the classifier-contour-line -- Andreas Warnke Fri, 01 May 2020 17:30:00 +0200 crystal-facet-uml (1.21.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * containers embrace their children keeping wider gaps -- Andreas Warnke Sun, 12 Apr 2020 16:30:00 +0200 crystal-facet-uml (1.20.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * xhtml output generates a css file to allow defining own color schemes * xhtml output keeps linebreaks in selected (md) cases * bugfix: exporting docbook and xhtml via command line arguments works again, as in 1.16.1 (Closes: #1) * exported xhtml passes https://validator.w3.org/check (for quality.cfu1) * exported xhtml/css shows chapter numbers -- Andreas Warnke Mon, 23 Mar 2020 18:30:00 +0100 crystal-facet-uml (1.19.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * free text search * small memory leak in nav-tree-view fixed -- Andreas Warnke Sat, 14 Mar 2020 12:30:00 +0100 crystal-facet-uml (1.18.1-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * when exporting xhtml and docbook files, windows pathnames are supported -- Andreas Warnke Mon, 20 Jan 2020 21:30:00 +0100 crystal-facet-uml (1.18.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * the search view allows one to search for object ids * bugfix: when changing type of an object, lastest changes to name or description are not lost * pressing enter in name or stereotype field causes a save action -- Andreas Warnke Sun, 19 Jan 2020 20:30:00 +0100 crystal-facet-uml (1.17.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * cmake build config is less platform dependent * nav-tree: dragging diagrams shows a tree-depth aware insert line * while dragging, grid lines are displayed * the description text-view has scrollbars * in nav view, a click into the current diagram zooms to edit mode * in create view, an icon next to the mouse cursor shows options * fix: type dropdown box does not change DB automatically if unknown type id * the type drop down box shows icons to faster find the right type * an icon grid allows one to change types quickly -- Andreas Warnke Sun, 05 Jan 2020 20:30:00 +0100 crystal-facet-uml (1.16.2-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * relationships may overlap if same type and same direction * title and filename of exported docbook and xhtml equals database file name -- Andreas Warnke Sun, 08 Dec 2019 11:30:00 +0100 crystal-facet-uml (1.16.1-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * rpm package build scripts beautified -- Andreas Warnke Tue, 26 Nov 2019 19:30:00 +0100 crystal-facet-uml (1.16.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * Diagram exports can be triggered from command line * Cut + paste of relationships is possible * Json format in clipboard slightly modified (set renamed to data, order required, relationship src/dst names added) * The default classifier size is calculated based on the grid-distances * Fix: Scenario based diagrams showing multiple identical classifier instances show not too many relationships -- Andreas Warnke Sat, 16 Nov 2019 19:30:00 +0100 crystal-facet-uml (1.15.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * The id of selected objects is displayed in the edit area * Child diagrams are layouted in a grid (in navigation view) -- Andreas Warnke Sun, 20 Oct 2019 12:30:00 +0200 crystal-facet-uml (1.14.2-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * gtk is initialized before data and ctrl packages --> fix for wine -- Andreas Warnke Fri, 06 Sep 2019 19:30:00 +0200 crystal-facet-uml (1.14.1-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * background image added to intro screen. * compatibility to GTK 3.6 established, newer features replaced * pthread dependency replaced by glib functions * build for wine using mingw -- Andreas Warnke Mon, 02 Sep 2019 21:30:00 +0200 crystal-facet-uml (1.14.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * all features (except lifelines) are hidden in scenario-based and box/list diagrams * non-global relationships are hidden in scenario-based and all in box/list diagrams * exporting descriptions of hidden relationships and features is suppressed * any classifier can be displayed as named instance or as anonymous instance. -- Andreas Warnke Sun, 14 Jul 2019 11:30:00 +0200 crystal-facet-uml (1.13.1-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * sqlite3_db_cacheflush() is only called if on the build system and on the target system available (bugfix) -- Andreas Warnke Sun, 23 Jun 2019 15:30:00 +0200 crystal-facet-uml (1.13.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * improved auto-layout of relationship labels * call/transition to self is layouted nicely in sequence/timing diagrams * automatically grey out arrows if source or destination classifier is greyed out * prevent creation of relationships if unsuitable diagram type * prevent creation of features if unsuitable diagram type * prevent creation of features if unsuitable classifier type -- Andreas Warnke Fri, 21 Jun 2019 15:30:00 +0200 crystal-facet-uml (1.12.1-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * Packageing issues addressed -- Andreas Warnke Wed, 15 May 2019 20:30:00 +0200 crystal-facet-uml (1.12.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * Auto-Layouting of classifiers improved -- Andreas Warnke Sat, 27 Apr 2019 21:33:01 +0200 crystal-facet-uml (1.11.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * New version 1.11.0 exports docbook and html formats -- Andreas Warnke Sun, 10 Mar 2019 11:33:01 +0100 crystal-facet-uml (1.10.0-1ubuntu1) UNRELEASED; urgency=medium [ Andreas Warnke ] * New version 1.10.0 provides more classifiers for activity diagrams -- Andreas Warnke Sun, 03 Feb 2019 17:32:01 +0100 crystal-facet-uml (1.9.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * New version 1.9.0 supports interfaces at components -- Andreas Warnke Thu, 17 Jan 2019 20:06:11 +0100 crystal-facet-uml (1.8.0-1) UNRELEASED; urgency=medium [ Andreas Warnke ] * New version 1.8.0 supports re-ordering features and diagrams -- Andreas Warnke Tue, 01 Jan 2019 08:57:14 +0100 crystal-facet-uml (1.7.1-1) UNRELEASED; urgency=medium * User documentation is generated from docbook. -- Andreas Warnke Wed, 21 Nov 2018 21:00:00 +0100 crystal-facet-uml (1.7.0-1) UNRELEASED; urgency=medium * tree view allows to navigate interactively * new sibling and new child diagrams can be created in tree view * when deleting a diagram, unfocused windows show parent diagram * only local-scenario relationships are shown in timing, sequence and communication diagrams -- Andreas Warnke Thu, 01 Nov 2018 15:42:20 +0100 crystal-facet-uml (1.6.1-1) UNRELEASED; urgency=medium * Restructure deb packet generation from CPACK to dh_make tool. -- Andreas Warnke Mon, 15 Oct 2018 21:00:00 +0200 crystal-facet-uml-1.34.1/build/deb/debian/compat000066400000000000000000000000031415120503000213750ustar00rootroot0000000000000010 crystal-facet-uml-1.34.1/build/deb/debian/control000066400000000000000000000022261415120503000216030ustar00rootroot00000000000000Source: crystal-facet-uml Section: devel Priority: optional Maintainer: Andreas Warnke Build-Depends: cmake, debhelper (>= 10), gcc, libsqlite3-dev, libgtk-3-dev Standards-Version: 4.1.2 Homepage: http://andreaswarnke.de/crystal_facet_uml/html/index.html Vcs-Git: https://github.com/awarnke/crystal-facet-uml.git Vcs-Browser: https://github.com/awarnke/crystal-facet-uml Package: crystal-facet-uml Architecture: any Depends: libgtk-3-0, libsqlite3-0, ${shlibs:Depends}, ${misc:Depends} Description: Diagram documentation tool for system and software architecture: crystal-facet-uml creates sysml/uml diagrams to document system and software architecture. . As software architect, you create a set of diagrams describing use-cases, requirements, structural views, behavioral and deployment views. crystal-facet-uml keeps element names and element hierarchies consistent. It exports diagrams in svg, pdf, ps and png formats to be used in text processing systems like DocBook, html, LaTeX. crystal-facet-uml exports the model to xmi format. This tool runs on your local linux PC and is based on glib, gdk, gtk, cairo, pango, sqlite. crystal-facet-uml-1.34.1/build/deb/debian/copyright000066400000000000000000000021231415120503000221270ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: crystal-facet-uml Source: https://github.com/awarnke/crystal-facet-uml Files: * Copyright: 2016-2020, Andreas Warnke License: Apache-2.0 Files: debian/* Copyright: 2018-2020, Andreas Warnke 2019-2020, Mike Gabriel License: Apache-2.0 License: Apache-2.0 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at . https://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. . On Debian systems, the complete text of the Apache version 2.0 license can be found in "/usr/share/common-licenses/Apache-2.0". crystal-facet-uml-1.34.1/build/deb/debian/doc-base000066400000000000000000000005001415120503000215710ustar00rootroot00000000000000Document: crystal-facet-uml-user-documentation Title: crystal-facet-uml Documentation Author: Andreas Warnke Abstract: This manual describes the features of crystal-facet-uml and how to use these. Section: Science/Engineering Format: PDF Files: /usr/share/doc/crystal-facet-uml/crystal-facet-uml_documentation.pdf.gz crystal-facet-uml-1.34.1/build/deb/debian/docs000066400000000000000000000000551415120503000210510ustar00rootroot00000000000000user_doc/crystal-facet-uml_documentation.pdf crystal-facet-uml-1.34.1/build/deb/debian/rules000077500000000000000000000012341415120503000212560ustar00rootroot00000000000000#!/usr/bin/make -f # See debhelper(7) (uncomment to enable) # output every command that modifies files on the build system. export DH_VERBOSE = 1 # see FEATURE AREAS in dpkg-buildflags(1) export DEB_BUILD_MAINT_OPTIONS = hardening=+all # see ENVIRONMENT in dpkg-buildflags(1) # package maintainers to append CFLAGS export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic %: dh $@ override_dh_auto_configure: dh_auto_configure -- \ -DCMAKE_VERBOSE_MAKEFILE:BOOL=TRUE \ -DCMAKE_BUILD_TYPE=Release override_dh_auto_build: DEB_BUILD_HARDENING=1 dh_auto_build get-orig-source: uscan --noconf --force-download --rename --download-current-version --destdir=.. crystal-facet-uml-1.34.1/build/deb/debian/source/000077500000000000000000000000001415120503000214765ustar00rootroot00000000000000crystal-facet-uml-1.34.1/build/deb/debian/source/format000066400000000000000000000000141415120503000227040ustar00rootroot000000000000003.0 (quilt) crystal-facet-uml-1.34.1/build/deb/debian/upstream/000077500000000000000000000000001415120503000220365ustar00rootroot00000000000000crystal-facet-uml-1.34.1/build/deb/debian/upstream/metadata000066400000000000000000000004001415120503000235330ustar00rootroot00000000000000--- Name: crystal-facet-uml Contact: Andreas Warnke Documentation: http://www.andreaswarnke.de/crystal_facet_uml/html/index.html Repository: https://github.com/awarnke/crystal-facet-uml.git Bug-Database: https://github.com/awarnke/crystal-facet-uml/issues crystal-facet-uml-1.34.1/build/deb/make.sh000077500000000000000000000020521415120503000202270ustar00rootroot00000000000000#!/bin/sh . ../../main/include/meta/meta_version.inl VERSIONSTR=${META_VERSION_STR} echo "Building Archive Version $VERSIONSTR" echo "based on latest git commit. (Remember to commit your latest changes!)" echo "----" echo "clean old files and directories" test -e crystal-facet-uml_$VERSIONSTR.orig.tar.gz && rm crystal-facet-uml_$VERSIONSTR.orig.tar.gz test -d crystal-facet-uml-$VERSIONSTR && rm -r crystal-facet-uml-$VERSIONSTR echo "pack src archive" cd ../.. git archive --format tar.gz --prefix=crystal-facet-uml-$VERSIONSTR/ --output=build/deb/crystal-facet-uml_$VERSIONSTR.orig.tar.gz master cd build/deb tar -xzf crystal-facet-uml_$VERSIONSTR.orig.tar.gz cp -r debian crystal-facet-uml-$VERSIONSTR/ # note _ is not allowed in debian package names cd crystal-facet-uml-$VERSIONSTR #debuild -i -us -uc -b --lintian-opts -i # -us and -uc suppress signing debuild -i -b --lintian-opts -i # check man dpkg-buildpackage and man lintian for options cd .. echo Test the created archive by installing it: echo sudo dpkg -i crystal-facet-uml_$VERSIONSTR-1_amd64.deb crystal-facet-uml-1.34.1/build/deb/readme.markdown000066400000000000000000000006631415120503000217620ustar00rootroot00000000000000 Release crystal_facet_uml ============= This section is for developers. It describes packaging and releasing a version of crystal_facet_uml. Pack ----------- > # commit all changes before packing ! > # build and test for debian, ubuntu, raspbian: > ./debian_pack.sh > debsigs --sign=origin -k=DA4213C7 crystal-facet-uml_$VERSIONSTR-1_amd64.deb > sudo dpkg -i crystal-facet-uml_$VERSIONSTR-1_amd64.deb crystal-facet-uml-1.34.1/build/deb/salsa_scripts/000077500000000000000000000000001415120503000216265ustar00rootroot00000000000000crystal-facet-uml-1.34.1/build/deb/salsa_scripts/debian_manual_build.sh000066400000000000000000000017151415120503000261240ustar00rootroot00000000000000#!/bin/sh # goal of this script is to perform the build steps # in a similar way as the the salsa/gitlab ci system echo run this script in the root folder of the cloned git repo https://salsa.debian.org/debian-edu-pkg-team/crystal-facet-uml test -e debian || exit echo cleaning up previous downloads and builds rm ../crystal-facet-uml_*.orig.tar.gz rm -fr CMakeCache.txt CMakeFiles/ cmake_install.cmake Makefile rm -r install_manifest.txt rm -fr architecture CMakeLists.txt ctrl data doxygen_build gui installation_linux io license.txt main pencil readme.markdown ChangeLog test_fw todo.txt trace tslog universal user_doc utf8stringbuf rm -f crystal-facet-uml test_crystal-facet-uml echo fetching sources debian/rules get-orig-source (cd .. && tar --strip=1 --one-top-level=crystal-facet-uml -xzf crystal-facet-uml_*.orig.tar.gz) echo building binaries and package debuild --diff-ignore='^(\.git.*|.*\.yml)$' --lintian-opts -i --pedantic yamllint debian/upstream/metadata crystal-facet-uml-1.34.1/build/gui_resources/000077500000000000000000000000001415120503000211005ustar00rootroot00000000000000crystal-facet-uml-1.34.1/build/gui_resources/prepare.sh000077500000000000000000000030571415120503000231020ustar00rootroot00000000000000#!/bin/sh SRCDIR=../../gui/source/resources BLDDIR=build_dir echo "creating Makefile..." rm -f Makefile echo "creating all target" echo ".PHONY: all " >> Makefile echo -n "all:${BLDDIR} " >> Makefile ls ${SRCDIR}/*.svg | sed -e 's#^\(../../gui/source/resources/\)\([^.]*\).svg# build_dir/\2.pdf build_dir/\2.png#g' | xargs echo -n >> Makefile echo " info" >> Makefile echo "" >> Makefile echo "creating ${BLDDIR} target" echo ".PHONY: ${BLDDIR}" >> Makefile echo "${BLDDIR}:" >> Makefile printf "\tmkdir -p ${BLDDIR}\n" >> Makefile echo "creating pdf targets" ls ${SRCDIR}/*.svg | sed -e 's#^\(../../gui/source/resources/\)\([^.]*\).svg#build_dir/\2.pdf: \1\2.svg\n\tinkscape --export-pdf=build_dir/\2.pdf --file=\1\2.svg --without-gui\n#' >> Makefile echo "creating png targets" ls ${SRCDIR}/*.svg | sed -e 's#^\(../../gui/source/resources/\)\([^.]*\).svg#build_dir/\2.png: \1\2.svg\n\tinkscape --export-png=build_dir/\2.png --file=\1\2.svg --without-gui\n#' >> Makefile echo "creating info target" echo ".PHONY: info" >> Makefile echo "info:" >> Makefile printf "\t@printf \"== call \\\\e[33;1m make install \\\\e[0m to update the files in folder ../../gui/source/resources ==\"\\n" >> Makefile echo "creating install target" echo "" >> Makefile echo ".PHONY: install" >> Makefile echo "install:" >> Makefile printf "\tcp build_dir/*.png build_dir/*.pdf ../../gui/source/resources/\n" >> Makefile echo "" >> Makefile echo "creating clean target" echo ".PHONY: clean" >> Makefile echo "clean:" >> Makefile printf "\trm -fr ${BLDDIR}\n" >> Makefile echo "Makefile created." crystal-facet-uml-1.34.1/build/package/000077500000000000000000000000001415120503000176155ustar00rootroot00000000000000crystal-facet-uml-1.34.1/build/package/make.sh000077500000000000000000000000601415120503000210650ustar00rootroot00000000000000#!/bin/sh . ./source_pack.sh . ./source_test.sh crystal-facet-uml-1.34.1/build/package/readme.markdown000066400000000000000000000013701415120503000226170ustar00rootroot00000000000000 Release crystal-facet-uml ============= This section is for developers. It describes packaging and releasing a version of crystal-facet-uml. Prepare ----------- Update all version numbers: > build/deb/debian/changelog : new entry > build/rpm/SPECS/crystal-facet-uml.spec : Version > main/include/meta/meta_version.inl : META_VERSION_STR > ChangeLog : new entry > user_doc/doc/crystal_facet_documentation.xml : date Pack ----------- > git commit -a -m 'version x.y.z' > # build and test source packet > ./source_pack.sh > ./source_test.sh Tag and Push ----------- > # add a version tag to the git revision: > git tag -a v1.12.0 8f17811 > git push origin master --follow-tags crystal-facet-uml-1.34.1/build/package/source_pack.sh000077500000000000000000000013301415120503000224470ustar00rootroot00000000000000#!/bin/sh . ../../main/include/meta/meta_version.inl VERSIONSTR=${META_VERSION_STR} echo "Building Source Package Version $VERSIONSTR" if [ -z ${VERSIONSTR} ]; then exit; fi echo "based on latest git commit. (Remember to commit your latest changes!)" echo "----" echo "clean up possibly broken previous build" test -e crystal-facet-uml_$VERSIONSTR.orig.tar.gz && rm crystal-facet-uml_$VERSIONSTR.orig.tar.gz echo "pack archive" cd ../.. git archive --format tar.gz --prefix=crystal-facet-uml-$VERSIONSTR/ --output=build/package/crystal-facet-uml_$VERSIONSTR.orig.tar.gz master cd build/package echo "----" echo "output written to crystal-facet-uml_$VERSIONSTR.orig.tar.gz" echo "test the archive by calling ./source_test.sh" crystal-facet-uml-1.34.1/build/package/source_test.sh000077500000000000000000000021231415120503000225110ustar00rootroot00000000000000#!/bin/sh . ../../main/include/meta/meta_version.inl VERSIONSTR=${META_VERSION_STR} echo "Testing Source Package Version $VERSIONSTR" if [ -z ${VERSIONSTR}]; then exit; fi echo "based on crystal-facet-uml_$VERSIONSTR.orig.tar.gz" echo "----" echo "clean up possibly broken previous test-build" test -d crystal-facet-uml-$VERSIONSTR && rm -fr crystal-facet-uml-$VERSIONSTR test -d cmake_build && rm -fr cmake_build echo "test archive" tar -xzf crystal-facet-uml_$VERSIONSTR.orig.tar.gz echo "building doc" cd crystal-facet-uml-$VERSIONSTR/build/source_code_doc ./make.sh cd ../../.. echo "building user doc and man page" cd crystal-facet-uml-$VERSIONSTR/build/user_doc make cd ../../.. echo "building binary" mkdir cmake_build cd cmake_build cmake -DCMAKE_BUILD_TYPE=Release ../crystal-facet-uml-$VERSIONSTR make -j4 # start up to 4 parallel processes to make use of quad-core processors cd .. echo "runing unit tests" cd cmake_build ./test_crystal-facet-uml -a || echo "ERROR == ERROR == ERROR == ERROR" cd .. echo "clean up test" sleep 10 rm -fr crystal-facet-uml-$VERSIONSTR rm -fr cmake_build crystal-facet-uml-1.34.1/build/package/stat.sh000077500000000000000000000007071415120503000211330ustar00rootroot00000000000000#!/bin/sh echo 'number of files' find ../../ctrl ../../data ../../gui ../../main ../../pencil ../../io ../../test_fw ../../trace ../../tslog ../../universal ../../utf8stringbuf -name '*.c' -o -name '*.inl' -o -name '*.h' | wc echo 'number of lines' find ../../ctrl ../../data ../../gui ../../main ../../pencil ../../io ../../test_fw ../../trace ../../tslog ../../universal ../../utf8stringbuf -name '*.c' -o -name '*.inl' -o -name '*.h' | sort | xargs wc crystal-facet-uml-1.34.1/build/readme.markdown000066400000000000000000000036701415120503000212310ustar00rootroot00000000000000 Build crystal-facet-uml ============= How to build from source ----------- Building from source is described in this section. debian/ubuntu/raspbian: > sudo apt install gcc > > sudo apt install cmake > > sudo apt install libgtk-3-dev > > sudo apt install libsqlite3-dev > > sudo apt install devscripts # for debian build, includes possibly build-essential > > sudo apt install build-essential # for debian build, possibly outdated? > > sudo apt install yamllint # for debian script checker > > sudo apt install debsigs # for signing debian packages > > sudo apt install dblatex # for user documentation > > sudo apt install xmlto # for user documentation > > sudo apt install doxygen # for source code documentation > > sudo apt install inkscape # for generation of pdf and png icons from svg > > sudo apt install lcov # for reporting test coverage > mkdir my_build && cd my_build > > cmake -DCMAKE_BUILD_TYPE=Release ../crystal-facet-uml/ # adapt the source directory name > > make crystal-facet-uml > > sudo make install openSuSE: > sudo zypper install gcc > > sudo zypper install cmake > > sudo zypper install gtk3-devel > > sudo zypper install sqlite3-devel > > sudo zypper install devscripts # for debian build, includes build-essential > > sudo zypper install dblatex # for user documentation > > sudo zypper install xmlto # for user documentation > > sudo zypper install doxygen # for source code documentation > > sudo zypper install fakeroot # to build debian archives > > sudo zypper install debhelper # to build debian archives > > sudo zypper install inkscape # for generation of pdf and png icons from svg > > sudo zypper install lcov # for reporting test coverage > mkdir my_build && cd my_build > > cmake -DCMAKE_BUILD_TYPE=Release ../crystal-facet-uml/ # adapt the source directory name > > make crystal-facet-uml > > sudo make install wine: > see win/readme.markdown crystal-facet-uml-1.34.1/build/rpm/000077500000000000000000000000001415120503000170205ustar00rootroot00000000000000crystal-facet-uml-1.34.1/build/rpm/SPECS/000077500000000000000000000000001415120503000176755ustar00rootroot00000000000000crystal-facet-uml-1.34.1/build/rpm/SPECS/crystal-facet-uml.spec000066400000000000000000000047171415120503000241160ustar00rootroot00000000000000# # spec file for package crystal-facet-uml # # Copyright (c) 2019-2020 SUSE LLC # Copyright (c) 2017-2020 Andreas Warnke cfu@andreaswarnke.de # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed # upon. The license for this file, and modifications and additions to the # file, is the same license as for the pristine package itself (unless the # license for the pristine package is not an Open Source License, in which # case the license is the MIT License). An "Open Source License" is a # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. # Please submit bugfixes or comments via https://bugs.opensuse.org/ # Name: crystal-facet-uml Version: 1.34.1 Release: 0 Summary: Draws UML/SysML Diagrams License: Apache-2.0 Group: Development/Tools/Doc Generators URL: https://github.com/awarnke/crystal-facet-uml Source: crystal-facet-uml_%{version}.orig.tar.gz BuildRequires: cmake BuildRequires: gcc BuildRequires: gtk3-devel BuildRequires: sqlite3-devel BuildRequires: tar BuildRequires: xorg-x11-fonts-core %description crystal-facet-uml creates sysml/uml diagrams to document system and software architecture. As software architect, you can create a set of diagrams describing use-cases, requirements, structural views, behavioral and deployment views. crystal-facet-uml keeps element names and element hierarchies consistent. The tool exports diagrams as svg, pdf, ps and png formats to be used in text processing systems as docbook, html, latex. crystal-facet-uml exports the model to xmi format. It runs on your local linux PC and is based on glib, gdk, gtk, cairo, pango, sqlite. %prep %setup -q -n crystal-facet-uml-%{version} %build %cmake \ -DCMAKE_BUILD_TYPE=Release %if 0%{?cmake_build:1} # cmake_build works with openSuSE_TumbleWeed and openSuSE_Leap_15.1 %cmake_build %else # fallback for old openSUSE_Leap_42.3: %make_jobs %endif %install %cmake_install %check ./build/crystal-facet-uml -v ./build/test_crystal-facet-uml -a %files %license license.txt %doc readme.markdown ChangeLog user_doc/crystal-facet-uml_documentation.pdf %{_bindir}/crystal-facet-uml %{_datadir}/pixmaps/crystal-facet-uml.png %{_datadir}/applications/crystal-facet-uml.desktop %{_datadir}/metainfo/crystal-facet-uml.metainfo.xml %{_mandir}/man1/crystal-facet-uml.1%{?ext_man} %changelog crystal-facet-uml-1.34.1/build/rpm/make.sh000077500000000000000000000011111415120503000202660ustar00rootroot00000000000000#!/bin/sh . ../../main/include/meta/meta_version.inl VERSIONSTR=${META_VERSION_STR} echo "prepare sources" test -e SOURCES && rm -fr SOURCES mkdir SOURCES cd ../.. git archive --format tar.gz --prefix=crystal-facet-uml-$VERSIONSTR/ --output=build/rpm/SOURCES/crystal-facet-uml_$VERSIONSTR.orig.tar.gz master cd build/rpm echo "prepare signatures" echo "%_signature gpg %_gpg_path /home/andi/.gnupg %_gpg_name Andreas Warnke %_gpgbin /usr/bin/gpg" > ~/.rpmmacros echo "do build" test -e BUILD && rm -fr BUILD rpmbuild --define "_topdir `pwd`" -bb SPECS/crystal-facet-uml.spec --sign crystal-facet-uml-1.34.1/build/rpm/readme.markdown000066400000000000000000000013671415120503000220300ustar00rootroot00000000000000 Release crystal-facet-uml ============= This section is for developers. It describes packaging and releasing a version of crystal-facet-uml. Pack ----------- > # commit all changes before packing ! > # build and test for opensuse > echo "for the oben suse build service, copy the source package and the spec file to a build directory." > echo "create a crystal-facet-uml.changes file there" > echo "run the osc (openSUSE build service command-line tool):" > osc help signkey > osc build --clean --local-package openSUSE_Tumbleweed > sudo zypper install /var/tmp/.../crystal-facet-uml-$VERSIONSTR-1.x86_64.rpm > echo "Note: the open build server seems to sign the packages, no need to do this locally" crystal-facet-uml-1.34.1/build/source_code_doc/000077500000000000000000000000001415120503000213415ustar00rootroot00000000000000crystal-facet-uml-1.34.1/build/source_code_doc/Doxyfile000066400000000000000000003076601415120503000230630ustar00rootroot00000000000000# 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 = crystal-facet-uml # 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 = set from external script, empty otherwise # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify 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 = doc # 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 = # 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 = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a # new page for each member. If set to NO, the documentation of a member will be # part of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 8 # 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 = YES # 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 = YES # 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 = YES # 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 = NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the # todo list. This list is created by putting \todo commands in the # documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the # test list. This list is created by putting \test commands in the # documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \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 = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO doxygen will only warn about wrong or incomplete parameter # documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = YES # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. # Note: If this tag is empty the current directory is searched. INPUT = ../../gui \ ../../tslog \ ../../trace \ ../../main \ ../../ctrl \ ../../data \ ../../utf8stringbuf \ ../../pencil \ ../../io \ ../../test \ ../../universal \ ./source_code_doc.txt \ ../../architecture/doc/programming_guidelines.txt # 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 = # 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). # also used for verbinclude 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 = ../../user_doc/doc ../../gui/source # 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: # # # # where is the value of the INPUT_FILTER tag, and 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 = YES # 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 = YES # 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 = NO # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is 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 = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the 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 + S # (what the is depends on the OS and browser, but it is typically # , /

crystal-facet-uml creates diagrams to document system and software architecture Apache-2.0 https://andreaswarnke.de/crystal-facet-uml/metainfo/crystal_facet_uml_80x80.png

As software architect, you create a set of diagrams describing use-cases, requirements, structural views, behavioral and deployment views.

crystal-facet-uml keeps element names and element hierarchies consistent. It exports diagrams in svg, pdf, ps and png formats to be used in text processing systems like DocBook, html, LaTeX. crystal-facet-uml exports the model to xmi format.

Development Documentation https://andreaswarnke.de/crystal-facet-uml/html/index.html https://github.com/awarnke/crystal-facet-uml/issues crystal-facet-uml.desktop https://andreaswarnke.de/crystal-facet-uml/metainfo/screenshot_1.png Andreas Warnke cfu@andreaswarnke.de crystal-facet-uml-1.34.1/installation_win/000077500000000000000000000000001415120503000205015ustar00rootroot00000000000000crystal-facet-uml-1.34.1/installation_win/crystal-facet-uml.bat000066400000000000000000000000471415120503000245260ustar00rootroot00000000000000@bin\crystal-facet-uml.exe %1 %2 %3 %4 crystal-facet-uml-1.34.1/installation_win/crystal-facet-uml_readme.txt000066400000000000000000000020251415120503000261120ustar00rootroot00000000000000 start crystal-facet-uml by a doubleclick on crystal-facet-uml.bat This archive contains - gtk, glib, gdk-pixbuf, pixman, cairo, pango, atk (Gnu License) as provided in gtk+-bundle_3.6.4-20130513_win32.zip by http://www.tarnyko.net/dl/gtk.htm - gtk and gdk (LGPL-2): https://gitlab.gnome.org/GNOME/gtk - glib and gio and gmodule and gobject (LGPL-2.1): https://gitlab.gnome.org/GNOME/glib - pango (LGPL-2) https://gitlab.gnome.org/GNOME/pango - gdk-pixbuf (LGPL-2.1) https://gitlab.gnome.org/GNOME/gdk-pixbuf - atk (LGPL-2) https://gitlab.gnome.org/GNOME/atk - cairo and pixman (LGPL-2.1) https://www.cairographics.org - fontconfig (MIT-like license) https://gitlab.freedesktop.org/fontconfig/fontconfig - freetype (FTL, BSD-style) https://www.freetype.org/ -libgail-util (LGPL-2) https://developer.gnome.org/gail-libgail-util/ - jasper (JASPER, similar to MIT) - libcroro (LGPL-2) https://github.com/GNOME/libcroco - lzma (Public Domain) http://tukaani.org/xz/ - crystal-facet-uml (Apache 2.0 License) - including sqlite3 (Public Domain) crystal-facet-uml-1.34.1/io/000077500000000000000000000000001415120503000155325ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/include/000077500000000000000000000000001415120503000171555ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/include/image/000077500000000000000000000000001415120503000202375ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/include/image/image_format_writer.h000066400000000000000000000075231415120503000244450ustar00rootroot00000000000000/* File: image_format_writer.h; Copyright and License: see below */ #ifndef IMAGE_FORMAT_WRITER_H #define IMAGE_FORMAT_WRITER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Exports a single diagram to a single file */ #include "io_file_format.h" #include "pencil_diagram_maker.h" #include "set/data_visible_set.h" #include "set/data_stat.h" #include "util/geometry/geometry_rectangle.h" #include /*! * \brief attributes of the diagram image file exporter */ struct image_format_writer_struct { data_database_reader_t *db_reader; /* !< pointer to external database reader */ data_visible_set_t *input_data; /*!< pointer to an external buffer for private use as data cache */ geometry_rectangle_t bounds; /*!< bounding box of the exported images */ pencil_diagram_maker_t painter; /*!< own instance of a diagram painter */ }; typedef struct image_format_writer_struct image_format_writer_t; /*! * \brief initializes the diagram image file exporter * * \param this_ pointer to own object attributes * \param db_reader pointer to a database reader object * \param input_data pointer to an external buffer for private use as data cache */ void image_format_writer_init( image_format_writer_t *this_, data_database_reader_t *db_reader, data_visible_set_t *input_data ); /*! * \brief destroys the diagram image file exporter * * \param this_ pointer to own object attributes */ void image_format_writer_destroy( image_format_writer_t *this_ ); /*! * \brief creates one cairo surface to render a diagram into a file * \param this_ pointer to own object attributes * \param diagram_id id of the diagram which to process for export * \param export_type image file format * \param target_filename path name of the file to store the cairo surface * \param io_render_stat pointer to already initialized statistics object where rendering statistics are added * \return 0 in case of success, -1 otherwise */ int image_format_writer_render_diagram_to_file( image_format_writer_t *this_, data_id_t diagram_id, io_file_format_t export_type, const char* target_filename, data_stat_t *io_render_stat ); /*! * \brief creates one cairo surface to render a diagram into a file * \param this_ pointer to own object attributes * \param export_type image file format * \param target_filename path name of the file to store the cairo surface * \param io_render_stat pointer to already initialized statistics object where rendering statistics are added * \return 0 in case of success, -1 otherwise */ int image_format_writer_private_render_surface_to_file( image_format_writer_t *this_, io_file_format_t export_type, const char* target_filename, data_stat_t *io_render_stat ); #endif /* IMAGE_FORMAT_WRITER_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/io_element_writer.h000066400000000000000000000401531415120503000230450ustar00rootroot00000000000000/* File: io_element_writer.h; Copyright and License: see below */ #ifndef IO_ELEMENT_WRITER_H #define IO_ELEMENT_WRITER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines a pair of a) a pointer to a concrete instance of an interface * and b) a pointer to objectdata that implements the interface. */ #include "io_element_writer_if.h" #include "data_classifier.h" #include "data_classifier_type.h" #include "data_feature.h" #include "data_relationship.h" #include "data_relationship_type.h" #include "data_diagram.h" #include "data_diagram_type.h" #include "data_diagramelement.h" /*! * \brief object (vmt+data) of a io_element_writer_t. * */ struct io_element_writer_struct { const io_element_writer_if_t* interface; /*!< set of interface functions to write to a stream, kind of VMT */ io_element_writer_impl_t* objectdata; /*!< object that implements writing to a stream, used in interface functions as this_ parameter */ }; typedef struct io_element_writer_struct io_element_writer_t; /*! * \brief initializes the io_element_writer_t * * Note: This function shall be called only by objects implementing this interface. * * \param this_ pointer to own object attributes * \param interface set of interface functions to write to a stream * \param objectdata object that implements writing to a stream */ static inline void io_element_writer_private_init( io_element_writer_t *this_, const io_element_writer_if_t *interface, io_element_writer_impl_t* objectdata ); /*! * \brief destroys the io_element_writer_t. * * Note: This function shall be called only by objects implementing this interface. * * \param this_ pointer to own object attributes * \return returns 0 if success, -1 in case of error */ static inline int io_element_writer_private_destroy( io_element_writer_t *this_ ); /*! * \brief gets the set of interface functions * * \param this_ pointer to own object attributes * \return the set of interface functions */ static inline const io_element_writer_if_t* io_element_writer_get_interface( io_element_writer_t *this_ ); /*! * \brief gets the object that implements writing to a stream * * \param this_ pointer to own object attributes * \return the object data that implements the interface */ static inline io_element_writer_impl_t* io_element_writer_get_objectdata( io_element_writer_t *this_ ); /*! * \brief writes the header of the document * * \param this_ pointer to own object attributes * \param document_title title of the document * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_write_header( io_element_writer_t *this_, const char *document_title ); /*! * \brief writes the start of the main section * * This starts a section that contains the main part of the document * * \param this_ pointer to own object attributes * \param document_title title of the document * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_start_main( io_element_writer_t *this_, const char *document_title ); /*! * \brief checks if a hosting parent classifier may nest a child classifier * * \param this_ pointer to own object attributes * \param host_type data_classifier_type_t of the hosting parent of which the nesting-ability shall be determined * \param child_type data_classifier_type_t of the nested child of which the nesting-ability shall be determined * \return true if nesting is allowed */ static inline bool io_element_writer_can_classifier_nest_classifier( io_element_writer_t *this_, data_classifier_type_t host_type, data_classifier_type_t child_type ); /*! * \brief checks if a hosting parent classifier may nest relationships * * \param this_ pointer to own object attributes * \param host_type data_classifier_type_t of the hosting parent of which the nesting-ability shall be determined * \param child_type data_relationship_type_t of the nested child of which the nesting-ability shall be determined * \return true if nesting or any relationship is allowed */ static inline bool io_element_writer_can_classifier_nest_relationship( io_element_writer_t *this_, data_classifier_type_t host_type, data_relationship_type_t child_type ); /*! * \brief writes a classifier start-element * * This starts a division that contains a classifier and a list of features and relationships * * \param this_ pointer to own object attributes * \param host_type type of the hosting parent classifier, needed for xmi export, DATA_CLASSIFIER_TYPE_VOID if toplevel * \param classifier_ptr pointer to classifier that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_start_classifier( io_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ); /*! * \brief writes contents of a classifier * * \param this_ pointer to own object attributes * \param host_type type of the hosting parent classifier, needed for xmi export, DATA_CLASSIFIER_TYPE_VOID if toplevel * \param classifier_ptr pointer to classifier that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_assemble_classifier( io_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ); /*! * \brief writes a classifier end-element * * This ends a division that contains a classifier and a list of features and relationships * * \param this_ pointer to own object attributes * \param host_type type of the hosting parent classifier, needed for xmi export, DATA_CLASSIFIER_TYPE_VOID if toplevel * \param classifier_ptr pointer to classifier that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_end_classifier( io_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ); /*! * \brief writes a feature start-element * * \param this_ pointer to own object attributes * \param parent_type type of the owning parent classifier * \param feature_ptr pointer to feature that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_start_feature( io_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ); /*! * \brief writes constents of a a feature * * \param this_ pointer to own object attributes * \param parent_type type of the owning parent classifier * \param feature_ptr pointer to feature that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_assemble_feature( io_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ); /*! * \brief writes a feature end-element * * \param this_ pointer to own object attributes * \param parent_type type of the owning parent classifier * \param feature_ptr pointer to feature that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_end_feature( io_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ); /*! * \brief starts a relationship * * \param this_ pointer to own object attributes * \param host_type type of the hosting parent classifier, needed for xmi export, DATA_CLASSIFIER_TYPE_VOID if toplevel * \param relation_ptr pointer to relationship that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_start_relationship( io_element_writer_t *this_, data_classifier_type_t host_type, const data_relationship_t *relation_ptr ); /*! * \brief writes the contents of a relationship * * \param this_ pointer to own object attributes * \param host the hosting parent classifier, needed for xmi export; is NULL on top-level of document * \param relation_ptr pointer to relationship that shall be written, not NULL * \param from_c the classifier at source end * \param from_f the feature at source end; NULL or !is_valid() if no feature specified * \param to_c the classifier at target end * \param to_f the feature at target end; NULL or !is_valid() if no feature specified * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_assemble_relationship( io_element_writer_t *this_, const data_classifier_t *host, const data_relationship_t *relation_ptr, const data_classifier_t *from_c, const data_feature_t *from_f, const data_classifier_t *to_c, const data_feature_t *to_f ); /*! * \brief ends a relationship * * \param this_ pointer to own object attributes * \param host_type type of the hosting parent classifier, needed for xmi export, DATA_CLASSIFIER_TYPE_VOID if toplevel * \param relation_ptr pointer to relationship that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_end_relationship( io_element_writer_t *this_, data_classifier_type_t host_type, const data_relationship_t *relation_ptr ); /*! * \brief writes a diagram start * * This starts a section that contains a diagram and a list of diagramelements (classifier-occurrences) * * \param this_ pointer to own object attributes * \param diag_ptr pointer to diagram that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_start_diagram( io_element_writer_t *this_, const data_diagram_t *diag_ptr ); /*! * \brief writes a diagram of the document * * \param this_ pointer to own object attributes * \param parent pointer to parent diagram or NULL in case of root * \param diag_ptr pointer to diagram that shall be written * \param diagram_file_base_name filename of the diagram without extension * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_assemble_diagram( io_element_writer_t *this_, const data_diagram_t *parent, const data_diagram_t *diag_ptr, const char *diagram_file_base_name ); /*! * \brief ends a diagram * * This ends a section that contains a diagram and a list of diagramelements (classifier-occurrences) * * \param this_ pointer to own object attributes * \param diag_ptr pointer to diagram that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_end_diagram( io_element_writer_t *this_, const data_diagram_t *diag_ptr ); /*! * \brief writes a diagramelement start-element * * \param this_ pointer to own object attributes * \param parent the hosting parent diagram * \param diagramelement_ptr pointer to diagramelement that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_start_diagramelement( io_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr ); /*! * \brief writes constents of a a diagramelement * * \param this_ pointer to own object attributes * \param parent the hosting parent diagram * \param diagramelement_ptr pointer to diagramelement that shall be written, not NULL * \param occurrence the occurring classifier * \param feat_occur the focused feature of the occurring classifier, NULL or !is_valid() if DATA_ROW_ID_VOID * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_assemble_diagramelement( io_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr, const data_classifier_t *occurrence, const data_feature_t *feat_occur ); /*! * \brief writes a diagramelement end-element * * \param this_ pointer to own object attributes * \param parent the hosting parent diagram * \param diagramelement_ptr pointer to diagramelement that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_end_diagramelement( io_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr ); /*! * \brief writes the ending of the main section * * This ends a section that contains the main part of the document * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_end_main( io_element_writer_t *this_ ); /*! * \brief writes the footer of the document * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ static inline int io_element_writer_write_footer( io_element_writer_t *this_ ); #include "io_element_writer.inl" #endif /* IO_ELEMENT_WRITER_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/io_element_writer.inl000066400000000000000000000323451415120503000234040ustar00rootroot00000000000000/* File: io_element_writer.inl; Copyright and License: see below */ #include static inline void io_element_writer_private_init( io_element_writer_t *this_, const io_element_writer_if_t *interface, io_element_writer_impl_t* objectdata ) { assert( interface != NULL ); assert( objectdata != NULL ); (*this_).interface = interface; (*this_).objectdata = objectdata; } static inline int io_element_writer_private_destroy( io_element_writer_t *this_ ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); /*int result = (*( (*( (*this_).interface )).destroy )) ( (*this_).objectdata );*/ (*this_).interface = NULL; (*this_).objectdata = NULL; /*return result;*/ return 0; } static inline const io_element_writer_if_t* io_element_writer_get_interface ( io_element_writer_t *this_ ) { assert( (*this_).interface != NULL ); return (*this_).interface; } static inline io_element_writer_impl_t* io_element_writer_get_objectdata ( io_element_writer_t *this_ ) { assert( (*this_).objectdata != NULL ); return (*this_).objectdata; } static inline int io_element_writer_write_header( io_element_writer_t *this_, const char *document_title ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).write_header != NULL ); return (*( (*((*this_).interface)).write_header )) ( (*this_).objectdata, document_title ); } static inline int io_element_writer_start_main( io_element_writer_t *this_, const char *document_title ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).start_main != NULL ); return (*( (*((*this_).interface)).start_main )) ( (*this_).objectdata, document_title ); } static inline bool io_element_writer_can_classifier_nest_classifier( io_element_writer_t *this_, data_classifier_type_t host_type, data_classifier_type_t child_type ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).can_classifier_nest_classifier != NULL ); return (*( (*((*this_).interface)).can_classifier_nest_classifier )) ( (*this_).objectdata, host_type, child_type ); } static inline bool io_element_writer_can_classifier_nest_relationship( io_element_writer_t *this_, data_classifier_type_t host_type, data_relationship_type_t child_type ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).can_classifier_nest_relationship != NULL ); return (*( (*((*this_).interface)).can_classifier_nest_relationship )) ( (*this_).objectdata, host_type, child_type ); } static inline int io_element_writer_start_classifier( io_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).start_classifier != NULL ); return (*( (*((*this_).interface)).start_classifier )) ( (*this_).objectdata, host_type, classifier_ptr ); } static inline int io_element_writer_assemble_classifier( io_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).assemble_classifier != NULL ); return (*( (*((*this_).interface)).assemble_classifier )) ( (*this_).objectdata, host_type, classifier_ptr ); } static inline int io_element_writer_end_classifier( io_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).end_classifier != NULL ); return (*( (*((*this_).interface)).end_classifier )) ( (*this_).objectdata, host_type, classifier_ptr ); } static inline int io_element_writer_start_feature( io_element_writer_t *this_, data_classifier_type_t host_type, const data_feature_t *feature_ptr ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).start_feature != NULL ); return (*( (*((*this_).interface)).start_feature )) ( (*this_).objectdata, host_type, feature_ptr ); } static inline int io_element_writer_assemble_feature( io_element_writer_t *this_, data_classifier_type_t host_type, const data_feature_t *feature_ptr ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).assemble_feature != NULL ); return (*( (*((*this_).interface)).assemble_feature )) ( (*this_).objectdata, host_type, feature_ptr ); } static inline int io_element_writer_end_feature( io_element_writer_t *this_, data_classifier_type_t host_type, const data_feature_t *feature_ptr ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).end_feature != NULL ); return (*( (*((*this_).interface)).end_feature )) ( (*this_).objectdata, host_type, feature_ptr ); } static inline int io_element_writer_start_relationship( io_element_writer_t *this_, data_classifier_type_t host_type, const data_relationship_t *relation_ptr ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).start_relationship != NULL ); return (*( (*((*this_).interface)).start_relationship )) ( (*this_).objectdata, host_type, relation_ptr ); } static inline int io_element_writer_assemble_relationship( io_element_writer_t *this_, const data_classifier_t *host, const data_relationship_t *relation_ptr, const data_classifier_t *from_c, const data_feature_t *from_f, const data_classifier_t *to_c, const data_feature_t *to_f ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).assemble_relationship != NULL ); return (*( (*((*this_).interface)).assemble_relationship )) ( (*this_).objectdata, host, relation_ptr, from_c, from_f, to_c, to_f ); } static inline int io_element_writer_end_relationship( io_element_writer_t *this_, data_classifier_type_t host_type, const data_relationship_t *relation_ptr ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).end_relationship != NULL ); return (*( (*((*this_).interface)).end_relationship )) ( (*this_).objectdata, host_type, relation_ptr ); } static inline int io_element_writer_start_diagram( io_element_writer_t *this_, const data_diagram_t *diag_ptr ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).start_diagram != NULL ); return (*( (*((*this_).interface)).start_diagram )) ( (*this_).objectdata, diag_ptr ); } static inline int io_element_writer_assemble_diagram( io_element_writer_t *this_, const data_diagram_t *parent, const data_diagram_t *diag_ptr, const char *diagram_file_base_name ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).assemble_diagram != NULL ); return (*( (*((*this_).interface)).assemble_diagram )) ( (*this_).objectdata, parent, diag_ptr, diagram_file_base_name ); } static inline int io_element_writer_end_diagram( io_element_writer_t *this_, const data_diagram_t *diag_ptr ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).end_diagram != NULL ); return (*( (*((*this_).interface)).end_diagram )) ( (*this_).objectdata, diag_ptr ); } static inline int io_element_writer_start_diagramelement( io_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).start_diagramelement != NULL ); return (*( (*((*this_).interface)).start_diagramelement )) ( (*this_).objectdata, parent, diagramelement_ptr ); } static inline int io_element_writer_assemble_diagramelement( io_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr, const data_classifier_t *occurrence, const data_feature_t *feat_occur ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).assemble_diagramelement != NULL ); return (*( (*((*this_).interface)).assemble_diagramelement )) ( (*this_).objectdata, parent, diagramelement_ptr, occurrence, feat_occur ); } static inline int io_element_writer_end_diagramelement( io_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).end_diagramelement != NULL ); return (*( (*((*this_).interface)).end_diagramelement )) ( (*this_).objectdata, parent, diagramelement_ptr ); } static inline int io_element_writer_end_main( io_element_writer_t *this_ ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).end_main != NULL ); return (*( (*((*this_).interface)).end_main )) ( (*this_).objectdata ); } static inline int io_element_writer_write_footer( io_element_writer_t *this_ ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).write_footer != NULL ); return (*( (*((*this_).interface)).write_footer )) ( (*this_).objectdata ); } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/io_element_writer_if.h000066400000000000000000000040141415120503000235170ustar00rootroot00000000000000/* File: io_element_writer_if.h; Copyright and License: see below */ #ifndef IO_ELEMENT_WRITER_IF_H #define IO_ELEMENT_WRITER_IF_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines a set of function pointers that allow to implement an output stream. * * This is an interface only - to be used in a pipes-and-filters architecture * where pipes and filters do not know their predecessor or successor. * * A user of this interface needs a) a pointer to a concrete instance of this interface * and b) a pointer to an object that implements the interface (this_). */ #include "data_classifier.h" #include "data_classifier_type.h" #include "data_feature.h" #include "data_relationship.h" #include "data_relationship_type.h" #include "data_diagram.h" #include "data_diagram_type.h" #include "data_diagramelement.h" #include #include #include /* io_element_writer_impl_t allows to distinguisth general void pointers from pointers to implementation objects */ typedef void io_element_writer_impl_t; /*! * \brief function pointers of a io_element_writer_if_t. * * This is similar to a vmt and used here to access an implementation of this interface * * Lifecycle functions like init and destroy are not part of the interface. */ struct io_element_writer_if_struct { #include "io_element_writer_if.inl" }; typedef struct io_element_writer_if_struct io_element_writer_if_t; #endif /* IO_ELEMENT_WRITER_IF_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/io_element_writer_if.inl000066400000000000000000000132441415120503000240570ustar00rootroot00000000000000/* File: io_element_writer_if.h; Copyright and License: see below */ int (*write_header)( io_element_writer_impl_t *this_, const char *document_title ); /*!< \see io_element_writer_t */ int (*start_main)( io_element_writer_impl_t *this_, const char *document_title ); /*!< \see io_element_writer_t */ bool (*can_classifier_nest_classifier)( io_element_writer_impl_t *this_, data_classifier_type_t host_type, data_classifier_type_t child_type ); /*!< \see io_element_writer_t */ bool (*can_classifier_nest_relationship)( io_element_writer_impl_t *this_, data_classifier_type_t host_type, data_relationship_type_t child_type ); /*!< \see io_element_writer_t */ int (*start_classifier)( io_element_writer_impl_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ); /*!< \see io_element_writer_t */ int (*assemble_classifier)( io_element_writer_impl_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ); /*!< \see io_element_writer_t */ int (*end_classifier)( io_element_writer_impl_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ); /*!< \see io_element_writer_t */ int (*start_feature)( io_element_writer_impl_t *this_, data_classifier_type_t host_type, const data_feature_t *feature_ptr ); /*!< \see io_element_writer_t */ int (*assemble_feature)( io_element_writer_impl_t *this_, data_classifier_type_t host_type, const data_feature_t *feature_ptr ); /*!< \see io_element_writer_t */ int (*end_feature)( io_element_writer_impl_t *this_, data_classifier_type_t host_type, const data_feature_t *feature_ptr ); /*!< \see io_element_writer_t */ int (*start_relationship)( io_element_writer_impl_t *this_, data_classifier_type_t host_type, const data_relationship_t *relation_ptr ); /*!< \see io_element_writer_t */ int (*assemble_relationship)( io_element_writer_impl_t *this_, const data_classifier_t *host, const data_relationship_t *relation_ptr, const data_classifier_t *from_c, const data_feature_t *from_f, const data_classifier_t *to_c, const data_feature_t *to_f ); /*!< \see io_element_writer_t */ int (*end_relationship)( io_element_writer_impl_t *this_, data_classifier_type_t host_type, const data_relationship_t *relation_ptr ); /*!< \see io_element_writer_t */ int (*start_diagram)( io_element_writer_impl_t *this_, const data_diagram_t *diag_ptr ); /*!< \see io_element_writer_t */ int (*assemble_diagram)( io_element_writer_impl_t *this_, const data_diagram_t *parent, const data_diagram_t *diag_ptr, const char *diagram_file_base_name ); /*!< \see io_element_writer_t */ int (*end_diagram)( io_element_writer_impl_t *this_, const data_diagram_t *diag_ptr ); /*!< \see io_element_writer_t */ int (*start_diagramelement)( io_element_writer_impl_t *this_, const data_diagram_t *host, const data_diagramelement_t *diagramelement_ptr ); /*!< \see io_element_writer_t */ int (*assemble_diagramelement)( io_element_writer_impl_t *this_, const data_diagram_t *host, const data_diagramelement_t *diagramelement_ptr, const data_classifier_t *occurrence, const data_feature_t *feat_occur ); /*!< \see io_element_writer_t */ int (*end_diagramelement)( io_element_writer_impl_t *this_, const data_diagram_t *host, const data_diagramelement_t *diagramelement_ptr ); /*!< \see io_element_writer_t */ int (*end_main)( io_element_writer_impl_t *this_ ); /*!< \see io_element_writer_t */ int (*write_footer)( io_element_writer_impl_t *this_ ); /*!< \see io_element_writer_t */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/io_export_diagram_traversal.h000066400000000000000000000151121415120503000251050ustar00rootroot00000000000000/* File: io_export_diagram_traversal.h; Copyright and License: see below */ #ifndef IO_EXPORT_DIAGRAM_TRAVERSAL_H #define IO_EXPORT_DIAGRAM_TRAVERSAL_H /* public file for the doxygen documentation: */ /*! * \file * \brief Traverses the model-part shown in a diagram and writes the elements to an format writer * * Source: db_reader(data_database_reader_t); * Task: traverse the source model-part; * Sink: xhtml_element_writer_t */ #include "io_element_writer.h" #include "set/data_visible_set.h" #include "set/data_node_set.h" #include "set/data_stat.h" #include "storage/data_database_reader.h" #include "data_table.h" #include "data_rules.h" #include /*! * \brief attributes of the description writer */ struct io_export_diagram_traversal_struct { data_database_reader_t *db_reader; /* !< pointer to external database reader */ data_visible_set_t *input_data; /*!< pointer to an external buffer for private use as data cache */ data_rules_t filter_rules; /*!< own instance of uml and sysml consistency rules */ data_stat_t *export_stat; /*!< pointer to external statistics object where export statistics are collected */ io_element_writer_t *element_writer; /*!< pointer to external io_element_writer_t which is the output sink */ data_diagram_t temp_parent_diag; /*!< own instance of a data cache for the parent diagram */ }; typedef struct io_export_diagram_traversal_struct io_export_diagram_traversal_t; /*! * \brief initializes the io_export_diagram_traversal_t * * \param this_ pointer to own object attributes * \param db_reader pointer to a database reader object * \param input_data pointer to an external buffer for private use as data cache * \param io_export_stat pointer to statistics object where export statistics are collected. * Errors and warnings during traversal are counted. Success shall be counted by io_element_writer_t. * Statistics are only added, *io_stat shall be initialized by caller. * \param out_element_writer pointer to an external io_element_writer_t which is the output sink */ void io_export_diagram_traversal_init( io_export_diagram_traversal_t *this_, data_database_reader_t *db_reader, data_visible_set_t *input_data, data_stat_t *io_export_stat, io_element_writer_t *out_element_writer ); /*! * \brief destroys the io_export_diagram_traversal_t * * \param this_ pointer to own object attributes */ void io_export_diagram_traversal_destroy( io_export_diagram_traversal_t *this_ ); /*! * \brief prints names and descriptions of the diagram and contained classifiers to the output stream * * Note: When finished, the caller may recurse to chilren diagrams. * Finally, io_export_diagram_traversal_end_diagram has to be called. * * \param this_ pointer to own object attributes * \param diagram_id id of the diagram which to process for export * \param diagram_file_base_name filename of the diagram without extension * \return -1 in case of error, 0 in case of success */ int io_export_diagram_traversal_begin_and_walk_diagram ( io_export_diagram_traversal_t *this_, data_id_t diagram_id, const char *diagram_file_base_name ); /*! * \brief prints the end of a diagram section * * \param this_ pointer to own object attributes * \param diagram_id id of the diagram which to process for export * \return -1 in case of error, 0 in case of success */ int io_export_diagram_traversal_end_diagram ( io_export_diagram_traversal_t *this_, data_id_t diagram_id ); /*! * \brief prints names and descriptions of the classifiers to the output stream * * \param this_ pointer to own object attributes * \param diagram_data diagram data of which the classifiers are written, not NULL * \return -1 in case of error, 0 in case of success */ int io_export_diagram_traversal_private_iterate_diagram_classifiers ( io_export_diagram_traversal_t *this_, const data_visible_set_t *diagram_data ); /*! * \brief prints names and descriptions of the classifier to the output stream * * \param this_ pointer to own object attributes * \param diagram_data diagram data that contains the classifier of which the features are written, not NULL * \param classifier_id id of the classifier of which the features are written * \return -1 in case of error, 0 in case of success */ int io_export_diagram_traversal_private_iterate_classifier_features ( io_export_diagram_traversal_t *this_, const data_visible_set_t *diagram_data, data_id_t classifier_id ); /*! * \brief prints names and descriptions of the relationships to the output stream * * \param this_ pointer to own object attributes * \param diagram_data diagram data that contains the from-classifier of which the relationships are written, not NULL * \param from_classifier_id id of the classifier of which the relationships are written * \return -1 in case of error, 0 in case of success */ int io_export_diagram_traversal_private_iterate_classifier_relationships ( io_export_diagram_traversal_t *this_, const data_visible_set_t *diagram_data, data_id_t from_classifier_id ); #endif /* IO_EXPORT_DIAGRAM_TRAVERSAL_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/io_export_flat_traversal.h000066400000000000000000000153721415120503000244370ustar00rootroot00000000000000/* File: io_export_flat_traversal.h; Copyright and License: see below */ #ifndef IO_EXPORT_FLAT_TRAVERSAL_H #define IO_EXPORT_FLAT_TRAVERSAL_H /* public file for the doxygen documentation: */ /*! * \file * \brief Traverses the model by iterating over a flat list of all classifiers * and writes the elements to an format writer. * * Source: db_reader(data_database_reader_t); * Task: traverse the source model; * Sink: io_element_writer_t */ #include "io_export_interaction_traversal.h" #include "io_element_writer.h" #include "set/data_node_set.h" #include "set/data_stat.h" #include "storage/data_database_reader.h" #include "data_table.h" #include "universal_array_list.h" #include /*! * \brief attributes of the description writer */ struct io_export_flat_traversal_struct { data_database_reader_t *db_reader; /* !< pointer to external database reader */ data_stat_t *export_stat; /*!< pointer to external statistics object where export statistics are collected */ io_element_writer_t *element_writer; /*!< pointer to external io_element_writer_t which is the output sink */ data_classifier_t temp_classifier; /*!< own buffer for private use as data cache */ data_node_set_t temp_node_data; /*!< own buffer for private use as data cache */ data_classifier_t temp_from_classifier; /*!< own buffer for private use as data cache in private_iterate_relationships*/ data_feature_t temp_from_feature; /*!< own buffer for private use as data cache in private_iterate_relationships*/ data_classifier_t temp_to_classifier; /*!< own buffer for private use as data cache in private_iterate_relationships*/ data_feature_t temp_to_feature; /*!< own buffer for private use as data cache in private_iterate_relationships*/ }; typedef struct io_export_flat_traversal_struct io_export_flat_traversal_t; /*! * \brief initializes the io_export_flat_traversal_t * * \param this_ pointer to own object attributes * \param db_reader pointer to a database reader object * \param io_export_stat pointer to statistics object where export statistics are collected. * Errors and warnings during traversal are counted. Success shall be counted by io_element_writer_t. * Statistics are only added, *io_stat shall be initialized by caller. * \param out_element_writer pointer to an external io_element_writer_t which is the output sink */ void io_export_flat_traversal_init( io_export_flat_traversal_t *this_, data_database_reader_t *db_reader, data_stat_t *io_export_stat, io_element_writer_t *out_element_writer ); /*! * \brief destroys the io_export_flat_traversal_t * * \param this_ pointer to own object attributes */ void io_export_flat_traversal_destroy( io_export_flat_traversal_t *this_ ); /*! * \brief prints all classifiers as flat list to the output stream * * \param this_ pointer to own object attributes * \return -1 in case of error, 0 in case of success */ int io_export_flat_traversal_iterate_classifiers ( io_export_flat_traversal_t *this_ ); /*! * \brief writes the classifier and feature and writes its outgoing relationships * * \param this_ pointer to own object attributes * \param classifier pointer to the classifier to process, most likely this is &((*this_).temp_classifier) * \return -1 in case of error, * 0 in case of success. */ int io_export_flat_traversal_private_traverse_classifier ( io_export_flat_traversal_t *this_, const data_classifier_t *classifier ); /*! * \brief iterates over features of a classifier. * * \param this_ pointer to own object attributes * \param node_data node data of the classifier of which the features are written, not NULL * \return -1 in case of error, 0 in case of success. */ int io_export_flat_traversal_private_iterate_features ( io_export_flat_traversal_t *this_, const data_node_set_t *node_data ); /*! * \brief iterates over relationships of a classifier. * * \param this_ pointer to own object attributes * \param node_data node data of the from-classifier of which the relationships are written, not NULL * \return -1 in case of error, 0 in case of success. */ int io_export_flat_traversal_private_iterate_relationships ( io_export_flat_traversal_t *this_, const data_node_set_t *node_data ); /*! * \brief gets the the end-objects of a relationship * * \param this_ pointer to own object attributes * \param relation pointer to relationship that shall be analyzed, not NULL * \param node_data the data set of a model-node where to look for already loaded data (otherwise, load from database) * \param out_from_c (a copy of) the classifier at source end * \param out_from_f (a copy of) the feature at source end; !is_valid() if no feature specified * \param out_to_c (a copy of) the classifier at target end * \param out_to_f (a copy of) the feature at target end; !is_valid() if no feature specified * \return DATA_ERROR_NONE in case of success */ data_error_t io_export_flat_traversal_private_get_relationship_ends( io_export_flat_traversal_t *this_, const data_relationship_t *relation, const data_node_set_t *node_data, data_classifier_t *out_from_c, data_feature_t *out_from_f, data_classifier_t *out_to_c, data_feature_t *out_to_f ); #endif /* IO_EXPORT_FLAT_TRAVERSAL_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/io_export_interaction_traversal.h000066400000000000000000000213471415120503000260270ustar00rootroot00000000000000/* File: io_export_interaction_traversal.h; Copyright and License: see below */ #ifndef IO_EXPORT_INTERACTION_TRAVERSAL_H #define IO_EXPORT_INTERACTION_TRAVERSAL_H /* public file for the doxygen documentation: */ /*! * \file * \brief Traverses the model-part shown in an interaction diagram and writes the elements to an xmi_interaction_writer * * Source: db_reader(data_database_reader_t); * Task: traverse the source model-part; * Sink: xmi_interaction_writer */ #include "io_element_writer.h" #include "xmi/xmi_interaction_writer.h" #include "set/data_visible_set.h" #include "set/data_node_set.h" #include "set/data_stat.h" #include "storage/data_database_reader.h" #include "data_table.h" #include "data_rules.h" #include "universal_array_list.h" #include /*! * \brief attributes of the description writer */ struct io_export_interaction_traversal_struct { data_database_reader_t *db_reader; /* !< pointer to external database reader */ data_visible_set_t *input_data; /*!< pointer to an external buffer for private use as data cache */ data_rules_t filter_rules; /*!< own instance of uml and sysml consistency rules */ universal_array_list_t *written_id_set; /*!< pointer to external list of already exported element ids */ data_stat_t *export_stat; /*!< pointer to external statistics object where export statistics are collected */ io_element_writer_t *element_writer; /*!< pointer to external io_element_writer_t which is the regular output sink */ data_classifier_t fake_interaction_classifier; /*!< a fake classifier of type DATA_CLASSIFIER_TYPE_INTERACTION */ data_feature_t fake_lifeline_feature; /*!< a fake feature of type DATA_FEATURE_TYPE_LIFELINE */ }; typedef struct io_export_interaction_traversal_struct io_export_interaction_traversal_t; /*! * \brief initializes the io_export_interaction_traversal_t * * \param this_ pointer to own object attributes * \param db_reader pointer to a database reader object * \param input_data pointer to an external buffer for private use as data cache * \param io_written_id_set pointer to external list of already exported element ids * \param io_export_stat pointer to statistics object where export statistics are collected. * Errors and warnings during traversal are counted. Success shall be counted by io_element_writer_t. * Statistics are only added, *io_stat shall be initialized by caller. * \param out_element_writer pointer to an io_element_writer_t which is the output sink */ void io_export_interaction_traversal_init( io_export_interaction_traversal_t *this_, data_database_reader_t *db_reader, data_visible_set_t *input_data, universal_array_list_t *io_written_id_set, data_stat_t *io_export_stat, io_element_writer_t *out_element_writer ); /*! * \brief destroys the io_export_interaction_traversal_t * * \param this_ pointer to own object attributes */ void io_export_interaction_traversal_destroy( io_export_interaction_traversal_t *this_ ); /*! * \brief iterates all interactions where classifier is involved, exports these interactions * * \param this_ pointer to own object attributes * \param nesting_type type of the nesting parent classifier * \param classifier_id id of the classifier which occurrences to process for export * \return -1 in case of error, 0 in case of success */ int io_export_interaction_traversal_iterate_classifier_occurrences ( io_export_interaction_traversal_t *this_, data_classifier_type_t nesting_type, data_id_t classifier_id ); /*! * \brief prints the end of a diagram section * * \param this_ pointer to own object attributes * \param nesting_type type of the nesting parent classifier * \param diagram_id id of the diagram which to process for export * \return -1 in case of error, 0 in case of success */ int io_export_interaction_traversal_private_walk_diagram ( io_export_interaction_traversal_t *this_, data_classifier_type_t nesting_type, data_id_t diagram_id ); /*! * \brief prints names and descriptions of the classifiers to the output stream * * \param this_ pointer to own object attributes * \param diagram_data diagram data of which the classifiers are written, not NULL * \param fake_interaction fake classifier of type DATA_CLASSIFIER_TYPE_INTERACTION derived from the diagram * \return -1 in case of error, 0 in case of success */ int io_export_interaction_traversal_private_iterate_diagram_classifiers ( io_export_interaction_traversal_t *this_, const data_visible_set_t *diagram_data, const data_classifier_t *fake_interaction ); /*! * \brief prints names and descriptions of the focused feature to the output stream * * \param this_ pointer to own object attributes * \param diagram_data diagram data that contains the classifier of which the features are written, not NULL * \param focused_feature_id id of the focused feature (lifeline) which shall be written * \return -1 in case of error, 0 in case of success */ int io_export_interaction_traversal_private_look_for_focused_feature ( io_export_interaction_traversal_t *this_, const data_visible_set_t *diagram_data, data_id_t focused_feature_id ); /*! * \brief prints names and descriptions of the relationships to the output stream * * \param this_ pointer to own object attributes * \param diagram_data diagram data that contains the from-classifier of which the relationships are written, not NULL * \param from_classifier_id id of the classifier of which the relationships are written * \param focused_feature_id id of the focused feature (lifeline) of which the relationships are written * \param fake_interaction fake classifier of type DATA_CLASSIFIER_TYPE_INTERACTION derived from the diagram * \return -1 in case of error, 0 in case of success */ int io_export_interaction_traversal_private_iterate_feature_relationships ( io_export_interaction_traversal_t *this_, const data_visible_set_t *diagram_data, data_id_t from_classifier_id, data_id_t focused_feature_id, const data_classifier_t *fake_interaction ); /*! * \brief converts the data fields of an interaction diagram to a fake classifier * * \param this_ pointer to own object attributes * \param interaction_diagram diagram data that contains the interaction information * \param[out] out_fake_classifier the classifier to be filled with data from interaction_diagram * \return -1 in case of error, 0 in case of success */ int io_export_interaction_traversal_private_fake_interaction ( io_export_interaction_traversal_t *this_, const data_diagram_t *interaction_diagram, data_classifier_t *out_fake_classifier ); #endif /* IO_EXPORT_INTERACTION_TRAVERSAL_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/io_export_model_traversal.h000066400000000000000000000320151415120503000246020ustar00rootroot00000000000000/* File: io_export_model_traversal.h; Copyright and License: see below */ #ifndef IO_EXPORT_MODEL_TRAVERSAL_H #define IO_EXPORT_MODEL_TRAVERSAL_H /* public file for the doxygen documentation: */ /*! * \file * \brief Traverses the model and writes the elements to an format writer * * Source: db_reader(data_database_reader_t); * Task: traverse the source model; * Sink: io_element_writer_t */ #include "io_export_interaction_traversal.h" #include "io_element_writer.h" #include "set/data_node_set.h" #include "set/data_stat.h" #include "storage/data_database_reader.h" #include "data_table.h" #include "universal_array_list.h" #include /*! * \brief constants for maximum values of io_export_model_traversal_t */ enum io_export_model_traversal_max_enum { IO_EXPORT_MODEL_TRAVERSAL_MAX_TOTAL_ELEMENTS = 32768, /*!< maximum number of total classifiers and relationships to be exported */ IO_EXPORT_MODEL_TRAVERSAL_MAX_TREE_DEPTH = 32, /*!< maximum number of recursive descend into containment children */ }; /*! * \brief attributes of the description writer */ struct io_export_model_traversal_struct { data_database_reader_t *db_reader; /* !< pointer to external database reader */ data_stat_t *export_stat; /*!< pointer to external statistics object where export statistics are collected */ io_element_writer_t *element_writer; /*!< pointer to external io_element_writer_t which is the output sink */ io_export_interaction_traversal_t interaction_helper; /* !< instance of own io_export_interaction_traversal to help with interaction exports */ data_id_t written_id_set_buf[IO_EXPORT_MODEL_TRAVERSAL_MAX_TOTAL_ELEMENTS]; /*!< buffer for list of already exported element ids */ universal_array_list_t written_id_set; /*!< list of already exported element ids (extended when starting to export an element), used for classifiers and relationships and lifelines(which are features) */ data_classifier_t temp_classifier; /*!< own buffer for private use as data cache */ data_classifier_t temp_from_classifier; /*!< own buffer for private use as data cache */ data_feature_t temp_from_feature; /*!< own buffer for private use as data cache */ data_classifier_t temp_to_classifier; /*!< own buffer for private use as data cache */ data_feature_t temp_to_feature; /*!< own buffer for private use as data cache */ data_node_set_t temp_node_data; /*!< own buffer for private use as data cache */ }; typedef struct io_export_model_traversal_struct io_export_model_traversal_t; /*! * \brief initializes the io_export_model_traversal_t * * \param this_ pointer to own object attributes * \param db_reader pointer to a database reader object * \param input_data pointer to an external buffer for private use as data cache by interaction_helper * \param io_export_stat pointer to statistics object where export statistics are collected. * Errors and warnings during traversal are counted. Success shall be counted by io_element_writer_t. * Statistics are only added, *io_stat shall be initialized by caller. * \param out_element_writer pointer to an external io_element_writer_t which is the output sink */ void io_export_model_traversal_init( io_export_model_traversal_t *this_, data_database_reader_t *db_reader, data_visible_set_t *input_data, data_stat_t *io_export_stat, io_element_writer_t *out_element_writer ); /*! * \brief destroys the io_export_model_traversal_t * * \param this_ pointer to own object attributes */ void io_export_model_traversal_destroy( io_export_model_traversal_t *this_ ); /*! * \brief prints all classifiers to the output stream * * \param this_ pointer to own object attributes * \return -1 in case of error, 0 in case of success */ int io_export_model_traversal_walk_model_nodes ( io_export_model_traversal_t *this_ ); /*! * \brief writes the node if it is not a duplicate. writes its relationships if they are not duplicates. * * While traversing, the written_id_set is extended. * Classifiers that are contained in written_id_set or that are beyond max_recursion are not traversed. * * \param this_ pointer to own object attributes * \param host_id the hosting parent classifier, needed for xmi export; DATA_ID_VOID on top-level of document * \param containment_relationship_id id of the containment relationship which caused the processing, DATA_ID_VOID if not applicable * \param classifier_id id of the classifier to process * \param recursion_depth current number of tree depth. * \return -1 in case of error, * 0 in case of success. */ int io_export_model_traversal_private_walk_node ( io_export_model_traversal_t *this_, data_id_t host_id, data_id_t containment_relationship_id, data_id_t classifier_id, unsigned int recursion_depth ); /*! * \brief writes the first half of the node * * \param this_ pointer to own object attributes * \param host_type type of the hosting parent classifier, needed for xmi export * \param node_data the data set of a model-node: a classifier, list of contained features and set of relationships * \return -1 in case of error, * 0 in case of success. */ int io_export_model_traversal_private_begin_node ( io_export_model_traversal_t *this_, data_classifier_type_t host_type, const data_node_set_t *node_data ); /*! * \brief retrieves the relationships of type DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT. * * \param this_ pointer to own object attributes * \param node_data the data set at a model-node: 1 classifier, contained features and set of relationships * \param io_contained_classifiers set of classifiers, contained classifiers are appended. This set shall be initialized when calling this function. * \param io_containment_relations set of relationships, containment relationships are appended. This set shall be initialized when calling this function. * \return -1 in case of error, * 0 in case of success. */ int io_export_model_traversal_private_get_containments ( io_export_model_traversal_t *this_, const data_node_set_t *node_data, data_small_set_t *io_contained_classifiers, data_small_set_t *io_containment_relations ); /*! * \brief recusively descends the containment tree (graph) of a classifier. * * \param this_ pointer to own object attributes * \param host_id the hosting parent classifier, needed for xmi export * \param contained_classifiers set of contained classifiers. * \param containment_relations set of containment relationships. * \param recursion_depth current number of tree depth. Used to actively limit the recursive descend to max IO_EXPORT_MODEL_TRAVERSAL_MAX_TREE_DEPTH. * \return -1 in case of error, * 0 in case of success. * If IO_EXPORT_MODEL_TRAVERSAL_MAX_TREE_DEPTH limits the descent, * or written_id_set prevents duplicate traversal of a classifier, * 0 is returned nonetheless. */ int io_export_model_traversal_private_walk_containments ( io_export_model_traversal_t *this_, data_id_t host_id, const data_small_set_t *contained_classifiers, const data_small_set_t *containment_relations, unsigned int recursion_depth ); /*! * \brief writes the second half of the node * * \param this_ pointer to own object attributes * \param host_type type of the hosting parent classifier, needed for xmi export * \param node_data the data set of a model-node: a classifier, list of contained features and set of relationships * \return -1 in case of error, * 0 in case of success. */ int io_export_model_traversal_private_end_node ( io_export_model_traversal_t *this_, data_classifier_type_t host_type, const data_node_set_t *node_data ); /*! * \brief iterates over features of a classifier. * * \param this_ pointer to own object attributes * \param node_data node data of the classifier of which the features are written, not NULL * \return -1 in case of error, 0 in case of success. */ int io_export_model_traversal_private_iterate_node_features ( io_export_model_traversal_t *this_, const data_node_set_t *node_data ); /*! * \brief iterates over relationships of a classifier. * * \param this_ pointer to own object attributes * \param nested_to_foreign_node true, if nested to a foreign node, e.g. the outer model, * false is nested to node_data. * \param host the hosting parent classifier, needed for xmi export; is NULL on top-level of document * \param node_data node data of the from-classifier of which the relationships are written, not NULL * \return -1 in case of error, 0 in case of success. */ int io_export_model_traversal_private_iterate_node_relationships ( io_export_model_traversal_t *this_, bool nested_to_foreign_node, const data_classifier_t *host, const data_node_set_t *node_data ); /*! * \brief gets the the end-objects of a relationship * * \param this_ pointer to own object attributes * \param relation pointer to relationship that shall be analyzed, not NULL * \param node_data the data set of a model-node where to look for already loaded data (otherwise, load from database) * \param out_from_c (a copy of) the classifier at source end * \param out_from_f (a copy of) the feature at source end; !is_valid() if no feature specified * \param out_to_c (a copy of) the classifier at target end * \param out_to_f (a copy of) the feature at target end; !is_valid() if no feature specified * \return DATA_ERROR_NONE in case of success */ data_error_t io_export_model_traversal_private_get_relationship_ends( io_export_model_traversal_t *this_, const data_relationship_t *relation, const data_node_set_t *node_data, data_classifier_t *out_from_c, data_feature_t *out_from_f, data_classifier_t *out_to_c, data_feature_t *out_to_f ); /*! * \brief checks in which interaction-diagrams the node is used and fakes interaction-model-objects. * * \param this_ pointer to own object attributes * \param nesting_type type of the nesting-parent classifier * \param node_data node data of the classifier of which the interactions are faked, not NULL * \return -1 in case of error, 0 in case of success. */ int io_export_model_traversal_private_fake_interactions_of_node ( io_export_model_traversal_t *this_, data_classifier_type_t nesting_type, const data_node_set_t *node_data ); #endif /* IO_EXPORT_MODEL_TRAVERSAL_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/io_export_set_traversal.h000066400000000000000000000116461415120503000243040ustar00rootroot00000000000000/* File: io_export_set_traversal.h; Copyright and License: see below */ #ifndef IO_EXPORT_SET_TRAVERSAL_H #define IO_EXPORT_SET_TRAVERSAL_H /* public file for the doxygen documentation: */ /*! \file * \brief Serializes a set of objects to the clipboard */ #include "io_element_writer.h" #include "data_feature.h" #include "storage/data_database_reader.h" #include "set/data_stat.h" #include "util/string/utf8stringbuf.h" /*! * \brief constants for maximum values of io_export_set_traversal_t */ enum io_export_set_traversal_max_enum { IO_EXPORT_SET_TRAVERSAL_MAX_FEATURES = 64, /*!< maximum number of features per classifier */ }; /*! * \brief attributes of the export traversal object */ struct io_export_set_traversal_struct { data_database_reader_t *db_reader; /*!< pointer to external data_database_reader */ data_stat_t *export_stat; /*!< pointer to external statistics object where export statistics are collected */ io_element_writer_t *element_writer; /*!< pointer to external io_element_writer_t which is the output sink */ data_feature_t temp_features[IO_EXPORT_SET_TRAVERSAL_MAX_FEATURES]; /*!< temporary memory for feature list */ }; typedef struct io_export_set_traversal_struct io_export_set_traversal_t; /*! * \brief initializes the io_export_set_traversal_t struct * * \param this_ pointer to own object attributes * \param db_reader pointer to a database reader * \param io_export_stat pointer to statistics object where export statistics are collected. * Errors and warnings during traversal are counted. Success shall be counted by io_element_writer_t. * Statistics are only added, *io_stat shall be initialized by caller. * \param out_element_writer pointer to an external io_element_writer_t which is the output sink */ void io_export_set_traversal_init ( io_export_set_traversal_t *this_, data_database_reader_t *db_reader, data_stat_t *io_export_stat, io_element_writer_t *out_element_writer ); /*! * \brief destroys the io_export_set_traversal_t struct * * \param this_ pointer to own object attributes */ void io_export_set_traversal_destroy ( io_export_set_traversal_t *this_ ); /*! * \brief copies a set of objects to a string buffer, can be forwarded e.g. to the clipboard * * features in the set are ignored. Features of classifiers in the set are exported. * * \param this_ pointer to own object attributes * \param set_to_be_exported ids of the objects to be exported * \return 0 in case of success, -1 if output buffer exceeded */ int io_export_set_traversal_export_set( io_export_set_traversal_t *this_, const data_small_set_t *set_to_be_exported ); /*! * \brief fetches required data from the db_reader and exports the object(s) via element_writer * * \param this_ pointer to own object attributes * \param id id of the object to be exported * \return 0 in case of success, -1 if output buffer exceeded */ int io_export_set_traversal_private_export_diagram( io_export_set_traversal_t *this_, data_id_t id ); /*! * \brief fetches required data from the db_reader and exports the object(s) via element_writer * * \param this_ pointer to own object attributes * \param id id of the object to be exported * \return 0 in case of success, -1 if output buffer exceeded */ int io_export_set_traversal_private_export_diagramelement( io_export_set_traversal_t *this_, data_id_t id ); /*! * \brief fetches required data from the db_reader and exports the object(s) via element_writer * * \param this_ pointer to own object attributes * \param id id of the object to be exported * \return 0 in case of success, -1 if output buffer exceeded */ int io_export_set_traversal_private_export_classifier( io_export_set_traversal_t *this_, data_id_t id ); /*! * \brief fetches required data from the db_reader and exports the object(s) via element_writer * * \param this_ pointer to own object attributes * \param id id of the object to be exported * \return 0 in case of success, -1 if output buffer exceeded */ int io_export_set_traversal_private_export_relationship( io_export_set_traversal_t *this_, data_id_t id ); #endif /* IO_EXPORT_SET_TRAVERSAL_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/io_exporter.h000066400000000000000000000217731415120503000216770ustar00rootroot00000000000000/* File: io_exporter.h; Copyright and License: see below */ #ifndef IO_EXPORTER_H #define IO_EXPORTER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Exports all diagrams and documents, defines filenames, traverses the diagram tree */ #include "io_file_format.h" #include "image/image_format_writer.h" #include "io_export_model_traversal.h" #include "io_export_diagram_traversal.h" #include "io_export_flat_traversal.h" #include "xhtml/xhtml_element_writer.h" #include "xmi/xmi_element_writer.h" #include "json/json_element_writer.h" #include "storage/data_database.h" #include "pencil_diagram_maker.h" #include "set/data_visible_set.h" #include "set/data_stat.h" #include "util/geometry/geometry_rectangle.h" #include "util/string/utf8stringbuf.h" #include /*! * \brief attributes of the file exporter */ struct io_exporter_struct { data_database_reader_t *db_reader; /*!< pointer to external database reader */ /* temporary member attributes, only valid during exporting */ data_visible_set_t temp_input_data; /*!< buffer to cache the diagram data */ image_format_writer_t temp_image_format_exporter; /*!< exports single diagram images to one given file */ io_export_model_traversal_t temp_model_traversal; /*!< own instance of a model_traversal for text export */ io_export_diagram_traversal_t temp_diagram_traversal; /*!< own instance of a diagram_traversal for text export */ io_export_flat_traversal_t temp_flat_traversal; /*!< own instance of a flat_nodes_traversal for json export */ xhtml_element_writer_t temp_format_writer; /*!< memory for a temporary format writer */ xmi_element_writer_t temp_xmi_writer; /*!< memory for a temporary xmi writer */ json_element_writer_t temp_json_writer; /*!< memory for a temporary json writer */ char temp_filename_buf[512]; /*!< buffer space for temporary filename construction */ utf8stringbuf_t temp_filename; /*!< buffer space for temporary filename construction */ data_diagram_t temp_diagram; /*!< buffer space for temporary diagram data */ }; typedef struct io_exporter_struct io_exporter_t; /*! * \brief initializes the main window * * \param this_ pointer to own object attributes * \param db_reader pointer to a database reader object */ void io_exporter_init( io_exporter_t *this_, data_database_reader_t *db_reader ); /*! * \brief destroys the main window * * \param this_ pointer to own object attributes */ void io_exporter_destroy( io_exporter_t *this_ ); /*! * \brief renders diagrams and exports these to picture (or text) files * \param this_ pointer to own object attributes * \param export_type bitset of file formats to export * \param target_folder path name to a folder where to store the images * \param document_file_path path to the central/main document file * \param io_export_stat pointer to already initialized statistics object where export statistics are collected * \return 0 in case of success, -1 otherwise */ int io_exporter_export_files( io_exporter_t *this_, io_file_format_t export_type, const char *target_folder, const char *document_file_path, data_stat_t *io_export_stat ); /*! * \brief extracts the base file name without extension from the given path * \param this_ pointer to own object attributes * \param path path name to a file from which to extract the base file name * \param out_base_filename name of the file - without path and without filename-suffix * \return 0 in case of success, -1 otherwise, e.g if filename is empty or too long */ int io_exporter_private_get_filename( io_exporter_t *this_, const char* path, utf8stringbuf_t out_base_filename ); /*! * \brief renders diagrams and exports these to picture (or text) files * \param this_ pointer to own object attributes * \param diagram_id id of the diagram to export; DATA_ROW_ID_VOID to export all root diagrams * \param max_recursion if greater than 0 and children exist, this function calls itself recursively * \param export_type image file format * \param target_folder path name to a folder where to store the images * \param io_export_stat pointer to statistics object where export statistics are collected * \return 0 in case of success, -1 otherwise */ int io_exporter_private_export_image_files( io_exporter_t *this_, data_id_t diagram_id, uint32_t max_recursion, io_file_format_t export_type, const char *target_folder, data_stat_t *io_export_stat ); /*! * \brief creates a document file * \param this_ pointer to own object attributes * \param export_type image file format * \param target_folder directory where to write the document to * \param document_file_name name of the central/main document file (without filename-suffix) * \param io_export_stat pointer to statistics object where export statistics are collected * \return 0 in case of success, -1 otherwise */ int io_exporter_private_export_document_file( io_exporter_t *this_, io_file_format_t export_type, const char *target_folder, const char *document_file_name, data_stat_t *io_export_stat ); /*! * \brief creates a document part * \param this_ pointer to own object attributes * \param diagram_id id of the diagram to export; DATA_ROW_ID_VOID to export all root diagrams * \param max_recursion if greater than 0 and children exist, this function calls itself recursively * \param io_export_stat pointer to statistics object where export statistics are collected * \return 0 in case of success, -1 otherwise */ int io_exporter_private_export_document_part( io_exporter_t *this_, data_id_t diagram_id, uint32_t max_recursion, data_stat_t *io_export_stat ); /*! * \brief creates a table of contents * \param this_ pointer to own object attributes * \param diagram_id id of the diagram to export; DATA_ROW_ID_VOID to export all root diagrams * \param max_recursion if greater than 0 and children exist, this function calls itself recursively * \param format_writer writer to format the data and stream it out to a file * \return 0 in case of success, -1 otherwise */ int io_exporter_private_export_table_of_contents( io_exporter_t *this_, data_id_t diagram_id, uint32_t max_recursion, xhtml_element_writer_t *format_writer ); /*! * \brief calculates a base filename (without type extension) for a givien diagram id * \param this_ pointer to own object attributes * \param diagram_id id of the diagam * \param filename filename stringbuffer to which to write the filename * \return 0 in case of success, -1 otherwise */ int io_exporter_private_get_filename_for_diagram( io_exporter_t *this_, data_id_t diagram_id, utf8stringbuf_t filename ); /*! * \brief appends all characters that are valid within a filename to filename * \param this_ pointer to own object attributes * \param name name of the object, after which the file shall be named * \param filename filename stringbuffer to which to write the valid characters */ void io_exporter_private_append_valid_chars_to_filename( io_exporter_t *this_, const char *name, utf8stringbuf_t filename ); #endif /* IO_EXPORTER_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/io_exporter_light.h000066400000000000000000000055031415120503000230570ustar00rootroot00000000000000/* File: io_exporter_light.h; Copyright and License: see below */ #ifndef IO_EXPORTER_LIGHT_H #define IO_EXPORTER_LIGHT_H /* public file for the doxygen documentation: */ /*! \file * \brief Serializes a set of objects to a stringbuffer. * * Only sets can be exported, only in json format, only to memory buffers. */ #include "io_export_set_traversal.h" #include "storage/data_database_reader.h" #include "set/data_stat.h" #include "util/string/utf8stringbuf.h" /*! * \brief attributes of the io_exporter_light_t object */ struct io_exporter_light_struct { data_database_reader_t *db_reader; /*!< pointer to external data_database_reader */ io_export_set_traversal_t temp_set_traversal; /*!< temporary memory for a traversal of a small set */ }; typedef struct io_exporter_light_struct io_exporter_light_t; /*! * \brief initializes the io_exporter_light_t struct * * \param this_ pointer to own object attributes * \param db_reader pointer to a database reader */ static inline void io_exporter_light_init ( io_exporter_light_t *this_, data_database_reader_t *db_reader ); /*! * \brief destroys the io_exporter_light_t struct * * \param this_ pointer to own object attributes */ static inline void io_exporter_light_destroy ( io_exporter_light_t *this_ ); /*! * \brief copies a set of objects to a string buffer, can be forwarded e.g. to the clipboard * * \param this_ pointer to own object attributes * \param set_to_be_exported ids of the objects to be exported * \param io_export_stat pointer to statistics object where export statistics are collected. * Statistics are only added, *io_stat shall be initialized by caller. * \param out_buf string buffer to which to write the json formatted data to * \return 0 in case of success, -1 if output buffer exceeded */ static inline int io_exporter_light_export_set_to_buf( io_exporter_light_t *this_, const data_small_set_t *set_to_be_exported, data_stat_t *io_export_stat, utf8stringbuf_t out_buf ); #include "io_exporter_light.inl" #endif /* IO_EXPORTER_LIGHT_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/io_exporter_light.inl000066400000000000000000000076121415120503000234150ustar00rootroot00000000000000/* File: io_exporter_light.h; Copyright and License: see below */ #include "json/json_element_writer.h" #include "json/json_writer_pass.h" #include "stream/universal_output_stream.h" #include "stream/universal_memory_output_stream.h" #include static inline void io_exporter_light_init ( io_exporter_light_t *this_, data_database_reader_t *db_reader ) { assert( NULL != db_reader ); (*this_).db_reader = db_reader; } static inline void io_exporter_light_destroy ( io_exporter_light_t *this_ ) { assert( NULL != (*this_).db_reader ); (*this_).db_reader = NULL; } static inline int io_exporter_light_export_set_to_buf( io_exporter_light_t *this_, const data_small_set_t *set_to_be_exported, data_stat_t *io_export_stat, utf8stringbuf_t out_buf ) { assert( NULL != set_to_be_exported ); assert( NULL != io_export_stat ); int exp_err = 0; data_stat_t count_just_once; data_stat_init( &count_just_once ); /* initialize an output stream */ universal_memory_output_stream_t memout; universal_memory_output_stream_init( &memout, utf8stringbuf_get_string( out_buf ), utf8stringbuf_get_size( out_buf ) ); universal_output_stream_t *output; output = universal_memory_output_stream_get_output_stream( &memout ); /* initialize an element writer */ json_element_writer_t json_writer; json_element_writer_init( &json_writer, io_export_stat, output ); io_element_writer_t *element_writer; element_writer = json_element_writer_get_element_writer( &json_writer ); /* initialize a traversal */ io_export_set_traversal_init( &((*this_).temp_set_traversal), (*this_).db_reader, &count_just_once, element_writer ); /* do traversal */ const char *const document_title = ""; exp_err |= io_element_writer_write_header( element_writer, document_title ); json_element_writer_set_mode( &json_writer, JSON_WRITER_PASS_VIEWS ); exp_err |= io_export_set_traversal_export_set( &((*this_).temp_set_traversal), set_to_be_exported ); data_stat_add( io_export_stat, &count_just_once ); /* after the first pass, report the error statistics */ json_element_writer_set_mode( &json_writer, JSON_WRITER_PASS_NODES ); exp_err |= io_export_set_traversal_export_set( &((*this_).temp_set_traversal), set_to_be_exported ); json_element_writer_set_mode( &json_writer, JSON_WRITER_PASS_EDGES ); exp_err |= io_export_set_traversal_export_set( &((*this_).temp_set_traversal), set_to_be_exported ); exp_err |= io_element_writer_write_footer( element_writer ); /* de-initialize a traversal */ io_export_set_traversal_destroy ( &((*this_).temp_set_traversal) ); /* de-initialize an element writer */ json_element_writer_destroy( &json_writer ); /* de-initialize an output stream */ exp_err |= universal_memory_output_stream_write_0term( &memout ); universal_memory_output_stream_destroy( &memout ); data_stat_destroy( &count_just_once ); return exp_err; } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/io_file_format.h000066400000000000000000000034761415120503000223160ustar00rootroot00000000000000/* File: io_file_format.h; Copyright and License: see below */ #ifndef IO_FILE_FORMAT_H #define IO_FILE_FORMAT_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines the export formats of diagram-image/text files */ #include "util/string/utf8stringbuf.h" /*! * \brief file format of exported images/text */ enum io_file_format_enum { IO_FILE_FORMAT_NONE = 0x00000, /*!< no format selected */ IO_FILE_FORMAT_SVG = 0x00001, /*!< scalable vector graphics */ IO_FILE_FORMAT_PDF = 0x00002, /*!< portable document format */ IO_FILE_FORMAT_PS = 0x00004, /*!< postscript */ IO_FILE_FORMAT_PNG = 0x00008, /*!< portable network graphics */ IO_FILE_FORMAT_TXT = 0x00010, /*!< utf8 encoded text */ IO_FILE_FORMAT_DOCBOOK = 0x00100, /*!< docbook */ IO_FILE_FORMAT_XHTML = 0x00200, /*!< xhtml */ IO_FILE_FORMAT_CSS = 0x00400, /*!< css for xhtml */ IO_FILE_FORMAT_XMI2 = 0x01000, /*!< xmi version 2.5.1 */ IO_FILE_FORMAT_JSON = 0x10000, /*!< json; json-ld: https://www.w3.org/TR/json-ld/ */ }; typedef enum io_file_format_enum io_file_format_t; void io_file_format_to_string( io_file_format_t format_set, utf8stringbuf_t out_fileformat ); #endif /* IO_FILE_FORMAT_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/io_importer.h000066400000000000000000000063421415120503000216630ustar00rootroot00000000000000/* File: io_importer.h; Copyright and License: see below */ #ifndef IO_IMPORTER_H #define IO_IMPORTER_H /* public file for the doxygen documentation: */ /*! \file * \brief Imports a set of objects from a file */ #include "json/json_import_to_database.h" #include "io_file_format.h" #include "ctrl_controller.h" #include "storage/data_database_reader.h" #include "set/data_stat.h" #include "universal_utf8_writer.h" /*! * \brief attributes of the import object */ struct io_importer_struct { json_import_to_database_t json_importer; }; typedef struct io_importer_struct io_importer_t; /*! * \brief initializes the io_importer_t struct * * \param this_ pointer to own object attributes * \param db_reader pointer to a database reader * \param controller pointer to a controller object which can modify the database */ void io_importer_init ( io_importer_t *this_, data_database_reader_t *db_reader, ctrl_controller_t *controller ); /*! * \brief destroys the io_importer_t struct * * \param this_ pointer to own object attributes */ void io_importer_destroy ( io_importer_t *this_ ); /*! * \brief imports the file contents to the database * * \param this_ pointer to own object attributes * \param import_format file format, currently only IO_FILE_FORMAT_JSON is supported * \param import_file_path null-terminated file path, not NULL * \param io_stat undefined in case of an error in the return value, * otherwise statistics on DATA_STAT_SERIES_CREATED, * DATA_STAT_SERIES_MODIFIED (e.g. in future) and * DATA_STAT_SERIES_IGNORED (e.g. at import of lifelines * or if classifier and its features already exist) and * DATA_STAT_SERIES_ERROR (e.g. if a relation has no source * or no destination) * Statistics are only added, *io_stat shall be initialized by caller. * \param out_english_report universal_utf8_writer_t where to write a non-translated report to * \return DATA_ERROR_NONE in case of success, * DATA_ERROR_INVALID_REQUEST if file cannot be opened, * DATA_ERROR_AT_FILE_READ in case of reading errors after open, * other error code otherwise */ data_error_t io_importer_import_file( io_importer_t *this_, io_file_format_t import_format, const char *import_file_path, data_stat_t *io_stat, universal_utf8_writer_t *out_english_report ); #endif /* IO_IMPORTER_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/json/000077500000000000000000000000001415120503000201265ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/include/json/json_constants.h000066400000000000000000000120731415120503000233470ustar00rootroot00000000000000/* File: json_constants.h; Copyright and License: see below */ #ifndef JSON_CONSTANTS_H #define JSON_CONSTANTS_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines constants for key-strings in json format. */ /* structure */ #define JSON_CONSTANTS_BEGIN_OBJECT_NL "{\n" #define JSON_CONSTANTS_END_OBJECT_NL "}\n" #define JSON_CONSTANTS_BEGIN_OBJECT "{" #define JSON_CONSTANTS_END_OBJECT "}" #define JSON_CONSTANTS_TAB " " #define JSON_CONSTANTS_QUOTE "\"" #define JSON_CONSTANTS_DEF ": " #define JSON_CONSTANTS_BEGIN_ARRAY "[" #define JSON_CONSTANTS_END_ARRAY "]" #define JSON_CONSTANTS_NEXT_NL ",\n" #define JSON_CONSTANTS_NL "\n" #define JSON_CONSTANTS_TRUE "true" #define JSON_CONSTANTS_FALSE "false" #define JSON_CONSTANTS_NULL "null" #define JSON_CONSTANTS_CHAR_NL '\n' #define JSON_CONSTANTS_CHAR_CR '\r' #define JSON_CONSTANTS_CHAR_TAB '\t' #define JSON_CONSTANTS_CHAR_SPACE ' ' #define JSON_CONSTANTS_CHAR_BEGIN_OBJECT '{' #define JSON_CONSTANTS_CHAR_END_OBJECT '}' #define JSON_CONSTANTS_CHAR_BEGIN_ARRAY '[' #define JSON_CONSTANTS_CHAR_END_ARRAY ']' #define JSON_CONSTANTS_CHAR_BEGIN_STRING '\"' #define JSON_CONSTANTS_CHAR_END_STRING '\"' #define JSON_CONSTANTS_CHAR_NAME_SEPARATOR ':' #define JSON_CONSTANTS_CHAR_VALUE_SEPARATOR ',' #define JSON_CONSTANTS_CHAR_ESC '\\' #define JSON_CONSTANTS_CHAR_BEGIN_TRUE 't' #define JSON_CONSTANTS_CHAR_BEGIN_FALSE 'f' #define JSON_CONSTANTS_CHAR_BEGIN_NULL 'n' /* content */ #define JSON_CONSTANTS_KEY_HEAD "head" #define JSON_CONSTANTS_KEY_NODES "nodes" #define JSON_CONSTANTS_KEY_EDGES "edges" #define JSON_CONSTANTS_KEY_VIEWS "views" #define JSON_CONSTANTS_KEY_UUID "uuid" #define JSON_CONSTANTS_KEY_DIAGRAM "diagram" #define JSON_CONSTANTS_KEY_DIAGRAM_ID "id" #define JSON_CONSTANTS_KEY_DIAGRAM_PARENT_ID "parent_id" #define JSON_CONSTANTS_KEY_DIAGRAM_PARENT "parent" #define JSON_CONSTANTS_KEY_DIAGRAM_DIAGRAM_TYPE "diagram_type" #define JSON_CONSTANTS_KEY_DIAGRAM_NAME "name" #define JSON_CONSTANTS_KEY_DIAGRAM_DESCRIPTION "description" #define JSON_CONSTANTS_KEY_DIAGRAM_LIST_ORDER "list_order" #define JSON_CONSTANTS_KEY_DIAGRAM_DISPLAY_FLAGS "display_flags" #define JSON_CONSTANTS_KEY_DIAGRAM_ELEMENTS "diagramelements" #define JSON_CONSTANTS_KEY_DIAGRAMELEMENT_ID "id" #define JSON_CONSTANTS_KEY_DIAGRAMELEMENT_DIAGRAM_ID "diagram_id" #define JSON_CONSTANTS_KEY_DIAGRAMELEMENT_CLASSIFIER_ID "classifier_id" #define JSON_CONSTANTS_KEY_DIAGRAMELEMENT_FOCUSED_FEATURE_ID "focused_feature_id" #define JSON_CONSTANTS_KEY_DIAGRAMELEMENT_DISPLAY_FLAGS "display_flags" #define JSON_CONSTANTS_KEY_DIAGRAMELEMENT_NODE "node" #define JSON_CONSTANTS_KEY_CLASSIFIER "classifier" #define JSON_CONSTANTS_KEY_CLASSIFIER_ID "id" #define JSON_CONSTANTS_KEY_CLASSIFIER_MAIN_TYPE "main_type" #define JSON_CONSTANTS_KEY_CLASSIFIER_STEREOTYPE "stereotype" #define JSON_CONSTANTS_KEY_CLASSIFIER_NAME "name" #define JSON_CONSTANTS_KEY_CLASSIFIER_DESCRIPTION "description" #define JSON_CONSTANTS_KEY_CLASSIFIER_X_ORDER "x_order" #define JSON_CONSTANTS_KEY_CLASSIFIER_Y_ORDER "y_order" #define JSON_CONSTANTS_KEY_CLASSIFIER_LIST_ORDER "list_order" #define JSON_CONSTANTS_KEY_CLASSIFIER_FEATURES "features" #define JSON_CONSTANTS_KEY_FEATURE_ID "id" #define JSON_CONSTANTS_KEY_FEATURE_MAIN_TYPE "main_type" #define JSON_CONSTANTS_KEY_FEATURE_KEY "key" #define JSON_CONSTANTS_KEY_FEATURE_VALUE "value" #define JSON_CONSTANTS_KEY_FEATURE_DESCRIPTION "description" #define JSON_CONSTANTS_KEY_FEATURE_LIST_ORDER "list_order" #define JSON_CONSTANTS_KEY_RELATIONSHIP "relationship" #define JSON_CONSTANTS_KEY_RELATIONSHIP_ID "id" #define JSON_CONSTANTS_KEY_RELATIONSHIP_FROM_CLASSIFIER_ID "from_classifier_id" #define JSON_CONSTANTS_KEY_RELATIONSHIP_FROM_CLASSIFIER_NAME "from_classifier_name" #define JSON_CONSTANTS_KEY_RELATIONSHIP_FROM_FEATURE_ID "from_feature_id" #define JSON_CONSTANTS_KEY_RELATIONSHIP_FROM_FEATURE_KEY "from_feature_key" #define JSON_CONSTANTS_KEY_RELATIONSHIP_FROM_NODE "from_node" #define JSON_CONSTANTS_KEY_RELATIONSHIP_TO_CLASSIFIER_ID "to_classifier_id" #define JSON_CONSTANTS_KEY_RELATIONSHIP_TO_CLASSIFIER_NAME "to_classifier_name" #define JSON_CONSTANTS_KEY_RELATIONSHIP_TO_FEATURE_ID "to_feature_id" #define JSON_CONSTANTS_KEY_RELATIONSHIP_TO_FEATURE_KEY "to_feature_key" #define JSON_CONSTANTS_KEY_RELATIONSHIP_TO_NODE "to_node" #define JSON_CONSTANTS_KEY_RELATIONSHIP_MAIN_TYPE "main_type" #define JSON_CONSTANTS_KEY_RELATIONSHIP_NAME "name" #define JSON_CONSTANTS_KEY_RELATIONSHIP_DESCRIPTION "description" #define JSON_CONSTANTS_KEY_RELATIONSHIP_LIST_ORDER "list_order" #endif /* JSON_CONSTANTS_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/json/json_deserializer.h000066400000000000000000000333771415120503000240270ustar00rootroot00000000000000/* File: json_deserializer.h; Copyright and License: see below */ #ifndef JSON_DESERIALIZER_H #define JSON_DESERIALIZER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Deserializes data objects from json format. * * This object is a json parser, using the json_token_reader as lexer. */ #include "json/json_token_reader.h" #include "data_error.h" #include "data_table.h" #include "data_classifier.h" #include "data_diagram.h" #include "data_feature.h" #include "data_relationship.h" #include "stream/universal_input_stream.h" #include "util/string/utf8stringbuf.h" #include #include /*! * \brief all data attributes needed for deserializing data objects * * The attribute values keep track on the structure of the input tokens * to check if these appear in the right order. */ struct json_deserializer_struct { json_token_reader_t tokenizer; /*!< own token_reader instance to consecutively fetch tokens from the json input file */ bool after_first_array_entry; /*!< true if the first array entry has already been parsed */ utf8stringbuf_t temp_string; /*!< a local buffer to buffer streamed strings before assigning them to data objects */ char temp_string_buffer[DATA_DIAGRAM_MAX_DESCRIPTION_SIZE]; }; typedef struct json_deserializer_struct json_deserializer_t; /*! * \brief initializes the json_deserializer_t struct * * \param this_ pointer to own object attributes * \param in_data json text to be parsed */ void json_deserializer_init ( json_deserializer_t *this_, universal_input_stream_t *in_data ); /*! * \brief re-initializes the json_deserializer_t struct * * \param this_ pointer to own object attributes * \param in_data json text to be parsed */ void json_deserializer_reinit ( json_deserializer_t *this_, universal_input_stream_t *in_data ); /*! * \brief destroys the json_deserializer_t struct * * \param this_ pointer to own object attributes */ void json_deserializer_destroy ( json_deserializer_t *this_ ); /*! * \brief checks that the header of the json data is valid * * \param this_ pointer to own object attributes * \return DATA_ERROR_PARSER_STRUCTURE if JSON format is valid but JSON content is unexpected, * DATA_ERROR_LEXICAL_STRUCTURE if JSON format is invalid, * DATA_ERROR_NONE if structure of the input is valid. */ data_error_t json_deserializer_expect_header ( json_deserializer_t *this_ ); /*! * \brief checks that the footer/ending of the json data is valid * * \param this_ pointer to own object attributes * \return DATA_ERROR_PARSER_STRUCTURE if JSON format is valid but JSON content is unexpected, * DATA_ERROR_LEXICAL_STRUCTURE if JSON format is invalid, * DATA_ERROR_NONE if structure of the input is valid. */ data_error_t json_deserializer_expect_footer ( json_deserializer_t *this_ ); /*! * \brief checks that the beginning of the json data is valid * * \param this_ pointer to own object attributes * \return DATA_ERROR_PARSER_STRUCTURE if JSON format is valid but JSON content is unexpected, * DATA_ERROR_LEXICAL_STRUCTURE if JSON format is invalid, * DATA_ERROR_NONE if structure of the input is valid. */ data_error_t json_deserializer_expect_begin_data ( json_deserializer_t *this_ ); /*! * \brief checks if the data array is at end. * * If yes, the end is read. * * \param this_ pointer to own object attributes * \param[out] out_end true if the data array is at its end. * \return DATA_ERROR_PARSER_STRUCTURE if JSON format is valid but JSON content is unexpected, * DATA_ERROR_LEXICAL_STRUCTURE if JSON format is invalid, * DATA_ERROR_NONE if structure of the input is valid. */ data_error_t json_deserializer_check_end_data ( json_deserializer_t *this_, bool* out_end ); /*! * \brief determines the type of object which is contained in this object * * \param this_ pointer to own object attributes * \param out_type pointer to storage location for the result. Must not be NULL. * DATA_TABLE_CLASSIFIER if the next object is a classifier, * DATA_TABLE_DIAGRAM if the next object is a diagram, * DATA_TABLE_RELATIONSHIP if the next object is a relationship, * DATA_TABLE_VOID if there is no next object. * \return DATA_ERROR_PARSER_STRUCTURE if JSON format is valid but JSON content is unexpected, * DATA_ERROR_LEXICAL_STRUCTURE if JSON format is invalid, * DATA_ERROR_NONE if structure of the input is valid. */ data_error_t json_deserializer_expect_begin_type_of_element ( json_deserializer_t *this_, data_table_t *out_type ); /*! * \brief checks that the ending of the json type-object is valid * * \param this_ pointer to own object attributes * \return DATA_ERROR_PARSER_STRUCTURE if JSON format is valid but JSON content is unexpected, * DATA_ERROR_LEXICAL_STRUCTURE if JSON format is invalid, * DATA_ERROR_NONE if structure of the input is valid. */ data_error_t json_deserializer_expect_end_type_of_element ( json_deserializer_t *this_ ); /*! * \brief parses the next object as classifier * * \param this_ pointer to own object attributes * \param out_object pointer to storage location for the result. Must not be NULL. * \param max_out_array_size size of the array where to store the results. If size is too small for the actual result set, this is an error. * \param out_feature array of features read from the database (in case of success), must not be NULL * \param out_feature_count number of feature records stored in out_feature * \return DATA_ERROR_STRING_BUFFER_EXCEEDED if strings do not fit into the out_object, * DATA_ERROR_PARSER_STRUCTURE if JSON format is valid but JSON content is unexpected, * DATA_ERROR_LEXICAL_STRUCTURE if JSON format is invalid, * DATA_ERROR_NONE if structure of the input is valid. */ data_error_t json_deserializer_get_next_classifier ( json_deserializer_t *this_, data_classifier_t *out_object, uint32_t max_out_array_size, data_feature_t (*out_feature)[], uint32_t *out_feature_count ); /*! * \brief parses the next object as diagram * * \param this_ pointer to own object attributes * \param out_object pointer to storage location for the result. Must not be NULL. * \return DATA_ERROR_STRING_BUFFER_EXCEEDED if strings do not fit into the out_object, * DATA_ERROR_PARSER_STRUCTURE if JSON format is valid but JSON content is unexpected, * DATA_ERROR_LEXICAL_STRUCTURE if JSON format is invalid, * DATA_ERROR_NONE if structure of the input is valid. */ data_error_t json_deserializer_get_next_diagram ( json_deserializer_t *this_, data_diagram_t *out_object ); /*! * \brief parses the next object as relationship * * \param this_ pointer to own object attributes * \param out_object pointer to storage location for the result. Must not be NULL. * \param out_from_classifier_name stringbuffer to copy the from classifier name into; * size should be DATA_CLASSIFIER_MAX_NAME_SIZE. * \param out_from_feature_key stringbuffer to copy the from feature key into; * empty string is written if no feature available; * size should be DATA_FEATURE_MAX_KEY_SIZE. * \param out_to_classifier_name stringbuffer to copy the to classifier name into; * size should be DATA_CLASSIFIER_MAX_NAME_SIZE. * \param out_to_feature_key stringbuffer to copy the to feature key into; * empty string is written if no feature available; * size should be DATA_FEATURE_MAX_KEY_SIZE. * \return DATA_ERROR_STRING_BUFFER_EXCEEDED if strings do not fit into the out_object, * DATA_ERROR_PARSER_STRUCTURE if JSON format is valid but JSON content is unexpected, * DATA_ERROR_LEXICAL_STRUCTURE if JSON format is invalid, * DATA_ERROR_NONE if structure of the input is valid. */ data_error_t json_deserializer_get_next_relationship ( json_deserializer_t *this_, data_relationship_t *out_object, utf8stringbuf_t out_from_classifier_name, utf8stringbuf_t out_from_feature_key, utf8stringbuf_t out_to_classifier_name, utf8stringbuf_t out_to_feature_key ); /*! * \brief skips the next object, e.g. a relationship if this is of no interest * * \param this_ pointer to own object attributes * \return DATA_ERROR_PARSER_STRUCTURE if JSON format is valid but JSON content is unexpected (e.g. array member), * DATA_ERROR_LEXICAL_STRUCTURE if JSON format is invalid, * DATA_ERROR_NONE if structure of the input is valid. */ data_error_t json_deserializer_skip_next_object ( json_deserializer_t *this_ ); /*! * \brief skips the next string, e.g. a key or string-value of no interest * * \param this_ pointer to own object attributes * \return DATA_ERROR_PARSER_STRUCTURE if JSON format is valid but JSON content is unexpected (e.g. array member), * DATA_ERROR_LEXICAL_STRUCTURE if JSON format is invalid, * DATA_ERROR_NONE if structure of the input is valid. */ data_error_t json_deserializer_skip_next_string ( json_deserializer_t *this_ ); /*! * \brief gets the line number at the current read position * * May be used to determine the position where a parse error occurred. * * \param this_ pointer to own object attributes * \param out_read_pos pointer to storage location for the result. Must not be NULL. */ void json_deserializer_get_read_line ( json_deserializer_t *this_, uint32_t *out_read_pos ); /*! * \brief parses the next feature array * * \param this_ pointer to own object attributes * \param max_out_array_size size of the array where to store the results. If size is too small for the actual result set, this is an error. * \param out_feature array of features read from the database (in case of success), must not be NULL * \param out_feature_count number of feature records stored in out_feature * \return DATA_ERROR_STRING_BUFFER_EXCEEDED if strings do not fit into the out_object, * DATA_ERROR_PARSER_STRUCTURE if JSON format is valid but JSON content is unexpected, * DATA_ERROR_LEXICAL_STRUCTURE if JSON format is invalid, * DATA_ERROR_NONE if structure of the input is valid. */ data_error_t json_deserializer_private_get_next_feature_array ( json_deserializer_t *this_, uint32_t max_out_array_size, data_feature_t (*out_feature)[], uint32_t *out_feature_count ); /*! * \brief parses the next object as feature * * This function may only be called from within parsing a classifier. * * \param this_ pointer to own object attributes * \param out_object pointer to storage location for the result. Must not be NULL. * \return DATA_ERROR_STRING_BUFFER_EXCEEDED if strings do not fit into the out_object, * DATA_ERROR_PARSER_STRUCTURE if JSON format is valid but JSON content is unexpected, * DATA_ERROR_LEXICAL_STRUCTURE if JSON format is invalid, * DATA_ERROR_NONE if structure of the input is valid. */ data_error_t json_deserializer_private_get_next_feature ( json_deserializer_t *this_, data_feature_t *out_object ); /*! * \brief parses the next diagramelement array * * \param this_ pointer to own object attributes * \return DATA_ERROR_STRING_BUFFER_EXCEEDED if strings do not fit into the out_object, * DATA_ERROR_PARSER_STRUCTURE if JSON format is valid but JSON content is unexpected, * DATA_ERROR_LEXICAL_STRUCTURE if JSON format is invalid, * DATA_ERROR_NONE if structure of the input is valid. */ data_error_t json_deserializer_private_skip_next_diagramelement_array ( json_deserializer_t *this_ ); /*! * \brief parses an array of strings and merges the entries * * \param this_ pointer to own object attributes * \param out_joined_string stringbuffer to copy joined string elements to; * \return DATA_ERROR_STRING_BUFFER_EXCEEDED if strings do not fit into the out_joined_string, * DATA_ERROR_PARSER_STRUCTURE if JSON format is valid but JSON content is unexpected, * DATA_ERROR_LEXICAL_STRUCTURE if JSON format is invalid, * DATA_ERROR_NONE if structure of the input is valid. */ data_error_t json_deserializer_private_read_string_array ( json_deserializer_t *this_, utf8stringbuf_t out_joined_string ); #endif /* JSON_DESERIALIZER_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/json/json_element_writer.h000066400000000000000000000374761415120503000243760ustar00rootroot00000000000000/* File: json_element_writer.h; Copyright and License: see below */ #ifndef JSON_ELEMENT_WRITER_H #define JSON_ELEMENT_WRITER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines a pair of a) a pointer to a concrete instance of an interface * and b) a pointer to objectdata that implements the interface. */ #include "json/json_writer.h" #include "json/json_writer_pass.h" #include "io_element_writer.h" #include "data_classifier.h" #include "data_classifier_type.h" #include "data_feature.h" #include "data_relationship.h" #include "data_relationship_type.h" #include "data_diagram.h" #include "data_diagram_type.h" #include "data_diagramelement.h" #include "set/data_stat.h" #include "stream/universal_output_stream.h" /*! * \brief object (vmt+data) of a json_element_writer_t. * */ struct json_element_writer_struct { io_element_writer_t element_writer; /*!< instance of implemented interface \c io_element_writer_t */ json_writer_pass_t mode; /*!< depending on the mode, filtering of data objects differs */ json_writer_t json_writer; /*!< own instance of the json writer */ bool in_outer_array; /*!< true if begin_array() was called and end_array() is not yet called. */ bool is_outer_first; /*!< true if after begin_array(), no object was inserted yet. */ bool in_inner_array; /*!< true if an inner array was begun and not yet ended. */ bool is_inner_first; /*!< true if in the innner array, no object was inserted yet. */ data_stat_t *export_stat; /*!< pointer to external statistics object where export statistics are collected */ }; typedef struct json_element_writer_struct json_element_writer_t; /*! * \brief initializes the json_element_writer_t * * \param this_ pointer to own object attributes * \param io_export_stat pointer to statistics object where export statistics are collected * \param output output stream where to write the generated output to */ void json_element_writer_init( json_element_writer_t *this_, data_stat_t *io_export_stat, universal_output_stream_t *output ); /*! * \brief destroys the json_element_writer_t. * * \param this_ pointer to own object attributes */ void json_element_writer_destroy( json_element_writer_t *this_ ); /*! * \brief gets the io element writer interface of this json_element_writer_t * * \param this_ pointer to own object attributes * \return the abstract base class of this_ */ io_element_writer_t * json_element_writer_get_element_writer( json_element_writer_t *this_ ); /*! * \brief sets the filtering mode of the json_element_writer_t * * \param this_ pointer to own object attributes * \param mode mode which data objects to filter from the output */ void json_element_writer_set_mode( json_element_writer_t *this_, json_writer_pass_t mode ); /*! * \brief writes the header of the document * * \param this_ pointer to own object attributes * \param document_title title of the document * \return 0 in case of success, -1 otherwise */ int json_element_writer_write_header( json_element_writer_t *this_, const char *document_title ); /*! * \brief writes the start of the main section * * This starts a section that contains the main part of the document * * \param this_ pointer to own object attributes * \param document_title title of the document * \return 0 in case of success, -1 otherwise */ int json_element_writer_start_main( json_element_writer_t *this_, const char *document_title ); /*! * \brief checks if a hosting parent classifier may nest a child classifier * * \param this_ pointer to own object attributes * \param host_type data_classifier_type_t of the hosting parent of which the nesting-ability shall be determined * \param child_type data_classifier_type_t of the nested child of which the nesting-ability shall be determined * \return true if nesting is allowed */ bool json_element_writer_can_classifier_nest_classifier( json_element_writer_t *this_, data_classifier_type_t host_type, data_classifier_type_t child_type ); /*! * \brief checks if a hosting parent classifier may nest relationships * * \param this_ pointer to own object attributes * \param host_type data_classifier_type_t of the hosting parent of which the nesting-ability shall be determined * \param child_type data_relationship_type_t of the nested child of which the nesting-ability shall be determined * \return true if nesting or any relationship is allowed */ bool json_element_writer_can_classifier_nest_relationship( json_element_writer_t *this_, data_classifier_type_t host_type, data_relationship_type_t child_type ); /*! * \brief writes a classifier start-element * * This starts a division that contains a classifier and a list of features and relationships * * \param this_ pointer to own object attributes * \param host_type type of the hosting parent classifier, needed for xmi export, DATA_CLASSIFIER_TYPE_VOID if toplevel * \param classifier_ptr pointer to classifier that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int json_element_writer_start_classifier( json_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ); /*! * \brief writes contents of a classifier * * \param this_ pointer to own object attributes * \param host_type type of the hosting parent classifier, needed for xmi export, DATA_CLASSIFIER_TYPE_VOID if toplevel * \param classifier_ptr pointer to classifier that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int json_element_writer_assemble_classifier( json_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ); /*! * \brief writes a classifier end-element * * This ends a division that contains a classifier and a list of features and relationships * * \param this_ pointer to own object attributes * \param host_type type of the hosting parent classifier, needed for xmi export, DATA_CLASSIFIER_TYPE_VOID if toplevel * \param classifier_ptr pointer to classifier that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int json_element_writer_end_classifier( json_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ); /*! * \brief writes a feature start-element * * \param this_ pointer to own object attributes * \param parent_type type of the owning parent classifier * \param feature_ptr pointer to feature that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int json_element_writer_start_feature( json_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ); /*! * \brief writes constents of a a feature * * \param this_ pointer to own object attributes * \param parent_type type of the owning parent classifier * \param feature_ptr pointer to feature that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int json_element_writer_assemble_feature( json_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ); /*! * \brief writes a feature end-element * * \param this_ pointer to own object attributes * \param parent_type type of the owning parent classifier * \param feature_ptr pointer to feature that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int json_element_writer_end_feature( json_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ); /*! * \brief starts a relationship * * \param this_ pointer to own object attributes * \param host_type type of the hosting parent classifier, needed for xmi export * \param relation_ptr pointer to relationship that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int json_element_writer_start_relationship( json_element_writer_t *this_, data_classifier_type_t host_type, const data_relationship_t *relation_ptr ); /*! * \brief writes the contents of a relationship * * \param this_ pointer to own object attributes * \param host the hosting parent classifier, needed for xmi export; is NULL on top-level of document * \param relation_ptr pointer to relationship that shall be written, not NULL * \param from_c the classifier at source end * \param from_f the feature at source end; NULL or !is_valid() if no feature specified * \param to_c the classifier at target end * \param to_f the feature at target end; NULL or !is_valid() if no feature specified * \return 0 in case of success, -1 otherwise */ int json_element_writer_assemble_relationship( json_element_writer_t *this_, const data_classifier_t *host, const data_relationship_t *relation_ptr, const data_classifier_t *from_c, const data_feature_t *from_f, const data_classifier_t *to_c, const data_feature_t *to_f ); /*! * \brief ends a relationship * * \param this_ pointer to own object attributes * \param host_type type of the hosting parent classifier, needed for xmi export * \param relation_ptr pointer to relationship that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int json_element_writer_end_relationship( json_element_writer_t *this_, data_classifier_type_t host_type, const data_relationship_t *relation_ptr ); /*! * \brief writes a diagram start * * This starts a section that contains a diagram and a list of diagramelements (classifier-occurrences) * * \param this_ pointer to own object attributes * \param diag_ptr pointer to diagram that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int json_element_writer_start_diagram( json_element_writer_t *this_, const data_diagram_t *diag_ptr ); /*! * \brief writes a diagram of the document * * \param this_ pointer to own object attributes * \param parent pointer to parent diagram or NULL in case of root * \param diag_ptr pointer to diagram that shall be written * \param diagram_file_base_name filename of the diagram without extension * \return 0 in case of success, -1 otherwise */ int json_element_writer_assemble_diagram( json_element_writer_t *this_, const data_diagram_t *parent, const data_diagram_t *diag_ptr, const char *diagram_file_base_name ); /*! * \brief ends a diagram * * This function is called as part of the abstract universal_output_stream_t - but it does nothing. * * \param this_ pointer to own object attributes * \param diag_ptr pointer to diagram that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int json_element_writer_end_diagram_fake( json_element_writer_t *this_, const data_diagram_t *diag_ptr ); /*! * \brief ends a diagram * * This ends a section that contains a diagram and a list of diagramelements (classifier-occurrences) * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int json_element_writer_private_end_diagram( json_element_writer_t *this_ ); /*! * \brief writes a diagramelement start-element * * \param this_ pointer to own object attributes * \param parent the hosting parent diagram * \param diagramelement_ptr pointer to diagramelement that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int json_element_writer_start_diagramelement( json_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr ); /*! * \brief writes constents of a a diagramelement * * \param this_ pointer to own object attributes * \param parent the hosting parent diagram * \param diagramelement_ptr pointer to diagramelement that shall be written, not NULL * \param occurrence the occurring classifier * \param feat_occur the focused feature of the occurring classifier * \return 0 in case of success, -1 otherwise */ int json_element_writer_assemble_diagramelement( json_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr, const data_classifier_t *occurrence, const data_feature_t *feat_occur ); /*! * \brief writes a diagramelement end-element * * \param this_ pointer to own object attributes * \param parent the hosting parent diagram * \param diagramelement_ptr pointer to diagramelement that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int json_element_writer_end_diagramelement( json_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr ); /*! * \brief writes the ending of the main section * * This ends a section that contains the main part of the document * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int json_element_writer_end_main( json_element_writer_t *this_ ); /*! * \brief writes the footer of the document * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int json_element_writer_write_footer( json_element_writer_t *this_ ); #endif /* JSON_ELEMENT_WRITER_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/json/json_import_to_database.h000066400000000000000000000243571415120503000252030ustar00rootroot00000000000000/* File: json_import_to_database.h; Copyright and License: see below */ #ifndef JSON_IMPORT_TO_DATABASE_H #define JSON_IMPORT_TO_DATABASE_H /* public file for the doxygen documentation: */ /*! \file * \brief Deserializes a set of objects from the clipboard */ #include "json/json_deserializer.h" #include "ctrl_controller.h" #include "data_rules.h" #include "set/data_visible_set.h" #include "set/data_stat.h" #include "storage/data_database_reader.h" #include "stream/universal_input_stream.h" #include "universal_utf8_writer.h" #include "util/string/utf8stringbuf.h" /*! * \brief constants for maximum values of json_import_to_database_t */ enum json_import_to_database_max_enum { JSON_IMPORT_TO_DATABASE_MAX_FEATURES = 64, /*!< maximum number of features per classifier */ JSON_IMPORT_TO_DATABASE_MAX_DIAGELES = DATA_VISIBLE_SET_MAX_CLASSIFIERS, /*!< maximum number of diagramelements per diagram */ }; /*! * \brief attributes of the json import object */ struct json_import_to_database_struct { data_database_reader_t *db_reader; /*!< pointer to external data_database_reader */ ctrl_controller_t *controller; /*!< pointer to external controller */ data_rules_t data_rules; /*!< own instance of uml and sysml consistency rules */ data_feature_t temp_features[JSON_IMPORT_TO_DATABASE_MAX_FEATURES]; /*!< temporary memory for feature list */ data_diagramelement_t temp_diageles[JSON_IMPORT_TO_DATABASE_MAX_DIAGELES]; /*!< temporary memory for diagramelement list */ }; typedef struct json_import_to_database_struct json_import_to_database_t; /*! * \brief initializes the json_import_to_database_t struct * * \param this_ pointer to own object attributes * \param db_reader pointer to a database reader * \param controller pointer to a controller object which can modify the database */ void json_import_to_database_init ( json_import_to_database_t *this_, data_database_reader_t *db_reader, ctrl_controller_t *controller ); /*! * \brief destroys the json_import_to_database_t struct * * \param this_ pointer to own object attributes */ void json_import_to_database_destroy ( json_import_to_database_t *this_ ); /*! * \brief copies the clipboard contents to the focused diagram * * \param this_ pointer to own object attributes * \param json_text 0-terminated string in json format, not NULL * \param diagram_id id of the diagram to which to attach the imported data * \param io_stat undefined in case of an error in the return value, * otherwise statistics on DATA_STAT_SERIES_CREATED, * DATA_STAT_SERIES_MODIFIED (e.g. in future) and * DATA_STAT_SERIES_IGNORED (e.g. at import of lifelines * or if classifier and its features already exist) and * DATA_STAT_SERIES_ERROR (e.g. if a relation has no source * or no destination) * Statistics are only added, *io_stat shall be initialized by caller. * \param out_read_line read position in the stream, in case of an error, this may help finding the cause * \return DATA_ERROR_NONE in case of success, DATA_ERROR_DB_STRUCTURE if diagram_id does not exist, other error code otherwise */ data_error_t json_import_to_database_import_buf_to_db( json_import_to_database_t *this_, const char *json_text, data_row_id_t diagram_id, data_stat_t *io_stat, uint32_t *out_read_line ); /*! * \brief copies the clipboard contents to the focused diagram * * \param this_ pointer to own object attributes * \param json_text stream in json format, not NULL * \param diagram_id id of the diagram to which to attach the imported data * \param io_stat undefined in case of an error in the return value, * otherwise statistics on DATA_STAT_SERIES_CREATED, * DATA_STAT_SERIES_MODIFIED (e.g. in future) and * DATA_STAT_SERIES_IGNORED (e.g. at import of lifelines * or if classifier and its features already exist) and * DATA_STAT_SERIES_ERROR (e.g. if a relation has no source * or no destination). * Statistics are only added, *io_stat shall be initialized by caller. * \param out_read_line read position in the stream, in case of an error, this may help finding the cause * \return DATA_ERROR_NONE in case of success, DATA_ERROR_DB_STRUCTURE if diagram_id does not exist, other error code otherwise */ data_error_t json_import_to_database_import_stream_to_db( json_import_to_database_t *this_, universal_input_stream_t *json_text, data_row_id_t diagram_id, data_stat_t *io_stat, uint32_t *out_read_line ); /*! * \brief checks if a given lifeline (feature) is visible (focused) in the current diagram * * \param this_ pointer to own object attributes * \param diagram_id id of the diagram to which to attach the imported data * \param feature_id id of the feature that shall be the focused_feature of the diagramelement (for a lifeline, this means being visible) * \return true if a matching diagramelement is found */ bool json_import_to_database_private_is_feature_focused_in_diagram( json_import_to_database_t *this_, data_row_id_t diagram_id, data_row_id_t feature_id ); /*! * \brief prescans which object ids are to be imported and which already exist in the current db * * \param this_ pointer to own object attributes * \param in_stream input stream where to import the data from * \param io_stat statistics object ot which import statistics are added * \param out_english_report non translated report on errors in input file and warnings from importing * \return DATA_ERROR_NONE in case of success */ data_error_t json_import_to_database_prescan( json_import_to_database_t *this_, universal_input_stream_t *in_stream, data_stat_t *io_stat, universal_utf8_writer_t *out_english_report ); /*! * \brief imports views to the focused diagram * * \param this_ pointer to own object attributes * \param deserializer structured data element stream * \param io_diagram_id id of the diagram to which to attach the imported data; is modified when creating a diagram * \param io_stat undefined in case of an error in the return value, otherwise statistics. * Statistics are only added, *io_stat shall be initialized by caller. * \return DATA_ERROR_NONE in case of success, DATA_ERROR_DB_STRUCTURE if diagram_id does not exist, other error code otherwise */ data_error_t json_import_to_database_private_import_views( json_import_to_database_t *this_, json_deserializer_t *deserializer, data_row_id_t *io_diagram_id, data_stat_t *io_stat ); /*! * \brief imports nodes to the focused diagram * * \param this_ pointer to own object attributes * \param deserializer structured data element stream * \param diagram_id id of the diagram to which to attach the imported data * \param io_stat undefined in case of an error in the return value, otherwise statistics. * Statistics are only added, *io_stat shall be initialized by caller. * \return DATA_ERROR_NONE in case of success, DATA_ERROR_DB_STRUCTURE if diagram_id does not exist, other error code otherwise */ data_error_t json_import_to_database_private_import_nodes( json_import_to_database_t *this_, json_deserializer_t *deserializer, data_row_id_t diagram_id, data_stat_t *io_stat ); /*! * \brief imports edges to the focused diagram * * \param this_ pointer to own object attributes * \param deserializer structured data element stream * \param diagram_id id of the diagram to which to attach the imported data * \param io_stat undefined in case of an error in the return value, otherwise statistics. * Statistics are only added, *io_stat shall be initialized by caller. * \return DATA_ERROR_NONE in case of success, DATA_ERROR_DB_STRUCTURE if diagram_id does not exist, other error code otherwise */ data_error_t json_import_to_database_private_import_edges( json_import_to_database_t *this_, json_deserializer_t *deserializer, data_row_id_t diagram_id, data_stat_t *io_stat ); #endif /* JSON_IMPORT_TO_DATABASE_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/json/json_token_reader.h000066400000000000000000000324501415120503000237760ustar00rootroot00000000000000/* File: json_token_reader.h; Copyright and License: see below */ #ifndef JSON_TOKEN_READER_H #define JSON_TOKEN_READER_H /* public file for the doxygen documentation: */ /*! * \file * \brief This class tokenizes one json input stream into a series of tokens, * * This json_token_reader verifies the JSON file tokens (lexer) and allows the caller (parser) to validate the data structure. * * In contrast to a DOM parser, this json_token_reader parses the input sequentially and provides parsed contents step by step. * In contrast to a SAX parser, this json_token_reader does not require callbacks that are called whenever the next token is parsed. * This json_token_reader allows the caller to specify the expectation what the next token is and fails if this expectation is wrong. * * In case of an unexpected token, this parser stops processing and returns an error code. */ #include "json/json_value_type.h" #include "data_error.h" #include "util/string/utf8stringbuf.h" #include "stream/universal_input_stream.h" #include "stream/universal_buffer_input_stream.h" #include "stream/universal_output_stream.h" #include #include /*! * \brief all data attributes needed for tokenizing data objects */ struct json_token_reader_struct { char input_buffer[512]; /*!< look-ahead input buffer to check for next bytes */ universal_buffer_input_stream_t in_stream; /*!< buffer around json input stream to be parsed */ unsigned int input_line; /*!< current input line, needed for error reporting */ }; typedef struct json_token_reader_struct json_token_reader_t; /*! * \brief initializes the json_token_reader_t struct * * \param in_stream json stream to be parsed * \param this_ pointer to own object attributes */ void json_token_reader_init ( json_token_reader_t *this_, universal_input_stream_t *in_stream ); /*! * \brief re-initializes the json_token_reader_t struct * * \param in_stream json stream to be parsed * \param this_ pointer to own object attributes */ void json_token_reader_reinit ( json_token_reader_t *this_, universal_input_stream_t *in_stream ); /*! * \brief destroys the json_token_reader_t struct * * \param this_ pointer to own object attributes */ void json_token_reader_destroy ( json_token_reader_t *this_ ); /*! * \brief checks that the next token is a "begin-object" json token * * \param this_ pointer to own object attributes * \return DATA_ERROR_NONE if the lexical+parser structure of the input is valid, * DATA_ERROR_PARSER_STRUCTURE if there is no begin-object token, * DATA_ERROR_LEXICAL_STRUCTURE otherwise. */ data_error_t json_token_reader_expect_begin_object ( json_token_reader_t *this_ ); /*! * \brief returns the next "member-name" json token * * \param this_ pointer to own object attributes * \param out_name return value: name of the "member-name" * \return DATA_ERROR_STRING_BUFFER_EXCEEDED if out_name does not provide enough space, * DATA_ERROR_NONE if the lexical+parser structure of the input is valid, * DATA_ERROR_PARSER_STRUCTURE if there is no member-name token, * DATA_ERROR_LEXICAL_STRUCTURE otherwise. */ data_error_t json_token_reader_read_member_name ( json_token_reader_t *this_, utf8stringbuf_t out_name ); /*! * \brief checks if the next token is an "end-object" json token. * * This function reads the end object token if there is one. * * \param this_ pointer to own object attributes * \param end_object return value: true if the next token is an "end-object" token. This parameter must not be NULL. * \return DATA_ERROR_NONE if the lexical structure of the input is valid, * DATA_ERROR_LEXICAL_STRUCTURE otherwise. */ data_error_t json_token_reader_check_end_object ( json_token_reader_t *this_, bool *end_object ); /*! * \brief checks that the next token is a "name-separator" json token * * \param this_ pointer to own object attributes * \param in_data utf8 encoded string where to read from * \param io_read_pos pointer to current read position. The read position will be moved(changed) if the next token is a "name-separator". * \return DATA_ERROR_NONE if the lexical+parser structure of the input is valid, * DATA_ERROR_PARSER_STRUCTURE if there is no end-object token, * DATA_ERROR_LEXICAL_STRUCTURE otherwise. */ data_error_t json_token_reader_expect_name_separator ( json_token_reader_t *this_ ); /*! * \brief checks that the next token is a "begin-array" json token * * \param this_ pointer to own object attributes * \return DATA_ERROR_NONE if the lexical+parser structure of the input is valid, * DATA_ERROR_PARSER_STRUCTURE if there is no begin-array token, * DATA_ERROR_LEXICAL_STRUCTURE otherwise. */ data_error_t json_token_reader_expect_begin_array ( json_token_reader_t *this_ ); /*! * \brief checks if the next token is an "end-array" json token. * * This function reads the end array token if there is one. * * \param this_ pointer to own object attributes * \param end_array return value: true if the next token is an "end-array" token. This parameter must not be NULL. * \return DATA_ERROR_NONE if the lexical structure of the input is valid, * DATA_ERROR_LEXICAL_STRUCTURE otherwise. */ data_error_t json_token_reader_check_end_array ( json_token_reader_t *this_, bool *end_array ); /*! * \brief checks that the next token is a "value-separator" json token * * \param this_ pointer to own object attributes * \return DATA_ERROR_NONE if the lexical+parser structure of the input is valid, * DATA_ERROR_PARSER_STRUCTURE if there is no value-separator token, * DATA_ERROR_LEXICAL_STRUCTURE otherwise. */ data_error_t json_token_reader_expect_value_separator ( json_token_reader_t *this_ ); /*! * \brief determines the type of the next value without modifying the read-pointer * * This function reads only as many charactes as necessary to determine the type. * It does not verify if the type is valid. * * \param this_ pointer to own object attributes * \param value_type return value: type of the next value-token. * JSON_VALUE_TYPE_INTEGER will not be returned, JSON_VALUE_TYPE_NUMBER instead. * This parameter must not be NULL. * \return DATA_ERROR_NONE if the lexical+parser structure of the input is valid, * DATA_ERROR_PARSER_STRUCTURE if there is no value-token (e.g. we are at the end of an array), * DATA_ERROR_LEXICAL_STRUCTURE otherwise. */ data_error_t json_token_reader_get_value_type ( json_token_reader_t *this_, json_value_type_t *value_type ); /*! * \brief determines the next value of type string * * \param this_ pointer to own object attributes * \param out_value return value: string-contents of the value-token * \return DATA_ERROR_STRING_BUFFER_EXCEEDED if out_value does not provide enough space, * DATA_ERROR_NONE if the lexical+parser structure of the input is valid, * DATA_ERROR_PARSER_STRUCTURE if there is no string-value-token, * DATA_ERROR_LEXICAL_STRUCTURE otherwise. */ data_error_t json_token_reader_read_string_value ( json_token_reader_t *this_, utf8stringbuf_t out_value ); /*! * \brief determines the next value of type integer (subtype of number) * * \param this_ pointer to own object attributes * \param in_data utf8 encoded string where to read from * \param io_read_pos pointer to current read position. The read position will be moved(changed) if the next token is an integer. * \param out_int return value: integer-contents of the value-token. This parameter must not be NULL. * \return DATA_ERROR_NONE if the lexical+parser structure of the input is valid, * DATA_ERROR_PARSER_STRUCTURE if there is no integer-value-token, * DATA_ERROR_LEXICAL_STRUCTURE otherwise. */ data_error_t json_token_reader_read_int_value ( json_token_reader_t *this_, int64_t *out_int ); /*! * \brief determines the next value of type number * * \param this_ pointer to own object attributes * \param[out] out_number return value: number-contents of the value-token. This parameter must not be NULL. * \return DATA_ERROR_NONE if the lexical+parser structure of the input is valid, * DATA_ERROR_PARSER_STRUCTURE if there is no number-value-token, * DATA_ERROR_LEXICAL_STRUCTURE otherwise. */ data_error_t json_token_reader_read_number_value ( json_token_reader_t *this_, double *out_number ); /*! * \brief determines the next value of type boolean * * \param this_ pointer to own object attributes * \param out_bool return value: boolean-contents of the value-token. This parameter must not be NULL. * \return DATA_ERROR_NONE if the lexical+parser structure of the input is valid, * DATA_ERROR_PARSER_STRUCTURE if there is no boolean-value-token, * DATA_ERROR_LEXICAL_STRUCTURE otherwise. */ data_error_t json_token_reader_read_boolean_value ( json_token_reader_t *this_, bool *out_bool ); /*! * \brief checks that the next token is a "null" json token * * \param this_ pointer to own object attributes * \return DATA_ERROR_NONE if the lexical+parser structure of the input is valid, * DATA_ERROR_PARSER_STRUCTURE if there is no null token, * DATA_ERROR_LEXICAL_STRUCTURE otherwise. */ data_error_t json_token_reader_expect_null_value ( json_token_reader_t *this_ ); /*! * \brief checks that the next token is EOF * * \param this_ pointer to own object attributes * \return DATA_ERROR_NONE if the lexical+parser structure of the input is valid, * DATA_ERROR_PARSER_STRUCTURE if there is no EOF, * DATA_ERROR_LEXICAL_STRUCTURE otherwise. */ data_error_t json_token_reader_expect_eof ( json_token_reader_t *this_ ); /*! * \brief skips whitespaces * * Whitespaces are skipped as defined in http://rfc7159.net/rfc7159#rfc.section.2 . * If there is no whitespace as next chatacter, the read pointer is not modified. * * \param this_ pointer to own object attributes */ static inline void json_token_reader_private_skip_whitespace ( json_token_reader_t *this_ ); /*! * \brief returns the current line number. * * \param this_ pointer to own object attributes * \return line number, the first line is 1. */ static inline unsigned int json_token_reader_get_input_line ( json_token_reader_t *this_ ); /*! * \brief returns the current stream position. * * \param this_ pointer to own object attributes * \return stream position, 0 if no character has been read. */ static inline size_t json_token_reader_get_input_pos ( json_token_reader_t *this_ ); /*! * \brief checks if the current value-token is ended * * If the next character after the current position * is one of the following: * {, }, [, ], :, comma, space, tab, newline, return, * then the current value-token is ended. * * This function is not suitable to check if a single-character token is ended, * it is intended to check if numbers, strings, true, null, false are finished. * * \param this_ pointer to own object attributes * \return false if input stream read position points to a stand-alone token */ static inline bool json_token_reader_private_is_value_end ( json_token_reader_t *this_ ); /*! * \brief reads a string literal to a utf8stringbuf * * The read pointer shall have passed the delimiting quotes already and will not pass the ending quotes. * * \param this_ pointer to own object attributes * \param out_stream string-contents of the value-token, unmodified including escape sequences * \return DATA_ERROR_STRING_BUFFER_EXCEEDED if out_stream does not provide enough space, * DATA_ERROR_NONE if the lexical+parser structure of the input is valid, * DATA_ERROR_LEXICAL_STRUCTURE otherwise. */ static inline data_error_t json_token_reader_private_read_string ( json_token_reader_t *this_, universal_output_stream_t *out_stream ); /*! * \brief parses the integer token * * The read pointer shall point to the first minus or digit. * * \param this_ pointer to own object attributes * \param[out] out_int parsed integer or 0 in case of error * \return DATA_ERROR_NONE if the lexical+parser structure of the input is valid, * DATA_ERROR_LEXICAL_STRUCTURE otherwise. */ static inline data_error_t json_token_reader_private_parse_integer ( json_token_reader_t *this_, int64_t *out_int ); /*! * \brief skips the number token, numbers are not supported by this parser * * The read pointer shall point to the first minus or digit. * * \param this_ pointer to own object attributes * \return DATA_ERROR_NONE if the lexical+parser structure of the input is valid, * DATA_ERROR_LEXICAL_STRUCTURE otherwise. */ static inline data_error_t json_token_reader_private_skip_number ( json_token_reader_t *this_ ); #include "json/json_token_reader.inl" #endif /* JSON_TOKEN_READER_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/json/json_token_reader.inl000066400000000000000000000162761415120503000243410ustar00rootroot00000000000000/* File: json_token_reader.inl; Copyright and License: see below */ #include "json/json_constants.h" #include "trace.h" #include static inline void json_token_reader_private_skip_whitespace ( json_token_reader_t *this_ ) { bool ws_end_reached = false; char current = ' '; while ( ( ! ws_end_reached ) && ( current != '\0' ) ) { current = universal_buffer_input_stream_peek_next( &((*this_).in_stream) ); if ( ( JSON_CONSTANTS_CHAR_NL != current ) && ( JSON_CONSTANTS_CHAR_CR != current ) && ( JSON_CONSTANTS_CHAR_TAB != current ) && ( JSON_CONSTANTS_CHAR_SPACE != current )) { ws_end_reached = true; } else { universal_buffer_input_stream_read_next( &((*this_).in_stream) ); if ( current == JSON_CONSTANTS_CHAR_NL ) { (*this_).input_line ++; } } } } static inline unsigned int json_token_reader_get_input_line ( json_token_reader_t *this_ ) { return (*this_).input_line; } static inline size_t json_token_reader_get_input_pos ( json_token_reader_t *this_ ) { return universal_buffer_input_stream_read_pos( &((*this_).in_stream) ); } static inline bool json_token_reader_private_is_value_end ( json_token_reader_t *this_ ) { char next = universal_buffer_input_stream_peek_next( &((*this_).in_stream) ); const bool result = (( next == '\0' ) || ( next == JSON_CONSTANTS_CHAR_NL ) || ( next == JSON_CONSTANTS_CHAR_CR ) || ( next == JSON_CONSTANTS_CHAR_TAB ) || ( next == JSON_CONSTANTS_CHAR_SPACE ) || ( next == JSON_CONSTANTS_CHAR_BEGIN_OBJECT ) || ( next == JSON_CONSTANTS_CHAR_END_OBJECT ) || ( next == JSON_CONSTANTS_CHAR_BEGIN_ARRAY ) || ( next == JSON_CONSTANTS_CHAR_END_ARRAY ) || ( next == JSON_CONSTANTS_CHAR_NAME_SEPARATOR ) || ( next == JSON_CONSTANTS_CHAR_VALUE_SEPARATOR )); return result; } static inline data_error_t json_token_reader_private_read_string ( json_token_reader_t *this_, universal_output_stream_t *out_stream ) { assert( out_stream != NULL ); data_error_t result = DATA_ERROR_NONE; bool str_end_reached = false; char esc_incomplete = false; char out_buffer[64]; size_t ouf_buf_len = 0; while ( ! str_end_reached ) { char current = universal_buffer_input_stream_peek_next( &((*this_).in_stream) ); if ( '\0' == current ) { str_end_reached = true; result = DATA_ERROR_LEXICAL_STRUCTURE; } else if (( JSON_CONSTANTS_CHAR_END_STRING == current )&&( ! esc_incomplete )) { str_end_reached = true; } else { assert( ouf_buf_len < sizeof(out_buffer) ); out_buffer[ouf_buf_len] = universal_buffer_input_stream_read_next( &((*this_).in_stream) ); ouf_buf_len ++; } if (( JSON_CONSTANTS_CHAR_ESC == current ) && ( ! esc_incomplete )) { esc_incomplete = true; } else { esc_incomplete = false; if ( ouf_buf_len >= (sizeof(out_buffer)-sizeof(char)) ) { /* only if not in the middle of an escape character, write to out_stream */ const int err = universal_output_stream_write( out_stream, &out_buffer, ouf_buf_len ); ouf_buf_len = 0; if ( err != 0 ) { TRACE_INFO( "could not write all data to output stream in json_token_reader_private_read_string." ); result = DATA_ERROR_STRING_BUFFER_EXCEEDED; } } } } { const int err2 = universal_output_stream_write( out_stream, &out_buffer, ouf_buf_len ); ouf_buf_len = 0; if ( err2 != 0 ) { TRACE_INFO( "could not write all data to output stream in json_token_reader_private_read_string" ); result = DATA_ERROR_STRING_BUFFER_EXCEEDED; } } return result; } static inline data_error_t json_token_reader_private_parse_integer ( json_token_reader_t *this_, int64_t *out_int ) { assert( out_int != NULL ); int64_t result; data_error_t err = DATA_ERROR_NONE; char first = universal_buffer_input_stream_peek_next( &((*this_).in_stream) ); if ( '0' == first ) { /* only zero may begin with digit zero */ result = 0; universal_buffer_input_stream_read_next( &((*this_).in_stream) ); } else { bool minus = false; bool has_digits = false; bool minus_zero_error = false; result = 0; /* check for minus */ if ( '-' == first ) { minus = true; universal_buffer_input_stream_read_next( &((*this_).in_stream) ); if ( '0' == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) ) { /* number starts with -0 which is invalid */ minus_zero_error = true; } } bool int_end_reached = false; while ( ! int_end_reached ) { char current = universal_buffer_input_stream_peek_next( &((*this_).in_stream) ); if (( '0' <= current )&&( current <= '9')) { has_digits = true; universal_buffer_input_stream_read_next( &((*this_).in_stream) ); result = (result*10)+((int) (current-'0')); } else { int_end_reached = true; } } if ( minus ) { result = -result; } if ( ( ! has_digits ) || minus_zero_error ) { result = 0; err = DATA_ERROR_LEXICAL_STRUCTURE; } } *out_int = result; return err; } static inline data_error_t json_token_reader_private_skip_number ( json_token_reader_t *this_ ) { data_error_t result = DATA_ERROR_LEXICAL_STRUCTURE; bool num_end_reached = false; while ( ! num_end_reached ) { char current = universal_buffer_input_stream_peek_next( &((*this_).in_stream) ); if ( (( '0' <= current )&&( current <= '9')) || ( 'e' == current ) || ( 'E' == current ) || ( '.' == current ) || ( '+' == current ) || ( '-' == current ) ) { /* could be part of a valid number */ universal_buffer_input_stream_read_next( &((*this_).in_stream) ); result = DATA_ERROR_NONE; } else { num_end_reached = true; } } return result; } /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/json/json_value_type.h000066400000000000000000000027001415120503000235040ustar00rootroot00000000000000/* File: json_value_type.h; Copyright and License: see below */ #ifndef JSON_VALUE_TYPE_H #define JSON_VALUE_TYPE_H /* public file for the doxygen documentation: */ /*! * \file * \brief Provides an enumeration of JSON value types */ /*! * \brief type constants, see rfc7159#rfc.section.3 */ enum json_value_type_enum { JSON_VALUE_TYPE_UNDEF = 0, /*!< undefined type */ JSON_VALUE_TYPE_OBJECT, /*!< object type */ JSON_VALUE_TYPE_ARRAY, /*!< array type */ JSON_VALUE_TYPE_NUMBER, /*!< number type */ JSON_VALUE_TYPE_INTEGER, /*!< integer subtype of number: numbers without exponent and without fraction */ JSON_VALUE_TYPE_STRING, /*!< string type */ JSON_VALUE_TYPE_BOOLEAN, /*!< false or true literal of type boolean */ JSON_VALUE_TYPE_NULL, /*!< null literal */ }; typedef enum json_value_type_enum json_value_type_t; #endif /* JSON_VALUE_TYPE_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/json/json_writer.h000066400000000000000000000173171415120503000226550ustar00rootroot00000000000000/* File: json_writer.h; Copyright and License: see below */ #ifndef JSON_WRITER_H #define JSON_WRITER_H /* public file for the doxygen documentation: */ /*! * \file * \brief writes strings to an json utf8 stream */ #include "json/json_constants.h" #include "data_diagram.h" #include "data_classifier.h" #include "data_table.h" #include "util/string/utf8string.h" #include "util/string/utf8stringview.h" #include "stream/universal_output_stream.h" #include "stream/universal_escaping_output_stream.h" /*! * \brief constants for max string sizes */ enum json_writer_max_enum { JSON_WRITER_MAX_STRING_SIZE = DATA_DIAGRAM_MAX_DESCRIPTION_LENGTH + DATA_CLASSIFIER_MAX_DESCRIPTION_LENGTH, JSON_WRITER_MAX_INDENT = 7, }; /*! * \brief indentation */ extern const char JSON_CONSTANTS_INDENT[(2*JSON_WRITER_MAX_INDENT)+sizeof('\0')]; /*! * \brief indentation, followed by quote */ extern const char JSON_CONSTANTS_INDENT_QUOTE[(2*JSON_WRITER_MAX_INDENT)+sizeof(JSON_CONSTANTS_QUOTE)]; /*! * \brief attributes of the json writer */ struct json_writer_struct { universal_output_stream_t *output; /*!< output stream where to write the generated document to */ universal_escaping_output_stream_t esc_output; /*!< escaping output stream filter that does the xml escaping */ const char *const ((*json_string_encode_table)[][2]); /*!< table for json encode string replacements */ const char *const ((*json_stringlist_encode_table)[][2]); /*!< table for json encode stringlist replacements */ }; typedef struct json_writer_struct json_writer_t; /*! * \brief initializes the xml writer * * \param this_ pointer to own object attributes * \param output output stream where to write the generated document to */ void json_writer_init( json_writer_t *this_, universal_output_stream_t *output ); /*! * \brief destroys the xml writer * * \param this_ pointer to own object attributes */ void json_writer_destroy( json_writer_t *this_ ); /*! * \brief writes a string to a file, unencoded * * \param this_ pointer to own object attributes * \param text string to write * \return 0 in case of success, -1 otherwise */ static inline int json_writer_write_plain ( json_writer_t *this_, utf8string_t text ); /*! * \brief writes stringview to a file, unencoded * * \param this_ pointer to own object attributes * \param string_view stringview to write, not 0-terminated * \return 0 in case of success, -1 otherwise */ static inline int json_writer_write_plain_view ( json_writer_t *this_, utf8stringview_t string_view ); /*! * \brief prints an id * * if the id is invalid, nothing is printed. * * \param this_ pointer to own object attributes * \param id the identifier * \return 0 in case of success, -1 otherwise */ int json_writer_write_plain_id ( json_writer_t *this_, data_id_t id ); /*! * \brief prints an integer * * \param this_ pointer to own object attributes * \param number the integer to print * \return 0 in case of success, -1 otherwise */ int json_writer_write_int ( json_writer_t *this_, int64_t number ); /*! * \brief writes a string to a file, json-string encoded * * \param this_ pointer to own object attributes * \param text string to write * \return 0 in case of success, -1 otherwise */ static inline int json_writer_write_string_enc ( json_writer_t *this_, utf8string_t text ); /*! * \brief writes a stringview to a file, json-string encoded * * \param this_ pointer to own object attributes * \param string_view stringview to write, not 0-terminated * \return 0 in case of success, -1 otherwise */ static inline int json_writer_write_string_view_enc ( json_writer_t *this_, utf8stringview_t string_view ); /*! * \brief writes a string to a file, encoded as list of json-strings, one string per line * * \param this_ pointer to own object attributes * \param text string to write, encoded for xml comments * \return 0 in case of success, -1 otherwise */ static inline int json_writer_write_stringlist_enc ( json_writer_t *this_, utf8string_t text ); /*! * \brief writes a stringview to a file, encoded as list of json-strings, one string per line * * \param this_ pointer to own object attributes * \param string_view stringview to write, not 0-terminated * \return 0 in case of success, -1 otherwise */ static inline int json_writer_write_stringlist_view_enc ( json_writer_t *this_, utf8stringview_t string_view ); /*! * \brief writes a member name and a value integer * * \param this_ pointer to own object attributes * \param indent indentation level: number of tabs, 0 <= indent <= JSON_WRITER_MAX_INDENT * \param enc_name name of the object member, json encoded string * \param number the integer to print * \param next_follows true if another member follows (a comma will be printed) * \return 0 in case of success, -1 otherwise */ static inline int json_writer_write_member_int ( json_writer_t *this_, unsigned int indent, utf8string_t enc_name, int64_t number_value, bool next_follows ); /*! * \brief writes a member name and an string, the value string is being json encoded * * \param this_ pointer to own object attributes * \param indent indentation level: number of tabs, 0 <= indent <= JSON_WRITER_MAX_INDENT * \param enc_name name of the object member, json encoded string * \param unenc_value string to write, being json encoded * \param next_follows true if another member follows (a comma will be printed) * \return 0 in case of success, -1 otherwise */ static inline int json_writer_write_member_string ( json_writer_t *this_, unsigned int indent, utf8string_t enc_name, utf8string_t unenc_value, bool next_follows ); /*! * \brief writes a member name and an string, * the value string is split at newlines and being json array encoded * * \param this_ pointer to own object attributes * \param indent indentation level: number of tabs, 0 <= indent <= JSON_WRITER_MAX_INDENT * \param enc_name name of the object member, json encoded string * \param unenc_value string to write, being json encoded * \param next_follows true if another member follows (a comma will be printed) * \return 0 in case of success, -1 otherwise */ static inline int json_writer_write_member_string_array ( json_writer_t *this_, unsigned int indent, utf8string_t enc_name, utf8string_t unenc_value, bool next_follows ); #include "json_writer.inl" #endif /* JSON_WRITER_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/json/json_writer.inl000066400000000000000000000204061415120503000232010ustar00rootroot00000000000000/* File: json_writer.inl; Copyright and License: see below */ #include #include "util/string/utf8error.h" #include "util/string/utf8codepoint.h" #include "util/string/utf8codepointiterator.h" static inline int json_writer_write_plain ( json_writer_t *this_, utf8string_t text ) { assert ( UTF8STRING_NULL != text ); int write_err; const size_t text_len = utf8string_get_length(text); write_err = universal_output_stream_write ( (*this_).output, text, text_len ); return ( write_err ); } static inline int json_writer_write_plain_view ( json_writer_t *this_, utf8stringview_t string_view ) { int write_err; const size_t length = utf8stringview_get_length( string_view ); const char *const start = utf8stringview_get_start( string_view ); write_err = universal_output_stream_write( (*this_).output, start, length ); return ( write_err ); } static inline int json_writer_write_string_enc ( json_writer_t *this_, utf8string_t text ) { assert ( UTF8STRING_NULL != text ); int write_err; const size_t text_len = utf8string_get_length(text); universal_escaping_output_stream_change_rules( &((*this_).esc_output), (*this_).json_string_encode_table ); write_err = universal_escaping_output_stream_write( &((*this_).esc_output), text, text_len ); universal_escaping_output_stream_flush( &((*this_).esc_output) ); return write_err; } static inline int json_writer_write_string_view_enc ( json_writer_t *this_, utf8stringview_t string_view ) { int write_err; const size_t length = utf8stringview_get_length( string_view ); const char *const start = utf8stringview_get_start( string_view ); universal_escaping_output_stream_change_rules( &((*this_).esc_output), (*this_).json_string_encode_table ); write_err = universal_escaping_output_stream_write( &((*this_).esc_output), start, length ); universal_escaping_output_stream_flush( &((*this_).esc_output) ); return write_err; } static inline int json_writer_write_stringlist_enc ( json_writer_t *this_, utf8string_t text ) { assert ( UTF8STRING_NULL != text ); int write_err; const size_t text_len = utf8string_get_length(text); universal_escaping_output_stream_change_rules( &((*this_).esc_output), (*this_).json_stringlist_encode_table ); write_err = universal_escaping_output_stream_write( &((*this_).esc_output), text, text_len ); universal_escaping_output_stream_flush( &((*this_).esc_output) ); return write_err; } static inline int json_writer_write_stringlist_view_enc ( json_writer_t *this_, utf8stringview_t string_view ) { int write_err; const size_t length = utf8stringview_get_length( string_view ); const char *const start = utf8stringview_get_start( string_view ); universal_escaping_output_stream_change_rules( &((*this_).esc_output), (*this_).json_stringlist_encode_table ); write_err = universal_escaping_output_stream_write( &((*this_).esc_output), start, length ); universal_escaping_output_stream_flush( &((*this_).esc_output) ); return write_err; } static inline int json_writer_write_member_int ( json_writer_t *this_, unsigned int indent, utf8string_t enc_name, int64_t number_value, bool next_follows ) { assert( 7 == JSON_WRITER_MAX_INDENT ); assert( indent <= JSON_WRITER_MAX_INDENT ); int write_err; write_err = json_writer_write_plain( this_, &(JSON_CONSTANTS_INDENT_QUOTE[2*(JSON_WRITER_MAX_INDENT-indent)]) ); write_err |= json_writer_write_plain( this_, enc_name ); write_err |= json_writer_write_plain( this_, JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF ); write_err |= json_writer_write_int( this_, number_value ); write_err |= json_writer_write_plain( this_, next_follows ? JSON_CONSTANTS_NEXT_NL : JSON_CONSTANTS_NL ); return write_err; } static inline int json_writer_write_member_string ( json_writer_t *this_, unsigned int indent, utf8string_t enc_name, utf8string_t unenc_value, bool next_follows ) { assert( 7 == JSON_WRITER_MAX_INDENT ); assert( indent <= JSON_WRITER_MAX_INDENT ); int write_err; write_err = json_writer_write_plain( this_, &(JSON_CONSTANTS_INDENT_QUOTE[2*(JSON_WRITER_MAX_INDENT-indent)]) ); write_err |= json_writer_write_plain( this_, enc_name ); write_err |= json_writer_write_plain( this_, JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF JSON_CONSTANTS_QUOTE ); write_err |= json_writer_write_string_enc( this_, unenc_value ); write_err |= json_writer_write_plain( this_, next_follows ? JSON_CONSTANTS_QUOTE JSON_CONSTANTS_NEXT_NL : JSON_CONSTANTS_QUOTE JSON_CONSTANTS_NL ); return write_err; } static inline int json_writer_write_member_string_array ( json_writer_t *this_, unsigned int indent, utf8string_t enc_name, utf8string_t unenc_value, bool next_follows ) { assert( 7 == JSON_WRITER_MAX_INDENT ); assert( indent <= JSON_WRITER_MAX_INDENT ); int write_err; write_err = json_writer_write_plain( this_, &(JSON_CONSTANTS_INDENT_QUOTE[2*(JSON_WRITER_MAX_INDENT-indent)]) ); write_err |= json_writer_write_plain( this_, enc_name ); write_err |= json_writer_write_plain( this_, JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF JSON_CONSTANTS_BEGIN_ARRAY JSON_CONSTANTS_NL JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE ); write_err |= json_writer_write_stringlist_enc( this_, unenc_value ); write_err |= json_writer_write_plain( this_, JSON_CONSTANTS_QUOTE JSON_CONSTANTS_NL ); write_err = json_writer_write_plain( this_, &(JSON_CONSTANTS_INDENT[2*(JSON_WRITER_MAX_INDENT-indent)]) ); write_err |= json_writer_write_plain( this_, next_follows ? JSON_CONSTANTS_END_ARRAY JSON_CONSTANTS_NEXT_NL : JSON_CONSTANTS_END_ARRAY JSON_CONSTANTS_NL ); return write_err; } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/json/json_writer_pass.h000066400000000000000000000023721415120503000236760ustar00rootroot00000000000000/* File: json_writer_pass.h; Copyright and License: see below */ #ifndef JSON_WRITER_PASS_H #define JSON_WRITER_PASS_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines the semantics of multiple model-traversal-passes */ /*! * \brief constants for output mode: classifiers+features, relationships, diagrams */ enum json_writer_pass_enum { JSON_WRITER_PASS_VIEWS = 0, /*!< mode diagrams and diagramelements output */ JSON_WRITER_PASS_NODES = 1, /*!< mode for classifiers and features output */ JSON_WRITER_PASS_EDGES = 2, /*!< mode for relationships output */ }; typedef enum json_writer_pass_enum json_writer_pass_t; #endif /* JSON_WRITER_PASS_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/md/000077500000000000000000000000001415120503000175555ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/include/md/md_filter.h000066400000000000000000000060351415120503000216770ustar00rootroot00000000000000/* File: md_filter.h; Copyright and License: see below */ #ifndef MD_FILTER_H #define MD_FILTER_H /* public file for the doxygen documentation: */ /*! * \file * \brief parses some md-like and link features of the input string to an xml writer. * * This class is a filter in the sense of the pipes-and-filters architecture pattern: * It modifies and enriches the piped-through data. */ #include "xml/xml_writer.h" #include "util/string/utf8stringbuf.h" #include "storage/data_database_reader.h" #include "data_diagram.h" /*! * \brief constants for max string sizes */ enum md_filter_max_enum { MD_FILTER_MAX_STRING_SIZE = DATA_DIAGRAM_MAX_DESCRIPTION_LENGTH + DATA_CLASSIFIER_MAX_DESCRIPTION_LENGTH, }; /*! * \brief attributes of the xml writer */ struct md_filter_struct { data_database_reader_t *db_reader; /*!< pointer to external database reader */ xml_writer_t *sink; /*!< output sink */ const char * tag_linebreak; /*!< tag for linebreak */ const char * tag_xref_start; /*!< tag for xref_start */ const char * tag_xref_middle; /*!< tag for xref_middle */ const char * tag_xref_end; /*!< tag for xref_end */ data_diagram_t temp_diagram; /*!< memory for temporary diagram storage */ }; typedef struct md_filter_struct md_filter_t; /*! * \brief initializes the document exporter * * \param this_ pointer to own object attributes * \param db_reader pointer to a database reader object * \param tag_linebreak tag for linebreak * \param tag_xref_start tag for xref_start * \param tag_xref_middle tag for xref_middle * \param tag_xref_end tag for xref_end * \param sink stream sink where to write the output to */ void md_filter_init( md_filter_t *this_, data_database_reader_t *db_reader, const char * tag_linebreak, const char * tag_xref_start, const char * tag_xref_middle, const char * tag_xref_end, xml_writer_t *sink ); /*! * \brief destroys the document exporter * * \param this_ pointer to own object attributes */ void md_filter_destroy( md_filter_t *this_ ); /*! * \brief parses the string, enriches it by links and paragraph-breaks and writes it to the sink * * \param this_ pointer to own object attributes * \param text string to parse * \return 0 in case of success, -1 otherwise */ int md_filter_transform ( md_filter_t *this_, const char *text ); #endif /* MD_FILTER_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/txt/000077500000000000000000000000001415120503000177745ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/include/txt/txt_writer.h000066400000000000000000000071111415120503000223600ustar00rootroot00000000000000/* File: txt_writer.h; Copyright and License: see below */ #ifndef TXT_WRITER_H #define TXT_WRITER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Exports a document in plain txt format */ #include "io_file_format.h" #include "xml/xml_writer.h" #include "data_diagram.h" #include "data_classifier.h" #include "set/data_visible_set.h" #include "util/geometry/geometry_rectangle.h" #include "util/string/utf8stringbuf.h" #include "stream/universal_output_stream.h" #include /*! * \brief attributes of the txt writer */ struct txt_writer_struct { universal_output_stream_t *output; /*!< output stream where to write the generated document to */ }; typedef struct txt_writer_struct txt_writer_t; /*! * \brief initializes the txt writer * * \param this_ pointer to own object attributes * \param output output stream where to write the generated document to */ void txt_writer_init( txt_writer_t *this_, universal_output_stream_t *output ); /*! * \brief destroys the txt writer * * \param this_ pointer to own object attributes */ void txt_writer_destroy( txt_writer_t *this_ ); /*! * \brief writes a string to a file * * \param this_ pointer to own object attributes * \param text string to write * \return 0 in case of success, -1 otherwise */ static inline int txt_writer_write_plain ( txt_writer_t *this_, const char *text ); /*! * \brief prints a multiline string with indentation prefix * * if the string is empty, no character is written. If the last line is not empty, an additional newline is appended. * newline, return and return-newline are recognized as line breaks. * * \param this_ pointer to own object attributes * \param indent pattern, by which each line is indented; must not be NULL * \param multiline_string string to write to out * \return 0 in case of success, -1 otherwise */ int txt_writer_write_indent_multiline_string ( txt_writer_t *this_, const char *indent, const char *multiline_string ); /*! * \brief prints an id with indentation prefix and surrounding brackets * * if the id is invalid, nothing is printed. * * \param this_ pointer to own object attributes * \param indent_width number of space-characters, by which each line is indented. Negative values cause a zero-indent. * \param id identifier * \return 0 in case of success, -1 otherwise */ int txt_writer_write_indent_id ( txt_writer_t *this_, int indent_width, data_id_t id ); /*! * \brief prints an id * * if the id is invalid, nothing is printed. * * \param this_ pointer to own object attributes * \param id identifier * \return 0 in case of success, -1 otherwise */ int txt_writer_write_plain_id ( txt_writer_t *this_, data_id_t id ); #include "txt_writer.inl" #endif /* TXT_WRITER_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/txt/txt_writer.inl000066400000000000000000000017661415120503000227250ustar00rootroot00000000000000/* File: xml_writer.inl; Copyright and License: see below */ #include #include "util/string/utf8error.h" static inline int txt_writer_write_plain ( txt_writer_t *this_, const char *text ) { assert ( NULL != text ); assert ( NULL != (*this_).output ); int write_err; const size_t text_len = strlen(text); write_err = universal_output_stream_write ( (*this_).output, text, text_len ); return ( write_err ); } /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/xhtml/000077500000000000000000000000001415120503000203115ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/include/xhtml/xhtml_element_writer.h000066400000000000000000000414371415120503000247340ustar00rootroot00000000000000/* File: xhtml_element_writer.h; Copyright and License: see below */ #ifndef XHTML_ELEMENT_WRITER_H #define XHTML_ELEMENT_WRITER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Writes several document pieces to one file output stream. * * Source: io_exporter and io_export_diagram_traversal; * Task: convert model-elements to an output stream (using an own txt/xml/... writer); * Sink: universal_output_stream_t */ #include "io_element_writer.h" #include "io_file_format.h" #include "xmi/xmi_writer_pass.h" #include "xml/xml_writer.h" #include "txt/txt_writer.h" #include "xmi/xmi_type_converter.h" #include "md/md_filter.h" #include "data_diagram.h" #include "data_classifier.h" #include "set/data_visible_set.h" #include "set/data_stat.h" #include "storage/data_database_reader.h" #include "util/string/utf8stringbuf.h" #include "stream/universal_output_stream.h" /*! * \brief attributes of the element writer */ struct xhtml_element_writer_struct { io_element_writer_t element_writer; /*!< instance of implemented interface \c io_element_writer_t */ data_stat_t *export_stat; /*!< pointer to external statistics object where export statistics are collected */ io_file_format_t export_type; /*!< format of output document */ uint32_t current_tree_depth; /*!< tree depth in diagram tree, starts at 0, increases with every call to xhtml_element_writer_start_diagram */ txt_writer_t txt_writer; /*!< own instance of a txt writer */ xml_writer_t xml_writer; /*!< own instance of an xml writer */ md_filter_t md_filter; /*!< own instance of an md filter */ }; typedef struct xhtml_element_writer_struct xhtml_element_writer_t; /*! * \brief initializes the element writer * * \param this_ pointer to own object attributes * \param db_reader pointer to a database reader object * \param export_type image file format * \param io_export_stat pointer to statistics object where export statistics are collected * \param output output stream where to write the generated output to */ void xhtml_element_writer_init( xhtml_element_writer_t *this_, data_database_reader_t *db_reader, io_file_format_t export_type, data_stat_t *io_export_stat, universal_output_stream_t *output ); /*! * \brief destroys the element writer * * \param this_ pointer to own object attributes */ void xhtml_element_writer_destroy( xhtml_element_writer_t *this_ ); /*! * \brief gets the io element writer interface of this xhtml_element_writer_t * * \param this_ pointer to own object attributes * \return the abstract base class of this_ */ io_element_writer_t * xhtml_element_writer_get_element_writer( xhtml_element_writer_t *this_ ); /*! * \brief writes the header of the document * * \param this_ pointer to own object attributes * \param document_title title of the document * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_write_header( xhtml_element_writer_t *this_, const char *document_title ); /*! * \brief writes the start of the main section * * This starts a section that contains the main part of the document * * \param this_ pointer to own object attributes * \param document_title title of the document * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_start_main( xhtml_element_writer_t *this_, const char *document_title ); /*! * \brief checks if a hosting parent classifier may nest a child classifier * * \param this_ pointer to own object attributes * \param host_type data_classifier_type_t of the hosting parent of which the nesting-ability shall be determined * \param child_type data_classifier_type_t of the nested child of which the nesting-ability shall be determined * \return true if nesting is allowed */ bool xhtml_element_writer_can_classifier_nest_classifier( xhtml_element_writer_t *this_, data_classifier_type_t host_type, data_classifier_type_t child_type ); /*! * \brief checks if a hosting parent classifier may nest relationships * * \param this_ pointer to own object attributes * \param host_type data_classifier_type_t of the hosting parent of which the nesting-ability shall be determined * \param child_type data_relationship_type_t of the nested child of which the nesting-ability shall be determined * \return true if nesting or any relationship is allowed */ bool xhtml_element_writer_can_classifier_nest_relationship( xhtml_element_writer_t *this_, data_classifier_type_t host_type, data_relationship_type_t child_type ); /*! * \brief starts a table-of-contents sublist * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_start_toc_sublist ( xhtml_element_writer_t *this_ ); /*! * \brief starts a table-of-contents entry, consisting of an entry and an optional sublist * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_start_toc_entry ( xhtml_element_writer_t *this_ ); /*! * \brief writes a table-of-contents entry * * \param this_ pointer to own object attributes * \param diag_ptr pointer to diagram that shall be written * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_write_toc_entry ( xhtml_element_writer_t *this_, const data_diagram_t *diag_ptr ); /*! * \brief end a table-of-contents entry, consisting of an entry and an optional sublist * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_end_toc_entry ( xhtml_element_writer_t *this_ ); /*! * \brief end a table-of-contents sublist * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_end_toc_sublist ( xhtml_element_writer_t *this_ ); /*! * \brief writes a classifier start * * This starts a division that contains a classifier and a list of features and relationships * * \param this_ pointer to own object attributes * \param host_type type of the hosting parent classifier, needed for xmi export, DATA_CLASSIFIER_TYPE_VOID if toplevel * \param classifier_ptr pointer to classifier that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_start_classifier( xhtml_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ); /*! * \brief writes a classifier of the document * * \param this_ pointer to own object attributes * \param host_type type of the hosting parent classifier, needed for xmi export, DATA_CLASSIFIER_TYPE_VOID if toplevel * \param classifier_ptr pointer to classifier that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_assemble_classifier( xhtml_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ); /*! * \brief writes a classifier end * * This ends a division that contains a classifier and a list of features and relationships * * \param this_ pointer to own object attributes * \param host_type type of the hosting parent classifier, needed for xmi export, DATA_CLASSIFIER_TYPE_VOID if toplevel * \param classifier_ptr pointer to classifier that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_end_classifier( xhtml_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ); /*! * \brief writes a feature start-element * * \param this_ pointer to own object attributes * \param parent_type type of the owning parent classifier * \param feature_ptr pointer to feature that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_start_feature( xhtml_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ); /*! * \brief writes a feature of the document * * \param this_ pointer to own object attributes * \param parent_type type of the owning parent classifier * \param feature_ptr pointer to feature that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_assemble_feature( xhtml_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ); /*! * \brief writes a feature end-element * * \param this_ pointer to own object attributes * \param parent_type type of the owning parent classifier * \param feature_ptr pointer to feature that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_end_feature( xhtml_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ); /*! * \brief starts a relationship * * \param this_ pointer to own object attributes * \param host_type type of the hosting parent classifier, needed for xmi export * \param relation_ptr pointer to relationship that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_start_relationship( xhtml_element_writer_t *this_, data_classifier_type_t host_type, const data_relationship_t *relation_ptr ); /*! * \brief writes a relationship of the document * * \param this_ pointer to own object attributes * \param host the hosting parent classifier, needed for xmi export; is NULL on top-level of document * \param relation_ptr pointer to relationship that shall be written, not NULL * \param from_c the classifier at source end * \param from_f the feature at source end; NULL or !is_valid() if no feature specified * \param to_c the classifier at target end * \param to_f the feature at target end; NULL or !is_valid() if no feature specified * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_assemble_relationship( xhtml_element_writer_t *this_, const data_classifier_t *host, const data_relationship_t *relation_ptr, const data_classifier_t *from_c, const data_feature_t *from_f, const data_classifier_t *to_c, const data_feature_t *to_f ); /*! * \brief ends a relationship * * \param this_ pointer to own object attributes * \param host_type type of the hosting parent classifier, needed for xmi export * \param relation_ptr pointer to relationship that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_end_relationship( xhtml_element_writer_t *this_, data_classifier_type_t host_type, const data_relationship_t *relation_ptr ); /*! * \brief writes a diagram start * * This starts a section that contains a diagram and a list of classifiers * * \param this_ pointer to own object attributes * \param diag_ptr pointer to diagram that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_start_diagram( xhtml_element_writer_t *this_, const data_diagram_t *diag_ptr ); /*! * \brief writes a diagram of the document * * \param this_ pointer to own object attributes * \param parent pointer to parent diagram or NULL in case of root * \param diag_ptr pointer to diagram that shall be written * \param diagram_file_base_name filename of the diagram without extension * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_assemble_diagram( xhtml_element_writer_t *this_, const data_diagram_t *parent, const data_diagram_t *diag_ptr, const char *diagram_file_base_name ); /*! * \brief writes a diagram end * * This ends a section that contains a diagram and a list of classifiers * * \param this_ pointer to own object attributes * \param diag_ptr pointer to diagram that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_end_diagram( xhtml_element_writer_t *this_, const data_diagram_t *diag_ptr ); /*! * \brief writes a diagramelement start-element * * \param this_ pointer to own object attributes * \param parent the hosting parent diagram * \param diagramelement_ptr pointer to diagramelement that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_start_diagramelement( xhtml_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr ); /*! * \brief writes constents of a a diagramelement * * \param this_ pointer to own object attributes * \param parent the hosting parent diagram * \param diagramelement_ptr pointer to diagramelement that shall be written, not NULL * \param occurrence the occurring classifier * \param feat_occur the focused feature of the occurring classifier * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_assemble_diagramelement( xhtml_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr, const data_classifier_t *occurrence, const data_feature_t *feat_occur ); /*! * \brief writes a diagramelement end-element * * \param this_ pointer to own object attributes * \param parent the hosting parent diagram * \param diagramelement_ptr pointer to diagramelement that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_end_diagramelement( xhtml_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr ); /*! * \brief writes the ending of the main section * * This ends a section that contains the main part of the document * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_end_main( xhtml_element_writer_t *this_ ); /*! * \brief writes the footer of the document * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int xhtml_element_writer_write_footer( xhtml_element_writer_t *this_ ); #endif /* XHTML_ELEMENT_WRITER_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/xhtml/xhtml_stylesheet_writer.h000066400000000000000000000036201415120503000254640ustar00rootroot00000000000000/* File: xhtml_stylesheet_writer.h; Copyright and License: see below */ #ifndef XHTML_STYLESHEET_WRITER_H #define XHTML_STYLESHEET_WRITER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Writes a css stylesheet to one file output stream. */ #include "stream/universal_output_stream.h" /*! * \brief attributes of the format writer */ struct xhtml_stylesheet_writer_struct { universal_output_stream_t *output; /*!< reference to a universal_output_stream_t */ }; typedef struct xhtml_stylesheet_writer_struct xhtml_stylesheet_writer_t; /*! * \brief initializes the format writer * * \param this_ pointer to own object attributes * \param output output stream where to write the generated output to */ void xhtml_stylesheet_writer_init( xhtml_stylesheet_writer_t *this_, universal_output_stream_t *output ); /*! * \brief destroys the format writer * * \param this_ pointer to own object attributes */ void xhtml_stylesheet_writer_destroy( xhtml_stylesheet_writer_t *this_ ); /*! * \brief writes a css stylesheet file * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int xhtml_stylesheet_writer_write_stylesheet( xhtml_stylesheet_writer_t *this_ ); #endif /* XHTML_STYLESHEET_WRITER_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/xmi/000077500000000000000000000000001415120503000177525ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/include/xmi/xmi_atom_writer.h000066400000000000000000000250661415120503000233450ustar00rootroot00000000000000/* File: xmi_atom_writer.h; Copyright and License: see below */ #ifndef XMI_ATOM_WRITER_H #define XMI_ATOM_WRITER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Writes xml fragments which represent parts of xmi elements to one file output stream. * * Source: io_exporter and io_export_model_traversal_t; * Task: convert model-elements to an output stream (using an own xml writer); * Sink: universal_output_stream_t */ #include "xml/xml_writer.h" #include "md/md_filter.h" #include "storage/data_database_reader.h" #include "util/string/utf8stringbuf.h" #include "stream/universal_output_stream.h" /*! * \brief attributes of the xmi_atom_writer_t */ struct xmi_atom_writer_struct { xml_writer_t *xml_writer; /*!< pointer to external xml writer */ }; typedef struct xmi_atom_writer_struct xmi_atom_writer_t; /*! * \brief initializes the xmi_atom_writer_t * * \param this_ pointer to own object attributes * \param out_writer output stream where to write the generated output to */ void xmi_atom_writer_init( xmi_atom_writer_t *this_, xml_writer_t *out_writer ); /*! * \brief destroys the xmi_atom_writer_t * * \param this_ pointer to own object attributes */ void xmi_atom_writer_destroy( xmi_atom_writer_t *this_ ); /*! * \brief writes a comment in xmi format * * \param this_ pointer to own object attributes * \param element_id id of the element which to write a comment for * \param comment_type type is typically spec - but maybe there are other types in future * \param comment the comment to encode and write * \return 0 in case of success, -1 otherwise */ int xmi_atom_writer_write_xmi_comment( xmi_atom_writer_t *this_, data_id_t element_id, const char *comment_type, const char *comment ); /*! * \brief encodes a data_id to an xml number (as required for xmi base_Class attribute) * * \param this_ pointer to own object attributes * \param element_id id which to encode for xmi * \return 0 in case of success, -1 otherwise */ int xmi_atom_writer_encode_xmi_id( xmi_atom_writer_t *this_, data_id_t element_id ); /*! * \brief reports an issue as comment in xmi output: a classifier has an unknown type * * This can happen if the database was created with a newer version of this program. * * \param this_ pointer to own object attributes * \param fact_classifier_id the id of classifier object * \param fact_classifier_type type of the classifier object * \return 0 in case of success, -1 otherwise */ int xmi_atom_writer_report_unknown_classifier( xmi_atom_writer_t *this_, data_id_t fact_classifier_id, data_classifier_type_t fact_classifier_type ); /*! * \brief reports an issue as comment in xmi output: a feature has an unknown type * * This can happen if the database was created with a newer version of this program. * * \param this_ pointer to own object attributes * \param fact_feature_id the id of feature object * \param fact_feature_type type of the feature object * \return 0 in case of success, -1 otherwise */ int xmi_atom_writer_report_unknown_feature( xmi_atom_writer_t *this_, data_id_t fact_feature_id, data_feature_type_t fact_feature_type ); /*! * \brief reports an issue as comment in xmi output: a relationship has an unknown type * * This can happen if the database was created with a newer version of this program. * * \param this_ pointer to own object attributes * \param fact_relationship_id the id of relationship object * \param fact_relationship_type type of the relationship object * \return 0 in case of success, -1 otherwise */ int xmi_atom_writer_report_unknown_relationship( xmi_atom_writer_t *this_, data_id_t fact_relationship_id, data_relationship_type_t fact_relationship_type ); /*! * \brief reports an issue as comment in xmi output: a container shall not contain the classifier of given type * * The report consists of three sentences: * A fact that is observed, * a rule that is not adhered, * a solution that is proposed. * * \param this_ pointer to own object attributes * \param fact_classifier_id the id of contained/nested classifier object * \param fact_classifier_type type of the container/host classifier object * \param fact_parent_type type of the container/host object * \return 0 in case of success, -1 otherwise */ int xmi_atom_writer_report_illegal_container( xmi_atom_writer_t *this_, data_id_t fact_classifier_id, data_classifier_type_t fact_classifier_type, data_classifier_type_t fact_parent_type ); /*! * \brief reports an issue as comment in xmi output: a stereotype has no valid tag-name characters * * The report consists of three sentences: * A fact that is observed, * a rule that is not adhered, * a solution that is proposed. * * \param this_ pointer to own object attributes * \param element_id the id of the element * \param stereotype stereotype of the element * \return 0 in case of success, -1 otherwise */ int xmi_atom_writer_report_illegal_stereotype( xmi_atom_writer_t *this_, data_id_t element_id, utf8stringview_t stereotype ); /*! * \brief reports an issue as comment in xmi output: an element has a datatype/valuetype but is not a typed element * * The report consists of three sentences: * A fact that is observed, * a rule that is not adhered, * a solution that is proposed. * * \param this_ pointer to own object attributes * \param feature_id the id of the feature * \param datatype datatype/valuetype of the feature * \return 0 in case of success, -1 otherwise */ int xmi_atom_writer_report_illegal_datatype( xmi_atom_writer_t *this_, data_id_t feature_id, const char * datatype ); /*! * \brief reports an issue as comment in xmi output: a parent shall not contain the feature of given type * * The report consists of three sentences: * A fact that is observed, * a rule that is not adhered, * a solution that is proposed. * * \param this_ pointer to own object attributes * \param fact_feature_id the id of child feature object * \param fact_feature_type type of the child feature object * \param fact_parent_type type of the parent object * \return 0 in case of success, -1 otherwise */ int xmi_atom_writer_report_illegal_parent( xmi_atom_writer_t *this_, data_id_t fact_feature_id, data_feature_type_t fact_feature_type, data_classifier_type_t fact_parent_type ); /*! * \brief reports an issue as comment in xmi output: the relationship of given type cannot be put to a location * * The report consists of three sentences: * A fact that is observed, * a rule that is not adhered, * a solution that is proposed. * * \param this_ pointer to own object attributes * \param fact_relationship_id the id of child feature object * \param fact_relationship_type type of the child feature object * \param fact_hosting_type type of the location/host object * \return 0 in case of success, -1 otherwise */ int xmi_atom_writer_report_illegal_location( xmi_atom_writer_t *this_, data_id_t fact_relationship_id, data_relationship_type_t fact_relationship_type, data_classifier_type_t fact_hosting_type ); /*! * \brief reports an issue as comment in xmi output: the relationship of given type cannot end at given type * * The report consists of three sentences: * A fact that is observed, * a rule that is not adhered, * a solution that is proposed. * * \param this_ pointer to own object attributes * \param fact_relationship_id the id of child feature object * \param fact_relationship_type type of the child feature object * \param fact_hosting_type type of the location/host object * \param fact_from_end true if the source(from) end, is requested, false if the target(to) end is requested. * \param fact_end_classifier_type the type of classifier at relationship-end * \param fact_end_feature_type the type of feature at relationship-end; DATA_FEATURE_TYPE_VOID if no feature specified * \return 0 in case of success, -1 in case of write error */ int xmi_atom_writer_report_illegal_relationship_end ( xmi_atom_writer_t *this_, data_id_t fact_relationship_id, data_relationship_type_t fact_relationship_type, data_classifier_type_t fact_hosting_type, bool fact_from_end, data_classifier_type_t fact_end_classifier_type, data_feature_type_t fact_end_feature_type ); #endif /* XMI_ATOM_WRITER_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/xmi/xmi_element_info.h000066400000000000000000000235441415120503000234540ustar00rootroot00000000000000/* File: xmi_element_info.h; Copyright and License: see below */ #ifndef XMI_ELEMENT_INFO_H #define XMI_ELEMENT_INFO_H /* public file for the doxygen documentation: */ /*! * \file * \brief Stores static data on xmi type names, type hierarchies and property names */ #include "xmi_spec.h" #include "xmi/xmi_element_is_a.h" #include "data_classifier_type.h" #include "data_feature_type.h" #include "data_relationship_type.h" #include /*! * \brief defines static data on xmi type name, type hierarchy and property names */ struct xmi_element_info_struct { int data_type_checksum; /*!< a checksum to assert that the program is still consistent */ xmi_spec_t specification; /*!< a bitfield stating which spec defines this, e.g. (XMI_SPEC_UML|XMI_SPEC_SYSML) */ const char * profile_name; /*!< name of the profile extension-type, NULL if not applicable */ const char * base_name; /*!< name of the uml element type */ xmi_element_is_a_t is_a; /*!< states if the type is a decendant of which parent types */ const char * property_from; /*!< in case of a relationship, states the property-name of the source end; NULL otherwise */ const char * property_to; /*!< in case of a relationship, states the property-name of the target end; NULL otherwise */ const char * additional_properties; /*!< additional xml attributes that are fix for this type; NULL if none */ }; typedef struct xmi_element_info_struct xmi_element_info_t; /*! * \brief gets the data_type_checksum. * * \param this_ pointer to own object attributes * \return data_type_checksum */ static inline int xmi_element_info_get_data_type_checksum ( const xmi_element_info_t *this_ ); /*! * \brief gets the specification. * * \param this_ pointer to own object attributes * \return specification */ static inline xmi_spec_t xmi_element_info_get_specification ( const xmi_element_info_t *this_ ); /*! * \brief gets the profile_name. * * \param this_ pointer to own object attributes * \return profile_name or NULL if not applicable */ static inline const char * xmi_element_info_get_profile_name ( const xmi_element_info_t *this_ ); /*! * \brief gets the base_name. * * \param this_ pointer to own object attributes * \return base_name */ static inline const char * xmi_element_info_get_base_name ( const xmi_element_info_t *this_ ); /*! * \brief gets the profile_name if not NULL, the base_name otherwise. * * \param this_ pointer to own object attributes * \return profile_name or base_name */ static inline const char * xmi_element_info_get_name ( const xmi_element_info_t *this_ ); /*! * \brief gets the property_from. * * \param this_ pointer to own object attributes * \return property_from or NULL if not applicable */ static inline const char * xmi_element_info_get_property_from ( const xmi_element_info_t *this_ ); /*! * \brief gets the property_to. * * \param this_ pointer to own object attributes * \return property_to or NULL if not applicable */ static inline const char * xmi_element_info_get_property_to ( const xmi_element_info_t *this_ ); /*! * \brief gets the additional_properties. * * \param this_ pointer to own object attributes * \return additional_properties or NULL if not applicable */ static inline const char * xmi_element_info_get_additional_properties ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a encapsulated_classifier. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_ENCAPSULATED_CLASSIFIER bits set */ static inline bool xmi_element_info_is_a_encapsulated_classifier ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a classifier. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_CLASSIFIER bits set */ static inline bool xmi_element_info_is_a_classifier ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a comment. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_COMMENT bits set */ static inline bool xmi_element_info_is_a_comment ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a behavior. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_BEHAVIOR bits set */ static inline bool xmi_element_info_is_a_behavior ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a named_element. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_NAMED_ELEMENT bits set */ static inline bool xmi_element_info_is_a_named_element ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a named_element. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_TYPED_ELEMENT bits set */ static inline bool xmi_element_info_is_a_typed_element ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a package. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_PACKAGE bits set */ static inline bool xmi_element_info_is_a_package ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a packageable_element. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_PACKAGEABLE_ELEMENT bits set */ static inline bool xmi_element_info_is_a_packageable_element ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a node. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_NODE bits set */ static inline bool xmi_element_info_is_a_node ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a activity group. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_ACTIVITY_GROUP bits set */ static inline bool xmi_element_info_is_a_activity_group ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a activity edge. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_ACTIVITY_EDGE bits set */ static inline bool xmi_element_info_is_a_activity_edge ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a activity_node. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_ACTIVITY_NODE bits set */ static inline bool xmi_element_info_is_a_activity_node ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a artifact. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_ARTIFACT bits set */ static inline bool xmi_element_info_is_a_artifact ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a behaviored_classifier. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_BEHAVIORED_CLASSIFIER bits set */ static inline bool xmi_element_info_is_a_behaviored_classifier ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a class. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_CLASS bits set */ static inline bool xmi_element_info_is_a_class ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a vertex. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_VERTEX bits set */ static inline bool xmi_element_info_is_a_vertex ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a transition. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_TRANSITION bits set */ static inline bool xmi_element_info_is_a_transition ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a message. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_MESSAGE bits set */ static inline bool xmi_element_info_is_a_message ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a interaction_fragment. * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_INTERACTION_FRAGMENT bits set */ static inline bool xmi_element_info_is_a_interaction_fragment ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a association (which includes aggegation, composition, communication path). * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_ASSOCIATION bits set */ static inline bool xmi_element_info_is_a_association ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a dependency (which includes aggegation, composition, communication path). * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_DEPENDENCY bits set */ static inline bool xmi_element_info_is_a_dependency ( const xmi_element_info_t *this_ ); /*! * \brief checks if the type is a property (which includes ports). * * \param this_ pointer to own object attributes * \return true if is_a has XMI_ELEMENT_IS_A_PROPERTY bits set */ static inline bool xmi_element_info_is_a_property ( const xmi_element_info_t *this_ ); #include "xmi_element_info.inl" #endif /* XMI_ELEMENT_INFO_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/xmi/xmi_element_info.inl000066400000000000000000000137141415120503000240050ustar00rootroot00000000000000/* File: xmi_element_info.inl; Copyright and License: see below */ #include static inline int xmi_element_info_get_data_type_checksum ( const xmi_element_info_t *this_ ) { return (*this_).data_type_checksum; } static inline xmi_spec_t xmi_element_info_get_specification ( const xmi_element_info_t *this_ ) { return (*this_).specification; } static inline const char * xmi_element_info_get_profile_name ( const xmi_element_info_t *this_ ) { return (*this_).profile_name; } static inline const char * xmi_element_info_get_base_name ( const xmi_element_info_t *this_ ) { return (*this_).base_name; } static inline const char * xmi_element_info_get_name ( const xmi_element_info_t *this_ ) { const char* result; if ( (*this_).profile_name == NULL ) { result = (*this_).base_name; } else { result = (*this_).profile_name; } return result; } static inline const char * xmi_element_info_get_property_from ( const xmi_element_info_t *this_ ) { return (*this_).property_from; } static inline const char * xmi_element_info_get_property_to ( const xmi_element_info_t *this_ ) { return (*this_).property_to; } static inline const char * xmi_element_info_get_additional_properties ( const xmi_element_info_t *this_ ) { return (*this_).additional_properties; } static inline bool xmi_element_info_is_a_encapsulated_classifier ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_ENCAPSULATED_CLASSIFIER ) == XMI_ELEMENT_IS_A_ENCAPSULATED_CLASSIFIER; } static inline bool xmi_element_info_is_a_classifier ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_CLASSIFIER ) == XMI_ELEMENT_IS_A_CLASSIFIER; } static inline bool xmi_element_info_is_a_comment ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_COMMENT ) == XMI_ELEMENT_IS_A_COMMENT; } static inline bool xmi_element_info_is_a_behavior ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_BEHAVIOR ) == XMI_ELEMENT_IS_A_BEHAVIOR; } static inline bool xmi_element_info_is_a_named_element ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_NAMED_ELEMENT ) == XMI_ELEMENT_IS_A_NAMED_ELEMENT; } static inline bool xmi_element_info_is_a_typed_element ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_TYPED_ELEMENT ) == XMI_ELEMENT_IS_A_TYPED_ELEMENT; } static inline bool xmi_element_info_is_a_package ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_PACKAGE ) == XMI_ELEMENT_IS_A_PACKAGE; } static inline bool xmi_element_info_is_a_packageable_element ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_PACKAGEABLE_ELEMENT ) == XMI_ELEMENT_IS_A_PACKAGEABLE_ELEMENT; } static inline bool xmi_element_info_is_a_node ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_NODE ) == XMI_ELEMENT_IS_A_NODE; } static inline bool xmi_element_info_is_a_activity_group ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_ACTIVITY_GROUP ) == XMI_ELEMENT_IS_A_ACTIVITY_GROUP; } static inline bool xmi_element_info_is_a_activity_edge ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_ACTIVITY_EDGE ) == XMI_ELEMENT_IS_A_ACTIVITY_EDGE; } static inline bool xmi_element_info_is_a_activity_node ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_ACTIVITY_NODE ) == XMI_ELEMENT_IS_A_ACTIVITY_NODE; } static inline bool xmi_element_info_is_a_artifact ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_ARTIFACT ) == XMI_ELEMENT_IS_A_ARTIFACT; } static inline bool xmi_element_info_is_a_behaviored_classifier ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_BEHAVIORED_CLASSIFIER ) == XMI_ELEMENT_IS_A_BEHAVIORED_CLASSIFIER; } static inline bool xmi_element_info_is_a_class ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_CLASS ) == XMI_ELEMENT_IS_A_CLASS; } static inline bool xmi_element_info_is_a_vertex ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_VERTEX ) == XMI_ELEMENT_IS_A_VERTEX; } static inline bool xmi_element_info_is_a_transition ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_TRANSITION ) == XMI_ELEMENT_IS_A_TRANSITION; } static inline bool xmi_element_info_is_a_message ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_MESSAGE ) == XMI_ELEMENT_IS_A_MESSAGE; } static inline bool xmi_element_info_is_a_interaction_fragment ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_INTERACTION_FRAGMENT ) == XMI_ELEMENT_IS_A_INTERACTION_FRAGMENT; } static inline bool xmi_element_info_is_a_association ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_ASSOCIATION ) == XMI_ELEMENT_IS_A_ASSOCIATION; } static inline bool xmi_element_info_is_a_dependency ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_DEPENDENCY ) == XMI_ELEMENT_IS_A_DEPENDENCY; } static inline bool xmi_element_info_is_a_property ( const xmi_element_info_t *this_ ) { return ( ((*this_).is_a) & XMI_ELEMENT_IS_A_PROPERTY ) == XMI_ELEMENT_IS_A_PROPERTY; } /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/xmi/xmi_element_info_map.h000066400000000000000000000172451415120503000243120ustar00rootroot00000000000000/* File: xmi_element_info_map.h; Copyright and License: see below */ #ifndef XMI_ELEMENT_INFO_MAP_H #define XMI_ELEMENT_INFO_MAP_H /* public file for the doxygen documentation: */ /*! * \file * \brief Lists static data on xmi type names, type hierarchies and property names */ #include "xmi/xmi_spec.h" #include "xmi/xmi_element_info.h" #include "data_classifier_type.h" #include "data_feature_type.h" #include "data_relationship_type.h" #include /*! * \brief defines the array indices of uml elements */ enum xmi_element_info_map_index_enum { /* ================================ CLASSIFIER ================================ */ XMI_ELEMENT_INFO_MAP_INDEX_BLOCK, XMI_ELEMENT_INFO_MAP_INDEX_CONSTRAINT_BLOCK, XMI_ELEMENT_INFO_MAP_INDEX_REQUIREMENT, XMI_ELEMENT_INFO_MAP_INDEX_ACTOR, XMI_ELEMENT_INFO_MAP_INDEX_USE_CASE, XMI_ELEMENT_INFO_MAP_INDEX_SUBSYSTEM, XMI_ELEMENT_INFO_MAP_INDEX_ACTIVITY, XMI_ELEMENT_INFO_MAP_INDEX_STRUCTURED_ACTIVITY_NODE, /*!< Nested activities */ XMI_ELEMENT_INFO_MAP_INDEX_STATEMACHINE, /*!< The outermost state is a statemachine */ XMI_ELEMENT_INFO_MAP_INDEX_STATE, XMI_ELEMENT_INFO_MAP_INDEX_INTERACTION_USE, /*!< equals diagram reference */ XMI_ELEMENT_INFO_MAP_INDEX_NODE, XMI_ELEMENT_INFO_MAP_INDEX_COMPONENT, XMI_ELEMENT_INFO_MAP_INDEX_INTERFACE, XMI_ELEMENT_INFO_MAP_INDEX_PACKAGE, XMI_ELEMENT_INFO_MAP_INDEX_CLASS, XMI_ELEMENT_INFO_MAP_INDEX_ARTIFACT, XMI_ELEMENT_INFO_MAP_INDEX_COMMENT, XMI_ELEMENT_INFO_MAP_INDEX_DYN_INTERRUPTABLE_REGION, XMI_ELEMENT_INFO_MAP_INDEX_DYN_ACTIVITY_INITIAL_NODE, XMI_ELEMENT_INFO_MAP_INDEX_DYN_STATE_INITIAL_NODE, XMI_ELEMENT_INFO_MAP_INDEX_DYN_ACTIVITY_FINAL_NODE, XMI_ELEMENT_INFO_MAP_INDEX_DYN_STATE_FINAL_NODE, XMI_ELEMENT_INFO_MAP_INDEX_DYN_FORK_NODE, XMI_ELEMENT_INFO_MAP_INDEX_DYN_JOIN_NODE, XMI_ELEMENT_INFO_MAP_INDEX_DYN_ACTIVITY_DECISION_NODE, XMI_ELEMENT_INFO_MAP_INDEX_DYN_STATE_DECISION_NODE, XMI_ELEMENT_INFO_MAP_INDEX_DYN_SHALLOW_HISTORY, XMI_ELEMENT_INFO_MAP_INDEX_DYN_DEEP_HISTORY, XMI_ELEMENT_INFO_MAP_INDEX_DYN_PARTITION, XMI_ELEMENT_INFO_MAP_INDEX_DYN_ACCEPT_EVENT, XMI_ELEMENT_INFO_MAP_INDEX_DYN_ACCEPT_TIME_EVENT, XMI_ELEMENT_INFO_MAP_INDEX_DYN_SEND_SIGNAL, XMI_ELEMENT_INFO_MAP_INDEX_INTERACTION, /* ================================ FEATURE ================================ */ XMI_ELEMENT_INFO_MAP_INDEX_PROPERTY, XMI_ELEMENT_INFO_MAP_INDEX_OPERATION, XMI_ELEMENT_INFO_MAP_INDEX_PORT, XMI_ELEMENT_INFO_MAP_INDEX_INPUT_PIN, XMI_ELEMENT_INFO_MAP_INDEX_OUTPUT_PIN, XMI_ELEMENT_INFO_MAP_INDEX_STATE_ENTRY, XMI_ELEMENT_INFO_MAP_INDEX_STATE_EXIT, XMI_ELEMENT_INFO_MAP_INDEX_LIFELINE, XMI_ELEMENT_INFO_MAP_INDEX_PROVIDED_INTERFACE, XMI_ELEMENT_INFO_MAP_INDEX_REQUIRED_INTERFACE, /* ================================ RELATIONSHIP ================================ */ XMI_ELEMENT_INFO_MAP_INDEX_DEPENDENCY, XMI_ELEMENT_INFO_MAP_INDEX_ASSOCIATION, XMI_ELEMENT_INFO_MAP_INDEX_AGGREGATION, XMI_ELEMENT_INFO_MAP_INDEX_COMPOSITION, XMI_ELEMENT_INFO_MAP_INDEX_GENERALIZATION, XMI_ELEMENT_INFO_MAP_INDEX_REALIZATION, XMI_ELEMENT_INFO_MAP_INDEX_ASYNC_CALL, XMI_ELEMENT_INFO_MAP_INDEX_SYNC_CALL, XMI_ELEMENT_INFO_MAP_INDEX_RETURN_CALL, XMI_ELEMENT_INFO_MAP_INDEX_COMMUNICATION_PATH, XMI_ELEMENT_INFO_MAP_INDEX_CONTROL_FLOW, XMI_ELEMENT_INFO_MAP_INDEX_OBJECT_FLOW, XMI_ELEMENT_INFO_MAP_INDEX_TRANSITION, XMI_ELEMENT_INFO_MAP_INDEX_DEPLOY, XMI_ELEMENT_INFO_MAP_INDEX_MANIFEST, XMI_ELEMENT_INFO_MAP_INDEX_EXTEND, XMI_ELEMENT_INFO_MAP_INDEX_INCLUDE, XMI_ELEMENT_INFO_MAP_INDEX_CONTAINMENT, XMI_ELEMENT_INFO_MAP_INDEX_REFINE, XMI_ELEMENT_INFO_MAP_INDEX_TRACE, }; typedef enum xmi_element_info_map_index_enum xmi_element_info_map_index_t; #define XMI_ELEMENT_INFO_MAP_INDEX_MAX (64) typedef xmi_element_info_t xmi_element_info_map_t[XMI_ELEMENT_INFO_MAP_INDEX_MAX]; extern const xmi_element_info_map_t xmi_element_info_map_standard; /*! * \brief returns a pointer to the xmi_element_info_t struct identified by classifier_type. * * \param this_ pointer to own object attributes; use e.g. the global &xmi_element_info_map_standard * \param parent_type for some classifiers, the result depends on the used context, therefore the parent type is needed to select the xmi_element_info_t * \param classifier_type selects the xmi_element_info_t * \param[out] out_element_info pointer to the selected xmi_element_info_t (or similar xmi_element_info_t in case of unexpected classifier_type) * \return 0 in case of success, -1 if no valid mapping found */ static inline int xmi_element_info_map_get_classifier ( const xmi_element_info_map_t *this_, data_classifier_type_t parent_type, data_classifier_type_t classifier_type, const xmi_element_info_t **out_element_info ); /*! * \brief returns a pointer to the xmi_element_info_t struct identified by feat_type. * * \param this_ pointer to own object attributes; use e.g. the global &xmi_element_info_map_standard * \param parent_type data_classifier_type_t of the parent of which the feature type shall be determined * \param feature_type selects the xmi_element_info_t * \param[out] out_element_info pointer to the selected xmi_element_info_t (or similar xmi_element_info_t in case of unexpected classifier_type) * \return 0 in case of success, -1 if no valid mapping found */ static inline int xmi_element_info_map_get_feature ( const xmi_element_info_map_t *this_, data_classifier_type_t parent_type, data_feature_type_t feature_type, const xmi_element_info_t **out_element_info ); /*! * \brief returns a pointer to the xmi_element_info_t struct identified by rel_type. * * \param this_ pointer to own object attributes; use e.g. the global &xmi_element_info_map_standard * \param statemachine_context for some relationships, the result depends on the used context, e.g. transition in statemachine or control flow in activities * \param rel_type selects the xmi_element_info_t * \param[out] out_element_info pointer to the selected xmi_element_info_t (or similar xmi_element_info_t in case of unexpected classifier_type) * \return 0 in case of success, -1 if no valid mapping found */ static inline int xmi_element_info_map_get_relationship ( const xmi_element_info_map_t *this_, bool statemachine_context, data_relationship_type_t rel_type, const xmi_element_info_t **out_element_info ); #include "xmi_element_info_map.inl" #endif /* XMI_ELEMENT_INFO_MAP_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/xmi/xmi_element_info_map.inl000066400000000000000000000532001415120503000246340ustar00rootroot00000000000000/* File: xmi_element_info_map.inl; Copyright and License: see below */ #include "trace.h" #include "tslog.h" #include #include extern const xmi_element_info_t xmi_element_info_map_unknown_type; extern const xmi_element_info_t xmi_element_info_map_unknown_rel_type; static inline int xmi_element_info_map_get_classifier ( const xmi_element_info_map_t *this_, data_classifier_type_t parent_type, data_classifier_type_t classifier_type, const xmi_element_info_t **out_element_info ) { assert( NULL != out_element_info ); const xmi_element_info_t * result = NULL; const bool statemachine_context = ( parent_type == DATA_CLASSIFIER_TYPE_STATE ); const bool activity_context = ( parent_type == DATA_CLASSIFIER_TYPE_ACTIVITY )||( parent_type == DATA_CLASSIFIER_TYPE_DYN_INTERRUPTABLE_REGION ); switch ( classifier_type ) { case DATA_CLASSIFIER_TYPE_BLOCK: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_BLOCK]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_BLOCK ); } break; case DATA_CLASSIFIER_TYPE_CONSTRAINT_BLOCK: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_CONSTRAINT_BLOCK]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_CONSTRAINT_BLOCK ); } break; case DATA_CLASSIFIER_TYPE_REQUIREMENT: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_REQUIREMENT]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_REQUIREMENT ); } break; case DATA_CLASSIFIER_TYPE_ACTOR: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_ACTOR]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_ACTOR ); } break; case DATA_CLASSIFIER_TYPE_USE_CASE: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_USE_CASE]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_USE_CASE ); } break; case DATA_CLASSIFIER_TYPE_SUBSYSTEM: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_SUBSYSTEM]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_SUBSYSTEM ); } break; case DATA_CLASSIFIER_TYPE_ACTIVITY: { if ( activity_context ) { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_STRUCTURED_ACTIVITY_NODE]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_ACTIVITY ); } else { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_ACTIVITY]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_ACTIVITY ); } } break; case DATA_CLASSIFIER_TYPE_STATE: { if ( statemachine_context ) { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_STATE]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_STATE ); } else { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_STATEMACHINE]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_STATE ); } } break; case DATA_CLASSIFIER_TYPE_DIAGRAM_REFERENCE: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_INTERACTION_USE]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_DIAGRAM_REFERENCE ); } break; case DATA_CLASSIFIER_TYPE_NODE: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_NODE]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_NODE ); } break; case DATA_CLASSIFIER_TYPE_COMPONENT: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_COMPONENT]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_COMPONENT ); } break; case DATA_CLASSIFIER_TYPE_PART: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_COMPONENT]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_COMPONENT ); } break; case DATA_CLASSIFIER_TYPE_INTERFACE: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_INTERFACE]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_INTERFACE ); } break; case DATA_CLASSIFIER_TYPE_PACKAGE: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_PACKAGE]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_PACKAGE ); } break; case DATA_CLASSIFIER_TYPE_CLASS: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_CLASS]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_CLASS ); } break; case DATA_CLASSIFIER_TYPE_OBJECT: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_CLASS]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_CLASS ); } break; case DATA_CLASSIFIER_TYPE_ARTIFACT: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_ARTIFACT]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_ARTIFACT ); } break; case DATA_CLASSIFIER_TYPE_COMMENT: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_COMMENT]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_COMMENT ); } break; case DATA_CLASSIFIER_TYPE_DYN_INTERRUPTABLE_REGION: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_DYN_INTERRUPTABLE_REGION]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_DYN_INTERRUPTABLE_REGION ); } break; case DATA_CLASSIFIER_TYPE_DYN_INITIAL_NODE: { if ( statemachine_context ) { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_DYN_STATE_INITIAL_NODE]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_DYN_INITIAL_NODE ); } else { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_DYN_ACTIVITY_INITIAL_NODE]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_DYN_INITIAL_NODE ); } } break; case DATA_CLASSIFIER_TYPE_DYN_FINAL_NODE: { if ( statemachine_context ) { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_DYN_STATE_FINAL_NODE]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_DYN_FINAL_NODE ); } else { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_DYN_ACTIVITY_FINAL_NODE]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_DYN_FINAL_NODE ); } } break; case DATA_CLASSIFIER_TYPE_DYN_FORK_NODE: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_DYN_FORK_NODE]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_DYN_FORK_NODE ); } break; case DATA_CLASSIFIER_TYPE_DYN_JOIN_NODE: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_DYN_JOIN_NODE]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_DYN_JOIN_NODE ); } break; case DATA_CLASSIFIER_TYPE_DYN_DECISION_NODE: { if ( statemachine_context ) { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_DYN_STATE_DECISION_NODE]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_DYN_DECISION_NODE ); } else { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_DYN_ACTIVITY_DECISION_NODE]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_DYN_DECISION_NODE ); } } break; case DATA_CLASSIFIER_TYPE_DYN_SHALLOW_HISTORY: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_DYN_SHALLOW_HISTORY]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_DYN_SHALLOW_HISTORY ); } break; case DATA_CLASSIFIER_TYPE_DYN_DEEP_HISTORY: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_DYN_DEEP_HISTORY]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_DYN_DEEP_HISTORY ); } break; /* case DATA_CLASSIFIER_TYPE_DYN_PARTITION: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_DYN_PARTITION]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_DYN_PARTITION ); } break; */ case DATA_CLASSIFIER_TYPE_DYN_ACCEPT_EVENT: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_DYN_ACCEPT_EVENT]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_DYN_ACCEPT_EVENT ); } break; case DATA_CLASSIFIER_TYPE_DYN_ACCEPT_TIME_EVENT: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_DYN_ACCEPT_TIME_EVENT]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_DYN_ACCEPT_TIME_EVENT ); } break; case DATA_CLASSIFIER_TYPE_DYN_SEND_SIGNAL: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_DYN_SEND_SIGNAL]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_DYN_SEND_SIGNAL ); } break; case DATA_CLASSIFIER_TYPE_INTERACTION: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_INTERACTION]); assert ( (*result).data_type_checksum == (int)DATA_CLASSIFIER_TYPE_INTERACTION ); } break; default: { TSLOG_ERROR_INT( "switch case statement for data_classifier_type_t incomplete", classifier_type ); /* this is a possible error case that can happen when a database created with a newer version of the program is opened with this version */ result = NULL; } break; } *out_element_info = (result==NULL) ? &xmi_element_info_map_unknown_type : result; return (result==NULL) ? -1 : 0; } static inline int xmi_element_info_map_get_feature ( const xmi_element_info_map_t *this_, data_classifier_type_t parent_type, data_feature_type_t feature_type, const xmi_element_info_t **out_element_info ) { assert( NULL != out_element_info ); const xmi_element_info_t * result = NULL; switch ( feature_type ) { case DATA_FEATURE_TYPE_PROPERTY: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_PROPERTY]); assert ( (*result).data_type_checksum == (int)DATA_FEATURE_TYPE_PROPERTY ); } break; case DATA_FEATURE_TYPE_OPERATION: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_OPERATION]); assert ( (*result).data_type_checksum == (int)DATA_FEATURE_TYPE_OPERATION ); } break; case DATA_FEATURE_TYPE_PORT: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_PORT]); assert ( (*result).data_type_checksum == (int)DATA_FEATURE_TYPE_PORT ); } break; case DATA_FEATURE_TYPE_IN_PORT_PIN: { const bool is_behavioral_parent = data_classifier_type_is_behavioral( parent_type ); if ( is_behavioral_parent ) { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_INPUT_PIN]); assert ( (*result).data_type_checksum == (int)DATA_FEATURE_TYPE_IN_PORT_PIN ); } else { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_PORT]); assert ( (*result).data_type_checksum == (int)DATA_FEATURE_TYPE_PORT ); } } break; case DATA_FEATURE_TYPE_OUT_PORT_PIN: { const bool is_behavioral_parent = data_classifier_type_is_behavioral( parent_type ); if ( is_behavioral_parent ) { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_OUTPUT_PIN]); assert ( (*result).data_type_checksum == (int)DATA_FEATURE_TYPE_OUT_PORT_PIN ); } else { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_PORT]); assert ( (*result).data_type_checksum == (int)DATA_FEATURE_TYPE_PORT ); } } break; case DATA_FEATURE_TYPE_ENTRY: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_STATE_ENTRY]); assert ( (*result).data_type_checksum == (int)DATA_FEATURE_TYPE_ENTRY ); } break; case DATA_FEATURE_TYPE_EXIT: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_STATE_EXIT]); assert ( (*result).data_type_checksum == (int)DATA_FEATURE_TYPE_EXIT ); } break; case DATA_FEATURE_TYPE_LIFELINE: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_LIFELINE]); assert ( (*result).data_type_checksum == (int)DATA_FEATURE_TYPE_LIFELINE ); } break; case DATA_FEATURE_TYPE_PROVIDED_INTERFACE: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_PROVIDED_INTERFACE]); assert ( (*result).data_type_checksum == (int)DATA_FEATURE_TYPE_PROVIDED_INTERFACE ); } break; case DATA_FEATURE_TYPE_REQUIRED_INTERFACE: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_REQUIRED_INTERFACE]); assert ( (*result).data_type_checksum == (int)DATA_FEATURE_TYPE_REQUIRED_INTERFACE ); } break; default: { TSLOG_ERROR_INT( "switch case statement for data_relationship_type_t incomplete", feature_type ); /* this is a possible error case that can happen when a database created with a newer version of the program is opened with this version */ result = NULL; } break; } *out_element_info = (result==NULL) ? &xmi_element_info_map_unknown_type : result; return (result==NULL) ? -1 : 0; } static inline int xmi_element_info_map_get_relationship ( const xmi_element_info_map_t *this_, bool statemachine_context, data_relationship_type_t rel_type, const xmi_element_info_t **out_element_info ) { assert( NULL != out_element_info ); const xmi_element_info_t * result = NULL; switch ( rel_type ) { case DATA_RELATIONSHIP_TYPE_UML_DEPENDENCY: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_DEPENDENCY]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_DEPENDENCY ); } break; case DATA_RELATIONSHIP_TYPE_UML_ASSOCIATION: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_ASSOCIATION]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_ASSOCIATION ); } break; case DATA_RELATIONSHIP_TYPE_UML_AGGREGATION: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_AGGREGATION]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_AGGREGATION ); } break; case DATA_RELATIONSHIP_TYPE_UML_COMPOSITION: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_COMPOSITION]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_COMPOSITION ); } break; case DATA_RELATIONSHIP_TYPE_UML_GENERALIZATION: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_GENERALIZATION]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_GENERALIZATION ); } break; case DATA_RELATIONSHIP_TYPE_UML_REALIZATION: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_REALIZATION]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_REALIZATION ); } break; case DATA_RELATIONSHIP_TYPE_UML_ASYNC_CALL: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_ASYNC_CALL]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_ASYNC_CALL ); } break; case DATA_RELATIONSHIP_TYPE_UML_SYNC_CALL: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_SYNC_CALL]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_SYNC_CALL ); } break; case DATA_RELATIONSHIP_TYPE_UML_RETURN_CALL: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_RETURN_CALL]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_RETURN_CALL ); } break; case DATA_RELATIONSHIP_TYPE_UML_COMMUNICATION_PATH: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_COMMUNICATION_PATH]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_COMMUNICATION_PATH ); } break; case DATA_RELATIONSHIP_TYPE_UML_CONTROL_FLOW: { if ( statemachine_context ) { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_TRANSITION]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_CONTROL_FLOW ); } else { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_CONTROL_FLOW]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_CONTROL_FLOW ); } } break; case DATA_RELATIONSHIP_TYPE_UML_OBJECT_FLOW: { if ( statemachine_context ) { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_TRANSITION]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_CONTROL_FLOW ); /*mix on purpose*/ } else { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_OBJECT_FLOW]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_OBJECT_FLOW ); } } break; case DATA_RELATIONSHIP_TYPE_UML_DEPLOY: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_DEPLOY]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_DEPLOY ); } break; case DATA_RELATIONSHIP_TYPE_UML_MANIFEST: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_MANIFEST]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_MANIFEST ); } break; case DATA_RELATIONSHIP_TYPE_UML_EXTEND: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_EXTEND]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_EXTEND ); } break; case DATA_RELATIONSHIP_TYPE_UML_INCLUDE: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_INCLUDE]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_INCLUDE ); } break; case DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_CONTAINMENT]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT ); } break; case DATA_RELATIONSHIP_TYPE_UML_REFINE: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_REFINE]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_REFINE ); } break; case DATA_RELATIONSHIP_TYPE_UML_TRACE: { result = &((*this_)[XMI_ELEMENT_INFO_MAP_INDEX_TRACE]); assert ( (*result).data_type_checksum == (int)DATA_RELATIONSHIP_TYPE_UML_TRACE ); } break; default: { TSLOG_ERROR_INT( "switch case statement for data_relationship_type_t incomplete", rel_type ); /* this is a possible error case that can happen when a database created with a newer version of the program is opened with this version */ result = NULL; } break; } *out_element_info = (result==NULL) ? &xmi_element_info_map_unknown_rel_type : result; return (result==NULL) ? -1 : 0; } /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/xmi/xmi_element_is_a.h000066400000000000000000000154151415120503000234320ustar00rootroot00000000000000/* File: xmi_element_is_a.h; Copyright and License: see below */ #ifndef XMI_ELEMENT_IS_A_H #define XMI_ELEMENT_IS_A_H /* public file for the doxygen documentation: */ /*! * \file * \brief Represents the part of the hierarchy of uml elements that is relevant for the xmi-export * * Only base classes that have at least one descendant are covered; * there is no need to represent a class that has no children. */ /*! * \brief Enumerates the uml types in a way that the bit-pattern represents the generalization-hierarchy */ enum xmi_element_is_a_enum { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF */ XMI_ELEMENT_IS_A_ELEMENT = 0x00000000, /*!< anything is a decendant of uml:Element */ XMI_ELEMENT_IS_A_COMMENT = 0x00000001 | XMI_ELEMENT_IS_A_ELEMENT, /*!< the type is a decendant of uml:Comment */ XMI_ELEMENT_IS_A_NAMED_ELEMENT = 0x00000002 | XMI_ELEMENT_IS_A_ELEMENT, /*!< the type is a decendant of uml:NamedElement */ XMI_ELEMENT_IS_A_TYPED_ELEMENT = 0x00000004 | XMI_ELEMENT_IS_A_NAMED_ELEMENT, /*!< the type is a decendant of uml:TypedElement */ XMI_ELEMENT_IS_A_RELATIONSHIP = 0x00000008 | XMI_ELEMENT_IS_A_ELEMENT, /*!< the type is a decendant of uml:Relationship */ XMI_ELEMENT_IS_A_INTERACTION_FRAGMENT = 0x00000010 | XMI_ELEMENT_IS_A_NAMED_ELEMENT, /*!< the type is a decendant of uml:InteractionFragment */ XMI_ELEMENT_IS_A_DEPLOYMENT_TARGET = 0x00000020 | XMI_ELEMENT_IS_A_NAMED_ELEMENT, /*!< the type is a decendant of uml:DeploymentTarget */ XMI_ELEMENT_IS_A_REDEFINEABLE_ELEMENT = 0x00000040 | XMI_ELEMENT_IS_A_NAMED_ELEMENT, /*!< the type is a decendant of uml:RedefinableElement */ XMI_ELEMENT_IS_A_PACKAGEABLE_ELEMENT = 0x00000080 | XMI_ELEMENT_IS_A_NAMED_ELEMENT, /*!< the type is a decendant of uml:PackageableElement */ XMI_ELEMENT_IS_A_PACKAGE = 0x00000100 | XMI_ELEMENT_IS_A_PACKAGEABLE_ELEMENT, /*!< the type is a decendant of uml:Package */ XMI_ELEMENT_IS_A_CLASSIFIER = 0x00000200 | XMI_ELEMENT_IS_A_NAMED_ELEMENT | XMI_ELEMENT_IS_A_REDEFINEABLE_ELEMENT | XMI_ELEMENT_IS_A_PACKAGEABLE_ELEMENT, /*!< the type is a decendant of uml:Classifier */ XMI_ELEMENT_IS_A_VERTEX = 0x00000400 | XMI_ELEMENT_IS_A_NAMED_ELEMENT, /*!< the type is a decendant of uml:Vertex */ XMI_ELEMENT_IS_A_EVENT = 0x00000800 | XMI_ELEMENT_IS_A_PACKAGEABLE_ELEMENT, /*!< the type is a decendant of uml:Event */ XMI_ELEMENT_IS_A_BEHAVIORED_CLASSIFIER = 0x00001000 | XMI_ELEMENT_IS_A_CLASSIFIER, /*!< the type is a decendant of uml:BehavioredClassifier */ XMI_ELEMENT_IS_A_STRUCTURED_CLASSIFIER = 0x00002000 | XMI_ELEMENT_IS_A_CLASSIFIER, /*!< the type is a decendant of uml:StructuredClassifier */ XMI_ELEMENT_IS_A_ENCAPSULATED_CLASSIFIER = 0x00004000 | XMI_ELEMENT_IS_A_STRUCTURED_CLASSIFIER, /*!< the type is a decendant of uml:EncapsulatedClassifier */ XMI_ELEMENT_IS_A_CLASS = 0x00008000 | XMI_ELEMENT_IS_A_ENCAPSULATED_CLASSIFIER | XMI_ELEMENT_IS_A_BEHAVIORED_CLASSIFIER, /*!< the type is a decendant of uml:Class */ XMI_ELEMENT_IS_A_BEHAVIOR = 0x00010000 | XMI_ELEMENT_IS_A_ENCAPSULATED_CLASSIFIER | XMI_ELEMENT_IS_A_BEHAVIORED_CLASSIFIER, /*!< the type is a decendant of uml:Behavior */ XMI_ELEMENT_IS_A_ACTIVITY_GROUP = 0x00020000 | XMI_ELEMENT_IS_A_NAMED_ELEMENT, /*!< the type is a decendant of uml:ActivityGroup */ XMI_ELEMENT_IS_A_ACTIVITY_NODE = 0x00040000 | XMI_ELEMENT_IS_A_REDEFINEABLE_ELEMENT, /*!< the type is a decendant of uml:ActivityNode */ XMI_ELEMENT_IS_A_ACTIVITY_EDGE = 0x00080000 | XMI_ELEMENT_IS_A_REDEFINEABLE_ELEMENT, /*!< the type is a decendant of uml:ActivityEdge */ XMI_ELEMENT_IS_A_NODE = 0x00100000 | XMI_ELEMENT_IS_A_CLASS | XMI_ELEMENT_IS_A_DEPLOYMENT_TARGET, /*!< the type is a decendant of uml:Node */ XMI_ELEMENT_IS_A_ARTIFACT = 0x00200000 | XMI_ELEMENT_IS_A_CLASSIFIER, /*!< the type is a decendant of uml:Artifact */ XMI_ELEMENT_IS_A_FEATURE = 0x00400000 | XMI_ELEMENT_IS_A_REDEFINEABLE_ELEMENT, /*!< the type is a decendant of uml:Feature */ XMI_ELEMENT_IS_A_PROPERTY = 0x00800000 | XMI_ELEMENT_IS_A_FEATURE | XMI_ELEMENT_IS_A_DEPLOYMENT_TARGET /*!< the type is a decendant of uml:Property */ | XMI_ELEMENT_IS_A_TYPED_ELEMENT, /*!< the type is a decendant of uml:ConnectableElement */ XMI_ELEMENT_IS_A_ASSOCIATION = 0x01000000 | XMI_ELEMENT_IS_A_RELATIONSHIP | XMI_ELEMENT_IS_A_CLASSIFIER, /*!< the type is a decendant of uml:Association */ XMI_ELEMENT_IS_A_DIRECTED_RELATIONSHIP = 0x02000000 | XMI_ELEMENT_IS_A_RELATIONSHIP, /*!< the type is a decendant of uml:DirectedRelationship */ XMI_ELEMENT_IS_A_DEPENDENCY = 0x04000000 | XMI_ELEMENT_IS_A_DIRECTED_RELATIONSHIP | XMI_ELEMENT_IS_A_PACKAGEABLE_ELEMENT, /*!< the type is a decendant of uml:Dependency */ XMI_ELEMENT_IS_A_ABSTRACTION = 0x08000000 | XMI_ELEMENT_IS_A_DEPENDENCY, /*!< the type is a decendant of uml:Abstraction */ XMI_ELEMENT_IS_A_TRANSITION = 0x10000000 | XMI_ELEMENT_IS_A_REDEFINEABLE_ELEMENT, /*!< the type is a decendant of uml:Transition */ XMI_ELEMENT_IS_A_MESSAGE = 0x40000000 | XMI_ELEMENT_IS_A_NAMED_ELEMENT, /*!< the type is a decendant of uml:Message */ }; typedef enum xmi_element_is_a_enum xmi_element_is_a_t; #endif /* XMI_ELEMENT_IS_A_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/xmi/xmi_element_part.h000066400000000000000000000066411415120503000234660ustar00rootroot00000000000000/* File: xmi_element_part.h; Copyright and License: see below */ #ifndef XMI_ELEMENT_PART_H #define XMI_ELEMENT_PART_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines string parts of elements to be exported at xmi export */ /*! * \brief fallback nesting type * * for the case that the outer model shall nest an element that is illegal according to uml/sysml spec */ extern const char * const XMI_ELEMENT_PART_FALLBACK_NESTING_ELEMENT; /*! * \brief fallback owned-feature type * * for the case that a classifier shall nest an feature of unknown type */ extern const char * const XMI_ELEMENT_PART_FALLBACK_OWNED_FEATURE; /*! * \brief ownedEnd element of CommunicationPath and Association */ extern const char * const XMI_ELEMENT_PART_ELEMENT_OWNED_END; /*! * \brief Property uml element of CommunicationPath and Association */ extern const char * const XMI_ELEMENT_PART_TYPE_PROPERTY; /*! * \brief id fragment of source end property of CommunicationPath and Association */ extern const char * const XMI_ELEMENT_PART_ID_FRAGMENT_SOURCE_END; /*! * \brief id fragment of target end property of CommunicationPath and Association */ extern const char * const XMI_ELEMENT_PART_ID_FRAGMENT_TARGET_END; /*! * \brief Association attribute of Property uml element of CommunicationPath and Association */ extern const char * const XMI_ELEMENT_PART_PROPERTY_ASSOCIATION_ATTRIBUTE; /*! * \brief Type element of Property uml element of CommunicationPath and Association */ extern const char * const XMI_ELEMENT_PART_PROPERTY_TYPE_ELEMENT; /*! * \brief Class element of Property uml element of CommunicationPath and Association */ extern const char * const XMI_ELEMENT_PART_PROPERTY_CLASS_ELEMENT; /*! * \brief Interface element of Property uml element of CommunicationPath and Association */ extern const char * const XMI_ELEMENT_PART_PROPERTY_INTERFACE_ELEMENT; /*! * \brief Aggregation attribute of Property uml element of CommunicationPath and Association */ extern const char * const XMI_ELEMENT_PART_PROPERTY_AGGREGATION_ATTRIBUTE; /*! * \brief Shared value for aggregation of Property uml element of CommunicationPath and Association */ extern const char * const XMI_ELEMENT_PART_PROPERTY_AGGREGATION_SHARED; /*! * \brief Composite value for aggregation of Property uml element of CommunicationPath and Association */ extern const char * const XMI_ELEMENT_PART_PROPERTY_AGGREGATION_COMPOSITE; /*! * \brief MessageEnd is a MessageOccurrenceSpecification * * see uml spec 2.5.1 chapter 17.12.21 */ extern const char * const XMI_ELEMENT_PART_TYPE_MSG_OCCURRENCE_SPEC; /*! * \brief covered property denotes the lifeline to which an OccurrenceSpecification belongs * * see uml spec 2.5.1 chapter 17.12.23 */ extern const char * const XMI_ELEMENT_PART_PROPERTY_OCCURRENCE_SPEC_COVERED; #endif /* XMI_ELEMENT_PART_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/xmi/xmi_element_writer.h000066400000000000000000000446651415120503000240440ustar00rootroot00000000000000/* File: xmi_element_writer.h; Copyright and License: see below */ #ifndef XMI_ELEMENT_WRITER_H #define XMI_ELEMENT_WRITER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Writes several document pieces to one file output stream. * * Source: io_exporter and io_export_model_traversal_t; * Task: convert model-elements to an output stream (using an own xml writer); * Sink: universal_output_stream_t */ #include "xmi/xmi_atom_writer.h" #include "xml/xml_writer.h" #include "xmi/xmi_type_converter.h" #include "xmi/xmi_interaction_writer.h" #include "io_file_format.h" #include "xmi_writer_pass.h" #include "io_element_writer_if.h" #include "io_element_writer.h" #include "data_diagram.h" #include "data_classifier.h" #include "data_classifier_type.h" #include "data_feature.h" #include "data_relationship.h" #include "data_relationship_type.h" #include "set/data_visible_set.h" #include "set/data_stat.h" #include "storage/data_database_reader.h" #include "util/string/utf8stringbuf.h" #include "stream/universal_output_stream.h" /*! * \brief attributes of the xmi_element_writer_t */ struct xmi_element_writer_struct { io_element_writer_t element_writer; /*!< instance of implemented interface \c io_element_writer_t */ xmi_writer_pass_t mode; /*!< depending on the mode, conversion from a data object to the output format differs */ xmi_interaction_writer_t interaction_writer; /*!< instance of own xmi_interaction_writer */ /*!< which is the interaction output sink, */ /*!< replaces this xmi_element_writer_t in case of interactions */ data_stat_t *export_stat; /*!< pointer to external statistics object where export statistics are collected */ xml_writer_t xml_writer; /*!< own instance of an xml writer */ xmi_atom_writer_t atom_writer; /*!< own instance of an atom writer */ xmi_type_converter_t xmi_types; /*!< own instance of an xmi_type_converter_t */ }; typedef struct xmi_element_writer_struct xmi_element_writer_t; /*! * \brief initializes the xmi_element_writer_t * * \param this_ pointer to own object attributes * \param io_export_stat pointer to statistics object where export statistics are collected * \param output output stream where to write the generated output to */ void xmi_element_writer_init( xmi_element_writer_t *this_, data_stat_t *io_export_stat, universal_output_stream_t *output ); /*! * \brief destroys the xmi_element_writer_t * * \param this_ pointer to own object attributes */ void xmi_element_writer_destroy( xmi_element_writer_t *this_ ); /*! * \brief gets the io element writer interface of this xmi_element_writer_t * * \param this_ pointer to own object attributes * \return the abstract base class of this_ */ io_element_writer_t * xmi_element_writer_get_element_writer( xmi_element_writer_t *this_ ); /*! * \brief sets the conversion mode of the xmi_element_writer_t * * \param this_ pointer to own object attributes * \param mode mode how to convert a data object to the output format, e.g. uml-basic or profile-extension */ void xmi_element_writer_set_mode( xmi_element_writer_t *this_, xmi_writer_pass_t mode ); /*! * \brief writes the header of the document * * \param this_ pointer to own object attributes * \param document_title title of the document * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_write_header( xmi_element_writer_t *this_, const char *document_title ); /*! * \brief writes the start of the main section * * This starts a section that contains the main part of the document * * \param this_ pointer to own object attributes * \param document_title title of the document * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_start_main( xmi_element_writer_t *this_, const char *document_title ); /*! * \brief checks if a host classifier may nest a child classifier * * \param this_ pointer to own object attributes * \param host_type data_classifier_type_t of the host of which the nesting-ability shall be determined * \param child_type data_classifier_type_t of the nested child of which the nesting-ability shall be determined * \return true if nesting is allowed */ bool xmi_element_writer_can_classifier_nest_classifier ( xmi_element_writer_t *this_, data_classifier_type_t host_type, data_classifier_type_t child_type ); /*! * \brief checks if a host classifier may nest relationships * * \param this_ pointer to own object attributes * \param host_type data_classifier_type_t of the host of which the nesting-ability shall be determined * \param child_type data_relationship_type_t of the nested child of which the nesting-ability shall be determined * \return true if nesting or any relationship is allowed */ bool xmi_element_writer_can_classifier_nest_relationship ( xmi_element_writer_t *this_, data_classifier_type_t host_type, data_relationship_type_t child_type ); /*! * \brief writes a classifier start-element * * This starts a division that contains a classifier and a list of features and relationships * * \param this_ pointer to own object attributes * \param host_type type of the host classifier * \param classifier_ptr pointer to classifier that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_start_classifier( xmi_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ); /*! * \brief writes contents of a classifier * * \param this_ pointer to own object attributes * \param host_type type of the host classifier * \param classifier_ptr pointer to classifier that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_assemble_classifier( xmi_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ); /*! * \brief writes a classifier end-element * * This ends a division that contains a classifier and a list of features and relationships * * \param this_ pointer to own object attributes * \param host_type type of the host classifier, needed for xmi export * \param classifier_ptr pointer to classifier that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_end_classifier( xmi_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ); /*! * \brief writes a feature start-element * * \param this_ pointer to own object attributes * \param parent_type type of the owning host classifier * \param feature_ptr pointer to feature that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_start_feature( xmi_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ); /*! * \brief writes constents of a a feature * * \param this_ pointer to own object attributes * \param parent_type type of the owning host classifier * \param feature_ptr pointer to feature that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_assemble_feature( xmi_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ); /*! * \brief writes a feature end-element * * \param this_ pointer to own object attributes * \param parent_type type of the owning host classifier * \param feature_ptr pointer to feature that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_end_feature( xmi_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ); /*! * \brief starts a relationship * * \param this_ pointer to own object attributes * \param host_type type of the host classifier, needed for xmi export * \param relation_ptr pointer to relationship that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_start_relationship( xmi_element_writer_t *this_, data_classifier_type_t host_type, const data_relationship_t *relation_ptr ); /*! * \brief writes the contents of a relationship * * \param this_ pointer to own object attributes * \param host the host classifier, needed for xmi export * \param relation_ptr pointer to relationship that shall be written, not NULL * \param from_c the classifier at source end * \param from_f the feature at source end; NULL if no feature specified * \param to_c the classifier at target end * \param to_f the feature at target end; NULL if no feature specified * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_assemble_relationship( xmi_element_writer_t *this_, const data_classifier_t *host, const data_relationship_t *relation_ptr, const data_classifier_t *from_c, const data_feature_t *from_f, const data_classifier_t *to_c, const data_feature_t *to_f ); /*! * \brief writes the contents of a relationship * * \param this_ pointer to own object attributes * \param host_type type of the host classifier, needed for xmi export * \param host_is_source indicates if the host classifier is the source end of the relationship * \param host_id id of the host classifier, needed for xmi-interaction export * \param relation_ptr pointer to relationship that shall be written, not NULL * \param from_c_type the type of classifier at source end * \param from_f_type the type of feature at source end; DATA_FEATURE_TYPE_VOID if no feature specified * \param to_c_type the type of classifier at target end * \param to_f_type the type of feature at target end; DATA_FEATURE_TYPE_VOID if no feature specified * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_private_assemble_relationship( xmi_element_writer_t *this_, data_classifier_type_t host_type, bool host_is_source, data_id_t host_id, const data_relationship_t *relation_ptr, data_classifier_type_t from_c_type, data_feature_type_t from_f_type, data_classifier_type_t to_c_type, data_feature_type_t to_f_type ); /*! * \brief ends a relationship * * \param this_ pointer to own object attributes * \param host_type type of the host classifier, needed for xmi export * \param relation_ptr pointer to relationship that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_end_relationship( xmi_element_writer_t *this_, data_classifier_type_t host_type, const data_relationship_t *relation_ptr ); /*! * \brief writes a diagram start * * This starts a section that contains a diagram and a list of diagramelements (classifier-occurrences) * * \param this_ pointer to own object attributes * \param diag_ptr pointer to diagram that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_start_diagram( xmi_element_writer_t *this_, const data_diagram_t *diag_ptr ); /*! * \brief writes a diagram of the document * * \param this_ pointer to own object attributes * \param parent pointer to parent diagram or NULL in case of root * \param diag_ptr pointer to diagram that shall be written * \param diagram_file_base_name filename of the diagram without extension * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_assemble_diagram( xmi_element_writer_t *this_, const data_diagram_t *parent, const data_diagram_t *diag_ptr, const char *diagram_file_base_name ); /*! * \brief ends a diagram * * This ends a section that contains a diagram and a list of diagramelements (classifier-occurrences) * * \param this_ pointer to own object attributes * \param diag_ptr pointer to diagram that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_end_diagram( xmi_element_writer_t *this_, const data_diagram_t *diag_ptr ); /*! * \brief writes a diagramelement start-element * * \param this_ pointer to own object attributes * \param parent the hosting diagram * \param diagramelement_ptr pointer to diagramelement that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_start_diagramelement( xmi_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr ); /*! * \brief writes constents of a a diagramelement * * \param this_ pointer to own object attributes * \param parent the hosting diagram * \param diagramelement_ptr pointer to diagramelement that shall be written, not NULL * \param occurrence the occurring classifier * \param feat_occur the focused feature of the occurring classifier * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_assemble_diagramelement( xmi_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr, const data_classifier_t *occurrence, const data_feature_t *feat_occur ); /*! * \brief writes a diagramelement end-element * * \param this_ pointer to own object attributes * \param parent the hosting diagram * \param diagramelement_ptr pointer to diagramelement that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_end_diagramelement( xmi_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr ); /*! * \brief writes the ending of the main section * * This ends a section that contains the main part of the document * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_end_main( xmi_element_writer_t *this_ ); /*! * \brief writes the footer of the document * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_write_footer( xmi_element_writer_t *this_ ); /*! * \brief writes a member end property of a relationship of uml-type association * * \param this_ pointer to own object attributes * \param relationship_id id of the relationship * \param relationship_type type of relation, used to determine aggregation kind; none, shared or composite * \param end_object_id id of the classifier or feature at the relationship-end * \param end_classifier_type the type of classifier at relationship end * \param end_feature_type the type of feature at relationship end; DATA_FEATURE_TYPE_VOID if no feature specified * \param is_target_end true if the target member-end shall be written, * false in case of the source member-end * \return 0 in case of success, -1 otherwise */ int xmi_element_writer_private_fake_memberend ( xmi_element_writer_t *this_, data_id_t relationship_id, data_relationship_type_t relationship_type, data_id_t end_object_id, data_classifier_type_t end_classifier_type, data_feature_type_t end_feature_type, bool is_target_end ); #endif /* XMI_ELEMENT_WRITER_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/xmi/xmi_interaction_writer.h000066400000000000000000000135631415120503000247230ustar00rootroot00000000000000/* File: xmi_interaction_writer.h; Copyright and License: see below */ #ifndef XMI_INTERACTION_WRITER_H #define XMI_INTERACTION_WRITER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Writes several document pieces to one file output stream. * * Source: io_exporter and io_export_model_traversal_t; * Task: convert model-elements to an output stream (using an own xml writer); * Sink: universal_output_stream_t */ #include "xmi/xmi_atom_writer.h" #include "xml/xml_writer.h" #include "xmi/xmi_type_converter.h" #include "io_file_format.h" #include "xmi_writer_pass.h" #include "data_diagram.h" #include "data_classifier.h" #include "set/data_visible_set.h" #include "set/data_stat.h" #include "storage/data_database_reader.h" #include "util/string/utf8stringbuf.h" /*! * \brief attributes of the format writer */ struct xmi_interaction_writer_struct { xmi_writer_pass_t mode; /*!< depending on the mode, conversion from a data object to the output format differs */ data_stat_t *export_stat; /*!< pointer to external statistics object where export statistics are collected */ xml_writer_t *xml_writer; /*!< pointer to external xml writer */ xmi_atom_writer_t atom_writer; /*!< own instance of an atom writer */ xmi_type_converter_t xmi_types; /*!< own instance of an xmi_type_converter_t */ }; typedef struct xmi_interaction_writer_struct xmi_interaction_writer_t; /*! * \brief initializes the format writer * * \param this_ pointer to own object attributes * \param io_export_stat pointer to statistics object where export statistics are collected * \param out_writer output stream where to write the generated output to */ void xmi_interaction_writer_init( xmi_interaction_writer_t *this_, data_stat_t *io_export_stat, xml_writer_t *out_writer ); /*! * \brief destroys the format writer * * \param this_ pointer to own object attributes */ void xmi_interaction_writer_destroy( xmi_interaction_writer_t *this_ ); /*! * \brief writes the start of the main section * * This starts a section that contains the main part of the document * * \param this_ pointer to own object attributes * \param parent_type type of the parent classifier * \param diagram_ptr diagram which shall be written as XMI interaction * \return 0 in case of success, -1 otherwise */ int xmi_interaction_writer_start_diagram( xmi_interaction_writer_t *this_, data_classifier_type_t parent_type, const data_diagram_t *diagram_ptr ); /*! * \brief writes the ending of the main section * * This ends a section that contains the main part of the document * * \param this_ pointer to own object attributes * \param parent_type type of the parent classifier * \return 0 in case of success, -1 otherwise */ int xmi_interaction_writer_end_diagram( xmi_interaction_writer_t *this_, data_classifier_type_t parent_type ); /*! * \brief writes constents of a lifeline-type feature * * \param this_ pointer to own object attributes * \param reference_id id of the object which this lifeline proxies * \param parent_type type of the owning parent classifier * \param feature_ptr pointer to feature that shall be written, not NULL * \return 0 in case of success, -1 otherwise */ int xmi_interaction_writer_assemble_feature( xmi_interaction_writer_t *this_, data_id_t reference_id, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ); /*! * \brief writes the contents of a message-type relationship * * \param this_ pointer to own object attributes * \param interaction_id id of the interaction to which the message (relationship) belongs * \param parent_type type of the nesting-parent classifier, needed for xmi export * \param relation_ptr pointer to relationship that shall be written, not NULL * \param from_c_type the type of classifier at source end * \param from_f_type the type of feature at source end; DATA_FEATURE_TYPE_VOID if no feature specified * \param to_c_type the type of classifier at target end * \param to_f_type the type of feature at target end; DATA_FEATURE_TYPE_VOID if no feature specified * \return 0 in case of success, -1 otherwise */ int xmi_interaction_writer_assemble_relationship( xmi_interaction_writer_t *this_, data_id_t interaction_id, data_classifier_type_t parent_type, const data_relationship_t *relation_ptr, data_classifier_type_t from_c_type, data_feature_type_t from_f_type, data_classifier_type_t to_c_type, data_feature_type_t to_f_type ); #endif /* XMI_INTERACTION_WRITER_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/xmi/xmi_spec.h000066400000000000000000000027671415120503000217460ustar00rootroot00000000000000/* File: xmi_spec.h; Copyright and License: see below */ #ifndef XMI_SPEC_H #define XMI_SPEC_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines the xmi specifications for crystal facet uml types */ /*! * \brief bit set of xmi specifications for crystal facet uml types */ enum xmi_spec_enum { XMI_SPEC_VOID = 0x0000, /*!< not specified anywhere */ XMI_SPEC_MOF = 0x0001, /*!< specified in MOF specification */ XMI_SPEC_XMI = 0x0002, /*!< specified in XMI file format specification */ XMI_SPEC_UML = 0x0004, /*!< specified in UML specification */ XMI_SPEC_PRIMITIVE = 0x0008, /*!< specified in Primitive Types profile specification */ XMI_SPEC_STANDARD = 0x0010, /*!< specified in StandardProfile specification */ XMI_SPEC_SYSML = 0x0020, /*!< specified in SYSML profile specification */ }; typedef enum xmi_spec_enum xmi_spec_t; #endif /* XMI_SPEC_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/xmi/xmi_type_converter.h000066400000000000000000000350031415120503000240510ustar00rootroot00000000000000/* File: xmi_type_converter.h; Copyright and License: see below */ #ifndef XMI_TYPE_CONVERTER_H #define XMI_TYPE_CONVERTER_H /* public file for the doxygen documentation: */ /*! * \file * \brief converts crystal facet uml types to xmi (uml and sysml) types */ #include "xmi/xmi_spec.h" #include "data_diagram_type.h" #include "data_classifier_type.h" #include "data_feature_type.h" #include "data_relationship_type.h" #include /* NOTE: When searching in the internet for xmi samples, use the following 12 characters: filetype:xmi */ /*! * \brief attributes of the xmi type converter */ struct xmi_type_converter_struct { int dummy; /*!< xmi_type_converter_t currently has not member attributes */ }; typedef struct xmi_type_converter_struct xmi_type_converter_t; /*! * \brief initializes the xmi type converter * * \param this_ pointer to own object attributes */ void xmi_type_converter_init( xmi_type_converter_t *this_ ); /*! * \brief destroys the xmi type converter * * \param this_ pointer to own object attributes */ void xmi_type_converter_destroy( xmi_type_converter_t *this_ ); /* ================================ CLASSIFIER ================================ */ /*! * \brief gets the xmi specification bitset for data_classifier_type_t types * * \param this_ pointer to own object attributes * \param c_type data_classifier_type_t to evaluate * \return xmi specification bitset */ xmi_spec_t xmi_type_converter_get_xmi_spec_of_classifier ( xmi_type_converter_t *this_, data_classifier_type_t c_type ); /*! * \brief gets a string representation of a data_classifier_type_t * * \param this_ pointer to own object attributes * \param parent_type for some classifiers, the result depends on the parent type, e.g. state or activity * \param c_type data_classifier_type_t to convert to a string * \param spec control, according to which specification the xmi type shall be returned. profiles define extensions to base types in mof+uml. * \return string representation of c_type, empty string if not available */ const char* xmi_type_converter_get_xmi_type_of_classifier ( xmi_type_converter_t *this_, data_classifier_type_t parent_type, data_classifier_type_t c_type, xmi_spec_t spec ); /*! * \brief gets a string representation of a classifiers nesting-type of a child classifier * * \param this_ pointer to own object attributes * \param parent_type data_classifier_type_t of the parent of which the nesting-type shall be determined * \param child_type data_classifier_type_t of the nested child of which the nesting-type shall be determined * \param out_xmi_name representation of the nesting-link type, empty string if not available (result != 0) * \return 0 in case of success, -1 in case of error. */ int xmi_type_converter_get_xmi_nesting_property_of_classifier ( xmi_type_converter_t *this_, data_classifier_type_t parent_type, data_classifier_type_t child_type, char const * *out_xmi_name ); /*! * \brief checks if a parent classifier may nest a child classifier * * \param this_ pointer to own object attributes * \param parent_type data_classifier_type_t of the parent of which the nesting-ability shall be determined * \param child_type data_classifier_type_t of the nested child of which the nesting-ability shall be determined * \return true if nesting is allowed */ static inline bool xmi_type_converter_can_nest_classifier ( xmi_type_converter_t *this_, data_classifier_type_t parent_type, data_classifier_type_t child_type ); /*! * \brief gets a string representation of a classifiers owning-type of a feature * * \param this_ pointer to own object attributes * \param parent_type data_classifier_type_t of the parent of which the owning-type shall be determined * \param feature_type data_feature_type_t of the child of which the owning-type shall be determined * \param out_xmi_name representation of the owning-link type, even in case of a type mismatch a string is provided * \return 0 in case of success, -1 in case of type mismatch between parent and owned-child */ int xmi_type_converter_get_xmi_owning_property_of_feature ( xmi_type_converter_t *this_, data_classifier_type_t parent_type, data_feature_type_t feature_type, char const * *out_xmi_name ); /*! * \brief gets a string representation of a classifiers nesting-type of a relationship * * \param this_ pointer to own object attributes * \param hosting_type data_classifier_type_t of the host of which the nesting-type shall be determined * \param child_type data_relationship_type_t of the nested child of which the nesting-type shall be determined * \param out_xmi_name representation of the nesting-link type, empty string if not available (result != 0) * \return 0 in case of success */ int xmi_type_converter_get_xmi_nesting_property_of_relationship ( xmi_type_converter_t *this_, data_classifier_type_t hosting_type, data_relationship_type_t child_type, char const * *out_xmi_name ); /*! * \brief checks if a parent classifier may nest a child relationship * * \param this_ pointer to own object attributes * \param hosting_type data_classifier_type_t of the host of which the nesting-ability shall be determined * \param child_type data_relationship_type_t of the nested child of which the nesting-ability shall be determined * \return true if nesting or any relationship is allowed */ static inline bool xmi_type_converter_can_nest_relationship ( xmi_type_converter_t *this_, data_classifier_type_t hosting_type, data_relationship_type_t child_type ); /* ================================ FEATURE ================================ */ /*! * \brief gets the xmi specification bitset for data_classifier_type_t types * * \param this_ pointer to own object attributes * \param feature_type data_feature_type_t to evaluate * \return xmi specification bitset */ xmi_spec_t xmi_type_converter_get_xmi_spec_of_feature ( xmi_type_converter_t *this_, data_feature_type_t feature_type ); /*! * \brief gets a string representation of a data_feature_type_t * * \param this_ pointer to own object attributes * \param parent_type data_classifier_type_t of the parent of which the owning-type shall be determined * \param feature_type data_feature_type_t to convert to a string * \param spec control, according to which specification the xmi type shall be returned. profiles define extensions to base types in mof+uml. * \return string representation of feature_type, empty string if not available */ const char* xmi_type_converter_get_xmi_type_of_feature ( xmi_type_converter_t *this_, data_classifier_type_t parent_type, data_feature_type_t feature_type, xmi_spec_t spec ); /* ================================ RELATIONSHIP ================================ */ /*! * \brief gets the xmi specification bitset for data_relationship_type_t types * * \param this_ pointer to own object attributes * \param r_type data_relationship_type_t to evaluate * \return xmi specification bitset */ xmi_spec_t xmi_type_converter_get_xmi_spec_of_relationship ( xmi_type_converter_t *this_, data_relationship_type_t r_type ); /*! * \brief gets a string representation of a data_relationship_type_t * * \param this_ pointer to own object attributes * \param hosting_type data_classifier_type_t of the host of which the nesting-type shall be determined * \param r_type data_relationship_type_t to convert to a string * \param spec control, according to which specification the xmi type shall be returned. profiles define extensions to base types in mof+uml. * \return string representation of r_type, empty string if not available */ const char* xmi_type_converter_get_xmi_type_of_relationship ( xmi_type_converter_t *this_, data_classifier_type_t hosting_type, data_relationship_type_t r_type, xmi_spec_t spec ); /*! * \brief gets a string representation of the from property of a data_relationship_type_t * * \param this_ pointer to own object attributes * \param hosting_type data_classifier_type_t of the host * \param rel_type data_relationship_type_t for which to determine the from property * \param from_classifier_type the type of classifier at relationship-end * \param from_feature_type the type of feature at relationship-end; DATA_FEATURE_TYPE_VOID if no feature specified * \param out_xmi_name string representation of the from property of the rel_type, empty string if not available * \return 0 in case of success, -1 in case of error. Even in case of error, a non-empty out_xmi_name may be returned. */ static inline int xmi_type_converter_get_xmi_from_property_of_relationship ( xmi_type_converter_t *this_, data_classifier_type_t hosting_type, data_relationship_type_t rel_type, data_classifier_type_t from_classifier_type, data_feature_type_t from_feature_type, char const * *out_xmi_name ); /*! * \brief gets a string representation of the to property of a data_relationship_type_t * * \param this_ pointer to own object attributes * \param hosting_type data_classifier_type_t of the host * \param rel_type data_relationship_type_t for which to determine the to property * \param to_classifier_type the type of classifier at relationship-end * \param to_feature_type the type of feature at relationship-end; DATA_FEATURE_TYPE_VOID if no feature specified * \param out_xmi_name string representation of the to property of the rel_type, empty string if not available * \return 0 in case of success, -1 in case of error. Even in case of error, a non-empty out_xmi_name may be returned. */ static inline int xmi_type_converter_get_xmi_to_property_of_relationship ( xmi_type_converter_t *this_, data_classifier_type_t hosting_type, data_relationship_type_t rel_type, data_classifier_type_t to_classifier_type, data_feature_type_t to_feature_type, char const * *out_xmi_name ); /*! * \brief gets a string representation of an end property of a data_relationship_type_t * * \param this_ pointer to own object attributes * \param hosting_type data_classifier_type_t of the host * \param rel_type data_relationship_type_t of the nested relationship * \param from_end true if the source(from) end, is requested, false if the target(to) end is requested. * \param end_classifier_type the type of classifier at relationship-end * \param end_feature_type the type of feature at relationship-end; DATA_FEATURE_TYPE_VOID if no feature specified * \param out_xmi_name string representation of the end property of the rel_type, empty string if not available * \return 0 in case of success, -1 in case of error. Even in case of error, a non-empty out_xmi_name may be returned. */ int xmi_type_converter_private_get_xmi_end_property_of_relationship ( xmi_type_converter_t *this_, data_classifier_type_t hosting_type, data_relationship_type_t rel_type, bool from_end, data_classifier_type_t end_classifier_type, data_feature_type_t end_feature_type, char const * *out_xmi_name ); #include "xmi_type_converter.inl" #endif /* XMI_TYPE_CONVERTER_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/xmi/xmi_type_converter.inl000066400000000000000000000121441415120503000244050ustar00rootroot00000000000000/* File: xmi_type_converter.inl; Copyright and License: see below */ #include /* ================================ CLASSIFIER ================================ */ static inline bool xmi_type_converter_can_nest_classifier ( xmi_type_converter_t *this_, data_classifier_type_t parent_type, data_classifier_type_t child_type ) { char const * xmi_name; const int err_code = xmi_type_converter_get_xmi_nesting_property_of_classifier ( this_, parent_type, child_type, &xmi_name ); return ( 0 == err_code ); } static inline bool xmi_type_converter_can_nest_relationship ( xmi_type_converter_t *this_, data_classifier_type_t hosting_type, data_relationship_type_t child_type ) { char const * xmi_name; const int err_code = xmi_type_converter_get_xmi_nesting_property_of_relationship ( this_, hosting_type, child_type, &xmi_name ); return ( 0 == err_code ); } /* ================================ FEATURE ================================ */ /* ================================ RELATIONSHIP ================================ */ static inline int xmi_type_converter_get_xmi_from_property_of_relationship ( xmi_type_converter_t *this_, data_classifier_type_t hosting_type, data_relationship_type_t rel_type, data_classifier_type_t from_classifier_type, data_feature_type_t from_feature_type, char const * *out_xmi_name ) { return xmi_type_converter_private_get_xmi_end_property_of_relationship( this_, hosting_type, rel_type, true /* = from */, from_classifier_type, from_feature_type, out_xmi_name ); } static inline int xmi_type_converter_get_xmi_to_property_of_relationship ( xmi_type_converter_t *this_, data_classifier_type_t hosting_type, data_relationship_type_t rel_type, data_classifier_type_t to_classifier_type, data_feature_type_t to_feature_type, char const * *out_xmi_name ) { return xmi_type_converter_private_get_xmi_end_property_of_relationship( this_, hosting_type, rel_type, false /* = to */, to_classifier_type, to_feature_type, out_xmi_name ); } /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/xmi/xmi_writer_pass.h000066400000000000000000000022641415120503000233460ustar00rootroot00000000000000/* File: xmi_writer_pass.h; Copyright and License: see below */ #ifndef XMI_WRITER_PASS_H #define XMI_WRITER_PASS_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines the semantics of multiple model-traversal-passes */ /*! * \brief constants for output mode: basic mode or extended profile mode. */ enum xmi_writer_pass_enum { XMI_WRITER_PASS_BASE = 0, /*!< mode for basic type output: xmi, uml and mof */ XMI_WRITER_PASS_PROFILE = 1, /*!< mode for profile type output: StandardProfile or SysML */ }; typedef enum xmi_writer_pass_enum xmi_writer_pass_t; #endif /* XMI_WRITER_PASS_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/xmi/xmi_xml.h000066400000000000000000000036001415120503000215770ustar00rootroot00000000000000/* File: xmi_xml.h; Copyright and License: see below */ #ifndef XMI_XML_H #define XMI_XML_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines the xml namespaces, xml elements, xml attributes for xmi export */ /*! * \brief namespace for uml elements and attributes */ extern const char XMI_XML_NS_UML[5]; /*! * \brief namespace for sysml profile elements and attributes */ extern const char XMI_XML_NS_SYSML[7]; /*! * \brief namespace for standard profile elements and attributes */ extern const char XMI_XML_NS_STDPROF[17]; /*! * \brief namespace for the model-local profile elements and attributes */ extern const char XMI_XML_NS_LOCALPROF[14]; /* spec-ref: https://www.omg.org/spec/XMI/2.5.1/PDF chapter 9.5.2 : 2e */ extern const char XMI_XML_ATTR_ID_START[9]; extern const char XMI_XML_ATTR_ID_END[3]; /* spec-ref: https://www.omg.org/spec/XMI/2.5.1/PDF chapter 9.5.2 : 2g */ extern const char XMI_XML_ATTR_TYPE_START[11]; extern const char XMI_XML_ATTR_TYPE_END[3]; /* spec-ref: https://www.omg.org/spec/XMI/2.5.1/PDF chapter 9.5.2 : 2l */ extern const char XMI_XML_ATTR_IDREF_START[12]; extern const char XMI_XML_ATTR_IDREF_END[3]; /* spec-ref: not-found */ extern const char XMI_XML_ATTR_NAME_START[7]; extern const char XMI_XML_ATTR_NAME_END[3]; #endif /* XMI_XML_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/xml/000077500000000000000000000000001415120503000177555ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/include/xml/xml_writer.h000066400000000000000000000200351415120503000223220ustar00rootroot00000000000000/* File: xml_writer.h; Copyright and License: see below */ #ifndef XML_WRITER_H #define XML_WRITER_H /* public file for the doxygen documentation: */ /*! * \file * \brief writes strings to an xml stream */ #include "data_diagram.h" #include "data_classifier.h" #include "data_table.h" #include "util/string/utf8string.h" #include "util/string/utf8stringview.h" #include "stream/universal_output_stream.h" #include "stream/universal_escaping_output_stream.h" /*! * \brief constants for max string sizes */ enum xml_writer_max_enum { XML_WRITER_MAX_STRING_SIZE = DATA_DIAGRAM_MAX_DESCRIPTION_LENGTH + DATA_CLASSIFIER_MAX_DESCRIPTION_LENGTH, }; extern const char XML_WRITER_START_TAG_START[2]; extern const char XML_WRITER_START_TAG_END[2]; extern const char XML_WRITER_END_TAG_START[3]; extern const char XML_WRITER_END_TAG_END[2]; /*! * \brief \c XML \c empty \c tags are leaf tags that do not contain contents or other tags - only attributes */ extern const char XML_WRITER_EMPTY_TAG_START[2]; extern const char XML_WRITER_EMPTY_TAG_END[3]; extern const char XML_WRITER_ATTR_SEPARATOR[2]; extern const char XML_WRITER_ATTR_VALUE_START[3]; extern const char XML_WRITER_ATTR_VALUE_END[2]; extern const char XML_WRITER_COMMENT_START[5]; extern const char XML_WRITER_COMMENT_END[4]; extern const char XML_WRITER_NL[2]; /*! * \brief attributes of the xml writer */ struct xml_writer_struct { universal_output_stream_t *output; /*!< output stream where to write the generated document to */ universal_escaping_output_stream_t esc_output; /*!< escaping output stream filter that does the xml escaping */ unsigned int indent_level; /*!< current indentation level of written lines */ const char *const ((*xml_encode_table)[][2]); /*!< table for xml encode string replacements */ const char *const ((*xml_comments_encode_table)[][2]); /*!< table for xml coments encode string replacements */ const char *const ((*xml_plain_table)[][2]); /*!< table for xml plain output, just performing indentation */ }; typedef struct xml_writer_struct xml_writer_t; /*! * \brief initializes the xml writer * * \param this_ pointer to own object attributes * \param output output stream where to write the generated document to */ void xml_writer_init( xml_writer_t *this_, universal_output_stream_t *output ); /*! * \brief destroys the xml writer * * \param this_ pointer to own object attributes */ void xml_writer_destroy( xml_writer_t *this_ ); /*! * \brief writes a string to a file, unencoded * * \param this_ pointer to own object attributes * \param text string to write * \return 0 in case of success, -1 otherwise */ static inline int xml_writer_write_plain ( xml_writer_t *this_, utf8string_t text ); /*! * \brief writes stringview to a file, unencoded * * \param this_ pointer to own object attributes * \param string_view stringview to write, not 0-terminated * \return 0 in case of success, -1 otherwise */ static inline int xml_writer_write_plain_view ( xml_writer_t *this_, utf8stringview_t string_view ); /*! * \brief prints an id * * if the id is invalid, nothing is printed. * * \param this_ pointer to own object attributes * \param id the identifier * \return 0 in case of success, -1 otherwise */ int xml_writer_write_plain_id ( xml_writer_t *this_, data_id_t id ); /*! * \brief prints an integer * * \param this_ pointer to own object attributes * \param number the integer to print * \return 0 in case of success, -1 otherwise */ int xml_writer_write_int ( xml_writer_t *this_, int64_t number ); /*! * \brief writes a string to a file, xml encoded * * \param this_ pointer to own object attributes * \param text string to write * \return 0 in case of success, -1 otherwise */ static inline int xml_writer_write_xml_enc ( xml_writer_t *this_, utf8string_t text ); /*! * \brief writes a stringview to a file, xml encoded * * \param this_ pointer to own object attributes * \param string_view stringview to write, not 0-terminated * \return 0 in case of success, -1 otherwise */ static inline int xml_writer_write_xml_enc_view ( xml_writer_t *this_, utf8stringview_t string_view ); /*! * \brief writes a string to a file, xml encoded and double-minus gets space-separated * * \param this_ pointer to own object attributes * \param text string to write, encoded for xml comments * \return 0 in case of success, -1 otherwise */ static inline int xml_writer_write_xml_comment ( xml_writer_t *this_, utf8string_t text ); /*! * \brief writes a stringview to a file, xml encoded and double-minus gets space-separated * * \param this_ pointer to own object attributes * \param string_view stringview to write, not 0-terminated * \return 0 in case of success, -1 otherwise */ static inline int xml_writer_write_xml_comment_view ( xml_writer_t *this_, utf8stringview_t string_view ); /*! * \brief checks if the stringview contains valid characters to form an xml-tag-name. * * Checks for characters according to Extensible Markup Language (XML) 1.1, chapter 2.3, Names and Tokens. * * Excludes the colon ":" because this is the namespace separator. * * \param this_ pointer to own object attributes * \param string_view string_view to check * \return true if string_view contains characters of which a valid xml-tag-name can be constructed */ static inline bool xml_writer_contains_xml_tag_name_characters ( xml_writer_t *this_, utf8stringview_t string_view ); /*! * \brief writes a valid xml-tag-name. * * Writes valid characters according to Extensible Markup Language (XML) 1.1, chapter 2.3, Names and Tokens * to the writer. Invalid ones are filtered. E.g. ", Design Decsisions" is transformed to "DesignDecisions" * * Excludes the colon ":" because this is the namespace separator. * * \param this_ pointer to own object attributes * \param string_view string_view to 1) filter and 2) write * \return 0 in case of success, -1 otherwise */ static inline int xml_writer_write_xml_tag_name_characters ( xml_writer_t *this_, utf8stringview_t string_view ); /*! * \brief resets the indentation level to 0 * * \param this_ pointer to own object attributes */ static inline void xml_writer_reset_indent ( xml_writer_t *this_ ); /*! * \brief increases the indentation level * * \param this_ pointer to own object attributes */ static inline void xml_writer_increase_indent ( xml_writer_t *this_ ); /*! * \brief decreases the indentation level * * \param this_ pointer to own object attributes */ static inline void xml_writer_decrease_indent ( xml_writer_t *this_ ); /*! * \brief adapts the encoding tables according to the current indentation level * * asserts that no more decreases are called than increases * * \param this_ pointer to own object attributes */ void xml_writer_private_update_encoding_tables ( xml_writer_t *this_ ); /*! * \brief checks if the codepoint is a valid character in an xml name * * Checks for characters according to Extensible Markup Language (XML) 1.1, chapter 2.3, Names and Tokens * * Excludes the colon ":" because this is the namespace separator. * * \param this_ pointer to own object attributes * \param codepoint codepoint to check * \param start true if this codepoint shall be the start of an xml name * \return true if codepoint is valid in an xml-tag-name */ static inline bool xml_writer_private_is_xml_tag_name_character ( xml_writer_t *this_, uint32_t codepoint, bool start ); #include "xml_writer.inl" #endif /* XML_WRITER_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/include/xml/xml_writer.inl000066400000000000000000000170271415120503000226640ustar00rootroot00000000000000/* File: xml_writer.inl; Copyright and License: see below */ #include #include "util/string/utf8error.h" #include "util/string/utf8codepoint.h" #include "util/string/utf8codepointiterator.h" static inline int xml_writer_write_plain ( xml_writer_t *this_, utf8string_t text ) { assert ( UTF8STRING_NULL != text ); int write_err; const size_t text_len = utf8string_get_length(text); universal_escaping_output_stream_change_rules( &((*this_).esc_output), (*this_).xml_plain_table ); write_err = universal_escaping_output_stream_write ( &((*this_).esc_output), text, text_len ); return ( write_err ); } static inline int xml_writer_write_plain_view ( xml_writer_t *this_, utf8stringview_t string_view ) { int write_err; const size_t length = utf8stringview_get_length( string_view ); const char *const start = utf8stringview_get_start( string_view ); universal_escaping_output_stream_change_rules( &((*this_).esc_output), (*this_).xml_plain_table ); write_err = universal_escaping_output_stream_write( &((*this_).esc_output), start, length ); return ( write_err ); } static inline int xml_writer_write_xml_enc ( xml_writer_t *this_, utf8string_t text ) { assert ( UTF8STRING_NULL != text ); int write_err; const size_t text_len = utf8string_get_length(text); universal_escaping_output_stream_change_rules( &((*this_).esc_output), (*this_).xml_encode_table ); write_err = universal_escaping_output_stream_write( &((*this_).esc_output), text, text_len ); return write_err; } static inline int xml_writer_write_xml_enc_view ( xml_writer_t *this_, utf8stringview_t string_view ) { int write_err; const size_t length = utf8stringview_get_length( string_view ); const char *const start = utf8stringview_get_start( string_view ); universal_escaping_output_stream_change_rules( &((*this_).esc_output), (*this_).xml_encode_table ); write_err = universal_escaping_output_stream_write( &((*this_).esc_output), start, length ); return write_err; } static inline int xml_writer_write_xml_comment ( xml_writer_t *this_, utf8string_t text ) { assert ( UTF8STRING_NULL != text ); int write_err; const size_t text_len = utf8string_get_length(text); universal_escaping_output_stream_change_rules( &((*this_).esc_output), (*this_).xml_comments_encode_table ); write_err = universal_escaping_output_stream_write( &((*this_).esc_output), text, text_len ); return write_err; } static inline int xml_writer_write_xml_comment_view ( xml_writer_t *this_, utf8stringview_t string_view ) { int write_err; const size_t length = utf8stringview_get_length( string_view ); const char *const start = utf8stringview_get_start( string_view ); universal_escaping_output_stream_change_rules( &((*this_).esc_output), (*this_).xml_comments_encode_table ); write_err = universal_escaping_output_stream_write( &((*this_).esc_output), start, length ); return write_err; } static inline bool xml_writer_contains_xml_tag_name_characters ( xml_writer_t *this_, utf8stringview_t string_view ) { bool result = false; utf8codepointiterator_t it; utf8codepointiterator_init( &it, string_view ); while( utf8codepointiterator_has_next( &it ) && ( ! result ) ) { utf8codepoint_t next = utf8codepointiterator_next( &it ); if ( xml_writer_private_is_xml_tag_name_character( this_, utf8codepoint_get_char( next ), true ) ) { result = true; } } utf8codepointiterator_destroy( &it ); return result; } static inline int xml_writer_write_xml_tag_name_characters ( xml_writer_t *this_, utf8stringview_t string_view ) { int result = -1; bool is_start = true; universal_escaping_output_stream_change_rules( &((*this_).esc_output), (*this_).xml_plain_table ); utf8codepointiterator_t it; utf8codepointiterator_init( &it, string_view ); while( utf8codepointiterator_has_next( &it ) ) { utf8codepoint_t next = utf8codepointiterator_next( &it ); if ( xml_writer_private_is_xml_tag_name_character( this_, utf8codepoint_get_char( next ), is_start ) ) { if ( is_start ) { is_start = false; result = 0; } const utf8codepointseq_t text = utf8codepoint_get_utf8( next ); const unsigned int text_len = utf8codepoint_get_length( next ); result |= universal_escaping_output_stream_write ( &((*this_).esc_output), &(text.seq), text_len ); } } utf8codepointiterator_destroy( &it ); return result; } static inline void xml_writer_reset_indent ( xml_writer_t *this_ ) { (*this_).indent_level = 0; xml_writer_private_update_encoding_tables( this_ ); } static inline void xml_writer_increase_indent ( xml_writer_t *this_ ) { (*this_).indent_level++; xml_writer_private_update_encoding_tables( this_ ); } static inline void xml_writer_decrease_indent ( xml_writer_t *this_ ) { if ( (*this_).indent_level > 0 ) { (*this_).indent_level--; xml_writer_private_update_encoding_tables( this_ ); } else { assert(false); } } static inline bool xml_writer_private_is_xml_tag_name_character ( xml_writer_t *this_, uint32_t codepoint, bool start ) { bool result = false; result = (( codepoint >= 'A' )&&( codepoint <= 'Z' )) /* [A-Z] */ || ( codepoint == '_' ) /* _ */ || (( codepoint >= 'a' )&&( codepoint <= 'z' )) /* [a-z] */ || (( codepoint >= 0xC0 )&&( codepoint <= 0xD6 )) /* [#xC0-#xD6] */ || (( codepoint >= 0xD8 )&&( codepoint <= 0xF6 )) /* [#xD8-#xF6] */ || (( codepoint >= 0xF8 )&&( codepoint <= 0x2FF )) /* [#xF8-#x2FF] */ || (( codepoint >= 0x370 )&&( codepoint <= 0x37D )) /* [#x370-#x37D] */ || (( codepoint >= 0x37F )&&( codepoint <= 0x1FFF )) /* [#x37F-#x1FFF] */ || (( codepoint >= 0x200C )&&( codepoint <= 0x200D )) /* [#x200C-#x200D] */ || (( codepoint >= 0x2070 )&&( codepoint <= 0x218F )) /* [#x2070-#x218F] */ || (( codepoint >= 0x2C00 )&&( codepoint <= 0x2FEF )) /* [#x2C00-#x2FEF] */ || (( codepoint >= 0x3001 )&&( codepoint <= 0xD7FF )) /* [#x3001-#xD7FF] */ || (( codepoint >= 0xF900 )&&( codepoint <= 0xFDCF )) /* [#xF900-#xFDCF] */ || (( codepoint >= 0xFDF0 )&&( codepoint <= 0xFFFD )) /* [#xFDF0-#xFFFD] */ || (( codepoint >= 0x10000 )&&( codepoint <= 0xEFFFF )); /* [#x10000-#xEFFFF] */ if (( ! result )&&( ! start )) { /* after name start, more characters are allowed: */ result = ( codepoint == '-' ) /* - */ || ( codepoint == '.' ) /* . */ || (( codepoint >= '0' )&&( codepoint <= '9' )) /* [0-9] */ || ( codepoint == 0xB7 ) /* xB7 */ || (( codepoint >= 0x0300 )&&( codepoint <= 0x036F )) /* [#x0300-#x036F] */ || (( codepoint >= 0x203F )&&( codepoint <= 0x2040 )); /* [#x203F-#x2040] */ } return result; } /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/000077500000000000000000000000001415120503000170325ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/source/image/000077500000000000000000000000001415120503000201145ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/source/image/image_format_writer.c000066400000000000000000000167621415120503000243220ustar00rootroot00000000000000/* File: image_format_writer.c; Copyright and License: see below */ #include "image/image_format_writer.h" #include "trace.h" #include "tslog.h" #include #include #include #include #include #include #include void image_format_writer_init ( image_format_writer_t *this_, data_database_reader_t *db_reader, data_visible_set_t *input_data ) { TRACE_BEGIN(); assert( NULL != db_reader ); assert( NULL != input_data ); (*this_).db_reader = db_reader; (*this_).input_data = input_data; geometry_rectangle_init( &((*this_).bounds), 0.0, 0.0, 800.0, 600.0 ); pencil_diagram_maker_init( &((*this_).painter), input_data ); TRACE_END(); } void image_format_writer_destroy( image_format_writer_t *this_ ) { TRACE_BEGIN(); pencil_diagram_maker_destroy( &((*this_).painter) ); geometry_rectangle_destroy(&((*this_).bounds)); (*this_).input_data = NULL; (*this_).db_reader = NULL; TRACE_END(); } #ifndef CAIRO_HAS_SVG_SURFACE #error "no svg" #endif #ifndef CAIRO_HAS_PNG_FUNCTIONS #error "no png" #endif int image_format_writer_render_diagram_to_file( image_format_writer_t *this_, data_id_t diagram_id, io_file_format_t export_type, const char* target_filename, data_stat_t *io_render_stat ) { TRACE_BEGIN(); assert( NULL != target_filename ); assert( NULL != io_render_stat ); assert( IO_FILE_FORMAT_TXT != export_type ); assert( data_id_get_table( &diagram_id ) == DATA_TABLE_DIAGRAM ); const data_row_id_t diagram_row_id = data_id_get_row_id( &diagram_id ); int result = 0; data_visible_set_init( (*this_).input_data ); const data_error_t d_err = data_visible_set_load( (*this_).input_data, diagram_row_id, (*this_).db_reader ); if( d_err != DATA_ERROR_NONE ) { result = -1; assert(false); } assert( data_visible_set_is_valid ( (*this_).input_data ) ); result |= image_format_writer_private_render_surface_to_file( this_, export_type, target_filename, io_render_stat ); data_visible_set_destroy( (*this_).input_data ); TRACE_END_ERR( result ); return result; } int image_format_writer_private_render_surface_to_file( image_format_writer_t *this_, io_file_format_t export_type, const char* target_filename, data_stat_t *io_render_stat ) { TRACE_BEGIN(); assert( NULL != target_filename ); assert( IO_FILE_FORMAT_TXT != export_type ); int result = 0; /* create surface */ cairo_surface_t *surface; if ( IO_FILE_FORMAT_SVG == export_type ) { surface = (cairo_surface_t *) cairo_svg_surface_create( target_filename, geometry_rectangle_get_width( &((*this_).bounds) ), geometry_rectangle_get_height( &((*this_).bounds) ) ); } else if ( IO_FILE_FORMAT_PDF == export_type ) { surface = (cairo_surface_t *) cairo_pdf_surface_create ( target_filename, geometry_rectangle_get_width( &((*this_).bounds) ), geometry_rectangle_get_height( &((*this_).bounds) ) ); } else if ( IO_FILE_FORMAT_PS == export_type ) { surface = (cairo_surface_t *) cairo_ps_surface_create ( target_filename, geometry_rectangle_get_width( &((*this_).bounds) ), geometry_rectangle_get_height( &((*this_).bounds) ) ); } else /*if ( IO_FILE_FORMAT_PNG == export_type )*/ { surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, (uint32_t) geometry_rectangle_get_width( &((*this_).bounds) ), (uint32_t) geometry_rectangle_get_height( &((*this_).bounds) ) ); } /* draw on surface */ if ( CAIRO_STATUS_SUCCESS != cairo_surface_status( surface ) ) { TSLOG_ERROR_INT( "surface could not be created", cairo_surface_status( surface ) ); result = -1; } else { cairo_t *cr; cr = cairo_create (surface); /* draw diagram */ /* draw paper */ cairo_set_source_rgba( cr, 1.0, 1.0, 1.0, 1.0 ); cairo_rectangle ( cr, geometry_rectangle_get_left( &((*this_).bounds) ), geometry_rectangle_get_top( &((*this_).bounds) ), geometry_rectangle_get_width( &((*this_).bounds) ), geometry_rectangle_get_height( &((*this_).bounds) ) ); cairo_fill (cr); /* layout diagram */ data_stat_t temp_stat; data_stat_init( &temp_stat ); pencil_diagram_maker_define_grid ( &((*this_).painter), (*this_).bounds ); pencil_diagram_maker_layout_elements ( &((*this_).painter), cr, &temp_stat ); #ifdef NDEBUG /* in release mode, do not report layouting warnings to the user */ data_stat_reset_series( &temp_stat, DATA_STAT_SERIES_WARNING ); #endif data_stat_add( io_render_stat, &temp_stat ); data_stat_destroy( &temp_stat ); /* draw the current diagram */ data_id_t void_id; data_id_init_void( &void_id ); data_small_set_t void_set; data_small_set_init( &void_set ); pencil_diagram_maker_draw ( &((*this_).painter), void_id, void_id, &void_set, cr ); /* finish drawing context */ cairo_destroy (cr); /* finish surface */ if ( IO_FILE_FORMAT_PNG == export_type ) { cairo_status_t png_result; png_result = cairo_surface_write_to_png ( surface, target_filename ); if ( CAIRO_STATUS_SUCCESS != png_result ) { TSLOG_ERROR("error writing png."); result = -1; } } else { cairo_surface_finish ( surface ); } } cairo_surface_destroy ( surface ); TRACE_END_ERR( result ); return result; } /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/io_export_diagram_traversal.c000066400000000000000000000401351415120503000247600ustar00rootroot00000000000000/* File: io_export_diagram_traversal.c; Copyright and License: see below */ #include "io_export_diagram_traversal.h" #include "trace.h" #include "data_diagram.h" #include "data_classifier.h" #include #include #include void io_export_diagram_traversal_init( io_export_diagram_traversal_t *this_, data_database_reader_t *db_reader, data_visible_set_t *input_data, data_stat_t *io_export_stat, io_element_writer_t *out_element_writer ) { TRACE_BEGIN(); assert( NULL != db_reader ); assert( NULL != input_data ); assert( NULL != io_export_stat ); assert( NULL != out_element_writer ); (*this_).db_reader = db_reader; (*this_).input_data = input_data; data_rules_init ( &((*this_).filter_rules) ); (*this_).export_stat = io_export_stat; (*this_).element_writer = out_element_writer; TRACE_END(); } void io_export_diagram_traversal_destroy( io_export_diagram_traversal_t *this_ ) { TRACE_BEGIN(); data_rules_destroy ( &((*this_).filter_rules) ); (*this_).input_data = NULL; (*this_).db_reader = NULL; (*this_).export_stat = NULL; (*this_).element_writer = NULL; TRACE_END(); } int io_export_diagram_traversal_begin_and_walk_diagram ( io_export_diagram_traversal_t *this_, data_id_t diagram_id, const char *diagram_file_base_name ) { TRACE_BEGIN(); assert( data_id_is_valid( &diagram_id ) ); assert( data_id_get_table( &diagram_id ) == DATA_TABLE_DIAGRAM ); int write_err = 0; /* load data to be drawn */ data_visible_set_init( (*this_).input_data ); const data_error_t d_err = data_visible_set_load( (*this_).input_data, data_id_get_row_id( &diagram_id ), (*this_).db_reader ); if( d_err != DATA_ERROR_NONE ) { write_err = -1; assert(false); } else { assert( data_visible_set_is_valid ( (*this_).input_data ) ); /* write diagram */ const data_diagram_t *diag_ptr = data_visible_set_get_diagram_const( (*this_).input_data ); assert( diag_ptr != NULL ); assert( data_diagram_is_valid( diag_ptr ) ); TRACE_INFO_INT("printing diagram with id",data_diagram_get_row_id(diag_ptr)); /* load parent diagram if there is one */ data_diagram_init_empty( &((*this_).temp_parent_diag) ); const data_row_id_t parent_id = data_diagram_get_parent_row_id( diag_ptr ); if ( DATA_ROW_ID_VOID != parent_id ) { const data_error_t d_err2 = data_database_reader_get_diagram_by_id( (*this_).db_reader, parent_id, &((*this_).temp_parent_diag) ); if( d_err2 != DATA_ERROR_NONE ) { write_err = -1; assert(false); } } write_err |= io_element_writer_start_diagram( (*this_).element_writer, diag_ptr ); write_err |= io_element_writer_assemble_diagram( (*this_).element_writer, &((*this_).temp_parent_diag), diag_ptr, diagram_file_base_name ); data_diagram_destroy( &((*this_).temp_parent_diag) ); /* write all classifiers */ write_err |= io_export_diagram_traversal_private_iterate_diagram_classifiers( this_, (*this_).input_data ); } data_visible_set_destroy( (*this_).input_data ); TRACE_END_ERR( write_err ); return write_err; } int io_export_diagram_traversal_end_diagram ( io_export_diagram_traversal_t *this_, data_id_t diagram_id ) { TRACE_BEGIN(); assert( data_id_is_valid( &diagram_id ) ); assert( data_id_get_table( &diagram_id ) == DATA_TABLE_DIAGRAM ); int write_err = 0; /* load diagram only to be drawn */ data_diagram_t *const diagram_ptr = data_visible_set_get_diagram_ptr ( (*this_).input_data ); const data_error_t d_err = data_database_reader_get_diagram_by_id( (*this_).db_reader, data_id_get_row_id( &diagram_id ), diagram_ptr ); if( d_err != DATA_ERROR_NONE ) { write_err = -1; assert(false); } else { assert( data_diagram_is_valid( diagram_ptr ) ); /* write footer */ write_err |= io_element_writer_end_diagram( (*this_).element_writer, diagram_ptr ); data_diagram_destroy( diagram_ptr ); } TRACE_END_ERR( write_err ); return write_err; } int io_export_diagram_traversal_private_iterate_diagram_classifiers ( io_export_diagram_traversal_t *this_, const data_visible_set_t *diagram_data ) { TRACE_BEGIN(); assert( diagram_data != NULL ); assert( data_visible_set_is_valid( diagram_data ) ); int write_err = 0; /* iterate over all classifiers */ uint32_t count; count = data_visible_set_get_visible_classifier_count ( diagram_data ); for ( uint32_t index = 0; index < count; index ++ ) { /* get classifier */ const data_visible_classifier_t *const visible_classifier = data_visible_set_get_visible_classifier_const ( diagram_data, index ); if (( visible_classifier != NULL ) && ( data_visible_classifier_is_valid( visible_classifier ) )) { const data_classifier_t *classifier = data_visible_classifier_get_classifier_const( visible_classifier ); const data_id_t classifier_id = data_classifier_get_data_id( classifier ); TRACE_INFO_INT( "printing classifier with id", data_id_get_row_id( &classifier_id ) ); /* start+assemble classifier */ write_err |= io_element_writer_start_classifier( (*this_).element_writer, DATA_CLASSIFIER_TYPE_VOID, /* no host */ classifier ); write_err |= io_element_writer_assemble_classifier( (*this_).element_writer, DATA_CLASSIFIER_TYPE_VOID, /* no host */ classifier ); /* print all features of the classifier */ write_err |= io_export_diagram_traversal_private_iterate_classifier_features( this_, diagram_data, classifier_id ); /* end classifier */ write_err |= io_element_writer_end_classifier( (*this_).element_writer, DATA_CLASSIFIER_TYPE_VOID, /* no host */ classifier ); /* print all relationships starting from classifier_id */ write_err |= io_export_diagram_traversal_private_iterate_classifier_relationships( this_, diagram_data, classifier_id ); const data_diagramelement_t *diagele = data_visible_classifier_get_diagramelement_const( visible_classifier ); const data_id_t diagele_id = data_diagramelement_get_data_id( diagele ); const data_diagram_t *const diagram_ptr = data_visible_set_get_diagram_ptr ( (*this_).input_data ); const data_row_id_t focused_feature_id = data_diagramelement_get_focused_feature_row_id( diagele ); const data_feature_t *const focused_f_or_null = ( focused_feature_id == DATA_ROW_ID_VOID ) ? NULL : data_visible_set_get_feature_by_id_const( diagram_data, focused_feature_id ); TRACE_INFO_INT( "printing diagramelement with id", data_id_get_row_id( &diagele_id ) ); /* start+assemble+end diagramelement */ write_err |= io_element_writer_start_diagramelement( (*this_).element_writer, diagram_ptr, diagele ); write_err |= io_element_writer_assemble_diagramelement( (*this_).element_writer, diagram_ptr, diagele, classifier, focused_f_or_null ); write_err |= io_element_writer_end_diagramelement( (*this_).element_writer, diagram_ptr, diagele ); } else { assert( false ); } } TRACE_END_ERR( write_err ); return write_err; } int io_export_diagram_traversal_private_iterate_classifier_features ( io_export_diagram_traversal_t *this_, const data_visible_set_t *diagram_data, data_id_t classifier_id ) { TRACE_BEGIN(); assert( diagram_data != NULL ); assert( data_visible_set_is_valid( diagram_data ) ); assert( DATA_TABLE_CLASSIFIER == data_id_get_table( &classifier_id ) ); assert( DATA_ROW_ID_VOID != data_id_get_row_id( &classifier_id) ); int write_err = 0; /* iterate over all features */ uint32_t count; count = data_visible_set_get_feature_count ( diagram_data ); for ( uint32_t index = 0; index < count; index ++ ) { /* get feature */ const data_feature_t *feature; feature = data_visible_set_get_feature_const ( diagram_data, index ); if (( feature != NULL ) && ( data_feature_is_valid( feature ) )) { const data_id_t f_classifier_id = data_feature_get_classifier_data_id( feature ); if ( data_id_equals( &classifier_id, &f_classifier_id ) ) { const bool is_visible = data_rules_diagram_shows_feature ( &((*this_).filter_rules), diagram_data, data_feature_get_row_id( feature ) ); const bool is_lifeline =( DATA_FEATURE_TYPE_LIFELINE == data_feature_get_main_type( feature ) ); if ( is_visible && ( ! is_lifeline ) ) { write_err |= io_element_writer_assemble_feature( (*this_).element_writer, DATA_CLASSIFIER_TYPE_VOID, /* not needed */ feature ); } } } else { assert( false ); } } TRACE_END_ERR( write_err ); return write_err; } int io_export_diagram_traversal_private_iterate_classifier_relationships ( io_export_diagram_traversal_t *this_, const data_visible_set_t *diagram_data, data_id_t from_classifier_id ) { TRACE_BEGIN(); assert( diagram_data != NULL ); assert( data_visible_set_is_valid( diagram_data ) ); assert( DATA_TABLE_CLASSIFIER == data_id_get_table( &from_classifier_id ) ); assert( DATA_ROW_ID_VOID != data_id_get_row_id( &from_classifier_id) ); int write_err = 0; /* iterate over all relationships */ uint32_t count; count = data_visible_set_get_relationship_count ( diagram_data ); for ( uint32_t index = 0; index < count; index ++ ) { /* get relationship */ const data_relationship_t *relation; relation = data_visible_set_get_relationship_const ( diagram_data, index ); if (( relation != NULL ) && ( data_relationship_is_valid( relation ) )) { const data_id_t r_from_classifier_id = data_relationship_get_from_classifier_data_id( relation ); if ( data_id_equals( &from_classifier_id, &r_from_classifier_id ) ) { const data_id_t relation_id = data_relationship_get_data_id( relation ); const bool is_visible = data_rules_diagram_shows_relationship ( &((*this_).filter_rules), diagram_data, data_id_get_row_id( &relation_id ) ); if ( is_visible /* no filter for duplicates */ ) { const data_row_id_t to_classifier_id = data_relationship_get_to_classifier_row_id( relation ); const data_classifier_t *dest_classifier = data_visible_set_get_classifier_by_id_const ( diagram_data, to_classifier_id ); if ( dest_classifier != NULL ) { /* destination classifier found, print the relation */ write_err |= io_element_writer_assemble_relationship( (*this_).element_writer, NULL, relation, NULL, NULL, dest_classifier, NULL ); } else { assert ( false ); /* is_visible should not be true if dest_classifier == NULL */ } } } } else { assert( false ); } } TRACE_END_ERR( write_err ); return write_err; } /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/io_export_flat_traversal.c000066400000000000000000000375001415120503000243040ustar00rootroot00000000000000/* File: io_export_flat_traversal.c; Copyright and License: see below */ #include "io_export_flat_traversal.h" #include "trace.h" #include "data_diagram.h" #include "data_classifier.h" #include #include #include void io_export_flat_traversal_init( io_export_flat_traversal_t *this_, data_database_reader_t *db_reader, data_stat_t *io_export_stat, io_element_writer_t *out_element_writer ) { TRACE_BEGIN(); assert( NULL != db_reader ); assert( NULL != io_export_stat ); assert( NULL != out_element_writer ); (*this_).db_reader = db_reader; (*this_).export_stat = io_export_stat; (*this_).element_writer = out_element_writer; TRACE_END(); } void io_export_flat_traversal_destroy( io_export_flat_traversal_t *this_ ) { TRACE_BEGIN(); (*this_).db_reader = NULL; (*this_).export_stat = NULL; (*this_).element_writer = NULL; TRACE_END(); } int io_export_flat_traversal_iterate_classifiers ( io_export_flat_traversal_t *this_ ) { TRACE_BEGIN(); int write_err = 0; { data_error_t data_err; data_database_iterator_classifiers_t classifier_iterator; /* init the iterator */ data_database_iterator_classifiers_init_empty( &classifier_iterator ); data_err = data_database_reader_get_all_classifiers_iterator ( (*this_).db_reader, &classifier_iterator ); if ( data_err != DATA_ERROR_NONE ) { write_err = -1; } else { while( data_database_iterator_classifiers_has_next( &classifier_iterator ) && ( write_err==0 ) ) { data_err = data_database_iterator_classifiers_next( &classifier_iterator, &((*this_).temp_classifier) ); if ( data_err != DATA_ERROR_NONE ) { write_err = -1; } else { write_err |= io_export_flat_traversal_private_traverse_classifier( this_, &((*this_).temp_classifier) ); data_classifier_destroy( &((*this_).temp_classifier) ); } } } data_err = data_database_iterator_classifiers_destroy( &classifier_iterator ); if ( data_err != DATA_ERROR_NONE ) { write_err = -1; } } TRACE_END_ERR( write_err ); return write_err; } int io_export_flat_traversal_private_traverse_classifier ( io_export_flat_traversal_t *this_, const data_classifier_t *classifier ) { TRACE_BEGIN(); assert( NULL != classifier ); assert( data_classifier_is_valid( classifier ) ); int write_err = 0; /* start classifier */ { const data_classifier_type_t host_type = DATA_CLASSIFIER_TYPE_VOID; write_err |= io_element_writer_start_classifier( (*this_).element_writer, host_type, classifier ); write_err |= io_element_writer_assemble_classifier( (*this_).element_writer, host_type, classifier ); } /* start features and relationships */ { data_node_set_init( &((*this_).temp_node_data) ); const data_error_t data_err_2 = data_node_set_load( &((*this_).temp_node_data), data_classifier_get_row_id( classifier ), (*this_).db_reader ); if ( data_err_2 != DATA_ERROR_NONE ) { write_err = -1; } else { /* write the features */ write_err |= io_export_flat_traversal_private_iterate_features( this_, &((*this_).temp_node_data) ); /* write the relationships */ write_err |= io_export_flat_traversal_private_iterate_relationships( this_, &((*this_).temp_node_data) ); } data_node_set_destroy( &((*this_).temp_node_data) ); } /* end classifier */ { const data_classifier_type_t host_type = DATA_CLASSIFIER_TYPE_VOID; write_err |= io_element_writer_end_classifier( (*this_).element_writer, host_type, classifier ); } TRACE_END_ERR( write_err ); return write_err; } int io_export_flat_traversal_private_iterate_features ( io_export_flat_traversal_t *this_, const data_node_set_t *node_data ) { TRACE_BEGIN(); assert( node_data != NULL ); assert( data_node_set_is_valid( node_data ) ); int write_err = 0; /* get parent classifier */ const data_classifier_t *const classifier = data_node_set_get_classifier_const ( node_data ); /* iterate over all features */ const uint32_t count = data_node_set_get_feature_count ( node_data ); for ( uint32_t index = 0; index < count; index ++ ) { /* get feature */ const data_feature_t *feature; feature = data_node_set_get_feature_const ( node_data, index ); if (( feature != NULL ) && ( data_feature_is_valid( feature ) )) { write_err |= io_element_writer_start_feature( (*this_).element_writer, data_classifier_get_main_type( classifier ), feature ); write_err |= io_element_writer_assemble_feature( (*this_).element_writer, data_classifier_get_main_type( classifier ), feature ); write_err |= io_element_writer_end_feature( (*this_).element_writer, data_classifier_get_main_type( classifier ), feature ); } else { assert( false ); } } TRACE_END_ERR( write_err ); return write_err; } int io_export_flat_traversal_private_iterate_relationships ( io_export_flat_traversal_t *this_, const data_node_set_t *node_data ) { TRACE_BEGIN(); assert( node_data != NULL ); assert( data_node_set_is_valid( node_data ) ); int write_err = 0; const data_classifier_t *const classifier = data_node_set_get_classifier_const ( node_data ); const data_classifier_type_t host_type = data_classifier_get_main_type( classifier ); /* iterate over all relationships */ const uint32_t count = data_node_set_get_relationship_count ( node_data ); for ( uint32_t index = 0; index < count; index ++ ) { /* get relationship */ const data_relationship_t *relation; relation = data_node_set_get_relationship_const ( node_data, index ); if (( relation != NULL ) && ( data_relationship_is_valid( relation ) )) { /* determine if the relationship is outgoing */ const bool is_outgoing = ( data_relationship_get_from_classifier_row_id( relation ) == data_classifier_get_row_id( classifier ) ); if ( is_outgoing ) { /* get the element types at both ends of the relationship */ data_classifier_init_empty( &((*this_).temp_from_classifier) ); data_feature_init_empty( &((*this_).temp_from_feature) ); data_classifier_init_empty( &((*this_).temp_to_classifier) ); data_feature_init_empty( &((*this_).temp_to_feature) ); const data_error_t d_err = io_export_flat_traversal_private_get_relationship_ends( this_, relation, node_data, &((*this_).temp_from_classifier), &((*this_).temp_from_feature), &((*this_).temp_to_classifier), &((*this_).temp_to_feature) ); if ( d_err == DATA_ERROR_NONE ) { /* all classifiers found, print the relation */ write_err |= io_element_writer_start_relationship( (*this_).element_writer, host_type, relation ); write_err |= io_element_writer_assemble_relationship( (*this_).element_writer, classifier, relation, &((*this_).temp_from_classifier), &((*this_).temp_from_feature), &((*this_).temp_to_classifier), &((*this_).temp_to_feature) ); write_err |= io_element_writer_end_relationship( (*this_).element_writer, host_type, relation ); } else { write_err |= -1; } data_classifier_destroy( &((*this_).temp_from_classifier) ); data_feature_destroy( &((*this_).temp_from_feature) ); data_classifier_destroy( &((*this_).temp_to_classifier) ); data_feature_destroy( &((*this_).temp_to_feature) ); } } else { assert( false ); } } TRACE_END_ERR( write_err ); return write_err; } data_error_t io_export_flat_traversal_private_get_relationship_ends( io_export_flat_traversal_t *this_, const data_relationship_t *relation, const data_node_set_t *node_data, data_classifier_t *out_from_c, data_feature_t *out_from_f, data_classifier_t *out_to_c, data_feature_t *out_to_f ) { TRACE_BEGIN(); assert( relation != NULL ); assert( node_data != NULL ); assert( out_from_c != NULL ); assert( out_from_f != NULL ); assert( out_to_c != NULL ); assert( out_to_f != NULL ); data_error_t data_err = DATA_ERROR_NONE; { /* get from classifier */ const data_row_id_t from_clcassifier_row_id = data_relationship_get_from_classifier_row_id ( relation ); bool from_classifier_found = false; if ( node_data != NULL ) { const data_classifier_t *node_classifier = data_node_set_get_classifier_const( node_data ); if (( node_classifier != NULL ) &&( from_clcassifier_row_id == data_classifier_get_row_id ( node_classifier ) )) { data_classifier_replace( out_from_c, node_classifier ); from_classifier_found = true; } } if ( ! from_classifier_found ) { data_err |= data_database_reader_get_classifier_by_id ( (*this_).db_reader, from_clcassifier_row_id, out_from_c ); } /* get from feature */ const data_row_id_t from_feature_row_id = data_relationship_get_from_feature_row_id ( relation ); bool from_feature_found = ( from_feature_row_id == DATA_ROW_ID_VOID ); if (( node_data != NULL )&&( ! from_feature_found )) { const data_feature_t *node_feature = data_node_set_get_feature_by_id_const ( node_data, from_feature_row_id ); if ( node_feature != NULL ) { data_feature_replace( out_from_f, node_feature ); from_feature_found = true; } } if ( ! from_feature_found ) { data_err |= data_database_reader_get_feature_by_id ( (*this_).db_reader, from_feature_row_id, out_from_f ); } /* get to classifier */ const data_row_id_t to_classifier_row_id = data_relationship_get_to_classifier_row_id ( relation ); bool to_classifier_found = false; if ( node_data != NULL ) { const data_classifier_t *node_classifier = data_node_set_get_classifier_const( node_data ); if (( node_classifier != NULL ) &&( to_classifier_row_id == data_classifier_get_row_id ( node_classifier ) )) { data_classifier_replace( out_to_c, node_classifier ); to_classifier_found = true; } } if ( ! to_classifier_found ) { data_err |= data_database_reader_get_classifier_by_id ( (*this_).db_reader, to_classifier_row_id, out_to_c ); } /* get to feature */ const data_row_id_t to_feature_row_id = data_relationship_get_to_feature_row_id ( relation ); bool to_feature_found = ( to_feature_row_id == DATA_ROW_ID_VOID ); if (( node_data != NULL )&&( ! to_feature_found )) { const data_feature_t *node_feature = data_node_set_get_feature_by_id_const ( node_data, to_feature_row_id ); if ( node_feature != NULL ) { data_feature_replace( out_to_f, node_feature ); to_feature_found = true; } } if ( ! to_feature_found ) { data_err |= data_database_reader_get_feature_by_id ( (*this_).db_reader, to_feature_row_id, out_to_f ); } } if ( data_err != DATA_ERROR_NONE ) { TSLOG_ERROR_INT( "A relationship references classifier(s) and/or feature(s) that do not exist:", data_relationship_get_row_id ( relation ) ); } TRACE_END_ERR( data_err ); return data_err; } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/io_export_interaction_traversal.c000066400000000000000000000564331415120503000257030ustar00rootroot00000000000000/* File: io_export_interaction_traversal.c; Copyright and License: see below */ #include "io_export_interaction_traversal.h" #include "xmi/xmi_element_info.h" #include "xmi/xmi_element_info_map.h" #include "trace.h" #include "data_diagram.h" #include "data_classifier.h" #include #include #include void io_export_interaction_traversal_init( io_export_interaction_traversal_t *this_, data_database_reader_t *db_reader, data_visible_set_t *input_data, universal_array_list_t *io_written_id_set, data_stat_t *io_export_stat, io_element_writer_t *out_element_writer ) { TRACE_BEGIN(); assert( NULL != db_reader ); assert( NULL != input_data ); assert( NULL != io_written_id_set ); assert( NULL != io_export_stat ); assert( NULL != out_element_writer ); (*this_).db_reader = db_reader; (*this_).input_data = input_data; data_rules_init ( &((*this_).filter_rules) ); (*this_).written_id_set = io_written_id_set; (*this_).export_stat = io_export_stat; (*this_).element_writer = out_element_writer; data_classifier_init_empty( &((*this_).fake_interaction_classifier) ); data_classifier_set_main_type( &((*this_).fake_interaction_classifier), DATA_CLASSIFIER_TYPE_INTERACTION ); data_feature_init_empty( &((*this_).fake_lifeline_feature) ); data_feature_set_main_type( &((*this_).fake_lifeline_feature), DATA_FEATURE_TYPE_LIFELINE ); TRACE_END(); } void io_export_interaction_traversal_destroy( io_export_interaction_traversal_t *this_ ) { TRACE_BEGIN(); data_classifier_destroy( &((*this_).fake_interaction_classifier) ); data_feature_destroy( &((*this_).fake_lifeline_feature) ); data_rules_destroy ( &((*this_).filter_rules) ); (*this_).input_data = NULL; (*this_).db_reader = NULL; (*this_).written_id_set = NULL; (*this_).export_stat = NULL; (*this_).element_writer = NULL; TRACE_END(); } int io_export_interaction_traversal_iterate_classifier_occurrences ( io_export_interaction_traversal_t *this_, data_classifier_type_t nesting_type, data_id_t classifier_id ) { TRACE_BEGIN(); assert( data_id_is_valid( &classifier_id ) ); int write_err = 0; data_small_set_t out_showing_diagram_ids; data_small_set_init( &out_showing_diagram_ids ); { const data_error_t data_err = data_database_reader_get_diagram_ids_by_classifier_id ( (*this_).db_reader, data_id_get_row_id( &classifier_id ), &out_showing_diagram_ids ); if( data_err == DATA_ERROR_NONE ) { const uint32_t diag_count = data_small_set_get_count( &out_showing_diagram_ids ); for ( uint32_t diag_idx = 0; diag_idx < diag_count; diag_idx ++ ) { const data_id_t diag_id = data_small_set_get_id( &out_showing_diagram_ids, diag_idx ); const bool duplicate_diagram =( -1 != universal_array_list_get_index_of( (*this_).written_id_set, &diag_id ) ); if ( ! duplicate_diagram ) { write_err |= io_export_interaction_traversal_private_walk_diagram( this_, nesting_type, diag_id ); } } } else { write_err = -1; assert(false); } } data_small_set_destroy( &out_showing_diagram_ids ); TRACE_END_ERR( write_err ); return write_err; } int io_export_interaction_traversal_private_walk_diagram ( io_export_interaction_traversal_t *this_, data_classifier_type_t nesting_type, data_id_t diagram_id ) { TRACE_BEGIN(); assert( data_id_get_table( &diagram_id ) == DATA_TABLE_DIAGRAM ); int write_err = 0; /* write part for current diagram */ if ( data_id_is_valid( &diagram_id ) ) { /* load data to be drawn */ data_visible_set_init( (*this_).input_data ); const data_error_t d_err = data_visible_set_load( (*this_).input_data, data_id_get_row_id( &diagram_id ), (*this_).db_reader ); if( d_err != DATA_ERROR_NONE ) { write_err = -1; assert(false); } assert( data_visible_set_is_valid ( (*this_).input_data ) ); /* write diagram */ const data_diagram_t *diag_ptr = data_visible_set_get_diagram_const( (*this_).input_data ); assert( diag_ptr != NULL ); assert( data_diagram_is_valid( diag_ptr ) ); const data_diagram_type_t diag_type = data_diagram_get_diagram_type( diag_ptr ); const bool is_interaction_type = (( diag_type == DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM ) || ( diag_type == DATA_DIAGRAM_TYPE_UML_COMMUNICATION_DIAGRAM ) || ( diag_type == DATA_DIAGRAM_TYPE_UML_TIMING_DIAGRAM ) || ( diag_type == DATA_DIAGRAM_TYPE_INTERACTION_OVERVIEW_DIAGRAM )); if ( is_interaction_type ) { TRACE_INFO_INT("exporting diagram as interaction, id:",data_diagram_get_row_id(diag_ptr)); /* add this classifier to the already written elements */ write_err |= universal_array_list_append( (*this_).written_id_set, &diagram_id ); data_classifier_t *const fake_interaction = &((*this_).fake_interaction_classifier); write_err |= io_export_interaction_traversal_private_fake_interaction( this_, diag_ptr, fake_interaction ); //write_err |= xmi_interaction_writer_start_diagram( &((*this_).interaction_writer), nesting_type, diag_ptr ); write_err |= io_element_writer_start_classifier( (*this_).element_writer, nesting_type, fake_interaction ); write_err |= io_element_writer_assemble_classifier( (*this_).element_writer, nesting_type, fake_interaction); /* write all classifiers */ write_err |= io_export_interaction_traversal_private_iterate_diagram_classifiers( this_, (*this_).input_data, fake_interaction ); //write_err |= xmi_interaction_writer_end_diagram( &((*this_).interaction_writer), nesting_type ); write_err |= io_element_writer_end_classifier( (*this_).element_writer, nesting_type, fake_interaction); } data_visible_set_destroy( (*this_).input_data ); } TRACE_END_ERR( write_err ); return write_err; } int io_export_interaction_traversal_private_iterate_diagram_classifiers ( io_export_interaction_traversal_t *this_, const data_visible_set_t *diagram_data, const data_classifier_t *fake_interaction ) { TRACE_BEGIN(); assert( diagram_data != NULL ); assert( data_visible_set_is_valid( diagram_data ) ); int write_err = 0; /* iterate over all classifiers */ uint32_t count; count = data_visible_set_get_visible_classifier_count ( diagram_data ); for ( uint32_t index = 0; index < count; index ++ ) { /* get classifier */ const data_visible_classifier_t *visible_classifier; visible_classifier = data_visible_set_get_visible_classifier_const ( diagram_data, index ); if (( visible_classifier != NULL ) && ( data_visible_classifier_is_valid( visible_classifier ) )) { const data_classifier_t *classifier; classifier = data_visible_classifier_get_classifier_const( visible_classifier ); const data_id_t classifier_id = data_classifier_get_data_id(classifier); TRACE_INFO_INT( "printing classifier with id", data_id_get_row_id( &classifier_id ) ); const data_diagramelement_t *diagele; diagele = data_visible_classifier_get_diagramelement_const( visible_classifier ); const data_id_t focused_feature_id = data_diagramelement_get_focused_feature_data_id( diagele ); /* print classifiers if of type comment or interaction-diagram-reference */ { const data_classifier_type_t parent_type = DATA_CLASSIFIER_TYPE_INTERACTION; /* fake parent type */ const data_classifier_type_t classifier_type = data_classifier_get_main_type(classifier); const bool is_classifier_compliant_here = io_element_writer_can_classifier_nest_classifier ( (*this_).element_writer, parent_type, classifier_type ); const bool is_duplicate = ( -1 != universal_array_list_get_index_of( (*this_).written_id_set, &classifier_id ) ); if ( is_classifier_compliant_here && ( ! is_duplicate ) ) { /* add the classifier to the duplicates list */ write_err |= universal_array_list_append( (*this_).written_id_set, &classifier_id ); /* print */ write_err |= io_element_writer_start_classifier( (*this_).element_writer, parent_type, classifier ); write_err |= io_element_writer_assemble_classifier( (*this_).element_writer, parent_type, classifier ); write_err |= io_element_writer_end_classifier( (*this_).element_writer, parent_type, classifier ); } } /* print focused features (lifelines) of the visible classifier */ if ( data_id_is_valid( &focused_feature_id ) ) { write_err |= io_export_interaction_traversal_private_look_for_focused_feature( this_, diagram_data, focused_feature_id ); /* print all relationships starting from focused feature (lifeline) of classifier_id */ write_err |= io_export_interaction_traversal_private_iterate_feature_relationships( this_, diagram_data, classifier_id, focused_feature_id, fake_interaction ); } } else { assert( false ); } } TRACE_END_ERR( write_err ); return write_err; } int io_export_interaction_traversal_private_look_for_focused_feature ( io_export_interaction_traversal_t *this_, const data_visible_set_t *diagram_data, data_id_t focused_feature_id ) { TRACE_BEGIN(); assert( diagram_data != NULL ); assert( data_visible_set_is_valid( diagram_data ) ); assert( DATA_TABLE_FEATURE == data_id_get_table( &focused_feature_id ) ); assert( DATA_ROW_ID_VOID != data_id_get_row_id( &focused_feature_id) ); int write_err = 0; /* iterate over all features */ uint32_t count; count = data_visible_set_get_feature_count ( diagram_data ); for ( uint32_t index = 0; index < count; index ++ ) { /* get feature */ const data_feature_t *feature; feature = data_visible_set_get_feature_const ( diagram_data, index ); if (( feature != NULL ) && ( data_feature_is_valid( feature ) )) { const data_id_t feat_id = data_feature_get_data_id( feature ); if ( data_id_equals( &focused_feature_id, &feat_id ) ) { const bool is_visible = data_rules_diagram_shows_feature ( &((*this_).filter_rules), diagram_data, data_feature_get_row_id( feature ) ); const bool is_lifeline =( DATA_FEATURE_TYPE_LIFELINE == data_feature_get_main_type( feature ) ); if ( is_visible && is_lifeline ) { /* add the lifeline to the duplicates list */ write_err |= universal_array_list_append( (*this_).written_id_set, &feat_id ); write_err |= io_element_writer_start_feature( (*this_).element_writer, DATA_CLASSIFIER_TYPE_INTERACTION, /* fake parent type */ feature ); write_err |= io_element_writer_assemble_feature( (*this_).element_writer, DATA_CLASSIFIER_TYPE_INTERACTION, /* fake parent type */ feature ); write_err |= io_element_writer_end_feature( (*this_).element_writer, DATA_CLASSIFIER_TYPE_INTERACTION, /* fake parent type */ feature ); } } } else { assert( false ); } } TRACE_END_ERR( write_err ); return write_err; } int io_export_interaction_traversal_private_iterate_feature_relationships( io_export_interaction_traversal_t *this_, const data_visible_set_t *diagram_data, data_id_t from_classifier_id, data_id_t focused_feature_id, const data_classifier_t *fake_interaction ) { TRACE_BEGIN(); assert( diagram_data != NULL ); assert( data_visible_set_is_valid( diagram_data ) ); assert( DATA_TABLE_CLASSIFIER == data_id_get_table( &from_classifier_id ) ); assert( DATA_ROW_ID_VOID != data_id_get_row_id( &from_classifier_id) ); int write_err = 0; /* iterate over all relationships */ uint32_t count; count = data_visible_set_get_relationship_count ( diagram_data ); for ( uint32_t index = 0; index < count; index ++ ) { /* get relationship */ const data_relationship_t *relation; relation = data_visible_set_get_relationship_const ( diagram_data, index ); if (( relation != NULL ) && ( data_relationship_is_valid( relation ) )) { /*const data_id_t r_from_classifier_id = data_relationship_get_from_classifier_data_id( relation );*/ const data_id_t rel_from_feature_id = data_relationship_get_from_feature_data_id( relation ); const data_id_t rel_to_feature_id = data_relationship_get_to_feature_data_id( relation ); /*if ( data_id_equals( &from_classifier_id, &r_from_classifier_id ) )*/ /* do not care if send or receive */ if (( data_id_equals( &focused_feature_id, &rel_from_feature_id ) ) ||( data_id_equals( &focused_feature_id, &rel_to_feature_id ) )) { const data_id_t relation_id = data_relationship_get_data_id( relation ); const bool is_visible = data_rules_diagram_shows_relationship ( &((*this_).filter_rules), diagram_data, data_id_get_row_id( &relation_id ) ); const bool is_relationship_compliant_here = io_element_writer_can_classifier_nest_relationship ( (*this_).element_writer, DATA_CLASSIFIER_TYPE_INTERACTION, /* fake parent type */ data_relationship_get_main_type( relation ) ); const bool duplicate_relationship = ( -1 != universal_array_list_get_index_of( (*this_).written_id_set, &relation_id ) ); /* is message */ const data_relationship_type_t relation_type = data_relationship_get_main_type( relation ); const xmi_element_info_t *relation_info; int map_err = xmi_element_info_map_get_relationship( &xmi_element_info_map_standard, false, /* interaction context, not state */ relation_type, &relation_info ); if ( map_err != 0 ) { TSLOG_WARNING_INT("xmi_element_info_map_get_relationship could not map type", relation_type ); } if ( is_visible && ( ! duplicate_relationship ) && is_relationship_compliant_here ) { /* add the relationship to the duplicates list */ write_err |= universal_array_list_append( (*this_).written_id_set, &relation_id ); /* destination classifier found, print the relation */ write_err |= io_element_writer_start_relationship( (*this_).element_writer, DATA_CLASSIFIER_TYPE_INTERACTION, /* fake parent type */ relation ); write_err |= io_element_writer_assemble_relationship( (*this_).element_writer, fake_interaction, relation, &((*this_).fake_interaction_classifier), /* fake from classifier type */ &((*this_).fake_lifeline_feature), /* guess from feature type */ &((*this_).fake_interaction_classifier), /* fake to classifier type */ &((*this_).fake_lifeline_feature) /* guess to feature type */ ); write_err |= io_element_writer_end_relationship( (*this_).element_writer, DATA_CLASSIFIER_TYPE_INTERACTION, /* fake parent type */ relation ); } } } else { assert( false ); } } TRACE_END_ERR( write_err ); return write_err; } int io_export_interaction_traversal_private_fake_interaction( io_export_interaction_traversal_t *this_, const data_diagram_t *interaction_diagram, data_classifier_t *out_fake_classifier ) { TRACE_BEGIN(); assert( out_fake_classifier != NULL ); assert( interaction_diagram != NULL ); assert( data_diagram_is_valid( interaction_diagram ) ); int write_err = 0; data_classifier_set_row_id( out_fake_classifier, 1000000 + data_diagram_get_row_id( interaction_diagram ) ); data_classifier_set_main_type( out_fake_classifier, DATA_CLASSIFIER_TYPE_INTERACTION ); write_err |= data_classifier_set_stereotype( out_fake_classifier, "" ); write_err |= data_classifier_set_name( out_fake_classifier, data_diagram_get_name_const( interaction_diagram ) ); write_err |= data_classifier_set_description( out_fake_classifier, data_diagram_get_description_const( interaction_diagram ) ); data_classifier_set_x_order( out_fake_classifier, data_diagram_get_list_order( interaction_diagram ) ); data_classifier_set_y_order( out_fake_classifier, data_diagram_get_list_order( interaction_diagram ) ); data_classifier_set_list_order( out_fake_classifier, data_diagram_get_list_order( interaction_diagram ) ); write_err |= data_classifier_set_uuid( out_fake_classifier, data_diagram_get_uuid_const( interaction_diagram ) ); TRACE_END_ERR( write_err ); return write_err; } /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/io_export_model_traversal.c000066400000000000000000001112631415120503000244550ustar00rootroot00000000000000/* File: io_export_model_traversal.c; Copyright and License: see below */ #include "io_export_model_traversal.h" #include "trace.h" #include "data_diagram.h" #include "data_classifier.h" #include #include #include void io_export_model_traversal_init( io_export_model_traversal_t *this_, data_database_reader_t *db_reader, data_visible_set_t *input_data, data_stat_t *io_export_stat, io_element_writer_t *out_element_writer ) { TRACE_BEGIN(); assert( NULL != db_reader ); assert( NULL != io_export_stat ); assert( NULL != out_element_writer ); (*this_).db_reader = db_reader; (*this_).export_stat = io_export_stat; (*this_).element_writer = out_element_writer; universal_array_list_init ( &((*this_).written_id_set), sizeof((*this_).written_id_set_buf)/sizeof(data_id_t), &((*this_).written_id_set_buf), sizeof(data_id_t), ((char*)(&((*this_).written_id_set_buf[1])))-((char*)(&((*this_).written_id_set_buf[0]))), (void (*)(void *, const void *)) &data_id_copy, (bool (*)(const void *, const void *)) &data_id_equals, (void (*)(void *)) &data_id_destroy ); io_export_interaction_traversal_init( &((*this_).interaction_helper), db_reader, input_data, &((*this_).written_id_set), io_export_stat, out_element_writer ); TRACE_END(); } void io_export_model_traversal_destroy( io_export_model_traversal_t *this_ ) { TRACE_BEGIN(); io_export_interaction_traversal_destroy ( &((*this_).interaction_helper) ); universal_array_list_destroy ( &((*this_).written_id_set) ); (*this_).db_reader = NULL; (*this_).export_stat = NULL; (*this_).element_writer = NULL; TRACE_END(); } int io_export_model_traversal_walk_model_nodes ( io_export_model_traversal_t *this_ ) { TRACE_BEGIN(); int write_err = 0; { data_error_t data_err; data_database_iterator_classifiers_t classifier_iterator; universal_array_list_clear( &((*this_).written_id_set) ); /* init the iterator */ data_database_iterator_classifiers_init_empty( &classifier_iterator ); data_err = data_database_reader_get_all_classifiers_iterator ( (*this_).db_reader, &classifier_iterator ); if ( data_err != DATA_ERROR_NONE ) { write_err = -1; } else { while( data_database_iterator_classifiers_has_next( &classifier_iterator ) && ( write_err==0 ) ) { data_err = data_database_iterator_classifiers_next( &classifier_iterator, &((*this_).temp_classifier) ); if ( data_err != DATA_ERROR_NONE ) { write_err = -1; } else { const data_id_t classifier_id = data_classifier_get_data_id( &((*this_).temp_classifier) ); data_classifier_destroy( &((*this_).temp_classifier) ); write_err |= io_export_model_traversal_private_walk_node ( this_, DATA_ID_VOID, DATA_ID_VOID, classifier_id, 0 /* initial recursion_depth */ ); } } } data_err = data_database_iterator_classifiers_destroy( &classifier_iterator ); if ( data_err != DATA_ERROR_NONE ) { write_err = -1; } } TRACE_END_ERR( write_err ); return write_err; } int io_export_model_traversal_private_walk_node ( io_export_model_traversal_t *this_, data_id_t host_id, data_id_t containment_relationship_id, data_id_t classifier_id, unsigned int recursion_depth ) { TRACE_BEGIN(); assert( recursion_depth <= IO_EXPORT_MODEL_TRAVERSAL_MAX_TREE_DEPTH ); assert( data_id_is_valid( &classifier_id ) ); int write_err = 0; /* initially define flags and attributes */ bool duplicate_classifier = ( -1 != universal_array_list_get_index_of( &((*this_).written_id_set), &classifier_id ) ); bool is_classifier_compliant_here = false; /* a default value */ const data_classifier_t *classifier = NULL; /* the id-sets needed on the stack during recursion */ data_small_set_t contained_classifiers; data_small_set_init (&contained_classifiers); data_small_set_t containment_relations; data_small_set_init (&containment_relations); /* tasks before recursion */ if ( ! duplicate_classifier ) { const data_error_t data_err_1 = ( ! data_id_is_valid( &host_id ) ) ? DATA_ERROR_NONE : data_database_reader_get_classifier_by_id( (*this_).db_reader, data_id_get_row_id(&host_id), &((*this_).temp_classifier) ); data_node_set_init( &((*this_).temp_node_data) ); const data_error_t data_err_2 = data_node_set_load( &((*this_).temp_node_data), data_id_get_row_id( &classifier_id ), (*this_).db_reader ); if (( data_err_1 != DATA_ERROR_NONE )||( data_err_2 != DATA_ERROR_NONE )) { write_err = -1; } else { /* update flags and attributes */ const data_classifier_type_t host_type = ( ! data_id_is_valid( &host_id ) ) ? DATA_CLASSIFIER_TYPE_PACKAGE /* a uml:Model is a uml:Package*/ : data_classifier_get_main_type( &((*this_).temp_classifier) ); classifier = data_node_set_get_classifier_const ( &((*this_).temp_node_data) ); const data_classifier_type_t classifier_type = data_classifier_get_main_type( classifier ); /* fake and export interactions in which the current node is participant first */ /* recursion trick: If classifier is nested, this block is evaluated * 1x for the nested classifier and 1x for same classifier at the toplevel model package */ { /* write the relationships that can be stated after the classifier or in the toplevel package */ write_err |= io_export_model_traversal_private_fake_interactions_of_node( this_, host_type, &((*this_).temp_node_data) ); /* check if the classifier is already written */ duplicate_classifier =( -1 != universal_array_list_get_index_of( &((*this_).written_id_set), &classifier_id ) ); } is_classifier_compliant_here = io_element_writer_can_classifier_nest_classifier( (*this_).element_writer, host_type, classifier_type ); if (( recursion_depth == 0 )&&( !is_classifier_compliant_here )) { /* fallback, there is no other place to put the classifier */ is_classifier_compliant_here = true; } if (( ! duplicate_classifier )&&( is_classifier_compliant_here )) { /* add this classifier to the already written elements */ write_err |= universal_array_list_append( &((*this_).written_id_set), &classifier_id ); /* if this classifier was found via a containment_relationship, */ /* add this containment_relationship to the already written elements */ if ( data_id_is_valid( &containment_relationship_id ) ) { write_err |= universal_array_list_append( &((*this_).written_id_set), &containment_relationship_id ); } /* walk node which is not a duplicate */ write_err |= io_export_model_traversal_private_begin_node( this_, host_type, &((*this_).temp_node_data) ); write_err |= io_export_model_traversal_private_iterate_node_features( this_, &((*this_).temp_node_data) ); write_err |= io_export_model_traversal_private_get_containments( this_, &((*this_).temp_node_data), &contained_classifiers, &containment_relations ); } } data_node_set_destroy( &((*this_).temp_node_data) ); } /* do recursion, all required data is stored on the stack now */ if (( ! duplicate_classifier )&&( is_classifier_compliant_here )) { write_err |= io_export_model_traversal_private_walk_containments( this_, classifier_id, &contained_classifiers, &containment_relations, recursion_depth ); } /* tasks after recursion */ { const data_error_t data_err_3 = ( ! data_id_is_valid( &host_id ) ) ? DATA_ERROR_NONE : data_database_reader_get_classifier_by_id( (*this_).db_reader, data_id_get_row_id(&host_id), &((*this_).temp_classifier) ); data_node_set_init( &((*this_).temp_node_data) ); const data_error_t data_err_4 = data_node_set_load( &((*this_).temp_node_data), data_id_get_row_id( &classifier_id ), (*this_).db_reader ); if (( data_err_3 != DATA_ERROR_NONE )||( data_err_4 != DATA_ERROR_NONE )) { write_err = -1; } else { const data_classifier_type_t host_type_2 = ( ! data_id_is_valid( &host_id ) ) ? DATA_CLASSIFIER_TYPE_PACKAGE /* a uml:Model is a uml:Package*/ : data_classifier_get_main_type( &((*this_).temp_classifier) ); const data_classifier_t *host_2 = ( ! data_id_is_valid( &host_id ) ) ? NULL : &((*this_).temp_classifier); if (( ! duplicate_classifier )&&( is_classifier_compliant_here )) { /* write the relationships that can be nested within the classifier */ write_err |= io_export_model_traversal_private_iterate_node_relationships( this_, false, classifier, &((*this_).temp_node_data) ); write_err |= io_export_model_traversal_private_end_node( this_, host_type_2, &((*this_).temp_node_data) ); } /* recursion trick: If from- and to- classifiers are nested, this block is evaluated * 1x for the nested from-/to- classifier and 1x for same classifier at the toplevel model package */ { /* write the relationships that can be stated after the classifier or in the toplevel package */ write_err |= io_export_model_traversal_private_iterate_node_relationships( this_, true, host_2, &((*this_).temp_node_data) ); } } data_node_set_destroy( &((*this_).temp_node_data) ); } data_small_set_destroy (&contained_classifiers); data_small_set_destroy (&containment_relations); TRACE_END_ERR( write_err ); return write_err; } int io_export_model_traversal_private_begin_node ( io_export_model_traversal_t *this_, data_classifier_type_t host_type, const data_node_set_t *node_data ) { TRACE_BEGIN(); assert( node_data != NULL ); int write_err = 0; /* get classifier */ const data_classifier_t *const classifier = data_node_set_get_classifier_const ( node_data ); write_err |= io_element_writer_start_classifier( (*this_).element_writer, host_type, classifier ); write_err |= io_element_writer_assemble_classifier( (*this_).element_writer, host_type, classifier ); TRACE_END_ERR( write_err ); return write_err; } int io_export_model_traversal_private_get_containments ( io_export_model_traversal_t *this_, const data_node_set_t *node_data, data_small_set_t *io_contained_classifiers, data_small_set_t *io_containment_relations ) { TRACE_BEGIN(); assert( node_data != NULL ); assert( io_contained_classifiers != NULL ); assert( io_containment_relations != NULL ); int write_err = 0; const data_classifier_t *const classifier = data_node_set_get_classifier_const ( node_data ); const data_id_t classifier_id = data_classifier_get_data_id( classifier ); /* search containments in relationships */ const uint32_t count = data_node_set_get_relationship_count ( node_data ); for ( uint32_t index = 0; index < count; index ++ ) { /* get relationship */ const data_relationship_t *const relation = data_node_set_get_relationship_const ( node_data, index ); if (( relation != NULL ) && ( data_relationship_is_valid( relation ) )) { if ( DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT == data_relationship_get_main_type( relation ) ) { const data_id_t relationship_id = data_relationship_get_data_id( relation ); const data_id_t from_feature_id = data_relationship_get_from_feature_data_id( relation ); const data_id_t to_feature_id = data_relationship_get_to_feature_data_id( relation ); const data_id_t to_classifier_id = data_relationship_get_to_classifier_data_id( relation ); if ( ( ! data_id_is_valid( &from_feature_id ) ) && ( ! data_id_is_valid( &to_feature_id ) ) && ( ! data_id_equals( &to_classifier_id, &classifier_id ) ) ) { data_small_set_add_obj ( io_contained_classifiers, to_classifier_id ); data_small_set_add_obj ( io_containment_relations, relationship_id ); } } } else { assert( false ); } } TRACE_END_ERR( write_err ); return write_err; } int io_export_model_traversal_private_walk_containments ( io_export_model_traversal_t *this_, data_id_t host_id, const data_small_set_t *contained_classifiers, const data_small_set_t *containment_relations, unsigned int recursion_depth ) { TRACE_BEGIN(); assert( contained_classifiers != NULL ); assert( containment_relations != NULL ); int write_err = 0; /* do recursion */ if ( recursion_depth < IO_EXPORT_MODEL_TRAVERSAL_MAX_TREE_DEPTH ) { const uint32_t children = data_small_set_get_count ( contained_classifiers ); assert( children == data_small_set_get_count ( containment_relations ) ); for ( uint32_t index = 0; index < children; index ++ ) { const data_id_t child = data_small_set_get_id ( contained_classifiers, index ); const data_id_t c_rel = data_small_set_get_id ( containment_relations, index ); write_err |= io_export_model_traversal_private_walk_node( this_, host_id, c_rel, child, recursion_depth+1 ); } } TRACE_END_ERR( write_err ); return write_err; } int io_export_model_traversal_private_end_node ( io_export_model_traversal_t *this_, data_classifier_type_t host_type, const data_node_set_t *node_data ) { TRACE_BEGIN(); assert( node_data != NULL ); int write_err = 0; /* get classifier again */ const data_classifier_t *const classifier = data_node_set_get_classifier_const ( node_data ); write_err |= io_element_writer_end_classifier( (*this_).element_writer, host_type, classifier ); TRACE_END_ERR( write_err ); return write_err; } int io_export_model_traversal_private_iterate_node_features ( io_export_model_traversal_t *this_, const data_node_set_t *node_data ) { TRACE_BEGIN(); assert( node_data != NULL ); assert( data_node_set_is_valid( node_data ) ); int write_err = 0; /* get parent classifier */ const data_classifier_t *const classifier = data_node_set_get_classifier_const ( node_data ); /* iterate over all features */ const uint32_t count = data_node_set_get_feature_count ( node_data ); for ( uint32_t index = 0; index < count; index ++ ) { /* get feature */ const data_feature_t *feature; feature = data_node_set_get_feature_const ( node_data, index ); if (( feature != NULL ) && ( data_feature_is_valid( feature ) )) { const bool is_lifeline =( DATA_FEATURE_TYPE_LIFELINE == data_feature_get_main_type( feature ) ); if ( ! is_lifeline ) { write_err |= io_element_writer_start_feature( (*this_).element_writer, data_classifier_get_main_type( classifier ), feature ); write_err |= io_element_writer_assemble_feature( (*this_).element_writer, data_classifier_get_main_type( classifier ), feature ); write_err |= io_element_writer_end_feature( (*this_).element_writer, data_classifier_get_main_type( classifier ), feature ); } } else { assert( false ); } } TRACE_END_ERR( write_err ); return write_err; } int io_export_model_traversal_private_iterate_node_relationships ( io_export_model_traversal_t *this_, bool nested_to_foreign_node, const data_classifier_t *host, const data_node_set_t *node_data ) { TRACE_BEGIN(); assert( node_data != NULL ); assert( data_node_set_is_valid( node_data ) ); int write_err = 0; const data_classifier_type_t host_type = (host==NULL) ? DATA_CLASSIFIER_TYPE_PACKAGE : data_classifier_get_main_type( host ); /* a uml:Model is a uml:Package*/ const data_classifier_t *const classifier = data_node_set_get_classifier_const ( node_data ); const data_id_t classifier_id = data_classifier_get_data_id( classifier ); /* iterate over all relationships */ const uint32_t count = data_node_set_get_relationship_count ( node_data ); for ( uint32_t index = 0; index < count; index ++ ) { /* get relationship */ const data_relationship_t *relation; relation = data_node_set_get_relationship_const ( node_data, index ); if (( relation != NULL ) && ( data_relationship_is_valid( relation ) )) { /* determine if the relationship is a duplicate */ const data_id_t relation_id = data_relationship_get_data_id( relation ); const bool duplicate_relationship = ( -1 != universal_array_list_get_index_of( &((*this_).written_id_set), &relation_id ) ); if ( ! duplicate_relationship ) { const data_id_t from_classifier_id = data_relationship_get_from_classifier_data_id( relation ); const bool source_already_written = ( -1 != universal_array_list_get_index_of( &((*this_).written_id_set), &from_classifier_id ) ); const data_id_t to_classifier_id = data_relationship_get_to_classifier_data_id( relation ); const bool destination_already_written = ( -1 != universal_array_list_get_index_of( &((*this_).written_id_set), &to_classifier_id ) ); const data_relationship_type_t r_type = data_relationship_get_main_type( relation ); const bool is_relationship_compliant_here = io_element_writer_can_classifier_nest_relationship( (*this_).element_writer, host_type, r_type ); const data_id_t from_feature_id = data_relationship_get_from_feature_data_id( relation ); const bool from_here = ( ( ! data_id_is_valid( &from_feature_id ) ) && ( data_id_equals( &from_classifier_id, &classifier_id ) ) ); /* nested_to_foreign_node is kind of yellow or even red emergency node: * source_already_written and possibly destination_already_written must have passed * to ensure that there is no other solution; * either (yellow) is_relationship_compliant_here * or (red) nesting to package shall be true. */ const bool foreign_yellow_ok = nested_to_foreign_node && source_already_written && is_relationship_compliant_here; const bool foreign_red_ok = nested_to_foreign_node && source_already_written && destination_already_written && ( host_type == DATA_CLASSIFIER_TYPE_PACKAGE ); /* in uml, the source is the dependant, the destination has no link to the source */ const bool local_ok = ( ! nested_to_foreign_node ) && is_relationship_compliant_here && from_here; if ( local_ok || foreign_yellow_ok || foreign_red_ok ) { /* add the relationship to the duplicates list */ write_err |= universal_array_list_append( &((*this_).written_id_set), &relation_id ); /* get the element types at both ends of the relationship */ data_classifier_init_empty( &((*this_).temp_from_classifier) ); data_feature_init_empty( &((*this_).temp_from_feature) ); data_classifier_init_empty( &((*this_).temp_to_classifier) ); data_feature_init_empty( &((*this_).temp_to_feature) ); const data_error_t d_err = io_export_model_traversal_private_get_relationship_ends( this_, relation, node_data, &((*this_).temp_from_classifier), &((*this_).temp_from_feature), &((*this_).temp_to_classifier), &((*this_).temp_to_feature) ); if ( d_err == DATA_ERROR_NONE ) { /* destination classifier found, print the relation */ write_err |= io_element_writer_start_relationship( (*this_).element_writer, host_type, relation ); write_err |= io_element_writer_assemble_relationship( (*this_).element_writer, host, relation, &((*this_).temp_from_classifier), &((*this_).temp_from_feature), &((*this_).temp_to_classifier), &((*this_).temp_to_feature) ); write_err |= io_element_writer_end_relationship( (*this_).element_writer, host_type, relation ); } else { write_err |= -1; } data_classifier_destroy( &((*this_).temp_from_classifier) ); data_feature_destroy( &((*this_).temp_from_feature) ); data_classifier_destroy( &((*this_).temp_to_classifier) ); data_feature_destroy( &((*this_).temp_to_feature) ); } } } else { assert( false ); } } TRACE_END_ERR( write_err ); return write_err; } data_error_t io_export_model_traversal_private_get_relationship_ends( io_export_model_traversal_t *this_, const data_relationship_t *relation, const data_node_set_t *node_data, data_classifier_t *out_from_c, data_feature_t *out_from_f, data_classifier_t *out_to_c, data_feature_t *out_to_f ) { TRACE_BEGIN(); assert( relation != NULL ); assert( out_from_c != NULL ); assert( out_from_f != NULL ); assert( out_to_c != NULL ); assert( out_to_f != NULL ); data_error_t data_err = DATA_ERROR_NONE; { /* get from classifier */ const data_row_id_t from_clcassifier_row_id = data_relationship_get_from_classifier_row_id ( relation ); bool from_classifier_found = false; if ( node_data != NULL ) { const data_classifier_t *node_classifier = data_node_set_get_classifier_const( node_data ); if (( node_classifier != NULL ) &&( from_clcassifier_row_id == data_classifier_get_row_id ( node_classifier ) )) { data_classifier_replace( out_from_c, node_classifier ); from_classifier_found = true; } } if ( ! from_classifier_found ) { data_err |= data_database_reader_get_classifier_by_id ( (*this_).db_reader, from_clcassifier_row_id, out_from_c ); } /* get from feature */ const data_row_id_t from_feature_row_id = data_relationship_get_from_feature_row_id ( relation ); bool from_feature_found = ( from_feature_row_id == DATA_ROW_ID_VOID ); if (( node_data != NULL )&&( ! from_feature_found )) { const data_feature_t *node_feature = data_node_set_get_feature_by_id_const ( node_data, from_feature_row_id ); if ( node_feature != NULL ) { data_feature_replace( out_from_f, node_feature ); from_feature_found = true; } } if ( ! from_feature_found ) { data_err |= data_database_reader_get_feature_by_id ( (*this_).db_reader, from_feature_row_id, out_from_f ); } /* get to classifier */ const data_row_id_t to_classifier_row_id = data_relationship_get_to_classifier_row_id ( relation ); bool to_classifier_found = false; if ( node_data != NULL ) { const data_classifier_t *node_classifier = data_node_set_get_classifier_const( node_data ); if (( node_classifier != NULL ) &&( to_classifier_row_id == data_classifier_get_row_id ( node_classifier ) )) { data_classifier_replace( out_to_c, node_classifier ); to_classifier_found = true; } } if ( ! to_classifier_found ) { data_err |= data_database_reader_get_classifier_by_id ( (*this_).db_reader, to_classifier_row_id, out_to_c ); } /* get to feature */ const data_row_id_t to_feature_row_id = data_relationship_get_to_feature_row_id ( relation ); bool to_feature_found = ( to_feature_row_id == DATA_ROW_ID_VOID ); if (( node_data != NULL )&&( ! to_feature_found )) { const data_feature_t *node_feature = data_node_set_get_feature_by_id_const ( node_data, to_feature_row_id ); if ( node_feature != NULL ) { data_feature_replace( out_to_f, node_feature ); to_feature_found = true; } } if ( ! to_feature_found ) { data_err |= data_database_reader_get_feature_by_id ( (*this_).db_reader, to_feature_row_id, out_to_f ); } } if ( data_err != DATA_ERROR_NONE ) { TSLOG_ERROR_INT( "A relationship references classifier(s) and/or feature(s) that do not exist:", data_relationship_get_row_id ( relation ) ); } TRACE_END_ERR( data_err ); return data_err; } int io_export_model_traversal_private_fake_interactions_of_node ( io_export_model_traversal_t *this_, data_classifier_type_t nesting_type, const data_node_set_t *node_data ) { TRACE_BEGIN(); assert( node_data != NULL ); assert( data_node_set_is_valid( node_data ) ); int write_err = 0; const data_classifier_t *const classifier = data_node_set_get_classifier_const ( node_data ); const data_id_t classifier_id = data_classifier_get_data_id( classifier ); /* iterate over all features, search for lifelines */ const uint32_t count = data_node_set_get_feature_count ( node_data ); for ( uint32_t index = 0; index < count; index ++ ) { /* get feature */ const data_feature_t *feature; feature = data_node_set_get_feature_const ( node_data, index ); if (( feature != NULL ) && ( data_feature_is_valid( feature ) )) { /* determine if the feature is a duplicate */ const data_id_t feature_id = data_feature_get_data_id( feature ); const bool duplicate_feature = ( -1 != universal_array_list_get_index_of( &((*this_).written_id_set), &feature_id ) ); /* determine if the feature is a lifeline */ const data_feature_type_t feat_type = data_feature_get_main_type( feature ); const bool is_lifeline = ( feat_type == DATA_FEATURE_TYPE_LIFELINE ); if (( ! duplicate_feature )&&( is_lifeline )) /* just an optimization, checked again by (*this_).interaction_helper */ { static const data_classifier_type_t FAKE_INTERACTION = DATA_CLASSIFIER_TYPE_CLASS; /* interaction is subclass of class */ const bool is_interaction_compliant_here = io_element_writer_can_classifier_nest_classifier( (*this_).element_writer, nesting_type, FAKE_INTERACTION ); if ( is_interaction_compliant_here ) { write_err |= io_export_interaction_traversal_iterate_classifier_occurrences( &((*this_).interaction_helper), nesting_type, classifier_id ); } } } else { assert( false ); } } TRACE_END_ERR( write_err ); return write_err; } /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/io_export_set_traversal.c000066400000000000000000000527171415120503000241600ustar00rootroot00000000000000/* File: io_export_set_traversal.c; Copyright and License: see below */ #include "io_export_set_traversal.h" #include "json/json_deserializer.h" #include "util/string/utf8string.h" #include "stream/universal_memory_output_stream.h" #include "trace.h" #include #include #include void io_export_set_traversal_init ( io_export_set_traversal_t *this_, data_database_reader_t *db_reader, data_stat_t *io_export_stat, io_element_writer_t *out_element_writer ) { TRACE_BEGIN(); assert( NULL != db_reader ); assert( NULL != io_export_stat ); assert( NULL != out_element_writer ); (*this_).db_reader = db_reader; (*this_).export_stat = io_export_stat; (*this_).element_writer = out_element_writer; TRACE_END(); } void io_export_set_traversal_destroy ( io_export_set_traversal_t *this_ ) { TRACE_BEGIN(); (*this_).db_reader = NULL; (*this_).export_stat = NULL; (*this_).element_writer = NULL; TRACE_END(); } int io_export_set_traversal_export_set( io_export_set_traversal_t *this_, const data_small_set_t *set_to_be_exported ) { TRACE_BEGIN(); assert( NULL != set_to_be_exported ); int serialize_error = 0; const char *const document_title = ""; serialize_error |= io_element_writer_start_main( (*this_).element_writer, document_title ); /* first pass: serialize the diagram(s) if there is one/some */ for ( int index = 0; index < data_small_set_get_count( set_to_be_exported ); index ++ ) { data_id_t current_id; current_id = data_small_set_get_id( set_to_be_exported, index ); switch ( data_id_get_table( ¤t_id ) ) { case DATA_TABLE_DIAGRAM: { serialize_error |= io_export_set_traversal_private_export_diagram( this_, current_id ); } break; case DATA_TABLE_DIAGRAMELEMENT: { serialize_error |= io_export_set_traversal_private_export_diagramelement( this_, current_id ); } break; case DATA_TABLE_CLASSIFIER: { serialize_error |= io_export_set_traversal_private_export_classifier( this_, current_id ); } break; case DATA_TABLE_FEATURE: { /* intentionally not supported */ TRACE_INFO( "io_export_set_traversal_export_set does not copy single features, only complete classifiers." ); data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_IGNORED ); } break; case DATA_TABLE_RELATIONSHIP: { serialize_error |= io_export_set_traversal_private_export_relationship( this_, current_id ); } break; default: break; } } serialize_error |= io_element_writer_end_main( (*this_).element_writer ); TRACE_END_ERR(serialize_error); return serialize_error; } int io_export_set_traversal_private_export_diagram( io_export_set_traversal_t *this_, data_id_t id ) { TRACE_BEGIN(); assert( data_id_is_valid( &id ) ); assert( DATA_TABLE_DIAGRAM == data_id_get_table( &id ) ); int serialize_error = 0; data_error_t read_error; data_diagram_t out_diagram; read_error = data_database_reader_get_diagram_by_id ( (*this_).db_reader, data_id_get_row_id( &id ), &out_diagram ); if ( read_error == DATA_ERROR_NONE ) { /* write diagram */ const char *const diagram_file_base_name = ""; serialize_error |= io_element_writer_start_diagram( (*this_).element_writer, &out_diagram ); serialize_error |= io_element_writer_assemble_diagram( (*this_).element_writer, NULL, /* parent, currently not needed here */ &out_diagram, diagram_file_base_name ); serialize_error |= io_element_writer_end_diagram( (*this_).element_writer, &out_diagram ); } else { /* program internal error */ TSLOG_ERROR( "io_export_set_traversal_export_set could not read all data of the set." ); data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_DIAGRAM, DATA_STAT_SERIES_ERROR ); } TRACE_END_ERR(serialize_error); return serialize_error; } int io_export_set_traversal_private_export_diagramelement( io_export_set_traversal_t *this_, data_id_t id ) { TRACE_BEGIN(); assert( data_id_is_valid( &id ) ); assert( DATA_TABLE_DIAGRAMELEMENT == data_id_get_table( &id ) ); int serialize_error = 0; data_error_t read_error; data_classifier_t out_classifier; data_diagramelement_t out_diagramelement; /* data_diagram_t out_diagram; */ read_error = data_database_reader_get_diagramelement_by_id( (*this_).db_reader, data_id_get_row_id( &id ), &out_diagramelement ); if ( read_error == DATA_ERROR_NONE ) { /* get classifier */ const data_row_id_t classifier_id = data_diagramelement_get_classifier_row_id( &out_diagramelement ); read_error = data_database_reader_get_classifier_by_id( (*this_).db_reader, classifier_id, &out_classifier ); /* get focused_feature */ /* assert ( IO_EXPORT_SET_TRAVERSAL_MAX_FEATURES >= 1 ); const data_row_id_t focused_feature_id = data_diagramelement_get_focused_feature_row_id( &out_diagramelement ); if ( DATA_ROW_ID_VOID == focused_feature_id ) { data_feature_init_empty( &((*this_).temp_features[0]) ); } else { read_error |= data_database_reader_get_feature_by_id ( (*this_).db_reader, focused_feature_id, &((*this_).temp_features[0]) ); } */ /* get diagram */ /* const data_row_id_t diag_id = data_diagramelement_get_diagram_row_id( &out_diagramelement ); read_error |= data_database_reader_get_diagram_by_id ( (*this_).db_reader, diag_id, &out_diagram ); */ if ( read_error == DATA_ERROR_NONE ) { /* intentionally not supported: diagramelements */ TRACE_INFO( "io_export_set_traversal_export_set does not copy single diagramelements, only referenced classifiers." ); /* serialize_error |= io_element_writer_start_diagramelement( (*this_).element_writer, &out_diagram, &out_diagramelement ); serialize_error |= io_element_writer_assemble_diagramelement( (*this_).element_writer, &out_diagram, &out_diagramelement, &out_classifier, &((*this_).temp_features[0] ); serialize_error |= io_element_writer_end_diagramelement( (*this_).element_writer, &out_diagram, &out_diagramelement ); */ } uint32_t feature_count; read_error = data_database_reader_get_features_by_classifier_id( (*this_).db_reader, classifier_id, IO_EXPORT_SET_TRAVERSAL_MAX_FEATURES, &((*this_).temp_features), &feature_count ); if ( read_error == DATA_ERROR_NONE ) { /* write classifier */ serialize_error |= io_element_writer_start_classifier( (*this_).element_writer, DATA_CLASSIFIER_TYPE_VOID, /* host_type */ &out_classifier ); serialize_error |= io_element_writer_assemble_classifier( (*this_).element_writer, DATA_CLASSIFIER_TYPE_VOID, /* host_type */ &out_classifier ); /* write classifier-features */ for ( uint32_t index = 0; index < feature_count; index ++ ) { const data_classifier_type_t parent_type = data_classifier_get_main_type( &out_classifier ); const data_feature_t *const feature_ptr = &(((*this_).temp_features)[index]); serialize_error |= io_element_writer_start_feature( (*this_).element_writer, parent_type, feature_ptr ); serialize_error |= io_element_writer_assemble_feature( (*this_).element_writer, parent_type, feature_ptr ); serialize_error |= io_element_writer_end_feature( (*this_).element_writer, parent_type, feature_ptr ); } serialize_error |= io_element_writer_end_classifier( (*this_).element_writer, DATA_CLASSIFIER_TYPE_VOID, /* host_type */ &out_classifier ); } else { /* program internal error */ TSLOG_ERROR( "io_export_set_traversal_export_set could not read referenced data of the set." ); data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_CLASSIFIER, DATA_STAT_SERIES_ERROR ); } } else { /* program internal error */ TSLOG_ERROR( "io_export_set_traversal_export_set could not read all data of the set." ); data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_CLASSIFIER, DATA_STAT_SERIES_ERROR ); } TRACE_END_ERR(serialize_error); return serialize_error; } int io_export_set_traversal_private_export_classifier( io_export_set_traversal_t *this_, data_id_t id ) { TRACE_BEGIN(); assert( data_id_is_valid( &id ) ); assert( DATA_TABLE_CLASSIFIER == data_id_get_table( &id ) ); int serialize_error = 0; data_error_t read_error; data_classifier_t out_classifier; read_error = data_database_reader_get_classifier_by_id( (*this_).db_reader, data_id_get_row_id( &id ), &out_classifier ); uint32_t feature_count; read_error = data_database_reader_get_features_by_classifier_id( (*this_).db_reader, data_id_get_row_id( &id ), IO_EXPORT_SET_TRAVERSAL_MAX_FEATURES, &((*this_).temp_features), &feature_count ); if ( read_error == DATA_ERROR_NONE ) { /* write classifier */ serialize_error |= io_element_writer_start_classifier( (*this_).element_writer, DATA_CLASSIFIER_TYPE_VOID, /* host_type */ &out_classifier ); serialize_error |= io_element_writer_assemble_classifier( (*this_).element_writer, DATA_CLASSIFIER_TYPE_VOID, /* host_type */ &out_classifier ); /* write classifier-features */ for ( uint32_t index = 0; index < feature_count; index ++ ) { const data_classifier_type_t parent_type = data_classifier_get_main_type( &out_classifier ); const data_feature_t *const feature_ptr = &(((*this_).temp_features)[index]); serialize_error |= io_element_writer_start_feature( (*this_).element_writer, parent_type, feature_ptr ); serialize_error |= io_element_writer_assemble_feature( (*this_).element_writer, parent_type, feature_ptr ); serialize_error |= io_element_writer_end_feature( (*this_).element_writer, parent_type, feature_ptr ); } serialize_error |= io_element_writer_end_classifier( (*this_).element_writer, DATA_CLASSIFIER_TYPE_VOID, /* host_type */ &out_classifier ); } else { /* program internal error */ TSLOG_ERROR( "io_export_set_traversal_export_set could not read all data of the set." ); data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_CLASSIFIER, DATA_STAT_SERIES_ERROR ); } TRACE_END_ERR(serialize_error); return serialize_error; } int io_export_set_traversal_private_export_relationship( io_export_set_traversal_t *this_, data_id_t id ) { TRACE_BEGIN(); assert( data_id_is_valid( &id ) ); assert( DATA_TABLE_RELATIONSHIP == data_id_get_table( &id ) ); int serialize_error = 0; data_error_t read_error; data_relationship_t out_relation; read_error = data_database_reader_get_relationship_by_id ( (*this_).db_reader, data_id_get_row_id( &id ), &out_relation ); if ( read_error == DATA_ERROR_NONE ) { data_classifier_t from_classifier; data_classifier_t to_classifier; assert ( IO_EXPORT_SET_TRAVERSAL_MAX_FEATURES >= 2 ); /* get source */ read_error |= data_database_reader_get_classifier_by_id ( (*this_).db_reader, data_relationship_get_from_classifier_row_id( &out_relation ), &from_classifier ); if ( DATA_ROW_ID_VOID == data_relationship_get_from_feature_row_id( &out_relation ) ) { data_feature_init_empty( &((*this_).temp_features[0]) ); } else { read_error |= data_database_reader_get_feature_by_id ( (*this_).db_reader, data_relationship_get_from_feature_row_id( &out_relation ), &((*this_).temp_features[0]) ); } /* get destination */ read_error |= data_database_reader_get_classifier_by_id ( (*this_).db_reader, data_relationship_get_to_classifier_row_id( &out_relation ), &to_classifier ); if ( DATA_ROW_ID_VOID == data_relationship_get_to_feature_row_id( &out_relation ) ) { data_feature_init_empty( &((*this_).temp_features[1]) ); } else { read_error |= data_database_reader_get_feature_by_id ( (*this_).db_reader, data_relationship_get_to_feature_row_id( &out_relation ), &((*this_).temp_features[1]) ); } /* serialize */ if ( read_error == DATA_ERROR_NONE ) { /* write relationship */ serialize_error |= io_element_writer_start_relationship( (*this_).element_writer, DATA_CLASSIFIER_TYPE_VOID, /* host_type */ &out_relation ); serialize_error |= io_element_writer_assemble_relationship( (*this_).element_writer, NULL, /* host */ &out_relation, &from_classifier, &((*this_).temp_features[0]), &to_classifier, &((*this_).temp_features[1]) ); serialize_error |= io_element_writer_end_relationship( (*this_).element_writer, DATA_CLASSIFIER_TYPE_VOID, /* host_type */ &out_relation ); } else { /* program internal error */ TSLOG_ERROR( "io_export_set_traversal_export_set could not read referenced data of the set." ); data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_ERROR ); } } else { /* program internal error */ TSLOG_ERROR( "io_export_set_traversal_export_set could not read all data of the set." ); data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_ERROR ); } TRACE_END_ERR(serialize_error); return serialize_error; } /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/io_exporter.c000066400000000000000000000714561415120503000215520ustar00rootroot00000000000000/* File: io_exporter.c; Copyright and License: see below */ #include "io_exporter.h" #include "xhtml/xhtml_stylesheet_writer.h" #include "stream/universal_file_output_stream.h" #include "stream/universal_output_stream.h" #include "xmi/xmi_writer_pass.h" #include "trace.h" #include "tslog.h" #include #include #include #include #include #include enum io_exporter_max_enum { IO_EXPORTER_MAX_DIAGRAM_TREE_DEPTH = 16, }; void io_exporter_init ( io_exporter_t *this_, data_database_reader_t *db_reader ) { TRACE_BEGIN(); assert( NULL != db_reader ); (*this_).db_reader = db_reader; (*this_).temp_filename = utf8stringbuf_init( sizeof((*this_).temp_filename_buf), (*this_).temp_filename_buf ); utf8stringbuf_clear( (*this_).temp_filename ); TRACE_END(); } void io_exporter_destroy( io_exporter_t *this_ ) { TRACE_BEGIN(); (*this_).db_reader = NULL; TRACE_END(); } int io_exporter_export_files( io_exporter_t *this_, io_file_format_t export_type, const char *target_folder, const char *document_file_path, data_stat_t *io_export_stat ) { TRACE_BEGIN(); assert ( NULL != target_folder ); assert ( NULL != document_file_path ); assert ( NULL != io_export_stat ); int export_err = 0; /* transform file path to name */ char temp_filename_buf[48]; utf8stringbuf_t temp_filename = UTF8STRINGBUF(temp_filename_buf); int err = io_exporter_private_get_filename( this_, document_file_path, temp_filename ); const char *const document_file_name = (err==0) ? utf8stringbuf_get_string(temp_filename) : "document"; if ( NULL != target_folder ) { if ( ( export_type & IO_FILE_FORMAT_SVG ) != 0 ) { export_err |= io_exporter_private_export_image_files( this_, DATA_ID_VOID, IO_EXPORTER_MAX_DIAGRAM_TREE_DEPTH, IO_FILE_FORMAT_SVG, target_folder, io_export_stat ); } if ( ( export_type & ( IO_FILE_FORMAT_PDF | IO_FILE_FORMAT_DOCBOOK ) ) != 0 ) { export_err |= io_exporter_private_export_image_files( this_, DATA_ID_VOID, IO_EXPORTER_MAX_DIAGRAM_TREE_DEPTH, IO_FILE_FORMAT_PDF, target_folder, io_export_stat ); } if ( ( export_type & IO_FILE_FORMAT_PS ) != 0 ) { export_err |= io_exporter_private_export_image_files( this_, DATA_ID_VOID, IO_EXPORTER_MAX_DIAGRAM_TREE_DEPTH, IO_FILE_FORMAT_PS, target_folder, io_export_stat ); } if ( ( export_type & ( IO_FILE_FORMAT_PNG | IO_FILE_FORMAT_DOCBOOK | IO_FILE_FORMAT_XHTML ) ) != 0 ) { export_err |= io_exporter_private_export_image_files( this_, DATA_ID_VOID, IO_EXPORTER_MAX_DIAGRAM_TREE_DEPTH, IO_FILE_FORMAT_PNG, target_folder, io_export_stat ); } if ( ( export_type & IO_FILE_FORMAT_TXT ) != 0 ) { export_err |= io_exporter_private_export_image_files( this_, DATA_ID_VOID, IO_EXPORTER_MAX_DIAGRAM_TREE_DEPTH, IO_FILE_FORMAT_TXT, target_folder, io_export_stat ); } if ( ( export_type & IO_FILE_FORMAT_DOCBOOK ) != 0 ) { export_err |= io_exporter_private_export_document_file( this_, IO_FILE_FORMAT_DOCBOOK, target_folder, document_file_name, io_export_stat ); } if ( ( export_type & IO_FILE_FORMAT_XHTML ) != 0 ) { export_err |= io_exporter_private_export_document_file( this_, IO_FILE_FORMAT_XHTML, target_folder, document_file_name, io_export_stat ); export_err |= io_exporter_private_export_document_file( this_, IO_FILE_FORMAT_CSS, target_folder, document_file_name, io_export_stat ); } if ( ( export_type & IO_FILE_FORMAT_JSON ) != 0 ) { export_err |= io_exporter_private_export_document_file( this_, IO_FILE_FORMAT_JSON, target_folder, document_file_name, io_export_stat ); } if ( ( export_type & IO_FILE_FORMAT_XMI2 ) != 0 ) { export_err |= io_exporter_private_export_document_file( this_, IO_FILE_FORMAT_XMI2, target_folder, document_file_name, io_export_stat ); } } else /* target_folder == NULL */ { TSLOG_WARNING("selected target folder was NULL."); export_err = -1; } TRACE_END_ERR(export_err); return export_err; } int io_exporter_private_get_filename( io_exporter_t *this_, const char* path, utf8stringbuf_t out_base_filename ) { TRACE_BEGIN(); assert ( NULL != path ); int err = 0; const unsigned int path_len = utf8string_get_length( path ); const int path_suffix = utf8string_find_last_str( path, "." ); const int path_start_filename_unix = utf8string_find_last_str( path, "/" ); const int path_start_filename_win = utf8string_find_last_str( path, "\\" ); const int path_start_filename = ( path_start_filename_unix < path_start_filename_win ) ? path_start_filename_win : path_start_filename_unix; const int start = (( path_start_filename == -1 ) ? 0 : (path_start_filename+1) ); const int length = (( path_suffix < start ) ? (path_len-start) : (path_suffix-start) ); utf8stringbuf_clear( out_base_filename ); utf8error_t u8err = utf8stringbuf_copy_region_from_str( out_base_filename, path, start, length ); err = (( u8err==UTF8ERROR_SUCCESS )&&(utf8stringbuf_get_length( out_base_filename )>0)) ? 0 : -1; TRACE_END_ERR(err); return err; } int io_exporter_private_export_image_files( io_exporter_t *this_, data_id_t diagram_id, uint32_t max_recursion, io_file_format_t export_type, const char *target_folder, data_stat_t *io_export_stat ) { TRACE_BEGIN(); assert ( NULL != target_folder ); assert ( NULL != io_export_stat ); TRACE_INFO_STR("target_folder:", target_folder ); const data_row_id_t diagram_row_id = data_id_get_row_id( &diagram_id ); int result = 0; /* draw current diagram */ if ( DATA_ROW_ID_VOID != diagram_row_id ) { assert( data_id_get_table( &diagram_id ) == DATA_TABLE_DIAGRAM ); /* determine filename */ utf8stringbuf_copy_str( (*this_).temp_filename, target_folder ); utf8stringbuf_append_str( (*this_).temp_filename, "/" ); result |= io_exporter_private_get_filename_for_diagram( this_, diagram_id, utf8stringbuf_get_end( (*this_).temp_filename ) ); if ( IO_FILE_FORMAT_SVG == export_type ) { utf8stringbuf_append_str( (*this_).temp_filename, ".svg" ); } else if ( IO_FILE_FORMAT_PNG == export_type ) { utf8stringbuf_append_str( (*this_).temp_filename, ".png" ); } else if ( IO_FILE_FORMAT_PDF == export_type ) { utf8stringbuf_append_str( (*this_).temp_filename, ".pdf" ); } else if ( IO_FILE_FORMAT_PS == export_type ) { utf8stringbuf_append_str( (*this_).temp_filename, ".ps" ); } else /* IO_FILE_FORMAT_TXT */ { utf8stringbuf_append_str( (*this_).temp_filename, ".txt" ); } TSLOG_EVENT_STR( "exporting diagram to file:", utf8stringbuf_get_string( (*this_).temp_filename ) ); /* create surface */ if (( IO_FILE_FORMAT_SVG == export_type ) || ( IO_FILE_FORMAT_PDF == export_type ) || ( IO_FILE_FORMAT_PS == export_type ) || ( IO_FILE_FORMAT_PNG == export_type ) ) { image_format_writer_init( &((*this_).temp_image_format_exporter ), (*this_).db_reader, &((*this_).temp_input_data) ); result = image_format_writer_render_diagram_to_file( &((*this_).temp_image_format_exporter ), diagram_id, export_type, utf8stringbuf_get_string( (*this_).temp_filename ), io_export_stat ); image_format_writer_destroy( &((*this_).temp_image_format_exporter ) ); } else /* IO_FILE_FORMAT_TXT */ { universal_file_output_stream_t text_output; universal_file_output_stream_init( &text_output ); universal_output_stream_t *output = universal_file_output_stream_get_output_stream( &text_output ); /* open file */ result |= universal_file_output_stream_open( &text_output, utf8stringbuf_get_string( (*this_).temp_filename ) ); if ( result == 0 ) { int write_err = 0; /* temporarily use the temp_model_traversal */ /* write file */ xhtml_element_writer_init( &((*this_).temp_format_writer ), (*this_).db_reader, IO_FILE_FORMAT_TXT, io_export_stat, output ); io_export_diagram_traversal_init( &((*this_).temp_diagram_traversal), (*this_).db_reader, &((*this_).temp_input_data), io_export_stat, xhtml_element_writer_get_element_writer( &((*this_).temp_format_writer) ) ); write_err |= xhtml_element_writer_write_header( &((*this_).temp_format_writer), "DUMMY_TITLE" ); write_err |= io_export_diagram_traversal_begin_and_walk_diagram ( &((*this_).temp_diagram_traversal), diagram_id, "NO_IMAGE_FILE" ); write_err |= io_export_diagram_traversal_end_diagram ( &((*this_).temp_diagram_traversal), diagram_id ); write_err |= xhtml_element_writer_write_footer( &((*this_).temp_format_writer) ); io_export_diagram_traversal_destroy( &((*this_).temp_diagram_traversal) ); xhtml_element_writer_destroy( &((*this_).temp_format_writer ) ); if ( 0 != write_err ) { TSLOG_ERROR("error writing txt."); result = -1; } /* close file */ result |= universal_file_output_stream_close( &text_output ); } result |= universal_file_output_stream_destroy( &text_output ); data_stat_inc_count ( io_export_stat, DATA_TABLE_DIAGRAM, DATA_STAT_SERIES_EXPORTED ); } } /* recursion to children */ if (( result == 0 )&&( max_recursion > 0 )) { data_error_t db_err; data_small_set_t the_set; data_small_set_init( &the_set ); db_err = data_database_reader_get_diagram_ids_by_parent_id ( (*this_).db_reader, diagram_row_id, &the_set ); if ( db_err != DATA_ERROR_NONE ) { TSLOG_ERROR("error reading database."); result = -1; } else { for ( uint32_t pos = 0; pos < data_small_set_get_count( &the_set ); pos ++ ) { data_id_t probe_id; probe_id = data_small_set_get_id( &the_set, pos ); result |= io_exporter_private_export_image_files( this_, probe_id, max_recursion-1, export_type, target_folder, io_export_stat ); data_id_destroy( &probe_id ); } } data_small_set_destroy( &the_set ); } TRACE_END_ERR( result ); return result; } int io_exporter_private_export_document_file( io_exporter_t *this_, io_file_format_t export_type, const char *target_folder, const char *document_file_name, data_stat_t *io_export_stat ) { TRACE_BEGIN(); assert ( NULL != target_folder ); assert ( NULL != document_file_name ); assert ( NULL != io_export_stat ); TRACE_INFO_STR("target_folder:", target_folder ); TRACE_INFO_STR("document_file_name:", document_file_name ); int export_err = 0; universal_file_output_stream_t file_output; universal_file_output_stream_init( &file_output ); universal_output_stream_t *output = universal_file_output_stream_get_output_stream( &file_output ); /* open file */ utf8stringbuf_copy_str( (*this_).temp_filename, target_folder ); utf8stringbuf_append_str( (*this_).temp_filename, "/" ); utf8stringbuf_append_str( (*this_).temp_filename, document_file_name ); switch ( export_type ) { case IO_FILE_FORMAT_DOCBOOK: { utf8stringbuf_append_str( (*this_).temp_filename, ".xml" ); } break; case IO_FILE_FORMAT_XHTML: { utf8stringbuf_append_str( (*this_).temp_filename, ".xhtml" ); } break; case IO_FILE_FORMAT_CSS: { utf8stringbuf_append_str( (*this_).temp_filename, ".css" ); } break; case IO_FILE_FORMAT_JSON: { utf8stringbuf_append_str( (*this_).temp_filename, ".json" ); } break; case IO_FILE_FORMAT_XMI2: { utf8stringbuf_append_str( (*this_).temp_filename, ".xmi" ); } break; default: { utf8stringbuf_append_str( (*this_).temp_filename, ".unknown_format" ); TSLOG_ERROR("error: unknown_format."); } break; } TSLOG_EVENT_STR( "exporting diagrams to document file:", utf8stringbuf_get_string( (*this_).temp_filename ) ); export_err |= universal_file_output_stream_open( &file_output, utf8stringbuf_get_string( (*this_).temp_filename ) ); if ( export_err == 0 ) { /* write file */ if ( IO_FILE_FORMAT_CSS == export_type ) { xhtml_stylesheet_writer_t css_writer; xhtml_stylesheet_writer_init( &css_writer, output ); export_err |= xhtml_stylesheet_writer_write_stylesheet( &css_writer ); xhtml_stylesheet_writer_destroy( &css_writer ); } else if ( IO_FILE_FORMAT_XMI2 == export_type ) { xmi_element_writer_init( &((*this_).temp_xmi_writer ), io_export_stat, output ); /* init the model_traversal */ io_export_model_traversal_init( &((*this_).temp_model_traversal), (*this_).db_reader, &((*this_).temp_input_data), io_export_stat, xmi_element_writer_get_element_writer( &((*this_).temp_xmi_writer) ) ); /* write the document */ export_err |= xmi_element_writer_write_header( &((*this_).temp_xmi_writer), document_file_name ); export_err |= xmi_element_writer_start_main( &((*this_).temp_xmi_writer), document_file_name ); xmi_element_writer_set_mode( &((*this_).temp_xmi_writer ), XMI_WRITER_PASS_BASE ); export_err |= io_export_model_traversal_walk_model_nodes( &((*this_).temp_model_traversal) ); export_err |= xmi_element_writer_end_main( &((*this_).temp_xmi_writer) ); xmi_element_writer_set_mode( &((*this_).temp_xmi_writer ), XMI_WRITER_PASS_PROFILE ); export_err |= io_export_model_traversal_walk_model_nodes( &((*this_).temp_model_traversal) ); export_err |= xmi_element_writer_write_footer( &((*this_).temp_xmi_writer) ); io_export_model_traversal_destroy( &((*this_).temp_model_traversal) ); xmi_element_writer_destroy( &((*this_).temp_xmi_writer ) ); } else if ( IO_FILE_FORMAT_JSON == export_type ) { json_element_writer_init( &((*this_).temp_json_writer ), io_export_stat, output ); export_err |= json_element_writer_write_header( &((*this_).temp_json_writer), document_file_name ); /* init the diagram_traversal */ { io_export_diagram_traversal_init( &((*this_).temp_diagram_traversal), (*this_).db_reader, &((*this_).temp_input_data), io_export_stat, json_element_writer_get_element_writer( &((*this_).temp_json_writer) ) ); /* write the document */ json_element_writer_set_mode( &((*this_).temp_json_writer ), JSON_WRITER_PASS_VIEWS ); export_err |= json_element_writer_start_main( &((*this_).temp_json_writer), document_file_name ); export_err |= io_exporter_private_export_document_part( this_, DATA_ID_VOID, IO_EXPORTER_MAX_DIAGRAM_TREE_DEPTH, io_export_stat ); export_err |= json_element_writer_end_main( &((*this_).temp_json_writer) ); io_export_diagram_traversal_destroy( &((*this_).temp_diagram_traversal) ); } /* init the model_traversal */ { io_export_flat_traversal_init( &((*this_).temp_flat_traversal), (*this_).db_reader, io_export_stat, json_element_writer_get_element_writer( &((*this_).temp_json_writer) ) ); /* write the document */ json_element_writer_set_mode( &((*this_).temp_json_writer ), JSON_WRITER_PASS_NODES ); export_err |= json_element_writer_start_main( &((*this_).temp_json_writer), document_file_name ); export_err |= io_export_flat_traversal_iterate_classifiers( &((*this_).temp_flat_traversal) ); export_err |= json_element_writer_end_main( &((*this_).temp_json_writer) ); json_element_writer_set_mode( &((*this_).temp_json_writer ), JSON_WRITER_PASS_EDGES ); export_err |= json_element_writer_start_main( &((*this_).temp_json_writer), document_file_name ); export_err |= io_export_flat_traversal_iterate_classifiers( &((*this_).temp_flat_traversal) ); export_err |= json_element_writer_end_main( &((*this_).temp_json_writer) ); io_export_flat_traversal_destroy( &((*this_).temp_flat_traversal) ); } export_err |= json_element_writer_write_footer( &((*this_).temp_json_writer) ); json_element_writer_destroy( &((*this_).temp_json_writer ) ); } else { xhtml_element_writer_init( &((*this_).temp_format_writer ), (*this_).db_reader, export_type, io_export_stat, output ); /* init the diagram_traversal */ io_export_diagram_traversal_init( &((*this_).temp_diagram_traversal), (*this_).db_reader, &((*this_).temp_input_data), io_export_stat, xhtml_element_writer_get_element_writer( &((*this_).temp_format_writer) ) ); /* write the document */ export_err |= xhtml_element_writer_write_header( &((*this_).temp_format_writer), document_file_name ); export_err |= io_exporter_private_export_table_of_contents( this_, DATA_ID_VOID, IO_EXPORTER_MAX_DIAGRAM_TREE_DEPTH, &((*this_).temp_format_writer) ); export_err |= io_exporter_private_export_document_part( this_, DATA_ID_VOID, IO_EXPORTER_MAX_DIAGRAM_TREE_DEPTH, io_export_stat ); export_err |= xhtml_element_writer_write_footer( &((*this_).temp_format_writer) ); io_export_diagram_traversal_destroy( &((*this_).temp_diagram_traversal) ); xhtml_element_writer_destroy( &((*this_).temp_format_writer ) ); } /* close file */ export_err |= universal_file_output_stream_close( &file_output ); } export_err |= universal_file_output_stream_destroy( &file_output ); TRACE_END_ERR( export_err ); return export_err; } int io_exporter_private_export_document_part( io_exporter_t *this_, data_id_t diagram_id, uint32_t max_recursion, data_stat_t *io_export_stat ) { TRACE_BEGIN(); assert ( NULL != io_export_stat ); const data_row_id_t diagram_row_id = data_id_get_row_id( &diagram_id ); int export_err = 0; /* write part for current diagram */ if ( DATA_ROW_ID_VOID != diagram_row_id ) { assert( data_id_get_table( &diagram_id ) == DATA_TABLE_DIAGRAM ); /* determine filename */ export_err |= io_exporter_private_get_filename_for_diagram( this_, diagram_id, (*this_).temp_filename ); /* write doc part */ export_err |= io_export_diagram_traversal_begin_and_walk_diagram( &((*this_).temp_diagram_traversal), diagram_id, utf8stringbuf_get_string( (*this_).temp_filename ) ); } /* recursion to children */ if (( export_err == 0 )&&( max_recursion > 0 )) { data_error_t db_err; data_small_set_t the_set; data_small_set_init( &the_set ); db_err = data_database_reader_get_diagram_ids_by_parent_id ( (*this_).db_reader, diagram_row_id, &the_set ); if ( db_err != DATA_ERROR_NONE ) { TSLOG_ERROR("error reading database."); export_err |= -1; } else { const uint32_t child_count = data_small_set_get_count( &the_set ); for ( uint32_t pos = 0; pos < child_count; pos ++ ) { data_id_t probe_id = data_small_set_get_id( &the_set, pos ); export_err |= io_exporter_private_export_document_part( this_, probe_id, max_recursion-1, io_export_stat ); data_id_destroy( &probe_id ); } } data_small_set_destroy( &the_set ); } /* end diagram section */ if ( DATA_ROW_ID_VOID != diagram_row_id ) { /* write doc part */ export_err |= io_export_diagram_traversal_end_diagram( &((*this_).temp_diagram_traversal), diagram_id ); } TRACE_END_ERR( export_err ); return export_err; } int io_exporter_private_export_table_of_contents( io_exporter_t *this_, data_id_t diagram_id, uint32_t max_recursion, xhtml_element_writer_t *format_writer ) { TRACE_BEGIN(); assert ( NULL != format_writer ); const data_row_id_t diagram_row_id = data_id_get_row_id( &diagram_id ); int export_err = 0; /* write entry for current diagram */ if ( DATA_ROW_ID_VOID != diagram_row_id ) { assert( data_id_get_table( &diagram_id ) == DATA_TABLE_DIAGRAM ); export_err |= xhtml_element_writer_start_toc_entry( format_writer ); /* load data to be drawn */ data_error_t db_err; db_err = data_database_reader_get_diagram_by_id ( (*this_).db_reader, diagram_row_id, &((*this_).temp_diagram) ); if ( db_err != DATA_ERROR_NONE ) { TSLOG_ERROR("error reading database."); export_err |= -1; } else { export_err |= xhtml_element_writer_write_toc_entry ( format_writer, &((*this_).temp_diagram) ); data_diagram_destroy( &((*this_).temp_diagram) ); } } /* recursion to children */ if (( export_err == 0 )&&( max_recursion > 0 )) { data_error_t db_err; data_small_set_t the_set; data_small_set_init( &the_set ); db_err = data_database_reader_get_diagram_ids_by_parent_id ( (*this_).db_reader, diagram_row_id, &the_set ); if ( db_err != DATA_ERROR_NONE ) { TSLOG_ERROR("error reading database."); export_err |= -1; } else { const uint32_t child_count = data_small_set_get_count( &the_set ); if ( child_count != 0 ) { export_err |= xhtml_element_writer_start_toc_sublist( format_writer ); for ( uint32_t pos = 0; pos < child_count; pos ++ ) { data_id_t probe_id = data_small_set_get_id( &the_set, pos ); export_err |= io_exporter_private_export_table_of_contents( this_, probe_id, max_recursion-1, format_writer ); data_id_destroy( &probe_id ); } export_err |= xhtml_element_writer_end_toc_sublist ( format_writer ); } } data_small_set_destroy( &the_set ); } /* end toc entry */ if ( DATA_ROW_ID_VOID != diagram_row_id ) { export_err |= xhtml_element_writer_end_toc_entry( format_writer ); } TRACE_END_ERR( export_err ); return export_err; } int io_exporter_private_get_filename_for_diagram( io_exporter_t *this_, data_id_t diagram_id, utf8stringbuf_t filename ) { TRACE_BEGIN(); assert( data_id_get_table( &diagram_id ) == DATA_TABLE_DIAGRAM ); int result = 0; utf8stringbuf_clear( filename ); data_error_t db_err; db_err = data_database_reader_get_diagram_by_id ( (*this_).db_reader, data_id_get_row_id( &diagram_id ), &((*this_).temp_diagram) ); if ( db_err != DATA_ERROR_NONE ) { TSLOG_ERROR("error reading database."); result |= -1; } else { const char *diag_name; diag_name = data_diagram_get_name_const( &((*this_).temp_diagram) ); /* determine filename */ data_id_to_utf8stringbuf( &diagram_id, filename ); utf8stringbuf_append_str( filename, "_" ); io_exporter_private_append_valid_chars_to_filename( this_, diag_name, filename ); data_diagram_destroy( &((*this_).temp_diagram) ); } TRACE_END_ERR( result ); return result; } void io_exporter_private_append_valid_chars_to_filename( io_exporter_t *this_, const char* name, utf8stringbuf_t filename ) { TRACE_BEGIN(); assert( NULL != name ); TRACE_INFO_STR( "name:", name ); bool finished = false; static const int MAX_APPEND_CHARS = 64; for ( int pos = 0; ( pos < MAX_APPEND_CHARS ) && ( ! finished ); pos ++ ) { char probe = name[pos]; if ( probe == '\0' ) { finished = true; } else if (( 'A' <= probe ) && ( probe <= 'Z' )) { utf8stringbuf_append_char( filename, probe ); } else if (( 'a' <= probe ) && ( probe <= 'z' )) { utf8stringbuf_append_char( filename, probe ); } else if (( '0' <= probe ) && ( probe <= '9' )) { utf8stringbuf_append_char( filename, probe ); } else if ( '-' == probe ) { utf8stringbuf_append_char( filename, probe ); } else if ( '_' == probe ) { utf8stringbuf_append_char( filename, probe ); } else if ( ' ' == probe ) { utf8stringbuf_append_char( filename, '_' ); } } TRACE_END(); } /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/io_file_format.c000066400000000000000000000053111415120503000221540ustar00rootroot00000000000000/* File: io_file_format.c; Copyright and License: see below */ #include "io_file_format.h" #include "trace.h" #include "util/string/utf8stringbuf.h" #include void io_file_format_to_string( io_file_format_t format_set, utf8stringbuf_t out_fileformat ) { TRACE_BEGIN(); int count = 0; utf8stringbuf_clear( out_fileformat ); if ( ( format_set & IO_FILE_FORMAT_PDF ) != 0 ) { /*utf8stringbuf_append_str( out_fileformat, (count==0)?("pdf"):(", pdf") );*/ utf8stringbuf_append_str( out_fileformat, "pdf" ); count ++; } if ( ( format_set & IO_FILE_FORMAT_PNG ) != 0 ) { utf8stringbuf_append_str( out_fileformat, (count==0)?("png"):(", png") ); count ++; } if ( ( format_set & IO_FILE_FORMAT_PS ) != 0 ) { utf8stringbuf_append_str( out_fileformat, (count==0)?("ps"):(", ps") ); count ++; } if ( ( format_set & IO_FILE_FORMAT_SVG ) != 0 ) { utf8stringbuf_append_str( out_fileformat, (count==0)?("svg"):(", svg") ); count ++; } if ( ( format_set & IO_FILE_FORMAT_TXT ) != 0 ) { utf8stringbuf_append_str( out_fileformat, (count==0)?("txt"):(", txt") ); count ++; } if ( ( format_set & IO_FILE_FORMAT_DOCBOOK ) != 0 ) { utf8stringbuf_append_str( out_fileformat, (count==0)?("docbook"):(", docbook") ); count ++; } if ( ( format_set & IO_FILE_FORMAT_XHTML ) != 0 ) { utf8stringbuf_append_str( out_fileformat, (count==0)?("xhtml"):(", xhtml") ); count ++; } if ( ( format_set & IO_FILE_FORMAT_CSS ) != 0 ) { utf8stringbuf_append_str( out_fileformat, (count==0)?("css"):(", css") ); count ++; } if ( ( format_set & IO_FILE_FORMAT_JSON ) != 0 ) { utf8stringbuf_append_str( out_fileformat, (count==0)?("json"):(", json") ); count ++; } if ( ( format_set & IO_FILE_FORMAT_XMI2 ) != 0 ) { utf8stringbuf_append_str( out_fileformat, (count==0)?("xmi"):(", xmi") ); count ++; } if ( count == 0 ) { utf8stringbuf_copy_str( out_fileformat, "none" ); } TRACE_END(); } /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/io_importer.c000066400000000000000000000100441415120503000215250ustar00rootroot00000000000000/* File: io_importer.c; Copyright and License: see below */ #include "io_importer.h" #include "json/json_deserializer.h" #include "stream/universal_file_input_stream.h" #include "ctrl_error.h" #include "util/string/utf8string.h" #include "trace.h" #include #include #include void io_importer_init ( io_importer_t *this_, data_database_reader_t *db_reader, ctrl_controller_t *controller ) { TRACE_BEGIN(); assert( NULL != db_reader ); assert( NULL != controller ); json_import_to_database_init( &((*this_).json_importer), db_reader, controller ); TRACE_END(); } void io_importer_destroy ( io_importer_t *this_ ) { TRACE_BEGIN(); json_import_to_database_destroy( &((*this_).json_importer) ); TRACE_END(); } data_error_t io_importer_import_file( io_importer_t *this_, io_file_format_t import_format, const char *import_file_path, data_stat_t *io_stat, universal_utf8_writer_t *out_english_report ) { TRACE_BEGIN(); assert( import_file_path != NULL ); assert( io_stat != NULL ); assert( out_english_report != NULL ); data_error_t parse_error = DATA_ERROR_NONE; universal_utf8_writer_write_str( out_english_report, "importing not yet implemented.\n" ); /*int id_mapper;*/ /* open file */ universal_file_input_stream_t in_file; universal_file_input_stream_init( &in_file ); const int err1 = universal_file_input_stream_open( &in_file, import_file_path ); if ( err1 != 0 ) { parse_error = DATA_ERROR_INVALID_REQUEST; } else { /* id scan */ TRACE_INFO("scanning file..."); /* create a list of diagram elements, check if the referenced diagrams and classifiers really exist */ const data_error_t err3 = json_import_to_database_prescan( &((*this_).json_importer), universal_file_input_stream_get_input_stream( &in_file ), io_stat, out_english_report ); if ( err3 != 0 ) { parse_error = DATA_ERROR_AT_FILE_READ; } /* import */ TRACE_INFO("importing file..."); const int err5 = universal_file_input_stream_reset( &in_file ); if ( err5 != 0 ) { parse_error = DATA_ERROR_AT_FILE_READ; } else { /* intelligent loop */ /* import lightweight diagram without description */ /* create fake diagrams for orphaned classifiers */ /* loop */ /* update diagram descriptions */ /* import classifier and diagramelements */ /* import features */ /* loop */ /* import relationship */ } /* close */ const int err7 = universal_file_input_stream_close( &in_file ); if ( err7 != 0 ) { parse_error = DATA_ERROR_AT_FILE_READ; } } const int err8 = universal_file_input_stream_destroy( &in_file ); if ( err8 != 0 ) { parse_error = DATA_ERROR_AT_FILE_READ; } TRACE_END_ERR( parse_error ); return parse_error; } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/json/000077500000000000000000000000001415120503000200035ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/source/json/json_deserializer.c000066400000000000000000001377401415120503000236760ustar00rootroot00000000000000/* File: json_deserializer.c; Copyright and License: see below */ #include "json/json_deserializer.h" #include "trace.h" #include "tslog.h" #include void json_deserializer_init ( json_deserializer_t *this_, universal_input_stream_t *in_data ) { TRACE_BEGIN(); (*this_).temp_string = utf8stringbuf_init( sizeof((*this_).temp_string_buffer), (*this_).temp_string_buffer ); json_token_reader_init( &((*this_).tokenizer), in_data ); (*this_).after_first_array_entry = false; TRACE_END(); } void json_deserializer_reinit ( json_deserializer_t *this_, universal_input_stream_t *in_data ) { TRACE_BEGIN(); json_deserializer_destroy( this_ ); json_deserializer_init( this_, in_data ); TRACE_END(); } void json_deserializer_destroy ( json_deserializer_t *this_ ) { TRACE_BEGIN(); json_token_reader_destroy( &((*this_).tokenizer) ); TRACE_END(); } data_error_t json_deserializer_expect_header ( json_deserializer_t *this_ ) { TRACE_BEGIN(); data_error_t result = DATA_ERROR_NONE; char member_name_buf[24] = ""; utf8stringbuf_t member_name = UTF8STRINGBUF( member_name_buf ); result = json_token_reader_expect_begin_object ( &((*this_).tokenizer) ); if ( DATA_ERROR_NONE == result ) { result = json_token_reader_read_member_name ( &((*this_).tokenizer), member_name ); if ( ! utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_HEAD ) ) { TSLOG_ERROR_INT( "unexpected object contents at line", json_token_reader_get_input_line( &((*this_).tokenizer) ) ); result |= DATA_ERROR_PARSER_STRUCTURE; } } if ( DATA_ERROR_NONE == result ) { result = json_token_reader_expect_name_separator( &((*this_).tokenizer) ); } if ( DATA_ERROR_NONE == result ) { result = json_deserializer_skip_next_object( this_ ); } TRACE_END_ERR( result ); return result; } data_error_t json_deserializer_expect_begin_data ( json_deserializer_t *this_ ) { TRACE_BEGIN(); data_error_t result = DATA_ERROR_NONE; char member_name_buf[24] = ""; utf8stringbuf_t member_name = UTF8STRINGBUF( member_name_buf ); result = json_token_reader_expect_value_separator ( &((*this_).tokenizer) ); if ( DATA_ERROR_NONE == result ) { result = json_token_reader_read_member_name ( &((*this_).tokenizer), member_name ); if (( ! utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_VIEWS ) ) && ( ! utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_NODES ) ) && ( ! utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_EDGES ) )) { TSLOG_ERROR_INT( "unexpected object contents at line", json_token_reader_get_input_line( &((*this_).tokenizer) ) ); result |= DATA_ERROR_PARSER_STRUCTURE; } } if ( DATA_ERROR_NONE == result ) { result = json_token_reader_expect_name_separator( &((*this_).tokenizer) ); } if ( DATA_ERROR_NONE == result ) { result = json_token_reader_expect_begin_array( &((*this_).tokenizer) ); } TRACE_END_ERR( result ); return result; } data_error_t json_deserializer_expect_footer ( json_deserializer_t *this_ ) { TRACE_BEGIN(); data_error_t result = DATA_ERROR_NONE; bool end_ok; result = json_token_reader_check_end_object ( &((*this_).tokenizer), &end_ok ); if ( ! end_ok ) { TSLOG_ERROR_INT( "unexpected object contents at line", json_token_reader_get_input_line( &((*this_).tokenizer) ) ); result |= DATA_ERROR_PARSER_STRUCTURE; } if ( DATA_ERROR_NONE == result ) { result = json_token_reader_expect_eof ( &((*this_).tokenizer) ); } TRACE_END_ERR( result ); return result; } data_error_t json_deserializer_check_end_data ( json_deserializer_t *this_, bool* out_end ) { TRACE_BEGIN(); assert( NULL != out_end ); data_error_t result = DATA_ERROR_NONE; result = json_token_reader_check_end_array ( &((*this_).tokenizer), out_end ); if (( DATA_ERROR_NONE == result ) && ( *out_end )) { (*this_).after_first_array_entry = false; } TRACE_END_ERR( result ); return result; } data_error_t json_deserializer_expect_begin_type_of_element ( json_deserializer_t *this_, data_table_t *out_type ) { TRACE_BEGIN(); assert ( NULL != out_type ); data_error_t result = DATA_ERROR_NONE; bool array_end; char member_name_buf[24]; utf8stringbuf_t member_name = UTF8STRINGBUF( member_name_buf ); result = json_token_reader_check_end_array ( &((*this_).tokenizer), &array_end ); if ( DATA_ERROR_NONE == result ) { if ( array_end ) { (*out_type) = DATA_TABLE_VOID; } else { if ( (*this_).after_first_array_entry ) { result = json_token_reader_expect_value_separator ( &((*this_).tokenizer) ); } else { (*this_).after_first_array_entry = true; } if ( DATA_ERROR_NONE == result ) { result = json_token_reader_expect_begin_object ( &((*this_).tokenizer) ); } if ( DATA_ERROR_NONE == result ) { result = json_token_reader_read_member_name ( &((*this_).tokenizer), member_name ); } if ( DATA_ERROR_NONE == result ) { if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_DIAGRAM ) ) { (*out_type) = DATA_TABLE_DIAGRAM; } /* else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_DIAGRAMELEMENT ) ) { (*out_type) = DATA_TABLE_DIAGRAMELEMENT; } */ else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_CLASSIFIER ) ) { (*out_type) = DATA_TABLE_CLASSIFIER; } /* else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_FEATURE ) ) { (*out_type) = DATA_TABLE_FEATURE; } */ else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_RELATIONSHIP ) ) { (*out_type) = DATA_TABLE_RELATIONSHIP; } else { TSLOG_ERROR_INT( "unexpected token at line", json_token_reader_get_input_line( &((*this_).tokenizer) ) ); result = DATA_ERROR_PARSER_STRUCTURE; } } if ( DATA_ERROR_NONE == result ) { result = json_token_reader_expect_name_separator ( &((*this_).tokenizer) ); } } } TRACE_END_ERR( result ); return result; } data_error_t json_deserializer_expect_end_type_of_element ( json_deserializer_t *this_ ) { TRACE_BEGIN(); data_error_t result = DATA_ERROR_NONE; bool condition; result = json_token_reader_check_end_object ( &((*this_).tokenizer), &condition ); if ( ! condition ) { TSLOG_ERROR_INT( "unexpected object contents at line", json_token_reader_get_input_line( &((*this_).tokenizer) ) ); result |= DATA_ERROR_PARSER_STRUCTURE; } TRACE_END_ERR( result ); return result; } data_error_t json_deserializer_get_next_classifier ( json_deserializer_t *this_, data_classifier_t *out_object, uint32_t max_out_array_size, data_feature_t (*out_feature)[], uint32_t *out_feature_count ) { TRACE_BEGIN(); assert ( NULL != out_object ); assert ( NULL != out_feature ); assert ( NULL != out_feature_count ); data_error_t result = DATA_ERROR_NONE; char member_name_buf[24]; utf8stringbuf_t member_name = UTF8STRINGBUF( member_name_buf ); data_classifier_init_empty( out_object ); /* header */ result = json_token_reader_expect_begin_object ( &((*this_).tokenizer) ); /* members */ bool first_member_passed = false; bool object_end = false; static const int MAX_MEMBERS = 16; /* mamimum number of members to parse */ if ( DATA_ERROR_NONE == result ) { for ( int count = 0; ( ! object_end ) && ( count < MAX_MEMBERS ); count ++ ) { result = json_token_reader_check_end_object ( &((*this_).tokenizer), &object_end ); if ( DATA_ERROR_NONE == result ) { if ( ! object_end ) { if ( first_member_passed ) { result = json_token_reader_expect_value_separator ( &((*this_).tokenizer) ); } else { first_member_passed = true; } if ( DATA_ERROR_NONE == result ) { result = json_token_reader_read_member_name ( &((*this_).tokenizer), member_name ); } if ( DATA_ERROR_NONE == result ) { result = json_token_reader_expect_name_separator ( &((*this_).tokenizer) ); } if ( DATA_ERROR_NONE == result ) { if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_CLASSIFIER_ID ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value ( &((*this_).tokenizer), &parsed_integer ); data_classifier_set_row_id ( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_CLASSIFIER_MAIN_TYPE ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value ( &((*this_).tokenizer), &parsed_integer ); data_classifier_set_main_type ( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_CLASSIFIER_X_ORDER ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value ( &((*this_).tokenizer), &parsed_integer ); data_classifier_set_x_order ( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_CLASSIFIER_Y_ORDER ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value ( &((*this_).tokenizer), &parsed_integer ); data_classifier_set_y_order ( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_CLASSIFIER_LIST_ORDER ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value ( &((*this_).tokenizer), &parsed_integer ); data_classifier_set_list_order ( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_CLASSIFIER_STEREOTYPE ) ) { result = json_token_reader_read_string_value( &((*this_).tokenizer), (*this_).temp_string ); data_classifier_set_stereotype( out_object, utf8stringbuf_get_string( (*this_).temp_string ) ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_CLASSIFIER_NAME ) ) { result = json_token_reader_read_string_value( &((*this_).tokenizer), (*this_).temp_string ); data_classifier_set_name( out_object, utf8stringbuf_get_string( (*this_).temp_string ) ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_CLASSIFIER_DESCRIPTION ) ) { result = json_deserializer_private_read_string_array( this_, (*this_).temp_string ); data_classifier_set_description( out_object, utf8stringbuf_get_string( (*this_).temp_string ) ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_UUID ) ) { /* TODO: do something with the uuid */ result = json_deserializer_skip_next_string( this_ ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_CLASSIFIER_FEATURES ) ) { result = json_deserializer_private_get_next_feature_array( this_, max_out_array_size, out_feature, out_feature_count ); } else { TSLOG_ERROR_INT( "unexpected member name at line", json_token_reader_get_input_line( &((*this_).tokenizer) ) ); result = DATA_ERROR_PARSER_STRUCTURE; } } } } else { TSLOG_ERROR_INT( "unexpected character at line", json_token_reader_get_input_line( &((*this_).tokenizer) ) ); result = DATA_ERROR_PARSER_STRUCTURE; object_end = true; } } } /* footer */ if ( DATA_ERROR_NONE == result ) { data_classifier_trace( out_object ); } TRACE_END_ERR( result ); return result; } data_error_t json_deserializer_get_next_diagram ( json_deserializer_t *this_, data_diagram_t *out_object ) { TRACE_BEGIN(); assert ( NULL != out_object ); data_error_t result = DATA_ERROR_NONE; char member_name_buf[24]; utf8stringbuf_t member_name = UTF8STRINGBUF( member_name_buf ); data_diagram_init_empty( out_object ); /* header */ result = json_token_reader_expect_begin_object ( &((*this_).tokenizer) ); /* members */ bool first_member_passed = false; bool object_end = false; static const int MAX_MEMBERS = 16; /* mamimum number of members to parse */ if ( DATA_ERROR_NONE == result ) { for ( int count = 0; ( ! object_end ) && ( count < MAX_MEMBERS ); count ++ ) { result = json_token_reader_check_end_object ( &((*this_).tokenizer), &object_end ); if ( DATA_ERROR_NONE == result ) { if ( ! object_end ) { if ( first_member_passed ) { result = json_token_reader_expect_value_separator ( &((*this_).tokenizer) ); } else { first_member_passed = true; } if ( DATA_ERROR_NONE == result ) { result = json_token_reader_read_member_name ( &((*this_).tokenizer), member_name ); } if ( DATA_ERROR_NONE == result ) { result = json_token_reader_expect_name_separator ( &((*this_).tokenizer) ); } if ( DATA_ERROR_NONE == result ) { if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_DIAGRAM_ID ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value ( &((*this_).tokenizer), &parsed_integer ); data_diagram_set_row_id ( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_DIAGRAM_PARENT_ID ) ) { int64_t ignored_integer; result = json_token_reader_read_int_value ( &((*this_).tokenizer), &ignored_integer ); (void) ignored_integer; } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_DIAGRAM_DIAGRAM_TYPE ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value ( &((*this_).tokenizer), &parsed_integer ); data_diagram_set_diagram_type ( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_DIAGRAM_LIST_ORDER ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value ( &((*this_).tokenizer), &parsed_integer ); data_diagram_set_list_order ( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_DIAGRAM_DESCRIPTION ) ) { result = json_deserializer_private_read_string_array( this_, (*this_).temp_string ); data_diagram_set_description( out_object, utf8stringbuf_get_string( (*this_).temp_string ) ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_DIAGRAM_NAME ) ) { result = json_token_reader_read_string_value( &((*this_).tokenizer), (*this_).temp_string ); data_diagram_set_name( out_object, utf8stringbuf_get_string( (*this_).temp_string ) ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_DIAGRAM_DISPLAY_FLAGS ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value( &((*this_).tokenizer), &parsed_integer ); data_diagram_set_display_flags ( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_DIAGRAM_PARENT ) ) { /* TODO: do something with the uuid */ result = json_deserializer_skip_next_string( this_ ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_UUID ) ) { /* TODO: do something with the uuid */ result = json_deserializer_skip_next_string( this_ ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_DIAGRAM_ELEMENTS ) ) { result = json_deserializer_private_skip_next_diagramelement_array ( this_ ); } else { TSLOG_ERROR_INT( "unexpected member name at line", json_token_reader_get_input_line( &((*this_).tokenizer) ) ); result = DATA_ERROR_PARSER_STRUCTURE; } } } } else { TSLOG_ERROR_INT( "unexpected character at line", json_token_reader_get_input_line( &((*this_).tokenizer) ) ); result = DATA_ERROR_PARSER_STRUCTURE; object_end = true; } } } /* footer */ if ( DATA_ERROR_NONE == result ) { data_diagram_trace( out_object ); } TRACE_END_ERR( result ); return result; } data_error_t json_deserializer_get_next_relationship ( json_deserializer_t *this_, data_relationship_t *out_object, utf8stringbuf_t out_from_classifier_name, utf8stringbuf_t out_from_feature_key, utf8stringbuf_t out_to_classifier_name, utf8stringbuf_t out_to_feature_key ) { TRACE_BEGIN(); assert( NULL != out_object ); data_error_t result = DATA_ERROR_NONE; char member_name_buf[24]; utf8stringbuf_t member_name = UTF8STRINGBUF( member_name_buf ); data_relationship_init_empty( out_object ); utf8stringbuf_clear( out_from_classifier_name ); utf8stringbuf_clear( out_from_feature_key ); utf8stringbuf_clear( out_to_classifier_name ); utf8stringbuf_clear( out_to_feature_key ); /* header */ result = json_token_reader_expect_begin_object ( &((*this_).tokenizer) ); /* members */ bool first_member_passed = false; bool object_end = false; static const int MAX_MEMBERS = 24; /* mamimum number of members to parse */ if ( DATA_ERROR_NONE == result ) { for ( int count = 0; ( ! object_end ) && ( count < MAX_MEMBERS ); count ++ ) { result = json_token_reader_check_end_object ( &((*this_).tokenizer), &object_end ); if ( DATA_ERROR_NONE == result ) { if ( ! object_end ) { if ( first_member_passed ) { result = json_token_reader_expect_value_separator ( &((*this_).tokenizer) ); } else { first_member_passed = true; } if ( DATA_ERROR_NONE == result ) { result = json_token_reader_read_member_name ( &((*this_).tokenizer), member_name ); } if ( DATA_ERROR_NONE == result ) { result = json_token_reader_expect_name_separator ( &((*this_).tokenizer) ); } if ( DATA_ERROR_NONE == result ) { if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_RELATIONSHIP_ID ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value ( &((*this_).tokenizer), &parsed_integer ); data_relationship_set_row_id ( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_RELATIONSHIP_MAIN_TYPE ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value ( &((*this_).tokenizer), &parsed_integer ); data_relationship_set_main_type ( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_RELATIONSHIP_LIST_ORDER ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value ( &((*this_).tokenizer), &parsed_integer ); data_relationship_set_list_order ( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_RELATIONSHIP_DESCRIPTION ) ) { result = json_deserializer_private_read_string_array( this_, (*this_).temp_string ); data_relationship_set_description( out_object, utf8stringbuf_get_string( (*this_).temp_string ) ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_RELATIONSHIP_NAME ) ) { result = json_token_reader_read_string_value( &((*this_).tokenizer), (*this_).temp_string ); data_relationship_set_name( out_object, utf8stringbuf_get_string( (*this_).temp_string ) ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_RELATIONSHIP_FROM_CLASSIFIER_ID ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value( &((*this_).tokenizer), &parsed_integer ); data_relationship_set_from_classifier_row_id ( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_RELATIONSHIP_FROM_CLASSIFIER_NAME ) ) { result = json_token_reader_read_string_value( &((*this_).tokenizer), (*this_).temp_string ); utf8stringbuf_copy_buf( out_from_classifier_name, (*this_).temp_string ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_RELATIONSHIP_FROM_FEATURE_ID ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value( &((*this_).tokenizer), &parsed_integer ); data_relationship_set_from_feature_row_id ( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_RELATIONSHIP_FROM_FEATURE_KEY ) ) { result = json_token_reader_read_string_value( &((*this_).tokenizer), (*this_).temp_string ); utf8stringbuf_copy_buf( out_from_feature_key, (*this_).temp_string ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_RELATIONSHIP_TO_CLASSIFIER_ID ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value( &((*this_).tokenizer), &parsed_integer ); data_relationship_set_to_classifier_row_id ( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_RELATIONSHIP_TO_CLASSIFIER_NAME ) ) { result = json_token_reader_read_string_value( &((*this_).tokenizer), (*this_).temp_string ); utf8stringbuf_copy_buf( out_to_classifier_name, (*this_).temp_string ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_RELATIONSHIP_TO_FEATURE_ID ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value( &((*this_).tokenizer), &parsed_integer ); data_relationship_set_to_feature_row_id ( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_RELATIONSHIP_TO_FEATURE_KEY ) ) { result = json_token_reader_read_string_value( &((*this_).tokenizer), (*this_).temp_string ); utf8stringbuf_copy_buf( out_to_feature_key, (*this_).temp_string ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_RELATIONSHIP_FROM_NODE ) ) { /* TODO: do something with the uuid */ result = json_deserializer_skip_next_string ( this_ ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_RELATIONSHIP_TO_NODE ) ) { /* TODO: do something with the uuid */ result = json_deserializer_skip_next_string ( this_ ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_UUID ) ) { /* TODO: do something with the uuid */ result = json_deserializer_skip_next_string ( this_ ); } else { TSLOG_ERROR_INT( "unexpected member name at line", json_token_reader_get_input_line( &((*this_).tokenizer) ) ); result = DATA_ERROR_PARSER_STRUCTURE; } } } } else { TSLOG_ERROR_INT( "unexpected character at line", json_token_reader_get_input_line( &((*this_).tokenizer) ) ); result = DATA_ERROR_PARSER_STRUCTURE; object_end = true; } } } /* footer */ if ( DATA_ERROR_NONE == result ) { data_relationship_trace( out_object ); } TRACE_END_ERR( result ); return result; } data_error_t json_deserializer_skip_next_object ( json_deserializer_t *this_ ) { TRACE_BEGIN(); data_error_t result = DATA_ERROR_NONE; char member_name_buf[24]; utf8stringbuf_t member_name = UTF8STRINGBUF( member_name_buf ); /* header */ result = json_token_reader_expect_begin_object ( &((*this_).tokenizer) ); /* members */ bool first_member_passed = false; bool object_end = false; static const int MAX_MEMBERS = 16; /* mamimum number of members to parse */ if ( DATA_ERROR_NONE == result ) { for ( int count = 0; ( ! object_end ) && ( count < MAX_MEMBERS ); count ++ ) { result = json_token_reader_check_end_object ( &((*this_).tokenizer), &object_end ); if ( DATA_ERROR_NONE == result ) { if ( ! object_end ) { if ( first_member_passed ) { result = json_token_reader_expect_value_separator ( &((*this_).tokenizer) ); } else { first_member_passed = true; } if ( DATA_ERROR_NONE == result ) { result = json_token_reader_read_member_name ( &((*this_).tokenizer), member_name ); } if ( DATA_ERROR_NONE == result ) { result = json_token_reader_expect_name_separator ( &((*this_).tokenizer) ); } json_value_type_t v_type; if ( DATA_ERROR_NONE == result ) { result = json_token_reader_get_value_type ( &((*this_).tokenizer), &v_type ); } if ( DATA_ERROR_NONE == result ) { switch ( v_type ) { case JSON_VALUE_TYPE_OBJECT: { result = DATA_ERROR_PARSER_STRUCTURE; /* this function does not expect objects in objects */ } break; case JSON_VALUE_TYPE_ARRAY: { result = DATA_ERROR_PARSER_STRUCTURE; /* this function does not expect arrays in objects */ } break; case JSON_VALUE_TYPE_NUMBER: { double parsed_number; result = json_token_reader_read_number_value ( &((*this_).tokenizer), &parsed_number ); } break; case JSON_VALUE_TYPE_INTEGER: { int64_t parsed_integer; result = json_token_reader_read_int_value ( &((*this_).tokenizer), &parsed_integer ); } break; case JSON_VALUE_TYPE_STRING: { result = json_deserializer_skip_next_string( this_ ); } break; case JSON_VALUE_TYPE_BOOLEAN: { bool parsed_bool; result = json_token_reader_read_boolean_value ( &((*this_).tokenizer), &parsed_bool ); } break; case JSON_VALUE_TYPE_NULL: { result = json_token_reader_expect_null_value ( &((*this_).tokenizer) ); } break; case JSON_VALUE_TYPE_UNDEF: default: { TSLOG_ERROR_INT( "unexpected member name at line", json_token_reader_get_input_line( &((*this_).tokenizer) ) ); result = DATA_ERROR_PARSER_STRUCTURE; /* this function does not expect objects in objects */ } break; } } } } else { TSLOG_ERROR_INT( "unexpected character at line", json_token_reader_get_input_line( &((*this_).tokenizer) ) ); result = DATA_ERROR_PARSER_STRUCTURE; object_end = true; } } } /* footer */ TRACE_END_ERR( result ); return result; } data_error_t json_deserializer_skip_next_string ( json_deserializer_t *this_ ) { TRACE_BEGIN(); data_error_t result = DATA_ERROR_NONE; char dummy_str[4]; utf8stringbuf_t dummy_strbuf = UTF8STRINGBUF ( dummy_str ); result = json_token_reader_read_string_value ( &((*this_).tokenizer), dummy_strbuf ); if ( result == DATA_ERROR_STRING_BUFFER_EXCEEDED ) { /* ignore this. The result string is not needed therefore dummy_str may be too small */ result = DATA_ERROR_NONE; } TRACE_END_ERR( result ); return result; } void json_deserializer_get_read_line ( json_deserializer_t *this_, uint32_t *out_read_pos ) { TRACE_BEGIN(); assert ( NULL != out_read_pos ); (*out_read_pos) = json_token_reader_get_input_line( &((*this_).tokenizer) ); TRACE_END(); } data_error_t json_deserializer_private_get_next_feature_array ( json_deserializer_t *this_, uint32_t max_out_array_size, data_feature_t (*out_feature)[], uint32_t *out_feature_count ) { TRACE_BEGIN(); assert ( NULL != out_feature ); assert ( NULL != out_feature_count ); data_error_t result = DATA_ERROR_NONE; uint32_t feature_count = 0; result = json_token_reader_expect_begin_array( &((*this_).tokenizer) ); if ( DATA_ERROR_NONE == result ) { bool end_array = false; bool first_element_passed = false; for ( int count = 0; ( ! end_array ) && ( count < max_out_array_size ); count ++ ) { result = json_token_reader_check_end_array( &((*this_).tokenizer), &end_array ); if ( DATA_ERROR_NONE == result ) { if ( ! end_array ) { if ( first_element_passed ) { result = json_token_reader_expect_value_separator ( &((*this_).tokenizer) ); } else { first_element_passed = true; } result |= json_deserializer_private_get_next_feature( this_, &((*out_feature)[count]) ); if ( DATA_ERROR_NONE == result ) { feature_count = count+1; } else { /* error, break loop */ end_array = true; } } } else { /* error, break loop */ TSLOG_ERROR_INT( "unexpected array contents at line", json_token_reader_get_input_line( &((*this_).tokenizer) ) ); result |= DATA_ERROR_PARSER_STRUCTURE; end_array = true; } } } if ( DATA_ERROR_NONE == result ) { *out_feature_count = feature_count; } TRACE_END_ERR( result ); return result; } data_error_t json_deserializer_private_get_next_feature ( json_deserializer_t *this_, data_feature_t *out_object ) { TRACE_BEGIN(); assert ( NULL != out_object ); data_error_t result = DATA_ERROR_NONE; char member_name_buf[24]; utf8stringbuf_t member_name = UTF8STRINGBUF( member_name_buf ); data_feature_init_empty( out_object ); /* header */ result = json_token_reader_expect_begin_object ( &((*this_).tokenizer) ); /* members */ bool first_member_passed = false; bool object_end = false; static const int MAX_MEMBERS = 16; /* mamimum number of members to parse */ if ( DATA_ERROR_NONE == result ) { for ( int count = 0; ( ! object_end ) && ( count < MAX_MEMBERS ); count ++ ) { result = json_token_reader_check_end_object ( &((*this_).tokenizer), &object_end ); if ( DATA_ERROR_NONE == result ) { if ( ! object_end ) { if ( first_member_passed ) { result = json_token_reader_expect_value_separator ( &((*this_).tokenizer) ); } else { first_member_passed = true; } if ( DATA_ERROR_NONE == result ) { result = json_token_reader_read_member_name( &((*this_).tokenizer), member_name ); } if ( DATA_ERROR_NONE == result ) { result = json_token_reader_expect_name_separator( &((*this_).tokenizer) ); } if ( DATA_ERROR_NONE == result ) { if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_FEATURE_ID ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value( &((*this_).tokenizer), &parsed_integer ); data_feature_set_row_id ( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_FEATURE_MAIN_TYPE ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value( &((*this_).tokenizer), &parsed_integer ); data_feature_set_main_type( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_FEATURE_LIST_ORDER ) ) { int64_t parsed_integer; result = json_token_reader_read_int_value ( &((*this_).tokenizer), &parsed_integer ); data_feature_set_list_order ( out_object, parsed_integer ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_FEATURE_DESCRIPTION ) ) { result = json_deserializer_private_read_string_array( this_, (*this_).temp_string ); data_feature_set_description( out_object, utf8stringbuf_get_string( (*this_).temp_string ) ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_FEATURE_KEY ) ) { result = json_token_reader_read_string_value( &((*this_).tokenizer), (*this_).temp_string ); data_feature_set_key( out_object, utf8stringbuf_get_string( (*this_).temp_string ) ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_FEATURE_VALUE ) ) { result = json_token_reader_read_string_value( &((*this_).tokenizer), (*this_).temp_string ); data_feature_set_value( out_object, utf8stringbuf_get_string( (*this_).temp_string ) ); } else if ( utf8stringbuf_equals_str( member_name, JSON_CONSTANTS_KEY_UUID ) ) { /* TODO: do something with the uuid */ result = json_deserializer_skip_next_string( this_ ); } else { TSLOG_ERROR_INT( "unexpected member name at line", json_token_reader_get_input_line( &((*this_).tokenizer) ) ); result = DATA_ERROR_PARSER_STRUCTURE; } } } } else { TSLOG_ERROR_INT( "unexpected character at line", json_token_reader_get_input_line( &((*this_).tokenizer) ) ); result = DATA_ERROR_PARSER_STRUCTURE; object_end = true; } } } /* footer */ if ( DATA_ERROR_NONE == result ) { data_feature_trace( out_object ); } TRACE_END_ERR( result ); return result; } data_error_t json_deserializer_private_skip_next_diagramelement_array ( json_deserializer_t *this_ ) { TRACE_BEGIN(); data_error_t result = DATA_ERROR_NONE; result = json_token_reader_expect_begin_array( &((*this_).tokenizer) ); bool end_array = false; bool first_element_passed = false; while (( ! end_array )&&( DATA_ERROR_NONE == result )) { result = json_token_reader_check_end_array( &((*this_).tokenizer), &end_array ); if ( DATA_ERROR_NONE == result ) { if ( ! end_array ) { if ( first_element_passed ) { result = json_token_reader_expect_value_separator ( &((*this_).tokenizer) ); } else { first_element_passed = true; } result |= json_deserializer_skip_next_object( this_ ); } } else { /* error, break loop */ TSLOG_ERROR_INT( "unexpected array contents at line", json_token_reader_get_input_line( &((*this_).tokenizer) ) ); } } TRACE_END_ERR( result ); return result; } data_error_t json_deserializer_private_read_string_array ( json_deserializer_t *this_, utf8stringbuf_t out_joined_string ) { TRACE_BEGIN(); data_error_t result = DATA_ERROR_NONE; utf8stringbuf_clear( out_joined_string ); result = json_token_reader_expect_begin_array( &((*this_).tokenizer) ); bool end_array = false; bool first_element_passed = false; while (( ! end_array )&&( DATA_ERROR_NONE == result )) { result = json_token_reader_check_end_array( &((*this_).tokenizer), &end_array ); if ( DATA_ERROR_NONE == result ) { if ( ! end_array ) { if ( first_element_passed ) { result = json_token_reader_expect_value_separator ( &((*this_).tokenizer) ); } else { first_element_passed = true; } utf8stringbuf_t unused_remaining = utf8stringbuf_get_end( out_joined_string ); result |= json_token_reader_read_string_value( &((*this_).tokenizer), unused_remaining ); } } else { /* error, break loop */ TSLOG_ERROR_INT( "unexpected array contents at line", json_token_reader_get_input_line( &((*this_).tokenizer) ) ); } } TRACE_END_ERR( result ); return result; } /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/json/json_element_writer.c000066400000000000000000002002631415120503000242300ustar00rootroot00000000000000/* File: json_element_writer.inl; Copyright and License: see below */ #include #include "json/json_constants.h" #include "meta/meta_info.h" #include "meta/meta_version.h" #include "trace.h" #include "tslog.h" #include /* define a struct where the function pointers have the exact right signatures to avoid typecasts */ #define io_element_writer_impl_t json_element_writer_t struct json_element_writer_io_element_writer_if_struct { #include "io_element_writer_if.inl" }; #undef io_element_writer_impl_t /* the vmt implementing the interface */ static const struct json_element_writer_io_element_writer_if_struct json_element_writer_private_io_element_writer_if = { .write_header = &json_element_writer_write_header, .start_main = &json_element_writer_start_main, .can_classifier_nest_classifier = &json_element_writer_can_classifier_nest_classifier, .can_classifier_nest_relationship = &json_element_writer_can_classifier_nest_relationship, .start_classifier = &json_element_writer_start_classifier, .assemble_classifier = &json_element_writer_assemble_classifier, .end_classifier = &json_element_writer_end_classifier, .start_feature = &json_element_writer_start_feature, .assemble_feature = &json_element_writer_assemble_feature, .end_feature = &json_element_writer_end_feature, .start_relationship = &json_element_writer_start_relationship, .assemble_relationship = &json_element_writer_assemble_relationship, .end_relationship = &json_element_writer_end_relationship, .start_diagram = &json_element_writer_start_diagram, .assemble_diagram = &json_element_writer_assemble_diagram, .end_diagram = &json_element_writer_end_diagram_fake, .start_diagramelement = &json_element_writer_start_diagramelement, .assemble_diagramelement = &json_element_writer_assemble_diagramelement, .end_diagramelement = &json_element_writer_end_diagramelement, .end_main = &json_element_writer_end_main, .write_footer = &json_element_writer_write_footer }; void json_element_writer_init( json_element_writer_t *this_, data_stat_t *io_export_stat, universal_output_stream_t *output) { TRACE_BEGIN(); assert( io_export_stat != NULL ); assert( output != NULL ); io_element_writer_private_init( &((*this_).element_writer), (io_element_writer_if_t*) &json_element_writer_private_io_element_writer_if, this_ ); json_writer_init( &((*this_).json_writer), output ); (*this_).in_outer_array = false; (*this_).is_outer_first = false; (*this_).in_inner_array = false; (*this_).is_inner_first = false; (*this_).mode = JSON_WRITER_PASS_NODES; (*this_).export_stat = io_export_stat; TRACE_END(); } void json_element_writer_destroy( json_element_writer_t *this_ ) { TRACE_BEGIN(); json_writer_destroy( &((*this_).json_writer) ); io_element_writer_private_destroy( &((*this_).element_writer) ); (*this_).export_stat = NULL; TRACE_END(); } io_element_writer_t * json_element_writer_get_element_writer( json_element_writer_t *this_ ) { TRACE_BEGIN(); io_element_writer_t * base = &((*this_).element_writer); TRACE_END(); return base; } void json_element_writer_set_mode( json_element_writer_t *this_, json_writer_pass_t mode ) { TRACE_BEGIN(); (*this_).mode = mode; TRACE_END(); } int json_element_writer_write_header( json_element_writer_t *this_, const char *document_title ) { TRACE_BEGIN(); assert( document_title != NULL ); assert( (*this_).in_outer_array == false ); assert( (*this_).in_inner_array == false ); int out_err = 0; out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_BEGIN_OBJECT_NL JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_HEAD JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF JSON_CONSTANTS_BEGIN_OBJECT_NL ); out_err |= json_writer_write_member_string( &((*this_).json_writer), 2, "encoding", "utf-8", true ); out_err |= json_writer_write_member_string( &((*this_).json_writer), 2, "structure_format", "rfc-8259", true ); out_err |= json_writer_write_member_string( &((*this_).json_writer), 2, "format", "cfu-json", true ); out_err |= json_writer_write_member_int( &((*this_).json_writer), 2, "major_version", 1, true ); out_err |= json_writer_write_member_int( &((*this_).json_writer), 2, "minor_version", 0, true ); out_err |= json_writer_write_member_string( &((*this_).json_writer), 2, "generator_name", META_INFO_PROGRAM_ID_STR, true ); out_err |= json_writer_write_member_string( &((*this_).json_writer), 2, "generator_version", META_VERSION_STR, false ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_END_OBJECT JSON_CONSTANTS_NL ); if ( out_err != 0 ) { TSLOG_ERROR( "output buffer exceeded." ); } TRACE_END_ERR(out_err); return out_err; } int json_element_writer_start_main( json_element_writer_t *this_, const char *document_title ) { TRACE_BEGIN(); assert( document_title != NULL ); assert( (*this_).in_outer_array == false ); assert( (*this_).in_inner_array == false ); int out_err = 0; out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_NEXT_NL JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE ); switch( (*this_).mode ) { case JSON_WRITER_PASS_VIEWS: { out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_KEY_VIEWS ); } break; case JSON_WRITER_PASS_NODES: { out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_KEY_NODES ); } break; case JSON_WRITER_PASS_EDGES: { out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_KEY_EDGES ); } break; default: { assert( false ); } break; } out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF JSON_CONSTANTS_NL JSON_CONSTANTS_TAB JSON_CONSTANTS_BEGIN_ARRAY ); if ( out_err != 0 ) { TSLOG_ERROR( "output buffer exceeded." ); } (*this_).in_outer_array = true; (*this_).is_outer_first = true; TRACE_END_ERR(out_err); return out_err; } bool json_element_writer_can_classifier_nest_classifier( json_element_writer_t *this_, data_classifier_type_t host_type, data_classifier_type_t child_type ) { TRACE_BEGIN(); const bool can_nest = false; TRACE_END(); return can_nest; } bool json_element_writer_can_classifier_nest_relationship( json_element_writer_t *this_, data_classifier_type_t host_type, data_relationship_type_t child_type ) { TRACE_BEGIN(); const bool can_nest = true; TRACE_END(); return can_nest; } int json_element_writer_start_classifier( json_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ) { TRACE_BEGIN(); assert( classifier_ptr != NULL ); int out_err = 0; if ( (*this_).mode == JSON_WRITER_PASS_NODES ) { /* separate objects in array if not first */ if ( (*this_).is_outer_first ) { (*this_).is_outer_first = false; out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NL ); } else { out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NEXT_NL ); } /* begin classifier */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_BEGIN_OBJECT JSON_CONSTANTS_NL JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_CLASSIFIER JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF JSON_CONSTANTS_BEGIN_OBJECT_NL ); } TRACE_END_ERR(out_err); return out_err; } int json_element_writer_assemble_classifier( json_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ) { TRACE_BEGIN(); assert( classifier_ptr != NULL ); int out_err = 0; if ( (*this_).mode == JSON_WRITER_PASS_NODES ) { assert( (*this_).in_outer_array == true ); assert( (*this_).in_inner_array == false ); /* id */ out_err |= json_writer_write_member_int( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_CLASSIFIER_ID, data_classifier_get_row_id( classifier_ptr ), true ); /* main type */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_CLASSIFIER_MAIN_TYPE JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF ); out_err |= json_writer_write_int( &((*this_).json_writer), data_classifier_get_main_type( classifier_ptr ) ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NEXT_NL ); /* stereotype */ out_err |= json_writer_write_member_string( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_CLASSIFIER_STEREOTYPE, data_classifier_get_stereotype_const( classifier_ptr ), true ); /* name */ out_err |= json_writer_write_member_string( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_CLASSIFIER_NAME, data_classifier_get_name_const( classifier_ptr ), true ); /* description */ out_err |= json_writer_write_member_string_array( &((*this_).json_writer) , 4, JSON_CONSTANTS_KEY_CLASSIFIER_DESCRIPTION, data_classifier_get_description_const( classifier_ptr ), true ); /* x_order */ out_err |= json_writer_write_member_int( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_CLASSIFIER_X_ORDER, data_classifier_get_x_order( classifier_ptr ), true ); /* y_order */ out_err |= json_writer_write_member_int( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_CLASSIFIER_Y_ORDER, data_classifier_get_y_order( classifier_ptr ), true ); /* list_order */ out_err |= json_writer_write_member_int( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_CLASSIFIER_LIST_ORDER, data_classifier_get_list_order( classifier_ptr ), true ); /* uuid */ out_err |= json_writer_write_member_string( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_UUID, data_classifier_get_uuid_const( classifier_ptr ), true ); /* array of features */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_CLASSIFIER_FEATURES JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF JSON_CONSTANTS_NL JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_BEGIN_ARRAY ); (*this_).in_inner_array = true; (*this_).is_inner_first = true; /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_CLASSIFIER, DATA_STAT_SERIES_EXPORTED ); } TRACE_END_ERR(out_err); return out_err; } int json_element_writer_end_classifier( json_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ) { TRACE_BEGIN(); assert( classifier_ptr != NULL ); int out_err = 0; if ( (*this_).mode == JSON_WRITER_PASS_NODES ) { assert( (*this_).in_outer_array == true ); assert( (*this_).in_inner_array == true ); (*this_).in_inner_array = false; (*this_).is_inner_first = false; out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NL ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_END_ARRAY JSON_CONSTANTS_NL ); /* end classifier */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_END_OBJECT_NL JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_END_OBJECT ); if ( out_err != 0 ) { TSLOG_ERROR( "output buffer exceeded." ); } } TRACE_END_ERR(out_err); return out_err; } int json_element_writer_start_feature( json_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ) { TRACE_BEGIN(); assert( feature_ptr != NULL ); int out_err = 0; if ( (*this_).mode == JSON_WRITER_PASS_NODES ) { /* separate objects in array if not first */ if ( (*this_).is_inner_first ) { (*this_).is_inner_first = false; out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NL ); } else { out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NEXT_NL ); } /* begin feature */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_BEGIN_OBJECT_NL ); } TRACE_END_ERR(out_err); return out_err; } int json_element_writer_assemble_feature( json_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ) { TRACE_BEGIN(); assert( feature_ptr != NULL ); int out_err = 0; if ( (*this_).mode == JSON_WRITER_PASS_NODES ) { assert( (*this_).in_outer_array == true ); assert( (*this_).in_inner_array == true ); /* id */ out_err |= json_writer_write_member_int( &((*this_).json_writer), 6, JSON_CONSTANTS_KEY_FEATURE_ID, data_feature_get_row_id( feature_ptr ), true ); /* main_type */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_FEATURE_MAIN_TYPE JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF ); out_err |= json_writer_write_int( &((*this_).json_writer), data_feature_get_main_type( feature_ptr ) ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NEXT_NL ); /* key */ out_err |= json_writer_write_member_string( &((*this_).json_writer), 6, JSON_CONSTANTS_KEY_FEATURE_KEY, data_feature_get_key_const( feature_ptr ), true ); /* value */ out_err |= json_writer_write_member_string( &((*this_).json_writer), 6, JSON_CONSTANTS_KEY_FEATURE_VALUE, data_feature_get_value_const( feature_ptr ), true ); /* description */ out_err |= json_writer_write_member_string_array( &((*this_).json_writer) , 6, JSON_CONSTANTS_KEY_FEATURE_DESCRIPTION, data_feature_get_description_const( feature_ptr ), true ); /* list_order */ out_err |= json_writer_write_member_int( &((*this_).json_writer), 6, JSON_CONSTANTS_KEY_FEATURE_LIST_ORDER, data_feature_get_list_order( feature_ptr ), true ); /* uuid */ out_err |= json_writer_write_member_string( &((*this_).json_writer), 6, JSON_CONSTANTS_KEY_UUID, data_feature_get_uuid_const( feature_ptr ), false /* LAST, no NEXT */ ); /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_EXPORTED ); } TRACE_END_ERR(out_err); return out_err; } int json_element_writer_end_feature( json_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ) { TRACE_BEGIN(); assert( feature_ptr != NULL ); int out_err = 0; if ( (*this_).mode == JSON_WRITER_PASS_NODES ) { /* end feature */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_END_OBJECT ); if ( out_err != 0 ) { TSLOG_ERROR( "output buffer exceeded." ); } } TRACE_END_ERR(out_err); return out_err; } int json_element_writer_start_relationship( json_element_writer_t *this_, data_classifier_type_t host_type, const data_relationship_t *relation_ptr ) { TRACE_BEGIN(); assert( relation_ptr != NULL ); int out_err = 0; if ( (*this_).mode == JSON_WRITER_PASS_EDGES ) { /* separate objects if not first */ if ( (*this_).is_outer_first ) { (*this_).is_outer_first = false; out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NL ); } else { out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NEXT_NL ); } /* begin relationship */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_BEGIN_OBJECT JSON_CONSTANTS_NL JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_RELATIONSHIP JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF JSON_CONSTANTS_BEGIN_OBJECT_NL ); } TRACE_END_ERR(out_err); return out_err; } int json_element_writer_assemble_relationship( json_element_writer_t *this_, const data_classifier_t *host, const data_relationship_t *relation_ptr, const data_classifier_t *from_c, const data_feature_t *from_f, const data_classifier_t *to_c, const data_feature_t *to_f ) { TRACE_BEGIN(); assert( relation_ptr != NULL ); int out_err = 0; if ( (*this_).mode == JSON_WRITER_PASS_EDGES ) { assert( from_c != NULL ); assert( to_c != NULL ); assert( (*this_).in_outer_array == true ); assert( (*this_).in_inner_array == false ); /* id */ out_err |= json_writer_write_member_int( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_RELATIONSHIP_ID, data_relationship_get_row_id( relation_ptr ), true ); /* main type */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_RELATIONSHIP_MAIN_TYPE JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF ); out_err |= json_writer_write_int( &((*this_).json_writer), data_relationship_get_main_type( relation_ptr ) ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NEXT_NL ); /* name */ out_err |= json_writer_write_member_string( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_RELATIONSHIP_NAME, data_relationship_get_name_const( relation_ptr ), true ); /* description */ out_err |= json_writer_write_member_string_array( &((*this_).json_writer) , 4, JSON_CONSTANTS_KEY_RELATIONSHIP_DESCRIPTION, data_relationship_get_description_const( relation_ptr ), true ); /* list_order */ out_err |= json_writer_write_member_int( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_RELATIONSHIP_LIST_ORDER, data_relationship_get_list_order( relation_ptr ), true ); const bool from_f_valid = ( from_f == NULL ) ? false : data_feature_is_valid( from_f ); const bool from_c_valid = ( from_c == NULL ) ? false : data_classifier_is_valid( from_c ); const bool to_f_valid = ( to_f == NULL ) ? false : data_feature_is_valid( to_f ); const bool to_c_valid = ( to_c == NULL ) ? false : data_classifier_is_valid( to_c ); /* from_classifier_id */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_RELATIONSHIP_FROM_CLASSIFIER_ID JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF ); out_err |= json_writer_write_int( &((*this_).json_writer), data_relationship_get_from_classifier_row_id( relation_ptr ) ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NEXT_NL ); /* from_classifier_name */ const char *const from_c_name = from_c_valid ? data_classifier_get_name_const( from_c ) : ""; out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_RELATIONSHIP_FROM_CLASSIFIER_NAME JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF JSON_CONSTANTS_QUOTE ); out_err |= json_writer_write_string_enc( &((*this_).json_writer), from_c_name ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_QUOTE JSON_CONSTANTS_NEXT_NL ); /* to_classifier_id */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_RELATIONSHIP_TO_CLASSIFIER_ID JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF ); out_err |= json_writer_write_int( &((*this_).json_writer), data_relationship_get_to_classifier_row_id( relation_ptr ) ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NEXT_NL ); /* to_classifier_name */ const char *const to_c_name = from_c_valid ? data_classifier_get_name_const( to_c ) : ""; out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_RELATIONSHIP_TO_CLASSIFIER_NAME JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF JSON_CONSTANTS_QUOTE ); out_err |= json_writer_write_string_enc( &((*this_).json_writer), to_c_name ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_QUOTE JSON_CONSTANTS_NEXT_NL ); /* from_feature_id */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_RELATIONSHIP_FROM_FEATURE_ID JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF ); out_err |= json_writer_write_int( &((*this_).json_writer), data_relationship_get_from_feature_row_id( relation_ptr ) ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NEXT_NL ); /* from_feature_key */ if ( from_f_valid ) { out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_RELATIONSHIP_FROM_FEATURE_KEY JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF JSON_CONSTANTS_QUOTE ); out_err |= json_writer_write_string_enc( &((*this_).json_writer), data_feature_get_key_const( from_f ) ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_QUOTE JSON_CONSTANTS_NEXT_NL ); } /* to_feature_id */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_RELATIONSHIP_TO_FEATURE_ID JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF ); out_err |= json_writer_write_int( &((*this_).json_writer), data_relationship_get_to_feature_row_id( relation_ptr ) ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NEXT_NL ); /* to_feature_key */ if ( to_f_valid ) { out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_RELATIONSHIP_TO_FEATURE_KEY JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF JSON_CONSTANTS_QUOTE ); out_err |= json_writer_write_string_enc( &((*this_).json_writer), data_feature_get_key_const( to_f ) ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_QUOTE JSON_CONSTANTS_NEXT_NL ); } /* from node ref_uuid */ const char *const from_node_ref = ( from_f_valid ) ? data_feature_get_uuid_const( from_f ) : ( from_c_valid ) ? data_classifier_get_uuid_const( from_c ) : ""; out_err |= json_writer_write_member_string( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_RELATIONSHIP_FROM_NODE, from_node_ref, true ); /* to node ref_uuid */ const char *const to_node_ref = ( to_f_valid ) ? data_feature_get_uuid_const( to_f ) : ( to_c_valid ) ? data_classifier_get_uuid_const( to_c ) : ""; out_err |= json_writer_write_member_string( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_RELATIONSHIP_TO_NODE, to_node_ref, true ); /* uuid */ out_err |= json_writer_write_member_string( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_UUID, data_relationship_get_uuid_const( relation_ptr ), false /* LAST, no NEXT */ ); /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_EXPORTED ); } TRACE_END_ERR(out_err); return out_err; } int json_element_writer_end_relationship( json_element_writer_t *this_, data_classifier_type_t host_type, const data_relationship_t *relation_ptr ) { TRACE_BEGIN(); assert( relation_ptr != NULL ); int out_err = 0; if ( (*this_).mode == JSON_WRITER_PASS_EDGES ) { /* end relationship */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_END_OBJECT_NL JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_END_OBJECT ); if ( out_err != 0 ) { TSLOG_ERROR( "output buffer exceeded." ); } } TRACE_END_ERR(out_err); return out_err; } int json_element_writer_start_diagram( json_element_writer_t *this_, const data_diagram_t *diag_ptr ) { TRACE_BEGIN(); assert( diag_ptr != NULL ); int out_err = 0; if ( (*this_).mode == JSON_WRITER_PASS_VIEWS ) { /* separate objects if not first */ if ( (*this_).is_outer_first ) { (*this_).is_outer_first = false; out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NL ); } else { /* print diagram end here because the official end requires hierarcical diagram containments */ out_err |= json_element_writer_private_end_diagram( this_ ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NEXT_NL ); } assert( (*this_).in_outer_array == true ); assert( (*this_).in_inner_array == false ); /* begin diagram */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_BEGIN_OBJECT JSON_CONSTANTS_NL JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_DIAGRAM JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF JSON_CONSTANTS_BEGIN_OBJECT_NL ); } TRACE_END_ERR(out_err); return out_err; } int json_element_writer_assemble_diagram( json_element_writer_t *this_, const data_diagram_t *parent, const data_diagram_t *diag_ptr, const char *diagram_file_base_name ) { TRACE_BEGIN(); assert( diag_ptr != NULL ); assert( diagram_file_base_name != NULL ); int out_err = 0; if ( (*this_).mode == JSON_WRITER_PASS_VIEWS ) { /* id */ out_err |= json_writer_write_member_int( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_DIAGRAM_ID, data_diagram_get_row_id( diag_ptr ), true ); /* parent_id */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_DIAGRAM_PARENT_ID JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF ); out_err |= json_writer_write_int( &((*this_).json_writer), data_diagram_get_parent_row_id( diag_ptr ) ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NEXT_NL ); /* diagram type */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_DIAGRAM_DIAGRAM_TYPE JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF ); out_err |= json_writer_write_int( &((*this_).json_writer), data_diagram_get_diagram_type( diag_ptr ) ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NEXT_NL ); /* name */ out_err |= json_writer_write_member_string( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_DIAGRAM_NAME, data_diagram_get_name_const( diag_ptr ), true ); /* description */ out_err |= json_writer_write_member_string_array( &((*this_).json_writer) , 4, JSON_CONSTANTS_KEY_DIAGRAM_DESCRIPTION, data_diagram_get_description_const( diag_ptr ), true ); /* list_order */ out_err |= json_writer_write_member_int( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_DIAGRAM_LIST_ORDER, data_diagram_get_list_order( diag_ptr ), true ); /* display_flags */ out_err |= json_writer_write_member_int( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_DIAGRAM_DISPLAY_FLAGS, data_diagram_get_display_flags( diag_ptr ), true ); /* parent uuid */ const bool parent_valid = ( parent == NULL ) ? false : data_diagram_is_valid( parent ); if ( parent_valid ) { out_err |= json_writer_write_member_string( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_DIAGRAM_PARENT, data_diagram_get_uuid_const( parent ), true ); } /* uuid */ out_err |= json_writer_write_member_string( &((*this_).json_writer), 4, JSON_CONSTANTS_KEY_UUID, data_diagram_get_uuid_const( diag_ptr ), true /* NEXT, not LAST */ ); /* array of features */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_DIAGRAM_ELEMENTS JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF JSON_CONSTANTS_NL JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_BEGIN_ARRAY ); (*this_).in_inner_array = true; (*this_).is_inner_first = true; /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_DIAGRAM, DATA_STAT_SERIES_EXPORTED ); } TRACE_END_ERR(out_err); return out_err; } int json_element_writer_end_diagram_fake( json_element_writer_t *this_, const data_diagram_t *diag_ptr ) { TRACE_BEGIN(); assert( diag_ptr != NULL ); int out_err = 0; /* The JSON export does not encapsulate one diagram into another. */ /* Therefore, diagrams are ended already when the next starts. */ TRACE_END_ERR(out_err); return out_err; } int json_element_writer_private_end_diagram( json_element_writer_t *this_ ) { TRACE_BEGIN(); int out_err = 0; if ( (*this_).mode == JSON_WRITER_PASS_VIEWS ) { (*this_).in_inner_array = false; (*this_).is_inner_first = false; out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NL ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_END_ARRAY JSON_CONSTANTS_NL ); /* end diagram */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_END_OBJECT_NL JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_END_OBJECT ); } TRACE_END_ERR(out_err); return out_err; } int json_element_writer_start_diagramelement( json_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr ) { TRACE_BEGIN(); assert( diagramelement_ptr != NULL ); assert( parent != NULL ); int out_err = 0; if ( (*this_).mode == JSON_WRITER_PASS_VIEWS ) { /* separate objects in array if not first */ if ( (*this_).is_inner_first ) { (*this_).is_inner_first = false; out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NL ); } else { out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NEXT_NL ); } /* begin diagramelement */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_BEGIN_OBJECT_NL ); if ( out_err != 0 ) { TSLOG_ERROR( "output buffer exceeded." ); } } TRACE_END_ERR(out_err); return out_err; } int json_element_writer_assemble_diagramelement( json_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr, const data_classifier_t *occurrence, const data_feature_t *feat_occur ) { TRACE_BEGIN(); assert( parent != NULL ); assert( diagramelement_ptr != NULL ); assert( parent != NULL ); assert( occurrence != NULL ); /* feat_occur may be NULL */ int out_err = 0; if ( (*this_).mode == JSON_WRITER_PASS_VIEWS ) { assert( (*this_).in_outer_array == true ); assert( (*this_).in_inner_array == true ); /* id */ out_err |= json_writer_write_member_int( &((*this_).json_writer), 6, JSON_CONSTANTS_KEY_DIAGRAMELEMENT_ID, data_diagramelement_get_row_id( diagramelement_ptr ), true ); /* display_flags */ out_err |= json_writer_write_member_int( &((*this_).json_writer), 6, JSON_CONSTANTS_KEY_DIAGRAMELEMENT_DISPLAY_FLAGS, data_diagramelement_get_display_flags( diagramelement_ptr ), true ); /* classifier_id */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_DIAGRAMELEMENT_CLASSIFIER_ID JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF ); out_err |= json_writer_write_int( &((*this_).json_writer), data_diagramelement_get_classifier_row_id( diagramelement_ptr ) ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NEXT_NL ); /* focused_feature_id */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE JSON_CONSTANTS_KEY_DIAGRAMELEMENT_FOCUSED_FEATURE_ID JSON_CONSTANTS_QUOTE JSON_CONSTANTS_DEF ); out_err |= json_writer_write_int( &((*this_).json_writer), data_diagramelement_get_focused_feature_row_id( diagramelement_ptr ) ); out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NEXT_NL ); /* ref_uuid */ const bool feat_valid = ( feat_occur == NULL ) ? false : data_feature_is_valid( feat_occur ); const bool clas_valid = ( occurrence == NULL ) ? false : data_classifier_is_valid( occurrence ); const char *const node_ref = ( feat_valid ) ? data_feature_get_uuid_const( feat_occur ) : ( clas_valid ) ? data_classifier_get_uuid_const( occurrence ) : ""; out_err |= json_writer_write_member_string( &((*this_).json_writer), 6, JSON_CONSTANTS_KEY_DIAGRAMELEMENT_NODE, node_ref, true ); /* uuid */ out_err |= json_writer_write_member_string( &((*this_).json_writer), 6, JSON_CONSTANTS_KEY_UUID, data_diagramelement_get_uuid_const( diagramelement_ptr ), false /* LAST, no NEXT */ ); /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_EXPORTED ); } TRACE_END_ERR(out_err); return out_err; } int json_element_writer_end_diagramelement( json_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr ) { TRACE_BEGIN(); assert( diagramelement_ptr != NULL ); assert( parent != NULL ); int out_err = 0; if ( (*this_).mode == JSON_WRITER_PASS_VIEWS ) { /* end diagramelement */ out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_END_OBJECT ); if ( out_err != 0 ) { TSLOG_ERROR( "output buffer exceeded." ); } } TRACE_END_ERR(out_err); return out_err; } int json_element_writer_end_main( json_element_writer_t *this_ ) { TRACE_BEGIN(); int out_err = 0; /* print diagram end here because the official end requires hierarcical diagram containments */ if ( (*this_).mode == JSON_WRITER_PASS_VIEWS ) { if ( ! (*this_).is_outer_first ) { out_err |= json_element_writer_private_end_diagram( this_ ); } } assert( (*this_).in_outer_array == true ); assert( (*this_).in_inner_array == false ); (*this_).in_outer_array = false; (*this_).is_outer_first = false; out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_NL JSON_CONSTANTS_TAB JSON_CONSTANTS_END_ARRAY JSON_CONSTANTS_NL ); if ( out_err != 0 ) { TSLOG_ERROR( "output buffer exceeded." ); } TRACE_END_ERR(out_err); return out_err; } int json_element_writer_write_footer( json_element_writer_t *this_ ) { TRACE_BEGIN(); assert( (*this_).in_outer_array == false ); assert( (*this_).in_inner_array == false ); int out_err = 0; out_err |= json_writer_write_plain( &((*this_).json_writer), JSON_CONSTANTS_END_OBJECT_NL ); if ( out_err != 0 ) { TSLOG_ERROR( "output buffer exceeded." ); } TRACE_END_ERR(out_err); return out_err; } /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/json/json_import_to_database.c000066400000000000000000001355471415120503000250570ustar00rootroot00000000000000/* File: json_import_to_database.c; Copyright and License: see below */ #include "json/json_import_to_database.h" #include "ctrl_error.h" #include "stream/universal_memory_input_stream.h" #include "util/string/utf8string.h" #include "trace.h" #include #include #include void json_import_to_database_init ( json_import_to_database_t *this_, data_database_reader_t *db_reader, ctrl_controller_t *controller ) { TRACE_BEGIN(); assert( NULL != db_reader ); assert( NULL != controller ); (*this_).db_reader = db_reader; (*this_).controller = controller; data_rules_init ( &((*this_).data_rules) ); TRACE_END(); } void json_import_to_database_destroy ( json_import_to_database_t *this_ ) { TRACE_BEGIN(); data_rules_destroy ( &((*this_).data_rules) ); (*this_).db_reader = NULL; (*this_).controller = NULL; TRACE_END(); } data_error_t json_import_to_database_import_buf_to_db( json_import_to_database_t *this_, const char *json_text, data_row_id_t diagram_id, data_stat_t *io_stat, uint32_t *out_read_line ) { TRACE_BEGIN(); assert( NULL != json_text ); data_error_t result = DATA_ERROR_NONE; universal_memory_input_stream_t in_mem_stream; universal_memory_input_stream_init( &in_mem_stream, json_text, strlen(json_text) ); universal_input_stream_t* in_stream = universal_memory_input_stream_get_input_stream( &in_mem_stream ); result = json_import_to_database_import_stream_to_db( this_, in_stream, diagram_id, io_stat, out_read_line ); universal_memory_input_stream_destroy( &in_mem_stream ); TRACE_END_ERR( result ); return result; } data_error_t json_import_to_database_import_stream_to_db( json_import_to_database_t *this_, universal_input_stream_t *json_text, data_row_id_t diagram_id, data_stat_t *io_stat, uint32_t *out_read_line ) { TRACE_BEGIN(); assert( NULL != json_text ); assert( NULL != io_stat ); assert( NULL != out_read_line ); data_error_t parse_error = DATA_ERROR_NONE; data_row_id_t attach_diagram_id = diagram_id; json_deserializer_t deserializer; json_deserializer_init( &deserializer, json_text ); /* check if diagram id exists */ { static data_diagram_t dummy_diagram; parse_error = data_database_reader_get_diagram_by_id ( (*this_).db_reader, diagram_id, &dummy_diagram ); if ( DATA_ERROR_NONE != parse_error ) { TSLOG_ERROR_INT( "diagram id where to import json data does not exist (anymore)", diagram_id ); } } /* read header */ if ( DATA_ERROR_NONE == parse_error ) { parse_error = json_deserializer_expect_header( &deserializer ); } if ( DATA_ERROR_NONE == parse_error ) { parse_error = json_import_to_database_private_import_views( this_, &deserializer, &attach_diagram_id, io_stat ); } if ( DATA_ERROR_NONE == parse_error ) { parse_error = json_import_to_database_private_import_nodes( this_, &deserializer, attach_diagram_id, io_stat ); } if ( DATA_ERROR_NONE == parse_error ) { parse_error = json_import_to_database_private_import_edges( this_, &deserializer, attach_diagram_id, io_stat ); } if ( DATA_ERROR_NONE == parse_error ) { parse_error = json_deserializer_expect_footer( &deserializer ); } json_deserializer_get_read_line ( &deserializer, out_read_line ); json_deserializer_destroy( &deserializer ); TRACE_END_ERR( parse_error ); return parse_error; } bool json_import_to_database_private_is_feature_focused_in_diagram( json_import_to_database_t *this_, data_row_id_t diagram_id, data_row_id_t feature_id ) { TRACE_BEGIN(); bool is_focused = false; /* read the database */ uint32_t diagramelement_count; data_error_t d_err; d_err = data_database_reader_get_diagramelements_by_diagram_id ( (*this_).db_reader, diagram_id, JSON_IMPORT_TO_DATABASE_MAX_DIAGELES, &((*this_).temp_diageles), &diagramelement_count ); if ( d_err == DATA_ERROR_NONE ) { for ( uint_fast32_t idx = 0; idx < diagramelement_count; idx ++ ) { data_diagramelement_t *current_diagele = &((*this_).temp_diageles[idx]); if ( feature_id == data_diagramelement_get_focused_feature_row_id( current_diagele ) ) { is_focused = true; } } } else { TSLOG_ERROR_HEX( "data_database_reader_get_diagramelements_by_diagram_id failed.", d_err ); } TRACE_END(); return is_focused; } data_error_t json_import_to_database_prescan( json_import_to_database_t *this_, universal_input_stream_t *in_stream, data_stat_t *io_stat, universal_utf8_writer_t *out_english_report ) { TRACE_BEGIN(); data_error_t result = DATA_ERROR_NONE; char buf[1024]; int err = 0; int count = 0; while( err == 0 ) { size_t length; err = universal_input_stream_read( in_stream, &buf, sizeof(buf), &length ); count ++; } universal_utf8_writer_write_str( out_english_report, "\nread size: " ); universal_utf8_writer_write_int( out_english_report, count ); universal_utf8_writer_write_str( out_english_report, " kB\n" ); TRACE_END_ERR( result ); return result; } data_error_t json_import_to_database_private_import_views( json_import_to_database_t *this_, json_deserializer_t *deserializer, data_row_id_t *io_diagram_id, data_stat_t *io_stat ) { TRACE_BEGIN(); assert( NULL != deserializer ); assert( NULL != io_stat ); assert( NULL != io_diagram_id ); data_error_t parse_error = DATA_ERROR_NONE; if ( DATA_ERROR_NONE == parse_error ) { parse_error = json_deserializer_expect_begin_data( deserializer ); } if ( DATA_ERROR_NONE == parse_error ) { data_table_t next_object_type; bool set_end = false; /* end of data set reached or error at parsing */ parse_error = json_deserializer_check_end_data( deserializer, &set_end ); bool any_error = ( parse_error != DATA_ERROR_NONE ); /* consolidation of parser errors and writer errors */ bool is_first = true; /* is this the first object in the database that is created? if false, database changes are appended to the last undo_redo_set */ static const uint32_t MAX_LOOP_COUNTER = (CTRL_UNDO_REDO_LIST_MAX_SIZE/2)-2; /* do not import more things than can be undone */ for ( int count = 0; ( ! set_end ) && ( ! any_error ) && ( count < MAX_LOOP_COUNTER ); count ++ ) { parse_error = json_deserializer_expect_begin_type_of_element( deserializer, &next_object_type ); if ( DATA_ERROR_NONE == parse_error ) { switch ( next_object_type ) { case DATA_TABLE_VOID: { /* we are finished */ set_end = true; } break; case DATA_TABLE_DIAGRAM: { data_diagram_t new_diagram; parse_error = json_deserializer_get_next_diagram ( deserializer, &new_diagram ); if ( DATA_ERROR_NONE != parse_error ) { /* parser error, break loop: */ any_error = true; } else { /* create the parsed diagram as child below the current diagram */ ctrl_diagram_controller_t *diag_ctrl; diag_ctrl = ctrl_controller_get_diagram_control_ptr( (*this_).controller ); ctrl_error_t write_error3; data_row_id_t new_diag_id; data_diagram_set_parent_row_id( &new_diagram, *io_diagram_id ); write_error3 = ctrl_diagram_controller_create_diagram ( diag_ctrl, &new_diagram, ( is_first ? CTRL_UNDO_REDO_ACTION_BOUNDARY_START_NEW : CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND ), &new_diag_id ); data_stat_inc_count ( io_stat, DATA_TABLE_DIAGRAM, (CTRL_ERROR_NONE==write_error3)?DATA_STAT_SERIES_CREATED:DATA_STAT_SERIES_ERROR ); if ( CTRL_ERROR_NONE != write_error3 ) { TSLOG_ERROR( "unexpected error at ctrl_diagram_controller_create_diagram" ); any_error = true; } else { /* insert all consecutive elements to this new diagram */ *io_diagram_id = new_diag_id; } is_first = false; } } break; default: { TSLOG_ERROR( "unexpected token error" ); any_error = true; } } if ( DATA_ERROR_NONE == parse_error ) { parse_error = json_deserializer_expect_end_type_of_element( deserializer ); /* parser error, break loop: */ any_error = ( any_error ||( DATA_ERROR_NONE != parse_error )); } } else { /* parser error, break loop: */ any_error = true; } if ( DATA_ERROR_NONE == parse_error ) { parse_error = json_deserializer_check_end_data( deserializer, &set_end ); /* parser error, break loop: */ any_error = ( any_error ||( DATA_ERROR_NONE != parse_error )); } } } TRACE_END_ERR( parse_error ); return parse_error; } data_error_t json_import_to_database_private_import_nodes( json_import_to_database_t *this_, json_deserializer_t *deserializer, data_row_id_t diagram_id, data_stat_t *io_stat ) { TRACE_BEGIN(); assert( NULL != deserializer ); assert( NULL != io_stat ); data_error_t parse_error = DATA_ERROR_NONE; if ( DATA_ERROR_NONE == parse_error ) { parse_error = json_deserializer_expect_begin_data( deserializer ); } if ( DATA_ERROR_NONE == parse_error ) { data_table_t next_object_type; bool set_end = false; /* end of data set reached or error at parsing */ parse_error = json_deserializer_check_end_data( deserializer, &set_end ); bool any_error = ( parse_error != DATA_ERROR_NONE ); /* consolidation of parser errors and writer errors */ bool is_first = true; /* is this the first object in the database that is created? if false, database changes are appended to the last undo_redo_set */ static const uint32_t MAX_LOOP_COUNTER = (CTRL_UNDO_REDO_LIST_MAX_SIZE/2)-2; /* do not import more things than can be undone */ for ( int count = 0; ( ! set_end ) && ( ! any_error ) && ( count < MAX_LOOP_COUNTER ); count ++ ) { parse_error = json_deserializer_expect_begin_type_of_element( deserializer, &next_object_type ); if ( DATA_ERROR_NONE == parse_error ) { switch ( next_object_type ) { case DATA_TABLE_VOID: { /* we are finished */ set_end = true; } break; case DATA_TABLE_CLASSIFIER: { data_classifier_t new_classifier; uint32_t feature_count; parse_error = json_deserializer_get_next_classifier ( deserializer, &new_classifier, JSON_IMPORT_TO_DATABASE_MAX_FEATURES, &((*this_).temp_features), &feature_count ); if ( DATA_ERROR_NONE != parse_error ) { /* parser error, break loop: */ any_error = true; } else { /* create classifier if not yet existing */ data_row_id_t the_classifier_id; { /* check if the parsed classifier already exists in this database; if not, create it */ ctrl_classifier_controller_t *classifier_ctrl; classifier_ctrl = ctrl_controller_get_classifier_control_ptr( (*this_).controller ); data_error_t read_error; data_classifier_t existing_classifier; read_error = data_database_reader_get_classifier_by_name ( (*this_).db_reader, data_classifier_get_name_const( &new_classifier ), &existing_classifier ); /* if the name is equal, expect the objects to be equal */ const bool classifier_exists = ( DATA_ERROR_NONE == read_error ); if ( ! classifier_exists ) { ctrl_error_t write_error; write_error = ctrl_classifier_controller_create_classifier( classifier_ctrl, &new_classifier, ( is_first ? CTRL_UNDO_REDO_ACTION_BOUNDARY_START_NEW : CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND ), &the_classifier_id ); data_stat_inc_count ( io_stat, DATA_TABLE_CLASSIFIER, (CTRL_ERROR_NONE==write_error)?DATA_STAT_SERIES_CREATED:DATA_STAT_SERIES_ERROR ); if ( CTRL_ERROR_NONE == write_error ) { /* create also the features */ for ( int f_index = 0; f_index < feature_count; f_index ++ ) { data_feature_t *current_feature = &((*this_).temp_features[f_index]); data_row_id_t new_feature_id; data_feature_set_classifier_row_id( current_feature, the_classifier_id ); /* filter lifelines */ if ( ! data_rules_feature_is_scenario_cond( &((*this_).data_rules), data_feature_get_main_type( current_feature ) ) ) { write_error |= ctrl_classifier_controller_create_feature ( classifier_ctrl, current_feature, CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND, &new_feature_id ); data_stat_inc_count ( io_stat, DATA_TABLE_FEATURE, (CTRL_ERROR_NONE==write_error)?DATA_STAT_SERIES_CREATED:DATA_STAT_SERIES_ERROR ); } else /* lifeline */ { data_stat_inc_count ( io_stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_IGNORED ); TRACE_INFO( "lifeline dropped at json import." ); } } } if ( CTRL_ERROR_NONE != write_error ) { TSLOG_ERROR( "unexpected error at ctrl_classifier_controller_create_classifier/feature" ); any_error = true; } is_first = false; } else { /* do the statistics */ data_stat_inc_count ( io_stat, DATA_TABLE_CLASSIFIER, DATA_STAT_SERIES_IGNORED ); for ( int f_index = 0; f_index < feature_count; f_index ++ ) { data_stat_inc_count ( io_stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_IGNORED ); } TRACE_INFO( "classifier did already exist, features dropped at json import." ); /* set the the_classifier_id */ the_classifier_id = data_classifier_get_row_id( &existing_classifier ); } } if ( ! any_error ) /* no error */ { /* link the classifier to the current diagram */ ctrl_diagram_controller_t *diag_ctrl; diag_ctrl = ctrl_controller_get_diagram_control_ptr( (*this_).controller ); ctrl_error_t write_error2; data_row_id_t new_element_id; data_diagramelement_t diag_ele; data_diagramelement_init_new ( &diag_ele, diagram_id, the_classifier_id, DATA_DIAGRAMELEMENT_FLAG_NONE, DATA_ROW_ID_VOID ); write_error2 = ctrl_diagram_controller_create_diagramelement ( diag_ctrl, &diag_ele, ( is_first ? CTRL_UNDO_REDO_ACTION_BOUNDARY_START_NEW : CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND ), &new_element_id ); data_stat_inc_count ( io_stat, DATA_TABLE_DIAGRAMELEMENT, (CTRL_ERROR_NONE==write_error2)?DATA_STAT_SERIES_CREATED:DATA_STAT_SERIES_ERROR ); if ( CTRL_ERROR_NONE != write_error2 ) { TSLOG_ERROR( "unexpected error at ctrl_diagram_controller_create_diagramelement" ); any_error = true; } is_first = false; } } } break; default: { TSLOG_ERROR( "unexpected token error" ); any_error = true; } } if ( DATA_ERROR_NONE == parse_error ) { parse_error = json_deserializer_expect_end_type_of_element( deserializer ); /* parser error, break loop: */ any_error = ( any_error ||( DATA_ERROR_NONE != parse_error )); } } else { /* parser error, break loop: */ any_error = true; } if ( DATA_ERROR_NONE == parse_error ) { parse_error = json_deserializer_check_end_data( deserializer, &set_end ); /* parser error, break loop: */ any_error = ( any_error ||( DATA_ERROR_NONE != parse_error )); } } } TRACE_END_ERR( parse_error ); return parse_error; } data_error_t json_import_to_database_private_import_edges( json_import_to_database_t *this_, json_deserializer_t *deserializer, data_row_id_t diagram_id, data_stat_t *io_stat ) { TRACE_BEGIN(); assert( NULL != deserializer ); assert( NULL != io_stat ); data_error_t parse_error = DATA_ERROR_NONE; if ( DATA_ERROR_NONE == parse_error ) { parse_error = json_deserializer_expect_begin_data( deserializer ); } if ( DATA_ERROR_NONE == parse_error ) { data_table_t next_object_type; bool set_end = false; /* end of data set reached or error at parsing */ parse_error = json_deserializer_check_end_data( deserializer, &set_end ); bool any_error = ( parse_error != DATA_ERROR_NONE ); /* consolidation of parser errors and writer errors */ bool is_first = true; /* is this the first object in the database that is created? if false, database changes are appended to the last undo_redo_set */ static const uint32_t MAX_LOOP_COUNTER = (CTRL_UNDO_REDO_LIST_MAX_SIZE/2)-2; /* do not import more things than can be undone */ for ( int count = 0; ( ! set_end ) && ( ! any_error ) && ( count < MAX_LOOP_COUNTER ); count ++ ) { parse_error = json_deserializer_expect_begin_type_of_element( deserializer, &next_object_type ); if ( DATA_ERROR_NONE == parse_error ) { switch ( next_object_type ) { case DATA_TABLE_VOID: { /* we are finished */ set_end = true; } break; case DATA_TABLE_RELATIONSHIP: { data_relationship_t new_relationship; char rel_from_clas_buf[DATA_CLASSIFIER_MAX_NAME_SIZE] = ""; utf8stringbuf_t rel_from_clas = UTF8STRINGBUF(rel_from_clas_buf); char rel_from_feat_buf[DATA_FEATURE_MAX_KEY_SIZE] = ""; utf8stringbuf_t rel_from_feat = UTF8STRINGBUF(rel_from_feat_buf); char rel_to_clas_buf[DATA_CLASSIFIER_MAX_NAME_SIZE] = ""; utf8stringbuf_t rel_to_clas = UTF8STRINGBUF(rel_to_clas_buf); char rel_to_feat_buf[DATA_FEATURE_MAX_KEY_SIZE] = ""; utf8stringbuf_t rel_to_feat = UTF8STRINGBUF(rel_to_feat_buf); parse_error = json_deserializer_get_next_relationship ( deserializer, &new_relationship, rel_from_clas, rel_from_feat, rel_to_clas, rel_to_feat ); if ( DATA_ERROR_NONE != parse_error ) { /* parser error, break loop: */ any_error = true; } else { data_row_id_t from_classifier_id = DATA_ROW_ID_VOID; data_row_id_t from_feature_id = DATA_ROW_ID_VOID; data_feature_type_t from_feature_type = DATA_FEATURE_TYPE_VOID; data_row_id_t to_classifier_id = DATA_ROW_ID_VOID; data_row_id_t to_feature_id = DATA_ROW_ID_VOID; data_feature_type_t to_feature_type = DATA_FEATURE_TYPE_VOID; /* determine ids in target database */ { data_error_t read_error2; data_classifier_t found_classifier; /* search source classifier id */ read_error2 = data_database_reader_get_classifier_by_name ( (*this_).db_reader, utf8stringbuf_get_string( rel_from_clas ), &found_classifier ); if ( DATA_ERROR_NONE == read_error2 ) { from_classifier_id = data_classifier_get_row_id( &found_classifier ); TRACE_INFO_STR( "id found for src classifier:", utf8stringbuf_get_string( rel_from_clas ) ); /* search source feature id */ if ( data_relationship_get_from_feature_row_id( &new_relationship ) != DATA_ROW_ID_VOID ) { uint32_t feature_count; read_error2 = data_database_reader_get_features_by_classifier_id ( (*this_).db_reader, from_classifier_id, JSON_IMPORT_TO_DATABASE_MAX_FEATURES, &((*this_).temp_features), &feature_count ); if ( DATA_ERROR_NONE == read_error2 ) { for ( int src_idx=0; src_idx < feature_count; src_idx ++ ) { const data_feature_t *const current_feature = &((*this_).temp_features[src_idx]); const data_row_id_t current_feature_id = data_feature_get_row_id( current_feature ); const char *const current_feature_key = data_feature_get_key_const( current_feature ); const data_feature_type_t current_feature_type = data_feature_get_main_type( current_feature ); if ( utf8stringbuf_equals_str( rel_from_feat, current_feature_key ) ) { if ( data_rules_feature_is_scenario_cond( &((*this_).data_rules), current_feature_type ) ) { /* lifeline is ok if visible in current diagram */ bool visible; visible = json_import_to_database_private_is_feature_focused_in_diagram ( this_, diagram_id, current_feature_id ); if ( visible ) { from_feature_id = current_feature_id; from_feature_type = current_feature_type; TRACE_INFO_STR( "id found for scenario src feature:", utf8stringbuf_get_string( rel_from_feat ) ); } else { /* ignore lifelines of other diagrams */ } } else { from_feature_id = current_feature_id; from_feature_type = current_feature_type; TRACE_INFO_STR( "id found for unconditional src feature:", utf8stringbuf_get_string( rel_from_feat ) ); } } } } } } /* search destination classifier id */ read_error2 = data_database_reader_get_classifier_by_name ( (*this_).db_reader, utf8stringbuf_get_string( rel_to_clas ), &found_classifier ); if ( DATA_ERROR_NONE == read_error2 ) { to_classifier_id = data_classifier_get_row_id( &found_classifier ); TRACE_INFO_STR( "id found for dst classifier:", utf8stringbuf_get_string( rel_to_clas ) ); /* search destination feature id */ if ( data_relationship_get_to_feature_row_id( &new_relationship ) != DATA_ROW_ID_VOID ) { uint32_t feature_count; read_error2 = data_database_reader_get_features_by_classifier_id ( (*this_).db_reader, to_classifier_id, JSON_IMPORT_TO_DATABASE_MAX_FEATURES, &((*this_).temp_features), &feature_count ); if ( DATA_ERROR_NONE == read_error2 ) { for ( int src_idx=0; src_idx < feature_count; src_idx ++ ) { const data_feature_t *const current_feature = &((*this_).temp_features[src_idx]); const data_row_id_t current_feature_id = data_feature_get_row_id( current_feature ); const char *const current_feature_key = data_feature_get_key_const( current_feature ); const data_feature_type_t current_feature_type = data_feature_get_main_type( current_feature ); if ( utf8stringbuf_equals_str( rel_to_feat, current_feature_key ) ) { if ( data_rules_feature_is_scenario_cond( &((*this_).data_rules), current_feature_type ) ) { /* lifeline is ok if visible in current diagram */ bool visible; visible = json_import_to_database_private_is_feature_focused_in_diagram ( this_, diagram_id, current_feature_id ); if ( visible ) { to_feature_id = current_feature_id; to_feature_type = current_feature_type; TRACE_INFO_STR( "id found for scenario dst feature:", utf8stringbuf_get_string( rel_from_feat ) ); } else { /* ignore lifelines of other diagrams */ } } else { to_feature_id = current_feature_id; to_feature_type = current_feature_type; TRACE_INFO_STR( "id found for unconditional dst feature:", utf8stringbuf_get_string( rel_from_feat ) ); } } } } } } } /* create relationship */ bool dropped=false; if ( from_classifier_id == DATA_ROW_ID_VOID ) { TSLOG_ERROR_STR( "A relationship could not be created because the source classifier could not be found.", utf8stringbuf_get_string( rel_from_clas ) ); dropped = true; } else if ( to_classifier_id == DATA_ROW_ID_VOID ) { TSLOG_ERROR_STR( "A relationship could not be created because the destination classifier could not be found.", utf8stringbuf_get_string( rel_to_clas ) ); dropped = true; } else if (( data_relationship_get_from_feature_row_id( &new_relationship ) != DATA_ROW_ID_VOID ) && ( from_feature_id == DATA_ROW_ID_VOID )) { TSLOG_ERROR_STR( "A relationship could not be created because the source feature could not be found.", utf8stringbuf_get_string( rel_from_feat ) ); dropped = true; } else if (( data_relationship_get_to_feature_row_id( &new_relationship ) != DATA_ROW_ID_VOID ) && ( to_feature_id == DATA_ROW_ID_VOID )) { TSLOG_ERROR_STR( "A relationship could not be created because the destination feature could not be found.", utf8stringbuf_get_string( rel_to_feat ) ); dropped = true; } else { ctrl_error_t write_error4; /* get classifier controller */ ctrl_classifier_controller_t *classifier_control4; classifier_control4 = ctrl_controller_get_classifier_control_ptr ( (*this_).controller ); /* update the json-parsed relationship struct */ data_relationship_set_row_id ( &new_relationship, DATA_ROW_ID_VOID ); data_relationship_set_from_classifier_row_id ( &new_relationship, from_classifier_id ); data_relationship_set_from_feature_row_id ( &new_relationship, from_feature_id ); data_relationship_set_to_classifier_row_id ( &new_relationship, to_classifier_id ); data_relationship_set_to_feature_row_id ( &new_relationship, to_feature_id ); /* create relationship */ data_row_id_t relationship_id; write_error4 = ctrl_classifier_controller_create_relationship ( classifier_control4, &new_relationship, ( is_first ? CTRL_UNDO_REDO_ACTION_BOUNDARY_START_NEW : CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND ), &relationship_id ); if ( CTRL_ERROR_NONE != write_error4 ) { TSLOG_ERROR( "unexpected error at ctrl_classifier_controller_create_relationship" ); any_error = true; } is_first = false; } /* cleanup */ data_relationship_destroy ( &new_relationship ); /* update statistics */ data_stat_inc_count ( io_stat, DATA_TABLE_RELATIONSHIP, (!dropped)?DATA_STAT_SERIES_CREATED:DATA_STAT_SERIES_ERROR ); if ( dropped ) { const bool is_scenario = data_rules_relationship_is_scenario_cond ( &((*this_).data_rules), from_feature_type, to_feature_type ); TRACE_INFO( is_scenario ? "relationship in scenario dropped" : "general relationship dropped" ); } } } break; default: { TSLOG_ERROR( "unexpected token error" ); any_error = true; } } if ( DATA_ERROR_NONE == parse_error ) { parse_error = json_deserializer_expect_end_type_of_element( deserializer ); /* parser error, break loop: */ any_error = ( any_error ||( DATA_ERROR_NONE != parse_error )); } } else { /* parser error, break loop: */ any_error = true; } if ( DATA_ERROR_NONE == parse_error ) { parse_error = json_deserializer_check_end_data( deserializer, &set_end ); /* parser error, break loop: */ any_error = ( any_error ||( DATA_ERROR_NONE != parse_error )); } } } TRACE_END_ERR( parse_error ); return parse_error; } /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/json/json_token_reader.c000066400000000000000000000364001415120503000236450ustar00rootroot00000000000000/* File: json_token_reader.c; Copyright and License: see below */ #include "json/json_token_reader.h" #include "stream/universal_escaping_output_stream.h" #include "stream/universal_memory_output_stream.h" #include "trace.h" #include "tslog.h" #include #include static const char *const JSON_TOKENIZER_PRIVATE_DECODE_JSON_STRINGS[][2] = { { "\\t", "\x09" }, /* tab */ { "\\n", "\x0a" }, /* newline */ { "\\r", "\x0d" }, /* return */ { "\\b", "\x08" }, /* backspace */ { "\\f", "\x0c" }, /* form feed */ { "\\\"", "\"" }, /* double quote */ { "\\\\", "\\" }, /* backslash*/ { "\\/", "/" }, /* slash */ { NULL, NULL } /* for JSON, see rfc7159 */ }; void json_token_reader_init ( json_token_reader_t *this_, universal_input_stream_t *in_stream ) { TRACE_BEGIN(); assert( NULL != in_stream ); universal_buffer_input_stream_init( &((*this_).in_stream), &((*this_).input_buffer), sizeof((*this_).input_buffer), in_stream ); (*this_).input_line = 1; /* the first line is 1, not 0 */ TRACE_END(); } void json_token_reader_reinit ( json_token_reader_t *this_, universal_input_stream_t *in_stream ) { TRACE_BEGIN(); assert( NULL != in_stream ); universal_buffer_input_stream_destroy( &((*this_).in_stream) ); universal_buffer_input_stream_init( &((*this_).in_stream), &((*this_).input_buffer), sizeof((*this_).input_buffer), in_stream ); (*this_).input_line = 1; /* the first line is 1, not 0 */ TRACE_END(); } void json_token_reader_destroy ( json_token_reader_t *this_ ) { TRACE_BEGIN(); universal_buffer_input_stream_destroy( &((*this_).in_stream) ); TRACE_END(); } data_error_t json_token_reader_expect_begin_object ( json_token_reader_t *this_ ) { TRACE_BEGIN(); data_error_t result_err = DATA_ERROR_NONE; /* skip whitespace */ json_token_reader_private_skip_whitespace( this_ ); if ( JSON_CONSTANTS_CHAR_BEGIN_OBJECT == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) ) { /* expected token found */ universal_buffer_input_stream_read_next( &((*this_).in_stream) ); } else { /* expected token missing */ result_err = DATA_ERROR_PARSER_STRUCTURE; } TRACE_END_ERR( result_err ); return result_err; } data_error_t json_token_reader_read_member_name ( json_token_reader_t *this_, utf8stringbuf_t out_name ) { TRACE_BEGIN(); data_error_t result_err = DATA_ERROR_NONE; result_err = json_token_reader_read_string_value( this_, out_name ); TRACE_INFO_STR( "member name:", utf8stringbuf_get_string( out_name ) ); TRACE_END_ERR( result_err ); return result_err; } data_error_t json_token_reader_check_end_object ( json_token_reader_t *this_, bool *end_object ) { TRACE_BEGIN(); assert( NULL != end_object ); data_error_t result_err = DATA_ERROR_NONE; /* skip whitespace */ json_token_reader_private_skip_whitespace( this_ ); if ( JSON_CONSTANTS_CHAR_END_OBJECT == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) ) { /* object-end token found */ universal_buffer_input_stream_read_next( &((*this_).in_stream) ); (*end_object) = true; TRACE_INFO( "end object: true" ); } else { /* expected token missing */ (*end_object) = false; } TRACE_END_ERR( result_err ); return result_err; } data_error_t json_token_reader_expect_name_separator ( json_token_reader_t *this_ ) { TRACE_BEGIN(); data_error_t result_err = DATA_ERROR_NONE; /* skip whitespace */ json_token_reader_private_skip_whitespace( this_ ); if ( JSON_CONSTANTS_CHAR_NAME_SEPARATOR == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) ) { /* expected token found */ universal_buffer_input_stream_read_next( &((*this_).in_stream) ); } else { /* expected token missing */ result_err = DATA_ERROR_PARSER_STRUCTURE; } TRACE_END_ERR( result_err ); return result_err; } data_error_t json_token_reader_expect_begin_array ( json_token_reader_t *this_ ) { TRACE_BEGIN(); data_error_t result_err = DATA_ERROR_NONE; /* skip whitespace */ json_token_reader_private_skip_whitespace( this_ ); if ( JSON_CONSTANTS_CHAR_BEGIN_ARRAY == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) ) { /* expected token found */ universal_buffer_input_stream_read_next( &((*this_).in_stream) ); } else { /* expected token missing */ result_err = DATA_ERROR_PARSER_STRUCTURE; } TRACE_END_ERR( result_err ); return result_err; } data_error_t json_token_reader_check_end_array ( json_token_reader_t *this_, bool *end_array ) { TRACE_BEGIN(); assert( NULL != end_array ); data_error_t result_err = DATA_ERROR_NONE; /* skip whitespace */ json_token_reader_private_skip_whitespace( this_ ); if ( JSON_CONSTANTS_CHAR_END_ARRAY == universal_buffer_input_stream_peek_next( &((*this_).in_stream) )) { /* array-end token found */ universal_buffer_input_stream_read_next( &((*this_).in_stream) ); (*end_array) = true; TRACE_INFO( "end array: true" ); } else { /* expected token missing */ (*end_array) = false; } TRACE_END_ERR( result_err ); return result_err; } data_error_t json_token_reader_expect_value_separator ( json_token_reader_t *this_ ) { TRACE_BEGIN(); data_error_t result_err = DATA_ERROR_NONE; /* skip whitespace */ json_token_reader_private_skip_whitespace( this_ ); if ( JSON_CONSTANTS_CHAR_VALUE_SEPARATOR == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) ) { /* expected token found */ universal_buffer_input_stream_read_next( &((*this_).in_stream) ); } else { /* expected token missing */ result_err = DATA_ERROR_PARSER_STRUCTURE; } TRACE_END_ERR( result_err ); return result_err; } data_error_t json_token_reader_get_value_type ( json_token_reader_t *this_, json_value_type_t *value_type ) { TRACE_BEGIN(); assert( NULL != value_type ); data_error_t result_err = DATA_ERROR_NONE; /* skip whitespace */ json_token_reader_private_skip_whitespace( this_ ); /* determine next token */ char current = universal_buffer_input_stream_peek_next( &((*this_).in_stream) ); if ( JSON_CONSTANTS_CHAR_BEGIN_OBJECT == current ) { *value_type = JSON_VALUE_TYPE_OBJECT; } else if ( JSON_CONSTANTS_CHAR_BEGIN_ARRAY == current ) { *value_type = JSON_VALUE_TYPE_ARRAY; } else if ( JSON_CONSTANTS_CHAR_BEGIN_STRING == current ) { *value_type = JSON_VALUE_TYPE_STRING; } else if ( JSON_CONSTANTS_CHAR_BEGIN_FALSE == current ) { *value_type = JSON_VALUE_TYPE_BOOLEAN; } else if ( JSON_CONSTANTS_CHAR_BEGIN_TRUE == current ) { *value_type = JSON_VALUE_TYPE_BOOLEAN; } else if ( JSON_CONSTANTS_CHAR_BEGIN_NULL == current ) { *value_type = JSON_VALUE_TYPE_NULL; } else if ( ( '-' == current ) || (( '0' <= current ) && ( current <= '9')) ) { /* return number even if integer subtype */ *value_type = JSON_VALUE_TYPE_NUMBER; } else { *value_type = JSON_VALUE_TYPE_UNDEF; result_err = DATA_ERROR_PARSER_STRUCTURE; /* this could also be a lexical error (invalid next token) instead of unexpected next token */ } TRACE_END_ERR( result_err ); return result_err; } data_error_t json_token_reader_read_string_value ( json_token_reader_t *this_, utf8stringbuf_t out_value ) { TRACE_BEGIN(); data_error_t result_err = DATA_ERROR_NONE; /* skip whitespace */ json_token_reader_private_skip_whitespace( this_ ); /* expect string begin */ if ( JSON_CONSTANTS_CHAR_BEGIN_STRING == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) ) { /* expected token found */ universal_buffer_input_stream_read_next( &((*this_).in_stream) ); universal_memory_output_stream_t mem_out; universal_memory_output_stream_init( &mem_out, utf8stringbuf_get_string(out_value), utf8stringbuf_get_size(out_value) ); universal_escaping_output_stream_t esc_out; universal_escaping_output_stream_init( &esc_out, &JSON_TOKENIZER_PRIVATE_DECODE_JSON_STRINGS, universal_memory_output_stream_get_output_stream( &mem_out ) ); result_err = json_token_reader_private_read_string( this_, universal_escaping_output_stream_get_output_stream( &esc_out ) ); universal_escaping_output_stream_flush( &esc_out ); universal_escaping_output_stream_destroy( &esc_out ); const int out_err = universal_memory_output_stream_write_0term( &mem_out ); if ( 0 != out_err ) { result_err = DATA_ERROR_STRING_BUFFER_EXCEEDED; } universal_memory_output_stream_destroy( &mem_out ); /* expect string end */ const bool in_err = ( JSON_CONSTANTS_CHAR_END_STRING != universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) ); if ( in_err ) { result_err = DATA_ERROR_LEXICAL_STRUCTURE; } else { universal_buffer_input_stream_read_next( &((*this_).in_stream) ); if ( ! json_token_reader_private_is_value_end( this_ ) ) { result_err = DATA_ERROR_LEXICAL_STRUCTURE; } } } else { /* expected start token missing */ result_err = DATA_ERROR_PARSER_STRUCTURE; } TRACE_END_ERR( result_err ); return result_err; } data_error_t json_token_reader_read_int_value ( json_token_reader_t *this_, int64_t *out_int ) { TRACE_BEGIN(); assert( NULL != out_int ); data_error_t result_err = DATA_ERROR_NONE; /* skip whitespace */ json_token_reader_private_skip_whitespace( this_ ); result_err = json_token_reader_private_parse_integer( this_, out_int ); if ( ! json_token_reader_private_is_value_end( this_ ) ) { result_err = DATA_ERROR_LEXICAL_STRUCTURE; } TRACE_END_ERR( result_err ); return result_err; } data_error_t json_token_reader_read_number_value ( json_token_reader_t *this_, double *out_number ) { TRACE_BEGIN(); assert( NULL != out_number ); data_error_t result_err = DATA_ERROR_NONE; /* skip whitespace */ json_token_reader_private_skip_whitespace( this_ ); result_err = json_token_reader_private_skip_number( this_ ); /* not yet implemented */ if ( ! json_token_reader_private_is_value_end( this_ ) ) { result_err = DATA_ERROR_LEXICAL_STRUCTURE; } else { (*out_number) = 0.0; result_err = DATA_ERROR_NOT_YET_IMPLEMENTED; } TRACE_END_ERR( result_err ); return result_err; } data_error_t json_token_reader_read_boolean_value ( json_token_reader_t *this_, bool *out_bool ) { TRACE_BEGIN(); assert( NULL != out_bool ); data_error_t result_err = DATA_ERROR_NONE; /* skip whitespace */ json_token_reader_private_skip_whitespace( this_ ); char current = universal_buffer_input_stream_peek_next( &((*this_).in_stream) ); if ( JSON_CONSTANTS_CHAR_BEGIN_FALSE == current ) { (*out_bool) = false; for ( int f_pos = 0; f_pos < strlen(JSON_CONSTANTS_FALSE); f_pos ++ ) { if ( JSON_CONSTANTS_FALSE[f_pos] == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) ) { universal_buffer_input_stream_read_next( &((*this_).in_stream) ); } else { result_err = DATA_ERROR_LEXICAL_STRUCTURE; } } if ( ! json_token_reader_private_is_value_end( this_ ) ) { result_err = DATA_ERROR_LEXICAL_STRUCTURE; } } else if ( JSON_CONSTANTS_CHAR_BEGIN_TRUE == current ) { (*out_bool) = true; for ( int t_pos = 0; t_pos < strlen(JSON_CONSTANTS_TRUE); t_pos ++ ) { if ( JSON_CONSTANTS_TRUE[t_pos] == universal_buffer_input_stream_peek_next( &((*this_).in_stream) ) ) { universal_buffer_input_stream_read_next( &((*this_).in_stream) ); } else { result_err = DATA_ERROR_LEXICAL_STRUCTURE; } } if ( ! json_token_reader_private_is_value_end( this_ ) ) { result_err = DATA_ERROR_LEXICAL_STRUCTURE; } } else { result_err = DATA_ERROR_LEXICAL_STRUCTURE; } TRACE_END_ERR( result_err ); return result_err; } data_error_t json_token_reader_expect_null_value ( json_token_reader_t *this_ ) { TRACE_BEGIN(); data_error_t result_err = DATA_ERROR_NONE; /* skip whitespace */ json_token_reader_private_skip_whitespace( this_ ); char current = universal_buffer_input_stream_peek_next( &((*this_).in_stream) ); if ( JSON_CONSTANTS_CHAR_BEGIN_NULL == current ) { for ( int n_pos = 0; n_pos < strlen(JSON_CONSTANTS_NULL); n_pos ++ ) { if ( JSON_CONSTANTS_NULL[n_pos] != universal_buffer_input_stream_read_next( &((*this_).in_stream) ) ) { result_err = DATA_ERROR_LEXICAL_STRUCTURE; } } if ( ! json_token_reader_private_is_value_end( this_ ) ) { result_err = DATA_ERROR_LEXICAL_STRUCTURE; } } else { result_err = DATA_ERROR_PARSER_STRUCTURE; } TRACE_END_ERR( result_err ); return result_err; } data_error_t json_token_reader_expect_eof ( json_token_reader_t *this_ ) { TRACE_BEGIN(); data_error_t result_err = DATA_ERROR_NONE; /* skip whitespace */ json_token_reader_private_skip_whitespace( this_ ); char eof = universal_buffer_input_stream_peek_next( &((*this_).in_stream) ); if ( '\0' == eof ) { /* expected token found */ } else { /* expected token missing */ result_err = DATA_ERROR_PARSER_STRUCTURE; } TRACE_END_ERR( result_err ); return result_err; } /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/json/json_writer.c000066400000000000000000000077601415120503000225260ustar00rootroot00000000000000/* File: json_writer.c; Copyright and License: see below */ #include "json/json_writer.h" #include "data_id.h" #include "trace.h" #include "tslog.h" #include #include #include static const char * const JSON_WRITER_PRIVATE_ENCODE_JSON_STRINGS[][2] = { { "\x09", "\\t" }, /* tab */ { "\x0a", "\\n" }, /* newline */ { "\x0d", "\\r" }, /* return */ { "\x08", "\\b" }, /* backspace */ { "\x0c", "\\f" }, /* form feed */ { "\"", "\\\"" }, /* double quote */ { "\\", "\\\\" }, /* backslash*/ { "/", "\\/" }, /* slash */ { NULL, NULL } /* for JSON, see rfc7159 */ }; static const char * const JSON_WRITER_PRIVATE_ENCODE_JSON_STRING_ARRAYS[][2] = { { "\x09", "\\t" }, /* tab */ { "\x0a", "\\n\",\n \"" }, /* newline */ { "\x0d", "\\r" }, /* return */ { "\x08", "\\b" }, /* backspace */ { "\x0c", "\\f" }, /* form feed */ { "\"", "\\\"" }, /* double quote */ { "\\", "\\\\" }, /* backslash*/ { "/", "\\/" }, /* slash */ { NULL, NULL } /* for JSON, see rfc7159 */ }; const char JSON_CONSTANTS_INDENT[(2*JSON_WRITER_MAX_INDENT)+sizeof('\0')] = JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB; const char JSON_CONSTANTS_INDENT_QUOTE[(2*JSON_WRITER_MAX_INDENT)+sizeof(JSON_CONSTANTS_QUOTE)] = JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_TAB JSON_CONSTANTS_QUOTE; void json_writer_init ( json_writer_t *this_, universal_output_stream_t *output ) { TRACE_BEGIN(); assert( NULL != output ); (*this_).output = output; universal_escaping_output_stream_init( &((*this_).esc_output), &JSON_WRITER_PRIVATE_ENCODE_JSON_STRINGS, output ); (*this_).json_string_encode_table = &JSON_WRITER_PRIVATE_ENCODE_JSON_STRINGS; (*this_).json_stringlist_encode_table = &JSON_WRITER_PRIVATE_ENCODE_JSON_STRING_ARRAYS; TRACE_END(); } void json_writer_destroy( json_writer_t *this_ ) { TRACE_BEGIN(); universal_escaping_output_stream_destroy( &((*this_).esc_output) ); (*this_).output = NULL; TRACE_END(); } int json_writer_write_plain_id ( json_writer_t *this_, data_id_t id ) { TRACE_BEGIN(); assert( DATA_TABLE_VOID != data_id_get_table(&id) ); assert( DATA_ROW_ID_VOID != data_id_get_row_id(&id) ); int result = 0; /* print id */ { char id_buf[DATA_ID_MAX_UTF8STRING_SIZE]; utf8stringbuf_t id_str = UTF8STRINGBUF( id_buf ); utf8stringbuf_clear( id_str ); data_id_to_utf8stringbuf( &id, id_str ); const unsigned int len = utf8stringbuf_get_length(id_str); universal_escaping_output_stream_change_rules( &((*this_).esc_output), (*this_).json_string_encode_table ); result = universal_escaping_output_stream_write( &((*this_).esc_output), utf8stringbuf_get_string(id_str), len ); } TRACE_END_ERR( result ); return result; } int json_writer_write_int ( json_writer_t *this_, int64_t number ) { TRACE_BEGIN(); char numberStr[21]; /* this is sufficient for signed 64 bit integers: -9223372036854775806 */ int result = 0; /* Note: snprintf is not available on every OS */ sprintf( numberStr, "%" PRIi64, number ); result = json_writer_write_plain( this_, &(numberStr[0]) ); TRACE_END_ERR( result ); return result; } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/md/000077500000000000000000000000001415120503000174325ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/source/md/md_filter.c000066400000000000000000000172061415120503000215510ustar00rootroot00000000000000/* File: md_filter.c; Copyright and License: see below */ #include "md/md_filter.h" #include "util/string/utf8stringview.h" #include "trace.h" #include "tslog.h" #include #include #include /* Note, this is no full markdown syntax support - but it helps keeping markdown in shape */ static const char MD_FILTER_LINEBREAK = '\n'; static const char MD_FILTER_LINK_AS_ID[] = "#id"; static const char MD_FILTER_LINK_AS_NAME[] = "#name"; void md_filter_init ( md_filter_t *this_, data_database_reader_t *db_reader, const char * tag_linebreak, const char * tag_xref_start, const char * tag_xref_middle, const char * tag_xref_end, xml_writer_t *sink ) { TRACE_BEGIN(); assert( NULL != db_reader ); assert( NULL != tag_linebreak ); assert( NULL != tag_xref_start ); assert( NULL != tag_xref_middle ); assert( NULL != tag_xref_end ); assert( NULL != sink ); (*this_).db_reader = db_reader; (*this_).tag_linebreak = tag_linebreak; (*this_).tag_xref_start = tag_xref_start; (*this_).tag_xref_middle = tag_xref_middle; (*this_).tag_xref_end = tag_xref_end; (*this_).sink = sink; TRACE_END(); } void md_filter_destroy( md_filter_t *this_ ) { TRACE_BEGIN(); (*this_).sink = NULL; (*this_).db_reader = NULL; TRACE_END(); } int md_filter_transform ( md_filter_t *this_, const char *text ) { TRACE_BEGIN(); assert ( NULL != text ); assert ( NULL != (*this_).db_reader ); assert ( NULL != (*this_).sink ); unsigned int text_start_byte = 0; const unsigned int text_byte_length = utf8string_get_length( text ); int write_err = 0; for ( unsigned int text_current_byte = 0; text_current_byte < text_byte_length; text_current_byte ++ ) { const char current = text[text_current_byte]; /* note: only in case current<=0x7f this is a valid code point */ const char peeknext = text[text_current_byte+1]; /* note: only in case current<=0x7f this is a valid code point, 0 at string end */ if ( current == MD_FILTER_LINEBREAK ) { if (( peeknext == MD_FILTER_LINEBREAK ) || ( peeknext == '+' ) /* list */ || ( peeknext == '*' ) /* list */ || ( peeknext == '-' ) /* list or heading */ || ( peeknext == '=' ) /* heading */ || ( peeknext == '#' ) /* heading */ || ( peeknext == '0' ) /* ordered list */ || ( peeknext == '1' ) /* ordered list */ || ( peeknext == '2' ) /* ordered list */ || ( peeknext == '3' ) /* ordered list */ || ( peeknext == '4' ) /* ordered list */ || ( peeknext == '5' ) /* ordered list */ || ( peeknext == '6' ) /* ordered list */ || ( peeknext == '7' ) /* ordered list */ || ( peeknext == '8' ) /* ordered list */ || ( peeknext == '9' ) /* ordered list */ || ( peeknext == '>' ) /* citation */ /*|| ( peeknext == ' ' )*/ /* list continuation */ || ( peeknext == '|' )) /* table */ { utf8stringview_t str_view = utf8stringview_init( &(text[text_start_byte]), text_current_byte-text_start_byte ); write_err |= xml_writer_write_xml_enc_view( (*this_).sink, str_view ); write_err |= xml_writer_write_plain ( (*this_).sink, (*this_).tag_linebreak ); text_start_byte = text_current_byte+1; } } else if ( current == DATA_TABLE_ALPHANUM_DIAGRAM /* = 'D' */) { /* try to parse an id */ data_id_t probe_id; size_t length; data_id_init_by_string_region ( &probe_id, text, text_current_byte, &length ); if ( data_id_is_valid( &probe_id ) ) { const bool show_id = utf8string_equals_region_str( text, text_current_byte+length, MD_FILTER_LINK_AS_ID ); const bool show_name = show_id ? false : utf8string_equals_region_str( text, text_current_byte+length, MD_FILTER_LINK_AS_NAME ); if ( show_id || show_name ) { data_error_t d_err; d_err = data_database_reader_get_diagram_by_id ( (*this_).db_reader, data_id_get_row_id( &probe_id ), &((*this_).temp_diagram) ); if ( d_err == DATA_ERROR_NONE ) { /* write previously parsed characters */ utf8stringview_t str_view = utf8stringview_init( &(text[text_start_byte]), text_current_byte-text_start_byte ); write_err |= xml_writer_write_xml_enc_view( (*this_).sink, str_view ); char probe_id_str_buf[DATA_ID_MAX_UTF8STRING_SIZE] = ""; utf8stringbuf_t probe_id_str = UTF8STRINGBUF( probe_id_str_buf ); write_err |= data_id_to_utf8stringbuf ( &probe_id, probe_id_str ); write_err |= xml_writer_write_plain ( (*this_).sink, (*this_).tag_xref_start ); write_err |= xml_writer_write_xml_enc( (*this_).sink, utf8stringbuf_get_string( probe_id_str ) ); write_err |= xml_writer_write_plain ( (*this_).sink, (*this_).tag_xref_middle ); text_start_byte = text_current_byte; if ( show_id ) { write_err |= xml_writer_write_xml_enc( (*this_).sink, utf8stringbuf_get_string( probe_id_str ) ); text_current_byte += length + sizeof(MD_FILTER_LINK_AS_ID)-1 - 1; } else /* show_name */ { write_err |= xml_writer_write_xml_enc( (*this_).sink, data_diagram_get_name_const( &((*this_).temp_diagram) ) ); text_current_byte += length + sizeof(MD_FILTER_LINK_AS_NAME)-1 - 1; } write_err |= xml_writer_write_plain ( (*this_).sink, (*this_).tag_xref_end ); text_start_byte = text_current_byte+1; /* destroy the diagram */ data_diagram_destroy( &((*this_).temp_diagram) ); } else { TRACE_INFO_INT("id found but diagram does not exist: D", data_id_get_row_id( &probe_id ) ); } } else { TRACE_INFO_INT("id found but #id or #name fragment missing: D", data_id_get_row_id( &probe_id ) ); } } } if ( text_current_byte+1 == text_byte_length ) { write_err |= xml_writer_write_xml_enc( (*this_).sink, &(text[text_start_byte]) ); } } TRACE_END_ERR( write_err ); return write_err; } /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/txt/000077500000000000000000000000001415120503000176515ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/source/txt/txt_writer.c000066400000000000000000000130211415120503000222250ustar00rootroot00000000000000/* File: txt_writer.c; Copyright and License: see below */ #include "txt/txt_writer.h" #include "trace.h" #include "tslog.h" #include #include #include enum txt_writer_indent_enum { TXT_WRITER_INDENT_COLUMN = 48, /*!< the text column in which the id starts */ }; static const char TXT_ID_INDENT_SPACES[TXT_WRITER_INDENT_COLUMN+1] = " "; static const char TXT_NEWLINE[] = "\n"; void txt_writer_init ( txt_writer_t *this_, universal_output_stream_t *output ) { TRACE_BEGIN(); assert( NULL != output ); (*this_).output = output; TRACE_END(); } void txt_writer_destroy( txt_writer_t *this_ ) { TRACE_BEGIN(); (*this_).output = NULL; TRACE_END(); } int txt_writer_write_indent_multiline_string ( txt_writer_t *this_, const char *indent, const char *multiline_string ) { TRACE_BEGIN(); assert( NULL != indent ); assert( NULL != (*this_).output ); int result = 0; const size_t indent_length = strlen( indent ); if ( NULL != multiline_string ) { const char *line_start = multiline_string; size_t line_length = 0; bool ignore_newline = false; /* newlines after returns are ignored */ size_t length = strlen( multiline_string ); for ( size_t index = 0; index < length; index ++ ) { bool end_of_line = false; char current = multiline_string[index]; if ( '\r' == current ) { ignore_newline = true; end_of_line = true; } else if ( '\n' == current ) { if ( ignore_newline ) { line_start = &(multiline_string[index+1]); } else { end_of_line = true; } ignore_newline = false; } else { ignore_newline = false; line_length ++; if ( index+1 == length ) { end_of_line = true; } } if ( end_of_line ) { /* print indent pattern */ result |= universal_output_stream_write ( (*this_).output, indent, indent_length ); /* print next line */ result |= universal_output_stream_write ( (*this_).output, line_start, line_length ); /* print newline */ result |= universal_output_stream_write ( (*this_).output, TXT_NEWLINE, strlen(TXT_NEWLINE) ); /* reset line indices */ line_start = &(multiline_string[index+1]); line_length = 0; } } } TRACE_END_ERR( result ); return result; } int txt_writer_write_indent_id ( txt_writer_t *this_, int indent_width, data_id_t id ) { TRACE_BEGIN(); assert( DATA_TABLE_VOID != data_id_get_table(&id) ); assert( DATA_ROW_ID_VOID != data_id_get_row_id(&id) ); assert( NULL != (*this_).output ); assert( sizeof(TXT_ID_INDENT_SPACES) == 1+TXT_WRITER_INDENT_COLUMN ); int result = 0; /* indent */ if ( indent_width > TXT_WRITER_INDENT_COLUMN ) { TSLOG_ERROR_INT( "more spaces requested than available. missing:", indent_width - TXT_WRITER_INDENT_COLUMN ); indent_width = TXT_WRITER_INDENT_COLUMN; } if ( indent_width > 0 ) { result |= universal_output_stream_write( (*this_).output, &TXT_ID_INDENT_SPACES, indent_width ); } /* print id */ { char id_buf[DATA_ID_MAX_UTF8STRING_SIZE+2]; utf8stringbuf_t id_str = UTF8STRINGBUF( id_buf ); utf8stringbuf_clear( id_str ); utf8stringbuf_append_str( id_str, " [" ); data_id_to_utf8stringbuf( &id, id_str ); utf8stringbuf_append_str( id_str, "]" ); const unsigned int len = utf8stringbuf_get_length(id_str); result |= universal_output_stream_write( (*this_).output, utf8stringbuf_get_string(id_str), len ); } TRACE_END_ERR( result ); return result; } int txt_writer_write_plain_id ( txt_writer_t *this_, data_id_t id ) { TRACE_BEGIN(); assert( DATA_TABLE_VOID != data_id_get_table(&id) ); assert( DATA_ROW_ID_VOID != data_id_get_row_id(&id) ); assert( NULL != (*this_).output ); int result = 0; /* print id */ { char id_buf[DATA_ID_MAX_UTF8STRING_SIZE]; utf8stringbuf_t id_str = UTF8STRINGBUF( id_buf ); utf8stringbuf_clear( id_str ); data_id_to_utf8stringbuf( &id, id_str ); const unsigned int len = utf8stringbuf_get_length(id_str); result |= universal_output_stream_write ( (*this_).output, utf8stringbuf_get_string(id_str), len ); } TRACE_END_ERR( result ); return result; } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/xhtml/000077500000000000000000000000001415120503000201665ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/source/xhtml/xhtml_element_writer.c000066400000000000000000001502311415120503000245750ustar00rootroot00000000000000/* File: xhtml_element_writer.c; Copyright and License: see below */ #include "xhtml/xhtml_element_writer.h" #include "util/string/utf8string.h" #include "data_id.h" #include "trace.h" #include "tslog.h" #include #include #include /* GENERAL STRUCTURE */ /* * _START * _MIDDLE #optional, if dynamic content needs to be added to the start * _TITLE_START #alternative to TITLE: NAME * _TITLE_END #alternative to TITLE: NAME * ... #optional text * __START #optional if there ore other sub-things * __END #optional if there ore other sub-things * _END */ /* IO_FILE_FORMAT_DOCBOOK */ static const char DOCBOOK_ENC[] = ""; static const char DOCBOOK_DOC_START[] = "\n"; static const char DOCBOOK_DOC_TITLE_START[] = "\n"; static const char DOCBOOK_DOC_TITLE_END[] = ""; static const char DOCBOOK_DOC_END[] = "\n\n"; static const char DOCBOOK_TOP_DIAGRAM_START[] = "\n"; static const char DOCBOOK_TOP_DIAGRAM_END[] = "\n"; static const char DOCBOOK_DIAGRAM_START[] = "\n
"; static const char DOCBOOK_DIAGRAM_TITLE_START[] = "\n"; static const char DOCBOOK_DIAGRAM_TITLE_END[] = ""; static const char DOCBOOK_DIAGRAM_IMG_START[] = "\n" "\n " "\n " "\n " "\n " "\n"; static const char DOCBOOK_DIAGRAM_END[] = "\n
"; static const char DOCBOOK_DESCRIPTION_START[] = "\n"; static const char DOCBOOK_DESCRIPTION_MIDDLE[] /* optional */ = "\n" "\n"; static const char DOCBOOK_DESCRIPTION_XREF_START[] = ": "; static const char DOCBOOK_DESCRIPTION_XREF_END[] = ""; static const char DOCBOOK_DESCRIPTION_END[] = "\n"; static const char DOCBOOK_ELEMENT_LIST_START[] = "\n"; static const char DOCBOOK_ELEMENT_START[] = "\n"; static const char DOCBOOK_ELEMENT_NAME_START[] = "\n"; static const char DOCBOOK_ELEMENT_NAME_END[] = ""; static const char DOCBOOK_ELEMENT_ID_START[] = "\n" "\n "; static const char DOCBOOK_ELEMENT_ID_END[] = ""; static const char DOCBOOK_ELEMENT_DESCR_START[] /* optional */ = "\n"; static const char DOCBOOK_ELEMENT_DESCR_END[] /* optional */ = "\n"; static const char DOCBOOK_ELEMENT_END[] = "\n " "\n"; static const char DOCBOOK_ELEMENT_LIST_END[] = "\n"; /* IO_FILE_FORMAT_XHTML */ enum XHTML_DIAGRAM_MAX { XHTML_DIAGRAM_MAX_DEPTH = 6, }; static const char XHTML_ENC[] = ""; static const char XHTML_DTD[] = "\n"; static const char XHTML_DOC_START[] = "\n"; static const char XHTML_HEAD_START[] = "\n" "\n "; static const char XHTML_HEAD_TITLE_START[] = "\n"; static const char XHTML_HEAD_TITLE_END[] = ""; static const char XHTML_HEAD_CSS_START[] = "\n"; static const char XHTML_HEAD_END[] = "\n"; static const char XHTML_BODY_START[] = "\n"; static const char XHTML_BODY_END[] = "\n"; static const char XHTML_DOC_END[] = "\n\n"; static const char XHTML_TOC_SUBLIST_START[] = "\n
"; static const char XHTML_DIAGRAM_START[] = "\n
"; static const char *XHTML_DIAGRAM_TITLE_START[XHTML_DIAGRAM_MAX_DEPTH] = { "\n

", "\n

", "\n

", "\n

", "\n

", "\n
" }; static const char *XHTML_DIAGRAM_TITLE_END[XHTML_DIAGRAM_MAX_DEPTH] = { "
", "", "", "", "", "" }; static const char XHTML_DIAGRAM_IMG_START[] = "\n
\"\"
"; static const char XHTML_DIAGRAM_END[] = "\n
"; static const char XHTML_DESCRIPTION_START[] = "\n

"; static const char XHTML_DESCRIPTION_MIDDLE[] /* optional */ = "\n
\n"; static const char XHTML_DESCRIPTION_XREF_START[] = ""; static const char XHTML_DESCRIPTION_XREF_END[] = ""; static const char XHTML_DESCRIPTION_END[] = "\n

"; static const char XHTML_ELEMENT_LIST_START[] = "\n
"; static const char XHTML_ELEMENT_START[] = "\n

"; static const char XHTML_ELEMENT_NAME_START[] = "\n"; static const char XHTML_ELEMENT_NAME_END[] = ""; static const char XHTML_ELEMENT_ID_START[] = "\n"; static const char XHTML_ELEMENT_ID_END[] = ""; static const char XHTML_ELEMENT_DESCR_START[] /* optional */ = "\n

" "\n

\n"; static const char XHTML_ELEMENT_DESCR_END[] /* optional */ = "\n"; static const char XHTML_ELEMENT_END[] = "\n

"; static const char XHTML_ELEMENT_LIST_END[] = "\n
"; /* IO_FILE_FORMAT_TXT */ static const int TXT_ID_INDENT_COLUMN = 48; static const char TXT_NEWLINE[] = "\n"; static const char TXT_SINGLE_INDENT[] = "| "; static const char TXT_DOUBLE_INDENT[] = " | "; static const char TXT_SPACE_INDENT[] = " "; static const char TXT_COLON_SPACE[] = ": "; static const char TXT_ARROW_SPACE[] = "--> "; static const char TXT_SPACE_ARROW_SPACE[] = " --> "; /* define a struct where the function pointers have the exact right signatures to avoid typecasts */ #define io_element_writer_impl_t xhtml_element_writer_t struct xhtml_element_writer_io_element_writer_if_struct { #include "io_element_writer_if.inl" }; #undef io_element_writer_impl_t /* the vmt implementing the interface */ static const struct xhtml_element_writer_io_element_writer_if_struct xhtml_element_writer_private_io_element_writer_if = { .write_header = &xhtml_element_writer_write_header, .start_main = &xhtml_element_writer_start_main, .can_classifier_nest_classifier = &xhtml_element_writer_can_classifier_nest_classifier, .can_classifier_nest_relationship = &xhtml_element_writer_can_classifier_nest_relationship, .start_classifier = &xhtml_element_writer_start_classifier, .assemble_classifier = &xhtml_element_writer_assemble_classifier, .end_classifier = &xhtml_element_writer_end_classifier, .start_feature = &xhtml_element_writer_start_feature, .assemble_feature = &xhtml_element_writer_assemble_feature, .end_feature = &xhtml_element_writer_end_feature, .start_relationship = &xhtml_element_writer_start_relationship, .assemble_relationship = &xhtml_element_writer_assemble_relationship, .end_relationship = &xhtml_element_writer_end_relationship, .start_diagram = &xhtml_element_writer_start_diagram, .assemble_diagram = &xhtml_element_writer_assemble_diagram, .end_diagram = &xhtml_element_writer_end_diagram, .start_diagramelement = &xhtml_element_writer_start_diagramelement, .assemble_diagramelement = &xhtml_element_writer_assemble_diagramelement, .end_diagramelement = &xhtml_element_writer_end_diagramelement, .end_main = &xhtml_element_writer_end_main, .write_footer = &xhtml_element_writer_write_footer }; void xhtml_element_writer_init ( xhtml_element_writer_t *this_, data_database_reader_t *db_reader, io_file_format_t export_type, data_stat_t *io_export_stat, universal_output_stream_t *output ) { TRACE_BEGIN(); assert( NULL != output ); assert( NULL != io_export_stat ); assert( NULL != db_reader ); io_element_writer_private_init( &((*this_).element_writer), (io_element_writer_if_t*) &xhtml_element_writer_private_io_element_writer_if, this_ ); (*this_).export_stat = io_export_stat; (*this_).export_type = export_type; (*this_).current_tree_depth = 0; txt_writer_init( &((*this_).txt_writer), output ); xml_writer_init( &((*this_).xml_writer), output ); switch ( (*this_).export_type ) { case IO_FILE_FORMAT_DOCBOOK: { md_filter_init( &((*this_).md_filter), db_reader, DOCBOOK_DESCRIPTION_MIDDLE, DOCBOOK_DESCRIPTION_XREF_START, DOCBOOK_DESCRIPTION_XREF_MIDDLE, DOCBOOK_DESCRIPTION_XREF_END, &((*this_).xml_writer) ); } break; case IO_FILE_FORMAT_XHTML: { md_filter_init( &((*this_).md_filter), db_reader, XHTML_DESCRIPTION_MIDDLE, XHTML_DESCRIPTION_XREF_START, XHTML_DESCRIPTION_XREF_MIDDLE, XHTML_DESCRIPTION_XREF_END, &((*this_).xml_writer) ); } break; default: { md_filter_init( &((*this_).md_filter), db_reader, "\n", "", ": ", "", &((*this_).xml_writer) ); } break; } TRACE_END(); } void xhtml_element_writer_destroy( xhtml_element_writer_t *this_ ) { TRACE_BEGIN(); md_filter_destroy( &((*this_).md_filter) ); xml_writer_destroy( &((*this_).xml_writer) ); txt_writer_destroy( &((*this_).txt_writer) ); (*this_).export_stat = NULL; io_element_writer_private_destroy( &((*this_).element_writer) ); TRACE_END(); } io_element_writer_t * xhtml_element_writer_get_element_writer( xhtml_element_writer_t *this_ ) { TRACE_BEGIN(); io_element_writer_t * base = &((*this_).element_writer); TRACE_END(); return base; } int xhtml_element_writer_write_header( xhtml_element_writer_t *this_, const char *document_title ) { TRACE_BEGIN(); assert ( NULL != document_title ); int export_err = 0; xml_writer_reset_indent ( &((*this_).xml_writer) ); switch ( (*this_).export_type ) { case IO_FILE_FORMAT_DOCBOOK: { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ENC ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_DOC_START ); xml_writer_increase_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_DOC_TITLE_START ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), document_title ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_DOC_TITLE_END ); } break; case IO_FILE_FORMAT_XMI2: { assert(false); /* use the xmi_element_writer instead */ } break; case IO_FILE_FORMAT_XHTML: { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ENC ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_DTD ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_DOC_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_HEAD_START ); xml_writer_increase_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_HEAD_TITLE_START ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), document_title ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_HEAD_TITLE_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_HEAD_CSS_START ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), document_title ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_HEAD_CSS_END ); xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_HEAD_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_BODY_START ); xml_writer_increase_indent ( &((*this_).xml_writer) ); } break; case IO_FILE_FORMAT_TXT: { /* no header */ } break; default: { TSLOG_ERROR("error: unknown_format."); export_err = -1; } break; } TRACE_END_ERR( export_err ); return export_err; } int xhtml_element_writer_start_main( xhtml_element_writer_t *this_, const char *document_title ) { TRACE_BEGIN(); assert( document_title != NULL ); int write_error = 0; TRACE_END_ERR(write_error); return write_error; } bool xhtml_element_writer_can_classifier_nest_classifier( xhtml_element_writer_t *this_, data_classifier_type_t host_type, data_classifier_type_t child_type ) { TRACE_BEGIN(); const bool can_nest = false; TRACE_END(); return can_nest; } bool xhtml_element_writer_can_classifier_nest_relationship( xhtml_element_writer_t *this_, data_classifier_type_t host_type, data_relationship_type_t child_type ) { TRACE_BEGIN(); const bool can_nest = true; TRACE_END(); return can_nest; } int xhtml_element_writer_start_toc_sublist ( xhtml_element_writer_t *this_ ) { TRACE_BEGIN(); int export_err = 0; /* increase tree depth */ (*this_).current_tree_depth ++; switch ( (*this_).export_type ) { case IO_FILE_FORMAT_XHTML: { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_TOC_SUBLIST_START ); xml_writer_increase_indent ( &((*this_).xml_writer) ); } break; default: { /* nothing to do, only xhtml provides a table of contents */ } break; } TRACE_END_ERR( export_err ); return export_err; } int xhtml_element_writer_start_toc_entry ( xhtml_element_writer_t *this_ ) { TRACE_BEGIN(); int export_err = 0; switch ( (*this_).export_type ) { case IO_FILE_FORMAT_XHTML: { const unsigned int index_of_depth = ((*this_).current_tree_depth > XHTML_DIAGRAM_MAX_DEPTH) ? (XHTML_DIAGRAM_MAX_DEPTH-1) : ((*this_).current_tree_depth-1); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_TOC_SUBLIST_ENTRY_START[index_of_depth] ); xml_writer_increase_indent ( &((*this_).xml_writer) ); } break; default: { /* nothing to do, only xhtml provides a table of contents */ } break; } TRACE_END_ERR( export_err ); return export_err; } int xhtml_element_writer_write_toc_entry ( xhtml_element_writer_t *this_, const data_diagram_t *diag_ptr ) { TRACE_BEGIN(); assert ( NULL != diag_ptr ); int export_err = 0; switch ( (*this_).export_type ) { case IO_FILE_FORMAT_XHTML: { const char *const diag_name = data_diagram_get_name_const(diag_ptr); const data_id_t diag_id = data_diagram_get_data_id(diag_ptr); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_TOC_SUBLIST_ENTRY_TITLE_START ); export_err |= xml_writer_write_plain_id ( &((*this_).xml_writer), diag_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_TOC_SUBLIST_ENTRY_TITLE_MIDDLE ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), diag_name ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_TOC_SUBLIST_ENTRY_TITLE_END ); } break; default: { /* nothing to do, only xhtml provides a table of contents */ } break; } TRACE_END_ERR( export_err ); return export_err; } int xhtml_element_writer_end_toc_entry ( xhtml_element_writer_t *this_ ) { TRACE_BEGIN(); int export_err = 0; switch ( (*this_).export_type ) { case IO_FILE_FORMAT_XHTML: { xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_TOC_SUBLIST_ENTRY_END ); } break; default: { /* nothing to do, only xhtml provides a table of contents */ } break; } TRACE_END_ERR( export_err ); return export_err; } int xhtml_element_writer_end_toc_sublist ( xhtml_element_writer_t *this_ ) { TRACE_BEGIN(); int export_err = 0; switch ( (*this_).export_type ) { case IO_FILE_FORMAT_XHTML: { xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_TOC_SUBLIST_END ); } break; default: { /* nothing to do, only xhtml provides a table of contents */ } break; } /* decrease tree depth */ (*this_).current_tree_depth --; TRACE_END_ERR( export_err ); return export_err; } int xhtml_element_writer_start_classifier( xhtml_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ) { TRACE_BEGIN(); assert ( NULL != classifier_ptr ); int export_err = 0; switch ( (*this_).export_type ) { case IO_FILE_FORMAT_DOCBOOK: { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_DESCRIPTION_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_LIST_START ); xml_writer_increase_indent ( &((*this_).xml_writer) ); } break; case IO_FILE_FORMAT_XMI2: { assert(false); /* use the xmi_element_writer instead */ } break; case IO_FILE_FORMAT_XHTML: { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_LIST_START ); } break; case IO_FILE_FORMAT_TXT: { export_err |= txt_writer_write_plain ( &((*this_).txt_writer), TXT_NEWLINE ); } break; default: { TSLOG_ERROR("error: unknown_format."); export_err = -1; } break; } TRACE_END_ERR( export_err ); return export_err; } int xhtml_element_writer_assemble_classifier( xhtml_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ) { TRACE_BEGIN(); assert ( NULL != classifier_ptr ); int export_err = 0; const char *const classifier_name = data_classifier_get_name_const(classifier_ptr); const char *const classifier_descr = data_classifier_get_description_const(classifier_ptr); const size_t classifier_descr_len = utf8string_get_length(classifier_descr); const data_id_t classifier_id = data_classifier_get_data_id(classifier_ptr); switch ( (*this_).export_type ) { case IO_FILE_FORMAT_DOCBOOK: { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_START ); xml_writer_increase_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_NAME_START ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), classifier_name ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_NAME_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_ID_START ); export_err |= xml_writer_write_plain_id( &((*this_).xml_writer), classifier_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_ID_END ); if ( 0 != classifier_descr_len ) { xml_writer_increase_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_DESCR_START ); export_err |= md_filter_transform ( &((*this_).md_filter), classifier_descr ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_DESCR_END ); xml_writer_decrease_indent ( &((*this_).xml_writer) ); } xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_END ); } break; case IO_FILE_FORMAT_XMI2: { assert(false); /* use the xmi_element_writer instead */ } break; case IO_FILE_FORMAT_XHTML: { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_NAME_START ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), classifier_name ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_NAME_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_ID_START ); export_err |= xml_writer_write_plain_id( &((*this_).xml_writer), classifier_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_ID_END ); if ( 0 != classifier_descr_len ) { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_DESCR_START ); export_err |= md_filter_transform ( &((*this_).md_filter), classifier_descr ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_DESCR_END ); } export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_END ); } break; case IO_FILE_FORMAT_TXT: { export_err |= txt_writer_write_plain ( &((*this_).txt_writer), TXT_NEWLINE ); export_err |= txt_writer_write_plain ( &((*this_).txt_writer), classifier_name ); export_err |= txt_writer_write_indent_id( &((*this_).txt_writer), TXT_ID_INDENT_COLUMN - utf8string_get_length(classifier_name), classifier_id ); export_err |= txt_writer_write_plain ( &((*this_).txt_writer), TXT_NEWLINE ); export_err |= txt_writer_write_indent_multiline_string( &((*this_).txt_writer), TXT_SINGLE_INDENT, classifier_descr ); } break; default: { TSLOG_ERROR("error: unknown_format."); export_err = -1; } break; } /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_CLASSIFIER, DATA_STAT_SERIES_EXPORTED ); TRACE_END_ERR( export_err ); return export_err; } int xhtml_element_writer_end_classifier( xhtml_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ) { TRACE_BEGIN(); assert ( NULL != classifier_ptr ); int export_err = 0; switch ( (*this_).export_type ) { case IO_FILE_FORMAT_DOCBOOK: { xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_LIST_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_DESCRIPTION_END ); } break; case IO_FILE_FORMAT_XMI2: { assert(false); /* use the xmi_element_writer instead */ } break; case IO_FILE_FORMAT_XHTML: { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_LIST_END ); } break; case IO_FILE_FORMAT_TXT: { /* no end classifier tags */ } break; default: { TSLOG_ERROR("error: unknown_format."); export_err = -1; } break; } TRACE_END_ERR( export_err ); return export_err; } int xhtml_element_writer_start_feature( xhtml_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr) { TRACE_BEGIN(); assert( feature_ptr != NULL ); int write_error = 0; TRACE_END_ERR(write_error); return write_error; } int xhtml_element_writer_assemble_feature( xhtml_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ) { TRACE_BEGIN(); assert ( NULL != feature_ptr ); int export_err = 0; const char *const feature_key = data_feature_get_key_const( feature_ptr ); const char *const feature_value = data_feature_get_value_const( feature_ptr ); const size_t feature_value_len = utf8string_get_length(feature_value); const char *const feature_descr = data_feature_get_description_const( feature_ptr ); const size_t feature_descr_len = utf8string_get_length(feature_descr); const data_id_t feature_id = data_feature_get_data_id( feature_ptr ); switch ( (*this_).export_type ) { case IO_FILE_FORMAT_DOCBOOK: { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_START ); xml_writer_increase_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_NAME_START ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), feature_key ); if ( 0 != feature_value_len ) { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), TXT_COLON_SPACE ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), feature_value ); } export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_NAME_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_ID_START ); export_err |= xml_writer_write_plain_id( &((*this_).xml_writer), feature_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_ID_END ); if ( 0 != feature_descr_len ) { xml_writer_increase_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_DESCR_START ); export_err |= md_filter_transform ( &((*this_).md_filter), feature_descr ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_DESCR_END ); xml_writer_decrease_indent ( &((*this_).xml_writer) ); } xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_END ); } break; case IO_FILE_FORMAT_XMI2: { assert(false); /* use the xmi_element_writer instead */ } break; case IO_FILE_FORMAT_XHTML: { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_START ); xml_writer_increase_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), feature_key ); if ( 0 != feature_value_len ) { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), TXT_COLON_SPACE ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), feature_value ); } export_err |= xml_writer_write_plain ( &((*this_).xml_writer), TXT_COLON_SPACE ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_ID_START ); export_err |= xml_writer_write_plain_id( &((*this_).xml_writer), feature_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_ID_END ); if ( 0 != feature_descr_len ) { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_DESCR_START ); export_err |= md_filter_transform ( &((*this_).md_filter), feature_descr ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_DESCR_END ); } xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_END ); } break; case IO_FILE_FORMAT_TXT: { export_err |= txt_writer_write_plain ( &((*this_).txt_writer), TXT_SPACE_INDENT ); export_err |= txt_writer_write_plain ( &((*this_).txt_writer), feature_key ); if ( 0 != feature_value_len ) { export_err |= txt_writer_write_plain ( &((*this_).txt_writer), TXT_COLON_SPACE ); export_err |= txt_writer_write_plain ( &((*this_).txt_writer), feature_value ); } size_t feature_key_len = utf8string_get_length(feature_key); int id_indent_width = TXT_ID_INDENT_COLUMN - utf8string_get_length(TXT_SPACE_INDENT) - feature_key_len - ((feature_value_len==0)?0:feature_value_len+utf8string_get_length(TXT_COLON_SPACE)); export_err |= txt_writer_write_indent_id( &((*this_).txt_writer), id_indent_width, feature_id ); export_err |= txt_writer_write_plain ( &((*this_).txt_writer), TXT_NEWLINE ); export_err |= txt_writer_write_indent_multiline_string( &((*this_).txt_writer), TXT_DOUBLE_INDENT, feature_descr ); } break; default: { TSLOG_ERROR("error: unknown_format."); export_err = -1; } break; } /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_EXPORTED ); TRACE_END_ERR( export_err ); return export_err; } int xhtml_element_writer_end_feature( xhtml_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr) { TRACE_BEGIN(); assert( feature_ptr != NULL ); int write_error = 0; TRACE_END_ERR(write_error); return write_error; } int xhtml_element_writer_start_relationship( xhtml_element_writer_t *this_, data_classifier_type_t host_type, const data_relationship_t *relation_ptr) { TRACE_BEGIN(); assert( relation_ptr != NULL ); int write_error = 0; TRACE_END_ERR(write_error); return write_error; } int xhtml_element_writer_assemble_relationship( xhtml_element_writer_t *this_, const data_classifier_t *host, const data_relationship_t *relation_ptr, const data_classifier_t *from_c, const data_feature_t *from_f, const data_classifier_t *to_c, const data_feature_t *to_f ) { TRACE_BEGIN(); assert ( NULL != relation_ptr ); /* NULL is allowed here: dest_classifier_ptr */ int export_err = 0; const char *const relation_name = data_relationship_get_name_const( relation_ptr ); const data_id_t relation_id = data_relationship_get_data_id( relation_ptr ); const char *const relation_descr = data_relationship_get_description_const( relation_ptr ); const size_t relation_descr_len = utf8string_get_length(relation_descr); const char *const dest_classifier_name = (NULL != to_c) ? data_classifier_get_name_const( to_c ) : ""; switch ( (*this_).export_type ) { case IO_FILE_FORMAT_DOCBOOK: { /* list start */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_DESCRIPTION_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_LIST_START ); xml_writer_increase_indent ( &((*this_).xml_writer) ); /* element */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_START ); xml_writer_increase_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_NAME_START ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), relation_name ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), TXT_SPACE_ARROW_SPACE ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), dest_classifier_name ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_NAME_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_ID_START ); export_err |= xml_writer_write_plain_id( &((*this_).xml_writer), relation_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_ID_END ); if ( 0 != relation_descr_len ) { xml_writer_increase_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_DESCR_START ); export_err |= md_filter_transform ( &((*this_).md_filter), relation_descr ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_DESCR_END ); xml_writer_decrease_indent ( &((*this_).xml_writer) ); } xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_END ); /* list end */ xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_ELEMENT_LIST_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_DESCRIPTION_END ); } break; case IO_FILE_FORMAT_XMI2: { assert(false); /* use the xmi_element_writer instead */ } break; case IO_FILE_FORMAT_XHTML: { /* list start */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_LIST_START ); /* element */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_START ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), relation_name ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), TXT_SPACE_ARROW_SPACE ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), dest_classifier_name ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_ID_START ); export_err |= xml_writer_write_plain_id( &((*this_).xml_writer), relation_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_ID_END ); if ( 0 != relation_descr_len ) { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_DESCR_START ); export_err |= md_filter_transform ( &((*this_).md_filter), relation_descr ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_DESCR_END ); } export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_END ); /* list end */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_ELEMENT_LIST_END ); } break; case IO_FILE_FORMAT_TXT: { export_err |= txt_writer_write_plain ( &((*this_).txt_writer), TXT_SPACE_INDENT ); export_err |= txt_writer_write_plain ( &((*this_).txt_writer), relation_name ); size_t relation_name_len = utf8string_get_length(relation_name); /* print arrow */ if ( relation_name_len == 0 ) { export_err |= txt_writer_write_plain ( &((*this_).txt_writer), TXT_ARROW_SPACE ); } else { export_err |= txt_writer_write_plain ( &((*this_).txt_writer), TXT_SPACE_ARROW_SPACE ); } export_err |= txt_writer_write_plain ( &((*this_).txt_writer), dest_classifier_name ); /* print id */ size_t dest_classifier_name_len = utf8string_get_length( dest_classifier_name ); int id_indent_width = TXT_ID_INDENT_COLUMN - utf8string_get_length(TXT_SPACE_INDENT) - relation_name_len - ((relation_name_len==0)?utf8string_get_length(TXT_ARROW_SPACE):utf8string_get_length(TXT_SPACE_ARROW_SPACE)) - dest_classifier_name_len; export_err |= txt_writer_write_indent_id( &((*this_).txt_writer), id_indent_width, relation_id ); export_err |= txt_writer_write_plain ( &((*this_).txt_writer), TXT_NEWLINE ); export_err |= txt_writer_write_indent_multiline_string( &((*this_).txt_writer), TXT_DOUBLE_INDENT, relation_descr ); } break; default: { TSLOG_ERROR("error: unknown_format."); export_err = -1; } break; } /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_EXPORTED ); TRACE_END_ERR( export_err ); return export_err; } int xhtml_element_writer_end_relationship( xhtml_element_writer_t *this_, data_classifier_type_t host_type, const data_relationship_t *relation_ptr) { TRACE_BEGIN(); assert( relation_ptr != NULL ); int write_error = 0; TRACE_END_ERR(write_error); return write_error; } int xhtml_element_writer_start_diagram( xhtml_element_writer_t *this_, const data_diagram_t *diag_ptr ) { TRACE_BEGIN(); assert ( NULL != diag_ptr ); int export_err = 0; const data_id_t diag_id = data_diagram_get_data_id(diag_ptr); /* increase tree depth */ (*this_).current_tree_depth ++; switch ( (*this_).export_type ) { case IO_FILE_FORMAT_DOCBOOK: { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), ((*this_).current_tree_depth==1) ? DOCBOOK_TOP_DIAGRAM_START : DOCBOOK_DIAGRAM_START ); export_err |= xml_writer_write_plain_id ( &((*this_).xml_writer), diag_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), ((*this_).current_tree_depth==1) ? DOCBOOK_TOP_DIAGRAM_MIDDLE : DOCBOOK_DIAGRAM_MIDDLE ); xml_writer_increase_indent ( &((*this_).xml_writer) ); } break; case IO_FILE_FORMAT_XMI2: { assert(false); /* use the xmi_element_writer instead */ } break; case IO_FILE_FORMAT_XHTML: { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_DIAGRAM_START ); export_err |= xml_writer_write_plain_id ( &((*this_).xml_writer), diag_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_DIAGRAM_MIDDLE ); xml_writer_increase_indent ( &((*this_).xml_writer) ); } break; case IO_FILE_FORMAT_TXT: { /* no start diagram tags */ } break; default: { TSLOG_ERROR("error: unknown_format."); export_err = -1; } break; } if ( export_err != 0 ) { TSLOG_ERROR( "not all bytes could be written" ); } TRACE_END_ERR( export_err ); return export_err; } int xhtml_element_writer_assemble_diagram( xhtml_element_writer_t *this_, const data_diagram_t *parent, const data_diagram_t *diag_ptr, const char *diagram_file_base_name ) { TRACE_BEGIN(); /* parent may be NULL */ assert ( NULL != diag_ptr ); assert ( NULL != diagram_file_base_name ); int export_err = 0; const char *const diag_name = data_diagram_get_name_const( diag_ptr ); const char *const diag_description = data_diagram_get_description_const( diag_ptr ); const data_id_t diag_id = data_diagram_get_data_id(diag_ptr); switch ( (*this_).export_type ) { case IO_FILE_FORMAT_DOCBOOK: { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_DIAGRAM_TITLE_START ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), diag_name ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_DIAGRAM_TITLE_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_DESCRIPTION_START ); export_err |= md_filter_transform ( &((*this_).md_filter), diag_description ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_DESCRIPTION_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_DIAGRAM_IMG_START ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), diagram_file_base_name ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_DIAGRAM_IMG_MIDDLE ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), diagram_file_base_name ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_DIAGRAM_IMG_END ); } break; case IO_FILE_FORMAT_XMI2: { assert(false); /* use the xmi_element_writer instead */ } break; case IO_FILE_FORMAT_XHTML: { const unsigned int index_of_depth = ((*this_).current_tree_depth > XHTML_DIAGRAM_MAX_DEPTH) ? (XHTML_DIAGRAM_MAX_DEPTH-1) : ((*this_).current_tree_depth-1); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_DIAGRAM_TITLE_START[index_of_depth] ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), diag_name ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_DIAGRAM_TITLE_END[index_of_depth] ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_DESCRIPTION_START ); export_err |= md_filter_transform ( &((*this_).md_filter), diag_description ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_DESCRIPTION_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_DIAGRAM_IMG_START ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), diagram_file_base_name ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_DIAGRAM_IMG_END ); } break; case IO_FILE_FORMAT_TXT: { export_err |= txt_writer_write_plain ( &((*this_).txt_writer), diag_name ); export_err |= txt_writer_write_indent_id( &((*this_).txt_writer), TXT_ID_INDENT_COLUMN - utf8string_get_length(diag_name), diag_id ); export_err |= txt_writer_write_plain ( &((*this_).txt_writer), TXT_NEWLINE ); export_err |= txt_writer_write_indent_multiline_string( &((*this_).txt_writer), TXT_SINGLE_INDENT, diag_description ); } break; default: { TSLOG_ERROR("error: unknown_format."); export_err = -1; } break; } /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_DIAGRAM, DATA_STAT_SERIES_EXPORTED ); TRACE_END_ERR( export_err ); return export_err; } int xhtml_element_writer_end_diagram( xhtml_element_writer_t *this_, const data_diagram_t *diag_ptr ) { TRACE_BEGIN(); assert ( NULL != diag_ptr ); int export_err = 0; switch ( (*this_).export_type ) { case IO_FILE_FORMAT_DOCBOOK: { xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), ((*this_).current_tree_depth==1) ? DOCBOOK_TOP_DIAGRAM_END : DOCBOOK_DIAGRAM_END ); } break; case IO_FILE_FORMAT_XMI2: { assert(false); /* use the xmi_element_writer instead */ } break; case IO_FILE_FORMAT_XHTML: { xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_DIAGRAM_END ); } break; case IO_FILE_FORMAT_TXT: { /* no end diagram tags */ } break; default: { TSLOG_ERROR("error: unknown_format."); export_err = -1; } break; } /* decrease tree depth */ (*this_).current_tree_depth --; TRACE_END_ERR( export_err ); return export_err; } int xhtml_element_writer_start_diagramelement( xhtml_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr ) { TRACE_BEGIN(); assert( diagramelement_ptr != NULL ); assert( parent != NULL ); int write_error = 0; TRACE_END_ERR(write_error); return write_error; } int xhtml_element_writer_assemble_diagramelement( xhtml_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr, const data_classifier_t *occurrence, const data_feature_t *feat_occur ) { TRACE_BEGIN(); assert( diagramelement_ptr != NULL ); assert( parent != NULL ); assert( occurrence != NULL ); /* NULL is allowed here: feat_occur */ int write_error = 0; TRACE_END_ERR(write_error); return write_error; } int xhtml_element_writer_end_diagramelement( xhtml_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr ) { TRACE_BEGIN(); assert( diagramelement_ptr != NULL ); assert( parent != NULL ); int write_error = 0; TRACE_END_ERR(write_error); return write_error; } int xhtml_element_writer_end_main( xhtml_element_writer_t *this_ ) { TRACE_BEGIN(); int write_error = 0; TRACE_END_ERR(write_error); return write_error; } int xhtml_element_writer_write_footer( xhtml_element_writer_t *this_ ) { TRACE_BEGIN(); int export_err = 0; switch ( (*this_).export_type ) { case IO_FILE_FORMAT_DOCBOOK: { xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), DOCBOOK_DOC_END ); } break; case IO_FILE_FORMAT_XMI2: { assert(false); /* use the xmi_element_writer instead */ } break; case IO_FILE_FORMAT_XHTML: { xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_BODY_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XHTML_DOC_END ); } break; case IO_FILE_FORMAT_TXT: { /* no footer */ } break; default: { TSLOG_ERROR("error: unknown_format."); export_err = -1; } break; } TRACE_END_ERR( export_err ); return export_err; } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/xhtml/xhtml_stylesheet_writer.c000066400000000000000000000116721415120503000253420ustar00rootroot00000000000000/* File: xhtml_stylesheet_writer.c; Copyright and License: see below */ #include "xhtml/xhtml_stylesheet_writer.h" #include "util/string/utf8string.h" #include "trace.h" #include "tslog.h" #include #include /* IO_FILE_FORMAT_CSS */ static const char CSS_ALL[] ="body {\n" " background-color: rgb(255,255,255);\n" " font-family: Helvetica,Arial,sans-serif;\n" "}\n" ".toc1 {\n" " color:rgb(192,128,0);\n" " font-size: small;\n" " counter-reset: cnt-head-two;\n" "}\n" ".toc2::before {\n" " counter-increment: cnt-head-two;\n" " content: counter(cnt-head-two) \"\\0000a0 \";\n" "}\n" ".toc2 {\n" " color:rgb(192,128,0);\n" " font-size: small;\n" " counter-reset: cnt-head-three;\n" "}\n" ".toc3::before {\n" " counter-increment: cnt-head-three;\n" " content: counter(cnt-head-two) \".\" counter(cnt-head-three) \"\\0000a0 \";\n" "}\n" ".toc3 {\n" " color:rgb(192,128,0);\n" " font-size: x-small;\n" " counter-reset: cnt-head-four;\n" "}\n" ".toc4::before {\n" " counter-increment: cnt-head-four;\n" " content: counter(cnt-head-two) \".\" counter(cnt-head-three) \".\" counter(cnt-head-four) \"\\0000a0 \";\n" "}\n" ".toc4 {\n" " color:rgb(192,128,0);\n" " font-size: x-small;\n" " counter-reset: cnt-head-five;\n" "}\n" ".toc5::before {\n" " counter-increment: cnt-head-five;\n" " content: counter(cnt-head-two) \".\" counter(cnt-head-three) \".\" counter(cnt-head-four) \".\" counter(cnt-head-five) \"\\0000a0 \";\n" "}\n" ".toc5 {\n" " color:rgb(192,128,0);\n" " font-size: xx-small;\n" " counter-reset: cnt-head-six;\n" "}\n" ".toc6::before {\n" " counter-increment: cnt-head-six;\n" " content: counter(cnt-head-two) \".\" counter(cnt-head-three) \".\" counter(cnt-head-four) \".\" counter(cnt-head-five) \".\" counter(cnt-head-six) \"\\0000a0 \";\n" "}\n" ".toc6 {\n" " color:rgb(192,128,0);\n" " font-size: xx-small;\n" "}\n" ".description {\n" " background-color:rgb(216,255,240);\n" " padding:6px;\n" " margin:2px;\n" " border:1px solid #44CC88;\n" "}\n" ".title {\n" " color:rgb(192,128,0);\n" "}\n" ".element {\n" " background-color:rgb(240,240,240);\n" "}\n" ".elementname {\n" " color:rgb(0,128,80);\n" "}\n" ".elementid::before {\n" " content:\" \\0000a0 \\0000a0 {id=\";\n" "}\n" ".elementid {\n" " color:rgb(160,160,160);\n" "}\n" ".elementid::after {\n" " content:\"}\";\n" "}\n" ".elementdescr {\n" " background-color:rgb(255,255,255);\n" " padding:6px;\n" " margin:2px;\n" " border:1px solid #CCCCCC;\n" "}\n" "h1 {\n" " counter-reset: cnt-head-two;\n" "}\n" "h2::before {\n" " counter-increment: cnt-head-two;\n" " content: counter(cnt-head-two) \"\\0000a0 \";\n" "}\n" "h2 {\n" " counter-reset: cnt-head-three;\n" "}\n" "h3::before {\n" " counter-increment: cnt-head-three;\n" " content: counter(cnt-head-two) \".\" counter(cnt-head-three) \"\\0000a0 \";\n" "}\n" "h3 {\n" " counter-reset: cnt-head-four;\n" "}\n" "h4::before {\n" " counter-increment: cnt-head-four;\n" " content: counter(cnt-head-two) \".\" counter(cnt-head-three) \".\" counter(cnt-head-four) \"\\0000a0 \";\n" "}\n" "h4 {\n" " counter-reset: cnt-head-five;\n" "}\n" "h5::before {\n" " counter-increment: cnt-head-five;\n" " content: counter(cnt-head-two) \".\" counter(cnt-head-three) \".\" counter(cnt-head-four) \".\" counter(cnt-head-five) \"\\0000a0 \";\n" "}\n" "h5 {\n" " counter-reset: cnt-head-six;\n" "}\n" "h6::before {\n" " counter-increment: cnt-head-six;\n" " content: counter(cnt-head-two) \".\" counter(cnt-head-three) \".\" counter(cnt-head-four) \".\" counter(cnt-head-five) \".\" counter(cnt-head-six) \"\\0000a0 \";\n" "}\n"; void xhtml_stylesheet_writer_init ( xhtml_stylesheet_writer_t *this_, universal_output_stream_t *output ) { TRACE_BEGIN(); assert( NULL != output ); (*this_).output = output; TRACE_END(); } void xhtml_stylesheet_writer_destroy( xhtml_stylesheet_writer_t *this_ ) { TRACE_BEGIN(); (*this_).output = NULL; TRACE_END(); } int xhtml_stylesheet_writer_write_stylesheet( xhtml_stylesheet_writer_t *this_ ) { TRACE_BEGIN(); int export_err = 0; utf8string_t text = CSS_ALL; const size_t text_len = utf8string_get_length(text); export_err |= universal_output_stream_write( (*this_).output, text, text_len); TRACE_END_ERR( export_err ); return export_err; } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/xmi/000077500000000000000000000000001415120503000176275ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/source/xmi/xmi_atom_writer.c000066400000000000000000000735271415120503000232220ustar00rootroot00000000000000/* File: xmi_atom_writer.c; Copyright and License: see below */ #include "xmi/xmi_atom_writer.h" #include "xmi/xmi_element_info.h" #include "xmi/xmi_element_info_map.h" #include "xmi/xmi_xml.h" #include "util/string/utf8string.h" #include "data_id.h" #include "trace.h" #include "tslog.h" #include #include /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 7.8.6.4 */ static const char XMI2_UML_OWNED_COMMENT_START[] = "\n data_id_get_row_id(&element_id) ) { if ( 10 > data_id_get_row_id(&element_id) ) { if ( 0 <= data_id_get_row_id(&element_id) ) { export_err |= xml_writer_write_plain ( (*this_).xml_writer, "000" ); } else { /* row_id is negative */ } } else { export_err |= xml_writer_write_plain ( (*this_).xml_writer, "00" ); } } else { if ( 1000 > data_id_get_row_id(&element_id) ) { export_err |= xml_writer_write_plain ( (*this_).xml_writer, "0" ); } else { /* row_id is greater than 1000 */ } } export_err |= xml_writer_write_int ( (*this_).xml_writer, data_id_get_row_id(&element_id) ); } TRACE_END_ERR( export_err ); return export_err; } int xmi_atom_writer_report_unknown_classifier( xmi_atom_writer_t *this_, data_id_t fact_classifier_id, data_classifier_type_t fact_classifier_type ) { TRACE_BEGIN(); int export_err = 0; export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); TRACE_END_ERR( export_err ); return export_err; } int xmi_atom_writer_report_unknown_feature( xmi_atom_writer_t *this_, data_id_t fact_feature_id, data_feature_type_t fact_feature_type ) { TRACE_BEGIN(); int export_err = 0; export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); TRACE_END_ERR( export_err ); return export_err; } int xmi_atom_writer_report_unknown_relationship( xmi_atom_writer_t *this_, data_id_t fact_relationship_id, data_relationship_type_t fact_relationship_type ) { TRACE_BEGIN(); int export_err = 0; export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); TRACE_END_ERR( export_err ); return export_err; } int xmi_atom_writer_report_illegal_container( xmi_atom_writer_t *this_, data_id_t fact_classifier_id, data_classifier_type_t fact_classifier_type, data_classifier_type_t fact_parent_type ) { TRACE_BEGIN(); int export_err = 0; const xmi_element_info_t *parent_info; int map_err = xmi_element_info_map_get_classifier( &xmi_element_info_map_standard, DATA_CLASSIFIER_TYPE_PACKAGE, /*guess, only used for an error message */ fact_parent_type, &parent_info ); if ( map_err != 0 ) { TSLOG_WARNING("xmi_element_info_map_get_classifier could not map DATA_CLASSIFIER_TYPE_PACKAGE"); } const xmi_element_info_t *classifier_info; map_err = xmi_element_info_map_get_classifier( &xmi_element_info_map_standard, fact_parent_type, fact_classifier_type, &classifier_info ); if ( map_err != 0 ) { TSLOG_WARNING_INT("xmi_element_info_map_get_classifier could not map type", fact_classifier_type ); } export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); TRACE_END_ERR( export_err ); return export_err; } int xmi_atom_writer_report_illegal_stereotype( xmi_atom_writer_t *this_, data_id_t element_id, utf8stringview_t stereotype ) { TRACE_BEGIN(); int export_err = 0; export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); TRACE_END_ERR( export_err ); return export_err; } int xmi_atom_writer_report_illegal_datatype( xmi_atom_writer_t *this_, data_id_t feature_id, const char * datatype ) { TRACE_BEGIN(); int export_err = 0; export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); TRACE_END_ERR( export_err ); return export_err; } int xmi_atom_writer_report_illegal_parent( xmi_atom_writer_t *this_, data_id_t fact_feature_id, data_feature_type_t fact_feature_type, data_classifier_type_t fact_parent_type ) { TRACE_BEGIN(); int export_err = 0; const xmi_element_info_t *parent_info; int map_err = xmi_element_info_map_get_classifier( &xmi_element_info_map_standard, DATA_CLASSIFIER_TYPE_PACKAGE, /*guess, only used for an error message */ fact_parent_type, &parent_info ); if ( map_err != 0 ) { TSLOG_WARNING("xmi_element_info_map_get_classifier could not map DATA_CLASSIFIER_TYPE_PACKAGE"); } const xmi_element_info_t *feature_info; map_err = xmi_element_info_map_get_feature( &xmi_element_info_map_standard, fact_parent_type, fact_feature_type, &feature_info ); if ( map_err != 0 ) { TSLOG_WARNING_INT("xmi_element_info_map_get_feature could not map type", fact_feature_type ); } export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); TRACE_END_ERR( export_err ); return export_err; } int xmi_atom_writer_report_illegal_location( xmi_atom_writer_t *this_, data_id_t fact_relationship_id, data_relationship_type_t fact_relationship_type, data_classifier_type_t fact_hosting_type ) { TRACE_BEGIN(); int export_err = 0; const xmi_element_info_t *host_info; int map_err = xmi_element_info_map_get_classifier( &xmi_element_info_map_standard, DATA_CLASSIFIER_TYPE_PACKAGE, /*guess, only used for an error message */ fact_hosting_type, &host_info ); if ( map_err != 0 ) { TSLOG_WARNING("xmi_element_info_map_get_classifier could not map DATA_CLASSIFIER_TYPE_PACKAGE"); } const xmi_element_info_t *relation_info; map_err = xmi_element_info_map_get_relationship( &xmi_element_info_map_standard, (fact_hosting_type==DATA_CLASSIFIER_TYPE_STATE), fact_relationship_type, &relation_info ); if ( map_err != 0 ) { TSLOG_WARNING_INT("xmi_element_info_map_get_relationship could not map type", fact_relationship_type ); } export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); TRACE_END_ERR( export_err ); return export_err; } int xmi_atom_writer_report_illegal_relationship_end ( xmi_atom_writer_t *this_, data_id_t fact_relationship_id, data_relationship_type_t fact_relationship_type, data_classifier_type_t fact_hosting_type, bool fact_from_end, data_classifier_type_t fact_end_classifier_type, data_feature_type_t fact_end_feature_type ) { TRACE_BEGIN(); int export_err = 0; const xmi_element_info_t *relation_info; int map_err = xmi_element_info_map_get_relationship( &xmi_element_info_map_standard, (fact_hosting_type==DATA_CLASSIFIER_TYPE_STATE), fact_relationship_type, &relation_info ); if ( map_err != 0 ) { TSLOG_WARNING_INT("xmi_element_info_map_get_relationship could not map type", fact_relationship_type ); } export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\n" ); TRACE_END_ERR( export_err ); return export_err; } /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/xmi/xmi_element_info_map.c000066400000000000000000001257011415120503000241570ustar00rootroot00000000000000/* File: xmi_element_info_map.c; Copyright and License: see below */ #include "xmi/xmi_element_info_map.h" #include "trace.h" #include "tslog.h" #include const xmi_element_info_map_t xmi_element_info_map_standard = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF */ /* note: if a property or association end starts with a slash(/), */ /* it is a derived value and shall not be specified in xmi */ /* note: google search pattern for examples may help: filetype:xmi */ /* ================================ CLASSIFIER ================================ */ [XMI_ELEMENT_INFO_MAP_INDEX_BLOCK] = { /* spec: https://www.omg.org/spec/SysML/20181001/SysML.xmi (v1.6) pkg: Blocks */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_BLOCK, .specification = XMI_SPEC_SYSML, .profile_name = "Block", .base_name = "Class", .is_a = (XMI_ELEMENT_IS_A_CLASS), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_CONSTRAINT_BLOCK] = { /* spec: https://www.omg.org/spec/SysML/20181001/SysML.xmi (v1.6) pkg: ConstraintBlocks */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_CONSTRAINT_BLOCK, .specification = XMI_SPEC_SYSML, .profile_name = "ConstraintBlock", .base_name = "Class", .is_a = (XMI_ELEMENT_IS_A_CLASS), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_REQUIREMENT] = { /* spec: https://www.omg.org/spec/SysML/20181001/SysML.xmi (v1.6) pkg: Requirements */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_REQUIREMENT, .specification = XMI_SPEC_SYSML, .profile_name = "Requirement", .base_name = "Class", .is_a = (XMI_ELEMENT_IS_A_CLASS), //.base_name = "NamedElement", //.is_a = (XMI_ELEMENT_IS_A_NAMED_ELEMENT), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_ACTOR] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: UseCases */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_ACTOR, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "Actor", .is_a = (XMI_ELEMENT_IS_A_BEHAVIORED_CLASSIFIER), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_USE_CASE] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: UseCases */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_USE_CASE, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "UseCase", .is_a = (XMI_ELEMENT_IS_A_BEHAVIORED_CLASSIFIER), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_SUBSYSTEM] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Deployments */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_SUBSYSTEM, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Component", .is_a = (XMI_ELEMENT_IS_A_CLASS), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_ACTIVITY] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Activities */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 15.7.1 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_ACTIVITY, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "Activity", .is_a = (XMI_ELEMENT_IS_A_BEHAVIOR), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_STRUCTURED_ACTIVITY_NODE] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 16.14.55 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_ACTIVITY, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "StructuredActivityNode", .is_a = (XMI_ELEMENT_IS_A_BEHAVIOR|XMI_ELEMENT_IS_A_ACTIVITY_NODE), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_STATEMACHINE] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: StateMachines */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 14.5.10 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_STATE, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "StateMachine", .is_a = (XMI_ELEMENT_IS_A_BEHAVIOR), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_STATE] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: StateMachines */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 14.5.9 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_STATE, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "State", .is_a = (XMI_ELEMENT_IS_A_VERTEX), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_INTERACTION_USE] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 17.12.16 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_DIAGRAM_REFERENCE, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "InteractionUse", .is_a = (XMI_ELEMENT_IS_A_INTERACTION_FRAGMENT), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_NODE] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Deployments */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 19.5.10 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_NODE, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Node", .is_a = (XMI_ELEMENT_IS_A_NODE), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_COMPONENT] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: StructuredClassifiers */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 11.8.6 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_COMPONENT, .specification = XMI_SPEC_UML, .profile_name = NULL, .base_name = "Component", .is_a = (XMI_ELEMENT_IS_A_CLASS), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_INTERFACE] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: SimpleClassifiers */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 10.5.5 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_INTERFACE, .specification = XMI_SPEC_UML, .profile_name = NULL, .base_name = "Interface", .is_a = (XMI_ELEMENT_IS_A_CLASSIFIER), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_PACKAGE] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Packages */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 12.4.5 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_PACKAGE, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "Package", .is_a = (XMI_ELEMENT_IS_A_PACKAGE), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_CLASS] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: StructuredClassifiers */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_CLASS, .specification = XMI_SPEC_UML, .profile_name = NULL, .base_name = "Class", .is_a = (XMI_ELEMENT_IS_A_CLASS), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_ARTIFACT] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Deployments */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 19.5.1 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_ARTIFACT, .specification = XMI_SPEC_UML, .profile_name = NULL, .base_name = "Artifact", .is_a = (XMI_ELEMENT_IS_A_ARTIFACT), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_COMMENT] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: CommonStructure */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_COMMENT, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "Comment", .is_a = (XMI_ELEMENT_IS_A_COMMENT), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_DYN_INTERRUPTABLE_REGION] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Activities */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 15.7.19 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_DYN_INTERRUPTABLE_REGION, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "InterruptibleActivityRegion", .is_a = (XMI_ELEMENT_IS_A_ACTIVITY_GROUP), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_DYN_ACTIVITY_INITIAL_NODE] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Activities */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 15.7.18 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_DYN_INITIAL_NODE, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "InitialNode", .is_a = (XMI_ELEMENT_IS_A_ACTIVITY_NODE), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_DYN_STATE_INITIAL_NODE] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 14.5.6 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_DYN_INITIAL_NODE, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "Pseudostate", .is_a = (XMI_ELEMENT_IS_A_VERTEX), .property_from = NULL, .property_to = NULL, /*.additional_properties = "kind=\"initial\"", -- the default value must not be written */ .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_DYN_ACTIVITY_FINAL_NODE] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 15.7.3 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_DYN_FINAL_NODE, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "ActivityFinalNode", .is_a = (XMI_ELEMENT_IS_A_ACTIVITY_NODE), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_DYN_STATE_FINAL_NODE] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 14.5.2 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_DYN_FINAL_NODE, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "FinalState", .is_a = (XMI_ELEMENT_IS_A_VERTEX), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_DYN_FORK_NODE] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Activities */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 15.7.17 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_DYN_FORK_NODE, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "ForkNode", .is_a = (XMI_ELEMENT_IS_A_ACTIVITY_NODE), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_DYN_JOIN_NODE] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Activities */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 15.7.17 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_DYN_JOIN_NODE, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "JoinNode", .is_a = (XMI_ELEMENT_IS_A_ACTIVITY_NODE), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_DYN_ACTIVITY_DECISION_NODE] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Activities */ /* "DecisionNode"; */ /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Actions */ /* "ConditionalNode"; */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 15.7.12 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_DYN_DECISION_NODE, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "DecisionNode", .is_a = (XMI_ELEMENT_IS_A_ACTIVITY_NODE), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_DYN_STATE_DECISION_NODE] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 14.5.6 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_DYN_DECISION_NODE, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "Pseudostate", .is_a = (XMI_ELEMENT_IS_A_VERTEX), .property_from = NULL, .property_to = NULL, .additional_properties = "kind=\"choice\"", }, [XMI_ELEMENT_INFO_MAP_INDEX_DYN_SHALLOW_HISTORY] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: StateMachines */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 14.5.6 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_DYN_SHALLOW_HISTORY, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "Pseudostate", .is_a = (XMI_ELEMENT_IS_A_VERTEX), .property_from = NULL, .property_to = NULL, .additional_properties = "kind=\"shallowHistory\"", }, [XMI_ELEMENT_INFO_MAP_INDEX_DYN_DEEP_HISTORY] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: StateMachines */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 14.5.6 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_DYN_DEEP_HISTORY, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "Pseudostate", .is_a = (XMI_ELEMENT_IS_A_VERTEX), .property_from = NULL, .property_to = NULL, .additional_properties = "kind=\"deepHistory\"", }, /* [XMI_ELEMENT_INFO_MAP_INDEX_DYN_PARTITION] = { / * spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Activities * / .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_DYN_PARTITION, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "ActivityPartition", .is_a = (XMI_ELEMENT_IS_A_ACTIVITY_GROUP), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, */ [XMI_ELEMENT_INFO_MAP_INDEX_DYN_ACCEPT_EVENT] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 16.14.2 */ /* spec-ref: https://www.omg.org/spec/SysML/1.6/PDF chapter 11.2 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_DYN_ACCEPT_EVENT, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "AcceptEventAction", .is_a = (XMI_ELEMENT_IS_A_ACTIVITY_NODE), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, /* TODO: property trigger is required */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 13.4.9 */ /*.base_name = "SignalEvent", -- does not work: signal is a mandatory relation and is not available */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 13.4.1 */ /*.base_name = "AnyReceiveEvent", */ /*.is_a = (XMI_ELEMENT_IS_A_EVENT), */ }, [XMI_ELEMENT_INFO_MAP_INDEX_DYN_ACCEPT_TIME_EVENT] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 16.14.2 */ /* spec-ref: https://www.omg.org/spec/SysML/1.6/PDF chapter 11.2 */ /* A Time Event is a AcceptEventAction referencing a Trigger referencint a TimeEvent */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_DYN_ACCEPT_TIME_EVENT, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "AcceptEventAction", .is_a = (XMI_ELEMENT_IS_A_ACTIVITY_NODE), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: CommonBehavior */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 13.4.10 */ /*.base_name = "TimeEvent", */ /*.is_a = (XMI_ELEMENT_IS_A_EVENT), */ }, [XMI_ELEMENT_INFO_MAP_INDEX_DYN_SEND_SIGNAL] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 16.14.50 */ /* spec-ref: https://www.omg.org/spec/SysML/1.6/PDF chapter 11.2 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_DYN_SEND_SIGNAL, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "SendSignalAction", .is_a = (XMI_ELEMENT_IS_A_ACTIVITY_NODE), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, /* TODO: properties signal and target are required */ /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: SimpleClassifiers */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 10.5.9 */ /* "Signal"; */ /*.is_a = (XMI_ELEMENT_IS_A_CLASSIFIER), */ }, [XMI_ELEMENT_INFO_MAP_INDEX_INTERACTION] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 17.2 */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_INTERACTION, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "Interaction", .is_a = (XMI_ELEMENT_IS_A_BEHAVIOR), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, /* ================================ FEATURE ================================ */ [XMI_ELEMENT_INFO_MAP_INDEX_PROPERTY] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 9.9.17 */ .data_type_checksum = (int) DATA_FEATURE_TYPE_PROPERTY, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "Property", .is_a = (XMI_ELEMENT_IS_A_PROPERTY), .property_from = NULL, .property_to = NULL, .additional_properties = "aggregation=\"composite\"", }, [XMI_ELEMENT_INFO_MAP_INDEX_OPERATION] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 9.9.11 */ .data_type_checksum = (int) DATA_FEATURE_TYPE_OPERATION, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "Operation", .is_a = (XMI_ELEMENT_IS_A_FEATURE), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_PORT] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 11.8.14 */ .data_type_checksum = (int) DATA_FEATURE_TYPE_PORT, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "Port", .is_a = (XMI_ELEMENT_IS_A_PROPERTY), .property_from = NULL, .property_to = NULL, .additional_properties = "aggregation=\"composite\"", }, [XMI_ELEMENT_INFO_MAP_INDEX_INPUT_PIN] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 16.14.24 */ .data_type_checksum = (int) DATA_FEATURE_TYPE_IN_PORT_PIN, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "InputPin", .is_a = (XMI_ELEMENT_IS_A_ACTIVITY_NODE | XMI_ELEMENT_IS_A_TYPED_ELEMENT), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_OUTPUT_PIN] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 16.14.32 */ .data_type_checksum = (int) DATA_FEATURE_TYPE_OUT_PORT_PIN, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "OutputPin", .is_a = (XMI_ELEMENT_IS_A_ACTIVITY_NODE | XMI_ELEMENT_IS_A_TYPED_ELEMENT), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_STATE_ENTRY] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 14.5.6 */ .data_type_checksum = (int) DATA_FEATURE_TYPE_ENTRY, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "Pseudostate", .is_a = (XMI_ELEMENT_IS_A_VERTEX), .property_from = NULL, .property_to = NULL, .additional_properties = "kind=\"entryPoint\"", }, [XMI_ELEMENT_INFO_MAP_INDEX_STATE_EXIT] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 14.5.6 */ .data_type_checksum = (int) DATA_FEATURE_TYPE_EXIT, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "Pseudostate", .is_a = (XMI_ELEMENT_IS_A_VERTEX), .property_from = NULL, .property_to = NULL, .additional_properties = "kind=\"exitPoint\"", }, [XMI_ELEMENT_INFO_MAP_INDEX_LIFELINE] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 17.12.17 */ .data_type_checksum = (int) DATA_FEATURE_TYPE_LIFELINE, .specification = (XMI_SPEC_UML | XMI_SPEC_SYSML), .profile_name = NULL, .base_name = "Lifeline", .is_a = (XMI_ELEMENT_IS_A_NAMED_ELEMENT), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_PROVIDED_INTERFACE] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 10.5.5 */ .data_type_checksum = (int) DATA_FEATURE_TYPE_PROVIDED_INTERFACE, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Interface", .is_a = (XMI_ELEMENT_IS_A_CLASSIFIER), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_REQUIRED_INTERFACE] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 10.5.5 */ .data_type_checksum = (int) DATA_FEATURE_TYPE_REQUIRED_INTERFACE, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Interface", .is_a = (XMI_ELEMENT_IS_A_CLASSIFIER), .property_from = NULL, .property_to = NULL, .additional_properties = NULL, }, /* ================================ RELATIONSHIP ================================ */ [XMI_ELEMENT_INFO_MAP_INDEX_DEPENDENCY] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: CommonStructure */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 7.8.4 */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_DEPENDENCY, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Dependency", .is_a = (XMI_ELEMENT_IS_A_DEPENDENCY), .property_from = "client", .property_to = "supplier", .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_ASSOCIATION] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: StructuredClassifiers */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 11.8.1 */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_ASSOCIATION, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Association", .is_a = (XMI_ELEMENT_IS_A_ASSOCIATION), /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 9.5.3, 9.8.3 */ .property_from = "memberEnd", .property_to = "memberEnd", .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_AGGREGATION] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 11.5 */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_AGGREGATION, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Association", .is_a = (XMI_ELEMENT_IS_A_ASSOCIATION), /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 9.5.3, 9.8.3 */ .property_from = "memberEnd", .property_to = "memberEnd", .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_COMPOSITION] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 11.5 */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_COMPOSITION, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Association", .is_a = (XMI_ELEMENT_IS_A_ASSOCIATION), /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 9.5.3, 9.8.3 */ .property_from = "memberEnd", .property_to = "memberEnd", .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_GENERALIZATION] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Classification */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_GENERALIZATION, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Generalization", .is_a = (XMI_ELEMENT_IS_A_DIRECTED_RELATIONSHIP), .property_from = "specific", .property_to = "general", .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_REALIZATION] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: SimpleClassifiers */ /* "InterfaceRealization"; */ /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: CommonStructure */ /* "Realization"; */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_REALIZATION, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Realization", .is_a = (XMI_ELEMENT_IS_A_ABSTRACTION), .property_from = "client", .property_to = "supplier", .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_ASYNC_CALL] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Interactions */ /* "Message"; */ /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: CommonBehavior */ /* "SignalEvent"; */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 17.12.18, 17.12.22 */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_ASYNC_CALL, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Message", .is_a = (XMI_ELEMENT_IS_A_MESSAGE), .property_from = "sendEvent", .property_to = "receiveEvent", .additional_properties = "messageSort=\"asynchSignal\"", }, [XMI_ELEMENT_INFO_MAP_INDEX_SYNC_CALL] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 17.12.18, 17.12.22 */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_SYNC_CALL, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Message", .is_a = (XMI_ELEMENT_IS_A_MESSAGE), .property_from = "sendEvent", .property_to = "receiveEvent", /*.additional_properties = "messageSort=\"synchCall\"",*/ /* this is the default value */ .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_RETURN_CALL] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 17.12.18, 17.12.22 */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_RETURN_CALL, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Message", .is_a = (XMI_ELEMENT_IS_A_MESSAGE), .property_from = "sendEvent", .property_to = "receiveEvent", .additional_properties = "messageSort=\"reply\"", }, [XMI_ELEMENT_INFO_MAP_INDEX_COMMUNICATION_PATH] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Deployments */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_COMMUNICATION_PATH, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "CommunicationPath", .is_a = (XMI_ELEMENT_IS_A_ASSOCIATION), /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 9.5.3, 9.8.3 */ .property_from = "memberEnd", .property_to = "memberEnd", .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_CONTROL_FLOW] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Activities */ /* XMI_TYPE_CONVERTER_NS_UML "ControlFlow"; */ /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Actions */ /* XMI_TYPE_CONVERTER_NS_UML "SendSignalAction"; */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_CONTROL_FLOW, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "ControlFlow", .is_a = (XMI_ELEMENT_IS_A_ACTIVITY_EDGE), .property_from = "source", .property_to = "target", .additional_properties = "weight=\"1\" guard=\"true\"", }, [XMI_ELEMENT_INFO_MAP_INDEX_OBJECT_FLOW] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Activities */ /* XMI_TYPE_CONVERTER_NS_UML "ObjectFlow"; */ /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Actions */ /* XMI_TYPE_CONVERTER_NS_UML "SendObjectAction"; */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_OBJECT_FLOW, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "ObjectFlow", .is_a = (XMI_ELEMENT_IS_A_ACTIVITY_EDGE), .property_from = "source", .property_to = "target", .additional_properties = "weight=\"1\" guard=\"true\"", }, [XMI_ELEMENT_INFO_MAP_INDEX_TRANSITION] = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 14.5.11 */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_CONTROL_FLOW, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Transition", .is_a = (XMI_ELEMENT_IS_A_TRANSITION), .property_from = "source", .property_to = "target", .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_DEPLOY] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Deployments */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_DEPLOY, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Deployment", .is_a = (XMI_ELEMENT_IS_A_DEPENDENCY), .property_from = "client", .property_to = "supplier", .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_MANIFEST] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Deployments */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_MANIFEST, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Manifestation", .is_a = (XMI_ELEMENT_IS_A_ABSTRACTION), .property_from = "client", .property_to = "supplier", .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_EXTEND] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: UseCases */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_EXTEND, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Extend", .is_a = (XMI_ELEMENT_IS_A_DIRECTED_RELATIONSHIP), .property_from = "extension", .property_to = "extendedCase", .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_INCLUDE] = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: UseCases */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_INCLUDE, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Include", .is_a = (XMI_ELEMENT_IS_A_DIRECTED_RELATIONSHIP), .property_from = "includingCase", .property_to = "addition", .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_CONTAINMENT] = { /* Note: This is a fallback only, if xmi_type_converter_get_xmi_nesting_property_of_classifier() fails, e.g. at circular containments */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Association", .is_a = (XMI_ELEMENT_IS_A_ASSOCIATION), /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 9.5.3, 9.8.3 */ .property_from = "memberEnd", .property_to = "memberEnd", .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_REFINE] = { /* spec: https://www.omg.org/spec/SysML/20181001/SysML.xmi (v1.6) pkg: Requirements */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_REFINE, .specification = (XMI_SPEC_STANDARD), .profile_name = "Refine", .base_name = "Abstraction", .is_a = (XMI_ELEMENT_IS_A_ABSTRACTION), .property_from = "client", .property_to = "supplier", .additional_properties = NULL, }, [XMI_ELEMENT_INFO_MAP_INDEX_TRACE] = { /* spec: https://www.omg.org/spec/SysML/20181001/SysML.xmi (v1.6) pkg: Requirements */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_TRACE, .specification = (XMI_SPEC_STANDARD), .profile_name = "Trace", .base_name = "Abstraction", .is_a = (XMI_ELEMENT_IS_A_ABSTRACTION), .property_from = "client", .property_to = "supplier", .additional_properties = NULL, }, }; const xmi_element_info_t xmi_element_info_map_unknown_type = { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: StructuredClassifiers */ .data_type_checksum = (int) DATA_CLASSIFIER_TYPE_CLASS, .specification = XMI_SPEC_UML, .profile_name = NULL, .base_name = "Class", .is_a = (XMI_ELEMENT_IS_A_CLASS), .property_from = NULL, .property_to = NULL, .additional_properties = "error=\"unknown type\"", }; const xmi_element_info_t xmi_element_info_map_unknown_rel_type = { /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 7.8.4 */ .data_type_checksum = (int) DATA_RELATIONSHIP_TYPE_UML_DEPENDENCY, .specification = (XMI_SPEC_UML), .profile_name = NULL, .base_name = "Dependency", .is_a = (XMI_ELEMENT_IS_A_DEPENDENCY), .property_from = "client", .property_to = "supplier", .additional_properties = "error=\"unknown type\"", }; /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/xmi/xmi_element_part.c000066400000000000000000000037041415120503000233330ustar00rootroot00000000000000/* File: xmi_element_part.c; Copyright and License: see below */ #include "xmi/xmi_element_part.h" /* constants naming scheme: XMI_ELEMENT_PART__ */ const char * const XMI_ELEMENT_PART_FALLBACK_NESTING_ELEMENT = "packagedElement"; const char * const XMI_ELEMENT_PART_FALLBACK_OWNED_FEATURE = "ownedAttribute"; const char * const XMI_ELEMENT_PART_ELEMENT_OWNED_END = "ownedEnd"; const char * const XMI_ELEMENT_PART_TYPE_PROPERTY = "Property"; const char * const XMI_ELEMENT_PART_ID_FRAGMENT_SOURCE_END = "#sourceend"; const char * const XMI_ELEMENT_PART_ID_FRAGMENT_TARGET_END = "#targetend"; const char * const XMI_ELEMENT_PART_PROPERTY_ASSOCIATION_ATTRIBUTE = "association"; const char * const XMI_ELEMENT_PART_PROPERTY_TYPE_ELEMENT = "type"; const char * const XMI_ELEMENT_PART_PROPERTY_CLASS_ELEMENT = "class"; const char * const XMI_ELEMENT_PART_PROPERTY_INTERFACE_ELEMENT = "interface"; const char * const XMI_ELEMENT_PART_PROPERTY_AGGREGATION_ATTRIBUTE = "aggregation"; const char * const XMI_ELEMENT_PART_PROPERTY_AGGREGATION_SHARED = "shared"; const char * const XMI_ELEMENT_PART_PROPERTY_AGGREGATION_COMPOSITE = "composite"; const char * const XMI_ELEMENT_PART_TYPE_MSG_OCCURRENCE_SPEC = "MessageOccurrenceSpecification"; const char * const XMI_ELEMENT_PART_PROPERTY_OCCURRENCE_SPEC_COVERED = "covered"; /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/xmi/xmi_element_writer.c000066400000000000000000002565561415120503000237200ustar00rootroot00000000000000/* File: xmi_element_writer.c; Copyright and License: see below */ #include "xmi/xmi_element_writer.h" #include "xmi/xmi_element_info_map.h" #include "xmi/xmi_element_info.h" #include "xmi/xmi_element_part.h" #include "xmi/xmi_xml.h" #include "util/string/utf8string.h" #include "util/string/utf8stringview.h" #include "util/string/utf8stringviewiterator.h" #include "data_id.h" #include "meta/meta_version.h" #include "meta/meta_info.h" #include "trace.h" #include "tslog.h" #include #include #include /* define a struct where the function pointers have the exact right signatures to avoid typecasts */ #define io_element_writer_impl_t xmi_element_writer_t struct xmi_element_writer_io_element_writer_if_struct { #include "io_element_writer_if.inl" }; #undef io_element_writer_impl_t /* the vmt implementing the interface */ static const struct xmi_element_writer_io_element_writer_if_struct xmi_element_writer_private_io_element_writer_if = { .write_header = &xmi_element_writer_write_header, .start_main = &xmi_element_writer_start_main, .can_classifier_nest_classifier = &xmi_element_writer_can_classifier_nest_classifier, .can_classifier_nest_relationship = &xmi_element_writer_can_classifier_nest_relationship, .start_classifier = &xmi_element_writer_start_classifier, .assemble_classifier = &xmi_element_writer_assemble_classifier, .end_classifier = &xmi_element_writer_end_classifier, .start_feature = &xmi_element_writer_start_feature, .assemble_feature = &xmi_element_writer_assemble_feature, .end_feature = &xmi_element_writer_end_feature, .start_relationship = &xmi_element_writer_start_relationship, .assemble_relationship = &xmi_element_writer_assemble_relationship, .end_relationship = &xmi_element_writer_end_relationship, .start_diagram = &xmi_element_writer_start_diagram, .assemble_diagram = &xmi_element_writer_assemble_diagram, .end_diagram = &xmi_element_writer_end_diagram, .start_diagramelement = &xmi_element_writer_start_diagramelement, .assemble_diagramelement = &xmi_element_writer_assemble_diagramelement, .end_diagramelement = &xmi_element_writer_end_diagramelement, .end_main = &xmi_element_writer_end_main, .write_footer = &xmi_element_writer_write_footer }; /* GENERAL STRUCTURE */ /* * _START * _MIDDLE #optional, if dynamic content needs to be added to the start * _TITLE_START #alternative to TITLE: NAME * _TITLE_END #alternative to TITLE: NAME * ... #optional text * __START #optional if there ore other sub-things * __END #optional if there ore other sub-things * _END */ /* Note: when writing, each method typically starts with writing a newline, it does not end with writing a newline. */ /* IO_FILE_FORMAT_XMI2 */ static const char XMI2_ENC[] = ""; /* spec-ref: https://www.omg.org/spec/XMI/2.5.1/PDF chapter 9.5.1 : 1,1a,1e,1f */ /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 12.3.3.1.3 */ /* spec-ref: https://www.omg.org/spec/SysML/1.6/PDF chapter G.3 */ //static const char XMI2_DOC_START[] // = "\n" // "\n "; static const char XMI2_DOC_START[] = "\n" "\n "; /* spec-ref: https://www.omg.org/spec/XMI/2.5.1/PDF chapter 9.5.1 : 1,1a */ static const char XMI2_DOC_END[] = "\n"; /* spec-ref: https://www.omg.org/spec/XMI/2.5.1/PDF chapter 7.5.3 + 7.5.5 */ static const char XMI2_DOC_METAINFO_START[] = "\n"; /* spec-ref: https://www.omg.org/spec/UML/2.5.1/PDF chapter 12.2.2, 12.3.5 */ /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Packages */ static const char XMI2_UML_MODEL_START[] = "\n" ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), "1" ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), classifier_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), "" ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), "" ); xml_writer_increase_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), classifier_descr ); xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), "\n" ); /* export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), "" ); */ } /* export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_COMMENT_START ); export_err |= xml_writer_write_plain_id( &((*this_).xml_writer), classifier_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_COMMENT_END ); */ xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_END_TAG_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_NS_SYSML ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), profile_type ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_END_TAG_END ); } /* write user-defined stereotypes */ { utf8stringviewiterator_t stereo_iterator; utf8stringviewiterator_init( &stereo_iterator, UTF8STRINGVIEW_STR(classifier_stereo), "," ); while( utf8stringviewiterator_has_next( &stereo_iterator ) ) { const utf8stringview_t stereotype_view = utf8stringviewiterator_next( &stereo_iterator ); size_t stereotype_len = utf8stringview_get_length( stereotype_view ); if ( stereotype_len != 0 ) { bool is_name = xml_writer_contains_xml_tag_name_characters( &((*this_).xml_writer), stereotype_view ); if ( is_name ) { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_EMPTY_TAG_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_NS_LOCALPROF ); export_err |= xml_writer_write_xml_tag_name_characters ( &((*this_).xml_writer), stereotype_view ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_ATTR_SEPARATOR ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_ID_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), "1" ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), classifier_id ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), "#" ); export_err |= xml_writer_write_xml_enc_view ( &((*this_).xml_writer), stereotype_view ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_ID_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI2_EXT_BASE_ELEMENT_START ); const char* base_type = xmi_type_converter_get_xmi_type_of_classifier ( &((*this_).xmi_types), host_type, classifier_type, XMI_SPEC_UML ); if ( classifier_type == DATA_CLASSIFIER_TYPE_REQUIREMENT ) { /* the base class is a Class, but the derived property name from AbstractRequirement is base_NamedElement */ base_type = "NamedElement"; /* but: one could understand differently the SysML 1.6 chapter 16.3.2.5 Requirement */ } export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), base_type ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI2_EXT_BASE_ELEMENT_MIDDLE ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), classifier_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI2_EXT_BASE_ELEMENT_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_EMPTY_TAG_END ); } else { export_err |= xmi_atom_writer_report_illegal_stereotype( &((*this_).atom_writer), classifier_id, stereotype_view ); /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_CLASSIFIER, DATA_STAT_SERIES_WARNING ); } } } } } TRACE_END_ERR( export_err ); return export_err; } int xmi_element_writer_end_classifier( xmi_element_writer_t *this_, data_classifier_type_t host_type, const data_classifier_t *classifier_ptr ) { TRACE_BEGIN(); assert ( NULL != classifier_ptr ); const data_classifier_type_t classifier_type = data_classifier_get_main_type(classifier_ptr); int export_err = 0; if ( (*this_).mode == XMI_WRITER_PASS_BASE ) { /* generate end to pseudo subelement region to statemachines and states */ if ( classifier_type == DATA_CLASSIFIER_TYPE_STATE ) { xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_END_TAG_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI2_STATE_REGION_NESTING_STATE ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_END_TAG_END ); } /* determine nesting tag */ const char* nesting_property; const int nesting_err = xmi_type_converter_get_xmi_nesting_property_of_classifier( &((*this_).xmi_types), host_type, classifier_type, &nesting_property ); if ( nesting_err != 0 ) { /* The caller requested to write a classifier to an illegal place */ /* use a fallback */ nesting_property = XMI_ELEMENT_PART_FALLBACK_NESTING_ELEMENT; } /* adjust indentation, write end tag */ xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_END_TAG_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), nesting_property ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_END_TAG_END ); } TRACE_END_ERR( export_err ); return export_err; } int xmi_element_writer_start_feature( xmi_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ) { TRACE_BEGIN(); assert ( NULL != feature_ptr ); int export_err = 0; const char *const feature_key = data_feature_get_key_const( feature_ptr ); const data_id_t feature_id = data_feature_get_data_id( feature_ptr ); const data_feature_type_t feature_type = data_feature_get_main_type( feature_ptr ); const xmi_element_info_t *feature_info; int map_err = xmi_element_info_map_get_feature( &xmi_element_info_map_standard, parent_type, feature_type, &feature_info ); if ( (*this_).mode == XMI_WRITER_PASS_BASE ) { if ( map_err != 0 ) { /* The caller requested to write a feature of unknown type */ TRACE_INFO("xmi_element_writer: request to write a feature of unknown type!") /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_WARNING ); /* inform the user via an XML comment: */ export_err |= xmi_atom_writer_report_unknown_feature( &((*this_).atom_writer), feature_id, feature_type ); } /* determine nesting tag */ const char* owning_type; const int owning_err = xmi_type_converter_get_xmi_owning_property_of_feature( &((*this_).xmi_types), parent_type, feature_type, &owning_type ); if ( owning_err != 0 ) { /* The caller requested to write a feature to an illegal place */ TRACE_INFO("xmi_element_writer: request to write a feature to an illegal place!") /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_WARNING ); /* inform the user via an XML comment: */ export_err |= xmi_atom_writer_report_illegal_parent( &((*this_).atom_writer), feature_id, feature_type, parent_type ); owning_type = XMI_ELEMENT_PART_FALLBACK_OWNED_FEATURE; } /* write nesting tag */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_START_TAG_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), owning_type ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_ATTR_SEPARATOR ); /* write type attribute */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_TYPE_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_NS_UML ); const char* f_type = xmi_type_converter_get_xmi_type_of_feature ( &((*this_).xmi_types), parent_type, feature_type, XMI_SPEC_UML ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), f_type ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_TYPE_END ); /* write id attribute */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_ID_START ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), feature_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_ID_END ); /* write name attribute */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_NAME_START ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), feature_key ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_NAME_END ); if ( NULL != xmi_element_info_get_additional_properties( feature_info ) ) { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), xmi_element_info_get_additional_properties( feature_info ) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_ATTR_SEPARATOR ); } export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_START_TAG_END ); xml_writer_increase_indent ( &((*this_).xml_writer) ); /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_EXPORTED ); } TRACE_END_ERR( export_err ); return export_err; } int xmi_element_writer_assemble_feature( xmi_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ) { TRACE_BEGIN(); assert ( NULL != feature_ptr ); int export_err = 0; const char *const feature_value = data_feature_get_value_const( feature_ptr ); const size_t feature_value_len = utf8string_get_length(feature_value); const char *const feature_descr = data_feature_get_description_const( feature_ptr ); const size_t feature_descr_len = utf8string_get_length(feature_descr); const data_id_t feature_id = data_feature_get_data_id( feature_ptr ); const data_feature_type_t feature_type = data_feature_get_main_type( feature_ptr ); const xmi_element_info_t *feature_info; int map_err = xmi_element_info_map_get_feature( &xmi_element_info_map_standard, parent_type, feature_type, &feature_info ); if ( (*this_).mode == XMI_WRITER_PASS_BASE ) { if ( 0 != feature_value_len ) { if (( map_err == 0 )&&( xmi_element_info_is_a_typed_element( feature_info ) )) { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_EMPTY_TAG_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), "type" ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_ATTR_SEPARATOR ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_TYPE_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_NS_UML ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), "DataType" ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_TYPE_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_ID_START ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), feature_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), "#type" ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_ID_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_NAME_START ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), feature_value ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_NAME_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_EMPTY_TAG_END ); } else { export_err |= xmi_atom_writer_report_illegal_datatype( &((*this_).atom_writer), feature_id, feature_value ); } } if ( 0 != feature_descr_len ) { export_err |= xmi_atom_writer_write_xmi_comment( &((*this_).atom_writer), feature_id, "specification", feature_descr ); } if ( parent_type == DATA_CLASSIFIER_TYPE_INTERACTION ) { const data_id_t classifier_id = data_feature_get_classifier_data_id ( feature_ptr ); export_err |= xmi_interaction_writer_assemble_feature( &((*this_).interaction_writer), classifier_id, DATA_CLASSIFIER_TYPE_INTERACTION, feature_ptr ); } } TRACE_END_ERR( export_err ); return export_err; } int xmi_element_writer_end_feature( xmi_element_writer_t *this_, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ) { TRACE_BEGIN(); assert ( NULL != feature_ptr ); int export_err = 0; const data_feature_type_t feature_type = data_feature_get_main_type( feature_ptr ); if ( (*this_).mode == XMI_WRITER_PASS_BASE ) { /* determine nesting tag */ const char* owning_type; const int owning_err = xmi_type_converter_get_xmi_owning_property_of_feature( &((*this_).xmi_types), parent_type, feature_type, &owning_type ); if ( owning_err != 0 ) { /* The caller requested to write a feature to an illegal place */ TRACE_INFO("xmi_element_writer: request to write a feature to an illegal place!"); owning_type = XMI_ELEMENT_PART_FALLBACK_OWNED_FEATURE; } xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_END_TAG_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), owning_type ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_END_TAG_END ); } TRACE_END_ERR( export_err ); return export_err; } int xmi_element_writer_start_relationship( xmi_element_writer_t *this_, data_classifier_type_t host_type, const data_relationship_t *relation_ptr ) { TRACE_BEGIN(); assert ( NULL != relation_ptr ); /* NULL is allowed here: dest_classifier_ptr */ int export_err = 0; const char *const relation_name = data_relationship_get_name_const( relation_ptr ); const size_t relation_name_len = utf8string_get_length(relation_name); const data_id_t relation_id = data_relationship_get_data_id( relation_ptr ); const data_relationship_type_t relation_type = data_relationship_get_main_type( relation_ptr ); const xmi_element_info_t *relation_info; int map_err = xmi_element_info_map_get_relationship( &xmi_element_info_map_standard, (host_type==DATA_CLASSIFIER_TYPE_STATE), relation_type, &relation_info ); const bool is_annotated_element = (( host_type == DATA_CLASSIFIER_TYPE_COMMENT )&&( relation_type == DATA_RELATIONSHIP_TYPE_UML_DEPENDENCY )); if ( (*this_).mode == XMI_WRITER_PASS_BASE ) { if ( map_err != 0 ) { /* The caller requested to write a relationship of unknown type */ TRACE_INFO("xmi_element_writer: request to write a relationship of unknown type!") /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_WARNING ); /* inform the user via an XML comment: */ export_err |= xmi_atom_writer_report_unknown_relationship( &((*this_).atom_writer), relation_id, relation_type ); } /* determine nesting tag */ const char* nesting_property; const int nesting_err = xmi_type_converter_get_xmi_nesting_property_of_relationship( &((*this_).xmi_types), host_type, relation_type, &nesting_property ); if ( nesting_err != 0 ) { /* The caller requested to write a relationship to an illegal place */ TRACE_INFO("xmi_element_writer: request to write a relationship to an illegal place!") /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_WARNING ); /* inform the user via an XML comment: */ export_err |= xmi_atom_writer_report_illegal_location( &((*this_).atom_writer), relation_id, relation_type, host_type ); /* use a fallback */ nesting_property = XMI_ELEMENT_PART_FALLBACK_NESTING_ELEMENT; } export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_START_TAG_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), nesting_property ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_ATTR_SEPARATOR ); if ( is_annotated_element ) { const data_id_t to_classifier_id = data_relationship_get_to_classifier_data_id( relation_ptr ); const data_id_t to_feature_id = data_relationship_get_to_feature_data_id( relation_ptr ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_IDREF_START ); if ( data_id_is_valid( &to_feature_id ) ) { export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), to_feature_id ); } else { export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), to_classifier_id ); } export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_IDREF_END ); } else { /* write type attribute */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_TYPE_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_NS_UML ); const char* r_type = xmi_type_converter_get_xmi_type_of_relationship ( &((*this_).xmi_types), host_type, relation_type, XMI_SPEC_UML ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), r_type ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_TYPE_END ); /* write id attribute */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_ID_START ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer),relation_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_ID_END ); /* write name attribute */ if ( xmi_element_info_is_a_named_element( relation_info ) ) { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_NAME_START ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), relation_name ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_NAME_END ); } if ( NULL != xmi_element_info_get_additional_properties( relation_info ) ) { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), xmi_element_info_get_additional_properties( relation_info ) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_ATTR_SEPARATOR ); } } export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_START_TAG_END ); xml_writer_increase_indent ( &((*this_).xml_writer) ); /* write name comment */ if (( ! xmi_element_info_is_a_named_element( relation_info ) )&&( relation_name_len > 0 )) { export_err |= xmi_atom_writer_write_xmi_comment( &((*this_).atom_writer), relation_id, "name", relation_name ); } /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_EXPORTED ); } else if ( (*this_).mode == XMI_WRITER_PASS_PROFILE ) { /* write profile tag if sysml/standardprofile-only extention */ if ( xmi_type_converter_get_xmi_spec_of_relationship( &((*this_).xmi_types), relation_type ) == XMI_SPEC_STANDARD ) { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_EMPTY_TAG_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_NS_STDPROF ); const char* profile_type = xmi_type_converter_get_xmi_type_of_relationship ( &((*this_).xmi_types), host_type, relation_type, XMI_SPEC_STANDARD ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), profile_type ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_ATTR_SEPARATOR ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_ID_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), "1" ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer),relation_id ); /*export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), "#profile" );*/ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_ID_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI2_EXT_BASE_ELEMENT_START ); const char* base_type = xmi_type_converter_get_xmi_type_of_relationship ( &((*this_).xmi_types), host_type, relation_type, XMI_SPEC_UML ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), base_type ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI2_EXT_BASE_ELEMENT_MIDDLE ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer),relation_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI2_EXT_BASE_ELEMENT_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_EMPTY_TAG_END ); /* export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_COMMENT_START ); export_err |= xml_writer_write_plain_id( &((*this_).xml_writer), relation_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_COMMENT_END ); */ } } TRACE_END_ERR( export_err ); return export_err; } int xmi_element_writer_assemble_relationship( xmi_element_writer_t *this_, const data_classifier_t *host, const data_relationship_t *relation_ptr, const data_classifier_t *from_c, const data_feature_t *from_f, const data_classifier_t *to_c, const data_feature_t *to_f ) { TRACE_BEGIN(); assert ( NULL != relation_ptr ); assert ( NULL != from_c ); assert ( NULL != to_c ); const data_classifier_type_t from_c_type = data_classifier_get_main_type( from_c ); const data_feature_type_t from_f_type = (from_f==NULL) ? DATA_FEATURE_TYPE_VOID : data_feature_is_valid(from_f) ? data_feature_get_main_type( from_f ) : DATA_FEATURE_TYPE_VOID; const data_classifier_type_t to_c_type = data_classifier_get_main_type( to_c ); const data_feature_type_t to_f_type = (to_f==NULL) ? DATA_FEATURE_TYPE_VOID : data_feature_is_valid(to_f) ? data_feature_get_main_type( to_f ) : DATA_FEATURE_TYPE_VOID; data_id_t host_id; data_classifier_type_t host_type; bool host_is_source; if ( host == NULL ) { host_id = DATA_ID_VOID; host_type = DATA_CLASSIFIER_TYPE_PACKAGE; /* a uml:Model is a uml:Package*/ host_is_source = false; } else { host_id = data_classifier_get_data_id( host ); host_type = data_classifier_get_main_type( host ); host_is_source = ( data_classifier_get_row_id( from_c ) == data_classifier_get_row_id( host ) ); } const int export_err = xmi_element_writer_private_assemble_relationship( this_, host_type, host_is_source, host_id, relation_ptr, from_c_type, from_f_type, to_c_type, to_f_type ); TRACE_END_ERR( export_err ); return export_err; } int xmi_element_writer_private_assemble_relationship( xmi_element_writer_t *this_, data_classifier_type_t host_type, bool host_is_source, data_id_t host_id, const data_relationship_t *relation_ptr, data_classifier_type_t from_c_type, data_feature_type_t from_f_type, data_classifier_type_t to_c_type, data_feature_type_t to_f_type ) { TRACE_BEGIN(); assert ( NULL != relation_ptr ); /* NULL is allowed here: dest_classifier_ptr */ int export_err = 0; const data_id_t relation_id = data_relationship_get_data_id( relation_ptr ); const char *const relation_descr = data_relationship_get_description_const( relation_ptr ); const size_t relation_descr_len = utf8string_get_length(relation_descr); const data_id_t from_classifier_id = data_relationship_get_from_classifier_data_id( relation_ptr ); const data_id_t from_feature_id = data_relationship_get_from_feature_data_id( relation_ptr ); const data_id_t from_end_id = data_id_is_valid( &from_feature_id ) ? from_feature_id : from_classifier_id; const data_id_t to_classifier_id = data_relationship_get_to_classifier_data_id( relation_ptr ); const data_id_t to_feature_id = data_relationship_get_to_feature_data_id( relation_ptr ); const data_id_t to_end_id = data_id_is_valid( &to_feature_id ) ? to_feature_id : to_classifier_id; const data_relationship_type_t relation_type = data_relationship_get_main_type( relation_ptr ); const xmi_element_info_t *relation_info; int map_err = xmi_element_info_map_get_relationship( &xmi_element_info_map_standard, (host_type==DATA_CLASSIFIER_TYPE_STATE), relation_type, &relation_info ); if ( map_err != 0 ) { /* The caller requested to write a relationship of unknown type, error was already logged at xmi_element_writer_start_relationship */ TRACE_INFO_INT("xmi_element_writer: request to write a relationship of unknown type", relation_type ); } const xmi_element_info_t *from_end_info = NULL; if (from_f_type == DATA_FEATURE_TYPE_VOID) { map_err = xmi_element_info_map_get_classifier( &xmi_element_info_map_standard, host_type /*wrong host here*/, from_c_type, &from_end_info ); if ( map_err != 0 ) { TRACE_INFO_INT("xmi_element_writer: request to write a relationship from-end of unknown c-type", from_c_type ); } } else { map_err = xmi_element_info_map_get_feature( &xmi_element_info_map_standard, from_c_type, from_f_type, &from_end_info ); if ( map_err != 0 ) { TRACE_INFO_INT("xmi_element_writer: request to write a relationship from-end of unknown f-type", from_f_type ); } } assert ( from_end_info != NULL ); const xmi_element_info_t *to_end_info = NULL; if (to_f_type == DATA_FEATURE_TYPE_VOID) { map_err = xmi_element_info_map_get_classifier( &xmi_element_info_map_standard, host_type /*wrong host here*/, to_c_type, &to_end_info ); if ( map_err != 0 ) { TRACE_INFO_INT("xmi_element_writer: request to write a relationship to-end of unknown c-type", to_c_type ); } } else { map_err = xmi_element_info_map_get_feature( &xmi_element_info_map_standard, to_c_type, to_f_type, &to_end_info ); if ( map_err != 0 ) { TRACE_INFO_INT("xmi_element_writer: request to write a relationship to-end of unknown f-type", to_f_type ); } } assert ( to_end_info != NULL ); /* evaluate if xmi requires to generate fake properties */ const bool fake_property_ends = xmi_element_info_is_a_association( relation_info ); const bool fake_property_at_from_end = fake_property_ends && ( ! xmi_element_info_is_a_property( from_end_info ) ); const bool fake_property_at_to_end = fake_property_ends && ( ! xmi_element_info_is_a_property( to_end_info ) ); /* check if suppress source end */ const bool suppress_source = (( relation_type == DATA_RELATIONSHIP_TYPE_UML_GENERALIZATION ) || ( relation_type == DATA_RELATIONSHIP_TYPE_UML_EXTEND ) || ( relation_type == DATA_RELATIONSHIP_TYPE_UML_INCLUDE )) && host_is_source; const bool is_annotated_element = (( host_type == DATA_CLASSIFIER_TYPE_COMMENT )&&( relation_type == DATA_RELATIONSHIP_TYPE_UML_DEPENDENCY )); const bool is_message = ( xmi_element_info_is_a_message ( relation_info ) ); if (( host_type == DATA_CLASSIFIER_TYPE_INTERACTION )&&( is_message )) { export_err |= xmi_interaction_writer_assemble_relationship( &((*this_).interaction_writer), host_id, DATA_CLASSIFIER_TYPE_INTERACTION, /* fake host type */ relation_ptr, DATA_CLASSIFIER_TYPE_INTERACTION, /* fake from classifier type */ DATA_FEATURE_TYPE_LIFELINE, /* guess from feature type */ DATA_CLASSIFIER_TYPE_INTERACTION, /* fake to classifier type */ DATA_FEATURE_TYPE_LIFELINE /* guess to feature type */ ); } else if (( (*this_).mode == XMI_WRITER_PASS_BASE )&&( ! is_annotated_element )) { if ( 0 != relation_descr_len ) { export_err |= xmi_atom_writer_write_xmi_comment( &((*this_).atom_writer), relation_id, "specification", relation_descr ); } /* source */ if ( ! suppress_source ) { /* determine from type tag */ const char* from_type_tag; const int from_type_err = xmi_type_converter_get_xmi_from_property_of_relationship ( &((*this_).xmi_types), host_type, relation_type, from_c_type, from_f_type, &from_type_tag ); if ( from_type_err != 0 ) { /* The caller requested to write a relationship of illegal source end type */ TRACE_INFO("xmi_element_writer: request to write a relationship connecting an illegal source end type!") /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_WARNING ); /* inform the user via an XML comment: */ export_err |= xmi_atom_writer_report_illegal_relationship_end ( &((*this_).atom_writer), relation_id, relation_type, host_type, true /* = from_end */, from_c_type, from_f_type ); } export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_EMPTY_TAG_START ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), from_type_tag ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_ATTR_SEPARATOR ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_IDREF_START ); if ( fake_property_at_from_end ) { export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), relation_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_ELEMENT_PART_ID_FRAGMENT_SOURCE_END ); } else { export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), from_end_id ); } export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_IDREF_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_EMPTY_TAG_END ); if ( fake_property_at_from_end ) { export_err |= xmi_element_writer_private_fake_memberend ( this_, relation_id, relation_type, from_end_id, from_c_type, from_f_type, false /* = is_target_end */ ); } } /* destination */ /* determine from type tag */ const char* to_type_tag; const int to_type_err = xmi_type_converter_get_xmi_to_property_of_relationship ( &((*this_).xmi_types), host_type, relation_type, to_c_type, to_f_type, &to_type_tag ); if ( to_type_err != 0 ) { /* The caller requested to write a relationship of illegal target end type */ TRACE_INFO("xmi_element_writer: request to write a relationship connecting an illegal target end type!") /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_WARNING ); /* inform the user via an XML comment: */ export_err |= xmi_atom_writer_report_illegal_relationship_end ( &((*this_).atom_writer), relation_id, relation_type, host_type, false /* = from_end */, to_c_type, to_f_type ); } export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_EMPTY_TAG_START ); export_err |= xml_writer_write_xml_enc ( &((*this_).xml_writer), to_type_tag ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_ATTR_SEPARATOR ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_IDREF_START ); if ( fake_property_at_to_end ) { export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), relation_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_ELEMENT_PART_ID_FRAGMENT_TARGET_END ); } else { export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), to_end_id ); } export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_IDREF_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_EMPTY_TAG_END ); if ( fake_property_at_to_end ) { export_err |= xmi_element_writer_private_fake_memberend ( this_, relation_id, relation_type, to_end_id, to_c_type, to_f_type, true /* = is_target_end */ ); } /* generate extension point for use cases */ if ( relation_type == DATA_RELATIONSHIP_TYPE_UML_EXTEND ) { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_EMPTY_TAG_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), "extensionLocation" ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_ATTR_SEPARATOR ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_IDREF_START ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), to_end_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), "#extensionpoint" ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_IDREF_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_EMPTY_TAG_END ); } } TRACE_END_ERR( export_err ); return export_err; } int xmi_element_writer_end_relationship( xmi_element_writer_t *this_, data_classifier_type_t host_type, const data_relationship_t *relation_ptr ) { TRACE_BEGIN(); assert ( NULL != relation_ptr ); /* NULL is allowed here: dest_classifier_ptr */ int export_err = 0; const data_relationship_type_t relation_type = data_relationship_get_main_type( relation_ptr ); if ( (*this_).mode == XMI_WRITER_PASS_BASE ) { /* determine nesting tag */ const char* nesting_property; const int nesting_err = xmi_type_converter_get_xmi_nesting_property_of_relationship( &((*this_).xmi_types), host_type, relation_type, &nesting_property ); if ( nesting_err != 0 ) { /* use a fallback */ nesting_property = XMI_ELEMENT_PART_FALLBACK_NESTING_ELEMENT; } xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_END_TAG_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), nesting_property ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_END_TAG_END ); } TRACE_END_ERR( export_err ); return export_err; } int xmi_element_writer_start_diagram( xmi_element_writer_t *this_, const data_diagram_t *diag_ptr ) { TRACE_BEGIN(); const int export_err = -1; TSLOG_WARNING( "xmi_element_writer_t does not export data_diagram_t" ); TRACE_END_ERR( export_err ); return export_err; } int xmi_element_writer_assemble_diagram( xmi_element_writer_t *this_, const data_diagram_t *parent, const data_diagram_t *diag_ptr, const char *diagram_file_base_name ) { TRACE_BEGIN(); const int export_err = -1; TSLOG_WARNING( "xmi_element_writer_t does not export data_diagram_t" ); TRACE_END_ERR( export_err ); return export_err; } int xmi_element_writer_end_diagram( xmi_element_writer_t *this_, const data_diagram_t *diag_ptr ) { TRACE_BEGIN(); const int export_err = -1; TSLOG_WARNING( "xmi_element_writer_t does not export data_diagram_t" ); TRACE_END_ERR( export_err ); return export_err; } int xmi_element_writer_start_diagramelement( xmi_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr ) { TRACE_BEGIN(); const int export_err = -1; TSLOG_WARNING( "xmi_element_writer_t does not export data_diagramelement_t" ); TRACE_END_ERR( export_err ); return export_err; } int xmi_element_writer_assemble_diagramelement( xmi_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr, const data_classifier_t *occurrence, const data_feature_t *feat_occur ) { TRACE_BEGIN(); /* NULL is allowed here: feat_occur */ const int export_err = -1; TSLOG_WARNING( "xmi_element_writer_t does not export data_diagramelement_t" ); TRACE_END_ERR( export_err ); return export_err; } int xmi_element_writer_end_diagramelement( xmi_element_writer_t *this_, const data_diagram_t *parent, const data_diagramelement_t *diagramelement_ptr ) { TRACE_BEGIN(); const int export_err = -1; TSLOG_WARNING( "xmi_element_writer_t does not export data_diagramelement_t" ); TRACE_END_ERR( export_err ); return export_err; } int xmi_element_writer_end_main( xmi_element_writer_t *this_ ) { TRACE_BEGIN(); int export_err = 0; xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI2_UML_MODEL_END ); TRACE_END_ERR( export_err ); return export_err; } int xmi_element_writer_write_footer( xmi_element_writer_t *this_ ) { TRACE_BEGIN(); int export_err = 0; xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI2_DOC_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); TRACE_END_ERR( export_err ); return export_err; } int xmi_element_writer_private_fake_memberend ( xmi_element_writer_t *this_, data_id_t relationship_id, data_relationship_type_t relationship_type, data_id_t end_object_id, data_classifier_type_t end_classifier_type, data_feature_type_t end_feature_type, bool is_target_end ) { TRACE_BEGIN(); int export_err = 0; const bool is_composition = ( relationship_type == DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT ) /* fallback relationship */ ||( relationship_type == DATA_RELATIONSHIP_TYPE_UML_COMPOSITION ); const bool is_aggregation = ( relationship_type == DATA_RELATIONSHIP_TYPE_UML_AGGREGATION ); const xmi_element_info_t *classifier_info; int map_err = xmi_element_info_map_get_classifier( &xmi_element_info_map_standard, DATA_CLASSIFIER_TYPE_PACKAGE, /* if state or activity context does not matter here */ end_classifier_type, &classifier_info ); if ( map_err != 0 ) { TRACE_INFO_INT("xmi_element_writer: request to write a member end of unknown type", end_classifier_type ) } assert ( classifier_info != NULL ); /* begin start member-end element */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_START_TAG_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_ELEMENT_PART_ELEMENT_OWNED_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_ATTR_SEPARATOR ); /* write type attribute */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_TYPE_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_NS_UML ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_ELEMENT_PART_TYPE_PROPERTY ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_TYPE_END ); /* write id attribute */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_ID_START ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), relationship_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), ( is_target_end ? XMI_ELEMENT_PART_ID_FRAGMENT_TARGET_END : XMI_ELEMENT_PART_ID_FRAGMENT_SOURCE_END ) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_ID_END ); /* write association attribute */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_ELEMENT_PART_PROPERTY_ASSOCIATION_ATTRIBUTE ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_ATTR_VALUE_START ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), relationship_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_ATTR_VALUE_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_ATTR_SEPARATOR ); /* write aggregation attribute */ if (( is_composition || is_aggregation )&& is_target_end ) { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_ELEMENT_PART_PROPERTY_AGGREGATION_ATTRIBUTE ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_ATTR_VALUE_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), is_composition ? XMI_ELEMENT_PART_PROPERTY_AGGREGATION_COMPOSITE : XMI_ELEMENT_PART_PROPERTY_AGGREGATION_SHARED ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_ATTR_VALUE_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_ATTR_SEPARATOR ); } /* end start member-end element */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_START_TAG_END ); xml_writer_increase_indent ( &((*this_).xml_writer) ); /* start type element */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_EMPTY_TAG_START ); if (( end_feature_type == DATA_FEATURE_TYPE_PROVIDED_INTERFACE )||( end_feature_type == DATA_FEATURE_TYPE_REQUIRED_INTERFACE ) ||(( end_feature_type == DATA_FEATURE_TYPE_VOID )&&( end_classifier_type == DATA_CLASSIFIER_TYPE_INTERFACE ))) { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_ELEMENT_PART_PROPERTY_INTERFACE_ELEMENT ); } else if (( end_feature_type == DATA_FEATURE_TYPE_VOID ) && xmi_element_info_is_a_class( classifier_info ) ) { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_ELEMENT_PART_PROPERTY_CLASS_ELEMENT ); } else { export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_ELEMENT_PART_PROPERTY_TYPE_ELEMENT ); } export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_ATTR_SEPARATOR ); /* write id-ref attribute */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_IDREF_START ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), end_object_id ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_XML_ATTR_IDREF_END ); /* end type element */ export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_EMPTY_TAG_END ); /* end member-end element */ xml_writer_decrease_indent ( &((*this_).xml_writer) ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_NL ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_END_TAG_START ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XMI_ELEMENT_PART_ELEMENT_OWNED_END ); export_err |= xml_writer_write_plain ( &((*this_).xml_writer), XML_WRITER_END_TAG_END ); TRACE_END_ERR( export_err ); return export_err; } /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/xmi/xmi_interaction_writer.c000066400000000000000000000531161415120503000245710ustar00rootroot00000000000000/* File: xmi_interaction_writer.c; Copyright and License: see below */ #include "xmi/xmi_interaction_writer.h" #include "xmi/xmi_element_info_map.h" #include "xmi/xmi_element_info.h" #include "xmi/xmi_element_part.h" #include "xmi/xmi_xml.h" #include "util/string/utf8string.h" #include "data_id.h" #include "data_classifier_type.h" #include "trace.h" #include "tslog.h" #include #include #include /* Note: when writing, each method typically starts with writing a newline, it does not end with writing a newline. */ void xmi_interaction_writer_init ( xmi_interaction_writer_t *this_, data_stat_t *io_export_stat, xml_writer_t *out_writer ) { TRACE_BEGIN(); assert( NULL != io_export_stat ); assert( NULL != out_writer ); (*this_).mode = XMI_WRITER_PASS_BASE; (*this_).export_stat = io_export_stat; (*this_).xml_writer = out_writer; xmi_type_converter_init( &((*this_).xmi_types) ); xmi_atom_writer_init( &((*this_).atom_writer), (*this_).xml_writer ); TRACE_END(); } void xmi_interaction_writer_destroy( xmi_interaction_writer_t *this_ ) { TRACE_BEGIN(); xmi_atom_writer_destroy( &((*this_).atom_writer) ); xmi_type_converter_destroy( &((*this_).xmi_types) ); (*this_).xml_writer = NULL; /* unreference */ (*this_).export_stat = NULL; /* unreference */ TRACE_END(); } #if 0 int xmi_interaction_writer_start_diagram( xmi_interaction_writer_t *this_, data_classifier_type_t parent_type, const data_diagram_t *diagram_ptr ) { TRACE_BEGIN(); assert ( NULL != diagram_ptr ); int export_err = 0; const char *const diagram_name = data_diagram_get_name_const(diagram_ptr); const char *const diagram_descr = data_diagram_get_description_const(diagram_ptr); const size_t diagram_descr_len = utf8string_get_length(diagram_descr); const data_id_t diagram_id = data_diagram_get_data_id(diagram_ptr); if ( (*this_).mode == XMI_WRITER_PASS_BASE ) { /* determine nesting tag */ const char* nesting_property; const int nesting_err = xmi_type_converter_get_xmi_nesting_property_of_classifier( &((*this_).xmi_types), parent_type, DATA_CLASSIFIER_TYPE_INTERACTION, /* fake child type */ &nesting_property ); if ( nesting_err != 0 ) { /* The caller requested to write an interaction to an illegal place. */ /* This should not have happened, because latest the model is a valid nesting container */ TRACE_INFO("xmi_element_writer: request to write an interaction to an illegal place!") assert(false); /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_CLASSIFIER, DATA_STAT_SERIES_WARNING ); /* inform the user via an XML comment: */ export_err |= xmi_atom_writer_report_illegal_container( &((*this_).atom_writer), diagram_id, DATA_CLASSIFIER_TYPE_INTERACTION, /* fake child type */ parent_type ); /* use a fallback */ nesting_property = XMI_ELEMENT_PART_FALLBACK_NESTING_ELEMENT; } /* write nesting tag */ export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_NL ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_START_TAG_START ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, nesting_property ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_ATTR_SEPARATOR ); xml_writer_increase_indent ( (*this_).xml_writer ); /* write type attribute */ export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_ATTR_TYPE_START ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_NS_UML ); /* TODO possibly a uml:Collaboration needs to be placed around the DATA_CLASSIFIER_TYPE_INTERACTION? */ const char* c_type = xmi_type_converter_get_xmi_type_of_classifier ( &((*this_).xmi_types), parent_type, DATA_CLASSIFIER_TYPE_INTERACTION, /* fake child type */ XMI_SPEC_UML ); export_err |= xml_writer_write_xml_enc ( (*this_).xml_writer, c_type ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_ATTR_TYPE_END ); /* write id attribute */ export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_ATTR_ID_START ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), diagram_id ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_ATTR_ID_END ); /* write name attribute */ export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_ATTR_NAME_START ); export_err |= xml_writer_write_xml_enc ( (*this_).xml_writer, diagram_name ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_ATTR_NAME_END ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_START_TAG_END ); /* write real id comment */ export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_COMMENT_START ); export_err |= xml_writer_write_plain_id( (*this_).xml_writer, diagram_id ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_COMMENT_END ); /* write description */ if ( 0 != diagram_descr_len ) { export_err |= xmi_atom_writer_write_xmi_comment( &((*this_).atom_writer), diagram_id, "specification", diagram_descr ); } /* update export statistics, report as classifier because DATA_CLASSIFIER_TYPE_INTERACTION is a classifier */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_CLASSIFIER, DATA_STAT_SERIES_EXPORTED ); } TRACE_END_ERR( export_err ); return export_err; } int xmi_interaction_writer_end_diagram( xmi_interaction_writer_t *this_, data_classifier_type_t parent_type ) { TRACE_BEGIN(); int export_err = 0; if ( (*this_).mode == XMI_WRITER_PASS_BASE ) { /* determine nesting tag */ const char* nesting_property; const int nesting_err = xmi_type_converter_get_xmi_nesting_property_of_classifier( &((*this_).xmi_types), parent_type, DATA_CLASSIFIER_TYPE_INTERACTION, /* fake child type */ &nesting_property ); if ( nesting_err != 0 ) { /* The caller requested to write a classifier to an illegal place */ /* use a fallback */ nesting_property = XMI_ELEMENT_PART_FALLBACK_NESTING_ELEMENT; } /* adjust indentation, write end tag */ xml_writer_decrease_indent ( (*this_).xml_writer ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_NL ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_END_TAG_START ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, nesting_property ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_END_TAG_END ); } TRACE_END_ERR( export_err ); return export_err; } #endif int xmi_interaction_writer_assemble_feature( xmi_interaction_writer_t *this_, data_id_t reference_id, data_classifier_type_t parent_type, const data_feature_t *feature_ptr ) { TRACE_BEGIN(); assert ( NULL != feature_ptr ); int export_err = 0; const data_id_t feature_id = data_feature_get_data_id( feature_ptr ); if ( (*this_).mode == XMI_WRITER_PASS_BASE ) { export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_NL ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_EMPTY_TAG_START ); export_err |= xml_writer_write_xml_enc ( (*this_).xml_writer, "represents" ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_ATTR_SEPARATOR ); /* write type attribute */ export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_ATTR_TYPE_START ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_NS_UML ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, "Property" ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_ATTR_TYPE_END ); /* write id attribute */ export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_ATTR_ID_START ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), feature_id ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, "#ref" ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_ATTR_ID_END ); /* write lifeline id attribute */ export_err |= xml_writer_write_plain ( (*this_).xml_writer, "type=\"" ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), reference_id ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\" " ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_EMPTY_TAG_END ); } TRACE_END_ERR( export_err ); return export_err; } int xmi_interaction_writer_assemble_relationship( xmi_interaction_writer_t *this_, data_id_t interaction_id, data_classifier_type_t parent_type, const data_relationship_t *relation_ptr, data_classifier_type_t from_c_type, data_feature_type_t from_f_type, data_classifier_type_t to_c_type, data_feature_type_t to_f_type ) { TRACE_BEGIN(); assert ( NULL != relation_ptr ); /* NULL is allowed here: dest_classifier_ptr */ int export_err = 0; const data_id_t relation_id = data_relationship_get_data_id( relation_ptr ); const char *const relation_descr = data_relationship_get_description_const( relation_ptr ); const size_t relation_descr_len = utf8string_get_length(relation_descr); const data_id_t from_classifier_id = data_relationship_get_from_classifier_data_id( relation_ptr ); const data_id_t from_feature_id = data_relationship_get_from_feature_data_id( relation_ptr ); const data_id_t to_classifier_id = data_relationship_get_to_classifier_data_id( relation_ptr ); const data_id_t to_feature_id = data_relationship_get_to_feature_data_id( relation_ptr ); const data_relationship_type_t relation_type = data_relationship_get_main_type( relation_ptr ); if ( (*this_).mode == XMI_WRITER_PASS_BASE ) { if ( 0 != relation_descr_len ) { export_err |= xmi_atom_writer_write_xmi_comment( &((*this_).atom_writer), relation_id, "specification", relation_descr ); } /* source */ /* determine from type tag */ const char* from_type_tag; const int from_type_err = xmi_type_converter_get_xmi_from_property_of_relationship ( &((*this_).xmi_types), parent_type, relation_type, from_c_type, from_f_type, &from_type_tag ); if ( from_type_err != 0 ) { /* The caller requested to write a relationship of illegal source end type */ TRACE_INFO("xmi_interaction_writer: request to write a relationship connecting an illegal source end type!") /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_WARNING ); /* inform the user via an XML comment: */ export_err |= xmi_atom_writer_report_illegal_relationship_end ( &((*this_).atom_writer), relation_id, relation_type, parent_type, true /* = from_end */, from_c_type, from_f_type ); } export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_NL ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_EMPTY_TAG_START ); export_err |= xml_writer_write_xml_enc ( (*this_).xml_writer, from_type_tag ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_ATTR_SEPARATOR ); /* write type attribute */ export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_ATTR_TYPE_START ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_NS_UML ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_ELEMENT_PART_TYPE_MSG_OCCURRENCE_SPEC ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_ATTR_TYPE_END ); /* write id attribute */ export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_ATTR_ID_START ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), relation_id ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_ELEMENT_PART_ID_FRAGMENT_SOURCE_END ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_ATTR_ID_END ); /* write lifeline id attribute */ export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_ELEMENT_PART_PROPERTY_OCCURRENCE_SPEC_COVERED ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_ATTR_VALUE_START ); if ( data_id_is_valid( &from_feature_id ) ) { export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), from_feature_id ); } else { export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), from_classifier_id ); } export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_ATTR_VALUE_END ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_ATTR_SEPARATOR ); /* write lifeline id attribute */ export_err |= xml_writer_write_plain ( (*this_).xml_writer, "enclosingInteraction=\"" ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), interaction_id ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\" " ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_EMPTY_TAG_END ); /* destination */ /* determine from type tag */ const char* to_type_tag; const int to_type_err = xmi_type_converter_get_xmi_to_property_of_relationship ( &((*this_).xmi_types), parent_type, relation_type, to_c_type, to_f_type, &to_type_tag ); if ( to_type_err != 0 ) { /* The caller requested to write a relationship of illegal target end type */ TRACE_INFO("xmi_interaction_writer: request to write a relationship connecting an illegal target end type!") /* update export statistics */ data_stat_inc_count ( (*this_).export_stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_WARNING ); /* inform the user via an XML comment: */ export_err |= xmi_atom_writer_report_illegal_relationship_end ( &((*this_).atom_writer), relation_id, relation_type, parent_type, false /* = from_end */, to_c_type, to_f_type ); } export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_NL ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_EMPTY_TAG_START ); export_err |= xml_writer_write_xml_enc ( (*this_).xml_writer, to_type_tag ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_ATTR_SEPARATOR ); /* write type attribute */ export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_ATTR_TYPE_START ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_NS_UML ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_ELEMENT_PART_TYPE_MSG_OCCURRENCE_SPEC ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_ATTR_TYPE_END ); /* write id attribute */ export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_ATTR_ID_START ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), relation_id ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_ELEMENT_PART_ID_FRAGMENT_TARGET_END ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_XML_ATTR_ID_END ); /* write lifeline id attribute */ export_err |= xml_writer_write_plain ( (*this_).xml_writer, XMI_ELEMENT_PART_PROPERTY_OCCURRENCE_SPEC_COVERED ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_ATTR_VALUE_START ); if ( data_id_is_valid( &to_feature_id ) ) { export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), to_feature_id ); } else { export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), to_classifier_id ); } export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_ATTR_VALUE_END ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_ATTR_SEPARATOR ); /* write lifeline id attribute */ export_err |= xml_writer_write_plain ( (*this_).xml_writer, "enclosingInteraction=\"" ); export_err |= xmi_atom_writer_encode_xmi_id( &((*this_).atom_writer), interaction_id ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, "\" " ); export_err |= xml_writer_write_plain ( (*this_).xml_writer, XML_WRITER_EMPTY_TAG_END ); } TRACE_END_ERR( export_err ); return export_err; } /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/xmi/xmi_type_converter.c000066400000000000000000000764471415120503000237420ustar00rootroot00000000000000/* File: xmi_type_converter.c; Copyright and License: see below */ #include "xmi/xmi_type_converter.h" #include "xmi/xmi_element_info_map.h" #include "trace.h" #include "tslog.h" #include void xmi_type_converter_init ( xmi_type_converter_t *this_ ) { TRACE_BEGIN(); TRACE_END(); } void xmi_type_converter_destroy( xmi_type_converter_t *this_ ) { TRACE_BEGIN(); TRACE_END(); } /* ================================ CLASSIFIER ================================ */ xmi_spec_t xmi_type_converter_get_xmi_spec_of_classifier ( xmi_type_converter_t *this_, data_classifier_type_t c_type ) { TRACE_BEGIN(); const xmi_element_info_t *classifier_info = NULL; int map_err = xmi_element_info_map_get_classifier( &xmi_element_info_map_standard, DATA_CLASSIFIER_TYPE_PACKAGE, /*this parameter does not matter for this use case*/ c_type, &classifier_info ); if ( map_err != 0 ) { TSLOG_WARNING_INT("xmi_element_info_map_get_classifier could not map unknown type", c_type ); } assert ( classifier_info != NULL ); const xmi_spec_t result = (*classifier_info).specification; TRACE_END(); return result; } const char* xmi_type_converter_get_xmi_type_of_classifier ( xmi_type_converter_t *this_, data_classifier_type_t parent_type, data_classifier_type_t c_type, xmi_spec_t spec ) { TRACE_BEGIN(); const xmi_element_info_t *classifier_info = NULL; int map_err = xmi_element_info_map_get_classifier( &xmi_element_info_map_standard, parent_type, c_type, &classifier_info ); if ( map_err != 0 ) { TSLOG_WARNING_INT("xmi_element_info_map_get_classifier could not map unknown type", c_type ); } assert ( classifier_info != NULL ); const char* result = (( (spec & (XMI_SPEC_SYSML|XMI_SPEC_STANDARD)) != 0 )&&( (*classifier_info).profile_name != NULL )) ? (*classifier_info).profile_name : (*classifier_info).base_name; assert ( result != NULL ); TRACE_END(); return result; } int xmi_type_converter_get_xmi_nesting_property_of_classifier ( xmi_type_converter_t *this_, data_classifier_type_t parent_type, data_classifier_type_t child_type, char const * *out_xmi_name ) { TRACE_BEGIN(); assert( out_xmi_name != NULL ); const char* result = NULL; const xmi_element_info_t *parent_info = NULL; int map_err = xmi_element_info_map_get_classifier( &xmi_element_info_map_standard, DATA_CLASSIFIER_TYPE_PACKAGE, /*TODO: fix guess*/ parent_type, &parent_info ); if ( map_err != 0 ) { TSLOG_WARNING_INT("xmi_element_info_map_get_classifier could not map unknown type", parent_type ); } assert ( parent_info != NULL ); const bool p_is_state = ( parent_type == DATA_CLASSIFIER_TYPE_STATE ); const bool p_is_activity = ( parent_type == DATA_CLASSIFIER_TYPE_ACTIVITY ); const bool p_is_interruptable_region = ( parent_type == DATA_CLASSIFIER_TYPE_DYN_INTERRUPTABLE_REGION ); const bool p_is_interaction = ( parent_type == DATA_CLASSIFIER_TYPE_INTERACTION ); const xmi_element_info_t *child_info = NULL; map_err = xmi_element_info_map_get_classifier( &xmi_element_info_map_standard, parent_type, child_type, &child_info ); if ( map_err != 0 ) { TSLOG_WARNING_INT("xmi_element_info_map_get_classifier could not map unknown type", child_type ); } assert ( child_info != NULL ); if ( xmi_element_info_is_a_package(parent_info) && xmi_element_info_is_a_packageable_element(child_info) ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 12.4.5.6 */ result = "packagedElement"; } else if ( xmi_element_info_is_a_comment(child_info) ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 7.2 */ /* any element can own 0..* comments */ result = "ownedComment"; } else if ( xmi_element_info_is_a_classifier(parent_info) && (child_type==DATA_CLASSIFIER_TYPE_USE_CASE) ) { /* spec: https://www.omg.org/spec/UML/20161101/UML.xmi (v2.5.1) pkg: Classifier */ result = "ownedUseCase"; } else if ( xmi_element_info_is_a_node(parent_info) && xmi_element_info_is_a_node(child_info) ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 19.5.10.5 */ result = "nestedNode"; } else if ( p_is_activity && xmi_element_info_is_a_activity_node(child_info) ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 15.7.1.5 */ result = "node"; } else if ( p_is_activity && xmi_element_info_is_a_activity_group(child_info) ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 15.7.1.5 */ result = "group"; } else if ( p_is_interruptable_region && xmi_element_info_is_a_activity_node(child_info) ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 15.7.19.4 */ result = "node"; } else if ( xmi_element_info_is_a_behaviored_classifier(parent_info) && xmi_element_info_is_a_behavior(child_info) ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 10.5.1 */ result = "ownedBehavior"; } else if ( xmi_element_info_is_a_class(parent_info) && xmi_element_info_is_a_classifier(child_info) ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 11.8.3.6 */ result = "nestedClassifier"; } else if ( xmi_element_info_is_a_artifact(parent_info) && xmi_element_info_is_a_artifact(child_info) ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 19.5.1.6 */ result = "nestedArtifact"; } else if ( p_is_state && xmi_element_info_is_a_vertex(child_info) ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 14.5.8 (note: states have an implicit Region) */ result = "subvertex"; } else if ( p_is_interaction && xmi_element_info_is_a_interaction_fragment(child_info) ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 17.12.11.4 */ result = "fragment"; } *out_xmi_name = (result==NULL) ? "" : result; const int result_err = (result==NULL) ? -1 : 0; TRACE_END_ERR( result_err ); return result_err; } int xmi_type_converter_get_xmi_owning_property_of_feature ( xmi_type_converter_t *this_, data_classifier_type_t parent_type, data_feature_type_t feature_type, char const * *out_xmi_name ) { TRACE_BEGIN(); assert( out_xmi_name != NULL ); const char* result = NULL; int result_err = -1; const xmi_element_info_t *parent_info = NULL; int map_err = xmi_element_info_map_get_classifier( &xmi_element_info_map_standard, DATA_CLASSIFIER_TYPE_PACKAGE, /*TODO: fix guess*/ parent_type, &parent_info ); if ( map_err != 0 ) { TSLOG_WARNING_INT("xmi_element_info_map_get_classifier could not map unknown type", parent_type ); } assert ( parent_info != NULL ); switch ( feature_type ) { case DATA_FEATURE_TYPE_PROPERTY: { const bool p_is_interface = ( parent_type == DATA_CLASSIFIER_TYPE_INTERFACE ); /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 11.8.3.6 */ /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 10.5.5.4 */ result = "ownedAttribute"; result_err = ( xmi_element_info_is_a_class(parent_info) || p_is_interface ) ? 0 : -1; } break; case DATA_FEATURE_TYPE_OPERATION: { const bool p_is_interface = ( parent_type == DATA_CLASSIFIER_TYPE_INTERFACE ); /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 11.8.3.6 */ /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 10.5.5.4 */ result = "ownedOperation"; result_err = ( xmi_element_info_is_a_class(parent_info) || p_is_interface ) ? 0 : -1; } break; case DATA_FEATURE_TYPE_PORT: /* or */ case DATA_FEATURE_TYPE_IN_PORT_PIN: /* or */ case DATA_FEATURE_TYPE_OUT_PORT_PIN: { const bool is_behavioral_parent = data_classifier_type_is_behavioral( parent_type ); if ( is_behavioral_parent ) { const bool p_is_activity_or_group = ( parent_type == DATA_CLASSIFIER_TYPE_ACTIVITY )||( parent_type == DATA_CLASSIFIER_TYPE_DYN_INTERRUPTABLE_REGION ); /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 15.7.1.5 */ result = "node"; result_err = p_is_activity_or_group ? 0 : -1; } else { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF ch 11.8.13.5 */ result = "ownedPort"; result_err = xmi_element_info_is_a_encapsulated_classifier(parent_info) ? 0 : -1; /*TODO ownedPort is a derived value*/ } } break; case DATA_FEATURE_TYPE_LIFELINE: { const bool p_is_interaction = ( parent_type == DATA_CLASSIFIER_TYPE_INTERACTION ); /* spec: https://www.omg.org/spec/UML/2.5.1/PDF 17.3.2 */ result = "lifeline"; result_err = p_is_interaction ? 0 : -1; /* note, DATA_CLASSIFIER_TYPE_INTERACTION is a fake type - only here, lifelines are valid. */ } break; case DATA_FEATURE_TYPE_PROVIDED_INTERFACE: { const bool p_is_component = ( parent_type == DATA_CLASSIFIER_TYPE_COMPONENT ) ||( parent_type == DATA_CLASSIFIER_TYPE_PART ); /* spec: https://www.omg.org/spec/UML/2.5.1/PDF ch 11.6.2 */ result = "provided"; result_err = p_is_component ? 0 : -1; /*TODO provided is a derived value*/ } break; case DATA_FEATURE_TYPE_REQUIRED_INTERFACE: { const bool p_is_component = ( parent_type == DATA_CLASSIFIER_TYPE_COMPONENT ) ||( parent_type == DATA_CLASSIFIER_TYPE_PART ); /* spec: https://www.omg.org/spec/UML/2.5.1/PDF ch 11.6.2 */ result = "required"; result_err = p_is_component ? 0 : -1; /*TODO required is a derived value*/ } break; case DATA_FEATURE_TYPE_ENTRY: /* or */ case DATA_FEATURE_TYPE_EXIT: { const bool p_is_state = ( parent_type == DATA_CLASSIFIER_TYPE_STATE ); /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 14.5.8 (note: states have an implicit Region) */ result = "subvertex"; result_err = ( p_is_state ) ? 0 : -1; } break; default: { TSLOG_ERROR_INT( "switch case statement for data_relationship_type_t incomplete", feature_type ); /* this is a possible error case that can happen when a database created with a newer version of the program is opened with this version */ result = NULL; } break; } *out_xmi_name = (result==NULL) ? "" : result; TRACE_END_ERR( result_err ); return result_err; } int xmi_type_converter_get_xmi_nesting_property_of_relationship ( xmi_type_converter_t *this_, data_classifier_type_t hosting_type, data_relationship_type_t child_type, char const * *out_xmi_name ) { TRACE_BEGIN(); assert( out_xmi_name != NULL ); const char* result = NULL; const xmi_element_info_t *host_info = NULL; int map_err = xmi_element_info_map_get_classifier( &xmi_element_info_map_standard, DATA_CLASSIFIER_TYPE_PACKAGE, /*TODO: fix guess*/ hosting_type, &host_info ); if ( map_err != 0 ) { TSLOG_WARNING_INT("xmi_element_info_map_get_classifier could not map unknown type", hosting_type ); } assert ( host_info != NULL ); const bool host_is_activity = ( hosting_type == DATA_CLASSIFIER_TYPE_ACTIVITY ); /*const bool host_is_interface = ( hosting_type == DATA_CLASSIFIER_TYPE_INTERFACE );*/ const bool host_is_implicit_region = ( hosting_type == DATA_CLASSIFIER_TYPE_STATE ); const bool host_is_usecase = ( hosting_type == DATA_CLASSIFIER_TYPE_USE_CASE ); const bool host_is_state = ( hosting_type == DATA_CLASSIFIER_TYPE_STATE ); const bool host_is_interaction = ( hosting_type == DATA_CLASSIFIER_TYPE_INTERACTION ); const bool host_is_comment = ( hosting_type == DATA_CLASSIFIER_TYPE_COMMENT ); const xmi_element_info_t *child_info = NULL; map_err = xmi_element_info_map_get_relationship( &xmi_element_info_map_standard, host_is_state, child_type, &child_info ); if ( map_err != 0 ) { TSLOG_WARNING_INT("xmi_element_info_map_get_relationship could not map unknown type", child_type ); } assert ( child_info != NULL ); const bool c_is_generalization = ( child_type == DATA_RELATIONSHIP_TYPE_UML_GENERALIZATION ); if ( xmi_element_info_is_a_package(host_info) && xmi_element_info_is_a_packageable_element(child_info) ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 12.4.5.6 */ result = "packagedElement"; } else if ( xmi_element_info_is_a_classifier(host_info) && c_is_generalization ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 9.9.4 */ result = "generalization"; } else if ( host_is_activity && xmi_element_info_is_a_activity_edge(child_info) ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 15.7.1.5 */ result = "edge"; } /* else if ( host_is_interface && xmi_element_info_is_a_reception(child_info) ) { / * spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 10.5.5.4 * / result = "ownedReception"; } */ /* else if ( xmi_element_info_is_a_class(host_info) && xmi_element_info_is_a_reception(child_info) ) { / * spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 11.8.3.6 * / result = "ownedReception"; } */ else if ( host_is_implicit_region && xmi_element_info_is_a_transition(child_info) ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 14.5.8.4 */ result = "transition"; } else if ( host_is_usecase && (child_type==DATA_RELATIONSHIP_TYPE_UML_EXTEND) ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 18.2.5.4 */ result = "extend"; } else if ( host_is_usecase && (child_type==DATA_RELATIONSHIP_TYPE_UML_INCLUDE) ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 18.2.5.4 */ result = "include"; } else if ( host_is_interaction && xmi_element_info_is_a_message(child_info) ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 17.4 */ result = "message"; } else if ( host_is_comment && (child_type==DATA_RELATIONSHIP_TYPE_UML_DEPENDENCY) ) { /* spec: https://www.omg.org/spec/UML/2.5.1/PDF chapter 7.8.2 */ result = "annotatedElement"; } *out_xmi_name = (result==NULL) ? "" : result; const int result_err = (result==NULL) ? -1 : 0; TRACE_END_ERR( result_err ); return result_err; } /* ================================ FEATURE ================================ */ xmi_spec_t xmi_type_converter_get_xmi_spec_of_feature ( xmi_type_converter_t *this_, data_feature_type_t feature_type ) { TRACE_BEGIN(); xmi_spec_t result = XMI_SPEC_UML; /* all currently known features are defined in the uml specification */ TRACE_END(); return result; } const char* xmi_type_converter_get_xmi_type_of_feature ( xmi_type_converter_t *this_, data_classifier_type_t parent_type, data_feature_type_t feature_type, xmi_spec_t spec ) { TRACE_BEGIN(); const xmi_element_info_t *feature_info = NULL; int map_err = xmi_element_info_map_get_feature( &xmi_element_info_map_standard, parent_type, feature_type, &feature_info ); if ( map_err != 0 ) { TSLOG_WARNING_INT("xmi_element_info_map_get_feature could not map unknown type", feature_type ); } assert ( feature_info != NULL ); const char* result = (( (spec & (XMI_SPEC_SYSML|XMI_SPEC_STANDARD)) != 0 )&&( (*feature_info).profile_name != NULL )) ? (*feature_info).profile_name : (*feature_info).base_name; assert ( result != NULL ); TRACE_END(); return result; } /* ================================ RELATIONSHIP ================================ */ xmi_spec_t xmi_type_converter_get_xmi_spec_of_relationship ( xmi_type_converter_t *this_, data_relationship_type_t r_type ) { TRACE_BEGIN(); const xmi_element_info_t *rel_info = NULL; int map_err = xmi_element_info_map_get_relationship( &xmi_element_info_map_standard, false, /*this parameter does not matter for this use case*/ r_type, &rel_info ); if ( map_err != 0 ) { TSLOG_WARNING_INT("xmi_element_info_map_get_relationship could not map unknown type", r_type ); } assert ( rel_info != NULL ); const xmi_spec_t result = (*rel_info).specification; TRACE_END(); return result; } const char* xmi_type_converter_get_xmi_type_of_relationship ( xmi_type_converter_t *this_, data_classifier_type_t hosting_type, data_relationship_type_t r_type, xmi_spec_t spec ) { TRACE_BEGIN(); const bool host_is_state = ( hosting_type == DATA_CLASSIFIER_TYPE_STATE ); const xmi_element_info_t *rel_info = NULL; int map_err = xmi_element_info_map_get_relationship( &xmi_element_info_map_standard, host_is_state, r_type, &rel_info ); if ( map_err != 0 ) { TSLOG_WARNING_INT("xmi_element_info_map_get_relationship could not map unknown type", r_type ); } assert ( rel_info != NULL ); const char* result = (( (spec & (XMI_SPEC_SYSML|XMI_SPEC_STANDARD)) != 0 )&&( (*rel_info).profile_name != NULL )) ? (*rel_info).profile_name : (*rel_info).base_name; assert ( result != NULL ); TRACE_END(); return result; } int xmi_type_converter_private_get_xmi_end_property_of_relationship ( xmi_type_converter_t *this_, data_classifier_type_t hosting_type, data_relationship_type_t rel_type, bool from_end, data_classifier_type_t end_classifier_type, data_feature_type_t end_feature_type, char const * *out_xmi_name ) { TRACE_BEGIN(); assert( out_xmi_name != NULL ); int err = 0; const bool host_is_state = ( hosting_type == DATA_CLASSIFIER_TYPE_STATE ); const xmi_element_info_t *rel_info = NULL; int map_err = xmi_element_info_map_get_relationship( &xmi_element_info_map_standard, host_is_state, rel_type, &rel_info ); if ( map_err != 0 ) { TSLOG_WARNING_INT("xmi_element_info_map_get_relationship could not map unknown type", rel_type ); } assert ( rel_info != NULL ); const char* result = ( from_end ) ? (*rel_info).property_from : (*rel_info).property_to; assert ( result != NULL ); *out_xmi_name = ( result == NULL ) ? "" : result; err = ( result == NULL ) ? -1 : 0; const xmi_element_info_t *classifier_info = NULL; map_err = xmi_element_info_map_get_classifier( &xmi_element_info_map_standard, hosting_type, end_classifier_type, &classifier_info ); if ( map_err != 0 ) { TSLOG_WARNING_INT("xmi_element_info_map_get_classifier could not map unknown type", end_classifier_type ); } assert ( classifier_info != NULL ); if ( end_feature_type == DATA_FEATURE_TYPE_VOID ) { /* relationship end is at a classifier */ /* DATA_RELATIONSHIP_TYPE_UML_CONTROL_FLOW and DATA_RELATIONSHIP_TYPE_UML_OBJECT_FLOW */ if ( xmi_element_info_is_a_transition( rel_info ) && xmi_element_info_is_a_vertex( classifier_info ) ) { /* valid relationship according to uml 2.5.1 spec, chapter 14.5.11 */ } else if ( xmi_element_info_is_a_activity_edge( rel_info ) && xmi_element_info_is_a_activity_node( classifier_info ) ) { /* valid relationship according to uml 2.5.1 spec, chapter 15.7.2 */ } //else if ( xmi_element_info_is_a_activity_edge( rel_info ) && ( end_classifier_type == DATA_CLASSIFIER_TYPE_ACTIVITY )) //{ /* valid relationship according to uml 2.5.1 spec, chapter 16.14.55 */ // this is duplicate for XMI_ELEMENT_INFO_MAP_INDEX_STRUCTURED_ACTIVITY_NODE // this is not true for XMI_ELEMENT_INFO_MAP_INDEX_ACTIVITY // see https://issues.omg.org/issues/lists/uml2-rtf#issue-47324 //} /* DATA_RELATIONSHIP_TYPE_UML_DEPENDENCY, DATA_RELATIONSHIP_TYPE_UML_REALIZATION, DATA_RELATIONSHIP_TYPE_UML_MANIFEST, */ /* DATA_RELATIONSHIP_TYPE_UML_DEPLOY, DATA_RELATIONSHIP_TYPE_UML_REFINE, DATA_RELATIONSHIP_TYPE_UML_TRACE */ else if ( xmi_element_info_is_a_dependency( rel_info ) && xmi_element_info_is_a_named_element( classifier_info ) ) { /* a dependency can connect any named elements according to uml 2.5.1 spec, chapter 7.8.4 */ } /* DATA_RELATIONSHIP_TYPE_UML_ASSOCIATION, DATA_RELATIONSHIP_TYPE_UML_AGGREGATION, DATA_RELATIONSHIP_TYPE_UML_COMPOSITION, */ /* DATA_RELATIONSHIP_TYPE_UML_COMMUNICATION_PATH, DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT */ else if ( xmi_element_info_is_a_association( rel_info ) && xmi_element_info_is_a_class( classifier_info ) ) { /* an association can connect to a propoerty according to uml 2.5.1 spec, chapter 11.8.1 */ /* a property can connect a class according to uml 2.5.1 spec, chapter 9.9.17 */ } else if ( xmi_element_info_is_a_association( rel_info ) && ( end_classifier_type == DATA_CLASSIFIER_TYPE_INTERFACE )) { /* an association can connect to a propoerty according to uml 2.5.1 spec, chapter 11.8.1 */ /* a property can connect an interface according to uml 2.5.1 spec, chapter 9.9.17 */ } else if ( xmi_element_info_is_a_association( rel_info ) && xmi_element_info_is_a_classifier( classifier_info ) ) { /* an association can connect to a propoerty according to uml 2.5.1 spec, chapter 11.8.1 */ /* a property is a typedelelemnt and can therefore connect a classifier(type) according to uml 2.5.1 spec, chapter 7.8.22 */ } /* DATA_RELATIONSHIP_TYPE_UML_EXTEND and DATA_RELATIONSHIP_TYPE_UML_INCLUDE */ else if (( rel_type == DATA_RELATIONSHIP_TYPE_UML_EXTEND ) && ( end_classifier_type == DATA_CLASSIFIER_TYPE_USE_CASE )) { /* an extend directed relationship can connect to a use case according to uml 2.5.1 spec, chapter 18.2.2 */ } else if (( rel_type == DATA_RELATIONSHIP_TYPE_UML_INCLUDE ) && ( end_classifier_type == DATA_CLASSIFIER_TYPE_USE_CASE )) { /* an include directed relationship can connect to a use case according to uml 2.5.1 spec, chapter 18.2.4 */ } /* DATA_RELATIONSHIP_TYPE_UML_GENERALIZATION */ else if (( rel_type == DATA_RELATIONSHIP_TYPE_UML_GENERALIZATION ) && xmi_element_info_is_a_classifier( classifier_info ) ) { /* a generalization can connect any classifiers according to uml 2.5.1 spec, chapter 9.9.7 */ } else { /* no valid end type for given relationship type */ err = -1; } } else { /* relationship end is at feature */ const xmi_element_info_t *feature_info = NULL; map_err = xmi_element_info_map_get_feature( &xmi_element_info_map_standard, end_classifier_type, end_feature_type, &feature_info ); if ( map_err != 0 ) { TSLOG_WARNING_INT("xmi_element_info_map_get_feature could not map unknown type", end_feature_type ); } assert ( feature_info != NULL ); /* DATA_RELATIONSHIP_TYPE_UML_CONTROL_FLOW and DATA_RELATIONSHIP_TYPE_UML_OBJECT_FLOW */ if ( xmi_element_info_is_a_transition( rel_info ) && (( end_feature_type == DATA_FEATURE_TYPE_ENTRY )||( end_feature_type == DATA_FEATURE_TYPE_EXIT ))) { /* valid relationship according to uml 2.5.1 spec, chapter 14.5.11 */ } else if ( xmi_element_info_is_a_activity_edge( rel_info ) && xmi_element_info_is_a_activity_node( feature_info ) ) { /* valid relationship according to uml 2.5.1 spec, chapter 15.7.2 */ } /* DATA_RELATIONSHIP_TYPE_UML_ASYNC_CALL or DATA_RELATIONSHIP_TYPE_UML_SYNC_CALL or DATA_RELATIONSHIP_TYPE_UML_RETURN_CALL */ else if ( xmi_element_info_is_a_message ( rel_info ) && ( end_feature_type == DATA_FEATURE_TYPE_LIFELINE )) { /* valid relationship according to uml 2.5.1 spec, chapter 17.12.23 */ } /* DATA_RELATIONSHIP_TYPE_UML_DEPENDENCY, DATA_RELATIONSHIP_TYPE_UML_REALIZATION, DATA_RELATIONSHIP_TYPE_UML_MANIFEST, */ /* DATA_RELATIONSHIP_TYPE_UML_DEPLOY, DATA_RELATIONSHIP_TYPE_UML_REFINE, DATA_RELATIONSHIP_TYPE_UML_TRACE */ else if ( xmi_element_info_is_a_dependency( rel_info ) && xmi_element_info_is_a_named_element( feature_info ) ) { /* a dependency can connect any named elements according to uml 2.5.1 spec, chapter 7.8.4 */ } /* DATA_RELATIONSHIP_TYPE_UML_ASSOCIATION, DATA_RELATIONSHIP_TYPE_UML_AGGREGATION, DATA_RELATIONSHIP_TYPE_UML_COMPOSITION, */ /* DATA_RELATIONSHIP_TYPE_UML_COMMUNICATION_PATH, DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT */ else if ( xmi_element_info_is_a_association( rel_info ) && xmi_element_info_is_a_class( feature_info ) ) { /* an association can connect to a propoerty according to uml 2.5.1 spec, chapter 11.8.1 */ /* a property can connect a class according to uml 2.5.1 spec, chapter 9.9.17 */ } else if ( xmi_element_info_is_a_association( rel_info ) && (( end_feature_type == DATA_FEATURE_TYPE_PROVIDED_INTERFACE )||( end_feature_type == DATA_FEATURE_TYPE_REQUIRED_INTERFACE ))) { /* an association can connect to a propoerty according to uml 2.5.1 spec, chapter 11.8.1 */ /* a property can connect an interface according to uml 2.5.1 spec, chapter 9.9.17 */ } else if ( xmi_element_info_is_a_association( rel_info ) && xmi_element_info_is_a_classifier( feature_info ) ) { /* an association can connect to a propoerty according to uml 2.5.1 spec, chapter 11.8.1 */ /* a property is a typedelelemnt and can therefore connect a classifier(type) according to uml 2.5.1 spec, chapter 7.8.22 */ } else if ( xmi_element_info_is_a_association( rel_info ) && xmi_element_info_is_a_property( feature_info ) ) { /* an association can connect to a propoerty according to uml 2.5.1 spec, chapter 11.8.1 */ /* a port is a property */ } else { /* no valid end type for given relationship type */ err = -1; } } TRACE_END_ERR( err ); return err; } /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/xmi/xmi_xml.c000066400000000000000000000024071415120503000214530ustar00rootroot00000000000000/* File: xmi_xml.c; Copyright and License: see below */ #include "xmi/xmi_xml.h" const char XMI_XML_NS_UML[5] = "uml:"; const char XMI_XML_NS_SYSML[7] = "SysML:"; const char XMI_XML_NS_STDPROF[17] = "StandardProfile:"; const char XMI_XML_NS_LOCALPROF[14] = "LocalProfile:"; const char XMI_XML_ATTR_ID_START[9] = "xmi:id=\""; const char XMI_XML_ATTR_ID_END[3] = "\" "; const char XMI_XML_ATTR_TYPE_START[11] = "xmi:type=\""; const char XMI_XML_ATTR_TYPE_END[3] = "\" "; const char XMI_XML_ATTR_IDREF_START[12] = "xmi:idref=\""; const char XMI_XML_ATTR_IDREF_END[3] = "\" "; const char XMI_XML_ATTR_NAME_START[7] = "name=\""; const char XMI_XML_ATTR_NAME_END[3] = "\" "; /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/source/xml/000077500000000000000000000000001415120503000176325ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/source/xml/xml_writer.c000066400000000000000000000277331415120503000222060ustar00rootroot00000000000000/* File: xml_writer.c; Copyright and License: see below */ #include "xml/xml_writer.h" #include "data_id.h" #include "trace.h" #include "tslog.h" #include #include #include const char XML_WRITER_START_TAG_START[2] = "<"; const char XML_WRITER_START_TAG_END[2] = ">"; const char XML_WRITER_END_TAG_START[3] = ""; const char XML_WRITER_EMPTY_TAG_START[2] = "<"; const char XML_WRITER_EMPTY_TAG_END[3] = "/>"; const char XML_WRITER_ATTR_SEPARATOR[2] = " "; const char XML_WRITER_ATTR_VALUE_START[3] = "=\""; const char XML_WRITER_ATTR_VALUE_END[2] = "\""; const char XML_WRITER_COMMENT_START[5] = ""; const char XML_WRITER_NL[2] = "\n"; #define XML_WRITER_PRIVATE_MAX_INDENT_LEVELS (12) static const char *const XML_WRITER_PRIVATE_ENCODE_XML_STRINGS[XML_WRITER_PRIVATE_MAX_INDENT_LEVELS][6][2] = { { { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "\n", "\n" }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ } }; static const char *const XML_WRITER_PRIVATE_ENCODE_XML_COMMENTS[XML_WRITER_PRIVATE_MAX_INDENT_LEVELS][8][2] = { { { "\n", "\n" }, { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "-", " - " }, { "\n", "\n" }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n" }, { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "-", " - " }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n" }, { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "-", " - " }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n" }, { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "-", " - " }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n" }, { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "-", " - " }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n" }, { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "-", " - " }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n" }, { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "-", " - " }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n" }, { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "-", " - " }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n" }, { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "-", " - " }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n" }, { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "-", " - " }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n" }, { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "-", " - " }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n" }, { "<", "<" }, { ">", ">" }, { "\"", """ }, { "&", "&" }, { "-", " - " }, { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ } }; static const char *const XML_WRITER_PRIVATE_INDENT_PLAIN[XML_WRITER_PRIVATE_MAX_INDENT_LEVELS][2][2] = { { { "\n", "\n" }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ }, { { "\n", "\n " }, /* indentation level */ { NULL, NULL } /* end translation table */ } }; void xml_writer_init ( xml_writer_t *this_, universal_output_stream_t *output ) { TRACE_BEGIN(); assert( NULL != output ); (*this_).output = output; universal_escaping_output_stream_init( &((*this_).esc_output), &(XML_WRITER_PRIVATE_ENCODE_XML_STRINGS[0]), output ); (*this_).indent_level = 0; (*this_).xml_encode_table = &(XML_WRITER_PRIVATE_ENCODE_XML_STRINGS[0]); (*this_).xml_comments_encode_table = &(XML_WRITER_PRIVATE_ENCODE_XML_COMMENTS[0]); (*this_).xml_plain_table = &(XML_WRITER_PRIVATE_INDENT_PLAIN[0]); TRACE_END(); } void xml_writer_destroy( xml_writer_t *this_ ) { TRACE_BEGIN(); universal_escaping_output_stream_destroy( &((*this_).esc_output) ); (*this_).output = NULL; TRACE_END(); } int xml_writer_write_plain_id ( xml_writer_t *this_, data_id_t id ) { TRACE_BEGIN(); assert( DATA_TABLE_VOID != data_id_get_table(&id) ); assert( DATA_ROW_ID_VOID != data_id_get_row_id(&id) ); int result = 0; /* print id */ { char id_buf[DATA_ID_MAX_UTF8STRING_SIZE]; utf8stringbuf_t id_str = UTF8STRINGBUF( id_buf ); utf8stringbuf_clear( id_str ); data_id_to_utf8stringbuf( &id, id_str ); const unsigned int len = utf8stringbuf_get_length(id_str); universal_escaping_output_stream_change_rules( &((*this_).esc_output), (*this_).xml_plain_table ); result = universal_escaping_output_stream_write( &((*this_).esc_output), utf8stringbuf_get_string(id_str), len ); } TRACE_END_ERR( result ); return result; } int xml_writer_write_int ( xml_writer_t *this_, int64_t number ) { TRACE_BEGIN(); char numberStr[21]; /* this is sufficient for signed 64 bit integers: -9223372036854775806 */ int result = 0; /* Note: snprintf is not available on every OS */ sprintf( numberStr, "%" PRIi64, number ); result = xml_writer_write_plain( this_, &(numberStr[0]) ); TRACE_END_ERR( result ); return result; } void xml_writer_private_update_encoding_tables ( xml_writer_t *this_ ) { TRACE_BEGIN(); const unsigned int level = ( (*this_).indent_level >= XML_WRITER_PRIVATE_MAX_INDENT_LEVELS ) ? ( XML_WRITER_PRIVATE_MAX_INDENT_LEVELS - 1 ) : ( (*this_).indent_level ); (*this_).xml_encode_table = &(XML_WRITER_PRIVATE_ENCODE_XML_STRINGS[level]); (*this_).xml_comments_encode_table = &(XML_WRITER_PRIVATE_ENCODE_XML_COMMENTS[level]); (*this_).xml_plain_table = &(XML_WRITER_PRIVATE_INDENT_PLAIN[level]); TRACE_END(); } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/test/000077500000000000000000000000001415120503000165115ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/test/integration/000077500000000000000000000000001415120503000210345ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/test/integration/io_export_model_traversal_test.c000066400000000000000000000551241415120503000275210ustar00rootroot00000000000000/* File: io_export_model_traversal_test.c; Copyright and License: see below */ #include "io_export_model_traversal_test.h" #include "io_export_model_traversal.h" #include "test_env/test_env_setup_data.h" #include "test_result_check/test_result_check_xml.h" #include "xmi/xmi_element_writer.h" #include "stream/universal_memory_output_stream.h" #include "set/data_stat.h" #include "ctrl_controller.h" #include "storage/data_database.h" #include "storage/data_database_writer.h" #include "storage/data_database_reader.h" #include "trace.h" #include "test_assert.h" static void set_up(void); static void tear_down(void); static void iterate_types_on_mini_model(void); /*! * \brief helper function to initialize the database */ static void create_mini_model( data_row_id_t * out_root_diagram, data_row_id_t * out_from_classifier_parent, data_row_id_t * out_from_classifier, data_row_id_t * out_from_feature, data_row_id_t * out_to_classifier_parent, data_row_id_t * out_to_classifier, data_row_id_t * out_to_feature, data_row_id_t * out_relation_clas_clas, data_row_id_t * out_relation_clas_feat, data_row_id_t * out_relation_feat_clas, data_row_id_t * out_relation_feat_feat ); /*! * \brief database instance on which the tests are performed */ static data_database_t database; /*! * \brief database reader to access the database */ static data_database_reader_t db_reader; /*! * \brief controller instance on which the tests are performed */ static ctrl_controller_t controller; /*! * \brief stream to write to a memory buffer */ static universal_memory_output_stream_t mem_output_stream; /*! * \brief mem-buffer to be written by mem_output_stream */ static char mem_buffer[16384]; test_suite_t io_export_model_traversal_test_get_list(void) { test_suite_t result; test_suite_init( &result, "io_export_model_traversal_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "iterate_types_on_mini_model", &iterate_types_on_mini_model ); return result; } static void set_up(void) { data_database_init( &database ); data_database_open_in_memory( &database ); data_database_reader_init( &db_reader, &database ); ctrl_controller_init( &controller, &database ); universal_memory_output_stream_init( &mem_output_stream, &mem_buffer, sizeof(mem_buffer) ); } static void tear_down(void) { universal_memory_output_stream_destroy( &mem_output_stream ); ctrl_controller_destroy( &controller ); data_database_reader_destroy( &db_reader ); data_database_close( &database ); data_database_destroy( &database ); } static void create_mini_model( data_row_id_t * out_root_diagram, data_row_id_t * out_from_classifier_parent, data_row_id_t * out_from_classifier, data_row_id_t * out_from_feature, data_row_id_t * out_to_classifier_parent, data_row_id_t * out_to_classifier, data_row_id_t * out_to_feature, data_row_id_t * out_relation_clas_clas, data_row_id_t * out_relation_clas_feat, data_row_id_t * out_relation_feat_clas, data_row_id_t * out_relation_feat_feat ) { ctrl_classifier_controller_t *classifier_ctrl; classifier_ctrl = ctrl_controller_get_classifier_control_ptr( &controller ); ctrl_error_t c_err; *out_root_diagram = test_env_setup_data_create_diagram( DATA_ROW_ID_VOID, "root diag", &controller ); *out_from_classifier_parent = test_env_setup_data_create_classifier( "from parent", &controller ); test_env_setup_data_create_diagramelement( *out_root_diagram, *out_from_classifier_parent, DATA_ROW_ID_VOID, &controller ); *out_from_classifier = test_env_setup_data_create_classifier( "from classifier", &controller ); *out_from_feature = test_env_setup_data_create_feature( *out_from_classifier, "from feature", &controller ); test_env_setup_data_create_diagramelement( *out_root_diagram, *out_from_classifier, *out_from_feature, &controller ); *out_to_classifier_parent = test_env_setup_data_create_classifier( "to parent", &controller ); test_env_setup_data_create_diagramelement( *out_root_diagram, *out_to_classifier_parent, DATA_ROW_ID_VOID, &controller ); *out_to_classifier = test_env_setup_data_create_classifier( "to classifier", &controller ); *out_to_feature = test_env_setup_data_create_feature( *out_to_classifier, "to feature", &controller ); test_env_setup_data_create_diagramelement( *out_root_diagram, *out_to_classifier, *out_to_feature, &controller ); /* from child has parent */ { data_row_id_t from_parent_rel_id = test_env_setup_data_create_relationship( *out_from_classifier_parent, DATA_ROW_ID_VOID, *out_from_classifier, DATA_ROW_ID_VOID, "from child rel", &controller ); c_err = ctrl_classifier_controller_update_relationship_main_type ( classifier_ctrl, from_parent_rel_id, DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT ); TEST_ENVIRONMENT_ASSERT( CTRL_ERROR_NONE == c_err ); } /* to child has parent */ { data_row_id_t to_parent_rel_id = test_env_setup_data_create_relationship( *out_to_classifier_parent, DATA_ROW_ID_VOID, *out_to_classifier, DATA_ROW_ID_VOID, "to child rel", &controller ); c_err = ctrl_classifier_controller_update_relationship_main_type ( classifier_ctrl, to_parent_rel_id, DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT ); TEST_ENVIRONMENT_ASSERT( CTRL_ERROR_NONE == c_err ); } *out_relation_clas_clas = test_env_setup_data_create_relationship( *out_from_classifier_parent, DATA_ROW_ID_VOID, *out_to_classifier, DATA_ROW_ID_VOID, "from classifier to classifier", &controller ); *out_relation_clas_feat = test_env_setup_data_create_relationship( *out_from_classifier_parent, DATA_ROW_ID_VOID, *out_to_classifier, *out_to_feature, "from classifier to feature", &controller ); *out_relation_feat_clas = test_env_setup_data_create_relationship( *out_from_classifier_parent, *out_from_feature, *out_to_classifier, DATA_ROW_ID_VOID, "from feature to classifier", &controller ); *out_relation_feat_feat = test_env_setup_data_create_relationship( *out_from_classifier_parent, *out_from_feature, *out_to_classifier, *out_to_feature, "from feature to feature", &controller ); } static const data_classifier_type_t classifier_types[] ={ DATA_CLASSIFIER_TYPE_BLOCK, DATA_CLASSIFIER_TYPE_SUBSYSTEM, /* equivilent to DATA_CLASSIFIER_TYPE_COMPONENT */ DATA_CLASSIFIER_TYPE_ACTIVITY, DATA_CLASSIFIER_TYPE_STATE, DATA_CLASSIFIER_TYPE_NODE, DATA_CLASSIFIER_TYPE_CLASS, /* equivilent to DATA_CLASSIFIER_TYPE_OBJECT */ DATA_CLASSIFIER_TYPE_DYN_INTERRUPTABLE_REGION, DATA_CLASSIFIER_TYPE_BLOCK, DATA_CLASSIFIER_TYPE_PACKAGE, /* unexpected */ DATA_CLASSIFIER_TYPE_CONSTRAINT_BLOCK, DATA_CLASSIFIER_TYPE_REQUIREMENT, DATA_CLASSIFIER_TYPE_USE_CASE, DATA_CLASSIFIER_TYPE_DIAGRAM_REFERENCE, DATA_CLASSIFIER_TYPE_INTERFACE, DATA_CLASSIFIER_TYPE_ARTIFACT, DATA_CLASSIFIER_TYPE_COMMENT, DATA_CLASSIFIER_TYPE_DYN_FINAL_NODE, /* equivilent to DATA_CLASSIFIER_TYPE_DYN_INITIAL_NODE, DATA_CLASSIFIER_TYPE_DYN_FORK_NODE */ /* DATA_CLASSIFIER_TYPE_DYN_JOIN_NODE */ DATA_CLASSIFIER_TYPE_DYN_DECISION_NODE, DATA_CLASSIFIER_TYPE_DYN_SHALLOW_HISTORY, /* equivilent to DATA_CLASSIFIER_TYPE_DYN_DEEP_HISTORY */ DATA_CLASSIFIER_TYPE_DYN_ACCEPT_EVENT, /* equivilent to DATA_CLASSIFIER_TYPE_DYN_ACCEPT_TIME_EVENT, DATA_CLASSIFIER_TYPE_DYN_SEND_SIGNAL */ DATA_CLASSIFIER_TYPE_INTERACTION, /* is fake id only */ DATA_CLASSIFIER_TYPE_PART, DATA_CLASSIFIER_TYPE_ACTOR, 470063, /* downwards compatibility check, equivilent to DATA_CLASSIFIER_TYPE_DEPRECATED_FEATURE */ }; static const data_feature_type_t feature_types[] ={ DATA_FEATURE_TYPE_PROPERTY, DATA_FEATURE_TYPE_OPERATION, DATA_FEATURE_TYPE_PORT, DATA_FEATURE_TYPE_LIFELINE, DATA_FEATURE_TYPE_PROVIDED_INTERFACE, DATA_FEATURE_TYPE_REQUIRED_INTERFACE, DATA_FEATURE_TYPE_IN_PORT_PIN, DATA_FEATURE_TYPE_OUT_PORT_PIN, DATA_FEATURE_TYPE_ENTRY, DATA_FEATURE_TYPE_EXIT, /* unexpected */ 470063, /* downwards compatibility check, equivilent to DATA_FEATURE_TYPE_VOID */ }; static const data_relationship_type_t relationship_types[] ={ DATA_RELATIONSHIP_TYPE_UML_DEPENDENCY, DATA_RELATIONSHIP_TYPE_UML_ASSOCIATION, DATA_RELATIONSHIP_TYPE_UML_AGGREGATION, /* equivilent to DATA_RELATIONSHIP_TYPE_UML_COMPOSITION */ DATA_RELATIONSHIP_TYPE_UML_GENERALIZATION, DATA_RELATIONSHIP_TYPE_UML_REALIZATION, DATA_RELATIONSHIP_TYPE_UML_ASYNC_CALL, /* equivilent to DATA_RELATIONSHIP_TYPE_UML_SYNC_CALL, DATA_RELATIONSHIP_TYPE_UML_RETURN_CALL */ DATA_RELATIONSHIP_TYPE_UML_COMMUNICATION_PATH, DATA_RELATIONSHIP_TYPE_UML_CONTROL_FLOW, DATA_RELATIONSHIP_TYPE_UML_OBJECT_FLOW, DATA_RELATIONSHIP_TYPE_UML_DEPLOY, /* equivilent to DATA_RELATIONSHIP_TYPE_UML_MANIFEST */ DATA_RELATIONSHIP_TYPE_UML_EXTEND, /* equivilent to DATA_RELATIONSHIP_TYPE_UML_INCLUDE */ DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT, DATA_RELATIONSHIP_TYPE_UML_TRACE, /* equivilent to DATA_RELATIONSHIP_TYPE_UML_REFINE */ /* unexpected */ 470063, /* downwards compatibility check */ }; static void iterate_types_on_mini_model(void) { /* fill database with mini model */ data_row_id_t from_classifier_parent; data_row_id_t from_classifier; data_row_id_t from_feature; data_row_id_t to_classifier_parent; data_row_id_t to_classifier; data_row_id_t to_feature; data_row_id_t relation_clas_clas; data_row_id_t relation_clas_feat; data_row_id_t relation_feat_clas; data_row_id_t relation_feat_feat; data_row_id_t root_diag_id; create_mini_model( &root_diag_id, &from_classifier_parent, &from_classifier, &from_feature, &to_classifier_parent, &to_classifier, &to_feature, &relation_clas_clas, &relation_clas_feat, &relation_feat_clas, &relation_feat_feat ); unsigned int clas_cnt = sizeof(classifier_types)/sizeof(classifier_types[0]); unsigned int feat_cnt = sizeof(feature_types)/sizeof(feature_types[0]); unsigned int rel_cnt = sizeof(relationship_types)/sizeof(relationship_types[0]); for ( unsigned int rel1_idx = 0; rel1_idx < rel_cnt; rel1_idx ++ ) { for ( unsigned int clas1_idx = 0; clas1_idx < clas_cnt; clas1_idx ++ ) { for ( unsigned int feat1_idx = 0; feat1_idx < feat_cnt; feat1_idx ++ ) { for ( unsigned int variation_idx = 0; variation_idx < 2; variation_idx ++ ) { TSLOG_ANOMALY_INT("variation_idx",variation_idx); /* update types in database */ { ctrl_classifier_controller_t *c_ctrl; c_ctrl = ctrl_controller_get_classifier_control_ptr( &controller ); /* determine if all 4 relationships between from_classifier and to_classifier shall have the same type */ const unsigned int rel2_idx = (variation_idx==0) ? rel1_idx /* same relationship type for all relationships */ : ( rel1_idx + clas1_idx + feat1_idx + variation_idx ) % rel_cnt; /* high variation otherwise */ /* determine if all 4 classifiers shall have the same type */ const unsigned int clas2_idx = (variation_idx==0) ? clas1_idx /* same classifier type for all classifiers */ : ( rel1_idx + clas1_idx + feat1_idx + variation_idx ) % clas_cnt; /* high variation otherwise */ /* determine if both features at from_classifier and to_classifier shall have the same type */ const unsigned int feat2_idx = (variation_idx==0) ? feat1_idx /* same feature type for all features */ : ( rel1_idx + clas1_idx + feat1_idx + variation_idx ) % feat_cnt; /* high variation otherwise */ ctrl_error_t c_err = CTRL_ERROR_NONE; c_err |= ctrl_classifier_controller_update_relationship_main_type ( c_ctrl, relation_clas_clas, relationship_types[rel1_idx] ); c_err |= ctrl_classifier_controller_update_relationship_main_type ( c_ctrl, relation_clas_feat, relationship_types[rel2_idx] ); c_err |= ctrl_classifier_controller_update_relationship_main_type ( c_ctrl, relation_feat_clas, relationship_types[rel1_idx] ); c_err |= ctrl_classifier_controller_update_relationship_main_type ( c_ctrl, relation_feat_feat, relationship_types[rel1_idx] ); c_err |= ctrl_classifier_controller_update_classifier_main_type ( c_ctrl, from_classifier_parent, classifier_types[clas1_idx] ); c_err |= ctrl_classifier_controller_update_classifier_main_type ( c_ctrl, from_classifier, classifier_types[clas1_idx] ); c_err |= ctrl_classifier_controller_update_classifier_main_type ( c_ctrl, to_classifier_parent, classifier_types[clas1_idx] ); c_err |= ctrl_classifier_controller_update_classifier_main_type ( c_ctrl, to_classifier, classifier_types[clas2_idx] ); c_err |= ctrl_classifier_controller_update_feature_main_type ( c_ctrl, from_feature, feature_types[feat1_idx] ); c_err |= ctrl_classifier_controller_update_feature_main_type ( c_ctrl, to_feature, feature_types[feat2_idx] ); TEST_ENVIRONMENT_ASSERT( CTRL_ERROR_NONE == c_err ); } data_stat_t stat; data_stat_init( &stat ); { /* static variables are ok for a single-threaded test case and preserves stack space, which is important for 32bit systems */ static data_visible_set_t temp_input_data; /*!< buffer to cache the diagram data */ static io_export_model_traversal_t temp_model_traversal; /*!< own instance of a model_traversal for text export */ xmi_element_writer_t temp_xmi_writer; /*!< memory for a temporary xmi writer */ universal_memory_output_stream_reset( &mem_output_stream ); universal_output_stream_t* output = universal_memory_output_stream_get_output_stream( &mem_output_stream ); { xmi_element_writer_init( &temp_xmi_writer, &stat, output ); /* init the model_traversal */ io_export_model_traversal_init( &temp_model_traversal, &db_reader, &temp_input_data, &stat, xmi_element_writer_get_element_writer( &temp_xmi_writer ) ); /* write the document */ int export_err = 0; export_err |= xmi_element_writer_write_header( &temp_xmi_writer, "document file name" ); export_err |= xmi_element_writer_start_main( &temp_xmi_writer, "document file name" ); xmi_element_writer_set_mode( &temp_xmi_writer, XMI_WRITER_PASS_BASE ); export_err |= io_export_model_traversal_walk_model_nodes( &temp_model_traversal ); export_err |= xmi_element_writer_end_main( &temp_xmi_writer ); xmi_element_writer_set_mode( &temp_xmi_writer, XMI_WRITER_PASS_PROFILE ); export_err |= io_export_model_traversal_walk_model_nodes( &temp_model_traversal ); export_err |= xmi_element_writer_write_footer( &temp_xmi_writer ); TEST_ASSERT_EQUAL_INT( 0, export_err ); io_export_model_traversal_destroy( &temp_model_traversal ); xmi_element_writer_destroy( &temp_xmi_writer ); } } //static const char TERM2[4]="qQe\n"; //universal_memory_output_stream_write( &mem_output_stream, &TERM2, sizeof(TERM2) ); static const char TERM='\00'; int write_err = universal_memory_output_stream_write( &mem_output_stream, &TERM, sizeof(TERM) ); TEST_ENVIRONMENT_ASSERT( 0 == write_err ); universal_memory_output_stream_flush( &mem_output_stream ); #ifndef NDEBUG fprintf( stdout, "\n%s\n", &(mem_buffer[0]) ); #endif const int xml_is_error = test_result_check_xml_validate_xml( &(mem_buffer[0]) ); TEST_ASSERT_EQUAL_INT( 0, xml_is_error ); data_stat_trace( &stat ); TEST_ASSERT_EQUAL_INT( 5, data_stat_get_count( &stat, DATA_TABLE_CLASSIFIER, DATA_STAT_SERIES_EXPORTED ) ); //TEST_ASSERT_EQUAL_INT( 2, data_stat_get_count( &stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_EXPORTED ) ); //TEST_ASSERT_EQUAL_INT( 4, data_stat_get_count( &stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_EXPORTED ) ); //TEST_ASSERT_EQUAL_INT( 10, data_stat_get_series_count( &stat, DATA_STAT_SERIES_EXPORTED ) ); TEST_ASSERT_EQUAL_INT( 0, data_stat_get_series_count( &stat, DATA_STAT_SERIES_MODIFIED ) ); TEST_ASSERT_EQUAL_INT( 0, data_stat_get_series_count( &stat, DATA_STAT_SERIES_DELETED ) ); TEST_ASSERT_EQUAL_INT( 0, data_stat_get_series_count( &stat, DATA_STAT_SERIES_IGNORED ) ); //TEST_ASSERT_EQUAL_INT( 0, data_stat_get_series_count( &stat, DATA_STAT_SERIES_WARNING ) ); TEST_ASSERT_EQUAL_INT( 0, data_stat_get_series_count( &stat, DATA_STAT_SERIES_ERROR ) ); data_stat_destroy( &stat ); } } } } } /* * Copyright 2020-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/io/test/integration/io_export_model_traversal_test.h000066400000000000000000000017141415120503000275220ustar00rootroot00000000000000/* File: io_export_model_traversal_test.h; Copyright and License: see below */ #ifndef IO_EXPORT_MODEL_TRAVERSAL_TEST_H #define IO_EXPORT_MODEL_TRAVERSAL_TEST_H /*! * \file * \brief MODULE TEST for io_export_model_traversal */ #include "test_suite.h" test_suite_t io_export_model_traversal_test_get_list(void); #endif /* IO_EXPORT_MODEL_TRAVERSAL_TEST_H */ /* * Copyright 2020-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/io/test/test_result_check/000077500000000000000000000000001415120503000222235ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/test/test_result_check/test_result_check_xml.h000066400000000000000000000020261415120503000267660ustar00rootroot00000000000000/* File: test_result_check_xml.h; Copyright and License: see below */ #ifndef TEST_RESULT_CHECK_XML_H #define TEST_RESULT_CHECK_XML_H /* public file for the doxygen documentation: */ /*! * \file * \brief Provides functions to check if test results are xml compliant */ /*! * \brief helper function to validate xml */ static int test_result_check_xml_validate_xml( const char* xml_string ); #include "test_result_check_xml.inl" #endif /* TEST_RESULT_CHECK_XML_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/io/test/test_result_check/test_result_check_xml.inl000066400000000000000000000025671415120503000273330ustar00rootroot00000000000000/* File: test_result_check_xml.c; Copyright and License: see below */ #include "trace.h" #include "test_assert.h" #include int test_result_check_xml_validate_xml( const char* xml_string ) { bool success; static GMarkupParser DEV_NULL_PARSER = { .start_element=NULL, .end_element=NULL, .text=NULL, .passthrough=NULL, .error=NULL }; GMarkupParseContext *my_ctx = g_markup_parse_context_new ( &DEV_NULL_PARSER, 0, NULL, NULL ); TEST_ENVIRONMENT_ASSERT( NULL != my_ctx ); success = g_markup_parse_context_parse ( my_ctx, xml_string, strlen(xml_string), NULL ); success &= g_markup_parse_context_end_parse ( my_ctx, NULL ); g_markup_parse_context_free( my_ctx ); return ( success ? 0 : -1 ); } /* * Copyright 2020-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/io/test/unit/000077500000000000000000000000001415120503000174705ustar00rootroot00000000000000crystal-facet-uml-1.34.1/io/test/unit/json_import_to_database_test.c000066400000000000000000001037011415120503000255660ustar00rootroot00000000000000/* File: json_import_to_database_test.c; Copyright and License: see below */ #include "json_import_to_database_test.h" #include "json/json_import_to_database.h" #include "set/data_stat.h" #include "ctrl_controller.h" #include "storage/data_database.h" #include "storage/data_database_writer.h" #include "storage/data_database_reader.h" #include "trace.h" #include "test_assert.h" static void set_up(void); static void tear_down(void); static void insert_invalid_json(void); static void insert_invalid_parent_diag(void); static void insert_empty_set(void); static void insert_new_classifier_to_existing_diagram(void); static void insert_new_classifier_to_new_diagram(void); static void insert_existing_classifier_to_existing_diagram(void); static void insert_existing_classifier_to_new_diagram(void); static void insert_unconditional_relationships(void); static void insert_scenario_relationships_to_scenario(void); static void insert_scenario_relationships_to_non_scenario(void); static data_row_id_t create_root_diag(); /* helper function */ /*! * \brief database instance on which the tests are performed */ static data_database_t database; /*! * \brief database reader to access the database */ static data_database_reader_t db_reader; /*! * \brief controller instance on which the tests are performed */ static ctrl_controller_t controller; test_suite_t json_import_to_database_test_get_list(void) { test_suite_t result; test_suite_init( &result, "json_import_to_database_test_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "insert_invalid_json", &insert_invalid_json ); test_suite_add_test_case( &result, "insert_invalid_parent_diag", &insert_invalid_parent_diag ); test_suite_add_test_case( &result, "insert_empty_set", &insert_empty_set ); test_suite_add_test_case( &result, "insert_new_classifier_to_existing_diagram", &insert_new_classifier_to_existing_diagram ); test_suite_add_test_case( &result, "insert_new_classifier_to_new_diagram", &insert_new_classifier_to_new_diagram ); test_suite_add_test_case( &result, "insert_existing_classifier_to_existing_diagram", &insert_existing_classifier_to_existing_diagram ); test_suite_add_test_case( &result, "insert_existing_classifier_to_new_diagram", &insert_existing_classifier_to_new_diagram ); test_suite_add_test_case( &result, "insert_unconditional_relationships", &insert_unconditional_relationships ); test_suite_add_test_case( &result, "insert_scenario_relationships_to_scenario", &insert_scenario_relationships_to_scenario ); test_suite_add_test_case( &result, "insert_scenario_relationships_to_non_scenario", &insert_scenario_relationships_to_non_scenario ); return result; } static void set_up(void) { data_database_init( &database ); data_database_open_in_memory( &database ); data_database_reader_init( &db_reader, &database ); ctrl_controller_init( &controller, &database ); } static void tear_down(void) { ctrl_controller_destroy( &controller ); data_database_reader_destroy( &db_reader ); data_database_close( &database ); data_database_destroy( &database ); } static data_row_id_t create_root_diag() { ctrl_error_t ctrl_err; data_error_t data_err; ctrl_diagram_controller_t *diagram_ctrl; diagram_ctrl = ctrl_controller_get_diagram_control_ptr( &controller ); /* create a diagram of type DATA_DIAGRAM_TYPE_UML_CLASS_DIAGRAM */ data_row_id_t root_diag_id; data_diagram_t root_diagram; data_err = data_diagram_init( &root_diagram, DATA_ROW_ID_VOID, /*=diagram_id is ignored*/ DATA_ROW_ID_VOID, /*=parent_diagram_id*/ DATA_DIAGRAM_TYPE_UML_CLASS_DIAGRAM, "the_root_diag", "diagram_description-root", 10555, /*=list_order*/ DATA_DIAGRAM_FLAG_NONE, "8a086be4-e05d-4299-a56a-10c5b9037835" ); TEST_ENVIRONMENT_ASSERT( DATA_ERROR_NONE == data_err ); root_diag_id = DATA_ROW_ID_VOID; ctrl_err = ctrl_diagram_controller_create_diagram ( diagram_ctrl, &root_diagram, CTRL_UNDO_REDO_ACTION_BOUNDARY_START_NEW, &root_diag_id ); TEST_ENVIRONMENT_ASSERT( CTRL_ERROR_NONE == ctrl_err ); TEST_ENVIRONMENT_ASSERT( DATA_ROW_ID_VOID != root_diag_id ); data_diagram_destroy ( &root_diagram ); return root_diag_id; } static const char *const test_json_own_diagram = "{\n" " \"head\":\n" " {\n" " },\n" " \"views\": \n" " [\n" " {\n" " \"diagram\": {\n" " \"id\": 3,\n" " \"diagram_type\": 13,\n" " \"name\": \"Sequence 1\",\n" " \"description\": [ \"\" ],\n" " \"list_order\": 65536,\n" " \"display_flags\": 0,\n" " \"uuid\": \"3318bd97-bfe4-4788-9ae8-0c57640fadae\",\n" " \"diagramelements\": \n" " [\n" " {\n" " \"id\": 89,\n" " \"classifier_id\": 15,\n" " \"focused_feature_id\": \"-1\",\n" " \"display_flags\": 0,\n" " \"uuid\": \"7fa23aed-0e92-4f00-9fb4-9b97930d58f2\"\n" " }\n" " ]\n" " }\n" " }\n" " ],\n" " \"nodes\": \n" " [\n" " {\n" " \"classifier\": {\n" " \"id\": 15,\n" " \"main_type\": 125,\n" " \"stereotype\": \"\",\n" " \"name\": \"\\\"the Serializer\\\"\",\n" " \"description\": [ \"hello\\nhello\" ],\n" " \"x_order\": -1087446901,\n" " \"y_order\": 359417528,\n" " \"list_order\": 446877143,\n" " \"uuid\": \"0967dfbf-7df0-458e-addc-85ef7be06067\",\n" " \"features\": \n" " [\n" " {\n" " \"id\": 34,\n" " \"main_type\": 3,\n" " \"key\": \"\",\n" " \"value\": \"\",\n" " \"description\": [ ],\n" " \"list_order\": 0,\n" " \"uuid\": \"67c2bc6d-ddc7-458a-80f1-be353c197381\"\n" " },\n" " {\n" " \"id\": 12,\n" " \"main_type\": 1,\n" " \"key\": \"new_get_state\",\n" " \"value\": \"enum\",\n" " \"description\": [ \"\" ],\n" " \"list_order\": 425984\n" " }\n" " ]\n" " }\n" " }\n" " ],\n" " \"edges\": \n" " [\n" " {\n" " \"relationship\": {\n" " \"id\": 25,\n" " \"main_type\": 221,\n" " \"name\": \"ping\",\n" " \"description\": [ \"\", \"\" ],\n" " \"list_order\": -244244146,\n" " \"from_classifier_id\": 15,\n" " \"from_classifier_name\": \"\\\"the Serializer\\\"\",\n" " \"to_classifier_id\": 13,\n" " \"to_classifier_name\": \"New||RingBuffer{⅞[\\]}\",\n" " \"from_feature_id\": 34,\n" " \"from_feature_key\": \"\",\n" " \"to_feature_id\": 33,\n" " \"to_feature_key\": \"\",\n" " \"uuid\": \"429fc16a-50d3-4541-b5a1-077381b55f02\"\n" " }\n" " }\n" " ]\n" "}\n"; static const char *const test_json_no_diag = "{\n" " \"head\":\n" " {\n" " },\n" " \"views\": \n" " [\n" " ],\n" " \"nodes\": \n" " [\n" " {\n" " \"classifier\": {\n" " \"id\": 13,\n" " \"main_type\": 125,\n" " \"stereotype\": \"\",\n" " \"name\": \"New||RingBuffer{⅞[\\]}\",\n" " \"description\": [ \"world\\n\", \"world\" ],\n" " \"x_order\": -1087446901,\n" " \"y_order\": 359417528,\n" " \"list_order\": 446877143,\n" " \"features\": \n" " [\n" " {\n" " \"id\": 33,\n" " \"main_type\": 3,\n" " \"key\": \"\",\n" " \"value\": \"\",\n" " \"description\": [ \"i am a lifeline\" ],\n" " \"list_order\": 0,\n" " \"uuid\": \"67c2bc6d-ddc7-458a-80f1-be353c197381\"\n" " },\n" " {\n" " \"id\": 11,\n" " \"main_type\": 1,\n" " \"key\": \"new_get_mode\",\n" " \"value\": \"enum\",\n" " \"description\": [ ],\n" " \"list_order\": 425984\n" " }\n" " ]\n" " }\n" " }\n" " ],\n" " \"edges\": \n" " [\n" " {\n" " \"relationship\": {\n" " \"id\": 25,\n" " \"main_type\": 221,\n" " \"name\": \"ping\",\n" " \"description\": [ \"LINE-1\\nLINE-2\" ],\n" " \"list_order\": -244244146,\n" " \"from_classifier_id\": 15,\n" " \"from_classifier_name\": \"\\\"the Serializer\\\"\",\n" " \"to_classifier_id\": 13,\n" " \"to_classifier_name\": \"New||RingBuffer{⅞[\\]}\",\n" " \"from_feature_id\": 12,\n" " \"from_feature_key\": \"new_get_state\",\n" " \"to_feature_id\": 11,\n" " \"to_feature_key\": \"new_get_mode\"\n" " }\n" " }\n" " ]\n" "}\n"; static void insert_invalid_json(void) { data_row_id_t root_diag_id = create_root_diag(); json_import_to_database_t importer; json_import_to_database_init ( &importer, &db_reader, &controller ); data_error_t data_err; data_stat_t stat; data_stat_init(&stat); uint32_t read_line; static const char *json_text_p = "{\"head\":{},\"views\":[{\n\"unknown-type\"\n:{}}]}"; data_err = json_import_to_database_import_buf_to_db( &importer, json_text_p, root_diag_id, &stat, &read_line ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_PARSER_STRUCTURE, data_err ); TEST_ASSERT_EQUAL_INT( data_stat_get_total_count( &stat ), 0 ); TEST_ASSERT_EQUAL_INT( read_line, 2 ); /* error happens at char 24 according to the log */ /* but this happens in json_deserializer_get_type_of_next_element which does not advance the read pos */ static const char *json_text_l = "{\"head\":{},\"views\":[{\"diagram\":\nnullnul\n}]}"; data_err = json_import_to_database_import_buf_to_db( &importer, json_text_l, root_diag_id, &stat, &read_line ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_PARSER_STRUCTURE, data_err ); TEST_ASSERT_EQUAL_INT( data_stat_get_total_count( &stat ), 0 ); TEST_ASSERT_EQUAL_INT( read_line, 2 ); data_stat_destroy(&stat); json_import_to_database_destroy ( &importer ); } static void insert_invalid_parent_diag(void) { data_row_id_t root_diag_id = create_root_diag(); json_import_to_database_t importer; json_import_to_database_init ( &importer, &db_reader, &controller ); data_error_t data_err; data_stat_t stat; data_stat_init(&stat); uint32_t read_line; data_err = json_import_to_database_import_buf_to_db( &importer, test_json_no_diag, root_diag_id+1, /* does not exist */ &stat, &read_line ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_DB_STRUCTURE, data_err ); TEST_ASSERT_EQUAL_INT( data_stat_get_total_count( &stat ), 0 ); TEST_ASSERT_EQUAL_INT( read_line, 1 ); data_stat_destroy(&stat); json_import_to_database_destroy ( &importer ); } static void insert_empty_set(void) { data_row_id_t root_diag_id = create_root_diag(); json_import_to_database_t importer; json_import_to_database_init ( &importer, &db_reader, &controller ); data_error_t data_err; data_stat_t stat; data_stat_init(&stat); uint32_t read_line; static const char *json_text = "{\"head\":{},\"views\":[],\"nodes\":[],\"edges\":[]}\n"; data_err = json_import_to_database_import_buf_to_db( &importer, json_text, root_diag_id, &stat, &read_line ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, data_err ); TEST_ASSERT_EQUAL_INT( data_stat_get_total_count( &stat ), 0 ); TEST_ASSERT_EQUAL_INT( read_line, 2 ); data_stat_destroy(&stat); json_import_to_database_destroy ( &importer ); } static void insert_new_classifier_to_existing_diagram(void) { data_row_id_t root_diag_id = create_root_diag(); json_import_to_database_t importer; json_import_to_database_init ( &importer, &db_reader, &controller ); data_error_t data_err; data_stat_t stat; data_stat_init(&stat); uint32_t read_pos; data_err = json_import_to_database_import_buf_to_db( &importer, test_json_no_diag, root_diag_id, &stat, &read_pos ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, data_err ); TEST_ASSERT_EQUAL_INT( 0, data_stat_get_table_count( &stat, DATA_TABLE_DIAGRAM ) ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_CREATED ) ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_CLASSIFIER, DATA_STAT_SERIES_CREATED ) ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_CREATED ) ); /* DATA_TABLE_FEATURE: lifeline (type 3) is dropped */ TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_IGNORED ) ); /* DATA_TABLE_RELATIONSHIP: no names of auto-generated lifelines are mentioned, therefore only unconditional relationships */ TEST_ASSERT_EQUAL_INT( 0, data_stat_get_count( &stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_CREATED ) ); /* DATA_TABLE_RELATIONSHIP: source does not exist */ TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_ERROR ) ); TEST_ASSERT_EQUAL_INT( 5, data_stat_get_total_count( &stat ) ); TEST_ASSERT_EQUAL_INT( 64, read_pos ); data_stat_destroy(&stat); json_import_to_database_destroy ( &importer ); } static void insert_new_classifier_to_new_diagram(void) { data_row_id_t root_diag_id = create_root_diag(); json_import_to_database_t importer; json_import_to_database_init ( &importer, &db_reader, &controller ); data_error_t data_err; data_stat_t stat; data_stat_init(&stat); uint32_t read_pos; data_err = json_import_to_database_import_buf_to_db( &importer, test_json_own_diagram, root_diag_id, &stat, &read_pos ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, data_err ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_DIAGRAM, DATA_STAT_SERIES_CREATED ) ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_CREATED ) ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_CLASSIFIER, DATA_STAT_SERIES_CREATED ) ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_CREATED ) ); /* DATA_TABLE_FEATURE: lifeline (type 3) is dropped */ TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_IGNORED ) ); /* DATA_TABLE_RELATIONSHIP: no names of auto-generated lifelines are mentioned, therefore only unconditional relationships */ TEST_ASSERT_EQUAL_INT( 0, data_stat_get_count( &stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_CREATED ) ); /* DATA_TABLE_RELATIONSHIP: destination does not exist */ TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_ERROR ) ); TEST_ASSERT_EQUAL_INT( 6, data_stat_get_total_count( &stat ) ); TEST_ASSERT_EQUAL_INT( 87, read_pos ); data_stat_destroy(&stat); json_import_to_database_destroy ( &importer ); } static void insert_existing_classifier_to_existing_diagram(void) { data_row_id_t root_diag_id = create_root_diag(); json_import_to_database_t importer; json_import_to_database_init ( &importer, &db_reader, &controller ); data_error_t data_err; { data_stat_t stat; data_stat_init(&stat); uint32_t read_pos; data_err = json_import_to_database_import_buf_to_db( &importer, test_json_no_diag, root_diag_id, &stat, &read_pos ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, data_err ); TEST_ASSERT_EQUAL_INT( 5, data_stat_get_total_count( &stat ) ); /* as in test case insert_new_classifier_to_existing_diagram */ TEST_ASSERT_EQUAL_INT( 64, read_pos ); data_stat_destroy(&stat); } { data_stat_t stat; data_stat_init(&stat); uint32_t read_pos; data_err = json_import_to_database_import_buf_to_db( &importer, test_json_no_diag, root_diag_id, &stat, &read_pos ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, data_err ); TEST_ASSERT_EQUAL_INT( 0, data_stat_get_table_count( &stat, DATA_TABLE_DIAGRAM ) ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_CREATED ) ); TEST_ASSERT_EQUAL_INT( 0, data_stat_get_count( &stat, DATA_TABLE_CLASSIFIER, DATA_STAT_SERIES_CREATED ) ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_CLASSIFIER, DATA_STAT_SERIES_IGNORED ) ); TEST_ASSERT_EQUAL_INT( 0, data_stat_get_count( &stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_CREATED ) ); /* DATA_TABLE_FEATURE: lifeline (type 3) is dropped */ /* DATA_TABLE_FEATURE a feature of an already existing classifier is dropped */ TEST_ASSERT_EQUAL_INT( 2, data_stat_get_count( &stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_IGNORED ) ); TEST_ASSERT_EQUAL_INT( 0, data_stat_get_count( &stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_WARNING ) ); /* DATA_TABLE_RELATIONSHIP: no names of auto-generated lifelines are mentioned, therefore only unconditional relationships */ TEST_ASSERT_EQUAL_INT( 0, data_stat_get_count( &stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_CREATED ) ); /* DATA_TABLE_RELATIONSHIP: source does not exist */ TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_ERROR ) ); TEST_ASSERT_EQUAL_INT( 5, data_stat_get_total_count( &stat ) ); TEST_ASSERT_EQUAL_INT( 64, read_pos ); data_stat_destroy(&stat); } json_import_to_database_destroy ( &importer ); } static void insert_existing_classifier_to_new_diagram(void) { data_row_id_t root_diag_id = create_root_diag(); json_import_to_database_t importer; json_import_to_database_init ( &importer, &db_reader, &controller ); data_error_t data_err; { data_stat_t stat; data_stat_init(&stat); uint32_t read_pos; data_err = json_import_to_database_import_buf_to_db( &importer, test_json_own_diagram, root_diag_id, &stat, &read_pos ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, data_err ); TEST_ASSERT_EQUAL_INT( 6, data_stat_get_total_count( &stat ) ); /* as in test case insert_new_classifier_to_new_diagram */ TEST_ASSERT_EQUAL_INT( 87, read_pos ); data_stat_destroy(&stat); } { data_stat_t stat; data_stat_init(&stat); uint32_t read_pos; data_err = json_import_to_database_import_buf_to_db( &importer, test_json_own_diagram, root_diag_id, &stat, &read_pos ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, data_err ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_DIAGRAM, DATA_STAT_SERIES_CREATED ) ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_CREATED ) ); TEST_ASSERT_EQUAL_INT( 0, data_stat_get_count( &stat, DATA_TABLE_CLASSIFIER, DATA_STAT_SERIES_CREATED ) ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_CLASSIFIER, DATA_STAT_SERIES_IGNORED ) ); TEST_ASSERT_EQUAL_INT( 0, data_stat_get_count( &stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_CREATED ) ); /* DATA_TABLE_FEATURE: lifeline (type 3) is dropped */ /* DATA_TABLE_FEATURE a feature of an already existing classifier is dropped */ TEST_ASSERT_EQUAL_INT( 2, data_stat_get_count( &stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_IGNORED ) ); TEST_ASSERT_EQUAL_INT( 0, data_stat_get_count( &stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_WARNING ) ); /* DATA_TABLE_RELATIONSHIP: no names of auto-generated lifelines are mentioned, therefore only unconditional relationships */ TEST_ASSERT_EQUAL_INT( 0, data_stat_get_count( &stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_CREATED ) ); /* DATA_TABLE_RELATIONSHIP: destination does not exist */ TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_ERROR ) ); TEST_ASSERT_EQUAL_INT( 6, data_stat_get_total_count( &stat ) ); TEST_ASSERT_EQUAL_INT( 87, read_pos ); data_stat_destroy(&stat); } json_import_to_database_destroy ( &importer ); } static void insert_unconditional_relationships(void) { data_row_id_t root_diag_id = create_root_diag(); json_import_to_database_t importer; json_import_to_database_init ( &importer, &db_reader, &controller ); data_error_t data_err; { data_stat_t stat; data_stat_init(&stat); uint32_t read_pos; data_err = json_import_to_database_import_buf_to_db( &importer, test_json_own_diagram, root_diag_id, &stat, &read_pos ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, data_err ); TEST_ASSERT_EQUAL_INT( 6, data_stat_get_total_count( &stat ) ); /* as in test case insert_new_classifier_to_new_diagram */ TEST_ASSERT_EQUAL_INT( 87, read_pos ); data_stat_destroy(&stat); } { data_stat_t stat; data_stat_init(&stat); uint32_t read_pos; data_err = json_import_to_database_import_buf_to_db( &importer, test_json_no_diag, root_diag_id, &stat, &read_pos ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, data_err ); TEST_ASSERT_EQUAL_INT( 0, data_stat_get_table_count( &stat, DATA_TABLE_DIAGRAM ) ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_CREATED ) ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_CLASSIFIER, DATA_STAT_SERIES_CREATED ) ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_CREATED ) ); /* DATA_TABLE_FEATURE: lifeline (type 3) is dropped */ TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_IGNORED ) ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_CREATED ) ); TEST_ASSERT_EQUAL_INT( 5, data_stat_get_total_count( &stat ) ); TEST_ASSERT_EQUAL_INT( 64, read_pos ); data_stat_destroy(&stat); } json_import_to_database_destroy ( &importer ); } static const char *const test_scenario_relationship = "{\n" " \"head\":\n" " {\n" " },\n" " \"views\": \n" " [\n" " {\n" " \"diagram\": {\n" " \"id\": 3,\n" " \"diagram_type\": 13,\n" " \"name\": \"Sequence 1\",\n" " \"description\": [ \"LINE-1\\n\", \"LINE-2\" ],\n" " \"list_order\": 65536\n" " }\n" " }\n" " ],\n" " \"nodes\": \n" " [\n" " {\n" " \"classifier\": {\n" " \"id\": 15,\n" " \"main_type\": 125,\n" " \"stereotype\": \"\",\n" " \"name\": \"\\\"the Serializer\\\"\",\n" " \"description\": [ \"hello\\nhello\" ],\n" " \"x_order\": -1087446901,\n" " \"y_order\": 359417528,\n" " \"list_order\": 446877143,\n" " \"features\": \n" " [\n" " ]\n" " }\n" " },\n" " {\n" " \"classifier\": {\n" " \"id\": 13,\n" " \"main_type\": 125,\n" " \"stereotype\": \"\",\n" " \"name\": \"New||RingBuffer{⅞[\\]}\",\n" " \"description\": [ \"world\\nworld\" ],\n" " \"x_order\": -1087446901,\n" " \"y_order\": 359417528,\n" " \"list_order\": 446877143,\n" " \"features\": \n" " [\n" " ]\n" " }\n" " }\n" " ],\n" " \"edges\": \n" " [\n" " {\n" " \"relationship\": {\n" " \"id\": 25,\n" " \"main_type\": 221,\n" " \"name\": \"ping\",\n" " \"description\": [ ],\n" " \"list_order\": -244244146,\n" " \"from_classifier_id\": 15,\n" " \"from_classifier_name\": \"\\\"the Serializer\\\"\",\n" " \"to_classifier_id\": 13,\n" " \"to_classifier_name\": \"New||RingBuffer{⅞[\\]}\",\n" " \"from_feature_id\": 34,\n" " \"from_feature_key\": \"\",\n" " \"to_feature_id\": 33,\n" " \"to_feature_key\": \"\"\n" " }\n" " }\n" " ]\n" "}\n"; static void insert_scenario_relationships_to_scenario(void) { data_row_id_t root_diag_id = create_root_diag(); json_import_to_database_t importer; json_import_to_database_init ( &importer, &db_reader, &controller ); data_error_t data_err; data_stat_t stat; data_stat_init(&stat); uint32_t read_pos; data_err = json_import_to_database_import_buf_to_db( &importer, test_scenario_relationship, root_diag_id, &stat, &read_pos ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, data_err ); /* type 13 == DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM; is scenario */ TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_DIAGRAM, DATA_STAT_SERIES_CREATED ) ); TEST_ASSERT_EQUAL_INT( 2, data_stat_get_count( &stat, DATA_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_CREATED ) ); TEST_ASSERT_EQUAL_INT( 2, data_stat_get_count( &stat, DATA_TABLE_CLASSIFIER, DATA_STAT_SERIES_CREATED ) ); TEST_ASSERT_EQUAL_INT( 0, data_stat_get_table_count( &stat, DATA_TABLE_FEATURE ) ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_CREATED ) ); TEST_ASSERT_EQUAL_INT( 6, data_stat_get_total_count( &stat ) ); TEST_ASSERT_EQUAL_INT( 71, read_pos ); data_stat_destroy(&stat); json_import_to_database_destroy ( &importer ); } static const char *const test_json_scenario_self_relation = "{\n" " \"head\":\n" " {\n" " },\n" " \"views\": \n" " [\n" " ],\n" " \"nodes\": \n" " [\n" " ],\n" " \"edges\": \n" " [\n" " {\n" " \"relationship\": {\n" " \"id\": 25,\n" " \"main_type\": 221,\n" " \"name\": \"ping\",\n" " \"description\": [ \"LINE-1\\n\", \"LINE-2\\n\" ],\n" " \"list_order\": 44244146,\n" " \"from_classifier_id\": 13,\n" " \"from_classifier_name\": \"New||RingBuffer{⅞[\\]}\",\n" " \"to_classifier_id\": 13,\n" " \"to_classifier_name\": \"New||RingBuffer{⅞[\\]}\",\n" " \"from_feature_id\": 33,\n" " \"from_feature_key\": \"\",\n" " \"to_feature_id\": 33,\n" " \"to_feature_key\": \"\"\n" " }\n" " }\n" " ]\n" "}\n"; static void insert_scenario_relationships_to_non_scenario(void) { data_row_id_t root_diag_id = create_root_diag(); /* root doag type is DATA_DIAGRAM_TYPE_UML_CLASS_DIAGRAM, no scenario */ json_import_to_database_t importer; json_import_to_database_init ( &importer, &db_reader, &controller ); data_error_t data_err; { data_stat_t stat; data_stat_init(&stat); uint32_t read_pos; data_err = json_import_to_database_import_buf_to_db( &importer, test_json_no_diag, root_diag_id, &stat, &read_pos ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, data_err ); TEST_ASSERT_EQUAL_INT( 5, data_stat_get_total_count( &stat ) ); /* as in test case insert_new_classifier_to_existing_diagram */ TEST_ASSERT_EQUAL_INT( 64, read_pos ); data_stat_destroy(&stat); } { data_stat_t stat; data_stat_init(&stat); uint32_t read_pos; data_err = json_import_to_database_import_buf_to_db( &importer, test_json_scenario_self_relation, root_diag_id, &stat, &read_pos ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, data_err ); /* type 13 == DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM; is scenario */ TEST_ASSERT_EQUAL_INT( 0, data_stat_get_table_count( &stat, DATA_TABLE_DIAGRAM ) ); TEST_ASSERT_EQUAL_INT( 0, data_stat_get_table_count( &stat, DATA_TABLE_DIAGRAMELEMENT ) ); TEST_ASSERT_EQUAL_INT( 0, data_stat_get_table_count( &stat, DATA_TABLE_CLASSIFIER ) ); TEST_ASSERT_EQUAL_INT( 0, data_stat_get_table_count( &stat, DATA_TABLE_FEATURE ) ); /* DATA_TABLE_RELATIONSHIP: source+dst classifier have no lifeline, no evidence for scenario */ TEST_ASSERT_EQUAL_INT( 0, data_stat_get_count( &stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_CREATED ) ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_count( &stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_ERROR ) ); TEST_ASSERT_EQUAL_INT( 1, data_stat_get_total_count( &stat ) ); TEST_ASSERT_EQUAL_INT( 32, read_pos ); data_stat_destroy(&stat); } json_import_to_database_destroy ( &importer ); } /* * Copyright 2019-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/io/test/unit/json_import_to_database_test.h000066400000000000000000000017001415120503000255670ustar00rootroot00000000000000/* File: json_import_to_database_test.h; Copyright and License: see below */ #ifndef JSON_IMPORT_TO_DATABASE_TEST_H #define JSON_IMPORT_TO_DATABASE_TEST_H /*! * \file * \brief MODULE TEST for json_import_to_database */ #include "test_suite.h" test_suite_t json_import_to_database_test_get_list(void); #endif /* JSON_IMPORT_TO_DATABASE_TEST_H */ /* * Copyright 2019-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/io/test/unit/json_token_reader_test.c000066400000000000000000000526001415120503000243710ustar00rootroot00000000000000/* File: json_token_reader_test.c; Copyright and License: see below */ #include "json_token_reader_test.h" #include "json/json_token_reader.h" #include "stream/universal_memory_input_stream.h" #include "test_assert.h" static void set_up(void); static void tear_down(void); static void test_skip_whitespace(void); static void test_is_value_end(void); static void test_get_value_type(void); static void test_parse_string(void); static void test_parse_integer(void); static void test_skip_number(void); static void test_parse(void); test_suite_t json_token_reader_test_get_list(void) { test_suite_t result; test_suite_init( &result, "json_token_reader_test", &set_up, &tear_down ); test_suite_add_test_case( &result, "test_skip_whitespace", &test_skip_whitespace ); test_suite_add_test_case( &result, "test_is_value_end", &test_is_value_end ); test_suite_add_test_case( &result, "test_get_value_type", &test_get_value_type ); test_suite_add_test_case( &result, "test_parse_string", &test_parse_string ); test_suite_add_test_case( &result, "test_parse_integer", &test_parse_integer ); test_suite_add_test_case( &result, "test_skip_number", &test_skip_number ); test_suite_add_test_case( &result, "test_parse", &test_parse ); return result; } static void set_up(void) { } static void tear_down(void) { } static json_token_reader_t tok; static void test_skip_whitespace(void) { universal_memory_input_stream_t test_input; const char test_str1[3] = "4 "; universal_memory_input_stream_init( &test_input, &test_str1, sizeof(test_str1) ); json_token_reader_init( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); /* test skip nothing */ json_token_reader_private_skip_whitespace( &tok ); TEST_ASSERT_EQUAL_INT( 0, json_token_reader_get_input_pos( &tok ) ); /* reset to test_str2 */ const char test_str2[10] = " \t\t\r\r\n\nd"; universal_memory_input_stream_reinit( &test_input, &test_str2, sizeof(test_str2) ); json_token_reader_reinit( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); /* test skip at string end */ json_token_reader_private_skip_whitespace( &tok ); TEST_ASSERT_EQUAL_INT( 8, json_token_reader_get_input_pos( &tok ) ); /* reset to test_str3 */ const char test_str3[1] = ""; universal_memory_input_stream_reinit( &test_input, &test_str3, sizeof(test_str3) ); json_token_reader_reinit( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); /* test skip all 4 whitespace types */ json_token_reader_private_skip_whitespace( &tok ); TEST_ASSERT_EQUAL_INT( 0, json_token_reader_get_input_pos( &tok ) ); json_token_reader_destroy( &tok ); universal_memory_input_stream_destroy( &test_input ); } static void test_is_value_end(void) { const char test_str[17] = "+2f\r" "5,7:" "9}b " "\"e\"."; const char results[18] = "0001" "0101" "0101" "00001"; assert( sizeof(test_str)+1 == sizeof(results) ); universal_memory_input_stream_t test_input; universal_memory_input_stream_init( &test_input, &test_str, sizeof(test_str) ); json_token_reader_init( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); /* test all positions */ for ( int pos = 0; pos < (sizeof(results)-1); pos ++ ) { /* reset to test_str[pos] */ universal_memory_input_stream_reinit( &test_input, &(test_str[pos]), sizeof(char) ); json_token_reader_reinit( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); const bool is_end = json_token_reader_private_is_value_end( &tok ); TEST_ASSERT_EQUAL_INT( ( results[pos] == '1' ), is_end ); } json_token_reader_destroy( &tok ); universal_memory_input_stream_destroy( &test_input ); } static void test_get_value_type(void) { data_error_t test_err; universal_memory_input_stream_t test_input; json_value_type_t value_type; /* JSON_VALUE_TYPE_OBJECT */ const char test_str_1[4] = "\n{a"; universal_memory_input_stream_init( &test_input, &test_str_1, sizeof(test_str_1) ); json_token_reader_init( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); test_err = json_token_reader_get_value_type ( &tok, &value_type ); TEST_ASSERT_EQUAL_INT( 1, json_token_reader_get_input_pos( &tok ) ); /* there is a whitespace in front of the value */ TEST_ASSERT_EQUAL_INT( JSON_VALUE_TYPE_OBJECT, value_type ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, test_err ); /* JSON_VALUE_TYPE_ARRAY */ const char test_str_2[4] = " [\t"; universal_memory_input_stream_reinit( &test_input, &test_str_2, sizeof(test_str_2) ); json_token_reader_reinit( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); test_err = json_token_reader_get_value_type ( &tok, &value_type ); TEST_ASSERT_EQUAL_INT( 1, json_token_reader_get_input_pos( &tok ) ); /* there is a whitespace in front of the value */ TEST_ASSERT_EQUAL_INT( JSON_VALUE_TYPE_ARRAY, value_type ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, test_err ); /* JSON_VALUE_TYPE_NUMBER */ const char test_str_3[4] = "-12"; universal_memory_input_stream_reinit( &test_input, &test_str_3, sizeof(test_str_3) ); json_token_reader_reinit( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); test_err = json_token_reader_get_value_type ( &tok, &value_type ); TEST_ASSERT_EQUAL_INT( 0, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( JSON_VALUE_TYPE_NUMBER, value_type ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, test_err ); /* JSON_VALUE_TYPE_STRING */ const char test_str_4[4] = "\"s\""; universal_memory_input_stream_reinit( &test_input, &test_str_4, sizeof(test_str_4) ); json_token_reader_reinit( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); test_err = json_token_reader_get_value_type ( &tok, &value_type ); TEST_ASSERT_EQUAL_INT( 0, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( JSON_VALUE_TYPE_STRING, value_type ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, test_err ); /* JSON_VALUE_TYPE_NULL */ const char test_str_5[4] = "nul"; universal_memory_input_stream_reinit( &test_input, &test_str_5, sizeof(test_str_5) ); json_token_reader_reinit( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); test_err = json_token_reader_get_value_type ( &tok, &value_type ); TEST_ASSERT_EQUAL_INT( 0, json_token_reader_get_input_pos( &tok ) ); /* there is a whitespace in front of the value */ TEST_ASSERT_EQUAL_INT( JSON_VALUE_TYPE_NULL, value_type ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, test_err ); /* JSON_VALUE_TYPE_BOOLEAN */ const char test_str_6[4] = "fal"; universal_memory_input_stream_reinit( &test_input, &test_str_6, sizeof(test_str_6) ); json_token_reader_reinit( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); test_err = json_token_reader_get_value_type ( &tok, &value_type ); TEST_ASSERT_EQUAL_INT( 0, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( JSON_VALUE_TYPE_BOOLEAN, value_type ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, test_err ); /* JSON_VALUE_TYPE_BOOLEAN */ const char test_str_7[4] = "\n\tt"; universal_memory_input_stream_reinit( &test_input, &test_str_7, sizeof(test_str_7) ); json_token_reader_reinit( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); test_err = json_token_reader_get_value_type ( &tok, &value_type ); TEST_ASSERT_EQUAL_INT( 2, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( JSON_VALUE_TYPE_BOOLEAN, value_type ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, test_err ); /* JSON_VALUE_TYPE_UNDEF */ const char test_str_8[4] = " ]}"; universal_memory_input_stream_reinit( &test_input, &test_str_8, sizeof(test_str_8) ); json_token_reader_reinit( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); test_err = json_token_reader_get_value_type ( &tok, &value_type ); TEST_ASSERT_EQUAL_INT( 1, json_token_reader_get_input_pos( &tok ) ); /* there is a whitespace in front of the not-value */ TEST_ASSERT_EQUAL_INT( JSON_VALUE_TYPE_UNDEF, value_type ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_PARSER_STRUCTURE, test_err ); /* EOF */ const char test_str_9[4] = " \r"; universal_memory_input_stream_reinit( &test_input, &test_str_9, sizeof(test_str_9) ); json_token_reader_reinit( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); test_err = json_token_reader_get_value_type ( &tok, &value_type ); TEST_ASSERT_EQUAL_INT( 3, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( JSON_VALUE_TYPE_UNDEF, value_type ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_PARSER_STRUCTURE, test_err ); json_token_reader_destroy( &tok ); universal_memory_input_stream_destroy( &test_input ); } static void test_parse_string(void) { data_error_t test_err; const char test_str[6][17] = { "\"\'\'simple \'\'\"", "\"\\\\mixed \\n\'\"", "\"\'\'esc at end\\\\\"", "\"\'\'2quote@end\\\"\"", "\"\'\'trailing\"trail", "\"\'\' no_end\\\"", }; char parsed_buf[20]; utf8stringbuf_t parsed_str = UTF8STRINGBUF( parsed_buf ); const char expect_str[6][15] = { "\'\'simple \'\'", "\\mixed \n\'", "\'\'esc at end\\", "\'\'2quote@end\"", "\'\'trailing", "\'\' no_end\"", }; universal_memory_input_stream_t test_input; universal_memory_input_stream_init( &test_input, &(test_str[0]), sizeof(test_str[0]) ); json_token_reader_init( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); /* test all positions */ for ( int index = 0; index < 6; index ++ ) { universal_memory_input_stream_reinit( &test_input, &(test_str[index]), sizeof(test_str[index]) ); json_token_reader_reinit( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); test_err = json_token_reader_read_string_value( &tok, parsed_str ); TEST_ASSERT_EQUAL_INT( (index>=4)?DATA_ERROR_LEXICAL_STRUCTURE:DATA_ERROR_NONE, test_err ); TEST_ASSERT_EQUAL_INT( 1, utf8stringbuf_equals_str( parsed_str, expect_str[index] ) ); } json_token_reader_destroy( &tok ); universal_memory_input_stream_destroy( &test_input ); } static void test_parse_integer(void) { data_error_t test_err; const char test_str[8][16] = { " 0", " 00", " -33", " -0", "-12345678,other", " -hello", " 123]", " abc", }; const int64_t int_results[8] = {0,0,-33,0,-12345678,0,123,0}; const int err_results[8] = {0,1, 0,1, 0,1, 0,1}; int64_t int_result; universal_memory_input_stream_t test_input; universal_memory_input_stream_init( &test_input, &(test_str[0]), sizeof(test_str[0]) ); json_token_reader_init( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); /* test all positions */ for ( int index = 0; index < 8; index ++ ) { universal_memory_input_stream_reinit( &test_input, &(test_str[index]), sizeof(test_str[index]) ); json_token_reader_reinit( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); test_err = json_token_reader_read_int_value( &tok, &int_result ); TEST_ASSERT_EQUAL_INT( (err_results[index]!=0)?DATA_ERROR_LEXICAL_STRUCTURE:DATA_ERROR_NONE, test_err ); TEST_ASSERT_EQUAL_INT( int_results[index], int_result ); printf("parsed: %" PRId64 "\n",int_result); } json_token_reader_destroy( &tok ); universal_memory_input_stream_destroy( &test_input ); } static void test_skip_number(void) { data_error_t test_err; const char test_str[8][16] = { "0.0000 ", "000000 ", "-33e+0 ", "-1.456;", "1.5e+8,", "1.4E88}", "1.5E-8]", "+123E8\n", }; universal_memory_input_stream_t test_input; universal_memory_input_stream_init( &test_input, &(test_str[0]), sizeof(test_str[0]) ); json_token_reader_init( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); /* test all positions */ for ( int index = 0; index < 8; index ++ ) { universal_memory_input_stream_reinit( &test_input, &(test_str[index]), sizeof(test_str[index]) ); json_token_reader_reinit( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); test_err = json_token_reader_private_skip_number( &tok ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, test_err ); TEST_ASSERT_EQUAL_INT( 6, json_token_reader_get_input_pos( &tok ) ); /* all numbers have 6 digits */ } json_token_reader_destroy( &tok ); universal_memory_input_stream_destroy( &test_input ); } static void test_parse(void) { static const char test_str[] = "\n{" "\n \"data\": [" "\n {" "\n \"classifier\"\t: {" "\n \"id\" \r\n:-99," "\n \"main_type\" \n\t\r : 90.0e+0 " "\n \"stereotype\\r\\/\\\"\\\\\": \"\\f\\n\\t\\b\\r\\/\\\"\\\\\"" "\n }" "\n }," "\n null," "\n true," "\n false" "\n ]" "\n}" "\n"; data_error_t res; bool cond; char my_buf[32]; utf8stringbuf_t my_string = UTF8STRINGBUF( my_buf ); int64_t my_int; double my_double; bool my_bool; universal_memory_input_stream_t test_input; universal_memory_input_stream_init( &test_input, &test_str, sizeof(test_str) ); json_token_reader_init( &tok, universal_memory_input_stream_get_input_stream( &test_input ) ); res = json_token_reader_expect_begin_object ( &tok ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 2, json_token_reader_get_input_pos( &tok ) ); res = json_token_reader_check_end_object ( &tok, &cond ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 5, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( false, cond ); res = json_token_reader_read_member_name ( &tok, my_string ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 11, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( 0, strcmp( "data", utf8stringbuf_get_string(my_string)) ); res = json_token_reader_expect_name_separator( &tok ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 12, json_token_reader_get_input_pos( &tok ) ); res = json_token_reader_expect_begin_array ( &tok ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 14, json_token_reader_get_input_pos( &tok ) ); res = json_token_reader_check_end_array ( &tok, &cond ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 19, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( false, cond ); res = json_token_reader_expect_begin_object ( &tok ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 20, json_token_reader_get_input_pos( &tok ) ); res = json_token_reader_check_end_object ( &tok, &cond ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 27, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( false, cond ); res = json_token_reader_read_member_name ( &tok, my_string ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 39, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( 0, strcmp( "classifier", utf8stringbuf_get_string(my_string)) ); res = json_token_reader_expect_name_separator( &tok ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 41, json_token_reader_get_input_pos( &tok ) ); res = json_token_reader_expect_begin_object ( &tok ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 43, json_token_reader_get_input_pos( &tok ) ); /* skip test for end object here */ res = json_token_reader_read_member_name ( &tok, my_string ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 56, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( 0, strcmp( "id", utf8stringbuf_get_string(my_string)) ); res = json_token_reader_expect_name_separator( &tok ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 61, json_token_reader_get_input_pos( &tok ) ); res = json_token_reader_read_int_value ( &tok, &my_int ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 64, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( -99, my_int ); /* skip test for end object here */ res = json_token_reader_expect_value_separator( &tok ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 65, json_token_reader_get_input_pos( &tok ) ); res = json_token_reader_read_member_name ( &tok, my_string ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 85, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( 0, strcmp( "main_type", utf8stringbuf_get_string(my_string)) ); res = json_token_reader_expect_name_separator( &tok ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 91, json_token_reader_get_input_pos( &tok ) ); res = json_token_reader_read_number_value ( &tok, &my_double ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NOT_YET_IMPLEMENTED, res ); TEST_ASSERT_EQUAL_INT( 99, json_token_reader_get_input_pos( &tok ) ); /* skip test for end object here */ res = json_token_reader_read_member_name ( &tok, my_string ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 129, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( 0, strcmp( "stereotype\r/\"\\", utf8stringbuf_get_string(my_string)) ); res = json_token_reader_expect_name_separator( &tok ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 130, json_token_reader_get_input_pos( &tok ) ); res = json_token_reader_read_string_value ( &tok, my_string ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 149, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( 0, strcmp( "\f\n\t\b\r/\"\\", utf8stringbuf_get_string(my_string)) ); res = json_token_reader_check_end_object ( &tok, &cond ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 157, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( true, cond ); res = json_token_reader_check_end_object ( &tok, &cond ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 163, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( true, cond ); /* skip test for end array here */ res = json_token_reader_expect_value_separator( &tok ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 164, json_token_reader_get_input_pos( &tok ) ); res = json_token_reader_expect_null_value ( &tok ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 173, json_token_reader_get_input_pos( &tok ) ); /* skip test for end array here */ res = json_token_reader_expect_value_separator( &tok ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 174, json_token_reader_get_input_pos( &tok ) ); res = json_token_reader_read_boolean_value ( &tok, &my_bool ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 183, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( true, my_bool ); /* skip test for end array here */ res = json_token_reader_expect_value_separator( &tok ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 184, json_token_reader_get_input_pos( &tok ) ); res = json_token_reader_read_boolean_value ( &tok, &my_bool ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 194, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( false, my_bool ); res = json_token_reader_check_end_array ( &tok, &cond ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 198, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( true, cond ); res = json_token_reader_check_end_object ( &tok, &cond ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 200, json_token_reader_get_input_pos( &tok ) ); TEST_ASSERT_EQUAL_INT( true, cond ); res = json_token_reader_expect_eof ( &tok ); TEST_ASSERT_EQUAL_INT( DATA_ERROR_NONE, res ); TEST_ASSERT_EQUAL_INT( 201, json_token_reader_get_input_pos( &tok ) ); json_token_reader_destroy( &tok ); universal_memory_input_stream_destroy( &test_input ); } /* * Copyright 2016-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/io/test/unit/json_token_reader_test.h000066400000000000000000000016201415120503000243720ustar00rootroot00000000000000/* File: json_token_reader_test.h; Copyright and License: see below */ #ifndef JSON_TOKENIZER_TEST_H #define JSON_TOKENIZER_TEST_H /*! * \file * \brief UNITTEST for json_token_reader */ #include "test_suite.h" test_suite_t json_token_reader_test_get_list(void); #endif /* JSON_TOKENIZER_TEST_H */ /* * Copyright 2016-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/io/test/unit/md_filter_test.c000066400000000000000000000164771415120503000226570ustar00rootroot00000000000000/* File: md_filter_test.c; Copyright and License: see below */ #include "md_filter_test.h" #include "md/md_filter.h" #include "xml/xml_writer.h" #include "ctrl_controller.h" #include "storage/data_database.h" #include "storage/data_database_writer.h" #include "storage/data_database_reader.h" #include "stream/universal_memory_output_stream.h" #include "trace.h" #include "test_assert.h" static void set_up(void); static void tear_down(void); static void test_md_plain_mixed(void); static void test_valid_links(void); static void test_invalid_links(void); static data_row_id_t create_root_diag(); /* helper function */ /*! * \brief database instance on which the tests are performed */ static data_database_t database; /*! * \brief database reader to access the database */ static data_database_reader_t db_reader; /*! * \brief controller instance on which the tests are performed */ static ctrl_controller_t controller; /*! * \brief md_filter to be tested */ static md_filter_t md_filter; #define TAG_BREAK "&LN;" #define TAG_LINK1 "" #define TAG_LINK3 "" static char my_out_buffer[200]; static universal_memory_output_stream_t my_out_stream; static xml_writer_t xml_writer; test_suite_t md_filter_test_get_list(void) { test_suite_t result; test_suite_init( &result, "md_filter_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "test_md_plain_mixed", &test_md_plain_mixed ); test_suite_add_test_case( &result, "test_valid_links", &test_valid_links ); test_suite_add_test_case( &result, "test_invalid_links", &test_invalid_links ); return result; } static void set_up(void) { data_database_init( &database ); data_database_open_in_memory( &database ); data_database_reader_init( &db_reader, &database ); ctrl_controller_init( &controller, &database ); memset( &my_out_buffer, '\0', sizeof(my_out_buffer) ); universal_memory_output_stream_init( &my_out_stream, &my_out_buffer, sizeof(my_out_buffer) ); xml_writer_init( &xml_writer, universal_memory_output_stream_get_output_stream( &my_out_stream ) ); md_filter_init( &md_filter, &db_reader, TAG_BREAK, TAG_LINK1, TAG_LINK2, TAG_LINK3, &xml_writer ); } static void tear_down(void) { md_filter_destroy( &md_filter ); xml_writer_destroy( &xml_writer ); universal_memory_output_stream_destroy( &my_out_stream ); ctrl_controller_destroy( &controller ); data_database_reader_destroy( &db_reader ); data_database_close( &database ); data_database_destroy( &database ); } static data_row_id_t create_root_diag() { ctrl_error_t ctrl_err; data_error_t data_err; ctrl_diagram_controller_t *diagram_ctrl; diagram_ctrl = ctrl_controller_get_diagram_control_ptr( &controller ); /* create a diagram */ data_row_id_t root_diag_id; data_diagram_t root_diagram; data_err = data_diagram_init_new( &root_diagram, DATA_ROW_ID_VOID /*=parent_diagram_id*/, DATA_DIAGRAM_TYPE_UML_CLASS_DIAGRAM, "Th& d\"agram", "diagram_description-root", 10555 ,/*=list_order*/ DATA_DIAGRAM_FLAG_NONE ); TEST_ENVIRONMENT_ASSERT( DATA_ERROR_NONE == data_err ); root_diag_id = DATA_ROW_ID_VOID; ctrl_err = ctrl_diagram_controller_create_diagram ( diagram_ctrl, &root_diagram, CTRL_UNDO_REDO_ACTION_BOUNDARY_START_NEW, &root_diag_id ); TEST_ENVIRONMENT_ASSERT( CTRL_ERROR_NONE == ctrl_err ); TEST_ENVIRONMENT_ASSERT( DATA_ROW_ID_VOID != root_diag_id ); data_diagram_destroy ( &root_diagram ); return root_diag_id; } static void test_md_plain_mixed(void) { int err; /* plain */ err = xml_writer_write_plain ( &xml_writer, "" ); TEST_ASSERT_EQUAL_INT( 0, err ); /* xml enc */ err = md_filter_transform ( &md_filter, "plain & \"\'<>D3D#name#id" ); TEST_ASSERT_EQUAL_INT( 0, err ); /* md */ err = md_filter_transform ( &md_filter, "ln 1a\nln 1b\n\nln 2\n- ln 3\n4\n5 ln 5\n\n\nln 7a\n ln 7b\n> ln8\n" ); TEST_ASSERT_EQUAL_INT( 0, err ); /* plain */ err = xml_writer_write_plain ( &xml_writer, "" ); TEST_ASSERT_EQUAL_INT( 0, err ); static const char expected[] = "plain &amp; "\'<>D3D#name#id" "ln 1a\nln 1b" TAG_BREAK "\nln 2" TAG_BREAK "- ln 3" TAG_BREAK "4" TAG_BREAK "5 ln 5" TAG_BREAK TAG_BREAK "\nln 7a\n ln 7b" TAG_BREAK "> ln8\n" ""; //fprintf( stdout, "%s\n", &(expected[0]) ); //fprintf( stdout, "%s\n", &(my_out_buffer[0]) ); //fflush(stdout); TEST_ENVIRONMENT_ASSERT( sizeof(my_out_buffer) >= sizeof(expected)-1 ); TEST_ASSERT( 0 == memcmp( &my_out_buffer, expected, sizeof(expected)-1 ) ); } static void test_valid_links(void) { data_row_id_t root_diag_id = create_root_diag(); TEST_ENVIRONMENT_ASSERT( 1 == root_diag_id ); /* otherwise D0001 needs to be adapted (hint: delete old database file) */ int err; /* 2 valid links, 1 valid but half link */ err = md_filter_transform ( &md_filter, ">D3DD0001#name#idD0001#id#nameD0001" ); TEST_ASSERT_EQUAL_INT( 0, err ); static const char expected[] = ">D3D" TAG_LINK1 "D0001" TAG_LINK2 "Th& <root> d"agram" TAG_LINK3 "#id" TAG_LINK1 "D0001" TAG_LINK2 "D0001" TAG_LINK3; //fprintf( stdout, "%s\n", &(expected[0]) ); //fprintf( stdout, "%s\n", &(my_out_buffer[0]) ); //fflush(stdout); TEST_ENVIRONMENT_ASSERT( sizeof(my_out_buffer) >= sizeof(expected)-1 ); TEST_ASSERT( 0 == memcmp( &my_out_buffer, expected, sizeof(expected)-1 ) ); } static void test_invalid_links(void) { data_row_id_t root_diag_id = create_root_diag(); TEST_ENVIRONMENT_ASSERT( 1 == root_diag_id ); /* otherwise D0001 needs to be adapted (hint: delete old database file) */ int err; /* 2 invalid links, 1 valid but non-existig link, 1 valid but half link */ err = md_filter_transform ( &md_filter, ">D3DD001#nameC0001#idD0002#id#nameD0001#nam" ); TEST_ASSERT_EQUAL_INT( 0, err ); static const char expected[] = ">D3DD001#nameC0001#idD0002#id#nameD0001#nam"; //fprintf( stdout, "%s\n", &(expected[0]) ); //fprintf( stdout, "%s\n", &(my_out_buffer[0]) ); //fflush(stdout); TEST_ENVIRONMENT_ASSERT( sizeof(my_out_buffer) >= sizeof(expected)-1 ); TEST_ASSERT( 0 == memcmp( &my_out_buffer, expected, sizeof(expected)-1 ) ); } /* * Copyright 2020-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/io/test/unit/md_filter_test.h000066400000000000000000000015541415120503000226520ustar00rootroot00000000000000/* File: md_filter_test.h; Copyright and License: see below */ #ifndef MD_FILTER_TEST_H #define MD_FILTER_TEST_H /*! * \file * \brief MODULE TEST for md_filter */ #include "test_suite.h" test_suite_t md_filter_test_get_list(void); #endif /* MD_FILTER_TEST_H */ /* * Copyright 2020-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/io/test/unit/txt_writer_test.c000066400000000000000000000140011415120503000231020ustar00rootroot00000000000000/* File: txt_writer_test.c; Copyright and License: see below */ #include "txt/txt_writer.h" #include "txt_writer_test.h" #include "set/data_visible_set.h" #include "stream/universal_memory_output_stream.h" #include "test_assert.h" #include static void set_up(void); static void tear_down(void); static void test_write_indent_multiline_string_null(void); static void test_write_indent_multiline_string_empty(void); static void test_write_indent_multiline_string_empty_last(void); static void test_write_indent_multiline_string_single(void); static void test_write_indent_multiline_string_dual(void); static void test_write_indent_multiline_string_crnl(void); static void test_write_indent_multiline_string_cr(void); test_suite_t txt_writer_test_get_list(void) { test_suite_t result; test_suite_init( &result, "txt_writer_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "test_write_indent_multiline_string_null", &test_write_indent_multiline_string_null ); test_suite_add_test_case( &result, "test_write_indent_multiline_string_empty", &test_write_indent_multiline_string_empty ); test_suite_add_test_case( &result, "test_write_indent_multiline_string_empty_last", &test_write_indent_multiline_string_empty_last ); test_suite_add_test_case( &result, "test_write_indent_multiline_string_single", &test_write_indent_multiline_string_single ); test_suite_add_test_case( &result, "test_write_indent_multiline_string_dual", &test_write_indent_multiline_string_dual ); test_suite_add_test_case( &result, "test_write_indent_multiline_string_crnl", &test_write_indent_multiline_string_crnl ); test_suite_add_test_case( &result, "test_write_indent_multiline_string_cr", &test_write_indent_multiline_string_cr ); return result; } static data_visible_set_t my_fake_input_data; static txt_writer_t my_fake_testee; static char my_out_buffer[24]; static universal_memory_output_stream_t my_out_stream; static const char ENDMARKER[] = "["; static const int ENDMARKER_LEN = 1; static void set_up(void) { data_visible_set_init( &my_fake_input_data ); universal_memory_output_stream_init( &my_out_stream, &my_out_buffer, sizeof(my_out_buffer) ); txt_writer_init( &my_fake_testee, universal_memory_output_stream_get_output_stream( &my_out_stream ) ); } static void tear_down(void) { txt_writer_destroy( &my_fake_testee ); universal_memory_output_stream_destroy( &my_out_stream ); data_visible_set_destroy( &my_fake_input_data ); } static void test_write_indent_multiline_string_null(void) { int err = txt_writer_write_indent_multiline_string( &my_fake_testee, "123_", NULL ); TEST_ASSERT_EQUAL_INT( 0, err ); universal_memory_output_stream_write( &my_out_stream, ENDMARKER, ENDMARKER_LEN ); /*fprintf( stdout, "check: \"%s\"\n", &my_out_buffer );*/ TEST_ASSERT( 0 == memcmp( &my_out_buffer, "[", strlen("[") ) ); } static void test_write_indent_multiline_string_empty(void) { int err = txt_writer_write_indent_multiline_string( &my_fake_testee, "123_", "" ); TEST_ASSERT_EQUAL_INT( 0, err ); universal_memory_output_stream_write( &my_out_stream, ENDMARKER, ENDMARKER_LEN ); /*fprintf( stdout, "check: \"%s\"\n", &my_out_buffer );*/ TEST_ASSERT( 0 == memcmp( &my_out_buffer, "[", strlen("[") ) ); } static void test_write_indent_multiline_string_empty_last(void) { int err = txt_writer_write_indent_multiline_string( &my_fake_testee, "123_", "456\n" ); TEST_ASSERT_EQUAL_INT( 0, err ); universal_memory_output_stream_write( &my_out_stream, ENDMARKER, ENDMARKER_LEN ); /*fprintf( stdout, "check: \"%s\"\n", &my_out_buffer );*/ TEST_ASSERT( 0 == memcmp( &my_out_buffer, "123_456\n[", strlen("123_456\n[") ) ); } static void test_write_indent_multiline_string_single(void) { int err = txt_writer_write_indent_multiline_string( &my_fake_testee, "123_", "456" ); TEST_ASSERT_EQUAL_INT( 0, err ); universal_memory_output_stream_write( &my_out_stream, ENDMARKER, ENDMARKER_LEN ); /*fprintf( stdout, "check: \"%s\"\n", &my_out_buffer );*/ TEST_ASSERT( 0 == memcmp( &my_out_buffer, "123_456\n[", strlen("123_456\n[") ) ); } static void test_write_indent_multiline_string_dual(void) { int err = txt_writer_write_indent_multiline_string( &my_fake_testee, "123_", "456\n789" ); TEST_ASSERT_EQUAL_INT( 0, err ); universal_memory_output_stream_write( &my_out_stream, ENDMARKER, ENDMARKER_LEN ); /*fprintf( stdout, "check: \"%s\"\n", &my_out_buffer );*/ TEST_ASSERT( 0 == memcmp( &my_out_buffer, "123_456\n123_789\n[", strlen("123_456\n123_456\n[") ) ); } static void test_write_indent_multiline_string_crnl(void) { int err = txt_writer_write_indent_multiline_string( &my_fake_testee, "123_", "456\r\n789\r\n" ); TEST_ASSERT_EQUAL_INT( 0, err ); universal_memory_output_stream_write( &my_out_stream, ENDMARKER, ENDMARKER_LEN ); /*fprintf( stdout, "check: \"%s\"\n", &my_out_buffer );*/ TEST_ASSERT( 0 == memcmp( &my_out_buffer, "123_456\n123_789\n[", strlen("123_456\n123_789\n[") ) ); } static void test_write_indent_multiline_string_cr(void) { int err = txt_writer_write_indent_multiline_string( &my_fake_testee, "123_", "456\r789\r" ); TEST_ASSERT_EQUAL_INT( 0, err ); universal_memory_output_stream_write( &my_out_stream, ENDMARKER, ENDMARKER_LEN ); /*fprintf( stdout, "check: \"%s\"\n", &my_out_buffer );*/ TEST_ASSERT( 0 == memcmp( &my_out_buffer, "123_456\n123_789\n[", strlen("123_456\n123_789\n[") ) ); } /* * Copyright 2017-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/io/test/unit/txt_writer_test.h000066400000000000000000000015571415120503000231230ustar00rootroot00000000000000/* File: txt_writer_test.h; Copyright and License: see below */ #ifndef TXT_WRITER_TEST_H #define TXT_WRITER_TEST_H /*! * \file * \brief UNITTEST for txt_writer */ #include "test_suite.h" test_suite_t txt_writer_test_get_list(void); #endif /* TXT_WRITER_TEST_H */ /* * Copyright 2017-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/license.txt000066400000000000000000000267771415120503000173310ustar00rootroot00000000000000 crystal-facet-uml is provided under the Apache-2.0 License. See below. crystal-facet-uml dynamically links to libraries - glib - gdk - gtk - atk - freetype - cairo - pango - gio-unix - sqlite3 (static linkage for win) It relies on - a POSIX OS The build environment requires - a c compiler and linker - cmake and make - doxygen ---------------------------------------------------------------------------- Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. crystal-facet-uml-1.34.1/main/000077500000000000000000000000001415120503000160475ustar00rootroot00000000000000crystal-facet-uml-1.34.1/main/include/000077500000000000000000000000001415120503000174725ustar00rootroot00000000000000crystal-facet-uml-1.34.1/main/include/meta/000077500000000000000000000000001415120503000204205ustar00rootroot00000000000000crystal-facet-uml-1.34.1/main/include/meta/meta_info.h000066400000000000000000000024301415120503000225310ustar00rootroot00000000000000/* File: meta_info.h; Copyright and License: see below */ #ifndef META_INFO_H #define META_INFO_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines the own program name */ /* human readable version */ #define META_INFO_PROGRAM_NAME_STR "crystal facet uml" /* machine readable version */ #define META_INFO_PROGRAM_ID_STR "crystal-facet-uml" #define META_INFO_COPYRIGHT_STR /*Copyright*/ "2016-2021 Andreas Warnke" #ifdef __linux__ #define META_INFO_LICENSE_STR "Apache-2.0" /* sqlite3 linked dynamicyally */ #else /* __linux__ */ #define META_INFO_LICENSE_STR "Apache-2.0 (includes sqlite3 which is public domain)" /* sqlite3 linked statically */ #endif /* __linux__ */ #endif /* META_INFO_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/main/include/meta/meta_version.h000066400000000000000000000016621415120503000232710ustar00rootroot00000000000000/* File: meta_version.h; Copyright and License: see below */ #ifndef META_VERSION_H #define META_VERSION_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines the current program version */ /* include the bash and c language independant version description */ static const char* #include "meta/meta_version.inl" ; #endif /* META_VERSION_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/main/include/meta/meta_version.inl000066400000000000000000000000321415120503000236120ustar00rootroot00000000000000META_VERSION_STR="1.34.1" crystal-facet-uml-1.34.1/main/source/000077500000000000000000000000001415120503000173475ustar00rootroot00000000000000crystal-facet-uml-1.34.1/main/source/main.c000066400000000000000000000146711415120503000204500ustar00rootroot00000000000000/* File: main.c; Copyright and License: see below */ #include "main.h" #include "main_commands.h" #include "io_file_format.h" #include "trace.h" #include "tslog.h" #include "meta/meta_info.h" #include "meta/meta_version.h" #include "util/string/utf8string.h" #include "stream/universal_stream_output_stream.h" #include "universal_utf8_writer.h" #include #include #include #include #include #include static const char *const MAIN_HELP = "\nUsage:\n" " -h for help\n" " -v for version\n" " -e to export all diagrams\n" " -i json to import elements\n" " -u to use/create a database file\n" " -g to upgrade the database tables from version 1.32.1 and older\n" " -t to test the database file\n" " -r to test and repair the database file\n"; int main (int argc, char *argv[]) { TRACE_BEGIN(); TRACE_TIMESTAMP(); int exit_code = 0; TSLOG_INIT(META_INFO_PROGRAM_ID_STR); char *database_file = NULL; char *export_directory = NULL; char *import_file = NULL; bool do_not_start = false; bool do_repair = false; bool do_check = false; bool do_export = false; bool do_upgrade = false; bool do_import = false; io_file_format_t export_format = 0; io_file_format_t import_format = 0; universal_stream_output_stream_t out_stream; universal_stream_output_stream_init( &out_stream, stdout ); universal_utf8_writer_t writer; universal_utf8_writer_init( &writer, universal_stream_output_stream_get_output_stream( &out_stream ) ); /* handle options */ if ( argc == 2 ) { if ( utf8string_equals_str( argv[1], "-h" ) ) { universal_utf8_writer_write_str( &writer, MAIN_HELP ); do_not_start = true; } if ( utf8string_equals_str( argv[1], "-v" ) ) { universal_utf8_writer_write_str( &writer, "\n" ); universal_utf8_writer_write_str( &writer, META_VERSION_STR ); universal_utf8_writer_write_str( &writer, "\n" ); do_not_start = true; } } if ( argc == 3 ) { if ( utf8string_equals_str( argv[1], "-r" ) ) { database_file = argv[2]; do_not_start = true; do_repair = true; } if ( utf8string_equals_str( argv[1], "-t" ) ) { database_file = argv[2]; do_not_start = true; do_check = true; } if ( utf8string_equals_str( argv[1], "-g" ) ) { database_file = argv[2]; do_not_start = true; do_upgrade = true; } if ( utf8string_equals_str( argv[1], "-u" ) ) { database_file = argv[2]; } } if ( argc == 5 ) { if ( utf8string_equals_str( argv[1], "-e" ) ) { database_file = argv[2]; export_format = main_private_get_selected_format(argv[3]); export_directory = argv[4]; do_not_start = true; do_export = true; } if ( utf8string_equals_str( argv[1], "-i" ) ) { database_file = argv[2]; import_format = main_private_get_selected_format(argv[3]); import_file = argv[4]; do_not_start = true; do_import = true; } } { static main_commands_t commands; exit_code |= main_commands_init( &commands, ( ! do_not_start ), argc, argv ); if ( do_upgrade || do_check || do_export ) { /* if upgrade or starting in read-only mode, upgrade db first: */ exit_code |= main_commands_upgrade( &commands, database_file, &writer ); } /* repair database */ if ( do_repair || do_check ) { exit_code |= main_commands_repair( &commands, database_file, do_check, &writer ); } if ( do_export ) { exit_code |= main_commands_export( &commands, database_file, export_format, export_directory, &writer ); } if ( do_import ) { exit_code |= main_commands_import( &commands, database_file, import_format, import_file, &writer ); } /* run program */ if ( ! do_not_start ) { exit_code |= main_commands_start_gui( &commands, database_file, &writer ); } main_commands_destroy( &commands ); } universal_utf8_writer_destroy( &writer ); universal_stream_output_stream_destroy( &out_stream ); TSLOG_DESTROY(); TRACE_TIMESTAMP(); TRACE_END_ERR(exit_code); return exit_code; } io_file_format_t main_private_get_selected_format( char *arg_fmt ) { TRACE_BEGIN(); assert( arg_fmt != NULL ); io_file_format_t result = 0; if ( utf8string_equals_str( arg_fmt, "pdf" ) ) { result = IO_FILE_FORMAT_PDF; } else if ( utf8string_equals_str( arg_fmt, "png" ) ) { result = IO_FILE_FORMAT_PNG; } else if ( utf8string_equals_str( arg_fmt, "ps" ) ) { result = IO_FILE_FORMAT_PS; } else if ( utf8string_equals_str( arg_fmt, "svg" ) ) { result = IO_FILE_FORMAT_SVG; } else if ( utf8string_equals_str( arg_fmt, "txt" ) ) { result = IO_FILE_FORMAT_TXT; } else if ( utf8string_equals_str( arg_fmt, "docbook" ) ) { result = IO_FILE_FORMAT_DOCBOOK; } else if ( utf8string_equals_str( arg_fmt, "xhtml" ) ) { result = IO_FILE_FORMAT_XHTML; } else if ( utf8string_equals_str( arg_fmt, "xmi" ) ) { result = IO_FILE_FORMAT_XMI2; } else if ( utf8string_equals_str( arg_fmt, "json" ) ) { result = IO_FILE_FORMAT_JSON; } TRACE_END(); return result; } /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/main/source/main.h000066400000000000000000000022571415120503000204520ustar00rootroot00000000000000/* File: main.h; Copyright and License: see below */ #ifndef MAIN_H #define MAIN_H /* public file for the doxygen documentation: */ /*! * \file * \brief Declares the functions to start and stop this program */ #include "io_file_format.h" /*! * \brief main starts the gui (or a headless feature) */ int main (int argc, char *argv[]); /*! * \brief compares the command line options to the available export file formats * * \return one or more bits of the io_file_format_t enumeration, 0 if no format could be determined. */ io_file_format_t main_private_get_selected_format( char *arg_fmt ); #endif /* MAIN_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/main/source/main_commands.c000066400000000000000000000276271415120503000223360ustar00rootroot00000000000000/* File: main_commands.c; Copyright and License: see below */ #include "main_commands.h" #include "gui_main.h" #include "io_exporter.h" #include "io_importer.h" #include "trace.h" #include "tslog.h" #include #include #include int main_commands_init ( main_commands_t *this_, bool start_gui, int argc, char *argv[] ) { TRACE_BEGIN(); int result = 0; /* initialize the base libraries: gobject, gio, glib, gdk and gtk */ if ( start_gui ) { gtk_init(&argc, &argv); /* if this program was not terminated, gtk init was successful. */ } else { gboolean success = gtk_init_check(&argc, &argv); if ( ! success ) { TSLOG_WARNING("gtk could not be initialized."); /* no error here, if no gui requested - test fail otherwise */ } } TRACE_END_ERR( result ); return result; } void main_commands_destroy ( main_commands_t *this_ ) { TRACE_BEGIN(); TRACE_END(); } int main_commands_upgrade ( main_commands_t *this_, const char *database_path, universal_utf8_writer_t *out_english_report ) { TRACE_BEGIN(); int result = 0; assert( database_path != NULL ); TRACE_INFO("starting DB..."); data_database_init( &((*this_).temp_database) ); TRACE_INFO("upgrading DB..."); const data_error_t up_err = data_database_open( &((*this_).temp_database), database_path ); /* upgrade is implicitely done */ if ( up_err != DATA_ERROR_NONE ) { universal_utf8_writer_write_str( out_english_report, "error opening database " ); universal_utf8_writer_write_str( out_english_report, database_path ); universal_utf8_writer_write_str( out_english_report, "\n" ); result = -1; } TRACE_INFO("stopping DB..."); data_database_close( &((*this_).temp_database) ); data_database_destroy( &((*this_).temp_database) ); TRACE_END_ERR( result ); return result; } int main_commands_repair ( main_commands_t *this_, const char *database_path, bool check_only, universal_utf8_writer_t *out_english_report ) { TRACE_BEGIN(); assert( database_path != NULL ); const bool do_repair = ( ! check_only ); static char repair_log_buffer[10000] = ""; static utf8stringbuf_t repair_log = UTF8STRINGBUF( repair_log_buffer ); int result = 0; TRACE_INFO("starting DB..."); data_database_init( &((*this_).temp_database) ); const data_error_t db_err = ( check_only ) ? data_database_open_read_only( &((*this_).temp_database), database_path ) : data_database_open( &((*this_).temp_database), database_path ); if ( db_err != DATA_ERROR_NONE ) { universal_utf8_writer_write_str( out_english_report, "error opening database " ); universal_utf8_writer_write_str( out_english_report, database_path ); universal_utf8_writer_write_str( out_english_report, "\n" ); } TRACE_INFO("initializing controller..."); ctrl_controller_init( &((*this_).temp_controller), &((*this_).temp_database) ); TRACE_INFO("reparing/testing..."); ctrl_controller_repair_database( &((*this_).temp_controller), do_repair, NULL, NULL, repair_log ); TRACE_INFO("reparing/testing finished."); TRACE_INFO("destroying controller..."); ctrl_controller_destroy( &((*this_).temp_controller) ); TRACE_INFO("stopping DB..."); data_database_close( &((*this_).temp_database) ); data_database_destroy( &((*this_).temp_database) ); universal_utf8_writer_write_str( out_english_report, "\n\n" ); universal_utf8_writer_write_str( out_english_report, utf8stringbuf_get_string(repair_log) ); universal_utf8_writer_write_str( out_english_report, "\n" ); TRACE_END_ERR( result ); return result; } int main_commands_start_gui ( main_commands_t *this_, const char *database_path, universal_utf8_writer_t *out_english_report ) { TRACE_BEGIN(); int result = 0; TRACE_INFO("starting DB..."); TRACE_INFO_INT("sizeof(data_database_t)/B:",sizeof(data_database_t)); data_database_init( &((*this_).temp_database) ); if ( NULL != database_path ) { const data_error_t db_err = data_database_open( &((*this_).temp_database), database_path ); if ( db_err != DATA_ERROR_NONE ) { universal_utf8_writer_write_str( out_english_report, "error opening database " ); universal_utf8_writer_write_str( out_english_report, database_path ); universal_utf8_writer_write_str( out_english_report, "\n" ); } } TRACE_TIMESTAMP(); TRACE_INFO("initializing controller..."); TRACE_INFO_INT("sizeof(ctrl_controller_t)/B:",sizeof(ctrl_controller_t)); ctrl_controller_init( &((*this_).temp_controller), &((*this_).temp_database) ); TRACE_TIMESTAMP(); TRACE_INFO("running GUI..."); gui_main( &((*this_).temp_controller), &((*this_).temp_database) ); TRACE_INFO("GUI stopped."); TRACE_TIMESTAMP(); TRACE_INFO("destroying controller..."); ctrl_controller_destroy( &((*this_).temp_controller) ); TRACE_TIMESTAMP(); TRACE_INFO("stopping DB..."); data_database_close( &((*this_).temp_database) ); data_database_destroy( &((*this_).temp_database) ); TRACE_END_ERR( result ); return result; } int main_commands_export ( main_commands_t *this_, const char *database_path, io_file_format_t export_format, const char *export_directory, universal_utf8_writer_t *out_english_report ) { TRACE_BEGIN(); assert( database_path != NULL ); assert( export_directory != NULL ); int export_err = 0; TRACE_INFO("starting DB..."); data_database_init( &((*this_).temp_database) ); const data_error_t db_err = data_database_open_read_only( &((*this_).temp_database), database_path ); if ( db_err != DATA_ERROR_NONE ) { universal_utf8_writer_write_str( out_english_report, "error opening database " ); universal_utf8_writer_write_str( out_english_report, database_path ); universal_utf8_writer_write_str( out_english_report, "\n" ); } TRACE_INFO("exporting DB..."); TRACE_INFO_STR( "chosen folder:", export_directory ); const char *document_filename = data_database_get_filename_ptr ( &((*this_).temp_database) ); if ( data_database_is_open( &((*this_).temp_database) ) ) { static data_database_reader_t db_reader; data_database_reader_init( &db_reader, &((*this_).temp_database) ); static io_exporter_t exporter; io_exporter_init( &exporter, &db_reader ); { data_stat_t export_stat; data_stat_init ( &export_stat ); export_err = io_exporter_export_files( &exporter, export_format, export_directory, document_filename, &export_stat ); { const unsigned int stat_ok = data_stat_get_series_count( &export_stat, DATA_STAT_SERIES_EXPORTED ); const unsigned int stat_warn = data_stat_get_series_count( &export_stat, DATA_STAT_SERIES_WARNING ); const unsigned int stat_err = data_stat_get_series_count( &export_stat, DATA_STAT_SERIES_ERROR ); universal_utf8_writer_write_str( out_english_report, "\nexported: " ); universal_utf8_writer_write_int( out_english_report, stat_ok ); universal_utf8_writer_write_str( out_english_report, "; warnings: " ); universal_utf8_writer_write_int( out_english_report, stat_warn ); universal_utf8_writer_write_str( out_english_report, "; errors: " ); universal_utf8_writer_write_int( out_english_report, stat_err ); universal_utf8_writer_write_str( out_english_report, "\n" ); } data_stat_trace( &export_stat ); data_stat_destroy ( &export_stat ); } io_exporter_destroy( &exporter ); data_database_reader_destroy( &db_reader ); } else { export_err = -1; } TRACE_INFO("stopping DB..."); data_database_close( &((*this_).temp_database) ); data_database_destroy( &((*this_).temp_database) ); TRACE_END_ERR( export_err ); return export_err; } int main_commands_import ( main_commands_t *this_, const char *database_path, io_file_format_t import_format, const char *import_file_path, universal_utf8_writer_t *out_english_report ) { TRACE_BEGIN(); assert( database_path != NULL ); assert( import_file_path != NULL ); int import_err = 0; TRACE_INFO("starting DB..."); data_database_init( &((*this_).temp_database) ); const data_error_t db_err = data_database_open( &((*this_).temp_database), database_path ); if ( db_err != DATA_ERROR_NONE ) { universal_utf8_writer_write_str( out_english_report, "error opening database " ); universal_utf8_writer_write_str( out_english_report, database_path ); universal_utf8_writer_write_str( out_english_report, "\n" ); } TRACE_INFO("initializing controller..."); ctrl_controller_init( &((*this_).temp_controller), &((*this_).temp_database) ); TRACE_INFO("importing data..."); TRACE_INFO_STR( "chosen data:", import_file_path ); if ( data_database_is_open( &((*this_).temp_database) ) ) { static data_database_reader_t db_reader; data_database_reader_init( &db_reader, &((*this_).temp_database) ); static io_importer_t importer; io_importer_init( &importer, &db_reader, &((*this_).temp_controller) ); { data_stat_t import_stat; data_stat_init ( &import_stat ); import_err = io_importer_import_file( &importer, import_format, import_file_path, &import_stat, out_english_report ); { const unsigned int stat_ok = data_stat_get_series_count( &import_stat, DATA_STAT_SERIES_EXPORTED ); const unsigned int stat_warn = data_stat_get_series_count( &import_stat, DATA_STAT_SERIES_WARNING ); const unsigned int stat_err = data_stat_get_series_count( &import_stat, DATA_STAT_SERIES_ERROR ); universal_utf8_writer_write_str( out_english_report, "\nimported: " ); universal_utf8_writer_write_int( out_english_report, stat_ok ); universal_utf8_writer_write_str( out_english_report, "; warnings: " ); universal_utf8_writer_write_int( out_english_report, stat_warn ); universal_utf8_writer_write_str( out_english_report, "; errors: " ); universal_utf8_writer_write_int( out_english_report, stat_err ); universal_utf8_writer_write_str( out_english_report, "\n" ); } data_stat_trace( &import_stat ); data_stat_destroy ( &import_stat ); } io_importer_destroy( &importer ); data_database_reader_destroy( &db_reader ); } else { import_err = -1; } TRACE_INFO("destroying controller..."); ctrl_controller_destroy( &((*this_).temp_controller) ); TRACE_INFO("stopping DB..."); data_database_close( &((*this_).temp_database) ); data_database_destroy( &((*this_).temp_database) ); TRACE_END_ERR( import_err ); return import_err; } /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/main/source/main_commands.h000066400000000000000000000116151415120503000223310ustar00rootroot00000000000000/* File: main_commands.h; Copyright and License: see below */ #ifndef MAIN_COMMANDS_H #define MAIN_COMMANDS_H /* public file for the doxygen documentation: */ /*! * \file * \brief Declares the main commands to be executed by this program */ #include "io_file_format.h" #include "storage/data_database.h" #include "ctrl_controller.h" #include "universal_utf8_writer.h" #include /*! * \brief attributes of the main_commands object */ struct main_commands_struct { data_database_t temp_database; /*!< a database struct, is only temporarily initialized (and then destroyed again) */ ctrl_controller_t temp_controller; /*!< a controller struct, is only temporarily initialized (and then destroyed again) */ }; typedef struct main_commands_struct main_commands_t; /*! * \brief initializes the main_commands_t struct * * \param start_gui true if a graphical window shall be started by main_commands * \param argc number of command line arguments * \param argv array of command line arguments * \param this_ pointer to own object attributes * \return 0 if success, -1 if error */ int main_commands_init ( main_commands_t *this_, bool start_gui, int argc, char *argv[] ); /*! * \brief destroys the main_commands_t struct * * \param this_ pointer to own object attributes */ void main_commands_destroy ( main_commands_t *this_ ); /*! * \brief upgrades the database to the latest format * * \param this_ pointer to own object attributes * \param database_path pathname of the database * \param out_english_report universal_utf8_writer_t where to write a non-translated report to * \return 0 if success, -1 if error */ int main_commands_upgrade ( main_commands_t *this_, const char *database_path, universal_utf8_writer_t *out_english_report ); /*! * \brief repairs or checks the database * * \param this_ pointer to own object attributes * \param database_path pathname of the database * \param check_only true if the database shall not be modified * \param out_english_report universal_utf8_writer_t where to write a non-translated report to * \return 0 if success, -1 if error */ int main_commands_repair ( main_commands_t *this_, const char *database_path, bool check_only, universal_utf8_writer_t *out_english_report ); /*! * \brief starts the graphical user interface * * \param this_ pointer to own object attributes * \param database_path pathname of the database, may be NULL if no preselected database file * \param out_english_report universal_utf8_writer_t where to write a non-translated report to * \return 0 if success, -1 if error */ int main_commands_start_gui ( main_commands_t *this_, const char *database_path, universal_utf8_writer_t *out_english_report ); /*! * \brief exports the database in the selected data format to the export_directory * * \param this_ pointer to own object attributes * \param database_path pathname of the database * \param export_format format to export * \param export_directory pathname of the directory where to write exported files to * \param out_english_report universal_utf8_writer_t where to write a non-translated report to * \return 0 if success, -1 if error */ int main_commands_export ( main_commands_t *this_, const char *database_path, io_file_format_t export_format, const char *export_directory, universal_utf8_writer_t *out_english_report ); /*! * \brief imports the database in the selected data format to the export_directory * * \param this_ pointer to own object attributes * \param database_path pathname of the database * \param import_format format to import * \param import_file_path pathname of the file which to import * \param out_english_report universal_utf8_writer_t where to write a non-translated report to * \return 0 if success, -1 if error */ int main_commands_import ( main_commands_t *this_, const char *database_path, io_file_format_t import_format, const char *import_file_path, universal_utf8_writer_t *out_english_report ); #endif /* MAIN_COMMANDS_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/main/test/000077500000000000000000000000001415120503000170265ustar00rootroot00000000000000crystal-facet-uml-1.34.1/main/test/test_main.c000066400000000000000000000215711415120503000211630ustar00rootroot00000000000000/* File: test_main.c; Copyright and License: see below */ #include "unit/data_change_notifier_test.h" #include "unit/data_small_set_test.h" #include "unit/data_uuid_test.h" #include "unit/data_rules_test.h" #include "unit/data_database_listener_test.h" #include "integration/data_database_reader_test.h" #include "unit/ctrl_diagram_controller_test.h" #include "unit/ctrl_controller_test.h" #include "unit/ctrl_classifier_controller_test.h" #include "unit/ctrl_consistency_checker_test.h" #include "unit/ctrl_undo_redo_list_test.h" #include "unit/ctrl_diagram_policy_enforcer_test.h" #include "unit/ctrl_classifier_policy_enforcer_test.h" #include "unit/geometry_rectangle_test.h" #include "unit/geometry_connector_test.h" #include "unit/geometry_non_linear_scale_test.h" #include "unit/gui_sketch_nav_tree_test.h" #include "unit/txt_writer_test.h" #include "unit/json_token_reader_test.h" #include "unit/json_import_to_database_test.h" #include "unit/md_filter_test.h" #include "integration/io_export_model_traversal_test.h" #include "unit/draw_classifier_contour_test.h" #include "unit/pencil_layout_data_test.h" #include "unit/pencil_classifier_composer_test.h" #include "integration/pencil_layouter_test.h" #include "integration/pencil_diagram_maker_test.h" #include "unit/universal_array_index_sorter_test.h" #include "unit/universal_array_list_test.h" #include "unit/universal_memory_output_stream_test.h" #include "unit/universal_escaping_output_stream_test.h" #include "unit/universal_memory_input_stream_test.h" #include "unit/universal_buffer_input_stream_test.h" #include "unit/universal_buffer_output_stream_test.h" #include "unit/universal_memory_arena_test.h" #include "unit/universal_arena_list_test.h" #include "unit/utf8stringbuf_test.h" #include "unit/utf8codepoint_test.h" #include "unit/utf8codepointiterator_test.h" #include "unit/utf8string_test.h" /* #include "unit/utf8stringbuf_performance.h" -- performance measurements are not reliable - depend on system config+load */ #include "unit/utf8stringview_test.h" #include "unit/utf8stringviewiterator_test.h" #include "trace.h" #include "tslog.h" #include "meta/meta_info.h" #include "meta/meta_version.h" #include "util/string/utf8string.h" #include "test_runner.h" #include #include #include /*! * \brief main runs the unit tests */ int main (int argc, char *argv[]) { TRACE_BEGIN(); TRACE_TIMESTAMP(); TRACE_INFO( "--------------------" ); int exit_code = 0; TSLOG_INIT(META_INFO_PROGRAM_ID_STR); /* print id, license and copyrights */ { fprintf( stdout, " + %s %s\n", META_INFO_PROGRAM_ID_STR, META_VERSION_STR ); fprintf( stdout, " + Copyright: %s\n", META_INFO_COPYRIGHT_STR ); fprintf( stdout, " + License: %s\n", META_INFO_LICENSE_STR ); } bool do_unit_tests = false; bool do_integration_tests = false; /* handle options */ if ( argc == 2 ) { if ( utf8string_equals_str( argv[1], "-h" ) ) { fprintf( stdout, "\nUsage:\n" ); fprintf( stdout, " %s -h for help\n", argv[0] ); fprintf( stdout, " %s -u to run the unit-tests (test functions of single software units)\n", argv[0] ); fprintf( stdout, " %s -i to run the integration tests (test interactions between several units)\n", argv[0] ); fprintf( stdout, " %s -a to run all tests\n", argv[0] ); } if ( utf8string_equals_str( argv[1], "-u" ) ) { do_unit_tests = true; } if ( utf8string_equals_str( argv[1], "-i" ) ) { do_integration_tests = true; } if ( utf8string_equals_str( argv[1], "-m" ) ) /* compatibility to 1.27.3 and older */ { do_integration_tests = true; } if ( utf8string_equals_str( argv[1], "-a" ) ) { do_unit_tests = true; do_integration_tests = true; } } /* initialize the base libraries: gobject, gio, glib, gdk and gtk */ { gboolean success = gtk_init_check(&argc, &argv); if ( ! success ) { TSLOG_WARNING("gtk could not be initialized."); } } /* start tests */ test_runner_t runner; test_runner_init ( &runner ); /* unit-tests */ if ( do_unit_tests ) { test_runner_run_suite( &runner, data_small_set_test_get_list() ); test_runner_run_suite( &runner, data_rules_test_get_list() ); test_runner_run_suite( &runner, data_uuid_test_get_list() ); test_runner_run_suite( &runner, data_change_notifier_test_get_list() ); test_runner_run_suite( &runner, data_database_listener_test_get_list() ); test_runner_run_suite( &runner, geometry_rectangle_test_get_list() ); test_runner_run_suite( &runner, geometry_connector_test_get_list() ); test_runner_run_suite( &runner, geometry_non_linear_scale_test_get_list() ); test_runner_run_suite( &runner, txt_writer_test_get_list() ); test_runner_run_suite( &runner, json_token_reader_test_get_list() ); test_runner_run_suite( &runner, draw_classifier_contour_test_get_list() ); test_runner_run_suite( &runner, pencil_classifier_composer_test_get_list() ); test_runner_run_suite( &runner, pencil_layout_data_test_get_list() ); test_runner_run_suite( &runner, universal_array_index_sorter_test_get_list() ); test_runner_run_suite( &runner, universal_array_list_test_get_list() ); test_runner_run_suite( &runner, universal_memory_output_stream_test_get_list() ); test_runner_run_suite( &runner, universal_escaping_output_stream_test_get_list() ); test_runner_run_suite( &runner, universal_memory_input_stream_test_get_list() ); test_runner_run_suite( &runner, universal_buffer_input_stream_test_get_list() ); test_runner_run_suite( &runner, universal_buffer_output_stream_test_get_list() ); test_runner_run_suite( &runner, universal_memory_arena_test_get_list() ); test_runner_run_suite( &runner, universal_arena_list_test_get_list() ); test_runner_run_suite( &runner, utf8codepoint_test_get_list() ); test_runner_run_suite( &runner, utf8codepointiterator_test_get_list() ); test_runner_run_suite( &runner, utf8stringbuf_test_get_list() ); test_runner_run_suite( &runner, utf8string_test_get_list() ); /* test_runner_run_suite( &runner, utf8stringbuf_performance_get_list() ); -- performance measurements are not reliable - depend on system config+load */ test_runner_run_suite( &runner, utf8stringview_test_get_list() ); test_runner_run_suite( &runner, utf8stringviewiterator_test_get_list() ); test_runner_run_suite( &runner, gui_sketch_nav_tree_test_get_list() ); } /* integration tests which involve multiple software units */ if ( do_integration_tests ) { test_runner_run_suite( &runner, data_database_reader_test_get_list() ); test_runner_run_suite( &runner, ctrl_controller_test_get_list() ); test_runner_run_suite( &runner, ctrl_diagram_controller_test_get_list() ); test_runner_run_suite( &runner, ctrl_classifier_controller_test_get_list() ); test_runner_run_suite( &runner, ctrl_consistency_checker_test_get_list() ); test_runner_run_suite( &runner, ctrl_undo_redo_list_test_get_list() ); test_runner_run_suite( &runner, ctrl_diagram_policy_enforcer_test_get_list() ); test_runner_run_suite( &runner, ctrl_classifier_policy_enforcer_test_get_list() ); test_runner_run_suite( &runner, pencil_layouter_test_get_list() ); test_runner_run_suite( &runner, pencil_diagram_maker_test_get_list() ); test_runner_run_suite( &runner, json_import_to_database_test_get_list() ); test_runner_run_suite( &runner, md_filter_test_get_list() ); test_runner_run_suite( &runner, io_export_model_traversal_test_get_list() ); } /* fetch failures */ test_result_t res = test_get_result( &runner ); fprintf( stdout, "ALL TESTS - RESULT: total %d, failed: %d\n", test_result_get_total( &res ), test_result_get_failed( &res ) ); exit_code = test_result_get_failed( &res ); TSLOG_DESTROY(); TRACE_INFO( "--------------------" ); TRACE_TIMESTAMP(); TRACE_END_ERR( exit_code ); return exit_code; } /* * Copyright 2016-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/000077500000000000000000000000001415120503000163755ustar00rootroot00000000000000crystal-facet-uml-1.34.1/pencil/include/000077500000000000000000000000001415120503000200205ustar00rootroot00000000000000crystal-facet-uml-1.34.1/pencil/include/draw/000077500000000000000000000000001415120503000207555ustar00rootroot00000000000000crystal-facet-uml-1.34.1/pencil/include/draw/draw_classifier_contour.h000066400000000000000000000277441415120503000260560ustar00rootroot00000000000000/* File: draw_classifier_contour.h; Copyright and License: see below */ #ifndef DRAW_CLASSIFIER_CONTOUR_H #define DRAW_CLASSIFIER_CONTOUR_H /* public file for the doxygen documentation: */ /*! * \file * \brief Draws simple geometric objects like 2d boxes, 3d boxes, ovals, rounded-corner-boxes */ #include "pencil_size.h" #include "util/geometry/geometry_h_align.h" #include "util/geometry/geometry_v_align.h" #include "util/geometry/geometry_rectangle.h" #include "data_classifier_type.h" #include #include /*! * \brief attributes of the draw geometry functions */ struct draw_classifier_contour_struct { int dummy; /*!< This object is a collection of stateless drawing functions */ }; typedef struct draw_classifier_contour_struct draw_classifier_contour_t; /*! * \brief initializes the draw_classifier_contour_t * * \param this_ pointer to own object attributes */ static inline void draw_classifier_contour_init( draw_classifier_contour_t *this_ ); /*! * \brief destroys the draw_classifier_contour_t * * \param this_ pointer to own object attributes */ static inline void draw_classifier_contour_destroy( draw_classifier_contour_t *this_ ); /*! * \brief determines the dimensions of the inner area (label and space) of the classifier-shape. * * based on the outer_bounds, the inner area is calculated. * In case of a fixed-sized symbol, the label-and-space area without icon is returned. * * \param this_ pointer to own object attributes * \param classifier_type type of the classifier to layout * \param outer_bounds outer bounding rectangle for the classifier * \param pencil_size set of sizes and colors for drawing lines and text * \return inner area. empty rectangle if outer_bounds too small. */ geometry_rectangle_t draw_classifier_contour_calc_inner_area ( const draw_classifier_contour_t *this_, data_classifier_type_t classifier_type, const geometry_rectangle_t *outer_bounds, const pencil_size_t *pencil_size ); /*! * \brief determines the outer bounding dimensions of the classifier-shape. * * based on the inner_area (label and space), the outer bounds is calculated. * * \param this_ pointer to own object attributes * \param classifier_type type of the classifier to layout * \param inner_area inner_area (label and space) that is needed for the classifier * \param pencil_size set of sizes and colors for drawing lines and text * \return outer bounds. */ geometry_rectangle_t draw_classifier_contour_calc_outer_bounds ( const draw_classifier_contour_t *this_, data_classifier_type_t classifier_type, const geometry_rectangle_t *inner_area, const pencil_size_t *pencil_size ); /*! * \brief draws a rectangle shape into the outer bounds rect * * \param this_ pointer to own object attributes * \param outer_bounds outer bounding rectangle of the shape, the rectangle has a distance of gap to the outer bounds * \param pencil_size set of sizes and colors for drawing lines and text * \param cr a cairo drawing context */ static inline void draw_classifier_contour_draw_rect ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, const pencil_size_t *pencil_size, cairo_t *cr ); /*! * \brief draws a rounded-corner-rectangle shape into the outer bounds rect * * \param this_ pointer to own object attributes * \param outer_bounds outer bounding rectangle of the shape, the rectangle has a distance of gap to the outer bounds * \param dashed_line true if the line shall be dashed * \param pencil_size set of sizes and colors for drawing lines and text * \param cr a cairo drawing context */ void draw_classifier_contour_draw_rounded_rect ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, bool dashed_line, const pencil_size_t *pencil_size, cairo_t *cr ); /*! * \brief draws an ellipse shape into the outer bounds rect * * \param this_ pointer to own object attributes * \param outer_bounds outer bounding rectangle of the shape, the ellipse has a distance of gap to the outer bounds * \param pencil_size set of sizes and colors for drawing lines and text * \param cr a cairo drawing context */ void draw_classifier_contour_draw_ellipse ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, const pencil_size_t *pencil_size, cairo_t *cr ); /*! * \brief draws a rhombus shape into the outer bounds rect * * \param this_ pointer to own object attributes * \param outer_bounds outer bounding rectangle of the shape, the rhombus has a distance of gap to the outer bounds * \param pencil_size set of sizes and colors for drawing lines and text * \param cr a cairo drawing context */ void draw_classifier_contour_draw_rhombus ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, const pencil_size_t *pencil_size, cairo_t *cr ); /*! * \brief draws an 3d_box shape into the outer bounds rect * * \param this_ pointer to own object attributes * \param outer_bounds outer bounding rectangle of the shape, the 3d_box has a distance of gap to the outer bounds * \param pencil_size set of sizes and colors for drawing lines and text * \param cr a cairo drawing context */ void draw_classifier_contour_draw_3d_box ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, const pencil_size_t *pencil_size, cairo_t *cr ); /*! * \brief draws an accept_event shape into the outer bounds rect * * \param this_ pointer to own object attributes * \param outer_bounds outer bounding rectangle of the shape, the accept_event has a distance of gap to the outer bounds * \param pencil_size set of sizes and colors for drawing lines and text * \param cr a cairo drawing context */ void draw_classifier_contour_draw_accept_event ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, const pencil_size_t *pencil_size, cairo_t *cr ); /*! * \brief draws a send_signal shape into the outer bounds rect * * \param this_ pointer to own object attributes * \param outer_bounds outer bounding rectangle of the shape, the send_signal has a distance of gap to the outer bounds * \param pencil_size set of sizes and colors for drawing lines and text * \param cr a cairo drawing context */ void draw_classifier_contour_draw_send_signal ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, const pencil_size_t *pencil_size, cairo_t *cr ); /*! * \brief draws a package shape into the outer bounds rect * * \param this_ pointer to own object attributes * \param outer_bounds outer bounding rectangle of the shape, the package has a distance of gap to the outer bounds * \param label_box rectangle of the label text * \param pencil_size set of sizes and colors for drawing lines and text * \param cr a cairo drawing context */ void draw_classifier_contour_draw_package ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, const geometry_rectangle_t *label_box, const pencil_size_t *pencil_size, cairo_t *cr ); /*! * \brief draws a diagram shape into the outer bounds rect * * \param this_ pointer to own object attributes * \param outer_bounds outer bounding rectangle of the shape, the diagram has a distance of gap to the outer bounds * \param pencil_size set of sizes and colors for drawing lines and text * \param cr a cairo drawing context */ void draw_classifier_contour_draw_diagram_ref ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, const pencil_size_t *pencil_size, cairo_t *cr ); /*! * \brief draws a comment shape into the outer bounds rect * * \param this_ pointer to own object attributes * \param outer_bounds outer bounding rectangle of the shape, the comment has a distance of gap to the outer bounds * \param pencil_size set of sizes and colors for drawing lines and text * \param cr a cairo drawing context */ void draw_classifier_contour_draw_comment ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, const pencil_size_t *pencil_size, cairo_t *cr ); /*! * \brief draws a horizontal line to e.g. split compartments of feature-groups * * \param this_ pointer to own object attributes * \param outer_bounds outer bounding rectangle of the shape, the line has a distance of gap to the outer bounds * \param y_coordinate coordinate where to draw the line * \param pencil_size set of sizes and colors for drawing lines and text * \param cr a cairo drawing context */ static inline void draw_classifier_contour_draw_compartment_line ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, double y_coordinate, const pencil_size_t *pencil_size, cairo_t *cr ); #include "draw_classifier_contour.inl" #endif /* DRAW_CLASSIFIER_CONTOUR_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/draw/draw_classifier_contour.inl000066400000000000000000000052511415120503000263760ustar00rootroot00000000000000/* File: draw_classifier_contour.inl; Copyright and License: see below */ #include "tslog.h" #include static inline void draw_classifier_contour_init( draw_classifier_contour_t *this_ ) { } static inline void draw_classifier_contour_destroy( draw_classifier_contour_t *this_ ) { } static inline void draw_classifier_contour_draw_rect ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, const pencil_size_t *pencil_size, cairo_t *cr ) { assert ( NULL != outer_bounds ); assert ( NULL != pencil_size ); assert ( NULL != cr ); const double left = geometry_rectangle_get_left ( outer_bounds ); const double top = geometry_rectangle_get_top ( outer_bounds ); const double width = geometry_rectangle_get_width ( outer_bounds ); const double height = geometry_rectangle_get_height ( outer_bounds ); const double gap = pencil_size_get_standard_object_border( pencil_size ); cairo_rectangle ( cr, left+gap, top+gap, width-gap-gap, height-gap-gap ); cairo_stroke (cr); } static inline void draw_classifier_contour_draw_compartment_line ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, double y_coordinate, const pencil_size_t *pencil_size, cairo_t *cr ) { assert ( NULL != outer_bounds ); assert ( NULL != pencil_size ); assert ( NULL != cr ); const double left = geometry_rectangle_get_left ( outer_bounds ); const double width = geometry_rectangle_get_width ( outer_bounds ); const double gap = pencil_size_get_standard_object_border( pencil_size ); cairo_move_to ( cr, left + gap, y_coordinate ); cairo_line_to ( cr, left + width - gap, y_coordinate ); cairo_stroke (cr); } /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/draw/draw_classifier_icon.h000066400000000000000000000322261415120503000253040ustar00rootroot00000000000000/* File: draw_classifier_icon.h; Copyright and License: see below */ #ifndef DRAW_CLASSIFIER_ICON_H #define DRAW_CLASSIFIER_ICON_H /* public file for the doxygen documentation: */ /*! * \file * \brief Renders a classifier into a cairo drawing context */ #include "pencil_size.h" #include "util/geometry/geometry_h_align.h" #include "util/geometry/geometry_v_align.h" #include "util/geometry/geometry_rectangle.h" #include "util/geometry/geometry_dimensions.h" #include "data_classifier_type.h" #include #include /*! \brief aspect ratio of the artifact icon */ extern const double DRAW_CLASSIFIER_ICON_ARTIFACT_ICON_WIDTH_TO_HEIGHT; /*! \brief aspect ratio of the component icon */ extern const double DRAW_CLASSIFIER_ICON_COMPONENT_ICON_WIDTH_TO_HEIGHT; /*! * \brief attributes of the draw symbol functions */ struct draw_classifier_icon_struct { int dummy; /*!< This object is a collection of stateless drawing functions */ }; typedef struct draw_classifier_icon_struct draw_classifier_icon_t; /*! * \brief initializes the draw_classifier_icon_t * * \param this_ pointer to own object attributes */ static inline void draw_classifier_icon_init( draw_classifier_icon_t *this_ ); /*! * \brief destroys the draw_classifier_icon_t * * \param this_ pointer to own object attributes */ static inline void draw_classifier_icon_destroy( draw_classifier_icon_t *this_ ); /*! * \brief returns true if the classifier is drawn as fixed-size symbol * * The following classifier types are fixed-sized symbols: (use-case:) actor, (activity:) start, end, fork, join, timeout, history * * \param this_ pointer to own object attributes * \param classifier_type type of the classifier to draw * \return id of the classifier */ static inline bool draw_classifier_icon_is_fix_sized_symbol ( const draw_classifier_icon_t *this_, data_classifier_type_t classifier_type ); /*! * \brief determines the dimensions of the type icon. * * Type icons are e.g. artifact-icon or component-icon. * * \param this_ pointer to own object attributes * \param classifier_type type of the classifier to draw * \param pencil_size set of sizes and colors for drawing lines and text * \return of the icon. */ static inline geometry_dimensions_t draw_classifier_icon_get_icon_dimensions ( const draw_classifier_icon_t *this_, data_classifier_type_t classifier_type, const pencil_size_t *pencil_size ); /*! * \brief calculates the bounding rectangle for component icon * * \param this_ pointer to own object attributes * \param x x location where to draw the icon * \param y y location where to draw the icon * \param h_align alignment of the icon versus the given x coordinate * \param v_align alignment of the icon versus the given y coordinate * \param height size of the icon * \return bounding box rectangle of the icon */ static inline geometry_rectangle_t draw_classifier_icon_get_component_bounds ( const draw_classifier_icon_t *this_, double x, double y, geometry_h_align_t h_align, geometry_v_align_t v_align, double height ); /*! * \brief draws the component icon into the bounds rect * * \param this_ pointer to own object attributes * \param bounds bounding rectangle of the icon * \param cr a cairo drawing context */ void draw_classifier_icon_draw_component ( const draw_classifier_icon_t *this_, geometry_rectangle_t bounds, cairo_t *cr ); /*! * \brief calculates the bounding rectangle for the artifact icon * * \param this_ pointer to own object attributes * \param x x location where to draw the icon * \param y y location where to draw the icon * \param h_align alignment of the icon versus the given x coordinate * \param v_align alignment of the icon versus the given y coordinate * \param height size of the icon * \return bounding box rectangle of the icon */ static inline geometry_rectangle_t draw_classifier_icon_get_artifact_bounds ( const draw_classifier_icon_t *this_, double x, double y, geometry_h_align_t h_align, geometry_v_align_t v_align, double height ); /*! * \brief draws the artifact icon into the bounds rect * * \param this_ pointer to own object attributes * \param bounds bounding rectangle of the icon * \param cr a cairo drawing context */ void draw_classifier_icon_draw_artifact ( const draw_classifier_icon_t *this_, geometry_rectangle_t bounds, cairo_t *cr ); /*! * \brief calculates the bounding rectangle for the actor icon * * \param this_ pointer to own object attributes * \param x x location where to draw the icon * \param y y location where to draw the icon * \param h_align alignment of the icon versus the given x coordinate * \param v_align alignment of the icon versus the given y coordinate * \param height size of the icon * \return bounding box rectangle of the icon */ static inline geometry_rectangle_t draw_classifier_icon_get_actor_bounds ( const draw_classifier_icon_t *this_, double x, double y, geometry_h_align_t h_align, geometry_v_align_t v_align, double height ); /*! * \brief draws the actor icon into the bounds rect * * \param this_ pointer to own object attributes * \param bounds bounding rectangle of the icon * \param cr a cairo drawing context */ void draw_classifier_icon_draw_actor ( const draw_classifier_icon_t *this_, geometry_rectangle_t bounds, cairo_t *cr ); /*! * \brief calculates the bounding rectangle for the circle icon at the defined location * * \param this_ pointer to own object attributes * \param x x location where to draw the icon * \param y y location where to draw the icon * \param h_align alignment of the icon versus the given x coordinate * \param v_align alignment of the icon versus the given y coordinate * \param height size of the icon * \return bounding box rectangle of the icon */ static inline geometry_rectangle_t draw_classifier_icon_get_circle_bounds ( const draw_classifier_icon_t *this_, double x, double y, geometry_h_align_t h_align, geometry_v_align_t v_align, double height ); /*! * \brief draws the circle icon into the bounds rect * * \param this_ pointer to own object attributes * \param bounds bounding rectangle of the icon * \param pencil_size a set of size-values used for drawing elements in this diagram * \param stroke true if the outer circle line shall be drawn * \param fill true if the inner circle area shall be filled * \param shallow_history true if the H character shall be drawn * \param deep_history true if the H* character pir shall be drawn * \param cr a cairo drawing context */ void draw_classifier_icon_draw_circle ( const draw_classifier_icon_t *this_, geometry_rectangle_t bounds, const pencil_size_t *pencil_size, bool stroke, bool fill, bool shallow_history, bool deep_history, cairo_t *cr ); /*! * \brief calculates the bounding rectangle for the time icon * * \param this_ pointer to own object attributes * \param x x location where to draw the icon * \param y y location where to draw the icon * \param h_align alignment of the icon versus the given x coordinate * \param v_align alignment of the icon versus the given y coordinate * \param height size of the icon * \return bounding box rectangle of the icon */ static inline geometry_rectangle_t draw_classifier_icon_get_time_bounds ( const draw_classifier_icon_t *this_, double x, double y, geometry_h_align_t h_align, geometry_v_align_t v_align, double height ); /*! * \brief draws the time icon into the bounds rect * * \param this_ pointer to own object attributes * \param bounds bounding rectangle of the icon * \param cr a cairo drawing context */ void draw_classifier_icon_draw_time ( const draw_classifier_icon_t *this_, geometry_rectangle_t bounds, cairo_t *cr ); /*! * \brief calculates the bounding rectangle for the sync icon * * \param this_ pointer to own object attributes * \param x x location where to draw the icon * \param y y location where to draw the icon * \param h_align alignment of the icon versus the given x coordinate * \param v_align alignment of the icon versus the given y coordinate * \param height size of the icon * \param pencil_size a set of size-values used for drawing elements in this diagram * \return bounding box rectangle of the icon */ static inline geometry_rectangle_t draw_classifier_icon_get_sync_bounds ( const draw_classifier_icon_t *this_, double x, double y, geometry_h_align_t h_align, geometry_v_align_t v_align, double height, const pencil_size_t *pencil_size ); /*! * \brief draws the sync icon into the bounds rect * * \param this_ pointer to own object attributes * \param bounds bounding rectangle of the icon * \param cr a cairo drawing context */ void draw_classifier_icon_draw_sync ( const draw_classifier_icon_t *this_, geometry_rectangle_t bounds, cairo_t *cr ); #include "draw_classifier_icon.inl" #endif /* DRAW_CLASSIFIER_ICON_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/draw/draw_classifier_icon.inl000066400000000000000000000222131415120503000256320ustar00rootroot00000000000000/* File: draw_classifier_icon.inl; Copyright and License: see below */ #include "tslog.h" #include static inline void draw_classifier_icon_init( draw_classifier_icon_t *this_ ) { } static inline void draw_classifier_icon_destroy( draw_classifier_icon_t *this_ ) { } static inline bool draw_classifier_icon_is_fix_sized_symbol ( const draw_classifier_icon_t *this_, data_classifier_type_t classifier_type ) { bool result; result = (( DATA_CLASSIFIER_TYPE_ACTOR == classifier_type ) || ( DATA_CLASSIFIER_TYPE_DYN_INITIAL_NODE == classifier_type ) || ( DATA_CLASSIFIER_TYPE_DYN_FINAL_NODE == classifier_type ) || ( DATA_CLASSIFIER_TYPE_DYN_FORK_NODE == classifier_type ) || ( DATA_CLASSIFIER_TYPE_DYN_JOIN_NODE == classifier_type ) || ( DATA_CLASSIFIER_TYPE_DYN_SHALLOW_HISTORY == classifier_type ) || ( DATA_CLASSIFIER_TYPE_DYN_DEEP_HISTORY == classifier_type ) || ( DATA_CLASSIFIER_TYPE_DYN_ACCEPT_TIME_EVENT == classifier_type )); return result; } static inline geometry_dimensions_t draw_classifier_icon_get_icon_dimensions( const draw_classifier_icon_t *this_, data_classifier_type_t classifier_type, const pencil_size_t *pencil_size ) { assert( pencil_size != NULL ); geometry_dimensions_t result; if ( classifier_type == DATA_CLASSIFIER_TYPE_COMPONENT ) { const double type_icon_height = pencil_size_get_title_font_size( pencil_size ); geometry_dimensions_init ( &result, DRAW_CLASSIFIER_ICON_COMPONENT_ICON_WIDTH_TO_HEIGHT * type_icon_height, type_icon_height ); } else if ( classifier_type == DATA_CLASSIFIER_TYPE_ARTIFACT ) { const double type_icon_height = pencil_size_get_title_font_size( pencil_size ); geometry_dimensions_init ( &result, DRAW_CLASSIFIER_ICON_ARTIFACT_ICON_WIDTH_TO_HEIGHT * type_icon_height, type_icon_height ); } else if ( classifier_type == DATA_CLASSIFIER_TYPE_COMMENT ) { /* comments do not have icons - but a folded corner at the same place - therefore this placeholder dimension */ const double corner_width = pencil_size_get_standard_font_size( pencil_size ); geometry_dimensions_init ( &result, corner_width, corner_width ); } else { geometry_dimensions_init ( &result, 0.0, 0.0 ); } return result; } static inline geometry_rectangle_t draw_classifier_icon_get_component_bounds ( const draw_classifier_icon_t *this_, double x, double y, geometry_h_align_t h_align, geometry_v_align_t v_align, double height ) { geometry_rectangle_t result; const double width = DRAW_CLASSIFIER_ICON_COMPONENT_ICON_WIDTH_TO_HEIGHT * height; geometry_rectangle_init ( &result, geometry_h_align_get_left( &h_align, width, x, 0.0 ), geometry_v_align_get_top( &v_align, height, y, 0.0 ), width, height ); return result; } static inline geometry_rectangle_t draw_classifier_icon_get_artifact_bounds ( const draw_classifier_icon_t *this_, double x, double y, geometry_h_align_t h_align, geometry_v_align_t v_align, double height ) { geometry_rectangle_t result; const double width = DRAW_CLASSIFIER_ICON_ARTIFACT_ICON_WIDTH_TO_HEIGHT * height; geometry_rectangle_init ( &result, geometry_h_align_get_left( &h_align, width, x, 0.0 ), geometry_v_align_get_top( &v_align, height, y, 0.0 ), width, height ); return result; } static inline geometry_rectangle_t draw_classifier_icon_get_actor_bounds ( const draw_classifier_icon_t *this_, double x, double y, geometry_h_align_t h_align, geometry_v_align_t v_align, double height ) { geometry_rectangle_t result; const double width = height/3.0; geometry_rectangle_init ( &result, geometry_h_align_get_left( &h_align, width, x, 0.0 ), geometry_v_align_get_top( &v_align, height, y, 0.0 ), width, height ); return result; } static inline geometry_rectangle_t draw_classifier_icon_get_circle_bounds ( const draw_classifier_icon_t *this_, double x, double y, geometry_h_align_t h_align, geometry_v_align_t v_align, double height ) { geometry_rectangle_t result; const double width = height; geometry_rectangle_init ( &result, geometry_h_align_get_left( &h_align, width, x, 0.0 ), geometry_v_align_get_top( &v_align, height, y, 0.0 ), width, height ); return result; } static inline geometry_rectangle_t draw_classifier_icon_get_time_bounds ( const draw_classifier_icon_t *this_, double x, double y, geometry_h_align_t h_align, geometry_v_align_t v_align, double height ) { geometry_rectangle_t result; const double width = height/1.732050808; geometry_rectangle_init ( &result, geometry_h_align_get_left( &h_align, width, x, 0.0 ), geometry_v_align_get_top( &v_align, height, y, 0.0 ), width, height ); return result; } static inline geometry_rectangle_t draw_classifier_icon_get_sync_bounds ( const draw_classifier_icon_t *this_, double x, double y, geometry_h_align_t h_align, geometry_v_align_t v_align, double height, const pencil_size_t *pencil_size ) { assert( pencil_size != NULL ); geometry_rectangle_t result; const double width = 3.0 * pencil_size_get_bold_line_width( pencil_size ); geometry_rectangle_init ( &result, geometry_h_align_get_left( &h_align, width, x, 0.0 ), geometry_v_align_get_top( &v_align, height, y, 0.0 ), width, height ); return result; } /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/draw/draw_classifier_label.h000066400000000000000000000123241415120503000254300ustar00rootroot00000000000000/* File: draw_classifier_label.h; Copyright and License: see below */ #ifndef DRAW_CLASSIFIER_LABEL_H #define DRAW_CLASSIFIER_LABEL_H /* public file for the doxygen documentation: */ /*! * \file * \brief Draws titles, stereotypes, underscores; performs linebreaks */ #include "pencil_size.h" #include "util/geometry/geometry_h_align.h" #include "util/geometry/geometry_v_align.h" #include "util/geometry/geometry_rectangle.h" #include "util/geometry/geometry_dimensions.h" #include "data_rules.h" #include "set/data_visible_classifier.h" #include #include /*! * \brief attributes of the draw label functions */ struct draw_classifier_label_struct { int dummy; /*!< This object is a collection of stateless drawing functions */ }; typedef struct draw_classifier_label_struct draw_classifier_label_t; /*! * \brief initializes the draw_classifier_label_t * * \param this_ pointer to own object attributes */ static inline void draw_classifier_label_init( draw_classifier_label_t *this_ ); /*! * \brief destroys the draw_classifier_label_t * * \param this_ pointer to own object attributes */ static inline void draw_classifier_label_destroy( draw_classifier_label_t *this_ ); /*! * \brief determines the dimensions of the stereotype and name of the classifier. * * \param this_ pointer to own object attributes * \param visible_classifier the visible_classifier consisting of diagramelement and classifier to draw * \param proposed_bounds proposed bounds for the text width and height * \param pencil_size set of sizes and colors for drawing lines and text * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context * \param out_text_width width of the text is returned. NULL is not allowed. * \param out_text_height height of the text is returned. NULL is not allowed. */ void draw_classifier_label_get_stereotype_and_name_dimensions( const draw_classifier_label_t *this_, const data_visible_classifier_t *visible_classifier, const geometry_dimensions_t *proposed_bounds, const pencil_size_t *pencil_size, PangoLayout *font_layout, double *out_text_width, double *out_text_height ); /*! * \brief renders stereotype and name of the classifier. * * \param this_ pointer to own object attributes * \param visible_classifier the visible_classifier consisting of diagramelement and classifier to draw * \param label_box the rectangle where to draw to * \param pencil_size set of sizes and colors for drawing lines and text * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context * \param cr the cairo drawing context. */ void draw_classifier_label_draw_stereotype_and_name( const draw_classifier_label_t *this_, const data_visible_classifier_t *visible_classifier, const geometry_rectangle_t *label_box, const pencil_size_t *pencil_size, PangoLayout *font_layout, cairo_t *cr ); /*! * \brief renders the id of the classifier. * * \param this_ pointer to own object attributes * \param visible_classifier the visible_classifier consisting of diagramelement and classifier to draw * \param classifier_bounds the bounding rectangle of the classifier * \param pencil_size set of sizes and colors for drawing lines and text * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context * \param cr the cairo drawing context. */ void draw_classifier_label_draw_id( const draw_classifier_label_t *this_, const data_visible_classifier_t *visible_classifier, const geometry_rectangle_t *classifier_bounds, const pencil_size_t *pencil_size, PangoLayout *font_layout, cairo_t *cr ); #include "draw_classifier_label.inl" #endif /* DRAW_CLASSIFIER_LABEL_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/draw/draw_classifier_label.inl000066400000000000000000000015271415120503000257660ustar00rootroot00000000000000/* File: draw_classifier_label.inl; Copyright and License: see below */ #include "tslog.h" #include static inline void draw_classifier_label_init( draw_classifier_label_t *this_ ) { } static inline void draw_classifier_label_destroy( draw_classifier_label_t *this_ ) { } /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/draw/draw_feature_label.h000066400000000000000000000071771415120503000247510ustar00rootroot00000000000000/* File: draw_feature_label.h; Copyright and License: see below */ #ifndef DRAW_FEATURE_LABEL_H #define DRAW_FEATURE_LABEL_H /* public file for the doxygen documentation: */ /*! * \file * \brief Draws keys and values of features */ #include "pencil_size.h" #include "util/geometry/geometry_h_align.h" #include "util/geometry/geometry_v_align.h" #include "util/geometry/geometry_rectangle.h" #include "util/geometry/geometry_dimensions.h" #include "data_feature.h" #include #include /*! * \brief attributes of the draw label functions */ struct draw_feature_label_struct { int dummy; }; typedef struct draw_feature_label_struct draw_feature_label_t; /*! * \brief initializes the draw_feature_label_t * * \param this_ pointer to own object attributes */ static inline void draw_feature_label_init( draw_feature_label_t *this_ ); /*! * \brief destroys the draw_feature_label_t * * \param this_ pointer to own object attributes */ static inline void draw_feature_label_destroy( draw_feature_label_t *this_ ); /*! * \brief determines the dimensions of the stereotype and name of the classifier. * * \param this_ pointer to own object attributes * \param feature the feature data to draw * \param pencil_size set of sizes and colors for drawing lines and text * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context * \param out_text_width width of the text is returned. NULL is not allowed. * \param out_text_height height of the text is returned. NULL is not allowed. */ void draw_feature_label_get_key_and_value_dimensions ( const draw_feature_label_t *this_, const data_feature_t *feature, const pencil_size_t *pencil_size, PangoLayout *font_layout, double *out_text_width, double *out_text_height ); /*! * \brief renders key and value of the feature * * \param this_ pointer to own object attributes * \param feature the feature data to draw * \param label_box the rectangle where to draw to * \param pencil_size set of sizes and colors for drawing lines and text * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context * \param cr the cairo drawing context. */ void draw_feature_label_draw_key_and_value ( const draw_feature_label_t *this_, const data_feature_t *feature, const geometry_rectangle_t *label_box, const pencil_size_t *pencil_size, PangoLayout *font_layout, cairo_t *cr ); #include "draw_feature_label.inl" #endif /* DRAW_FEATURE_LABEL_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/draw/draw_feature_label.inl000066400000000000000000000015061415120503000252720ustar00rootroot00000000000000/* File: draw_feature_label.inl; Copyright and License: see below */ #include "tslog.h" #include static inline void draw_feature_label_init( draw_feature_label_t *this_ ) { } static inline void draw_feature_label_destroy( draw_feature_label_t *this_ ) { } /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/draw/draw_relationship_label.h000066400000000000000000000074721415120503000260150ustar00rootroot00000000000000/* File: draw_relationship_label.h; Copyright and License: see below */ #ifndef DRAW_RELATIONSHIP_LABEL_H #define DRAW_RELATIONSHIP_LABEL_H /* public file for the doxygen documentation: */ /*! * \file * \brief Draws titles and types of relationships */ #include "pencil_size.h" #include "util/geometry/geometry_h_align.h" #include "util/geometry/geometry_v_align.h" #include "util/geometry/geometry_rectangle.h" #include "util/geometry/geometry_dimensions.h" #include "data_relationship.h" #include #include /*! * \brief attributes of the draw label functions */ struct draw_relationship_label_struct { int dummy; }; typedef struct draw_relationship_label_struct draw_relationship_label_t; /*! * \brief initializes the draw_relationship_label_t * * \param this_ pointer to own object attributes */ static inline void draw_relationship_label_init( draw_relationship_label_t *this_ ); /*! * \brief destroys the draw_relationship_label_t * * \param this_ pointer to own object attributes */ static inline void draw_relationship_label_destroy( draw_relationship_label_t *this_ ); /*! * \brief determines the dimensions of the stereotype and name of the classifier. * * \param this_ pointer to own object attributes * \param relationship the relationship to draw * \param pencil_size set of sizes and colors for drawing lines and text * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context * \param out_text_width width of the text is returned. NULL is not allowed. * \param out_text_height height of the text is returned. NULL is not allowed. */ void draw_relationship_label_get_type_and_name_dimensions( const draw_relationship_label_t *this_, const data_relationship_t *relationship, const pencil_size_t *pencil_size, PangoLayout *font_layout, double *out_text_width, double *out_text_height ); /*! * \brief renders stereotype and name of the classifier. * * \param this_ pointer to own object attributes * \param relationship the relationship to draw * \param label_box the rectangle where to draw to * \param pencil_size set of sizes and colors for drawing lines and text * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context * \param cr the cairo drawing context. */ void draw_relationship_label_draw_type_and_name( const draw_relationship_label_t *this_, const data_relationship_t *relationship, const geometry_rectangle_t *label_box, const pencil_size_t *pencil_size, PangoLayout *font_layout, cairo_t *cr ); #include "draw_relationship_label.inl" #endif /* DRAW_RELATIONSHIP_LABEL_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/draw/draw_relationship_label.inl000066400000000000000000000015371415120503000263440ustar00rootroot00000000000000/* File: draw_relationship_label.inl; Copyright and License: see below */ #include "tslog.h" #include static inline void draw_relationship_label_init( draw_relationship_label_t *this_ ) { } static inline void draw_relationship_label_destroy( draw_relationship_label_t *this_ ) { } /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/layout/000077500000000000000000000000001415120503000213355ustar00rootroot00000000000000crystal-facet-uml-1.34.1/pencil/include/layout/layout_diagram.h000066400000000000000000000072361415120503000245170ustar00rootroot00000000000000/* File: layout_diagram.h; Copyright and License: see below */ #ifndef LAYOUT_DIAGRAM_H #define LAYOUT_DIAGRAM_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines dimensions of a diagram */ #include "util/geometry/geometry_rectangle.h" #include "data_diagram.h" /*! * \brief dimensions of a diagram */ struct layout_diagram_struct { geometry_rectangle_t bounds; /*!< bounding box of the diagram */ geometry_rectangle_t draw_area; /*!< drawing rectangle of inner contents of the diagram */ const data_diagram_t *data; /*!< pointer to the data object of the diagram */ }; typedef struct layout_diagram_struct layout_diagram_t; /*! * \brief initializes the layout_diagram_t struct with a pointer to diagram_data. * * \param this_ pointer to own object attributes * \param diagram_data pointer to data object which is layouted */ static inline void layout_diagram_init ( layout_diagram_t *this_, const data_diagram_t *diagram_data ); /*! * \brief destroys the layout_diagram_t struct * * \param this_ pointer to own object attributes */ static inline void layout_diagram_destroy ( layout_diagram_t *this_ ); /*! * \brief checks if the diagram data is valid * * \param this_ pointer to own object attributes * \return true if (*this_).data points to valid data */ static inline bool layout_diagram_is_valid ( const layout_diagram_t *this_ ); /*! * \brief gets the bounding box of the diagram * * \param this_ pointer to own object attributes * \return pointer to geometry_rectangle_t. */ static inline const geometry_rectangle_t *layout_diagram_get_bounds_const ( const layout_diagram_t *this_ ); /*! * \brief sets the bounding box of the diagram * * \param this_ pointer to own object attributes * \param diagram_bounds coordinates of new bounding box */ static inline void layout_diagram_set_bounds ( layout_diagram_t *this_, const geometry_rectangle_t *diagram_bounds ); /*! * \brief gets the draw area of the diagram * * \param this_ pointer to own object attributes * \return pointer to geometry_rectangle_t. */ static inline const geometry_rectangle_t *layout_diagram_get_draw_area_const ( const layout_diagram_t *this_ ); /*! * \brief sets the draw_area of the diagram * * \param this_ pointer to own object attributes * \param diagram_draw_area coordinates of new draw_area */ static inline void layout_diagram_set_draw_area ( layout_diagram_t *this_, const geometry_rectangle_t *diagram_draw_area ); /*! * \brief gets the data_diagram_t object * * \param this_ pointer to own object attributes * \return a pointer to the corresponding data_diagram_t object */ static inline const data_diagram_t *layout_diagram_get_data_const ( const layout_diagram_t *this_ ); /*! * \brief gets the row id of the diagram * * This is a shortcut for data_diagram_get_row_id( layout_diagram_get_data_const ( X ) ) * * \param this_ pointer to own object attributes * \return id of the diagram */ static inline data_row_id_t layout_diagram_get_diagram_id ( const layout_diagram_t *this_ ); #include "layout_diagram.inl" #endif /* LAYOUT_DIAGRAM_H */ /* Copyright 2018-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/layout/layout_diagram.inl000066400000000000000000000046621415120503000250520ustar00rootroot00000000000000/* File: layout_diagram.inl; Copyright and License: see below */ #include static inline void layout_diagram_init ( layout_diagram_t *this_, const data_diagram_t *diagram_data ) { assert ( NULL != diagram_data ); geometry_rectangle_init_empty( &((*this_).bounds) ); geometry_rectangle_init_empty( &((*this_).draw_area) ); (*this_).data = diagram_data; } static inline void layout_diagram_destroy ( layout_diagram_t *this_ ) { geometry_rectangle_destroy( &((*this_).bounds) ); geometry_rectangle_destroy( &((*this_).draw_area) ); (*this_).data = NULL; } static inline bool layout_diagram_is_valid ( const layout_diagram_t *this_ ) { bool result; if ( (*this_).data == NULL ) { result = false; /* cannot happen on initialized objects */ } else { result = data_diagram_is_valid( (*this_).data ); } return result; } static inline const geometry_rectangle_t *layout_diagram_get_bounds_const ( const layout_diagram_t *this_ ) { return &((*this_).bounds); } static inline void layout_diagram_set_bounds ( layout_diagram_t *this_, const geometry_rectangle_t *diagram_bounds ) { geometry_rectangle_replace( &((*this_).bounds), diagram_bounds ); } static inline const geometry_rectangle_t *layout_diagram_get_draw_area_const ( const layout_diagram_t *this_ ) { return &((*this_).draw_area); } static inline void layout_diagram_set_draw_area ( layout_diagram_t *this_, const geometry_rectangle_t *diagram_draw_area ) { geometry_rectangle_replace( &((*this_).draw_area), diagram_draw_area ); } static inline const data_diagram_t *layout_diagram_get_data_const ( const layout_diagram_t *this_ ) { assert ( NULL != (*this_).data ); return (*this_).data; } static inline data_row_id_t layout_diagram_get_diagram_id ( const layout_diagram_t *this_ ) { return data_diagram_get_row_id( (*this_).data ); } /* Copyright 2018-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/layout/layout_feature.h000066400000000000000000000136141415120503000245430ustar00rootroot00000000000000/* File: layout_feature.h; Copyright and License: see below */ #ifndef LAYOUT_FEATURE_H #define LAYOUT_FEATURE_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines visibility, shape and location of a feature */ #include "layout/layout_visible_classifier.h" #include "util/geometry/geometry_direction.h" #include "util/geometry/geometry_rectangle.h" #include "util/geometry/geometry_point.h" #include "data_feature.h" /*! * \brief visibility, shape and location of a feature */ struct layout_feature_struct { geometry_rectangle_t symbol_box; /*!< In case the feature is a symbol, the label_box may be outside of symbol_box. Oterwise it is the bounding boy of the feature */ geometry_direction_t icon_direction; /*!< icon direction, a hint for drawing the icon of a feature, e.g. lifelines and required interfaces. */ geometry_rectangle_t label_box; /*!< bounding box of the label of the feature. For operations and properties, this is identical to the bounding box */ const data_feature_t *data; /*!< pointer to the data object of the feature */ layout_visible_classifier_t *classifier; /*!< pointer to the layout of the parent visible classifier */ }; typedef struct layout_feature_struct layout_feature_t; /*! * \brief initializes the layout_feature_t struct with a pointer to feature_data. * * \param this_ pointer to own object attributes * \param feature_data pointer to data object which is layouted * \param classifier pointer to layout of the parent classifier object */ static inline void layout_feature_init ( layout_feature_t *this_, const data_feature_t *feature_data, layout_visible_classifier_t *classifier ); /*! * \brief destroys the layout_feature_t struct * * \param this_ pointer to own object attributes */ static inline void layout_feature_destroy ( layout_feature_t *this_ ); /*! * \brief checks if the feature data is valid * * \param this_ pointer to own object attributes * \return true if (*this_).data points to valid data and is consistent with (*this_).classifier */ static inline bool layout_feature_is_valid ( const layout_feature_t *this_ ); /*! * \brief gets the bounding box of the feature * * \param this_ pointer to own object attributes * \return pointer to geometry_rectangle_t. */ static inline const geometry_rectangle_t *layout_feature_get_symbol_box_const ( const layout_feature_t *this_ ); /*! * \brief gets the middle location of the feature's symbol * * \param this_ pointer to own object attributes * \return point of middle of symbol_box. */ static inline geometry_point_t layout_feature_get_symbol_middle ( const layout_feature_t *this_ ); /*! * \brief sets the symbol_box of the feature * * \param this_ pointer to own object attributes * \param feature_symbol_box coordinates of new bounding box */ static inline void layout_feature_set_symbol_box ( layout_feature_t *this_, const geometry_rectangle_t *feature_symbol_box ); /*! * \brief gets the icon direction of the layout feature * * \param this_ pointer to own object attributes * \return icon direction of the feature */ static inline geometry_direction_t layout_feature_get_icon_direction ( const layout_feature_t *this_ ); /*! * \brief sets the icon direction of the layout feature * * \param this_ pointer to own object attributes * \param direction new icon direction to set */ static inline void layout_feature_set_icon_direction ( layout_feature_t *this_, geometry_direction_t direction ); /*! * \brief gets the label bounds of the feature * * \param this_ pointer to own object attributes * \return pointer to geometry_rectangle_t. */ static inline const geometry_rectangle_t *layout_feature_get_label_box_const ( const layout_feature_t *this_ ); /*! * \brief sets the label bounds of the feature * * \param this_ pointer to own object attributes * \param label_box coordinates of new label bounds */ static inline void layout_feature_set_label_box ( layout_feature_t *this_, const geometry_rectangle_t *label_box ); /*! * \brief gets the data_feature_t object * * \param this_ pointer to own object attributes * \return a pointer to the corresponding data_feature_t object */ static inline const data_feature_t *layout_feature_get_data_const ( const layout_feature_t *this_ ); /*! * \brief gets the layout_visible_classifier_t object * * \param this_ pointer to own object attributes * \return a pointer to the parent layout_visible_classifier_t object */ static inline layout_visible_classifier_t *layout_feature_get_classifier_ptr ( layout_feature_t *this_ ); /*! * \brief gets the layout_visible_classifier_t object * * \param this_ pointer to own object attributes * \return a pointer to the parent layout_visible_classifier_t object */ static inline const layout_visible_classifier_t *layout_feature_get_classifier_const ( const layout_feature_t *this_ ); /*! * \brief gets the row id of the feature * * This is a shortcut for data_feature_get_row_id( layout_feature_get_data_const ( X ) ) * * \param this_ pointer to own object attributes * \return id of the feature */ static inline data_row_id_t layout_feature_get_feature_id ( const layout_feature_t *this_ ); #include "layout_feature.inl" #endif /* LAYOUT_FEATURE_H */ /* Copyright 2018-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/layout/layout_feature.inl000066400000000000000000000075431415120503000251020ustar00rootroot00000000000000/* File: layout_feature.inl; Copyright and License: see below */ #include static inline void layout_feature_init ( layout_feature_t *this_, const data_feature_t *feature_data, layout_visible_classifier_t *classifier ) { assert ( NULL != feature_data ); assert ( NULL != classifier ); geometry_rectangle_init_empty( &((*this_).symbol_box) ); geometry_rectangle_init_empty( &((*this_).label_box) ); (*this_).icon_direction = GEOMETRY_DIRECTION_CENTER; (*this_).data = feature_data; (*this_).classifier = classifier; } static inline void layout_feature_destroy ( layout_feature_t *this_ ) { geometry_rectangle_destroy( &((*this_).symbol_box) ); geometry_rectangle_destroy( &((*this_).label_box) ); (*this_).data = NULL; } static inline bool layout_feature_is_valid ( const layout_feature_t *this_ ) { bool result; if (( (*this_).data == NULL )||( (*this_).classifier == NULL )) { result = false; /* cannot happen on initialized objects */ } else { result = data_feature_is_valid( (*this_).data ) && layout_visible_classifier_is_valid( (*this_).classifier ) && ( data_feature_get_classifier_row_id( (*this_).data ) == layout_visible_classifier_get_classifier_id( (*this_).classifier )); } return result; } static inline const geometry_rectangle_t *layout_feature_get_symbol_box_const ( const layout_feature_t *this_ ) { return &((*this_).symbol_box); } static inline geometry_point_t layout_feature_get_symbol_middle ( const layout_feature_t *this_ ) { geometry_point_t result; geometry_point_init( &result, geometry_rectangle_get_center_x( &((*this_).symbol_box) ), geometry_rectangle_get_center_y( &((*this_).symbol_box) ) ); return result; } static inline void layout_feature_set_symbol_box ( layout_feature_t *this_, const geometry_rectangle_t *feature_symbol_box ) { geometry_rectangle_replace( &((*this_).symbol_box), feature_symbol_box ); } static inline geometry_direction_t layout_feature_get_icon_direction ( const layout_feature_t *this_ ) { return (*this_).icon_direction; } static inline void layout_feature_set_icon_direction ( layout_feature_t *this_, geometry_direction_t direction ) { (*this_).icon_direction = direction; } static inline const geometry_rectangle_t *layout_feature_get_label_box_const ( const layout_feature_t *this_ ) { return &((*this_).label_box); } static inline void layout_feature_set_label_box ( layout_feature_t *this_, const geometry_rectangle_t *label_box ) { geometry_rectangle_replace( &((*this_).label_box), label_box ); } static inline const data_feature_t *layout_feature_get_data_const ( const layout_feature_t *this_ ) { return (*this_).data; } static inline layout_visible_classifier_t *layout_feature_get_classifier_ptr ( layout_feature_t *this_ ) { return (*this_).classifier; } static inline const layout_visible_classifier_t *layout_feature_get_classifier_const ( const layout_feature_t *this_ ) { return (*this_).classifier; } static inline data_row_id_t layout_feature_get_feature_id ( const layout_feature_t *this_ ) { return data_feature_get_row_id( (*this_).data ); } /* Copyright 2018-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/layout/layout_order.h000066400000000000000000000136641415120503000242300ustar00rootroot00000000000000/* File: layout_order.h; Copyright and License: see below */ #ifndef LAYOUT_ORDER_H #define LAYOUT_ORDER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Represents an order value for an object, either a list order or an x-/y- order */ #include /*! * \brief enumeration of pencil internal order types */ enum layout_order_type_enum { PENCIL_LAYOUT_ORDER_TYPE_NONE = 0, /*!< there is no order for this type of object in this type of diagram */ PENCIL_LAYOUT_ORDER_TYPE_OUT_OF_RANGE = 1, /*!< there is an order but the position is out of range */ PENCIL_LAYOUT_ORDER_TYPE_X_Y = 2, /*!< the order is an x/y order pair */ PENCIL_LAYOUT_ORDER_TYPE_LIST = 3, /*!< the order is a list order */ }; typedef enum layout_order_type_enum layout_order_type_t; /*! * \brief attributes of the layout_order */ struct layout_order_struct { layout_order_type_t order_type; /*!< defines the type of order */ int32_t first; /*!< list_order if _TYPE_LIST, x_order if _TYPE_X_Y, undefined otherwise */ int32_t second; /*!< y_order if _TYPE_X_Y, undefined otherwise */ }; typedef struct layout_order_struct layout_order_t; /*! * \brief initializes the layout_order_t struct * * \param this_ pointer to own object attributes * \param order_type order_type, defines the interpretation of first and second parameter * \param first first value of the pair * \param second second value of the pair */ static inline void layout_order_private_init ( layout_order_t *this_, layout_order_type_t order_type, int32_t first, int32_t second ); /*! * \brief re-initializes the layout_order_t struct * * \param this_ pointer to own object attributes * \param order_type order_type, defines the interpretation of first and second parameter * \param first first value of the pair * \param second second value of the pair */ static inline void layout_order_private_reinit ( layout_order_t *this_, layout_order_type_t order_type, int32_t first, int32_t second ); /*! * \brief initializes the layout_order_t struct to PENCIL_LAYOUT_ORDER_TYPE_X_Y * * \param this_ pointer to own object attributes * \param x_order first value of the pair * \param y_order second value of the pair */ static inline void layout_order_init_x_y ( layout_order_t *this_, int32_t x_order, int32_t y_order ); /*! * \brief re-initializes the layout_order_t struct to PENCIL_LAYOUT_ORDER_TYPE_X_Y * * \param this_ pointer to own object attributes * \param x_order first value of the pair * \param y_order second value of the pair */ static inline void layout_order_reinit_x_y ( layout_order_t *this_, int32_t x_order, int32_t y_order ); /*! * \brief initializes the layout_order_t struct to PENCIL_LAYOUT_ORDER_TYPE_LIST * * \param this_ pointer to own object attributes * \param list_order the list_order value */ static inline void layout_order_init_list ( layout_order_t *this_, int32_t list_order ); /*! * \brief re-initializes the layout_order_t struct to PENCIL_LAYOUT_ORDER_TYPE_LIST * * \param this_ pointer to own object attributes * \param list_order the list_order value */ static inline void layout_order_reinit_list ( layout_order_t *this_, int32_t list_order ); /*! * \brief copies original to this uninitialized layout_order_t struct * * \param this_ pointer to own object attributes * \param original pointer to object attributes that shall be copied */ static inline void layout_order_copy ( layout_order_t *this_, const layout_order_t *original ); /*! * \brief replaces the already initialized layout_order_t struct by other data * * \param this_ pointer to own object attributes * \param original pointer to object attributes that shall be copied */ static inline void layout_order_replace ( layout_order_t *this_, const layout_order_t *original ); /*! * \brief initializes the layout_order_t struct to a pair of 0,0, PENCIL_LAYOUT_ORDER_TYPE_NONE * * \param this_ pointer to own object attributes */ static inline void layout_order_init_empty ( layout_order_t *this_ ); /*! * \brief re-initializes the layout_order_t struct to a pair of 0,0, PENCIL_LAYOUT_ORDER_TYPE_NONE * * \param this_ pointer to own object attributes */ static inline void layout_order_reinit_empty ( layout_order_t *this_ ); /*! * \brief destroys the layout_order_t struct * * \param this_ pointer to own object attributes */ static inline void layout_order_destroy ( layout_order_t *this_ ); /*! * \brief gets the order type of layout_order_t * * \param this_ pointer to own object attributes * \return order type value of the layout order */ static inline layout_order_type_t layout_order_get_order_type ( const layout_order_t *this_ ); /*! * \brief gets the first value of layout_order_t * * \param this_ pointer to own object attributes * \return first value of the layout order pair */ static inline int32_t layout_order_get_first ( const layout_order_t *this_ ); /*! * \brief gets the second value of layout_order_t * * \param this_ pointer to own object attributes * \return second value of the layout order pair */ static inline int32_t layout_order_get_second ( const layout_order_t *this_ ); /*! * \brief prints the layout_order_t struct to the trace output * * \param this_ pointer to own object attributes */ static inline void layout_order_trace ( const layout_order_t *this_ ); #include "layout_order.inl" #endif /* LAYOUT_ORDER_H */ /* Copyright 2018-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/layout/layout_order.inl000066400000000000000000000076661415120503000245700ustar00rootroot00000000000000/* File: layout_order.inl; Copyright and License: see below */ #include "trace.h" static inline void layout_order_private_init ( layout_order_t *this_, layout_order_type_t order_type, int32_t first, int32_t second ) { (*this_).first = first; (*this_).second = second; (*this_).order_type = order_type; } static inline void layout_order_private_reinit ( layout_order_t *this_, layout_order_type_t order_type, int32_t first, int32_t second ) { (*this_).first = first; (*this_).second = second; (*this_).order_type = order_type; } static inline void layout_order_init_x_y ( layout_order_t *this_, int32_t x_order, int32_t y_order ) { (*this_).first = x_order; (*this_).second = y_order; (*this_).order_type = PENCIL_LAYOUT_ORDER_TYPE_X_Y; } static inline void layout_order_reinit_x_y ( layout_order_t *this_, int32_t x_order, int32_t y_order ) { (*this_).first = x_order; (*this_).second = y_order; (*this_).order_type = PENCIL_LAYOUT_ORDER_TYPE_X_Y; } static inline void layout_order_init_list ( layout_order_t *this_, int32_t list_order ) { (*this_).first = list_order; (*this_).second = 0; (*this_).order_type = PENCIL_LAYOUT_ORDER_TYPE_LIST; } static inline void layout_order_reinit_list ( layout_order_t *this_, int32_t list_order ) { (*this_).first = list_order; (*this_).second = 0; (*this_).order_type = PENCIL_LAYOUT_ORDER_TYPE_LIST; } static inline void layout_order_copy ( layout_order_t *this_, const layout_order_t *original ) { (*this_) = (*original); } static inline void layout_order_replace ( layout_order_t *this_, const layout_order_t *original ) { (*this_) = (*original); } static inline void layout_order_init_empty ( layout_order_t *this_ ) { (*this_).first = 0; (*this_).second = 0; (*this_).order_type = PENCIL_LAYOUT_ORDER_TYPE_NONE; } static inline void layout_order_reinit_empty ( layout_order_t *this_ ) { (*this_).first = 0; (*this_).second = 0; (*this_).order_type = PENCIL_LAYOUT_ORDER_TYPE_NONE; } static inline void layout_order_destroy ( layout_order_t *this_ ) { } static inline layout_order_type_t layout_order_get_order_type ( const layout_order_t *this_ ) { return (*this_).order_type; } static inline int32_t layout_order_get_first ( const layout_order_t *this_ ) { return (*this_).first; } static inline int32_t layout_order_get_second ( const layout_order_t *this_ ) { return (*this_).second; } static inline void layout_order_trace ( const layout_order_t *this_ ) { TRACE_INFO( "layout_order_t" ); switch ( (*this_).order_type ) { case PENCIL_LAYOUT_ORDER_TYPE_NONE: { TRACE_INFO( "- order_type: PENCIL_LAYOUT_ORDER_TYPE_NONE" ); } break; case PENCIL_LAYOUT_ORDER_TYPE_OUT_OF_RANGE: { TRACE_INFO( "- order_type: PENCIL_LAYOUT_ORDER_TYPE_OUT_OF_RANGE" ); } break; case PENCIL_LAYOUT_ORDER_TYPE_X_Y: { TRACE_INFO( "- order_type: PENCIL_LAYOUT_ORDER_TYPE_X_Y" ); } break; case PENCIL_LAYOUT_ORDER_TYPE_LIST: { TRACE_INFO( "- order_type: PENCIL_LAYOUT_ORDER_TYPE_LIST" ); } break; default: { TRACE_INFO( "- order_type: " ); } break; } TRACE_INFO_INT( "- first:", (*this_).first ); TRACE_INFO_INT( "- second:", (*this_).second ); } /* Copyright 2018-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/layout/layout_relationship.h000066400000000000000000000202711415120503000256060ustar00rootroot00000000000000/* File: layout_relationship.h; Copyright and License: see below */ #ifndef LAYOUT_RELATIONSHIP_H #define LAYOUT_RELATIONSHIP_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines visibility, shape and location of a relationship */ #include "layout/layout_visible_classifier.h" #include "layout/layout_feature.h" #include "option/pencil_visibility.h" #include "util/geometry/geometry_connector.h" #include "data_relationship.h" /*! * \brief visibility, shape and location of a relationship */ struct layout_relationship_struct { pencil_visibility_t visible; /*!< defines if the relationship is visible */ geometry_connector_t shape; /*!< shape of relationship records */ geometry_rectangle_t label_box; /*!< bounding box of the label of the relationship. */ const data_relationship_t *data; /*!< pointer to the data object of the relationship */ layout_visible_classifier_t *from_classifier; /*!< pointer to the layout of the source visible classifier */ layout_visible_classifier_t *to_classifier; /*!< pointer to the layout of the destination visible classifier */ layout_feature_t *from_feature; /*!< pointer to the layout of the source feature, NULL if none */ layout_feature_t *to_feature; /*!< pointer to the layout of the destination feature, NULL if none */ }; typedef struct layout_relationship_struct layout_relationship_t; /*! * \brief initializes the layout_relationship_t struct with a pointer to data_relationship_t. * * \param this_ pointer to own object attributes * \param relationship_data pointer to data object which is layouted * \param from_classifier pointer to layout of the source classifier object * \param to_classifier pointer to layout of the destination classifier object * \param from_feature pointer to layout of the source feature object or NULL if not originating from a feature * \param to_feature pointer to layout of the destination feature object or NULL if not directed to a feature */ static inline void layout_relationship_init ( layout_relationship_t *this_, const data_relationship_t *relationship_data, layout_visible_classifier_t *from_classifier, layout_visible_classifier_t *to_classifier, layout_feature_t *from_feature, layout_feature_t *to_feature ); /*! * \brief destroys the layout_relationship_t struct * * \param this_ pointer to own object attributes */ static inline void layout_relationship_destroy ( layout_relationship_t *this_ ); /*! * \brief checks if the relationship data is valid * * \param this_ pointer to own object attributes * \return true if (*this_).data points to valid data and is consistent with (*this_).from_classifier, * (*this_).to_classifier, (*this_).from_feature, (*this_).to_feature */ static inline bool layout_relationship_is_valid ( const layout_relationship_t *this_ ); /*! * \brief gets the visibility of the relationship * * \param this_ pointer to own object attributes * \return visibility of the relationship layout. */ static inline pencil_visibility_t layout_relationship_get_visibility ( const layout_relationship_t *this_ ); /*! * \brief sets the visibility of the relationship * * \param this_ pointer to own object attributes * \param visible visibility of the relationship layout. */ static inline void layout_relationship_set_visibility ( layout_relationship_t *this_, pencil_visibility_t visible ); /*! * \brief gets the shape of the relationship * * \param this_ pointer to own object attributes * \return pointer to geometry_rectangle_t. */ static inline const geometry_connector_t *layout_relationship_get_shape_const ( const layout_relationship_t *this_ ); /*! * \brief sets the shape of the relationship * * \param this_ pointer to own object attributes * \param shape new shape of this relationship */ static inline void layout_relationship_set_shape ( layout_relationship_t *this_, const geometry_connector_t *shape ); /*! * \brief gets the middle location of the relationship * * \param this_ pointer to own object attributes * \return point of middle of connector. */ static inline geometry_point_t layout_relationship_get_middle ( const layout_relationship_t *this_ ); /*! * \brief gets the label bounds of the relationship * * \param this_ pointer to own object attributes * \return pointer to geometry_rectangle_t. */ static inline const geometry_rectangle_t *layout_relationship_get_label_box_const ( const layout_relationship_t *this_ ); /*! * \brief sets the label bounds of the relationship * * \param this_ pointer to own object attributes * \param label_box coordinates of new label bounds */ static inline void layout_relationship_set_label_box ( layout_relationship_t *this_, const geometry_rectangle_t *label_box ); /*! * \brief gets the data_relationship_t object * * \param this_ pointer to own object attributes * \return a pointer to a data_relationship_t object. */ static inline const data_relationship_t *layout_relationship_get_data_const ( const layout_relationship_t *this_ ); /*! * \brief gets the source layout_visible_classifier_t object * * \param this_ pointer to own object attributes * \return a pointer to the source layout_visible_classifier_t object. */ static inline layout_visible_classifier_t *layout_relationship_get_from_classifier_ptr ( const layout_relationship_t *this_ ); /*! * \brief gets the destination layout_visible_classifier_t object * * \param this_ pointer to own object attributes * \return a pointer to the destination layout_visible_classifier_t object. */ static inline layout_visible_classifier_t *layout_relationship_get_to_classifier_ptr ( const layout_relationship_t *this_ ); /*! * \brief gets the source layout_feature_t object * * \param this_ pointer to own object attributes * \return a pointer to the source layout_feature_t object or NULL if the relationship does not originate from a feature */ static inline layout_feature_t *layout_relationship_get_from_feature_ptr ( const layout_relationship_t *this_ ); /*! * \brief gets the destination layout_feature_t object * * \param this_ pointer to own object attributes * \return a pointer to the destination layout_feature_t object, or NULL if the relationship does not point to a feature */ static inline layout_feature_t *layout_relationship_get_to_feature_ptr ( const layout_relationship_t *this_ ); /*! * \brief gets the row id of the relationship * * This is a shortcut for data_relationship_get_row_id( layout_relationship_get_data_const ( X ) ) * * \param this_ pointer to own object attributes * \return id of the relationship */ static inline data_row_id_t layout_relationship_get_relationship_id ( const layout_relationship_t *this_ ); /*! * \brief gets the symbol_box of the source object, the feature or the classifier * * \param this_ pointer to own object attributes * \return pointer to const geometry_rectangle_t. */ static inline const geometry_rectangle_t *layout_relationship_get_from_symbol_box_const ( const layout_relationship_t *this_ ); /*! * \brief gets the symbol_box of the destination object, the feature or the classifier * * \param this_ pointer to own object attributes * \return pointer to const geometry_rectangle_t. */ static inline const geometry_rectangle_t *layout_relationship_get_to_symbol_box_const ( const layout_relationship_t *this_ ); #include "layout_relationship.inl" #endif /* LAYOUT_RELATIONSHIP_H */ /* Copyright 2018-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/layout/layout_relationship.inl000066400000000000000000000150521415120503000261420ustar00rootroot00000000000000/* File: layout_relationship.inl; Copyright and License: see below */ #include static inline void layout_relationship_init ( layout_relationship_t *this_, const data_relationship_t *relationship_data, layout_visible_classifier_t *from_classifier, layout_visible_classifier_t *to_classifier, layout_feature_t *from_feature, layout_feature_t *to_feature ) { assert ( NULL != relationship_data ); assert ( NULL != from_classifier ); assert ( NULL != to_classifier ); (*this_).visible = PENCIL_VISIBILITY_HIDE; geometry_connector_init_empty( &((*this_).shape) ); geometry_rectangle_init_empty( &((*this_).label_box) ); (*this_).data = relationship_data; (*this_).from_classifier = from_classifier; (*this_).to_classifier = to_classifier; (*this_).from_feature = from_feature; (*this_).to_feature = to_feature; } static inline void layout_relationship_destroy ( layout_relationship_t *this_ ) { geometry_connector_destroy( &((*this_).shape) ); geometry_rectangle_destroy( &((*this_).label_box) ); (*this_).data = NULL; } static inline bool layout_relationship_is_valid ( const layout_relationship_t *this_ ) { bool result; if (( (*this_).data == NULL )||( (*this_).from_classifier == NULL )||( (*this_).to_classifier == NULL )) { result = false; /* cannot happen on initialized objects */ } else { const data_row_id_t from_classifier_id = data_relationship_get_from_classifier_row_id( (*this_).data ); const data_row_id_t to_classifier_id = data_relationship_get_to_classifier_row_id( (*this_).data ); const data_row_id_t from_feature_id = data_relationship_get_from_feature_row_id( (*this_).data ); const data_row_id_t to_feature_id = data_relationship_get_to_feature_row_id( (*this_).data ); const bool from_feature_ok = ( NULL == (*this_).from_feature ) ? ( from_feature_id == DATA_ROW_ID_VOID ) : ( from_feature_id == layout_feature_get_feature_id( (*this_).from_feature ) ); const bool to_feature_ok = ( NULL == (*this_).to_feature ) ? ( to_feature_id == DATA_ROW_ID_VOID ) : ( to_feature_id == layout_feature_get_feature_id( (*this_).to_feature ) ); result = data_relationship_is_valid( (*this_).data ) && layout_visible_classifier_is_valid( (*this_).from_classifier ) && layout_visible_classifier_is_valid( (*this_).to_classifier ) && ( from_classifier_id == layout_visible_classifier_get_classifier_id( (*this_).from_classifier ) ) && ( to_classifier_id == layout_visible_classifier_get_classifier_id( (*this_).to_classifier ) ) && from_feature_ok && to_feature_ok; } return result; } static inline pencil_visibility_t layout_relationship_get_visibility ( const layout_relationship_t *this_ ) { return (*this_).visible; } static inline void layout_relationship_set_visibility ( layout_relationship_t *this_, pencil_visibility_t visible ) { (*this_).visible = visible; } static inline const geometry_connector_t *layout_relationship_get_shape_const ( const layout_relationship_t *this_ ) { return &((*this_).shape); } static inline void layout_relationship_set_shape ( layout_relationship_t *this_, const geometry_connector_t *shape ) { geometry_connector_replace ( &((*this_).shape), shape ); } static inline geometry_point_t layout_relationship_get_middle ( const layout_relationship_t *this_ ) { double connector_length = geometry_connector_get_length( &((*this_).shape) ); return geometry_connector_calculate_waypoint( &((*this_).shape), connector_length/2.0 ); } static inline const geometry_rectangle_t *layout_relationship_get_label_box_const ( const layout_relationship_t *this_ ) { return &((*this_).label_box); } static inline void layout_relationship_set_label_box ( layout_relationship_t *this_, const geometry_rectangle_t *label_box ) { geometry_rectangle_replace( &((*this_).label_box), label_box ); } static inline const data_relationship_t *layout_relationship_get_data_const ( const layout_relationship_t *this_ ) { assert ( NULL != (*this_).data ); return (*this_).data; } static inline layout_visible_classifier_t *layout_relationship_get_from_classifier_ptr ( const layout_relationship_t *this_ ) { return (*this_).from_classifier; } static inline layout_visible_classifier_t *layout_relationship_get_to_classifier_ptr ( const layout_relationship_t *this_ ) { return (*this_).to_classifier; } static inline layout_feature_t *layout_relationship_get_from_feature_ptr ( const layout_relationship_t *this_ ) { return (*this_).from_feature; } static inline layout_feature_t *layout_relationship_get_to_feature_ptr ( const layout_relationship_t *this_ ) { return (*this_).to_feature; } static inline data_row_id_t layout_relationship_get_relationship_id ( const layout_relationship_t *this_ ) { return data_relationship_get_row_id( (*this_).data ); } static inline const geometry_rectangle_t *layout_relationship_get_from_symbol_box_const ( const layout_relationship_t *this_ ) { const geometry_rectangle_t *result; if ( NULL != (*this_).from_feature ) { result = layout_feature_get_symbol_box_const( (*this_).from_feature ); } else { result = layout_visible_classifier_get_symbol_box_const( (*this_).from_classifier ); } return result; } static inline const geometry_rectangle_t *layout_relationship_get_to_symbol_box_const ( const layout_relationship_t *this_ ) { const geometry_rectangle_t *result; if ( NULL != (*this_).to_feature ) { result = layout_feature_get_symbol_box_const( (*this_).to_feature ); } else { result = layout_visible_classifier_get_symbol_box_const( (*this_).to_classifier ); } return result; } /* Copyright 2018-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/layout/layout_visible_classifier.h000066400000000000000000000260271415120503000267530ustar00rootroot00000000000000/* File: layout_visible_classifier.h; Copyright and License: see below */ #ifndef LAYOUT_VISIBLE_CLASSIFIER_H #define LAYOUT_VISIBLE_CLASSIFIER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines shape and location of a visible_classifier */ #include "util/geometry/geometry_rectangle.h" #include "util/geometry/geometry_h_align.h" #include "util/geometry/geometry_v_align.h" #include "set/data_visible_classifier.h" /*! * \brief shape and location of a visible_classifier */ struct layout_visible_classifier_struct { geometry_rectangle_t symbol_box; /*!< symbol_box of a classifier shape. */ /*!< Depending on the classifier type, this is the icon or the contour or both. */ /*!< The label_box may be outside of the symbol_box. */ /*!< symbol_box is stated in absolute coordinates. */ geometry_rectangle_t space; /*!< inner space of a classifier record where properties, operations */ /*!< or contained classifiers are drawn. space is stated in absolute coordinates. */ geometry_rectangle_t label_box; /*!< bounding box of the label of the visible classifier. */ /*!< label_box is stated in absolute coordinates. */ geometry_h_align_t label_h_anchor; /*!< side of the label box that stays fix in case of expand */ geometry_v_align_t label_v_anchor; /*!< side of the label box that stays fix in case of expand */ geometry_rectangle_t envelope_box_cache; /*!< for caching the envelope_box, */ /*!< which is derived from the other three rectangles */ const data_visible_classifier_t *data; /*!< pointer to the data object of the visible classifier */ }; typedef struct layout_visible_classifier_struct layout_visible_classifier_t; /*! * \brief initializes the layout_visible_classifier_t struct with a pointer to the corresponding data_visible_classifier_t. * * \param this_ pointer to own object attributes * \param visible_classifier_data pointer to data object which is layouted */ static inline void layout_visible_classifier_init ( layout_visible_classifier_t *this_, const data_visible_classifier_t *visible_classifier_data ); /*! * \brief copies a layout_visible_classifier_t struct to this uninitialized layout_visible_classifier_t struct * * \param this_ pointer to own object attributes * \param original pointer to original object attributes */ static inline void layout_visible_classifier_copy ( layout_visible_classifier_t *this_, const layout_visible_classifier_t *original ); /*! * \brief moves a layout_visible_classifier_t struct to this uninitialized layout_visible_classifier_t struct * * \param this_ pointer to own object attributes * \param that pointer to original object attributes to be moved */ static inline void layout_visible_classifier_move ( layout_visible_classifier_t *this_, layout_visible_classifier_t *that ); /*! * \brief copies a layout_visible_classifier_t struct to this already initialized layout_visible_classifier_t struct * * \param this_ pointer to own object attributes * \param original pointer to original object attributes */ static inline void layout_visible_classifier_replace ( layout_visible_classifier_t *this_, const layout_visible_classifier_t *original ); /*! * \brief moves a layout_visible_classifier_t struct to this already initialized layout_visible_classifier_t struct * * \param this_ pointer to own object attributes * \param that pointer to original object attributes to be moved */ static inline void layout_visible_classifier_replacemove ( layout_visible_classifier_t *this_, layout_visible_classifier_t *that ); /*! * \brief destroys the layout_visible_classifier_t struct * * \param this_ pointer to own object attributes */ static inline void layout_visible_classifier_destroy ( layout_visible_classifier_t *this_ ); /*! * \brief checks if the layout_visible_classifier data is valid * * \param this_ pointer to own object attributes * \return true if (*this_).data points to valid data */ static inline bool layout_visible_classifier_is_valid ( const layout_visible_classifier_t *this_ ); /*! * \brief gets the symbol_box of the classifier * * \param this_ pointer to own object attributes * \return pointer to geometry_rectangle_t. */ static inline const geometry_rectangle_t *layout_visible_classifier_get_symbol_box_const ( const layout_visible_classifier_t *this_ ); /*! * \brief sets the symbol_box of the classifier * * \param this_ pointer to own object attributes * \param symbol_box coordinates of new symbol_box */ static inline void layout_visible_classifier_set_symbol_box ( layout_visible_classifier_t *this_, const geometry_rectangle_t *symbol_box ); /*! * \brief gets the inner space of the classifier * * \param this_ pointer to own object attributes * \return pointer to geometry_rectangle_t. */ static inline const geometry_rectangle_t *layout_visible_classifier_get_space_const ( const layout_visible_classifier_t *this_ ); /*! * \brief sets the inner space of the classifier * * \param this_ pointer to own object attributes * \param space coordinates of new space for contained classifiers and features */ static inline void layout_visible_classifier_set_space ( layout_visible_classifier_t *this_, const geometry_rectangle_t *space ); /*! * \brief gets the label bounds of the classifier * * \param this_ pointer to own object attributes * \return pointer to geometry_rectangle_t. */ static inline const geometry_rectangle_t *layout_visible_classifier_get_label_box_const ( const layout_visible_classifier_t *this_ ); /*! * \brief sets the label bounds of the classifier * * \param this_ pointer to own object attributes * \param label_box coordinates of new label bounds */ static inline void layout_visible_classifier_set_label_box ( layout_visible_classifier_t *this_, const geometry_rectangle_t *label_box ); /*! * \brief sets the bounding box of the classifier * * \param this_ pointer to own object attributes * \param label_h_anchor side of the label that stays fix in case of expand * \param label_v_anchor side of the label that stays fix in case of expand */ static inline void layout_visible_classifier_set_label_anchor ( layout_visible_classifier_t *this_, geometry_h_align_t label_h_anchor, geometry_v_align_t label_v_anchor ); /*! * \brief calculates the envelope bounds of the classifier. * * The envelope contains the label and the symbol box and implicitly the (inner) space. * * \param this_ pointer to own object attributes * \return geometry_rectangle_t which is the envelope to label and symbol-box. */ static inline geometry_rectangle_t layout_visible_classifier_get_envelope_box ( const layout_visible_classifier_t *this_ ); /*! * \brief gets the envelope of the classifier * * \param this_ pointer to own object attributes * \return pointer to geometry_rectangle_t. */ static inline const geometry_rectangle_t *layout_visible_classifier_get_envelope_box_const ( const layout_visible_classifier_t *this_ ); /*! * \brief moves the layout_visible_classifier_t * * \param this_ pointer to own object attributes * \param delta_x delta-x difference by which to shift the layout_visible_classifier_t * \param delta_y delta-y difference by which to shift the layout_visible_classifier_t */ static inline void layout_visible_classifier_shift ( layout_visible_classifier_t *this_, double delta_x, double delta_y ); /*! * \brief gets the pointer to the data_visible_classifier_t object * * \param this_ pointer to own object attributes * \return a pointer to a data_visible_classifier_t object. */ static inline const data_visible_classifier_t *layout_visible_classifier_get_data_const ( const layout_visible_classifier_t *this_ ); /*! * \brief gets the pointer to the const classifier * * \param this_ pointer to own object attributes * \return a pointer to a classifier. */ static inline const data_classifier_t *layout_visible_classifier_get_classifier_const ( const layout_visible_classifier_t *this_ ); /*! * \brief gets the pointer to the const diagramelement * * \param this_ pointer to own object attributes * \return a pointer to a diagramelement. */ static inline const data_diagramelement_t *layout_visible_classifier_get_diagramelement_const ( const layout_visible_classifier_t *this_ ); /*! * \brief gets the row id of the classifier * * This is a shortcut for data_classifier_get_row_id( data_visible_classifier_get_classifier_const ( (*this_).data ) ) * * \param this_ pointer to own object attributes * \return id of the classifier */ static inline data_row_id_t layout_visible_classifier_get_classifier_id ( const layout_visible_classifier_t *this_ ); /*! * \brief gets the row id of the diagramelement * * This is a shortcut for data_diagramelement_get_row_id( data_visible_classifier_get_diagramelement_const ( (*this_).data ) ) * * \param this_ pointer to own object attributes * \return id of the diagramelement */ static inline data_row_id_t layout_visible_classifier_get_diagramelement_id ( const layout_visible_classifier_t *this_ ); /*! * \brief checks if the ids of the associated diagramelements are identical * * This is a shortcut for layout_visible_classifier_get_diagramelement_id( this_ )==layout_visible_classifier_get_diagramelement_id( that ) * * \param this_ pointer to own object attributes * \param that pointer to others object attributes * \return true if ids of the associated diagramelements are identical */ static inline bool layout_visible_classifier_is_equal_diagramelement_id ( const layout_visible_classifier_t *this_, const layout_visible_classifier_t *that ); /*! * \brief calculates the envelope bounds of the classifier and stores it in envelope_box_cache. * * The envelope contains the label and the symbol box and the (inner) space. * * \param this_ pointer to own object attributes */ static inline void layout_visible_classifier_private_update_envelope_box ( layout_visible_classifier_t *this_ ); #include "layout_visible_classifier.inl" #endif /* LAYOUT_VISIBLE_CLASSIFIER_H */ /* Copyright 2018-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/layout/layout_visible_classifier.inl000066400000000000000000000224351415120503000273050ustar00rootroot00000000000000/* File: layout_visible_classifier.inl; Copyright and License: see below */ #include static inline void layout_visible_classifier_init ( layout_visible_classifier_t *this_, const data_visible_classifier_t *visible_classifier_data ) { assert ( NULL != visible_classifier_data ); geometry_rectangle_init_empty( &((*this_).symbol_box) ); geometry_rectangle_init_empty( &((*this_).space) ); geometry_rectangle_init_empty( &((*this_).label_box) ); geometry_rectangle_init_empty( &((*this_).envelope_box_cache) ); (*this_).label_h_anchor = GEOMETRY_H_ALIGN_CENTER; /* most labels are centered */ (*this_).label_v_anchor = GEOMETRY_V_ALIGN_TOP; /* most labels are fixed to the top */ (*this_).data = visible_classifier_data; } static inline void layout_visible_classifier_copy( layout_visible_classifier_t *this_, const layout_visible_classifier_t *original ) { assert ( NULL != original ); assert ( NULL != (*original).data ); geometry_rectangle_copy( &((*this_).symbol_box), &((*original).symbol_box) ); geometry_rectangle_copy( &((*this_).space), &((*original).space) ); geometry_rectangle_copy( &((*this_).label_box), &((*original).label_box) ); geometry_rectangle_copy( &((*this_).envelope_box_cache), &((*original).envelope_box_cache) ); (*this_).label_h_anchor = (*original).label_h_anchor; (*this_).label_v_anchor = (*original).label_v_anchor; (*this_).data = (*original).data; } static inline void layout_visible_classifier_move( layout_visible_classifier_t *this_, layout_visible_classifier_t *that ) { assert ( NULL != that ); assert ( NULL != (*that).data ); geometry_rectangle_move( &((*this_).symbol_box), &((*that).symbol_box) ); geometry_rectangle_move( &((*this_).space), &((*that).space) ); geometry_rectangle_move( &((*this_).label_box), &((*that).label_box) ); geometry_rectangle_move( &((*this_).envelope_box_cache), &((*that).envelope_box_cache) ); (*this_).label_h_anchor = (*that).label_h_anchor; (*this_).label_v_anchor = (*that).label_v_anchor; (*this_).data = (*that).data; (*that).data = NULL; } static inline void layout_visible_classifier_replace( layout_visible_classifier_t *this_, const layout_visible_classifier_t *original ) { assert ( NULL != original ); assert ( NULL != (*original).data ); geometry_rectangle_replace( &((*this_).symbol_box), &((*original).symbol_box) ); geometry_rectangle_replace( &((*this_).space), &((*original).space) ); geometry_rectangle_replace( &((*this_).label_box), &((*original).label_box) ); geometry_rectangle_replace( &((*this_).envelope_box_cache), &((*original).envelope_box_cache) ); (*this_).label_h_anchor = (*original).label_h_anchor; (*this_).label_v_anchor = (*original).label_v_anchor; (*this_).data = (*original).data; } static inline void layout_visible_classifier_replacemove( layout_visible_classifier_t *this_, layout_visible_classifier_t *that ) { assert ( NULL != that ); assert ( NULL != (*that).data ); geometry_rectangle_replacemove( &((*this_).symbol_box), &((*that).symbol_box) ); geometry_rectangle_replacemove( &((*this_).space), &((*that).space) ); geometry_rectangle_replacemove( &((*this_).label_box), &((*that).label_box) ); geometry_rectangle_replacemove( &((*this_).envelope_box_cache), &((*that).envelope_box_cache) ); (*this_).label_h_anchor = (*that).label_h_anchor; (*this_).label_v_anchor = (*that).label_v_anchor; (*this_).data = (*that).data; (*that).data = NULL; } static inline void layout_visible_classifier_destroy ( layout_visible_classifier_t *this_ ) { geometry_rectangle_destroy( &((*this_).symbol_box) ); geometry_rectangle_destroy( &((*this_).space) ); geometry_rectangle_destroy( &((*this_).label_box) ); geometry_rectangle_destroy( &((*this_).envelope_box_cache) ); (*this_).data = NULL; } static inline bool layout_visible_classifier_is_valid ( const layout_visible_classifier_t *this_ ) { bool result; if ( (*this_).data == NULL ) { result = false; /* cannot happen on initialized objects */ } else { result = data_visible_classifier_is_valid( (*this_).data ); } return result; } static inline const geometry_rectangle_t *layout_visible_classifier_get_symbol_box_const ( const layout_visible_classifier_t *this_ ) { return &((*this_).symbol_box); } static inline void layout_visible_classifier_set_symbol_box ( layout_visible_classifier_t *this_, const geometry_rectangle_t *symbol_box ) { geometry_rectangle_replace( &((*this_).symbol_box), symbol_box ); /* update the cached value of envelope_box */ layout_visible_classifier_private_update_envelope_box( this_ ); } static inline const geometry_rectangle_t *layout_visible_classifier_get_space_const ( const layout_visible_classifier_t *this_ ) { return &((*this_).space); } static inline void layout_visible_classifier_set_space ( layout_visible_classifier_t *this_, const geometry_rectangle_t *space ) { geometry_rectangle_replace( &((*this_).space), space ); /* update the cached value of envelope_box */ layout_visible_classifier_private_update_envelope_box( this_ ); } static inline const geometry_rectangle_t *layout_visible_classifier_get_label_box_const ( const layout_visible_classifier_t *this_ ) { return &((*this_).label_box); } static inline void layout_visible_classifier_set_label_box ( layout_visible_classifier_t *this_, const geometry_rectangle_t *label_box ) { geometry_rectangle_replace( &((*this_).label_box), label_box ); /* update the cached value of envelope_box */ layout_visible_classifier_private_update_envelope_box( this_ ); } static inline void layout_visible_classifier_set_label_anchor ( layout_visible_classifier_t *this_, geometry_h_align_t label_h_anchor, geometry_v_align_t label_v_anchor ) { (*this_).label_h_anchor = label_h_anchor; (*this_).label_v_anchor = label_v_anchor; } static inline geometry_rectangle_t layout_visible_classifier_get_envelope_box ( const layout_visible_classifier_t *this_ ) { return (*this_).envelope_box_cache; } static inline const geometry_rectangle_t *layout_visible_classifier_get_envelope_box_const ( const layout_visible_classifier_t *this_ ) { /* return the cached value */ return &((*this_).envelope_box_cache); } static inline void layout_visible_classifier_shift ( layout_visible_classifier_t *this_, double delta_x, double delta_y ) { geometry_rectangle_shift( &((*this_).symbol_box), delta_x, delta_y ); geometry_rectangle_shift( &((*this_).space), delta_x, delta_y ); geometry_rectangle_shift( &((*this_).label_box), delta_x, delta_y ); /* update the cached value of envelope_box */ geometry_rectangle_shift( &((*this_).envelope_box_cache), delta_x, delta_y ); } static inline const data_visible_classifier_t *layout_visible_classifier_get_data_const ( const layout_visible_classifier_t *this_ ) { return (*this_).data; } static inline const data_classifier_t *layout_visible_classifier_get_classifier_const ( const layout_visible_classifier_t *this_ ) { return data_visible_classifier_get_classifier_const ( (*this_).data ); } static inline const data_diagramelement_t *layout_visible_classifier_get_diagramelement_const ( const layout_visible_classifier_t *this_ ) { return data_visible_classifier_get_diagramelement_const ( (*this_).data ); } static inline data_row_id_t layout_visible_classifier_get_classifier_id ( const layout_visible_classifier_t *this_ ) { return data_classifier_get_row_id( data_visible_classifier_get_classifier_const ( (*this_).data ) ); } static inline data_row_id_t layout_visible_classifier_get_diagramelement_id ( const layout_visible_classifier_t *this_ ) { return data_diagramelement_get_row_id( data_visible_classifier_get_diagramelement_const ( (*this_).data ) ); } static inline bool layout_visible_classifier_is_equal_diagramelement_id ( const layout_visible_classifier_t *this_, const layout_visible_classifier_t *that ) { const data_row_id_t this_diagele_id = layout_visible_classifier_get_diagramelement_id( this_ ); const data_row_id_t that_diagele_id = layout_visible_classifier_get_diagramelement_id( that ); return ( this_diagele_id == that_diagele_id ); } static inline void layout_visible_classifier_private_update_envelope_box ( layout_visible_classifier_t *this_ ) { geometry_rectangle_t intermediate; geometry_rectangle_init_by_bounds( &intermediate, &((*this_).symbol_box), &((*this_).label_box) ); geometry_rectangle_init_by_bounds( &((*this_).envelope_box_cache), &intermediate, &((*this_).space) ); } /* Copyright 2018-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/option/000077500000000000000000000000001415120503000213305ustar00rootroot00000000000000crystal-facet-uml-1.34.1/pencil/include/option/pencil_type_filter.h000066400000000000000000000021661415120503000253660ustar00rootroot00000000000000/* File: pencil_type_filter.h; Copyright and License: see below */ #ifndef PENCIL_TYPE_FILTER_H #define PENCIL_TYPE_FILTER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines filter for of objects */ /*! * \brief enumeration of filter types */ enum pencil_type_filter_enum { PENCIL_TYPE_FILTER_NONE, /*!< all objects pass the filter */ PENCIL_TYPE_FILTER_LIFELINE, /*!< all objects except lifeline-features pass the filter */ }; typedef enum pencil_type_filter_enum pencil_type_filter_t; #endif /* PENCIL_TYPE_FILTER_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/option/pencil_visibility.h000066400000000000000000000024721415120503000252270ustar00rootroot00000000000000/* File: pencil_visibility.h; Copyright and License: see below */ #ifndef PENCIL_VISIBILITY_H #define PENCIL_VISIBILITY_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines visibility of objects */ /*! * \brief enumeration of all visibility types */ enum pencil_visibility_enum { PENCIL_VISIBILITY_HIDE, /*!< object is not shown, not even if mouse-over or if selected */ PENCIL_VISIBILITY_IMPLICIT, /*!< object need not be drawn explicitly unless required by conditions like mouse-over or selected */ PENCIL_VISIBILITY_GRAY_OUT, /*!< object is shown but grayed out */ PENCIL_VISIBILITY_SHOW, /*!< object is shown */ }; typedef enum pencil_visibility_enum pencil_visibility_t; #endif /* PENCIL_VISIBILITY_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_classifier_1d_layouter.h000066400000000000000000000160701415120503000261630ustar00rootroot00000000000000/* File: pencil_classifier_1d_layouter.h; Copyright and License: see below */ #ifndef PENCIL_CLASSIFIER_1D_LAYOUTER_H #define PENCIL_CLASSIFIER_1D_LAYOUTER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Calculates positions of classifiers and features in a 1-dimensional diagram. * * Timing, Sequence and list diagrams are layouted 1-dimensional. */ #include "pencil_classifier_composer.h" #include "pencil_size.h" #include "pencil_layout_data.h" #include "util/geometry/geometry_rectangle.h" #include "util/geometry/geometry_h_align.h" #include "util/geometry/geometry_v_align.h" #include "data_diagram.h" #include "set/data_small_set.h" #include "data_id.h" #include "set/data_visible_set.h" #include "universal_array_index_sorter.h" #include #include /*! * \brief attributes of the classifier layouter */ struct pencil_classifier_1d_layouter_struct { pencil_layout_data_t *layout_data; /* pointer to external layout data */ const pencil_size_t *pencil_size; /*!< pointer to an external pencil_size_t object, defining pen sizes, gap sizes, font sizes and colors */ const geometry_rectangle_t *diagram_draw_area; /*!< pointer to an external drawing rectangle containing inner contents of the diagram */ pencil_classifier_composer_t classifier_composer; /*!< own instance of a composer object to ask for display dimensions */ }; typedef struct pencil_classifier_1d_layouter_struct pencil_classifier_1d_layouter_t; /*! * \brief initializes the classifier layouter * * \param this_ pointer to own object attributes * \param layout_data pointer to the layout information to be used and modified * \param pencil_size pointer to the pencil_size_t object */ void pencil_classifier_1d_layouter_init( pencil_classifier_1d_layouter_t *this_, pencil_layout_data_t *layout_data, const pencil_size_t *pencil_size ); /*! * \brief destroys the layouter * * \param this_ pointer to own object attributes */ void pencil_classifier_1d_layouter_destroy( pencil_classifier_1d_layouter_t *this_ ); /*! * \brief defines classifier bounds for list diagrams * * \param this_ pointer to own object attributes * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context */ void pencil_classifier_1d_layouter_layout_for_list( pencil_classifier_1d_layouter_t *this_, PangoLayout *font_layout ); /*! * \brief defines classifier bounds for sequence diagrams * * \param this_ pointer to own object attributes * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context */ void pencil_classifier_1d_layouter_layout_for_sequence( pencil_classifier_1d_layouter_t *this_, PangoLayout *font_layout ); /*! * \brief defines classifier bounds for timing diagrams * * \param this_ pointer to own object attributes * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context */ void pencil_classifier_1d_layouter_layout_for_timing( pencil_classifier_1d_layouter_t *this_, PangoLayout *font_layout ); /*! * \brief positions the already composed classifiers as equally-spaced horizontal list to a target rectangle * * \param this_ pointer to own object attributes * \param classifier_list an array sorter object * \param dest_rect an array sorter object * \param v_alignment GEOMETRY_V_ALIGN_TOP, GEOMETRY_V_ALIGN_CENTER or GEOMETRY_V_ALIGN_BOTTOM */ void pencil_classifier_1d_layouter_private_layout_horizontal( const pencil_classifier_1d_layouter_t *this_, const universal_array_index_sorter_t *classifier_list, const geometry_rectangle_t *dest_rect, geometry_v_align_t v_alignment ); /*! * \brief positions the already composed classifiers as equally-spaced vertical list to a target rectangle * * \param this_ pointer to own object attributes * \param classifier_list an array sorter object * \param dest_rect an array sorter object * \param h_alignment GEOMETRY_H_ALIGN_LEFT, GEOMETRY_H_ALIGN_CENTER or GEOMETRY_H_ALIGN_RIGHT */ void pencil_classifier_1d_layouter_private_layout_vertical( const pencil_classifier_1d_layouter_t *this_, const universal_array_index_sorter_t *classifier_list, const geometry_rectangle_t *dest_rect, geometry_h_align_t h_alignment ); /*! * \brief positions the already composed classifiers linear to list_order horizontally to a target rectangle * * \param this_ pointer to own object attributes * \param classifier_list an array sorter object * \param dest_rect an array sorter object * \param v_alignment GEOMETRY_V_ALIGN_TOP, GEOMETRY_V_ALIGN_CENTER or GEOMETRY_V_ALIGN_BOTTOM */ void pencil_classifier_1d_layouter_private_linear_horizontal( const pencil_classifier_1d_layouter_t *this_, const universal_array_index_sorter_t *classifier_list, const geometry_rectangle_t *dest_rect, geometry_v_align_t v_alignment ); /*! * \brief positions the already composed classifiers as linear to list_order vertically to a target rectangle * * \param this_ pointer to own object attributes * \param classifier_list an array sorter object * \param dest_rect an array sorter object * \param h_alignment GEOMETRY_H_ALIGN_LEFT, GEOMETRY_H_ALIGN_CENTER or GEOMETRY_H_ALIGN_RIGHT */ void pencil_classifier_1d_layouter_private_linear_vertical( const pencil_classifier_1d_layouter_t *this_, const universal_array_index_sorter_t *classifier_list, const geometry_rectangle_t *dest_rect, geometry_h_align_t h_alignment ); #endif /* PENCIL_CLASSIFIER_1D_LAYOUTER_H */ /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_classifier_2d_layouter.h000066400000000000000000000344161415120503000261700ustar00rootroot00000000000000/* File: pencil_classifier_2d_layouter.h; Copyright and License: see below */ #ifndef PENCIL_CLASSIFIER_2D_LAYOUTER_H #define PENCIL_CLASSIFIER_2D_LAYOUTER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Calculates positions of classifiers and features in a 2-dimensional diagram */ #include "pencil_classifier_composer.h" #include "pencil_size.h" #include "pencil_layout_data.h" #include "pencil_feature_layouter.h" #include "util/geometry/geometry_rectangle.h" #include "util/geometry/geometry_dimensions.h" #include "util/geometry/geometry_non_linear_scale.h" #include "data_diagram.h" #include "set/data_small_set.h" #include "data_id.h" #include "set/data_visible_set.h" #include "universal_int32_pair.h" #include "universal_bool_list.h" #include "universal_array_index_sorter.h" #include #include /*! * \brief attributes of the classifier layouter */ struct pencil_classifier_2d_layouter_struct { pencil_layout_data_t *layout_data; /* pointer to external layout data */ const pencil_size_t *pencil_size; /*!< pointer to an external pencil_size_t object, */ /*!< defining pen sizes, gap sizes, font sizes and colors */ const geometry_rectangle_t *diagram_draw_area; /*!< pointer to an external drawing rectangle */ /*!< containing inner contents of the diagram */ geometry_non_linear_scale_t *x_scale; /*!< pointer to an external scale object for the x-axis */ geometry_non_linear_scale_t *y_scale; /*!< pointer to an external scale object for the y-axis */ geometry_dimensions_t *default_classifier_size; /*!< pointer to an external classifier default size rectangle */ pencil_classifier_composer_t classifier_composer; /*!< own instance of a composer object to ask for display dimensions */ pencil_feature_layouter_t *feature_layouter; /*!< pointer or an external helper to layout features */ }; typedef struct pencil_classifier_2d_layouter_struct pencil_classifier_2d_layouter_t; /*! * \brief initializes the classifier layouter * * \param this_ pointer to own object attributes * \param layout_data pointer to the layout information to be used and modified * \param pencil_size pointer to the pencil_size_t object * \param default_classifier_size pointer to the default size of a classifier * \param x_scale pointer to the scale object for the x-axis * \param y_scale pointer to the scale object for the y-axis * \param feature_layouter pointer to a feature layout helper */ void pencil_classifier_2d_layouter_init( pencil_classifier_2d_layouter_t *this_, pencil_layout_data_t *layout_data, const pencil_size_t *pencil_size, geometry_dimensions_t *default_classifier_size, geometry_non_linear_scale_t *x_scale, geometry_non_linear_scale_t *y_scale, pencil_feature_layouter_t *feature_layouter ); /*! * \brief destroys the layouter * * \param this_ pointer to own object attributes */ void pencil_classifier_2d_layouter_destroy( pencil_classifier_2d_layouter_t *this_ ); /* ================================ INITIAL LAYOUT ================================ */ /*! * \brief estimates classifier bounds for each classifier * * \param this_ pointer to own object attributes * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context */ void pencil_classifier_2d_layouter_estimate_bounds ( pencil_classifier_2d_layouter_t *this_, PangoLayout *font_layout ); /* ================================ MOVE TO AVOID OVERLAPS ================================ */ /*! * \brief move classifiers to avoid overlaps * * \param this_ pointer to own object attributes */ void pencil_classifier_2d_layouter_move_to_avoid_overlaps ( pencil_classifier_2d_layouter_t *this_ ); /*! * \brief determine order by which to move classifiers * * \param this_ pointer to own object attributes * \param out_sorted sorting order by which to move classifiers; must not be NULL, shall be initialized to empty. */ void pencil_classifier_2d_layouter_private_propose_move_processing_order ( pencil_classifier_2d_layouter_t *this_, universal_array_index_sorter_t *out_sorted ); /*! * \brief propose multiple solutions to move one classifier up/down/left/right * * \param this_ pointer to own object attributes * \param sorted sorting order by which to move classifiers; must not be NULL. * \param sort_index index of the current classifier for which to propose solutions * \param solutions_max maximum number (array size) of solutions to propose * \param out_solution_move_dx array of solutions: proposal to move in x direction * \param out_solution_move_dy array of solutions: proposal to move in y direction * \param out_solutions_count number of proposed solutions; 1 <= out_solutions_count < solutions_max */ void pencil_classifier_2d_layouter_private_propose_4dir_move_solutions ( pencil_classifier_2d_layouter_t *this_, const universal_array_index_sorter_t *sorted, uint32_t sort_index, uint32_t solutions_max, double out_solution_move_dx[], double out_solution_move_dy[], uint32_t *out_solutions_count ); /*! * \brief propose another solution to move one classifier based on another algorithm * * \param this_ pointer to own object attributes * \param sorted sorting order by which to move classifiers; must not be NULL. * \param sort_index index of the current classifier for which to propose solutions * \param out_solution_move_dx proposal to move in x direction * \param out_solution_move_dy proposal to move in y direction */ void pencil_classifier_2d_layouter_private_propose_anchored_solution ( pencil_classifier_2d_layouter_t *this_, const universal_array_index_sorter_t *sorted, uint32_t sort_index, double * out_solution_move_dx, double * out_solution_move_dy ); /*! * \brief selects one solution to move a classifier * * \param this_ pointer to own object attributes * \param sorted sorting order by which to move classifiers; must not be NULL. * \param sort_index index (in sorted classifiers) of the current classifier for which to select a solution * \param solutions_count number of proposed solutions; 1 <= out_solutions_count < solutions_max * \param solution_move_dx array of solutions: proposal to move in x direction * \param solution_move_dy array of solutions: proposal to move in y direction * \param out_index_of_best index (of solution) of the best solution; must not be NULL. */ void pencil_classifier_2d_layouter_private_select_move_solution ( pencil_classifier_2d_layouter_t *this_, const universal_array_index_sorter_t *sorted, uint32_t sort_index, uint32_t solutions_count, const double solution_move_dx[], const double solution_move_dy[], uint32_t *out_index_of_best ); /* ================================ EMBRACE CHILDREN STEP BY STEP ================================ */ /*! * \brief resize classifiers so that they embrace their children * * \param this_ pointer to own object attributes * \param font_layout pango layout object to determine the font metrics if re-layouting titles */ void pencil_classifier_2d_layouter_embrace_children( pencil_classifier_2d_layouter_t *this_, PangoLayout *font_layout ); /*! * \brief determine order by which to embrace classifiers * * \param this_ pointer to own object attributes * \param out_sorted sorting order of relationships by which to adapt classifiers; must not be NULL, shall be initialized to empty. */ void pencil_classifier_2d_layouter_private_propose_embracing_order ( pencil_classifier_2d_layouter_t *this_, universal_array_index_sorter_t *out_sorted ); /*! * \brief try to resize classifiers so that they embrace their children * * \param this_ pointer to own object attributes * \param the_relationship the relationship to process: the parent tries to embrace the child * \param move true if the containing parent classifier may move to the child, false if it shall expand only * \param font_layout pango layout object to determine the font metrics if re-layouting titles * \return 0 in case of success, -1 if embracing was not possible */ int pencil_classifier_2d_layouter_private_try_embrace_child ( pencil_classifier_2d_layouter_t *this_, layout_relationship_t *the_relationship, bool move, PangoLayout *font_layout ); /* ================================ EMBRACE CHILDREN COMMON ================================ */ /*! * \brief hides containment relationships if parents embrace their children * * \param this_ pointer to own object attributes */ void pencil_classifier_2d_layouter_hide_relations_of_embraced_children( pencil_classifier_2d_layouter_t *this_ ); /* ================================ EMBRACE AND MOVE CHILDREN TOGETHER ================================ */ /*! * \brief move and embrace child classifiers so that they have nice distances to neighbours and parent * * \param this_ pointer to own object attributes * \param font_layout pango layout object to determine the font metrics if re-layouting titles */ void pencil_classifier_2d_layouter_move_and_embrace_children( pencil_classifier_2d_layouter_t *this_, PangoLayout *font_layout ); /*! * \brief determine order by which to move and embrace child classifiers * * \param this_ pointer to own object attributes * \param out_sorted sorting order by which to grow classifiers; must not be NULL, shall be initialized to empty. */ void pencil_classifier_2d_layouter_private_propose_move_embrace_order ( pencil_classifier_2d_layouter_t *this_, universal_array_index_sorter_t *out_sorted ); /*! * \brief calculates the envelope hull of all descendants (excluding self). * * If there are not children, the envelope of ancestor_classifier is returned. * * \param this_ pointer to own object attributes * \param ancestor_classifier the classifier of whichs children to determine the envelope */ static inline geometry_rectangle_t pencil_classifier_2d_layouter_private_calc_descendant_envelope( pencil_classifier_2d_layouter_t *this_, const layout_visible_classifier_t *ancestor_classifier ); /*! * \brief calculates the outer space around a given rectangle ignoring descendants, ancesters and self. * * \param this_ pointer to own object attributes * \param start_rect rectangle for which to explore and determine the outer space * \param the_classifier the classifier of which descendants, ancesters and self shall be ignored */ static inline geometry_rectangle_t pencil_classifier_2d_layouter_private_calc_outer_space( pencil_classifier_2d_layouter_t *this_, const geometry_rectangle_t *start_rect, const layout_visible_classifier_t *the_classifier ); /*! * \brief moves all descendants of a classifier * * \param this_ pointer to own object attributes * \param ancestor_classifier the ancestor classifier * \param delta_x distance to move in x direction * \param delta_y distance to move in y direction */ static inline void pencil_classifier_2d_layouter_private_move_descendants( pencil_classifier_2d_layouter_t *this_, const layout_visible_classifier_t *ancestor_classifier, double delta_x, double delta_y ); #include "pencil_classifier_2d_layouter.inl" #endif /* PENCIL_CLASSIFIER_2D_LAYOUTER_H */ /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_classifier_2d_layouter.inl000066400000000000000000000156601415120503000265230ustar00rootroot00000000000000/* File: pencil_classifier_2d_layouter.inl; Copyright and License: see below */ #include "tslog.h" #include /* ================================ INITIAL LAYOUT ================================ */ /* ================================ MOVE TO AVOID OVERLAPS ================================ */ /* ================================ EMBRACE CHILDREN STEP BY STEP ================================ */ /* ================================ EMBRACE CHILDREN COMMON ================================ */ /* ================================ EMBRACE AND MOVE CHILDREN TOGETHER ================================ */ static inline geometry_rectangle_t pencil_classifier_2d_layouter_private_calc_descendant_envelope( pencil_classifier_2d_layouter_t *this_, const layout_visible_classifier_t *ancestor_classifier ) { assert( ancestor_classifier != NULL ); geometry_rectangle_t descendant_envelope; bool descendant_envelope_initialized = false; const uint32_t count_classifiers = pencil_layout_data_get_visible_classifier_count( (*this_).layout_data ); for ( uint32_t classifier_search_idx = 0; classifier_search_idx < count_classifiers; classifier_search_idx ++ ) { const layout_visible_classifier_t *const probe_classifier = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, classifier_search_idx ); if ( pencil_layout_data_is_ancestor( (*this_).layout_data, ancestor_classifier, probe_classifier ) ) { const geometry_rectangle_t probe_envelope = layout_visible_classifier_get_envelope_box( probe_classifier ); if ( ! descendant_envelope_initialized ) { geometry_rectangle_copy( &descendant_envelope, &probe_envelope ); descendant_envelope_initialized = true; } else { geometry_rectangle_init_by_bounds ( &descendant_envelope, &descendant_envelope, &probe_envelope ); } } } if ( ! descendant_envelope_initialized ) { descendant_envelope = layout_visible_classifier_get_envelope_box( ancestor_classifier ); } return descendant_envelope; } static inline geometry_rectangle_t pencil_classifier_2d_layouter_private_calc_outer_space( pencil_classifier_2d_layouter_t *this_, const geometry_rectangle_t *start_rect, const layout_visible_classifier_t *the_classifier ) { assert( start_rect != NULL ); assert( the_classifier != NULL ); /* fetch data on parent classifier */ const geometry_rectangle_t parent_envelope = layout_visible_classifier_get_envelope_box( the_classifier ); const geometry_rectangle_t *const parent_space = layout_visible_classifier_get_space_const( the_classifier ); const double parent_space_width_diff = geometry_rectangle_get_width(&parent_envelope) - geometry_rectangle_get_width(parent_space); const double parent_space_height_diff = geometry_rectangle_get_height(&parent_envelope) - geometry_rectangle_get_height(parent_space); /* determine outer space around start_rect rectangle */ geometry_rectangle_t outer_space; { geometry_rectangle_copy( &outer_space, start_rect ); const double children_envelope_w = geometry_rectangle_get_width(start_rect); const double children_envelope_h = geometry_rectangle_get_height(start_rect); geometry_rectangle_shift ( &outer_space, -0.5*children_envelope_w-parent_space_width_diff, -0.5*children_envelope_h-parent_space_height_diff ); geometry_rectangle_enlarge ( &outer_space, children_envelope_w+2.0*parent_space_width_diff, children_envelope_h+2.0*parent_space_height_diff ); geometry_rectangle_init_by_intersect( &outer_space, &outer_space, (*this_).diagram_draw_area ); const uint32_t count_classifiers = pencil_layout_data_get_visible_classifier_count ( (*this_).layout_data ); for ( uint32_t probe_index = 0; probe_index < count_classifiers; probe_index ++ ) { /* get classifier to check overlaps */ const layout_visible_classifier_t *const the_probe = pencil_layout_data_get_visible_classifier_const( (*this_).layout_data, probe_index ); const bool ignore = pencil_layout_data_is_ancestor ( (*this_).layout_data, the_classifier, the_probe ) || pencil_layout_data_is_ancestor ( (*this_).layout_data, the_probe, the_classifier ) /* ancestor may already encapsulate probe */ || ( layout_visible_classifier_is_equal_diagramelement_id( the_classifier, the_probe )); if ( ! ignore ) { const geometry_rectangle_t probe_envelope = layout_visible_classifier_get_envelope_box( the_probe ); geometry_rectangle_init_by_difference( &outer_space, &outer_space, &probe_envelope ); } } } return outer_space; } static inline void pencil_classifier_2d_layouter_private_move_descendants( pencil_classifier_2d_layouter_t *this_, const layout_visible_classifier_t *ancestor_classifier, double delta_x, double delta_y ) { assert( ancestor_classifier != NULL ); /* check all classifiers */ const uint32_t count_classifiers = pencil_layout_data_get_visible_classifier_count ( (*this_).layout_data ); for ( uint32_t index = 0; index < count_classifiers; index ++ ) { layout_visible_classifier_t *const probe_classifier = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, index ); const bool is_descendant = pencil_layout_data_is_ancestor ( (*this_).layout_data, ancestor_classifier, probe_classifier ); if ( is_descendant ) { layout_visible_classifier_shift ( probe_classifier, delta_x, delta_y ); } } } /* Copyright 2018-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_classifier_composer.h000066400000000000000000000233671415120503000255710ustar00rootroot00000000000000/* File: pencil_classifier_composer.h; Copyright and License: see below */ #ifndef PENCIL_CLASSIFIER_COMPOSER_H #define PENCIL_CLASSIFIER_COMPOSER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Renders a classifier by composing it of draw_graphics, draw_classifier_icon and draw_classifier_label commands */ #include "pencil_marker.h" #include "pencil_size.h" #include "pencil_feature_painter.h" #include "pencil_layout_data.h" #include "layout/layout_visible_classifier.h" #include "draw/draw_classifier_icon.h" #include "draw/draw_classifier_label.h" #include "draw/draw_classifier_contour.h" #include "util/geometry/geometry_rectangle.h" #include "util/geometry/geometry_dimensions.h" #include "util/geometry/geometry_h_align.h" #include "util/geometry/geometry_v_align.h" #include "data_diagram.h" #include "set/data_small_set.h" #include "data_id.h" #include "data_rules.h" #include "set/data_visible_set.h" #include #include /*! * \brief attributes of the classifier painter */ struct pencil_classifier_composer_struct { pencil_marker_t marker; /*!< own instance of a marker */ data_rules_t data_rules; /*!< own instance of data rules */ draw_classifier_icon_t draw_classifier_icon; /*!< collection of draw symbol/icon functions */ draw_classifier_label_t draw_classifier_label; /*!< collection of draw label functions */ draw_classifier_contour_t draw_classifier_contour; /*!< collection of draw contour functions */ }; typedef struct pencil_classifier_composer_struct pencil_classifier_composer_t; /*! * \brief initializes the painter * * \param this_ pointer to own object attributes */ void pencil_classifier_composer_init( pencil_classifier_composer_t *this_ ); /*! * \brief destroys the painter * * \param this_ pointer to own object attributes */ void pencil_classifier_composer_destroy( pencil_classifier_composer_t *this_ ); /*! * \brief draws the chosen classifier contents into the diagram_bounds area of the cairo drawing context * * \param this_ pointer to own object attributes * \param layouted_classifier pointer to the layout-information and data to be drawn * \param mark_focused true if the object is to be marked as "focused" * \param mark_highlighted true if the object is to be marked as "highlighted" * \param mark_selected true if the object is to be marked as "selected" * \param layout_data pointer to the diagrams layout-information needed to calculate the feature compartments * \param pencil_size set of sizes and colors for drawing lines and text * \param font_layout structure to layout fonts * \param cr a cairo drawing context */ void pencil_classifier_composer_draw ( const pencil_classifier_composer_t *this_, const layout_visible_classifier_t *layouted_classifier, data_id_t mark_focused, data_id_t mark_highlighted, const data_small_set_t *mark_selected, const pencil_layout_data_t *layout_data, const pencil_size_t *pencil_size, PangoLayout *font_layout, cairo_t *cr ); /*! * \brief recalculates symbol_box and label_box based on new space_and_label * * Precondition: the objects coordinates need to be valid already. This is just a partly recalculation. * * \param this_ pointer to own object attributes * \param space exact new space * \param shows_contained_children true if the classifier has contained children (needed for uml package because the symbol differs) * \param pencil_size set of sizes and colors for drawing lines and text * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context * \param io_classifier_layout classifier layout of which the box coordinates shall be modified. Must not be NULL. * \return 0 in case of success, 1 in case of additionally needed width by label text */ int pencil_classifier_composer_expand_space ( const pencil_classifier_composer_t *this_, const geometry_rectangle_t *space, bool shows_contained_children, const pencil_size_t *pencil_size, PangoLayout *font_layout, layout_visible_classifier_t *io_classifier_layout ); /*! * \brief resizes the contour, inner drawing space for contained classifiers and features - and the label_box * * This method returns values to embrace title and ornaments. classifiers symbol_box is expected to be fix. * * \param this_ pointer to own object attributes * \param envelope exact new outer envelope box; should be big enough to contain the classifier * \param shows_contained_children true if the classifier has contained children (needed for uml package because the symbol differs) * \param pencil_size set of sizes and colors for drawing lines and text * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context * \param io_classifier_layout input is symbol box, output is space and label_box. Must not be NULL. * \return 0 in case of success, 1 in case of additionally needed width or height */ int pencil_classifier_composer_set_envelope_box ( const pencil_classifier_composer_t *this_, const geometry_rectangle_t *envelope, bool shows_contained_children, const pencil_size_t *pencil_size, PangoLayout *font_layout, layout_visible_classifier_t *io_classifier_layout ); /*! * \brief determines the dimensions of the stereotype and name of the classifier. * * Internally, this method determines also the classifier type and icon-dimensions to calculate the label alignment. * * \param this_ pointer to own object attributes * \param visible_classifier the visible_classifier consisting of diagramelement and classifier to draw * \param shows_contained_children true if the classifier has contained children (needed for uml package because the symbol differs) * \param space_and_label proposed rectangle for the position, width and height of: label and icon and features and contained classifiers * \param icon_dim dimensions of the label * \param pencil_size set of sizes and colors for drawing lines and text * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context * \param out_label_box position and dimensions of the label box (smallest box containing stereotype and name) * \param out_label_compartment position and dimensions of label compartment (width as the inner_area if fitting, may contain an icon) * \return 0 in case of success, 1 in case of additionally needed width or height */ int pencil_classifier_composer_private_get_label_box ( const pencil_classifier_composer_t *this_, const data_visible_classifier_t *visible_classifier, bool shows_contained_children, const geometry_rectangle_t *space_and_label, const geometry_dimensions_t *icon_dim, const pencil_size_t *pencil_size, PangoLayout *font_layout, geometry_rectangle_t *out_label_box, geometry_rectangle_t *out_label_compartment ); /*! * \brief draws feature compartments of the given classifier into the classifier_space area * * \param this_ pointer to own object attributes * \param layouted_classifier pointer to the classifiers layout-information and data to be drawn * \param layout_data pointer to the diagrams layout-information needed to calculate the feature compartments * \param pencil_size set of sizes and colors for drawing lines and text * \param cr a cairo drawing context */ void pencil_classifier_composer_private_draw_feature_compartments ( const pencil_classifier_composer_t *this_, const layout_visible_classifier_t *layouted_classifier, const pencil_layout_data_t *layout_data, const pencil_size_t *pencil_size, cairo_t *cr ); #endif /* PENCIL_CLASSIFIER_COMPOSER_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_diagram_maker.h000066400000000000000000000317311415120503000243130ustar00rootroot00000000000000/* File: pencil_diagram_maker.h; Copyright and License: see below */ #ifndef PENCIL_DIAGRAM_MAKER_H #define PENCIL_DIAGRAM_MAKER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Layouts and paints a diagram with all its contents into a cairo drawing context */ #include "pencil_layouter.h" #include "pencil_marker.h" #include "pencil_diagram_painter.h" #include "pencil_classifier_composer.h" #include "pencil_relationship_painter.h" #include "pencil_size.h" #include "pencil_error.h" #include "option/pencil_type_filter.h" #include "layout/layout_order.h" #include "set/data_id_pair.h" #include "util/geometry/geometry_rectangle.h" #include "util/geometry/geometry_non_linear_scale.h" #include "data_diagram.h" #include "set/data_small_set.h" #include "set/data_stat.h" #include "data_id.h" #include "set/data_visible_set.h" #include "universal_int32_pair.h" #include "universal_bool_list.h" #include #include /*! * \brief attributes of the diagram painter */ struct pencil_diagram_maker_struct { const data_visible_set_t *input_data; /*!< pointer to an external data cache */ pencil_layouter_t layouter; /* own instance of a layouter */ pencil_diagram_painter_t diagram_painter; /*!< own instance of a diagram_painter */ pencil_classifier_composer_t classifier_painter; /*!< own instance of a classifier painter */ pencil_relationship_painter_t relationship_painter; /*!< own instance of a relationship_painter */ pencil_feature_painter_t feature_painter; /*!< own instance of a feature_painter */ }; typedef struct pencil_diagram_maker_struct pencil_diagram_maker_t; /*! * \brief initializes the painter * * \param this_ pointer to own object attributes * \param input_data pointer to the (cached) data to be drawn */ static inline void pencil_diagram_maker_init( pencil_diagram_maker_t *this_, const data_visible_set_t *input_data ); /*! * \brief re-initializes the painter * * \param this_ pointer to own object attributes * \param input_data pointer to the (cached) data to be drawn */ static inline void pencil_diagram_maker_reinit( pencil_diagram_maker_t *this_, const data_visible_set_t *input_data ); /*! * \brief destroys the painter * * \param this_ pointer to own object attributes */ static inline void pencil_diagram_maker_destroy( pencil_diagram_maker_t *this_ ); /*! * \brief defines coordinates * * Resets internal caches, changes in input_data are ok. * * \param this_ pointer to own object attributes * \param diagram_bounds the diagram_bounds rectangle where to draw the diagram */ static inline void pencil_diagram_maker_define_grid ( pencil_diagram_maker_t *this_, geometry_rectangle_t diagram_bounds ); /*! * \brief layouts the chosen diagram contents into the diagram_bounds area * * No reset of internal caches, no structural changes in input_data are allowed - only updates of attributes. * * \param this_ pointer to own object attributes * \param cr a cairo drawing context, used to determine the font metrics in the given drawing context * \param io_layout_stat pointer to already initialized statistics object where layouting statistics are added * or NULL if no statistics of interest */ static inline void pencil_diagram_maker_layout_elements ( pencil_diagram_maker_t *this_, cairo_t *cr, data_stat_t *io_layout_stat ); /*! * \brief draws the chosen diagram contents into the diagram_bounds area of the cairo drawing context * * \param this_ pointer to own object attributes * \param mark_focused id of the object that is to be marked as "focused" * \param mark_highlighted id of the object that is to be marked as "highlighted" * \param mark_selected set of objects that are to be marked as "selected" * \param cr a cairo drawing context */ void pencil_diagram_maker_draw ( pencil_diagram_maker_t *this_, data_id_t mark_focused, data_id_t mark_highlighted, const data_small_set_t *mark_selected, cairo_t *cr ); /*! * \brief draws the classifiers and contained features into the diagram_bounds area of the cairo drawing context * * \param this_ pointer to own object attributes * \param mark_focused id of the object that is to be marked as "focused" * \param mark_highlighted id of the object that is to be marked as "highlighted" * \param mark_selected set of objects that are to be marked as "selected" * \param layout structure to layout fonts * \param cr a cairo drawing context */ void pencil_diagram_maker_private_draw_classifiers ( pencil_diagram_maker_t *this_, data_id_t mark_focused, data_id_t mark_highlighted, const data_small_set_t *mark_selected, PangoLayout *layout, cairo_t *cr ); /*! * \brief draws the features of classifiers into the diagram_bounds area of the cairo drawing context * * \param this_ pointer to own object attributes * \param mark_focused id of the object that is to be marked as "focused" * \param mark_highlighted id of the object that is to be marked as "highlighted" * \param mark_selected set of objects that are to be marked as "selected" * \param layout structure to layout fonts * \param cr a cairo drawing context */ void pencil_diagram_maker_private_draw_features ( pencil_diagram_maker_t *this_, data_id_t mark_focused, data_id_t mark_highlighted, const data_small_set_t *mark_selected, PangoLayout *layout, cairo_t *cr ); /*! * \brief draws the relationships into the diagram_bounds area of the cairo drawing context * * \param this_ pointer to own object attributes * \param mark_focused id of the object that is to be marked as "focused" * \param mark_highlighted id of the object that is to be marked as "highlighted" * \param mark_selected set of objects that are to be marked as "selected" * \param layout structure to layout fonts * \param cr a cairo drawing context */ void pencil_diagram_maker_private_draw_relationships ( pencil_diagram_maker_t *this_, data_id_t mark_focused, data_id_t mark_highlighted, const data_small_set_t *mark_selected, PangoLayout *layout, cairo_t *cr ); /*! * \brief gets the object-id of the object at a given position * * \param this_ pointer to own object attributes * \param x x-position * \param y y-position * \param filter a filter for object types. E.g. PENCIL_TYPE_FILTER_LIFELINE will return the classifier instead of the lifeline-feature. * \param out_selected_id the object id at the given location. The id is invalid if there is no object at the given location. * \param out_surrounding_id the id of the embracing object at the given location. The id is invalid if there is no object at the given location. * \return PENCIL_ERROR_OUT_OF_BOUNDS if the given position x, y is not in the diagram. */ static inline pencil_error_t pencil_diagram_maker_get_object_id_at_pos ( const pencil_diagram_maker_t *this_, double x, double y, pencil_type_filter_t filter, data_id_pair_t* out_selected_id, data_id_pair_t* out_surrounding_id ); /*! * \brief determines if the given position is on a grid line * * \param this_ pointer to own object attributes * \param x x-position * \param y y-position * \param out_x_on_grid flag indicating if the given x position is on a grid line * \param out_y_on_grid flag indicating if the given y position is on a grid line */ static inline void pencil_diagram_maker_is_pos_on_grid ( const pencil_diagram_maker_t *this_, double x, double y, bool *out_x_on_grid, bool *out_y_on_grid ); /*! * \brief determines the grid lines * * \param this_ pointer to own object attributes * \param out_x0 x-position of leftmost grid line * \param out_y0 y-position of topmost grid line * \param out_dx width between grid lines * \param out_dy height between grid lines * \param out_x_count number of x-position grid lines * \param out_y_count number of y-position grid lines */ static inline void pencil_diagram_maker_get_grid_lines ( const pencil_diagram_maker_t *this_, double *out_x0, double *out_y0, double *out_dx, double *out_dy, uint32_t *out_x_count, uint32_t *out_y_count ); /*! * \brief gets the layout order at a given position * * \param this_ pointer to own object attributes * \param obj_id object for which to determine the layout order * \param x x-position * \param y y-position * \param out_layout_order order at given position * \return PENCIL_ERROR_OUT_OF_BOUNDS if the given position x, y is not in the diagram, * PENCIL_ERROR_UNKNOWN_OBJECT if the object is not in the diagram */ pencil_error_t pencil_diagram_maker_get_order_at_pos ( const pencil_diagram_maker_t *this_, data_id_t obj_id, double x, double y, layout_order_t* out_layout_order ); /*! * \brief gets the layout order at a given position for a feature * * Avoid using this function, prefer to use pencil_diagram_maker_get_order_at_pos() * unless the feature is new/fake and does not yet have an ID. * * \param this_ pointer to own object attributes * \param feature_ptr feature for which to determine the layout order; not NULL * \param x x-position * \param y y-position * \param out_layout_order order at given position * \return PENCIL_ERROR_OUT_OF_BOUNDS if the given position x, y is not in the diagram, * PENCIL_ERROR_UNKNOWN_OBJECT if the parent classifier is not in the diagram */ pencil_error_t pencil_diagram_maker_get_feature_order_at_pos ( const pencil_diagram_maker_t *this_, const data_feature_t *feature_ptr, double x, double y, layout_order_t* out_layout_order ); #include "pencil_diagram_maker.inl" #endif /* PENCIL_DIAGRAM_MAKER_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_diagram_maker.inl000066400000000000000000000130371415120503000246450ustar00rootroot00000000000000/* File: pencil_diagram_maker.inl; Copyright and License: see below */ #include "pencil_diagram_maker.h" #include "trace.h" #include static inline void pencil_diagram_maker_init( pencil_diagram_maker_t *this_, const data_visible_set_t *input_data ) { TRACE_BEGIN(); assert( NULL != input_data ); pencil_diagram_painter_init( &((*this_).diagram_painter) ); pencil_classifier_composer_init( &((*this_).classifier_painter) ); pencil_relationship_painter_init( &((*this_).relationship_painter) ); pencil_feature_painter_init( &((*this_).feature_painter) ); (*this_).input_data = input_data; pencil_layouter_init( &((*this_).layouter), input_data ); TRACE_END(); } static inline void pencil_diagram_maker_reinit( pencil_diagram_maker_t *this_, const data_visible_set_t *input_data ) { TRACE_BEGIN(); assert( NULL != input_data ); (*this_).input_data = input_data; pencil_layouter_reinit( &((*this_).layouter), input_data ); TRACE_END(); } static inline void pencil_diagram_maker_destroy( pencil_diagram_maker_t *this_ ) { TRACE_BEGIN(); pencil_diagram_painter_destroy( &((*this_).diagram_painter) ); pencil_classifier_composer_destroy( &((*this_).classifier_painter) ); pencil_relationship_painter_destroy( &((*this_).relationship_painter) ); pencil_feature_painter_destroy( &((*this_).feature_painter) ); pencil_layouter_destroy( &((*this_).layouter) ); (*this_).input_data = NULL; TRACE_END(); } static inline void pencil_diagram_maker_define_grid ( pencil_diagram_maker_t *this_, geometry_rectangle_t diagram_bounds ) { pencil_layouter_prepare ( &((*this_).layouter) ); pencil_layouter_define_grid ( &((*this_).layouter), diagram_bounds ); } static inline void pencil_diagram_maker_layout_elements ( pencil_diagram_maker_t *this_, cairo_t *cr, data_stat_t *io_layout_stat ) { assert( cr != NULL ); PangoLayout *font_layout; font_layout = pango_cairo_create_layout (cr); pencil_layouter_layout_elements ( &((*this_).layouter), font_layout, io_layout_stat ); g_object_unref (font_layout); } static inline pencil_error_t pencil_diagram_maker_get_object_id_at_pos ( const pencil_diagram_maker_t *this_, double x, double y, pencil_type_filter_t filter, data_id_pair_t* out_selected_id, data_id_pair_t* out_surrounding_id ) { return pencil_layouter_get_object_id_at_pos ( &((*this_).layouter), x, y, 3.0, filter, out_selected_id, out_surrounding_id ); } static const double snap_to_grid_distance_for_drag_marker = 3.13; /* smaller than snap_to_grid_distance_for_dropping */ /* to ensure object really snaps when marked so */ static inline void pencil_diagram_maker_is_pos_on_grid ( const pencil_diagram_maker_t *this_, double x, double y, bool *out_x_on_grid, bool *out_y_on_grid ) { pencil_layouter_is_pos_on_grid ( &((*this_).layouter), x, y, snap_to_grid_distance_for_drag_marker, out_x_on_grid, out_y_on_grid ); } static inline void pencil_diagram_maker_get_grid_lines ( const pencil_diagram_maker_t *this_, double *out_x0, double *out_y0, double *out_dx, double *out_dy, uint32_t *out_x_count, uint32_t *out_y_count ) { pencil_layouter_get_grid_lines( &((*this_).layouter), out_x0, out_y0, out_dx, out_dy, out_x_count, out_y_count ); } /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_diagram_painter.h000066400000000000000000000073441415120503000246610ustar00rootroot00000000000000/* File: pencil_diagram_painter.h; Copyright and License: see below */ #ifndef PENCIL_DIAGRAM_PAINTER_H #define PENCIL_DIAGRAM_PAINTER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Renders a diagram into a cairo drawing context */ #include "pencil_marker.h" #include "pencil_size.h" #include "layout/layout_diagram.h" #include "util/geometry/geometry_rectangle.h" #include "data_diagram.h" #include "set/data_small_set.h" #include "data_id.h" #include "set/data_visible_set.h" #include #include /*! * \brief attributes of the diagram painter */ struct pencil_diagram_painter_struct { pencil_marker_t marker; /*!< own instance of a marker */ }; typedef struct pencil_diagram_painter_struct pencil_diagram_painter_t; /*! * \brief initializes the painter * * \param this_ pointer to own object attributes */ void pencil_diagram_painter_init( pencil_diagram_painter_t *this_ ); /*! * \brief destroys the painter * * \param this_ pointer to own object attributes */ void pencil_diagram_painter_destroy( pencil_diagram_painter_t *this_ ); /*! * \brief draws the chosen classifier contents into the diagram_bounds area of the cairo drawing context * * \param this_ pointer to own object attributes * \param layouted_diagram pointer to the the layout-information and data to be drawn * \param mark_focused true if the object is to be marked as "focused" * \param mark_highlighted true if the object is to be marked as "highlighted" * \param mark_selected true if the object is to be marked as "selected" * \param pencil_size set of sizes and colors for drawing lines and text * \param font_layout structure to layout fonts * \param cr a cairo drawing context */ void pencil_diagram_painter_draw ( const pencil_diagram_painter_t *this_, const layout_diagram_t *layouted_diagram, bool mark_focused, bool mark_highlighted, bool mark_selected, const pencil_size_t *pencil_size, PangoLayout *font_layout, cairo_t *cr ); /*! * \brief determines the inner drawing space for contained classifiers * * \param this_ pointer to own object attributes * \param the_diagram pointer to the data to be drawn * \param pencil_size set of sizes and colors for drawing lines and text * \param diagram_bounds the destination rectangle where to draw the diagram * \param out_diagram_space memory location where the result shall be stored. Must not be NULL. */ void pencil_diagram_painter_get_drawing_space ( const pencil_diagram_painter_t *this_, const data_diagram_t *the_diagram, const pencil_size_t *pencil_size, const geometry_rectangle_t *diagram_bounds, geometry_rectangle_t *out_diagram_space ); #endif /* PENCIL_DIAGRAM_PAINTER_H */ /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_error.h000066400000000000000000000022761415120503000226630ustar00rootroot00000000000000/* File: pencil_error.h; Copyright and License: see below */ #ifndef PENCIL_ERROR_H #define PENCIL_ERROR_H /* public file for the doxygen documentation: */ /*! * \file * \brief Notifies errors in the pencil module */ /*! * \brief error constants which explain errors which occurred in the pencil module */ enum pencil_error_enum { PENCIL_ERROR_NONE = 0, /*!< 0: success */ PENCIL_ERROR_OUT_OF_BOUNDS = 1, /*!< 1: input parameters are out of bounds */ PENCIL_ERROR_UNKNOWN_OBJECT = 2, /*!< 2: referenced object is not in current diagram */ }; typedef enum pencil_error_enum pencil_error_t; #endif /* PENCIL_ERROR_H */ /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_feat_label_layouter.h000066400000000000000000000105461415120503000255330ustar00rootroot00000000000000/* File: pencil_feat_label_layouter.h; Copyright and License: see below */ #ifndef PENCIL_FEAT_LABEL_LAYOUTER_H #define PENCIL_FEAT_LABEL_LAYOUTER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Calculates the label positions of features in a diagram */ #include "pencil_size.h" #include "pencil_layout_data.h" #include "pencil_label_layout_helper.h" #include "draw/draw_feature_label.h" #include "util/geometry/geometry_rectangle.h" #include "data_diagram.h" #include "set/data_small_set.h" #include "set/data_visible_set.h" #include "data_id.h" #include "universal_array_index_sorter.h" #include #include /*! * \brief attributes of the feature-label layouter */ struct pencil_feat_label_layouter_struct { pencil_layout_data_t *layout_data; /* pointer to an instance of layout data */ pencil_size_t *pencil_size; /*!< pointer to an instance of a pencil_size_t object, defining pen sizes, gap sizes, font sizes and colors */ draw_feature_label_t draw_feature_label; /*!< collection of draw label functions */ pencil_label_layout_helper_t label_layout_helper; /*!< collection of layout label functions */ }; typedef struct pencil_feat_label_layouter_struct pencil_feat_label_layouter_t; /*! * \brief initializes the feature-label layouter * * \param this_ pointer to own object attributes * \param layout_data pointer to the layout information to be used and modified * \param pencil_size pointer to the pencil_size_t object */ void pencil_feat_label_layouter_init( pencil_feat_label_layouter_t *this_, pencil_layout_data_t *layout_data, pencil_size_t *pencil_size ); /*! * \brief destroys the feature-label layouter * * \param this_ pointer to own object attributes */ void pencil_feat_label_layouter_destroy( pencil_feat_label_layouter_t *this_ ); /*! * \brief determines the rectangels of the feature-label * * \param this_ pointer to own object attributes * \param font_layout structure to layout fonts */ void pencil_feat_label_layouter_do_layout ( pencil_feat_label_layouter_t *this_, PangoLayout *font_layout ); /*! * \brief determine order by which to layout the feature-labels * * Features that are not visible are ignored. Therefore out_sorted may contain fewer features than (*this_).layout_data. * * \param this_ pointer to own object attributes * \param out_sorted sorting order by which to layout feature-labels; must not be NULL, shall be initialized to empty. */ void pencil_feat_label_layouter_private_propose_processing_order ( pencil_feat_label_layouter_t *this_, universal_array_index_sorter_t *out_sorted ); /*! * \brief propose multiple solutions to layout one feature-label * * \param this_ pointer to own object attributes * \param current_feature feature for which to propose solutions * \param font_layout structure to layout fonts * \param solutions_max maximum number (array size) of solutions to propose * \param out_solutions array of solutions * \param out_solutions_count number of proposed solutions; 1 <= out_solutions_count < solutions_max */ void pencil_feat_label_layouter_private_propose_solutions ( pencil_feat_label_layouter_t *this_, layout_feature_t *current_feature, PangoLayout *font_layout, uint32_t solutions_max, geometry_rectangle_t out_solutions[], uint32_t *out_solutions_count ); #endif /* PENCIL_FEAT_LABEL_LAYOUTER_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_feature_layouter.h000066400000000000000000000173601415120503000251110ustar00rootroot00000000000000/* File: pencil_feature_layouter.h; Copyright and License: see below */ #ifndef PENCIL_FEATURE_LAYOUTER_H #define PENCIL_FEATURE_LAYOUTER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Calculates positions of features in a diagram */ #include "pencil_size.h" #include "pencil_layout_data.h" #include "pencil_feature_painter.h" #include "util/geometry/geometry_rectangle.h" #include "util/geometry/geometry_dimensions.h" #include "util/geometry/geometry_non_linear_scale.h" #include "data_diagram.h" #include "set/data_visible_set.h" #include "set/data_small_set.h" #include "data_id.h" #include "data_rules.h" #include "universal_int32_pair.h" #include "universal_bool_list.h" #include "universal_array_index_sorter.h" #include #include /*! * \brief attributes of the feature layouter */ struct pencil_feature_layouter_struct { pencil_layout_data_t *layout_data; /* pointer to external layout data */ pencil_size_t *pencil_size; /*!< pointer to an external pencil_size_t object, defining pen sizes, gap sizes, font sizes and colors */ data_rules_t rules; /*!< own instance of modelling rules */ pencil_feature_painter_t feature_painter; /*!< own instance of a painter object to ask for display dimensions */ }; typedef struct pencil_feature_layouter_struct pencil_feature_layouter_t; /*! * \brief initializes the feature layouter * * \param this_ pointer to own object attributes * \param layout_data pointer to the layout information to be used and modified * \param pencil_size pointer to the pencil_size_t object */ void pencil_feature_layouter_init( pencil_feature_layouter_t *this_, pencil_layout_data_t *layout_data, pencil_size_t *pencil_size ); /*! * \brief destroys the feature layouter * * \param this_ pointer to own object attributes */ void pencil_feature_layouter_destroy( pencil_feature_layouter_t *this_ ); /*! * \brief determines the bounding boxes of the features * * \param this_ pointer to own object attributes * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context */ void pencil_feature_layouter_do_layout ( pencil_feature_layouter_t *this_, PangoLayout *font_layout ); /*! * \brief calculates feature bounding dimensions of property and operation features for one diagramelement * * \param this_ pointer to own object attributes * \param diagramelement_id id of the diagramelement for which to calculate the feature bounds * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context * \param out_features_bounds memory location where the result shall be stored. Must not be NULL. */ void pencil_feature_layouter_calculate_features_bounds ( pencil_feature_layouter_t *this_, data_row_id_t diagramelement_id, PangoLayout *font_layout, geometry_dimensions_t *out_features_bounds ); /*! * \brief determines the symbol box of a lifeline * * \param this_ pointer to own object attributes * \param diagram_space drawing space of the diagram * \param diagram_type diagram type of the diagram * \param classifier_type type of the parent classifier * \param classifier_symbol_box symbol box of the classifier * \param out_feature_layout output parameter: feature layout coordinates */ void pencil_feature_layouter_private_layout_lifeline ( pencil_feature_layouter_t *this_, const geometry_rectangle_t *diagram_space, data_diagram_type_t diagram_type, data_classifier_type_t classifier_type, const geometry_rectangle_t *classifier_symbol_box, layout_feature_t *out_feature_layout ); /*! * \brief determines the symbol box of a port or action-pin or entry/exit state * * \param this_ pointer to own object attributes * \param classifier_type type of the parent classifier * \param classifier_symbol_box symbol box of the parent classifier * \param the_feature the feature data to be layouted * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context * \param out_feature_layout output parameter: feature layout coordinates */ void pencil_feature_layouter_private_layout_port_pin ( pencil_feature_layouter_t *this_, data_classifier_type_t classifier_type, const geometry_rectangle_t *classifier_symbol_box, const data_feature_t *the_feature, PangoLayout *font_layout, layout_feature_t *out_feature_layout ); /*! * \brief determines the symbol box of a provided or required interface * * \param this_ pointer to own object attributes * \param classifier_symbol_box symbol box of the classifier * \param the_feature the feature data to be layouted * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context * \param out_feature_layout output parameter: feature layout coordinates */ void pencil_feature_layouter_private_layout_interface ( pencil_feature_layouter_t *this_, const geometry_rectangle_t *classifier_symbol_box, const data_feature_t *the_feature, PangoLayout *font_layout, layout_feature_t *out_feature_layout ); /*! * \brief determines the symbol box of a property or operation * * \param this_ pointer to own object attributes * \param classifier_space space area in the classifier * \param the_feature the feature data to be layouted * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context * \param out_feature_layout output parameter: feature layout coordinates */ void pencil_feature_layouter_private_layout_prop_or_op ( pencil_feature_layouter_t *this_, const geometry_rectangle_t *classifier_space, const data_feature_t *the_feature, PangoLayout *font_layout, layout_feature_t *out_feature_layout ); #endif /* PENCIL_FEATURE_LAYOUTER_H */ /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_feature_painter.h000066400000000000000000000163541415120503000247110ustar00rootroot00000000000000/* File: pencil_feature_painter.h; Copyright and License: see below */ #ifndef PENCIL_FEATURE_PAINTER_H #define PENCIL_FEATURE_PAINTER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Renders a feature into a cairo drawing context */ #include "pencil_marker.h" #include "pencil_size.h" #include "layout/layout_feature.h" #include "draw/draw_feature_label.h" #include "util/geometry/geometry_rectangle.h" #include "util/geometry/geometry_dimensions.h" #include "data_diagram.h" #include "set/data_small_set.h" #include "data_id.h" #include "set/data_visible_set.h" #include #include /*! * \brief attributes of the feature painter */ struct pencil_feature_painter_struct { pencil_marker_t marker; /*!< own instance of a marker */ draw_feature_label_t draw_feature_label; /*!< collection of draw label functions */ }; typedef struct pencil_feature_painter_struct pencil_feature_painter_t; /*! * \brief initializes the painter * * \param this_ pointer to own object attributes */ void pencil_feature_painter_init( pencil_feature_painter_t *this_ ); /*! * \brief destroys the painter * * \param this_ pointer to own object attributes */ void pencil_feature_painter_destroy( pencil_feature_painter_t *this_ ); /*! * \brief draws the feature to the cairo drawing context * * \param this_ pointer to own object attributes * \param layouted_feature pointer to the layout-information and data to be drawn * \param mark_focused true if the object is to be marked as "focused" * \param mark_highlighted true if the object is to be marked as "highlighted" * \param mark_selected true if the object is to be marked as "selected" * \param gray_out true if the object is to be marked as grayed out. Is ignored in case mark_highlighted is true. * \param pencil_size set of sizes and colors for drawing lines and text * \param layout structure to layout fonts * \param cr a cairo drawing context */ void pencil_feature_painter_draw ( pencil_feature_painter_t *this_, const layout_feature_t *layouted_feature, bool mark_focused, bool mark_highlighted, bool mark_selected, bool gray_out, const pencil_size_t *pencil_size, PangoLayout *layout, cairo_t *cr ); /*! * \brief draws the icon of the lifeline feature * * \param this_ pointer to own object attributes * \param layouted_feature pointer to the layout-information and data to be drawn * \param marked true if mark_highlighted * \param pencil_size set of sizes and colors for drawing lines and text * \param cr a cairo drawing context */ void pencil_feature_painter_private_draw_lifeline_icon ( pencil_feature_painter_t *this_, const layout_feature_t *layouted_feature, bool marked, const pencil_size_t *pencil_size, cairo_t *cr ); /*! * \brief draws the icon of the pin/port feature * * \param this_ pointer to own object attributes * \param layouted_feature pointer to the layout-information and data to be drawn * \param pencil_size set of sizes and colors for drawing lines and text * \param foreground_color color to restore after having drawn the white background * \param cr a cairo drawing context */ void pencil_feature_painter_private_draw_port_pin_icon ( pencil_feature_painter_t *this_, const layout_feature_t *layouted_feature, const pencil_size_t *pencil_size, GdkRGBA foreground_color, cairo_t *cr ); /*! * \brief draws the icon of the entry/exit feature * * \param this_ pointer to own object attributes * \param layouted_feature pointer to the layout-information and data to be drawn * \param pencil_size set of sizes and colors for drawing lines and text * \param foreground_color color to restore after having drawn the white background * \param cr a cairo drawing context */ void pencil_feature_painter_private_draw_entry_exit_icon ( pencil_feature_painter_t *this_, const layout_feature_t *layouted_feature, const pencil_size_t *pencil_size, GdkRGBA foreground_color, cairo_t *cr ); /*! * \brief draws the icon of the interface feature * * \param this_ pointer to own object attributes * \param layouted_feature pointer to the layout-information and data to be drawn * \param pencil_size set of sizes and colors for drawing lines and text * \param cr a cairo drawing context */ void pencil_feature_painter_private_draw_interface_icon ( pencil_feature_painter_t *this_, const layout_feature_t *layouted_feature, const pencil_size_t *pencil_size, cairo_t *cr ); /*! * \brief determines the minumum feature bounds * * \param this_ pointer to own object attributes * \param the_feature pointer to the data to be layouted * \param pencil_size set of sizes and colors for drawing lines and text * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context * \param out_feature_bounds memory location where the result shall be stored. Must not be NULL. */ void pencil_feature_painter_get_minimum_bounds ( pencil_feature_painter_t *this_, const data_feature_t *the_feature, const pencil_size_t *pencil_size, PangoLayout *font_layout, geometry_dimensions_t *out_feature_bounds ); #endif /* PENCIL_FEATURE_PAINTER_H */ /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_label_layout_helper.h000066400000000000000000000053051415120503000255410ustar00rootroot00000000000000/* File: pencil_label_layout_helper.h; Copyright and License: see below */ #ifndef PENCIL_LABEL_LAYOUT_HELPER_H #define PENCIL_LABEL_LAYOUT_HELPER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Evaluates proposed label positions in a diagram */ #include "pencil_layout_data.h" #include "util/geometry/geometry_rectangle.h" #include "util/geometry/geometry_point.h" /* #include "util/geometry/geometry_anchor.h" */ /*! * \brief attributes of the label layout helper */ struct pencil_label_layout_helper_struct { int dummy; /*!< This object is a collection of stateless layouting helper functions */ }; typedef struct pencil_label_layout_helper_struct pencil_label_layout_helper_t; /*! * \brief initializes the label layout helper * * \param this_ pointer to own object attributes */ void pencil_label_layout_helper_init( pencil_label_layout_helper_t *this_ ); /*! * \brief destroys the label layout helper * * \param this_ pointer to own object attributes */ void pencil_label_layout_helper_destroy( pencil_label_layout_helper_t *this_ ); /*! * \brief selects one solution to layout a label rectangle * * \param this_ pointer to own object attributes * \param layout_data data that is already (partly) layouted - by which to select a solution * \param target_point point where the object is located to which the label belongs * \param solutions_count number of proposed solutions; at least 1 shall be provided * \param solutions array of solutions * \param out_index_of_best index of the best solution; must not be NULL. */ void pencil_label_layout_helper_select_solution ( pencil_label_layout_helper_t *this_, pencil_layout_data_t *layout_data, geometry_point_t target_point, uint32_t solutions_count, const geometry_rectangle_t solutions[], uint32_t *out_index_of_best ); #endif /* PENCIL_LABEL_LAYOUT_HELPER_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_layout_data.h000066400000000000000000000336111415120503000240350ustar00rootroot00000000000000/* File: pencil_layout_data.h; Copyright and License: see below */ #ifndef PENCIL_LAYOUT_DATA_H #define PENCIL_LAYOUT_DATA_H /* public file for the doxygen documentation: */ /*! * \file * \brief Stores the layout data for input data. */ #include "util/geometry/geometry_connector.h" #include "util/geometry/geometry_rectangle.h" #include "layout/layout_diagram.h" #include "layout/layout_feature.h" #include "layout/layout_relationship.h" #include "layout/layout_visible_classifier.h" #include "option/pencil_visibility.h" #include "set/data_visible_set.h" #include "set/data_stat.h" #include "data_rules.h" #include #include #include #ifndef NDEBUG /* make the layout visible for debugging: */ /* define PENCIL_LAYOUT_DATA_DRAW_FOR_DEBUG */ #endif /*! * \brief constants for maximum values of pencil_layout_data_t * * While the data_visible_set_t contains features and relationships just once, * pencil_layout_data_t contains these once per instance of every visible_classifier_t. */ enum pencil_layout_data_max_enum { PENCIL_LAYOUT_DATA_MAX_CLASSIFIERS = DATA_VISIBLE_SET_MAX_CLASSIFIERS, /*!< maximum number of classifiers to be shown in one single diagram */ PENCIL_LAYOUT_DATA_MAX_FEATURES = DATA_VISIBLE_SET_MAX_FEATURES + 32, /*!< maximum number of features to be shown in one single diagram */ PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS = DATA_VISIBLE_SET_MAX_RELATIONSHIPS * 2, /*!< maximum number of relationships to be shown in one single diagram */ }; /*! * \brief attributes of the pencil_layout_data_t * * pencil_layout_data_t contains a consistent subset of the database model: * If a feature is contained, its classifier is contained. * If a relationship is contained, the classifiers of both ends are contained. * * In case the data exceeds the limits of the member arrays, some data cannot be shown. * There is no guarantee for completeness. */ struct pencil_layout_data_struct { /* diagram layout*/ layout_diagram_t diagram_layout; /*!< layout data of the diagram */ bool diagram_valid; /*!< true if diagram_layout is initialized */ /* classifier layout*/ layout_visible_classifier_t visible_classifier_layout[PENCIL_LAYOUT_DATA_MAX_CLASSIFIERS]; /*!< layout data of visible classifiers */ uint32_t visible_classifier_count; /*!< number of all layouted visible classifier records */ /* feature layout */ layout_feature_t feature_layout[PENCIL_LAYOUT_DATA_MAX_FEATURES]; /*!< layout data of features */ uint32_t feature_count; /*!< number of all layouted feature records */ /* relationship layout */ layout_relationship_t relationship_layout[PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS]; /*!< layout data of relationships */ uint32_t relationship_count; /*!< number of all layouted relationship records */ /* input data */ const data_visible_set_t *input_data; /*!< the input data which is base for the layout data */ data_rules_t filter_rules; /*!< own instance of uml and sysml consistency rules */ }; typedef struct pencil_layout_data_struct pencil_layout_data_t; /*! * \brief initializes the painter input data layout * * \param this_ pointer to own object attributes * \param input_data pointer to the (cached) data to be layouted */ void pencil_layout_data_init( pencil_layout_data_t *this_, const data_visible_set_t *input_data ); /*! * \brief re-initializes the painter input data layout * * reinit shall be called when the input_data set has changed * to ensure that the layout data reflects the input data * * \param this_ pointer to own object attributes * \param input_data pointer to the (cached) data to be layouted */ static inline void pencil_layout_data_reinit( pencil_layout_data_t *this_, const data_visible_set_t *input_data ); /*! * \brief destroys the painter input data layout * * \param this_ pointer to own object attributes */ void pencil_layout_data_destroy( pencil_layout_data_t *this_ ); /*! * \brief re-initializes the painter input data layout * * resync shall be called when any element in the input_data set has changed * (but not the set itself) * to ensure that the layout data reflects the input data * * \param this_ pointer to own object attributes */ static inline void pencil_layout_data_resync( pencil_layout_data_t *this_ ); /* ================================ diagram ================================ */ /*! * \brief gets the layouted diagram * * \param this_ pointer to own object attributes * \return pointer to layout_diagram_t. */ static inline layout_diagram_t *pencil_layout_data_get_diagram_ptr ( pencil_layout_data_t *this_ ); /*! * \brief gets the layouted diagram * * \param this_ pointer to own object attributes * \return pointer to layout_diagram_t. */ static inline const layout_diagram_t *pencil_layout_data_get_diagram_const ( const pencil_layout_data_t *this_ ); /* ================================ classifiers ================================ */ /*! * \brief gets the number of visible classifiers within the painter layout data * * \param this_ pointer to own object attributes */ static inline uint32_t pencil_layout_data_get_visible_classifier_count ( const pencil_layout_data_t *this_ ); /*! * \brief gets the layouted visible_classifier * * \param this_ pointer to own object attributes * \param index index of the layouted classifier to retrieve; 0 <= index < PENCIL_LAYOUT_DATA_MAX_CLASSIFIERS. * \return pointer to layout_visible_classifier_t. */ static inline layout_visible_classifier_t *pencil_layout_data_get_visible_classifier_ptr ( pencil_layout_data_t *this_, uint32_t index ); /*! * \brief gets the layouted visible_classifier * * \param this_ pointer to own object attributes * \param index index of the layouted classifier to retrieve; 0 <= index < PENCIL_LAYOUT_DATA_MAX_CLASSIFIERS. * \return pointer to layout_visible_classifier_t. */ static inline const layout_visible_classifier_t *pencil_layout_data_get_visible_classifier_const ( const pencil_layout_data_t *this_, uint32_t index ); /* ================================ features ================================ */ /*! * \brief gets the number of features within the painter layout data * * \param this_ pointer to own object attributes */ static inline uint32_t pencil_layout_data_get_feature_count ( const pencil_layout_data_t *this_ ); /*! * \brief gets the layouted feature * * \param this_ pointer to own object attributes * \param index index of the layouted feature to retrieve; 0 <= index < PENCIL_LAYOUT_DATA_MAX_FEATURES. * \return pointer to layout_feature_t. */ static inline layout_feature_t *pencil_layout_data_get_feature_ptr ( pencil_layout_data_t *this_, uint32_t index ); /*! * \brief gets the layouted feature * * \param this_ pointer to own object attributes * \param index index of the layouted feature to retrieve; 0 <= index < PENCIL_LAYOUT_DATA_MAX_FEATURES. * \return pointer to layout_feature_t. */ static inline const layout_feature_t *pencil_layout_data_get_feature_const ( const pencil_layout_data_t *this_, uint32_t index ); /* ================================ relationships ================================ */ /*! * \brief gets the visibility of a relationship * * \param this_ pointer to own object attributes * \param index index of the relationship visibility to retrieve; 0 <= index < PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS. * \return true if visible. */ static inline pencil_visibility_t pencil_layout_data_get_relationship_visibility ( const pencil_layout_data_t *this_, uint32_t index ); /*! * \brief sets the visibility of a relationship * * \param this_ pointer to own object attributes * \param index index of the relationship visibility to set; 0 <= index < PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS. * \param visible true if visible. */ static inline void pencil_layout_data_set_relationship_visibility ( pencil_layout_data_t *this_, uint32_t index, pencil_visibility_t visible ); /*! * \brief gets the number of relationships within the painter layout data * * \param this_ pointer to own object attributes */ static inline uint32_t pencil_layout_data_get_relationship_count ( const pencil_layout_data_t *this_ ); /*! * \brief gets the layouted relationship * * \param this_ pointer to own object attributes * \param index index of the layouted relationship to retrieve; 0 <= index < PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS. * \return pointer to layout_relationship_t. */ static inline layout_relationship_t *pencil_layout_data_get_relationship_ptr ( pencil_layout_data_t *this_, uint32_t index ); /*! * \brief gets the layouted relationship * * \param this_ pointer to own object attributes * \param index index of the layouted relationship to retrieve; 0 <= index < PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS. * \return pointer to layout_relationship_t. */ static inline const layout_relationship_t *pencil_layout_data_get_relationship_const ( const pencil_layout_data_t *this_, uint32_t index ); /*! * \brief determines if ancestor is an ancestor of descendant * * \param this_ pointer to own object attributes * \param ancestor the ancestor classifier * \param descendant the descendant classifier * \return true if there is a DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT relationship from ancestor to descendant within the data_visible_set object */ static inline bool pencil_layout_data_is_ancestor ( const pencil_layout_data_t *this_, const layout_visible_classifier_t *ancestor, const layout_visible_classifier_t *descendant ); /*! * \brief counts the number of ancestors of a classifier * * \param this_ pointer to own object attributes * \param classifier the classifier of which to count ancestors * \return number of ancestors of classifier which are listed in this_. */ static inline uint32_t pencil_layout_data_count_ancestors ( const pencil_layout_data_t *this_, const layout_visible_classifier_t *classifier ); /*! * \brief counts the number of descendants of a classifier * * \param this_ pointer to own object attributes * \param classifier the classifier of which to count decendants * \return number of descendants of classifier which are listed in this_. */ static inline uint32_t pencil_layout_data_count_descendants ( const pencil_layout_data_t *this_, const layout_visible_classifier_t *classifier ); /* ================================ misc ================================ */ /*! * \brief checks if the pencil_layout_data is initialized and consistent * * \param this_ pointer to own object attributes * \return true if this_ contains valid data for sketching a diagram */ bool pencil_layout_data_is_valid ( const pencil_layout_data_t *this_ ); /*! * \brief gets statistics on pencil_layout_data. * * This encompasses number of objects, number of overlaps (warnings), number of objects outside diagram (errors). * * \param this_ pointer to own object attributes * \param io_layout_stat pointer to already initialized statistics object where layouting statistics are added */ void pencil_layout_data_get_statistics ( const pencil_layout_data_t *this_, data_stat_t *io_layout_stat ); /*! * \brief initializes the diagram_layout member * * \param this_ pointer to own object attributes, input_data shall be already initialized */ void pencil_layout_data_private_init_diagram( pencil_layout_data_t *this_ ); /*! * \brief initializes the visible_classifier_layout array * * \param this_ pointer to own object attributes, input_data shall be already initialized */ void pencil_layout_data_private_init_classifiers( pencil_layout_data_t *this_ ); /*! * \brief initializes the feature_layout array * * \param this_ pointer to own object attributes, input_data and visible_classifier_layout shall be already initialized */ void pencil_layout_data_private_init_features( pencil_layout_data_t *this_ ); /*! * \brief initializes the relationship_layout array * * \param this_ pointer to own object attributes, input_data and visible_classifier_layout and feature_layout shall be already initialized */ void pencil_layout_data_private_init_relationships( pencil_layout_data_t *this_ ); /*! * \brief initializes all layout relationships for one data relationship * * \param this_ pointer to own object attributes, input_data and visible_classifier_layout and feature_layout shall be already initialized * \param relationship_data pointer into the data set structure (*this_).input_data, pointing to the data relationship struct * \param io_dropped_relationships io parameter, counter that is increased for every non-instantiated layout relationship * \return number of created layout relationships */ uint32_t pencil_layout_data_private_init_relationship( pencil_layout_data_t *this_, const data_relationship_t *relationship_data, uint32_t *io_dropped_relationships ); #include "pencil_layout_data.inl" #endif /* PENCIL_LAYOUT_DATA_H */ /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_layout_data.inl000066400000000000000000000161541415120503000243730ustar00rootroot00000000000000/* File: pencil_layout_data.inl; Copyright and License: see below */ #include "tslog.h" #include static inline void pencil_layout_data_reinit( pencil_layout_data_t *this_, const data_visible_set_t *input_data ) { pencil_layout_data_destroy( this_ ); pencil_layout_data_init( this_, input_data ); } static inline void pencil_layout_data_resync( pencil_layout_data_t *this_ ) { pencil_layout_data_reinit( this_, (*this_).input_data ); } /* ================================ diagram ================================ */ static inline layout_diagram_t *pencil_layout_data_get_diagram_ptr ( pencil_layout_data_t *this_ ) { /*assert ( (*this_).diagram_valid );*/ /* we return the pointer even if diagram_layout is not yet initialized */ return &((*this_).diagram_layout); } static inline const layout_diagram_t *pencil_layout_data_get_diagram_const ( const pencil_layout_data_t *this_ ) { /*assert ( (*this_).diagram_valid );*/ /* we return the pointer even if diagram_layout is not yet initialized */ return &((*this_).diagram_layout); } /* ================================ classifiers ================================ */ static inline uint32_t pencil_layout_data_get_visible_classifier_count ( const pencil_layout_data_t *this_ ) { assert ( (*this_).visible_classifier_count <= PENCIL_LAYOUT_DATA_MAX_CLASSIFIERS ); return (*this_).visible_classifier_count; } static inline layout_visible_classifier_t *pencil_layout_data_get_visible_classifier_ptr ( pencil_layout_data_t *this_, uint32_t index ) { assert( index < (*this_).visible_classifier_count ); assert ( (*this_).visible_classifier_count <= PENCIL_LAYOUT_DATA_MAX_CLASSIFIERS ); return &((*this_).visible_classifier_layout[index]); } static inline const layout_visible_classifier_t *pencil_layout_data_get_visible_classifier_const ( const pencil_layout_data_t *this_, uint32_t index ) { assert( index < (*this_).visible_classifier_count ); assert ( (*this_).visible_classifier_count <= PENCIL_LAYOUT_DATA_MAX_CLASSIFIERS ); return &((*this_).visible_classifier_layout[index]); } /* ================================ features ================================ */ static inline uint32_t pencil_layout_data_get_feature_count ( const pencil_layout_data_t *this_ ) { assert( (*this_).feature_count <= PENCIL_LAYOUT_DATA_MAX_FEATURES ); return (*this_).feature_count; } static inline layout_feature_t *pencil_layout_data_get_feature_ptr ( pencil_layout_data_t *this_, uint32_t index ) { assert( index < (*this_).feature_count ); assert( (*this_).feature_count <= PENCIL_LAYOUT_DATA_MAX_FEATURES ); return &((*this_).feature_layout[index]); } static inline const layout_feature_t *pencil_layout_data_get_feature_const ( const pencil_layout_data_t *this_, uint32_t index ) { assert( index < (*this_).feature_count ); assert( (*this_).feature_count <= PENCIL_LAYOUT_DATA_MAX_FEATURES ); return &((*this_).feature_layout[index]); } /* ================================ relationships ================================ */ static inline pencil_visibility_t pencil_layout_data_get_relationship_visibility ( const pencil_layout_data_t *this_, uint32_t index ) { assert( index < (*this_).relationship_count ); assert( (*this_).relationship_count <= PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS ); return layout_relationship_get_visibility ( &((*this_).relationship_layout[index]) ); } static inline void pencil_layout_data_set_relationship_visibility ( pencil_layout_data_t *this_, uint32_t index, pencil_visibility_t visible ) { assert( index < (*this_).relationship_count ); assert( (*this_).relationship_count <= PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS ); layout_relationship_set_visibility ( &((*this_).relationship_layout[index]), visible ); } static inline uint32_t pencil_layout_data_get_relationship_count ( const pencil_layout_data_t *this_ ) { assert( (*this_).relationship_count <= PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS ); return (*this_).relationship_count; } static inline layout_relationship_t *pencil_layout_data_get_relationship_ptr ( pencil_layout_data_t *this_, uint32_t index ) { assert( index < (*this_).relationship_count ); assert( (*this_).relationship_count <= PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS ); return &((*this_).relationship_layout[index]); } static inline const layout_relationship_t *pencil_layout_data_get_relationship_const ( const pencil_layout_data_t *this_, uint32_t index ) { assert( index < (*this_).relationship_count ); assert( (*this_).relationship_count <= PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS ); return &((*this_).relationship_layout[index]); } static inline bool pencil_layout_data_is_ancestor ( const pencil_layout_data_t *this_, const layout_visible_classifier_t *ancestor, const layout_visible_classifier_t *descendant ) { assert ( NULL != ancestor ); assert ( NULL != descendant ); /* get index */ uint32_t ancestor_index; uint32_t descendant_index; ancestor_index = data_visible_set_get_classifier_index_from_pointer ( (*this_).input_data, layout_visible_classifier_get_data_const(ancestor) ); descendant_index = data_visible_set_get_classifier_index_from_pointer ( (*this_).input_data, layout_visible_classifier_get_data_const(descendant) ); /* ask input_data */ return data_visible_set_is_ancestor_by_index ( (*this_).input_data, ancestor_index, descendant_index ); } static inline uint32_t pencil_layout_data_count_ancestors ( const pencil_layout_data_t *this_, const layout_visible_classifier_t *classifier ) { assert ( NULL != classifier ); /* get index */ uint32_t classifier_index; classifier_index = data_visible_set_get_classifier_index_from_pointer ( (*this_).input_data, layout_visible_classifier_get_data_const(classifier) ); /* ask input_data */ return data_visible_set_count_ancestors_of_index ( (*this_).input_data, classifier_index ); } static inline uint32_t pencil_layout_data_count_descendants ( const pencil_layout_data_t *this_, const layout_visible_classifier_t *classifier ) { assert ( NULL != classifier ); /* get index */ uint32_t classifier_index; classifier_index = data_visible_set_get_classifier_index_from_pointer ( (*this_).input_data, layout_visible_classifier_get_data_const(classifier) ); /* ask input_data */ return data_visible_set_count_descendants_of_index ( (*this_).input_data, classifier_index ); } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_layouter.h000066400000000000000000000363431415120503000234000ustar00rootroot00000000000000/* File: pencil_layouter.h; Copyright and License: see below */ #ifndef PENCIL_LAYOUTER_H #define PENCIL_LAYOUTER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Calculates positions of classifiers, features and relationships in a diagram */ #include "pencil_marker.h" #include "pencil_classifier_composer.h" #include "pencil_size.h" #include "pencil_layout_data.h" #include "pencil_diagram_painter.h" #include "pencil_feature_painter.h" #include "pencil_feature_layouter.h" #include "pencil_feat_label_layouter.h" #include "pencil_relationship_layouter.h" #include "pencil_rel_label_layouter.h" #include "pencil_classifier_2d_layouter.h" #include "pencil_classifier_1d_layouter.h" #include "pencil_error.h" #include "option/pencil_type_filter.h" #include "layout/layout_order.h" #include "set/data_id_pair.h" #include "util/geometry/geometry_rectangle.h" #include "util/geometry/geometry_dimensions.h" #include "util/geometry/geometry_non_linear_scale.h" #include "data_diagram.h" #include "set/data_small_set.h" #include "set/data_stat.h" #include "data_id.h" #include "data_rules.h" #include "set/data_visible_set.h" #include "universal_int32_pair.h" #include "universal_bool_list.h" #include "universal_array_index_sorter.h" #include #include /*! * \brief attributes of the layouter */ struct pencil_layouter_struct { pencil_layout_data_t layout_data; /* own instance of layout data */ pencil_size_t pencil_size; /*!< own instance of a pencil_size_t object, defining pen sizes, gap sizes, font sizes and colors */ geometry_non_linear_scale_t x_scale; /*!< own instance of a scale object for the x-axis */ geometry_non_linear_scale_t y_scale; /*!< own instance of a scale object for the y-axis */ geometry_dimensions_t default_classifier_size; /*!< own instance of a classifier default size */ data_rules_t rules; /*!< own instance of modelling rules */ pencil_diagram_painter_t diagram_painter; /*!< own instance of a painter object to ask for display dimensions */ pencil_classifier_2d_layouter_t pencil_classifier_2d_layouter; /*!< own instance of a helper object to layout classifiers */ pencil_classifier_1d_layouter_t pencil_classifier_1d_layouter; /*!< own instance of a helper object to layout classifiers */ pencil_feature_layouter_t feature_layouter; /*!< own instance of a helper object to layout features */ pencil_feat_label_layouter_t feature_label_layouter; /*!< own instance of a helper object to layout feature labels */ pencil_relationship_layouter_t pencil_relationship_layouter; /*!< own instance of a helper object to layout relationships */ pencil_rel_label_layouter_t relationship_label_layouter; /*!< own instance of a helper object to layout relationship labels */ }; typedef struct pencil_layouter_struct pencil_layouter_t; /*! * \brief initializes the layouter * * \param this_ pointer to own object attributes * \param input_data pointer to the (cached) data to be layouted */ void pencil_layouter_init( pencil_layouter_t *this_, const data_visible_set_t *input_data ); /*! * \brief re-initializes the layouter to layout new/other input_data * * \param this_ pointer to own object attributes * \param input_data pointer to the data to be layouted */ void pencil_layouter_reinit( pencil_layouter_t *this_, const data_visible_set_t *input_data ); /*! * \brief destroys the layouter * * \param this_ pointer to own object attributes */ void pencil_layouter_destroy( pencil_layouter_t *this_ ); /*! * \brief resets previous layout data, synchronizes the internal layout data with the *input_data * * \param this_ pointer to own object attributes */ static inline void pencil_layouter_prepare ( pencil_layouter_t *this_ ); /*! * \brief defines the grid coordinates * * \param this_ pointer to own object attributes * \param diagram_bounds the diagram_bounds rectangle where to draw the diagram */ void pencil_layouter_define_grid ( pencil_layouter_t *this_, geometry_rectangle_t diagram_bounds ); /*! * \brief layouts the chosen diagram contents into the diagram_bounds area * * \param this_ pointer to own object attributes * \param font_layout pango layout object to determine the font metrics in the current cairo drawing context * \param io_layout_stat pointer to already initialized statistics object where layouting statistics are added * or NULL if no statistics of interest */ void pencil_layouter_layout_elements ( pencil_layouter_t *this_, PangoLayout *font_layout, data_stat_t *io_layout_stat ); /* ! * \brief returns the pencil_layout_data_t object * * \param this_ pointer to own object attributes */ static inline pencil_layout_data_t *pencil_layouter_get_layout_data_ptr ( pencil_layouter_t *this_ ); /*! * \brief returns the pencil_layout_data_t object * * \param this_ pointer to own object attributes */ static inline const pencil_layout_data_t *pencil_layouter_get_layout_data_const ( const pencil_layouter_t *this_ ); /*! * \brief returns the pencil size object * * \param this_ pointer to own object attributes */ static inline pencil_size_t *pencil_layouter_get_pencil_size_ptr ( pencil_layouter_t *this_ ); /*! * \brief gets the object-id of the object at a given position * * \param this_ pointer to own object attributes * \param x x-position * \param y y-position * \param filter a filter for object types. E.g. PENCIL_TYPE_FILTER_LIFELINE will return the classifier instead of the lifeline-feature. * \param snap_distance maximum distance to the next connector line when to select the connector * \param out_selected_id the object id at the given location. The id is invalid if there is no object at the given location. * \param out_surrounding_id the id of the embracing object at the given location. The id is invalid if there is no object at the given location. * \return PENCIL_ERROR_OUT_OF_BOUNDS if the given position x, y is not in the diagram. */ pencil_error_t pencil_layouter_get_object_id_at_pos ( const pencil_layouter_t *this_, double x, double y, double snap_distance, pencil_type_filter_t filter, data_id_pair_t* out_selected_id, data_id_pair_t* out_surrounding_id ); /*! * \brief gets the classifier-id of the classifier at a given position * * \param this_ pointer to own object attributes * \param x x-position * \param y y-position * \param out_selected_id the object id at the given location. The id is invalid if there is no object at the given location. * \param out_surrounding_id the id of the embracing object at the given location. The id is invalid if there is no object at the given location. * \return PENCIL_ERROR_OUT_OF_BOUNDS if no classifier is at the given position x, y. */ pencil_error_t pencil_layouter_private_get_classifier_id_at_pos ( const pencil_layouter_t *this_, double x, double y, data_id_pair_t* out_selected_id, data_id_pair_t* out_surrounding_id ); /*! * \brief gets the feature-id of the feature at a given position * * \param this_ pointer to own object attributes * \param x x-position * \param y y-position * \param filter a filter for object types. E.g. PENCIL_TYPE_FILTER_LIFELINE will return the classifier instead of the lifeline-feature. * \param out_selected_id the object id at the given location. The id is invalid if there is no object at the given location. * \param out_surrounding_id the id of the embracing object at the given location. The id is invalid if there is no object at the given location. * \return PENCIL_ERROR_OUT_OF_BOUNDS if no feature is at the given position x, y. */ pencil_error_t pencil_layouter_private_get_feature_id_at_pos ( const pencil_layouter_t *this_, double x, double y, pencil_type_filter_t filter, data_id_pair_t* out_selected_id, data_id_pair_t* out_surrounding_id ); /*! * \brief gets the relationship-id of the relationship at a given position * * \param this_ pointer to own object attributes * \param x x-position * \param y y-position * \param snap_distance maximum distance to the next connector line when to select the connector * \param out_selected_id the object id at the given location. The id is invalid if there is no object at the given location. * \return PENCIL_ERROR_OUT_OF_BOUNDS if no relationship is at the given position x, y. */ pencil_error_t pencil_layouter_private_get_relationship_id_at_pos ( const pencil_layouter_t *this_, double x, double y, double snap_distance, data_id_pair_t* out_selected_id ); /*! * \brief gets the layout order for a classifier at a given position * * \param this_ pointer to own object attributes * * \param c_type classifier type for which to determine the order * \param x x-position * \param y y-position * \param snap_distance maximum distance to the next grid line when to snap to a grid position * \param out_layout_order order at given position * \return PENCIL_ERROR_OUT_OF_BOUNDS if the given position x, y is not in the diagram */ pencil_error_t pencil_layouter_get_classifier_order_at_pos ( const pencil_layouter_t *this_, data_classifier_type_t c_type, double x, double y, double snap_distance, layout_order_t* out_layout_order ); /*! * \brief gets the layout order for a feature at a given position (relative to a classifier) * * \param this_ pointer to own object attributes * \param feature_ptr pointer to the feature for which to determine the order at x/y * \param x x-position * \param y y-position * \param out_layout_order order at given position * \return PENCIL_ERROR_OUT_OF_BOUNDS if the given position x, y is not in the diagram, * PENCIL_ERROR_UNKNOWN_OBJECT if the object is not in the diagram or has unsupported type */ pencil_error_t pencil_layouter_get_feature_order_at_pos ( const pencil_layouter_t *this_, const data_feature_t *feature_ptr, double x, double y, layout_order_t* out_layout_order ); /*! * \brief gets the layout order for a relationship at a given position * * \param this_ pointer to own object attributes * \param x x-position * \param y y-position * \param out_layout_order order at given position * \return PENCIL_ERROR_OUT_OF_BOUNDS if the given position x, y is not in the diagram, * PENCIL_ERROR_UNKNOWN_OBJECT if the object is not in the diagram or has unsupported type */ pencil_error_t pencil_layouter_get_relationship_order_at_pos ( const pencil_layouter_t *this_, double x, double y, layout_order_t* out_layout_order ); /*! * \brief determines if the given position is on a grid line * * \param this_ pointer to own object attributes * \param x x-position * \param y y-position * \param snap_distance maximum distance to the next grid line when to evaluate to "yes, on grid" * \param out_x_on_grid flag indicating if the given x position is on a grid line * \param out_y_on_grid flag indicating if the given y position is on a grid line */ static inline void pencil_layouter_is_pos_on_grid ( const pencil_layouter_t *this_, double x, double y, double snap_distance, bool *out_x_on_grid, bool *out_y_on_grid ); /*! * \brief determines the grid lines * * \param this_ pointer to own object attributes * \param out_x0 x-position of leftmost grid line * \param out_y0 y-position of topmost grid line * \param out_dx width between grid lines * \param out_dy height between grid lines * \param out_x_count number of x-position grid lines * \param out_y_count number of y-position grid lines */ static inline void pencil_layouter_get_grid_lines ( const pencil_layouter_t *this_, double *out_x0, double *out_y0, double *out_dx, double *out_dy, uint32_t *out_x_count, uint32_t *out_y_count ); /*! * \brief proposes a default classifier bounds rectangle * * \param this_ pointer to own object attributes */ void pencil_layouter_private_propose_default_classifier_size ( pencil_layouter_t *this_ ); #include "pencil_layouter.inl" #endif /* PENCIL_LAYOUTER_H */ /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_layouter.inl000066400000000000000000000064521415120503000237310ustar00rootroot00000000000000/* File: pencil_layouter.inl; Copyright and License: see below */ #include "tslog.h" #include static inline void pencil_layouter_prepare ( pencil_layouter_t *this_ ) { pencil_layout_data_resync( &((*this_).layout_data) ); } static inline pencil_layout_data_t *pencil_layouter_get_layout_data_ptr ( pencil_layouter_t *this_ ) { return &((*this_).layout_data); } static inline const pencil_layout_data_t *pencil_layouter_get_layout_data_const ( const pencil_layouter_t *this_ ) { return &((*this_).layout_data); } static inline pencil_size_t *pencil_layouter_get_pencil_size_ptr ( pencil_layouter_t *this_ ) { return &((*this_).pencil_size); } static inline void pencil_layouter_is_pos_on_grid ( const pencil_layouter_t *this_, double x, double y, double snap_distance, bool *out_x_on_grid, bool *out_y_on_grid ) { assert ( NULL != out_x_on_grid ); assert ( NULL != out_y_on_grid ); double x_dist = geometry_non_linear_scale_get_closest_fix_location( &((*this_).x_scale), x ) - x; double y_dist = geometry_non_linear_scale_get_closest_fix_location( &((*this_).y_scale), y ) - y; *out_x_on_grid = ((-snap_distance < x_dist)&&( x_dist < snap_distance)); *out_y_on_grid = ((-snap_distance < y_dist)&&( y_dist < snap_distance)); } static inline void pencil_layouter_get_grid_lines ( const pencil_layouter_t *this_, double *out_x0, double *out_y0, double *out_dx, double *out_dy, uint32_t *out_x_count, uint32_t *out_y_count ) { assert( out_x0 != NULL ); assert( out_y0 != NULL ); assert( out_dx != NULL ); assert( out_dy != NULL ); assert( out_x_count != NULL ); assert( out_y_count != NULL ); *out_x0 = geometry_non_linear_scale_get_location ( &((*this_).x_scale), /*order=*/ INT32_MIN ); *out_dx = geometry_non_linear_scale_get_grid_distances ( &((*this_).x_scale) ); *out_x_count = geometry_non_linear_scale_get_grid_intervals ( &((*this_).x_scale) ) + 1; *out_y0 = geometry_non_linear_scale_get_location ( &((*this_).y_scale), /*order=*/ INT32_MIN ); *out_dy = geometry_non_linear_scale_get_grid_distances ( &((*this_).y_scale) ); *out_y_count = geometry_non_linear_scale_get_grid_intervals ( &((*this_).y_scale) ) + 1; } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_marker.h000066400000000000000000000043101415120503000230020ustar00rootroot00000000000000/* File: pencil_marker.h; Copyright and License: see below */ #ifndef PENCIL_MARKER_H #define PENCIL_MARKER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Marks objects by colors and/or lines/ornaments */ #include "util/geometry/geometry_rectangle.h" #include "data_diagram.h" #include "set/data_small_set.h" #include "data_id.h" #include "set/data_visible_set.h" #include #include /*! * \brief attributes of the marker */ struct pencil_marker_struct { void *dummy; }; typedef struct pencil_marker_struct pencil_marker_t; /*! * \brief initializes the marker * * \param this_ pointer to own object attributes */ void pencil_marker_init( pencil_marker_t *this_ ); /*! * \brief destroys the marker * * \param this_ pointer to own object attributes */ void pencil_marker_destroy( pencil_marker_t *this_ ); /*! * \brief draws markers around the destination area of the cairo drawing context * * \param this_ pointer to own object attributes * \param rect the rectangle which to mark as focused. Drawings may be done outside. * \param cr a cairo drawing context */ void pencil_marker_mark_focused_rectangle ( const pencil_marker_t *this_, geometry_rectangle_t rect, cairo_t *cr ); /*! * \brief draws markers around the destination area of the cairo drawing context * * \param this_ pointer to own object attributes * \param rect the rectangle which to mark as selected. Drawings may be done outside. * \param cr a cairo drawing context */ void pencil_marker_mark_selected_rectangle ( const pencil_marker_t *this_, geometry_rectangle_t rect, cairo_t *cr ); #endif /* PENCIL_MARKER_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_rel_label_layouter.h000066400000000000000000000106201415120503000253670ustar00rootroot00000000000000/* File: pencil_rel_label_layouter.h; Copyright and License: see below */ #ifndef PENCIL_REL_LABEL_LAYOUTER_H #define PENCIL_REL_LABEL_LAYOUTER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Calculates the label positions of relationships in a diagram */ #include "pencil_size.h" #include "pencil_layout_data.h" #include "pencil_label_layout_helper.h" #include "draw/draw_relationship_label.h" #include "util/geometry/geometry_rectangle.h" #include "data_diagram.h" #include "set/data_small_set.h" #include "set/data_visible_set.h" #include "data_id.h" #include "universal_array_index_sorter.h" #include #include /*! * \brief attributes of the relationship-label layouter */ struct pencil_rel_label_layouter_struct { pencil_layout_data_t *layout_data; /* pointer to an instance of layout data */ pencil_size_t *pencil_size; /*!< pointer to an instance of a pencil_size_t object, defining pen sizes, gap sizes, font sizes and colors */ draw_relationship_label_t draw_relationship_label; /*!< collection of draw label functions */ pencil_label_layout_helper_t label_layout_helper; /*!< collection of layout label functions */ }; typedef struct pencil_rel_label_layouter_struct pencil_rel_label_layouter_t; /*! * \brief initializes the relationship-label layouter * * \param this_ pointer to own object attributes * \param layout_data pointer to the layout information to be used and modified * \param pencil_size pointer to the pencil_size_t object */ void pencil_rel_label_layouter_init( pencil_rel_label_layouter_t *this_, pencil_layout_data_t *layout_data, pencil_size_t *pencil_size ); /*! * \brief destroys the relationship-label layouter * * \param this_ pointer to own object attributes */ void pencil_rel_label_layouter_destroy( pencil_rel_label_layouter_t *this_ ); /*! * \brief determines the rectangels of the relationship-labels * * \param this_ pointer to own object attributes * \param font_layout structure to layout fonts */ void pencil_rel_label_layouter_do_layout ( pencil_rel_label_layouter_t *this_, PangoLayout *font_layout ); /*! * \brief determine order by which to layout relationship-labels * * Relationships that are not visible are ignored. Therefore out_sorted may contain fewer relationships than (*this_).layout_data. * * \param this_ pointer to own object attributes * \param out_sorted sorting order by which to layout relationship-labels; must not be NULL, shall be initialized to empty. */ void pencil_rel_label_layouter_private_propose_processing_order ( pencil_rel_label_layouter_t *this_, universal_array_index_sorter_t *out_sorted ); /*! * \brief propose multiple solutions to layout one relationship-label * * \param this_ pointer to own object attributes * \param current_relation relationship for which to propose solutions * \param font_layout structure to layout fonts * \param solutions_max maximum number (array size) of solutions to propose * \param out_solutions array of solutions * \param out_solutions_count number of proposed solutions; 1 <= out_solutions_count < solutions_max */ void pencil_rel_label_layouter_private_propose_solutions ( pencil_rel_label_layouter_t *this_, layout_relationship_t *current_relation, PangoLayout *font_layout, uint32_t solutions_max, geometry_rectangle_t out_solutions[], uint32_t *out_solutions_count ); #endif /* PENCIL_REL_LABEL_LAYOUTER_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_relationship_layouter.h000066400000000000000000000302171415120503000261530ustar00rootroot00000000000000/* File: pencil_relationship_layouter.h; Copyright and License: see below */ #ifndef PENCIL_RELATIONSHIP_LAYOUTER_H #define PENCIL_RELATIONSHIP_LAYOUTER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Calculates positions of relationships in a diagram */ #include "pencil_size.h" #include "pencil_layout_data.h" #include "pencil_relationship_painter.h" #include "util/geometry/geometry_rectangle.h" #include "util/geometry/geometry_non_linear_scale.h" #include "data_diagram.h" #include "set/data_small_set.h" #include "set/data_visible_set.h" #include "data_id.h" #include "universal_int32_pair.h" #include "universal_bool_list.h" #include "universal_array_index_sorter.h" #include #include /*! * \brief attributes of the relationship layouter */ struct pencil_relationship_layouter_struct { pencil_layout_data_t *layout_data; /* pointer to an instance of layout data */ pencil_size_t *pencil_size; /*!< pointer to an instance of a pencil_size_t object, defining pen sizes, gap sizes, font sizes and colors */ pencil_relationship_painter_t relationship_painter; /*!< own instance of a painter object to ask for display dimensions */ }; typedef struct pencil_relationship_layouter_struct pencil_relationship_layouter_t; /*! * \brief initializes the layouter * * \param this_ pointer to own object attributes * \param layout_data pointer to the layout information to be used and modified * \param pencil_size pointer to the pencil_size_t object */ void pencil_relationship_layouter_init( pencil_relationship_layouter_t *this_, pencil_layout_data_t *layout_data, pencil_size_t *pencil_size ); /*! * \brief destroys the layouter * * \param this_ pointer to own object attributes */ void pencil_relationship_layouter_destroy( pencil_relationship_layouter_t *this_ ); /*! * \brief determines the shapes of the relationships * * \param this_ pointer to own object attributes */ void pencil_relationship_layouter_private_do_layout ( pencil_relationship_layouter_t *this_ ); /*! * \brief determine order by which to shape relationships * * Relationships that are not visible are ignored. Therefore out_sorted may contain fewer relationships than (*this_).layout_data. * * \param this_ pointer to own object attributes * \param out_sorted sorting order by which to shape relationships; must not be NULL, shall be initialized to empty. */ void pencil_relationship_layouter_private_propose_processing_order ( pencil_relationship_layouter_t *this_, universal_array_index_sorter_t *out_sorted ); /*! * \brief propose multiple solutions to shape one relationship * * \param this_ pointer to own object attributes * \param sorted sorting order by which to shape relationships; must not be NULL. * \param sort_index index of the current relationship for which to propose solutions * \param solutions_max maximum number (array size) of solutions to propose * \param out_solutions array of solutions * \param out_solutions_count number of proposed solutions; 1 <= out_solutions_count < solutions_max */ void pencil_relationship_layouter_private_propose_solutions ( pencil_relationship_layouter_t *this_, const universal_array_index_sorter_t *sorted, uint32_t sort_index, uint32_t solutions_max, geometry_connector_t out_solutions[], uint32_t *out_solutions_count ); /*! * \brief selects one solution to shape a relationship * * \param this_ pointer to own object attributes * \param sorted sorting order by which to shape relationships; must not be NULL. * \param sort_index index (in sorted relationships) of the current relationship for which to select a solution * \param solutions_count number of proposed solutions; 1 <= out_solutions_count < solutions_max * \param solutions array of solutions * \param out_index_of_best index (of solution) of the best solution; must not be NULL. */ void pencil_relationship_layouter_private_select_solution ( pencil_relationship_layouter_t *this_, const universal_array_index_sorter_t *sorted, uint32_t sort_index, uint32_t solutions_count, const geometry_connector_t solutions[], uint32_t *out_index_of_best ); /*! * \brief layouts a connection from one rectangle to another in shape of Z or N * * \param this_ pointer to own object attributes * \param source_rect pointer to the source rectangle * \param dest_rect pointer to the destination rectangle * \param solutions_max maximum number (array size) of solutions to propose * \param out_solutions array of solutions * \param out_solutions_count number of proposed solutions; 1 <= out_solutions_count < solutions_max */ void pencil_relationship_layouter_private_connect_rectangles_by_ZN ( pencil_relationship_layouter_t *this_, const geometry_rectangle_t *source_rect, const geometry_rectangle_t *dest_rect, uint32_t solutions_max, geometry_connector_t out_solutions[], uint32_t *out_solutions_count ); /*! * \brief layouts a connection from one rectangle to another in shape of U or C * * \param this_ pointer to own object attributes * \param source_rect pointer to the source rectangle * \param dest_rect pointer to the destination rectangle * \param solutions_max maximum number (array size) of solutions to propose * \param out_solutions array of solutions * \param out_solutions_count number of proposed solutions; 1 <= out_solutions_count < solutions_max */ void pencil_relationship_layouter_private_connect_rectangles_by_UC ( pencil_relationship_layouter_t *this_, const geometry_rectangle_t *source_rect, const geometry_rectangle_t *dest_rect, uint32_t solutions_max, geometry_connector_t out_solutions[], uint32_t *out_solutions_count ); /*! * \brief layouts a connection from one rectangle to another in shape of L or 7 * * \param this_ pointer to own object attributes * \param source_rect pointer to the source rectangle * \param dest_rect pointer to the destination rectangle * \param solutions_max maximum number (array size) of solutions to propose * \param out_solutions array of solutions * \param out_solutions_count number of proposed solutions; 1 <= out_solutions_count < solutions_max */ void pencil_relationship_layouter_private_connect_rectangles_by_L7 ( pencil_relationship_layouter_t *this_, const geometry_rectangle_t *source_rect, const geometry_rectangle_t *dest_rect, uint32_t solutions_max, geometry_connector_t out_solutions[], uint32_t *out_solutions_count ); /*! * \brief finds an empty, unused line in a rectangle * * \param this_ pointer to own object attributes * \param search_rect pointer to the rectangle within which to search * \param horizontal_line true if space for a horizontal line is searched for, false for vertical line * \param min_gap minimum distance to other objects on the diagram * \param out_success pointer to locatoin where to store if the function was successful or not * \param out_coordinate ordinate (y-coordinate) or abscissa (x-coordinate) value where space is available. */ void pencil_relationship_layouter_private_find_space_for_line ( pencil_relationship_layouter_t *this_, const geometry_rectangle_t *search_rect, bool horizontal_line, double min_gap, bool *out_success, double *out_coordinate ); /*! * \brief make all relationships visible. * * Sets either normal visibility or grayed out status. * * \param this_ pointer to own object attributes */ void pencil_relationship_layouter_private_make_all_visible ( pencil_relationship_layouter_t *this_ ); /*! * \brief layouts all relationships. * * This function performs a standard layouting of relationships * suitable for most diagram types. * Exceptions are LIST, BOX, SEQUENCE, TIMING, COMMUNICATION * * \param this_ pointer to own object attributes */ void pencil_relationship_layouter_layout_standard( pencil_relationship_layouter_t *this_ ); /*! * \brief hides all relationships. * * Relationships are not visible in simple list and box diagrams. * * \param this_ pointer to own object attributes */ void pencil_relationship_layouter_layout_void( pencil_relationship_layouter_t *this_ ); /*! * \brief defines the shapes of relationships in sequence diagrams * * Shows only relationships that are associated to a lifeline because a sequence diagram * shows only an example sequence of messages, not all dependencies. * * \param this_ pointer to own object attributes */ void pencil_relationship_layouter_layout_for_sequence( pencil_relationship_layouter_t *this_ ); /*! * \brief defines the shapes of relationships in timing diagrams * * Shows only relationships that are associated to a lifeline because a timing diagram * shows only an example timing-sequence of messages, not all dependencies. * * \param this_ pointer to own object attributes */ void pencil_relationship_layouter_layout_for_timing( pencil_relationship_layouter_t *this_ ); /*! * \brief defines the shapes of relationships in communication diagrams. * * Shows only relationships that are associated to a lifeline because a communication diagram * shows only an example sequence of messages, not all dependencies. * * \param this_ pointer to own object attributes */ void pencil_relationship_layouter_layout_for_communication( pencil_relationship_layouter_t *this_ ); #endif /* PENCIL_RELATIONSHIP_LAYOUTER_H */ /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_relationship_painter.h000066400000000000000000000061131415120503000257470ustar00rootroot00000000000000/* File: pencil_relationship_painter.h; Copyright and License: see below */ #ifndef PENCIL_RELATIONSHIP_PAINTER_H #define PENCIL_RELATIONSHIP_PAINTER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Renders a relationship into a cairo drawing context */ #include "pencil_marker.h" #include "pencil_size.h" #include "layout/layout_relationship.h" #include "draw/draw_relationship_label.h" #include "util/geometry/geometry_connector.h" #include "data_diagram.h" #include "set/data_visible_set.h" #include "set/data_small_set.h" #include "data_id.h" #include #include /*! * \brief attributes of the relationship painter */ struct pencil_relationship_painter_struct { pencil_marker_t marker; /*!< own instance of a marker */ draw_relationship_label_t draw_relationship_label; /*!< collection of draw label functions */ }; typedef struct pencil_relationship_painter_struct pencil_relationship_painter_t; /*! * \brief initializes the painter * * \param this_ pointer to own object attributes */ void pencil_relationship_painter_init( pencil_relationship_painter_t *this_ ); /*! * \brief destroys the painter * * \param this_ pointer to own object attributes */ void pencil_relationship_painter_destroy( pencil_relationship_painter_t *this_ ); /*! * \brief draws the chosen classifier contents into the diagram_bounds area of the cairo drawing context * * \param this_ pointer to own object attributes * \param layouted_relationship pointer to the layout-information and data to be drawn * \param mark_focused true if the object is to be marked as "focused" * \param mark_highlighted true if the object is to be marked as "highlighted" * \param mark_selected true if the object is to be marked as "selected" * \param pencil_size set of sizes and colors for drawing lines and text * \param layout structure to layout fonts * \param cr a cairo drawing context */ void pencil_relationship_painter_draw ( pencil_relationship_painter_t *this_, const layout_relationship_t *layouted_relationship, bool mark_focused, bool mark_highlighted, bool mark_selected, const pencil_size_t *pencil_size, PangoLayout *layout, cairo_t *cr ); #endif /* PENCIL_RELATIONSHIP_PAINTER_H */ /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_size.h000066400000000000000000000206321415120503000225000ustar00rootroot00000000000000/* File: pencil_size.h; Copyright and License: see below */ #ifndef PENCIL_SIZE_H #define PENCIL_SIZE_H /* public file for the doxygen documentation: */ /*! * \file * \brief Provides a set of size values used to draw a diagram */ #include #include #include #include #include /*! * \brief attributes of the pencil_size_t */ struct pencil_size_struct { double footnote_font_size; /*!< text size of footnote text */ PangoFontDescription *footnote_font_description; /*!< text description of footnote text */ double standard_font_size; /*!< text size of standard text */ PangoFontDescription *standard_font_description; /*!< text description of standard text */ double title_font_size; /*!< text size of title text */ PangoFontDescription *title_font_description; /*!< text description of title text */ double standard_line_width; /*!< line width of standard lines */ double bold_line_width; /*!< line width of bold lines */ double line_dash_length; /*!< dash length of a short-dashed line */ double standard_object_border; /*!< gap between the bounding rectangle and the outer line of an object */ double arrow_stroke_length; /*!< length of a stroke to paint an arrow tip */ double arrow_stroke_087_length; /*!< sqrt(0.75)=0.8660 parts of the length of a stroke to paint an arrow */ double preferred_object_distance; /*!< preferred distance between two objects or object and connector */ double classifier_symbol_height; /*!< height of actors, timeouts, fork, join, start, end */ GdkRGBA standard_color; /*!< foreground color of all standard objects */ GdkRGBA select_color; /*!< foreground color of all currently selected objects (user selected set): pink */ GdkRGBA highlight_color; /*!< foreground color of the current highlighted/mouse over object: turquoise */ GdkRGBA focus_color; /*!< foreground color of the one currently focused object: yellow */ GdkRGBA emphasized_bgcolor; /*!< background color of the durable-emphasized objects: yellow */ GdkRGBA gray_out_color; /*!< foreground color of the durable-greyed_out objects: gray */ }; typedef struct pencil_size_struct pencil_size_t; /*! * \brief initializes the size values * * \param this_ pointer to own object attributes * \param width of the area where to draw the diagram * \param height of the area where to draw the diagram */ static inline void pencil_size_init( pencil_size_t *this_, double width, double height ); /*! * \brief initializes the size values by defaults * * \param this_ pointer to own object attributes */ static inline void pencil_size_init_empty( pencil_size_t *this_ ); /*! * \brief destroys the pencil_size_t * * \param this_ pointer to own object attributes */ static inline void pencil_size_destroy( pencil_size_t *this_ ); /*! * \brief re-initializes the pencil_size_t * * \param this_ pointer to own object attributes * \param width of the area where to draw the diagram * \param height of the area where to draw the diagram */ static inline void pencil_size_reinit( pencil_size_t *this_, double width, double height ); /*! * \brief gets the attribute of pencil_size_t: footnote_font_size * * \param this_ pointer to own object attributes */ static inline double pencil_size_get_footnote_font_size( const pencil_size_t *this_ ); /*! * \brief gets the PangoFontDescription for the footnote font * * \param this_ pointer to own object attributes */ static inline const PangoFontDescription *pencil_size_get_footnote_font_description( const pencil_size_t *this_ ); /*! * \brief gets the attribute of pencil_size_t: standard_font_size * * \param this_ pointer to own object attributes */ static inline double pencil_size_get_standard_font_size( const pencil_size_t *this_ ); /*! * \brief gets the PangoFontDescription for the standard font * * \param this_ pointer to own object attributes */ static inline const PangoFontDescription *pencil_size_get_standard_font_description( const pencil_size_t *this_ ); /*! * \brief gets the attribute of pencil_size_t: title_font_size * * \param this_ pointer to own object attributes */ static inline double pencil_size_get_title_font_size( const pencil_size_t *this_ ); /*! * \brief determines PangoFontDescription for the title font * * \param this_ pointer to own object attributes */ static inline const PangoFontDescription *pencil_size_get_title_font_description( const pencil_size_t *this_ ); /*! * \brief proposes a tab size * * \param this_ pointer to own object attributes */ static inline double pencil_size_get_font_tab_size( const pencil_size_t *this_ ); /*! * \brief determines the gap between font lines * * \param this_ pointer to own object attributes */ static inline double pencil_size_get_font_line_gap( const pencil_size_t *this_ ); /*! * \brief gets the attribute of pencil_size_t: standard_line_width * * \param this_ pointer to own object attributes */ static inline double pencil_size_get_standard_line_width( const pencil_size_t *this_ ); /*! * \brief gets the attribute of pencil_size_t: bold_line_width * * \param this_ pointer to own object attributes */ static inline double pencil_size_get_bold_line_width( const pencil_size_t *this_ ); /*! * \brief gets the attribute of pencil_size_t: line_dash_length * * \param this_ pointer to own object attributes */ static inline double pencil_size_get_line_dash_length( const pencil_size_t *this_ ); /*! * \brief gets the attribute of pencil_size_t: standard_object_border aka gap * * \param this_ pointer to own object attributes */ static inline double pencil_size_get_standard_object_border( const pencil_size_t *this_ ); /*! * \brief gets the attribute of pencil_size_t: arrow_stroke_length * * \param this_ pointer to own object attributes */ static inline double pencil_size_get_arrow_stroke_length( const pencil_size_t *this_ ); /*! * \brief gets the attribute of pencil_size_t: arrow_stroke_087_length * * \param this_ pointer to own object attributes */ static inline double pencil_size_get_arrow_stroke_087_length( const pencil_size_t *this_ ); /*! * \brief gets the attribute of pencil_size_t: preferred_object_distance * * \param this_ pointer to own object attributes */ static inline double pencil_size_get_preferred_object_distance( const pencil_size_t *this_ ); /*! * \brief gets the attribute of pencil_size_t: classifier_symbol_height * * \param this_ pointer to own object attributes */ static inline double pencil_size_get_classifier_symbol_height( const pencil_size_t *this_ ); /*! * \brief gets the attribute of pencil_size_t: standard_color * * \param this_ pointer to own object attributes */ static inline GdkRGBA pencil_size_get_standard_color( const pencil_size_t *this_ ); /*! * \brief gets the attribute of pencil_size_t: select_color * * \param this_ pointer to own object attributes */ static inline GdkRGBA pencil_size_get_select_color( const pencil_size_t *this_ ); /*! * \brief gets the attribute of pencil_size_t: highlight_color * * \param this_ pointer to own object attributes */ static inline GdkRGBA pencil_size_get_highlight_color( const pencil_size_t *this_ ); /*! * \brief gets the attribute of pencil_size_t: focus_color * * \param this_ pointer to own object attributes */ static inline GdkRGBA pencil_size_get_focus_color( const pencil_size_t *this_ ); /*! * \brief gets the attribute of pencil_size_t: emphasized_bgcolor * * \param this_ pointer to own object attributes */ static inline GdkRGBA pencil_size_get_emphasized_bgcolor( const pencil_size_t *this_ ); /*! * \brief gets the attribute of pencil_size_t: gray_out_color * * \param this_ pointer to own object attributes */ static inline GdkRGBA pencil_size_get_gray_out_color( const pencil_size_t *this_ ); #include "pencil_size.inl" #endif /* PENCIL_SIZE_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/pencil_size.inl000066400000000000000000000215411415120503000230330ustar00rootroot00000000000000/* File: pencil_size.inl; Copyright and License: see below */ #include "tslog.h" #include static inline void pencil_size_init( pencil_size_t *this_, double width, double height ) { pencil_size_init_empty( this_ ); pencil_size_reinit( this_, width, height); } static inline void pencil_size_destroy( pencil_size_t *this_ ) { pango_font_description_free ( (*this_).footnote_font_description ); (*this_).footnote_font_description = NULL; pango_font_description_free ( (*this_).standard_font_description ); (*this_).standard_font_description = NULL; pango_font_description_free ( (*this_).title_font_description ); (*this_).title_font_description = NULL; } static const char *PENCIL_SIZE_FONT_FAMILY = "Sans"; static inline void pencil_size_init_empty( pencil_size_t *this_ ) { (*this_).standard_color.red = 0.0; (*this_).standard_color.green = 0.0; (*this_).standard_color.blue = 0.0; (*this_).standard_color.alpha = 1.0; (*this_).select_color.red = 1.0; (*this_).select_color.green = 0.3; (*this_).select_color.blue = 0.8; (*this_).select_color.alpha = 1.0; (*this_).highlight_color.red = 0.0; (*this_).highlight_color.green = 0.6; (*this_).highlight_color.blue = 0.4; (*this_).highlight_color.alpha = 1.0; (*this_).focus_color.red = 0.9; (*this_).focus_color.green = 0.85; (*this_).focus_color.blue = 0.0; (*this_).focus_color.alpha = 1.0; (*this_).emphasized_bgcolor.red = 1.0; (*this_).emphasized_bgcolor.green = 1.0; (*this_).emphasized_bgcolor.blue = 0.3; (*this_).emphasized_bgcolor.alpha = 1.0; (*this_).gray_out_color.red = 0.7; (*this_).gray_out_color.green = 0.7; (*this_).gray_out_color.blue = 0.7; (*this_).gray_out_color.alpha = 1.0; /* guess some default values: */ (*this_).footnote_font_size = 9.0; (*this_).footnote_font_description = pango_font_description_new (); pango_font_description_set_family_static ( (*this_).footnote_font_description, PENCIL_SIZE_FONT_FAMILY ); pango_font_description_set_style ( (*this_).footnote_font_description, PANGO_STYLE_NORMAL ); pango_font_description_set_weight ( (*this_).footnote_font_description, PANGO_WEIGHT_MEDIUM ); pango_font_description_set_stretch ( (*this_).footnote_font_description, PANGO_STRETCH_NORMAL ); pango_font_description_set_size ( (*this_).footnote_font_description, 9 * PANGO_SCALE ); (*this_).standard_font_size = 12.0; (*this_).standard_font_description = pango_font_description_new (); pango_font_description_set_family_static ( (*this_).standard_font_description, PENCIL_SIZE_FONT_FAMILY ); pango_font_description_set_style ( (*this_).standard_font_description, PANGO_STYLE_NORMAL ); pango_font_description_set_weight ( (*this_).standard_font_description, PANGO_WEIGHT_MEDIUM ); pango_font_description_set_stretch ( (*this_).standard_font_description, PANGO_STRETCH_NORMAL ); pango_font_description_set_size ( (*this_).standard_font_description, 12 * PANGO_SCALE ); (*this_).title_font_size = 14.0; (*this_).title_font_description = pango_font_description_new (); pango_font_description_set_family_static ( (*this_).title_font_description, PENCIL_SIZE_FONT_FAMILY ); pango_font_description_set_style ( (*this_).title_font_description, PANGO_STYLE_NORMAL ); pango_font_description_set_weight ( (*this_).title_font_description, PANGO_WEIGHT_BOLD ); pango_font_description_set_stretch ( (*this_).title_font_description, PANGO_STRETCH_NORMAL ); pango_font_description_set_size ( (*this_).title_font_description, 14 * PANGO_SCALE ); (*this_).standard_line_width = 1.0; (*this_).bold_line_width = 2.0; (*this_).line_dash_length = 5.0; (*this_).standard_object_border = 2.0; (*this_).arrow_stroke_length = 10.0; (*this_).arrow_stroke_087_length = 8.66; (*this_).preferred_object_distance = 20.0; (*this_).classifier_symbol_height = 24.0; } static inline void pencil_size_reinit( pencil_size_t *this_, double width, double height ) { double smaller_border = (width static inline bool geometry_3dir_equals ( const geometry_3dir_t *this_, const geometry_3dir_t *that ) { const bool result = (( (*this_).first == (*that).first )&&( (*this_).second == (*that).second )&&( (*this_).third == (*that).third )); return result; } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/util/geometry/geometry_anchor.h000066400000000000000000000077351415120503000262020ustar00rootroot00000000000000/* File: geometry_anchor.h; Copyright and License: see below */ #ifndef GEOMETRY_ANCHOR_H #define GEOMETRY_ANCHOR_H /* public file for the doxygen documentation: */ /*! * \file * \brief Stores the coordinates of a reference point and an x/y alignment instruction * * This structure allows to layout a geometric object * by providing an anchor point and the information how the object * shall be aligned relative to this anchor point */ #include "util/geometry/geometry_point.h" #include "util/geometry/geometry_h_align.h" #include "util/geometry/geometry_v_align.h" #include /*! * \brief attributes of an anchor */ struct geometry_anchor_struct { geometry_point_t reference_point; geometry_h_align_t x_align; geometry_v_align_t y_align; }; typedef struct geometry_anchor_struct geometry_anchor_t; /*! * \brief initializes the geometry_anchor_t struct * * \param this_ pointer to own object attributes * \param x x coordinate of the reference point * \param y y coordinate of the reference point * \param x_align horizontal alignment relative to the reference point * \param y_align vertical alignment relative to the reference point */ static inline void geometry_anchor_init ( geometry_anchor_t *this_, double x, double y, geometry_h_align_t x_align, geometry_v_align_t y_align ); /*! * \brief copies original to this uninitialized geometry_anchor_t struct * * \param this_ pointer to own object attributes * \param original pointer to object attributes that shall be copied */ static inline void geometry_anchor_copy ( geometry_anchor_t *this_, const geometry_anchor_t *original ); /*! * \brief replaces the already initialized geometry_anchor_t struct by other data * * \param this_ pointer to own object attributes * \param original pointer to object attributes that shall be copied */ static inline void geometry_anchor_replace ( geometry_anchor_t *this_, const geometry_anchor_t *original ); /*! * \brief destroys the geometry_anchor_t struct * * \param this_ pointer to own object attributes */ static inline void geometry_anchor_destroy ( geometry_anchor_t *this_ ); /*! * \brief gets the x coordinate of geometry_anchor_t * * \param this_ pointer to own object attributes */ static inline double geometry_anchor_get_x ( const geometry_anchor_t *this_ ); /*! * \brief gets the y coordinate of geometry_anchor_t * * \param this_ pointer to own object attributes */ static inline double geometry_anchor_get_y ( const geometry_anchor_t *this_ ); /*! * \brief gets the horizontal alignment of geometry_anchor_t * * \param this_ pointer to own object attributes */ static inline geometry_h_align_t geometry_anchor_get_x_align ( const geometry_anchor_t *this_ ); /*! * \brief gets the vertical alignment coordinate of geometry_anchor_t * * \param this_ pointer to own object attributes */ static inline geometry_v_align_t geometry_anchor_get_y_align ( const geometry_anchor_t *this_ ); /*! * \brief prints the geometry_anchor_t struct to the trace output * * \param this_ pointer to own object attributes */ static inline void geometry_anchor_trace ( const geometry_anchor_t *this_ ); #include "util/geometry/geometry_anchor.inl" #endif /* GEOMETRY_ANCHOR_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/util/geometry/geometry_anchor.inl000066400000000000000000000050241415120503000265220ustar00rootroot00000000000000/* File: geometry_anchor.inl; Copyright and License: see below */ #include "trace.h" #include "tslog.h" #include #include static inline void geometry_anchor_init ( geometry_anchor_t *this_, double x, double y, geometry_h_align_t x_align, geometry_v_align_t y_align ) { geometry_point_init( &((*this_).reference_point), x, y ); (*this_).x_align = x_align; (*this_).y_align = y_align; } static inline void geometry_anchor_copy ( geometry_anchor_t *this_, const geometry_anchor_t *original ) { assert( NULL != original ); (*this_) = (*original); } static inline void geometry_anchor_replace ( geometry_anchor_t *this_, const geometry_anchor_t *original ) { assert( NULL != original ); (*this_) = (*original); } static inline void geometry_anchor_destroy ( geometry_anchor_t *this_ ) { geometry_point_destroy( &((*this_).reference_point) ); } static inline double geometry_anchor_get_x ( const geometry_anchor_t *this_ ) { return geometry_point_get_x( &((*this_).reference_point) ); } static inline double geometry_anchor_get_y ( const geometry_anchor_t *this_ ) { return geometry_point_get_y( &((*this_).reference_point) ); } static inline geometry_h_align_t geometry_anchor_get_x_align ( const geometry_anchor_t *this_ ) { return (*this_).x_align; } static inline geometry_v_align_t geometry_anchor_get_y_align ( const geometry_anchor_t *this_ ) { return (*this_).y_align; } static inline void geometry_anchor_trace ( const geometry_anchor_t *this_ ) { TRACE_INFO( "geometry_anchor_t" ); TRACE_INFO_INT( "- x:", geometry_point_get_x( &((*this_).reference_point) ) ); TRACE_INFO_INT( "- y:", geometry_point_get_y( &((*this_).reference_point) ) ); TRACE_INFO_INT( "- x_align:", (*this_).x_align ); TRACE_INFO_INT( "- y_align:", (*this_).y_align ); } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/util/geometry/geometry_connector.h000066400000000000000000000271201415120503000267100ustar00rootroot00000000000000/* File: geometry_connector.h; Copyright and License: see below */ #ifndef GEOMETRY_CONNECTOR_H #define GEOMETRY_CONNECTOR_H /* public file for the doxygen documentation: */ /*! * \file * \brief Stores coordinates of a connector. * * The connector consists of a source-end, * connected to a main-line, connected to a destination-end. */ #include "util/geometry/geometry_rectangle.h" #include "util/geometry/geometry_point.h" #include "util/geometry/geometry_3dir.h" #include #include /*! * \brief attributes of a connector */ struct geometry_connector_struct { double source_end_x; double source_end_y; double main_line_source_x; double main_line_source_y; double main_line_destination_x; double main_line_destination_y; double destination_end_x; double destination_end_y; }; typedef struct geometry_connector_struct geometry_connector_t; /*! * \brief initializes the geometry_connector_t struct for a vertical main-line * * \param this_ pointer to own object attributes * \param source_end_x x coordinate of the source end point * \param source_end_y y coordinate of the source end point * \param destination_end_x x coordinate of the destination end point * \param destination_end_y y coordinate of the destination end point * \param main_line_x x coordinate of the vertical main bar */ static inline void geometry_connector_init_vertical ( geometry_connector_t *this_, double source_end_x, double source_end_y, double destination_end_x, double destination_end_y, double main_line_x ); /*! * \brief initializes the geometry_connector_t struct for a horizontal main-line * * \param this_ pointer to own object attributes * \param source_end_x x coordinate of the source end point * \param source_end_y y coordinate of the source end point * \param destination_end_x x coordinate of the destination end point * \param destination_end_y y coordinate of the destination end point * \param main_line_y y coordinate of the horizontal main bar */ static inline void geometry_connector_init_horizontal ( geometry_connector_t *this_, double source_end_x, double source_end_y, double destination_end_x, double destination_end_y, double main_line_y ); /*! * \brief re-initializes the geometry_connector_t struct for a vertical main-line * * \param this_ pointer to own object attributes * \param source_end_x x coordinate of the source end point * \param source_end_y y coordinate of the source end point * \param destination_end_x x coordinate of the destination end point * \param destination_end_y y coordinate of the destination end point * \param main_line_x x coordinate of the vertical main bar */ static inline void geometry_connector_reinit_vertical ( geometry_connector_t *this_, double source_end_x, double source_end_y, double destination_end_x, double destination_end_y, double main_line_x ); /*! * \brief re-initializes the geometry_connector_t struct for a horizontal main-line * * \param this_ pointer to own object attributes * \param source_end_x x coordinate of the source end point * \param source_end_y y coordinate of the source end point * \param destination_end_x x coordinate of the destination end point * \param destination_end_y y coordinate of the destination end point * \param main_line_y y coordinate of the horizontal main bar */ static inline void geometry_connector_reinit_horizontal ( geometry_connector_t *this_, double source_end_x, double source_end_y, double destination_end_x, double destination_end_y, double main_line_y ); /*! * \brief copies original to this uninitialized geometry_connector_t struct * * \param this_ pointer to own object attributes * \param original pointer to object attributes that shall be copied */ static inline void geometry_connector_copy ( geometry_connector_t *this_, const geometry_connector_t *original ); /*! * \brief replaces the already initialized geometry_connector_t struct by a copy of original * * \param this_ pointer to own object attributes * \param original pointer to object attributes that shall be copied */ static inline void geometry_connector_replace ( geometry_connector_t *this_, const geometry_connector_t *original ); /*! * \brief initializes the geometry_connector_t struct to a connector from 0,0 to 0,0 * * \param this_ pointer to own object attributes */ static inline void geometry_connector_init_empty ( geometry_connector_t *this_ ); /*! * \brief re-initializes the geometry_connector_t struct to a connector from 0,0 to 0,0 * * \param this_ pointer to own object attributes */ static inline void geometry_connector_reinit_empty ( geometry_connector_t *this_ ); /*! * \brief destroys the geometry_connector_t struct * * \param this_ pointer to own object attributes */ static inline void geometry_connector_destroy ( geometry_connector_t *this_ ); /*! * \brief gets the attribute source_end_x from geometry_connector_t * * \param this_ pointer to own object attributes */ static inline double geometry_connector_get_source_end_x ( const geometry_connector_t *this_ ); /*! * \brief gets the attribute source_end_y from geometry_connector_t * * \param this_ pointer to own object attributes */ static inline double geometry_connector_get_source_end_y ( const geometry_connector_t *this_ ); /*! * \brief gets the attribute main_line_source_x from geometry_connector_t * * \param this_ pointer to own object attributes */ static inline double geometry_connector_get_main_line_source_x ( const geometry_connector_t *this_ ); /*! * \brief gets the attribute main_line_source_y from geometry_connector_t * * \param this_ pointer to own object attributes */ static inline double geometry_connector_get_main_line_source_y ( const geometry_connector_t *this_ ); /*! * \brief gets the attribute main_line_destination_x from geometry_connector_t * * \param this_ pointer to own object attributes */ static inline double geometry_connector_get_main_line_destination_x ( const geometry_connector_t *this_ ); /*! * \brief gets the attribute main_line_destination_y from geometry_connector_t * * \param this_ pointer to own object attributes */ static inline double geometry_connector_get_main_line_destination_y ( const geometry_connector_t *this_ ); /*! * \brief gets the attribute destination_end_x from geometry_connector_t * * \param this_ pointer to own object attributes */ static inline double geometry_connector_destination_end_x ( const geometry_connector_t *this_ ); /*! * \brief gets the attribute destination_end_y from geometry_connector_t * * \param this_ pointer to own object attributes */ static inline double geometry_connector_get_destination_end_y ( const geometry_connector_t *this_ ); /*! * \brief calculates the the point of the connector line after distance_covered * * \param this_ pointer to own object attributes * \param distance_covered distance from source, expected values range from 0.0 .. geometry_connector_get_length * \return point on the connector line that has distance distance_covered from source end. * If distance_covered < 0.0, the source point is returned. * If distance > geometry_connector_get_length, the destination point is returned. */ static inline geometry_point_t geometry_connector_calculate_waypoint ( const geometry_connector_t *this_, double distance_covered ); /*! * \brief gets the length of the connector line * * \param this_ pointer to own object attributes */ static inline double geometry_connector_get_length ( const geometry_connector_t *this_ ); /*! * \brief determines if a given coordinate is close to geometry_connector_t * * \param this_ pointer to own object attributes * \param x x coordinate * \param y y coordinate * \param max_distance maximum distance between (x,y) to the connector * \return true if the location is close to the connector. */ static inline bool geometry_connector_is_close ( const geometry_connector_t *this_, double x, double y, double max_distance ); /*! * \brief determines if a given rectangle is overlapped (touching excluded) * * \param this_ pointer to own object attributes * \param rect rectangle that is checked for overlaps * \return true if the rectangle is intersected */ static inline bool geometry_connector_is_intersecting_rectangle ( const geometry_connector_t *this_, const geometry_rectangle_t *rect ); /*! * \brief counts intersections of two connector objects * * \param this_ pointer to own object attributes * \param that pointer to connector where intersections shall be determined * \return number of intersections. 0 if there are no intersections, 9 max (3x3, one for each segment) */ static inline uint32_t geometry_connector_count_connector_intersects ( const geometry_connector_t *this_, const geometry_connector_t *that ); /*! * \brief gets the bounding rectangle of geometry_connector_t * * \param this_ pointer to own object attributes */ static inline geometry_rectangle_t geometry_connector_get_bounding_rectangle ( const geometry_connector_t *this_ ); /*! * \brief gets the directions-pattern that is described by the connector * * \param this_ pointer to own object attributes * \return three geometry_direction_t, index 0 for source, 1 for mainline, 2 for destination */ static inline geometry_3dir_t geometry_connector_get_directions ( const geometry_connector_t *this_ ); /*! * \brief prints the geometry_connector_t struct to the trace output * * \param this_ pointer to own object attributes */ static inline void geometry_connector_trace ( const geometry_connector_t *this_ ); #include "util/geometry/geometry_connector.inl" #endif /* GEOMETRY_CONNECTOR_H */ /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/util/geometry/geometry_connector.inl000066400000000000000000000544231415120503000272510ustar00rootroot00000000000000/* File: geometry_connector.inl; Copyright and License: see below */ #include "trace.h" #include "tslog.h" #include static inline void geometry_connector_init_vertical ( geometry_connector_t *this_, double source_end_x, double source_end_y, double destination_end_x, double destination_end_y, double main_line_x ) { (*this_).source_end_x = source_end_x; (*this_).source_end_y = source_end_y; (*this_).main_line_source_x = main_line_x; (*this_).main_line_source_y = source_end_y; (*this_).main_line_destination_x = main_line_x; (*this_).main_line_destination_y = destination_end_y; (*this_).destination_end_x = destination_end_x; (*this_).destination_end_y = destination_end_y; } static inline void geometry_connector_init_horizontal ( geometry_connector_t *this_, double source_end_x, double source_end_y, double destination_end_x, double destination_end_y, double main_line_y ) { (*this_).source_end_x = source_end_x; (*this_).source_end_y = source_end_y; (*this_).main_line_source_x = source_end_x; (*this_).main_line_source_y = main_line_y; (*this_).main_line_destination_x = destination_end_x; (*this_).main_line_destination_y = main_line_y; (*this_).destination_end_x = destination_end_x; (*this_).destination_end_y = destination_end_y; } static inline void geometry_connector_reinit_vertical ( geometry_connector_t *this_, double source_end_x, double source_end_y, double destination_end_x, double destination_end_y, double main_line_x ) { (*this_).source_end_x = source_end_x; (*this_).source_end_y = source_end_y; (*this_).main_line_source_x = main_line_x; (*this_).main_line_source_y = source_end_y; (*this_).main_line_destination_x = main_line_x; (*this_).main_line_destination_y = destination_end_y; (*this_).destination_end_x = destination_end_x; (*this_).destination_end_y = destination_end_y; } static inline void geometry_connector_reinit_horizontal ( geometry_connector_t *this_, double source_end_x, double source_end_y, double destination_end_x, double destination_end_y, double main_line_y ) { (*this_).source_end_x = source_end_x; (*this_).source_end_y = source_end_y; (*this_).main_line_source_x = source_end_x; (*this_).main_line_source_y = main_line_y; (*this_).main_line_destination_x = destination_end_x; (*this_).main_line_destination_y = main_line_y; (*this_).destination_end_x = destination_end_x; (*this_).destination_end_y = destination_end_y; } static inline void geometry_connector_copy ( geometry_connector_t *this_, const geometry_connector_t *original ) { (*this_) = (*original); } static inline void geometry_connector_replace ( geometry_connector_t *this_, const geometry_connector_t *original ) { (*this_) = (*original); } static inline void geometry_connector_init_empty ( geometry_connector_t *this_ ) { (*this_).source_end_x = 0.0; (*this_).source_end_y = 0.0; (*this_).main_line_source_x = 0.0; (*this_).main_line_source_y = 0.0; (*this_).main_line_destination_x = 0.0; (*this_).main_line_destination_y = 0.0; (*this_).destination_end_x = 0.0; (*this_).destination_end_y = 0.0; } static inline void geometry_connector_reinit_empty ( geometry_connector_t *this_ ) { (*this_).source_end_x = 0.0; (*this_).source_end_y = 0.0; (*this_).main_line_source_x = 0.0; (*this_).main_line_source_y = 0.0; (*this_).main_line_destination_x = 0.0; (*this_).main_line_destination_y = 0.0; (*this_).destination_end_x = 0.0; (*this_).destination_end_y = 0.0; } static inline void geometry_connector_destroy ( geometry_connector_t *this_ ) { } static inline double geometry_connector_get_source_end_x ( const geometry_connector_t *this_ ) { return (*this_).source_end_x; } static inline double geometry_connector_get_source_end_y ( const geometry_connector_t *this_ ) { return (*this_).source_end_y; } static inline double geometry_connector_get_main_line_source_x ( const geometry_connector_t *this_ ) { return (*this_).main_line_source_x; } static inline double geometry_connector_get_main_line_source_y ( const geometry_connector_t *this_ ) { return (*this_).main_line_source_y; } static inline double geometry_connector_get_main_line_destination_x ( const geometry_connector_t *this_ ) { return (*this_).main_line_destination_x; } static inline double geometry_connector_get_main_line_destination_y ( const geometry_connector_t *this_ ) { return (*this_).main_line_destination_y; } static inline double geometry_connector_destination_end_x ( const geometry_connector_t *this_ ) { return (*this_).destination_end_x; } static inline double geometry_connector_get_destination_end_y ( const geometry_connector_t *this_ ) { return (*this_).destination_end_y; } static inline geometry_point_t geometry_connector_calculate_waypoint ( const geometry_connector_t *this_, double distance_covered ) { geometry_point_t result; const double source_end_length = fabs( (*this_).source_end_x - (*this_).main_line_source_x ) + fabs( (*this_).source_end_y - (*this_).main_line_source_y ); const double main_line_length = fabs( (*this_).main_line_source_x - (*this_).main_line_destination_x ) + fabs( (*this_).main_line_source_y - (*this_).main_line_destination_y ); const double dest_end_length = fabs( (*this_).main_line_destination_x - (*this_).destination_end_x ) + fabs( (*this_).main_line_destination_y - (*this_).destination_end_y ); if ( distance_covered < source_end_length ) { if (( distance_covered <= 0.0 )||( source_end_length < 0.000000001 )) { geometry_point_init ( &result, (*this_).source_end_x, (*this_).source_end_y ); } else { geometry_point_init ( &result, (*this_).source_end_x, (*this_).source_end_y ); const double segment_part1 = distance_covered / source_end_length; geometry_point_shift( &result, segment_part1 * ( (*this_).main_line_source_x - (*this_).source_end_x ), segment_part1 * ( (*this_).main_line_source_y - (*this_).source_end_y ) ); } } else { const double shifted_distance = distance_covered - source_end_length; if (( shifted_distance < main_line_length )&&( main_line_length >= 0.000000001 )) { geometry_point_init ( &result, (*this_).main_line_source_x, (*this_).main_line_source_y ); const double segment_part2 = shifted_distance / main_line_length; geometry_point_shift( &result, segment_part2 * ( (*this_).main_line_destination_x - (*this_).main_line_source_x ), segment_part2 * ( (*this_).main_line_destination_y - (*this_).main_line_source_y ) ); } else { const double shifted2_distance = shifted_distance - main_line_length; if (( shifted2_distance < dest_end_length )&&( dest_end_length >= 0.000000001 )) { geometry_point_init ( &result, (*this_).main_line_destination_x, (*this_).main_line_destination_y ); const double segment_part3 = shifted2_distance / dest_end_length; geometry_point_shift( &result, segment_part3 * ( (*this_).destination_end_x - (*this_).main_line_destination_x ), segment_part3 * ( (*this_).destination_end_y - (*this_).main_line_destination_y ) ); } else { geometry_point_init ( &result, (*this_).destination_end_x, (*this_).destination_end_y ); } } } return result; } static inline double geometry_connector_get_length ( const geometry_connector_t *this_ ) { double source_end_length; double main_line_length; double dest_end_length; source_end_length = fabs( (*this_).source_end_x - (*this_).main_line_source_x ) + fabs( (*this_).source_end_y - (*this_).main_line_source_y ); main_line_length = fabs( (*this_).main_line_source_x - (*this_).main_line_destination_x ) + fabs( (*this_).main_line_source_y - (*this_).main_line_destination_y ); dest_end_length = fabs( (*this_).main_line_destination_x - (*this_).destination_end_x ) + fabs( (*this_).main_line_destination_y - (*this_).destination_end_y ); return source_end_length + main_line_length + dest_end_length; } static inline bool geometry_connector_is_close ( const geometry_connector_t *this_, double x, double y, double max_distance ) { bool close_to_source_end_line; bool close_to_main_line; bool close_to_destination_end_line; close_to_source_end_line = ((( (*this_).source_end_x - max_distance < x ) && ( x < (*this_).main_line_source_x + max_distance )) || (( (*this_).main_line_source_x - max_distance < x ) && ( x < (*this_).source_end_x + max_distance ))) && ((( (*this_).source_end_y - max_distance < y ) && ( y < (*this_).main_line_source_y + max_distance )) || (( (*this_).main_line_source_y - max_distance < y ) && ( y < (*this_).source_end_y + max_distance ))); close_to_main_line = ((( (*this_).main_line_destination_x - max_distance < x ) && ( x < (*this_).main_line_source_x + max_distance )) || (( (*this_).main_line_source_x - max_distance < x ) && ( x < (*this_).main_line_destination_x + max_distance ))) && ((( (*this_).main_line_destination_y - max_distance < y ) && ( y < (*this_).main_line_source_y + max_distance )) || (( (*this_).main_line_source_y - max_distance < y ) && ( y < (*this_).main_line_destination_y + max_distance ))); close_to_destination_end_line = ((( (*this_).main_line_destination_x - max_distance < x ) && ( x < (*this_).destination_end_x + max_distance )) || (( (*this_).destination_end_x - max_distance < x ) && ( x < (*this_).main_line_destination_x + max_distance ))) && ((( (*this_).main_line_destination_y - max_distance < y ) && ( y < (*this_).destination_end_y + max_distance )) || (( (*this_).destination_end_y - max_distance < y ) && ( y < (*this_).main_line_destination_y + max_distance ))); return ( close_to_source_end_line || close_to_main_line || close_to_destination_end_line ); } static inline bool geometry_connector_is_intersecting_rectangle ( const geometry_connector_t *this_, const geometry_rectangle_t *rect ) { geometry_rectangle_t source; geometry_rectangle_t main_line; geometry_rectangle_t destination; geometry_rectangle_init_by_corners( &source, (*this_).source_end_x, (*this_).source_end_y, (*this_).main_line_source_x, (*this_).main_line_source_y ); geometry_rectangle_init_by_corners( &main_line, (*this_).main_line_source_x, (*this_).main_line_source_y, (*this_).main_line_destination_x, (*this_).main_line_destination_y ); geometry_rectangle_init_by_corners( &destination, (*this_).main_line_destination_x, (*this_).main_line_destination_y, (*this_).destination_end_x, (*this_).destination_end_y ); const bool result = geometry_rectangle_is_intersecting( &source, rect ) || geometry_rectangle_is_intersecting( &main_line, rect ) || geometry_rectangle_is_intersecting( &destination, rect ); geometry_rectangle_destroy( &source ); geometry_rectangle_destroy( &main_line ); geometry_rectangle_destroy( &destination ); return result; } static inline uint32_t geometry_connector_count_connector_intersects ( const geometry_connector_t *this_, const geometry_connector_t *that ) { uint32_t result = 0; /* do some simple prechecks */ geometry_rectangle_t this_bounds; geometry_rectangle_t that_bounds; this_bounds = geometry_connector_get_bounding_rectangle( this_ ); that_bounds = geometry_connector_get_bounding_rectangle( that ); if ( geometry_rectangle_is_contiguous( &this_bounds, &that_bounds ) ) { /* do some more complicated checks */ geometry_rectangle_t this_source_end; geometry_rectangle_t this_main_line; geometry_rectangle_t this_destination_end; geometry_rectangle_t that_source_end; geometry_rectangle_t that_main_line; geometry_rectangle_t that_destination_end; geometry_rectangle_init_by_corners( &this_source_end, (*this_).main_line_source_x, (*this_).main_line_source_y, (*this_).source_end_x, (*this_).source_end_y ); geometry_rectangle_init_by_corners( &this_main_line, (*this_).main_line_destination_x, (*this_).main_line_destination_y, (*this_).main_line_source_x, (*this_).main_line_source_y ); geometry_rectangle_init_by_corners( &this_destination_end, (*this_).destination_end_x, (*this_).destination_end_y, (*this_).main_line_destination_x, (*this_).main_line_destination_y ); geometry_rectangle_init_by_corners( &that_source_end, (*that).main_line_source_x, (*that).main_line_source_y, (*that).source_end_x, (*that).source_end_y ); geometry_rectangle_init_by_corners( &that_main_line, (*that).main_line_destination_x, (*that).main_line_destination_y, (*that).main_line_source_x, (*that).main_line_source_y ); geometry_rectangle_init_by_corners( &that_destination_end, (*that).destination_end_x, (*that).destination_end_y, (*that).main_line_destination_x, (*that).main_line_destination_y ); if ( geometry_rectangle_is_contiguous( &this_source_end, &that_source_end ) ) { result += 1; } if ( geometry_rectangle_is_contiguous( &this_main_line, &that_source_end ) ) { result += 1; } if ( geometry_rectangle_is_contiguous( &this_destination_end, &that_source_end ) ) { result += 1; } if ( geometry_rectangle_is_contiguous( &this_source_end, &that_main_line ) ) { result += 1; } if ( geometry_rectangle_is_contiguous( &this_main_line, &that_main_line ) ) { result += 1; } if ( geometry_rectangle_is_contiguous( &this_destination_end, &that_main_line ) ) { result += 1; } if ( geometry_rectangle_is_contiguous( &this_source_end, &that_destination_end ) ) { result += 1; } if ( geometry_rectangle_is_contiguous( &this_main_line, &that_destination_end ) ) { result += 1; } if ( geometry_rectangle_is_contiguous( &this_destination_end, &that_destination_end ) ) { result += 1; } geometry_rectangle_destroy( &this_source_end ); geometry_rectangle_destroy( &this_main_line ); geometry_rectangle_destroy( &this_destination_end ); geometry_rectangle_destroy( &that_source_end ); geometry_rectangle_destroy( &that_main_line ); geometry_rectangle_destroy( &that_destination_end ); } /* else no intersects, result = 0 */ geometry_rectangle_destroy( &this_bounds ); geometry_rectangle_destroy( &that_bounds ); return result; } static inline geometry_rectangle_t geometry_connector_get_bounding_rectangle ( const geometry_connector_t *this_ ) { geometry_rectangle_t result; double left; double right; double top; double bottom; left = fmin ( (*this_).main_line_source_x, fmin( (*this_).source_end_x, (*this_).destination_end_x ) ); right = fmax ( (*this_).main_line_source_x, fmax( (*this_).source_end_x, (*this_).destination_end_x ) ); top = fmin ( (*this_).main_line_source_y, fmin( (*this_).source_end_y, (*this_).destination_end_y ) ); bottom = fmax ( (*this_).main_line_source_y, fmax( (*this_).source_end_y, (*this_).destination_end_y ) ); geometry_rectangle_init( &result, left, top, right - left, bottom - top ); return result; } static inline geometry_3dir_t geometry_connector_get_directions ( const geometry_connector_t *this_ ) { const double very_small = 0.000000001; const double src_dx = (*this_).main_line_source_x - (*this_).source_end_x; const double src_dy = (*this_).main_line_source_y - (*this_).source_end_y; const double abs_src_dx = fabs( src_dx ); const double abs_src_dy = fabs( src_dy ); const bool src_exists = (( abs_src_dx > very_small )||( abs_src_dy > very_small )); const bool src_is_horizontal = ( abs_src_dx > abs_src_dy ); const geometry_direction_t src_dir = ( ! src_exists ) ? GEOMETRY_DIRECTION_CENTER : src_is_horizontal ? (( src_dx > 0.0 ) ? GEOMETRY_DIRECTION_RIGHT : GEOMETRY_DIRECTION_LEFT ) : (( src_dy > 0.0 ) ? GEOMETRY_DIRECTION_DOWN : GEOMETRY_DIRECTION_UP ); const double main_dx = (*this_).main_line_destination_x - (*this_).main_line_source_x; const double main_dy = (*this_).main_line_destination_y - (*this_).main_line_source_y; const double abs_main_dx = fabs( main_dx ); const double abs_main_dy = fabs( main_dy ); const bool main_exists = (( abs_main_dx > very_small )||( abs_main_dy > very_small )); const bool main_is_horizontal = ( abs_main_dx > abs_main_dy ); const geometry_direction_t main_dir = ( ! main_exists ) ? GEOMETRY_DIRECTION_CENTER : main_is_horizontal ? (( main_dx > 0.0 ) ? GEOMETRY_DIRECTION_RIGHT : GEOMETRY_DIRECTION_LEFT ) : (( main_dy > 0.0 ) ? GEOMETRY_DIRECTION_DOWN : GEOMETRY_DIRECTION_UP ); const double dst_dx = (*this_).destination_end_x - (*this_).main_line_destination_x; const double dst_dy = (*this_).destination_end_y - (*this_).main_line_destination_y; const double abs_dst_dx = fabs( dst_dx ); const double abs_dst_dy = fabs( dst_dy ); const bool dst_exists = (( abs_dst_dx > very_small )||( abs_dst_dy > very_small )); const bool dst_is_horizontal = ( abs_dst_dx > abs_dst_dy ); const geometry_direction_t dst_dir = ( ! dst_exists ) ? GEOMETRY_DIRECTION_CENTER : dst_is_horizontal ? (( dst_dx > 0.0 ) ? GEOMETRY_DIRECTION_RIGHT : GEOMETRY_DIRECTION_LEFT ) : (( dst_dy > 0.0 ) ? GEOMETRY_DIRECTION_DOWN : GEOMETRY_DIRECTION_UP ); const geometry_3dir_t result = { .first = src_dir, .second = main_dir, .third = dst_dir }; return result; } static inline void geometry_connector_trace ( const geometry_connector_t *this_ ) { static const char geometry_mnemomic[GEOMETRY_DIRECTION_MAX] = { '.', '<', 'F', '^', '7', '>', 'J', 'v', 'L' }; const geometry_3dir_t pattern = geometry_connector_get_directions( this_ ); const char pattern_as_str[6] = { [0] = geometry_mnemomic[pattern.first], [1] = ' ', [2] = geometry_mnemomic[pattern.second], [3] = ' ', [4] = geometry_mnemomic[pattern.third], [5] = '\0' }; TRACE_INFO( "geometry_connector_t" ); TRACE_INFO_INT( "- source_end_x:", (*this_).source_end_x ); TRACE_INFO_INT( "- source_end_y:", (*this_).source_end_y ); TRACE_INFO_INT( "- main_line_source_x:", (*this_).main_line_source_x ); TRACE_INFO_INT( "- main_line_source_y:", (*this_).main_line_source_y ); TRACE_INFO_INT( "- main_line_destination_x:", (*this_).main_line_destination_x ); TRACE_INFO_INT( "- main_line_destination_y:", (*this_).main_line_destination_y ); TRACE_INFO_INT( "- destination_end_x:", (*this_).destination_end_x ); TRACE_INFO_INT( "- destination_end_y:", (*this_).destination_end_y ); TRACE_INFO_STR( "- get_directions:", pattern_as_str ); } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/util/geometry/geometry_dimensions.h000066400000000000000000000116651415120503000270750ustar00rootroot00000000000000/* File: geometry_dimensions.h; Copyright and License: see below */ #ifndef GEOMETRY_DIMENSIONS_H #define GEOMETRY_DIMENSIONS_H /* public file for the doxygen documentation: */ /*! * \file * \brief Stores width and height of an object */ #include /*! * \brief attributes of dimensions */ struct geometry_dimensions_struct { double width; double height; }; typedef struct geometry_dimensions_struct geometry_dimensions_t; /*! * \brief initializes the geometry_dimensions_t struct * * \param this_ pointer to own object attributes * \param width width of the object * \param height height of the object */ static inline void geometry_dimensions_init ( geometry_dimensions_t *this_, double width, double height ); /*! * \brief re-initializes the geometry_dimensions_t struct * * \param this_ pointer to own object attributes * \param width width of the object * \param height height of the object */ static inline void geometry_dimensions_reinit ( geometry_dimensions_t *this_, double width, double height ); /*! * \brief copies original to this uninitialized geometry_dimensions_t struct * * \param this_ pointer to own object attributes * \param original pointer to object attributes that shall be copied */ static inline void geometry_dimensions_copy ( geometry_dimensions_t *this_, const geometry_dimensions_t *original ); /*! * \brief replaces the already initialized geometry_dimensions_t struct by other data * * \param this_ pointer to own object attributes * \param original pointer to object attributes that shall be copied */ static inline void geometry_dimensions_replace ( geometry_dimensions_t *this_, const geometry_dimensions_t *original ); /*! * \brief initializes the geometry_dimensions_t struct to an empty rect * * \param this_ pointer to own object attributes */ static inline void geometry_dimensions_init_empty ( geometry_dimensions_t *this_ ); /*! * \brief re-initializes the geometry_dimensions_t struct to an empty rect * * \param this_ pointer to own object attributes */ static inline void geometry_dimensions_reinit_empty ( geometry_dimensions_t *this_ ); /*! * \brief destroys the geometry_dimensions_t struct * * \param this_ pointer to own object attributes */ static inline void geometry_dimensions_destroy ( geometry_dimensions_t *this_ ); /*! * \brief gets the width of geometry_dimensions_t * * \param this_ pointer to own object attributes */ static inline double geometry_dimensions_get_width ( const geometry_dimensions_t *this_ ); /*! * \brief gets the height of geometry_dimensions_t * * \param this_ pointer to own object attributes */ static inline double geometry_dimensions_get_height ( const geometry_dimensions_t *this_ ); /*! * \brief gets the area-value of geometry_dimensions_t * * \param this_ pointer to own object attributes */ static inline double geometry_dimensions_get_area ( const geometry_dimensions_t *this_ ); /*! * \brief determines if the given dimensions have a valid (positive) size * * \param this_ pointer to own object attributes * \return false if the dimensions have a positive size. */ static inline bool geometry_dimensions_is_empty ( const geometry_dimensions_t *this_ ); /*! * \brief determines if the given dimensions can contain the other * * \param this_ pointer to own object attributes * \param that pointer to others object attributes * \return false if the dimensions can not contain the other. (touching is still containing) */ static inline bool geometry_dimensions_can_contain ( const geometry_dimensions_t *this_, const geometry_dimensions_t *that ); /*! * \brief expands or shrinks the geometry_dimensions_t * * \param this_ pointer to own object attributes * \param delta_width value by which to increase the width. In case of a negative value, the dimensions shrink (but not below 0). * \param delta_height value by which to increase the height. In case of a negative value, the dimensions shrink (but not below 0). */ static inline void geometry_dimensions_expand ( geometry_dimensions_t *this_, double delta_width, double delta_height ); /*! * \brief prints the geometry_dimensions_t struct to the trace output * * \param this_ pointer to own object attributes */ static inline void geometry_dimensions_trace ( const geometry_dimensions_t *this_ ); #include "util/geometry/geometry_dimensions.inl" #endif /* GEOMETRY_DIMENSIONS_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/util/geometry/geometry_dimensions.inl000066400000000000000000000062551415120503000274270ustar00rootroot00000000000000/* File: geometry_dimensions.inl; Copyright and License: see below */ #include "trace.h" #include "tslog.h" #include #include static inline void geometry_dimensions_init ( geometry_dimensions_t *this_, double width, double height ) { (*this_).width = width; (*this_).height = height; } static inline void geometry_dimensions_reinit ( geometry_dimensions_t *this_, double width, double height ) { (*this_).width = width; (*this_).height = height; } static inline void geometry_dimensions_copy ( geometry_dimensions_t *this_, const geometry_dimensions_t *original ) { assert( NULL != original ); (*this_) = (*original); } static inline void geometry_dimensions_replace ( geometry_dimensions_t *this_, const geometry_dimensions_t *original ) { assert( NULL != original ); (*this_) = (*original); } static inline void geometry_dimensions_init_empty ( geometry_dimensions_t *this_ ) { (*this_).width = 0.0; (*this_).height = 0.0; } static inline void geometry_dimensions_reinit_empty ( geometry_dimensions_t *this_ ) { (*this_).width = 0.0; (*this_).height = 0.0; } static inline void geometry_dimensions_destroy ( geometry_dimensions_t *this_ ) { } static inline double geometry_dimensions_get_width ( const geometry_dimensions_t *this_ ) { return (*this_).width; } static inline double geometry_dimensions_get_height ( const geometry_dimensions_t *this_ ) { return (*this_).height; } static inline double geometry_dimensions_get_area ( const geometry_dimensions_t *this_ ) { return (*this_).width * (*this_).height; } static inline bool geometry_dimensions_is_empty ( const geometry_dimensions_t *this_ ) { return ( ( (*this_).width < 0.000000001 )||( (*this_).height < 0.000000001 ) ); } static inline bool geometry_dimensions_can_contain ( const geometry_dimensions_t *this_, const geometry_dimensions_t *that ) { assert( NULL != that ); const bool result = ( (*this_).width + 0.000000001 > (*that).width )&&( (*this_).height + 0.000000001 > (*that).height ); return result; } static inline void geometry_dimensions_expand ( geometry_dimensions_t *this_, double delta_width, double delta_height ) { (*this_).width += delta_width; if ( (*this_).width < 0.0 ) { (*this_).width = 0.0; } (*this_).height += delta_height; if ( (*this_).height < 0.0 ) { (*this_).height = 0.0; } } static inline void geometry_dimensions_trace ( const geometry_dimensions_t *this_ ) { TRACE_INFO( "geometry_dimensions_t" ); TRACE_INFO_INT( "- width:", (*this_).width ); TRACE_INFO_INT( "- height:", (*this_).height ); } /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/util/geometry/geometry_direction.h000066400000000000000000000034311415120503000266750ustar00rootroot00000000000000/* File: geometry_direction.h; Copyright and License: see below */ #ifndef GEOMETRY_DIRECTION_H #define GEOMETRY_DIRECTION_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines layout directions of objects */ /*! * \brief enumeration of directions * * Do not assume any order. */ enum geometry_direction_enum { GEOMETRY_DIRECTION_CENTER = 0, /*!< the direction points to the center of the object */ GEOMETRY_DIRECTION_LEFT = 1, /*!< the direction points to the left */ GEOMETRY_DIRECTION_UP_LEFT = 2, /*!< the direction points up-left */ GEOMETRY_DIRECTION_UP = 3, /*!< the direction points up */ GEOMETRY_DIRECTION_UP_RIGHT = 4, /*!< the direction points up-right */ GEOMETRY_DIRECTION_RIGHT = 5, /*!< the direction points to the right */ GEOMETRY_DIRECTION_DOWN_RIGHT = 6, /*!< the direction points down-right */ GEOMETRY_DIRECTION_DOWN = 7, /*!< the direction points down */ GEOMETRY_DIRECTION_DOWN_LEFT = 8, /*!< the direction points down-left */ GEOMETRY_DIRECTION_MAX = 9, /*!< maximum number of directions, can be used to iterate over all directions */ }; typedef enum geometry_direction_enum geometry_direction_t; #endif /* GEOMETRY_DIRECTION_H */ /* Copyright 2018-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/util/geometry/geometry_h_align.h000066400000000000000000000034451415120503000263230ustar00rootroot00000000000000/* File: geometry_h_align.h; Copyright and License: see below */ #ifndef GEOMETRY_H_ALIGN_H #define GEOMETRY_H_ALIGN_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines the horizontal alignment of geometry objects */ /*! * \brief alignment constants of vertical alignment * */ enum geometry_h_align_enum { GEOMETRY_H_ALIGN_LEFT, GEOMETRY_H_ALIGN_CENTER, GEOMETRY_H_ALIGN_RIGHT, }; typedef enum geometry_h_align_enum geometry_h_align_t; /*! * \brief gets the left coordinate of an aligned object * * \param this_ pointer to own object attributes * \param width width of object to be aligned * \param reference_left left coordinate of object to which to align to * \param reference_width width of object to which to align to * \return left coordinate of aligned object */ static inline double geometry_h_align_get_left ( const geometry_h_align_t *this_, double width, double reference_left, double reference_width ); #include "util/geometry/geometry_h_align.inl" #endif /* GEOMETRY_H_ALIGN_H */ /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/util/geometry/geometry_h_align.inl000066400000000000000000000027141415120503000266540ustar00rootroot00000000000000/* File: geometry_h_align.inl; Copyright and License: see below */ #include "trace.h" #include "tslog.h" #include static inline double geometry_h_align_get_left ( const geometry_h_align_t *this_, double width, double reference_left, double reference_width ) { double left; switch ( *this_ ) { case GEOMETRY_H_ALIGN_LEFT: { left = reference_left; } break; case GEOMETRY_H_ALIGN_CENTER: { left = reference_left + 0.5 * ( reference_width - width ); } break; case GEOMETRY_H_ALIGN_RIGHT: { left = reference_left + reference_width - width; } break; default: { TSLOG_ERROR("unknown geometry_h_align_t in geometry_h_align_get_left()"); assert(0); left = 0.0; } break; } return left; } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/util/geometry/geometry_non_linear_scale.h000066400000000000000000000115341415120503000302130ustar00rootroot00000000000000/* File: geometry_non_linear_scale.h; Copyright and License: see below */ #ifndef GEOMETRY_NON_LINEAR_SCALE_H #define GEOMETRY_NON_LINEAR_SCALE_H /* public file for the doxygen documentation: */ /*! * \file * \brief Maps order-values to locations */ #include /*! * \brief constants of geometry_non_linear_scale_t */ enum geometry_non_linear_scale_max_enum { GEOMETRY_NON_LINEAR_SCALE_MAX_POINTS = 32, /*!< maximum number of points by which the non-linear scale function is defined */ }; /*! * \brief attributes of a non_linear_scale */ struct geometry_non_linear_scale_struct { uint32_t num_points; /*!< number of valid elements in the arrays location and order */ double location[ GEOMETRY_NON_LINEAR_SCALE_MAX_POINTS ]; /*!< array containing locations for which an order is defined */ int32_t order[ GEOMETRY_NON_LINEAR_SCALE_MAX_POINTS ]; /*!< array containing order-values which correspond to a location */ }; typedef struct geometry_non_linear_scale_struct geometry_non_linear_scale_t; /*! * \brief initializes the geometry_non_linear_scale_t struct * * \param this_ pointer to own object attributes * \param lower_bound lower bound location, defines the lowest location value * \param upper_bound upper bound location, defines the upper-most location value */ void geometry_non_linear_scale_init ( geometry_non_linear_scale_t *this_, double lower_bound, double upper_bound ); /*! * \brief re-initializes the geometry_non_linear_scale_t struct * * \param this_ pointer to own object attributes * \param lower_bound lower bound location, defines the lowest location value * \param upper_bound upper bound location, defines the upper-most location value */ static inline void geometry_non_linear_scale_reinit ( geometry_non_linear_scale_t *this_, double lower_bound, double upper_bound ); /*! * \brief destroys the geometry_non_linear_scale_t struct * * \param this_ pointer to own object attributes */ static inline void geometry_non_linear_scale_destroy ( geometry_non_linear_scale_t *this_ ); /*! * \brief prints the geometry_non_linear_scale_t struct to the trace output * * \param this_ pointer to own object attributes */ void geometry_non_linear_scale_trace ( const geometry_non_linear_scale_t *this_ ); /*! * \brief adds an order-value to the non-linear scale, updates the locations of all defined points * * \param this_ pointer to own object attributes * \param order order value for which a location shall be inserted to the scale */ void geometry_non_linear_scale_add_order ( geometry_non_linear_scale_t *this_, int32_t order ); /*! * \brief gets a location given an order-value * * \param this_ pointer to own object attributes * \param order order value for which the location shall be determined */ static inline double geometry_non_linear_scale_get_location ( const geometry_non_linear_scale_t *this_, int32_t order ); /*! * \brief gets an order-value given a location * * \param this_ pointer to own object attributes * \param location location for which the order shall be determined * \param snap_interval maximum distance from location to next point which snaps the location to the points location */ static inline int32_t geometry_non_linear_scale_get_order ( const geometry_non_linear_scale_t *this_, double location, double snap_interval ); /*! * \brief gets the location of the closest fix point * * \param this_ pointer to own object attributes * \param location location value for which the closest fix-point location shall be determined */ static inline double geometry_non_linear_scale_get_closest_fix_location ( const geometry_non_linear_scale_t *this_, double location ); /*! * \brief gets the interval count between the points. * * \param this_ pointer to own object attributes * \return (*this_).num_points - 1 */ static inline uint32_t geometry_non_linear_scale_get_grid_intervals ( const geometry_non_linear_scale_t *this_ ); /*! * \brief determines the average distance between grid points * * \param this_ pointer to own object attributes * \return (upper_bound-lower_bound)/(*this_).num_points */ static inline double geometry_non_linear_scale_get_grid_distances ( const geometry_non_linear_scale_t *this_ ); #include "util/geometry/geometry_non_linear_scale.inl" #endif /* GEOMETRY_NON_LINEAR_SCALE_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/util/geometry/geometry_non_linear_scale.inl000066400000000000000000000142721415120503000305500ustar00rootroot00000000000000/* File: geometry_non_linear_scale.inl; Copyright and License: see below */ #include "trace.h" #include "tslog.h" #include #include static inline void geometry_non_linear_scale_reinit ( geometry_non_linear_scale_t *this_, double lower_bound, double upper_bound ) { geometry_non_linear_scale_init( this_, lower_bound, upper_bound ); } static inline void geometry_non_linear_scale_destroy ( geometry_non_linear_scale_t *this_ ) { } static inline double geometry_non_linear_scale_get_location ( const geometry_non_linear_scale_t *this_, int32_t order ) { TRACE_BEGIN(); assert( (*this_).num_points <= GEOMETRY_NON_LINEAR_SCALE_MAX_POINTS ); double result = (*this_).location[(*this_).num_points-1]; bool found; found = false; if ( order <= (*this_).order[0] ) { found = true; result = (*this_).location[0]; TRACE_INFO_INT( "result-%", result*100 ); } for ( uint32_t pos = 1; ( pos < (*this_).num_points ) && ( ! found ) ; pos ++ ) { if ( order < (*this_).order[pos] ) { found = true; double loc_interval_width = (*this_).location[pos] - (*this_).location[pos-1]; uint32_t ord_interval_width = (*this_).order[pos] - (*this_).order[pos-1]; if ( ord_interval_width == 0 ) { result = (*this_).location[pos-1]; /* prevent division by zero */ } else { uint32_t order_interval_offset = order - (*this_).order[pos-1]; result = (*this_).location[pos-1] + ( loc_interval_width * ((double)order_interval_offset) / ((double)ord_interval_width) ); } TRACE_INFO_INT( "interval id:", pos ); TRACE_INFO_INT_INT( "interval [i-1,i]:", (int32_t)(*this_).location[pos-1], (int32_t)(*this_).location[pos] ); TRACE_INFO_INT( "result", (int32_t)result ); } else if ( order == (*this_).order[pos] ) { found = true; result = (*this_).location[pos]; TRACE_INFO_INT( "result", (int32_t)result ); } } TRACE_END(); return result; } static inline int32_t geometry_non_linear_scale_get_order ( const geometry_non_linear_scale_t *this_, double location, double snap_interval ) { TRACE_BEGIN(); assert( (*this_).num_points <= GEOMETRY_NON_LINEAR_SCALE_MAX_POINTS ); int32_t result = (*this_).order[(*this_).num_points-1]; bool found; found = false; if ( location <= ( (*this_).location[0] + snap_interval) ) { found = true; result = (*this_).order[0]; TRACE_INFO_INT( "result", result ); } for ( uint32_t pos = 1; ( pos < (*this_).num_points ) && ( ! found ) ; pos ++ ) { if ( location <= ( (*this_).location[pos] + snap_interval ) ) { if ( location > ( (*this_).location[pos] - snap_interval ) ) { found = true; result = (*this_).order[pos]; TRACE_INFO_INT( "result", result ); } else { found = true; double loc_interval_width = (*this_).location[pos] - (*this_).location[pos-1]; uint32_t ord_interval_width = (*this_).order[pos] - (*this_).order[pos-1]; if ( ( loc_interval_width > -0.000000001 ) && ( loc_interval_width < 0.000000001 ) ) { result = (*this_).order[pos-1]; /* prevent division by zero */ } else { uint32_t order_interval_offset = ((double)ord_interval_width) * ( location - (*this_).location[pos-1] ) / loc_interval_width; result = (*this_).order[pos-1] + order_interval_offset; } TRACE_INFO_INT( "interval id:", pos ); TRACE_INFO_INT_INT( "interval [i-1,i]:", (*this_).order[pos-1], (*this_).order[pos] ); TRACE_INFO_INT( "result", result ); } } } TRACE_END(); return result; } static inline double geometry_non_linear_scale_get_closest_fix_location ( const geometry_non_linear_scale_t *this_, double location ) { TRACE_BEGIN(); assert( (*this_).num_points <= GEOMETRY_NON_LINEAR_SCALE_MAX_POINTS ); double result = (*this_).location[(*this_).num_points-1]; bool found; found = false; if ( location <= (*this_).location[0] ) { found = true; result = (*this_).location[0]; TRACE_INFO_INT( "result-pos", 0 ); } for ( uint32_t pos = 1; ( pos < (*this_).num_points ) && ( ! found ) ; pos ++ ) { if ( location <= (*this_).location[pos] ) { found = true; if ( ( location - (*this_).location[pos-1] ) < ( (*this_).location[pos] - location ) ) { result = (*this_).location[pos-1]; TRACE_INFO_INT( "result-pos", pos-1 ); } else { result = (*this_).location[pos]; TRACE_INFO_INT( "result-pos", pos ); } } } TRACE_END(); return result; } static inline uint32_t geometry_non_linear_scale_get_grid_intervals ( const geometry_non_linear_scale_t *this_ ) { assert( (*this_).num_points >= 2 ); return ( (*this_).num_points - 1 ); } static inline double geometry_non_linear_scale_get_grid_distances ( const geometry_non_linear_scale_t *this_ ) { assert( (*this_).num_points >= 2 ); assert( (*this_).num_points <= GEOMETRY_NON_LINEAR_SCALE_MAX_POINTS ); return (( (*this_).location[(*this_).num_points-1] - (*this_).location[0] )/( (*this_).num_points - 1 )); } /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/util/geometry/geometry_point.h000066400000000000000000000107401415120503000260470ustar00rootroot00000000000000/* File: geometry_point.h; Copyright and License: see below */ #ifndef GEOMETRY_POINT_H #define GEOMETRY_POINT_H /* public file for the doxygen documentation: */ /*! * \file * \brief Stores the coordinates of a point */ #include "util/geometry/geometry_direction.h" #include /*! * \brief attributes of a point */ struct geometry_point_struct { double x; double y; }; typedef struct geometry_point_struct geometry_point_t; /*! * \brief initializes the geometry_point_t struct * * \param this_ pointer to own object attributes * \param x x coordinate of the object * \param y y coordinate of the object */ static inline void geometry_point_init ( geometry_point_t *this_, double x, double y ); /*! * \brief re-initializes the geometry_point_t struct * * \param this_ pointer to own object attributes * \param x x coordinate of the object * \param y y coordinate of the object */ static inline void geometry_point_reinit ( geometry_point_t *this_, double x, double y ); /*! * \brief copies original to this uninitialized geometry_point_t struct * * \param this_ pointer to own object attributes * \param original pointer to object attributes that shall be copied */ static inline void geometry_point_copy ( geometry_point_t *this_, const geometry_point_t *original ); /*! * \brief replaces the already initialized geometry_point_t struct by other data * * \param this_ pointer to own object attributes * \param original pointer to object attributes that shall be copied */ static inline void geometry_point_replace ( geometry_point_t *this_, const geometry_point_t *original ); /*! * \brief destroys the geometry_point_t struct * * \param this_ pointer to own object attributes */ static inline void geometry_point_destroy ( geometry_point_t *this_ ); /*! * \brief gets the x coordinate of geometry_point_t * * \param this_ pointer to own object attributes */ static inline double geometry_point_get_x ( const geometry_point_t *this_ ); /*! * \brief gets the y coordinate of geometry_point_t * * \param this_ pointer to own object attributes */ static inline double geometry_point_get_y ( const geometry_point_t *this_ ); /*! * \brief gets the chess distance between two geometry_point_t structs * * \param this_ pointer to own object attributes * \param that pointer to other object attributes * \return chess distance between the two points */ static inline double geometry_point_calc_chess_distance ( const geometry_point_t *this_, const geometry_point_t *that ); /*! * \brief determines if the two geometry_point_t refer to the same location * * \param this_ pointer to own object attributes * \param that pointer to other object attributes * \return true if the two points are equal */ static inline bool geometry_point_equals ( const geometry_point_t *this_, const geometry_point_t *that ); /*! * \brief gets the direction of *that point from the perspective of *this_ point. * * Lesser y values mean GEOMETRY_DIRECTION_UP, lesser x values mean GEOMETRY_DIRECTION_LEFT. GEOMETRY_DIRECTION_CENTER if points are equal. * * \param this_ pointer to own object attributes * \param that pointer to other object attributes * \return direction of the other point */ static inline geometry_direction_t geometry_point_get_direction ( const geometry_point_t *this_, const geometry_point_t *that ); /*! * \brief shifts the geometry_point_t * * \param this_ pointer to own object attributes * \param delta_x value by which to increase the x. * \param delta_y value by which to increase the y. */ static inline void geometry_point_shift ( geometry_point_t *this_, double delta_x, double delta_y ); /*! * \brief prints the geometry_point_t struct to the trace output * * \param this_ pointer to own object attributes */ static inline void geometry_point_trace ( const geometry_point_t *this_ ); #include "util/geometry/geometry_point.inl" #endif /* GEOMETRY_POINT_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/util/geometry/geometry_point.inl000066400000000000000000000074411415120503000264060ustar00rootroot00000000000000/* File: geometry_point.inl; Copyright and License: see below */ #include "trace.h" #include "tslog.h" #include #include static inline void geometry_point_init ( geometry_point_t *this_, double x, double y ) { (*this_).x = x; (*this_).y = y; } static inline void geometry_point_reinit ( geometry_point_t *this_, double x, double y ) { (*this_).x = x; (*this_).y = y; } static inline void geometry_point_copy ( geometry_point_t *this_, const geometry_point_t *original ) { assert( NULL != original ); (*this_) = (*original); } static inline void geometry_point_replace ( geometry_point_t *this_, const geometry_point_t *original ) { assert( NULL != original ); (*this_) = (*original); } static inline void geometry_point_destroy ( geometry_point_t *this_ ) { } static inline double geometry_point_get_x ( const geometry_point_t *this_ ) { return (*this_).x; } static inline double geometry_point_get_y ( const geometry_point_t *this_ ) { return (*this_).y; } static inline double geometry_point_calc_chess_distance ( const geometry_point_t *this_, const geometry_point_t *that ) { assert( NULL != that ); return ( fabs( (*this_).x - (*that).x ) + fabs( (*this_).y - (*that).y ) ); } static inline bool geometry_point_equals ( const geometry_point_t *this_, const geometry_point_t *that ) { assert( NULL != that ); return ( ( fabs( (*this_).x - (*that).x ) + fabs( (*this_).y - (*that).y ) ) < 0.000000001 ); } static inline geometry_direction_t geometry_point_get_direction ( const geometry_point_t *this_, const geometry_point_t *that ) { assert( NULL != that ); geometry_direction_t result; if ( (*this_).x + 0.000000001 < (*that).x ) { /* that is right of this_ */ if ( (*this_).y + 0.000000001 < (*that).y ) { result = GEOMETRY_DIRECTION_DOWN_RIGHT; } else if ( (*this_).y - 0.000000001 > (*that).y ) { result = GEOMETRY_DIRECTION_UP_RIGHT; } else { result = GEOMETRY_DIRECTION_RIGHT; } } else if ( (*this_).x - 0.000000001 > (*that).x ) { /* that is left of this_ */ if ( (*this_).y + 0.000000001 < (*that).y ) { result = GEOMETRY_DIRECTION_DOWN_LEFT; } else if ( (*this_).y - 0.000000001 > (*that).y ) { result = GEOMETRY_DIRECTION_UP_LEFT; } else { result = GEOMETRY_DIRECTION_LEFT; } } else { /* that is x-equal to this_ */ if ( (*this_).y + 0.000000001 < (*that).y ) { result = GEOMETRY_DIRECTION_DOWN; } else if ( (*this_).y - 0.000000001 > (*that).y ) { result = GEOMETRY_DIRECTION_UP; } else { result = GEOMETRY_DIRECTION_CENTER; } } return result; } static inline void geometry_point_shift ( geometry_point_t *this_, double delta_x, double delta_y ) { (*this_).x += delta_x; (*this_).y += delta_y; } static inline void geometry_point_trace ( const geometry_point_t *this_ ) { TRACE_INFO( "geometry_point_t" ); TRACE_INFO_INT( "- x:", (*this_).x ); TRACE_INFO_INT( "- y:", (*this_).y ); } /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/util/geometry/geometry_rectangle.h000066400000000000000000000344511415120503000266670ustar00rootroot00000000000000/* File: geometry_rectangle.h; Copyright and License: see below */ #ifndef GEOMETRY_RECTANGLE_H #define GEOMETRY_RECTANGLE_H /* public file for the doxygen documentation: */ /*! * \file * \brief Stores coordinates of a rectangle */ #include "util/geometry/geometry_point.h" #include "util/geometry/geometry_dimensions.h" #include /*! * \brief attributes of a rectangle */ struct geometry_rectangle_struct { double left; double top; double width; double height; }; typedef struct geometry_rectangle_struct geometry_rectangle_t; /*! * \brief initializes the geometry_rectangle_t struct * * \param this_ pointer to own object attributes * \param left left coordinate of the rectangle * \param top top coordinate of the rectangle * \param width width of the rectangle * \param height height of the rectangle */ static inline void geometry_rectangle_init ( geometry_rectangle_t *this_, double left, double top, double width, double height ); /*! * \brief re-initializes the geometry_rectangle_t struct * * \param this_ pointer to own object attributes * \param left left coordinate of the rectangle * \param top top coordinate of the rectangle * \param width width of the rectangle * \param height height of the rectangle */ static inline void geometry_rectangle_reinit ( geometry_rectangle_t *this_, double left, double top, double width, double height ); /*! * \brief copies original to this uninitialized geometry_rectangle_t struct * * \param this_ pointer to own object attributes * \param original pointer to object attributes that shall be copied */ static inline void geometry_rectangle_copy ( geometry_rectangle_t *this_, const geometry_rectangle_t *original ); /*! * \brief moves original to this uninitialized geometry_rectangle_t struct * * \param this_ pointer to own object attributes * \param that pointer to object attributes that shall be moved */ static inline void geometry_rectangle_move ( geometry_rectangle_t *this_, geometry_rectangle_t *that ); /*! * \brief replaces the already initialized geometry_rectangle_t struct by other data * * \param this_ pointer to own object attributes * \param original pointer to object attributes that shall be copied */ static inline void geometry_rectangle_replace ( geometry_rectangle_t *this_, const geometry_rectangle_t *original ); /*! * \brief replaces the already initialized geometry_rectangle_t struct by other data to be moved there * * \param this_ pointer to own object attributes * \param that pointer to object attributes that shall be copied */ static inline void geometry_rectangle_replacemove ( geometry_rectangle_t *this_, geometry_rectangle_t *that ); /*! * \brief initializes the geometry_rectangle_t struct to an empty rect at position 0,0 * * \param this_ pointer to own object attributes */ static inline void geometry_rectangle_init_empty ( geometry_rectangle_t *this_ ); /*! * \brief re-initializes the geometry_rectangle_t struct to an empty rect at position 0,0 * * \param this_ pointer to own object attributes */ static inline void geometry_rectangle_reinit_empty ( geometry_rectangle_t *this_ ); /*! * \brief initializes the geometry_rectangle_t struct by the intersect of a and b * * It is valid if parameters this_ and/or rect_a and/or rect_b are identical (same pointer). * * \param this_ pointer to own object attributes * \param rect_a rectangle a. Must not be NULL * \param rect_b rectangle b. Must not be NULL * \return 0 in case of success, -1 if the rectangles a and b do not overlap (touching is intersecting) */ static inline int geometry_rectangle_init_by_intersect ( geometry_rectangle_t *this_, const geometry_rectangle_t *rect_a, const geometry_rectangle_t *rect_b ); /*! * \brief initializes the geometry_rectangle_t struct by the minimum bounding box of a and b (similar to a convex hull) * * It is valid if parameters this_ and/or rect_a and/or rect_b are identical (same pointer). * * \param this_ pointer to own object attributes * \param rect_a rectangle a. Must not be NULL * \param rect_b rectangle b. Must not be NULL * \return 0 in case of success (always) */ static inline int geometry_rectangle_init_by_bounds ( geometry_rectangle_t *this_, const geometry_rectangle_t *rect_a, const geometry_rectangle_t *rect_b ); /*! * \brief initializes the geometry_rectangle_t struct by providing two corner coordinates * * \param this_ pointer to own object attributes * \param x1 x coordinate of a corner * \param y1 y coordinate of a corner * \param x2 x coordinate of a corner * \param y2 y coordinate of a corner */ static inline void geometry_rectangle_init_by_corners ( geometry_rectangle_t *this_, double x1, double y1, double x2, double y2 ); /*! * \brief initializes the geometry_rectangle_t struct by the difference of a minus b. * * If the difference is not a rectangle, the algorithm chooses the maximum contained rectange. * * It is valid if parameters this_ and/or rect_a and/or rect_b are identical (same pointer). * * \param this_ pointer to own object attributes * \param rect_a rectangle a. Must not be NULL * \param rect_b rectangle b. Must not be NULL * \return 0 in case of success (always) */ int geometry_rectangle_init_by_difference ( geometry_rectangle_t *this_, const geometry_rectangle_t *rect_a, const geometry_rectangle_t *rect_b ); /*! * \brief destroys the geometry_rectangle_t struct * * \param this_ pointer to own object attributes */ static inline void geometry_rectangle_destroy ( geometry_rectangle_t *this_ ); /*! * \brief gets the left coordinate of geometry_rectangle_t * * \param this_ pointer to own object attributes */ static inline double geometry_rectangle_get_left ( const geometry_rectangle_t *this_ ); /*! * \brief gets the top coordinate of geometry_rectangle_t * * \param this_ pointer to own object attributes */ static inline double geometry_rectangle_get_top ( const geometry_rectangle_t *this_ ); /*! * \brief gets the right coordinate of geometry_rectangle_t * * \param this_ pointer to own object attributes */ static inline double geometry_rectangle_get_right ( const geometry_rectangle_t *this_ ); /*! * \brief gets the bottom coordinate of geometry_rectangle_t * * \param this_ pointer to own object attributes */ static inline double geometry_rectangle_get_bottom ( const geometry_rectangle_t *this_ ); /*! * \brief gets the width of geometry_rectangle_t * * \param this_ pointer to own object attributes */ static inline double geometry_rectangle_get_width ( const geometry_rectangle_t *this_ ); /*! * \brief gets the height of geometry_rectangle_t * * \param this_ pointer to own object attributes */ static inline double geometry_rectangle_get_height ( const geometry_rectangle_t *this_ ); /*! * \brief gets the x-center of geometry_rectangle_t * * \param this_ pointer to own object attributes */ static inline double geometry_rectangle_get_center_x ( const geometry_rectangle_t *this_ ); /*! * \brief gets the y-center of geometry_rectangle_t * * \param this_ pointer to own object attributes */ static inline double geometry_rectangle_get_center_y ( const geometry_rectangle_t *this_ ); /*! * \brief gets the center of geometry_rectangle_t * * \param this_ pointer to own object attributes */ static inline geometry_point_t geometry_rectangle_get_center ( const geometry_rectangle_t *this_ ); /*! * \brief gets the dimensions of geometry_rectangle_t * * \param this_ pointer to own object attributes * \return dimensions (width and height) of the rectangle */ static inline geometry_dimensions_t geometry_rectangle_get_dimensions ( const geometry_rectangle_t *this_ ); /*! * \brief gets the area-value of geometry_rectangle_t * * \param this_ pointer to own object attributes * \return space within the rectangle. */ static inline double geometry_rectangle_get_area ( const geometry_rectangle_t *this_ ); /*! * \brief determines if a given coordinate is within geometry_rectangle_t * * \param this_ pointer to own object attributes * \param x x coordinate * \param y y coordinate * \return true if the location is within the rectangle. */ static inline bool geometry_rectangle_contains ( const geometry_rectangle_t *this_, double x, double y ); /*! * \brief determines if the given rectangle has a valid (positive) size * * \param this_ pointer to own object attributes * \return false if the rectangle has a positive size. */ static inline bool geometry_rectangle_is_empty ( const geometry_rectangle_t *this_ ); /*! * \brief determines if the given rectangle intersects the other (not just touching) * * \param this_ pointer to own object attributes * \param that pointer to others object attributes * \return false if the rectangle does not intersect the other. (touching is intersecting) */ static inline bool geometry_rectangle_is_intersecting ( const geometry_rectangle_t *this_, const geometry_rectangle_t *that ); /*! * \brief determines if the given rectangle touches or intersects the other * * \param this_ pointer to own object attributes * \param that pointer to others object attributes * \return false if the rectangle does not intersect the other. (touching is intersecting) */ static inline bool geometry_rectangle_is_contiguous ( const geometry_rectangle_t *this_, const geometry_rectangle_t *that ); /*! * \brief determines if the given rectangle contains the other * * \param this_ pointer to own object attributes * \param that pointer to others object attributes * \return false if the rectangle does not contain the other. (touching outside is still containing) */ static inline bool geometry_rectangle_is_containing ( const geometry_rectangle_t *this_, const geometry_rectangle_t *that ); /*! * \brief determines the chess-distance/manhattan-distance of a given coordinate to this geometry_rectangle_t * * \param this_ pointer to own object attributes * \param x x coordinate * \param y y coordinate * \return chess-distance from x/y to the rectangle; 0.0 if x/y is contained. */ static inline double geometry_rectangle_calc_chess_distance ( const geometry_rectangle_t *this_, double x, double y ); /*! * \brief gets the intersect area of two geometry_rectangle_t * * \param this_ pointer to own object attributes * \param that pointer to others object attributes * \return space within the instersect of the rectangles. */ static inline double geometry_rectangle_get_intersect_area ( const geometry_rectangle_t *this_, const geometry_rectangle_t *that ); /*! * \brief moves the geometry_rectangle_t * * \param this_ pointer to own object attributes * \param delta_x delta-x difference by which to shift the rectangle * \param delta_y delta-y difference by which to shift the rectangle */ static inline void geometry_rectangle_shift ( geometry_rectangle_t *this_, double delta_x, double delta_y ); /*! * \brief expands or shrinks the geometry_rectangle_t * * The top left corner remains fix. * * \param this_ pointer to own object attributes * \param delta_width value by which to increase the width. In case of a negative value, the rectangle shrinks (but not below 0). * \param delta_height value by which to increase the height. In case of a negative value, the rectangle shrinks (but not below 0). */ static inline void geometry_rectangle_enlarge ( geometry_rectangle_t *this_, double delta_width, double delta_height ); /*! * \brief expands or shrinks the geometry_rectangle_t to all sides * * The center remains fix. * * \param this_ pointer to own object attributes * \param delta_width value by which to increase the width twice. * In case of a negative value, the rectangle shrinks (but not below 0). * The left side moves to left by delta_width. * \param delta_height value by which to increase the height twice. * In case of a negative value, the rectangle shrinks (but not below 0). * The top side moves to top by delta_height. */ static inline void geometry_rectangle_expand_4dir ( geometry_rectangle_t *this_, double delta_width, double delta_height ); /*! * \brief sets the left coordinate of geometry_rectangle_t * * \param this_ pointer to own object attributes * \param left new left value */ static inline void geometry_rectangle_set_left ( geometry_rectangle_t *this_, double left ); /*! * \brief sets the top coordinate of geometry_rectangle_t * * \param this_ pointer to own object attributes * \param top new top value */ static inline void geometry_rectangle_set_top ( geometry_rectangle_t *this_, double top ); /*! * \brief sets the width of geometry_rectangle_t * * \param this_ pointer to own object attributes * \param width new width value */ static inline void geometry_rectangle_set_width ( geometry_rectangle_t *this_, double width ); /*! * \brief sets the height of geometry_rectangle_t * * \param this_ pointer to own object attributes * \param height new heigth value */ static inline void geometry_rectangle_set_height ( geometry_rectangle_t *this_, double height ); /*! * \brief prints the geometry_rectangle_t struct to the trace output * * \param this_ pointer to own object attributes */ static inline void geometry_rectangle_trace ( const geometry_rectangle_t *this_ ); #include "util/geometry/geometry_rectangle.inl" #endif /* GEOMETRY_RECTANGLE_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/util/geometry/geometry_rectangle.inl000066400000000000000000000302321415120503000272130ustar00rootroot00000000000000/* File: geometry_rectangle.inl; Copyright and License: see below */ #include "trace.h" #include "tslog.h" #include #include static inline void geometry_rectangle_init ( geometry_rectangle_t *this_, double left, double top, double width, double height ) { (*this_).left = left; (*this_).top = top; (*this_).width = width; (*this_).height = height; } static inline void geometry_rectangle_reinit ( geometry_rectangle_t *this_, double left, double top, double width, double height ) { (*this_).left = left; (*this_).top = top; (*this_).width = width; (*this_).height = height; } static inline void geometry_rectangle_copy ( geometry_rectangle_t *this_, const geometry_rectangle_t *original ) { assert( NULL != original ); (*this_) = (*original); } static inline void geometry_rectangle_move ( geometry_rectangle_t *this_, geometry_rectangle_t *that ) { assert( NULL != that ); (*this_) = (*that); } static inline void geometry_rectangle_replace ( geometry_rectangle_t *this_, const geometry_rectangle_t *original ) { assert( NULL != original ); (*this_) = (*original); } static inline void geometry_rectangle_replacemove ( geometry_rectangle_t *this_, geometry_rectangle_t *that ) { assert( NULL != that ); (*this_) = (*that); } static inline void geometry_rectangle_init_empty ( geometry_rectangle_t *this_ ) { (*this_).left = 0.0; (*this_).top = 0.0; (*this_).width = 0.0; (*this_).height = 0.0; } static inline void geometry_rectangle_reinit_empty ( geometry_rectangle_t *this_ ) { (*this_).left = 0.0; (*this_).top = 0.0; (*this_).width = 0.0; (*this_).height = 0.0; } static inline int geometry_rectangle_init_by_intersect ( geometry_rectangle_t *this_, const geometry_rectangle_t *rect_a, const geometry_rectangle_t *rect_b ) { assert( NULL != rect_a ); assert( NULL != rect_b ); int result = 0; const double rect_a_right = (*rect_a).left + (*rect_a).width; const double rect_a_bottom = (*rect_a).top + (*rect_a).height; const double rect_b_right = (*rect_b).left + (*rect_b).width; const double rect_b_bottom = (*rect_b).top + (*rect_b).height; (*this_).left = fmax( (*rect_a).left, (*rect_b).left ); (*this_).top = fmax( (*rect_a).top, (*rect_b).top ); (*this_).width = fmin( rect_a_right, rect_b_right ) - (*this_).left; (*this_).height = fmin( rect_a_bottom, rect_b_bottom ) - (*this_).top; if (( (*this_).width < -0.000000001 ) || ( (*this_).height < -0.000000001 )) { /* if intersection is empty, result is -1 */ (*this_).left = 0.0; (*this_).top = 0.0; (*this_).width = 0.0; (*this_).height = 0.0; result = -1; } else if (( (*this_).width < 0.0 ) || ( (*this_).height < 0.0 )) { /* update rounding error */ (*this_).width = 0.0; (*this_).height = 0.0; } return result; } static inline int geometry_rectangle_init_by_bounds ( geometry_rectangle_t *this_, const geometry_rectangle_t *rect_a, const geometry_rectangle_t *rect_b ) { assert( NULL != rect_a ); assert( NULL != rect_b ); int result = 0; const double rect_a_right = (*rect_a).left + (*rect_a).width; const double rect_a_bottom = (*rect_a).top + (*rect_a).height; const double rect_b_right = (*rect_b).left + (*rect_b).width; const double rect_b_bottom = (*rect_b).top + (*rect_b).height; (*this_).left = fmin( (*rect_a).left, (*rect_b).left ); (*this_).top = fmin( (*rect_a).top, (*rect_b).top ); (*this_).width = fmax( rect_a_right, rect_b_right ) - (*this_).left; (*this_).height = fmax( rect_a_bottom, rect_b_bottom ) - (*this_).top; return result; } static inline bool geometry_rectangle_is_intersecting ( const geometry_rectangle_t *this_, const geometry_rectangle_t *that ) { assert( NULL != that ); bool result; const double rect_this_right = (*this_).left + (*this_).width; const double rect_this_bottom = (*this_).top + (*this_).height; const double rect_that_right = (*that).left + (*that).width; const double rect_that_bottom = (*that).top + (*that).height; if ( ( rect_this_right < (*that).left + 0.000000001 ) || ( rect_this_bottom < (*that).top + 0.000000001 ) || ( (*this_).left + 0.000000001 > rect_that_right ) || ( (*this_).top + 0.000000001 > rect_that_bottom ) ) { result = false; } else { result = true; } return result; } static inline bool geometry_rectangle_is_contiguous ( const geometry_rectangle_t *this_, const geometry_rectangle_t *that ) { assert( NULL != that ); bool result; const double rect_this_right = (*this_).left + (*this_).width; const double rect_this_bottom = (*this_).top + (*this_).height; const double rect_that_right = (*that).left + (*that).width; const double rect_that_bottom = (*that).top + (*that).height; if ( ( rect_this_right + 0.000000001 < (*that).left ) || ( rect_this_bottom + 0.000000001 < (*that).top ) || ( (*this_).left > rect_that_right + 0.000000001 ) || ( (*this_).top > rect_that_bottom + 0.000000001 ) ) { result = false; } else { result = true; } return result; } static inline bool geometry_rectangle_is_containing ( const geometry_rectangle_t *this_, const geometry_rectangle_t *that ) { assert( NULL != that ); bool result; const double rect_this_right = (*this_).left + (*this_).width; const double rect_this_bottom = (*this_).top + (*this_).height; const double rect_that_right = (*that).left + (*that).width; const double rect_that_bottom = (*that).top + (*that).height; if ( ( (*this_).left < (*that).left + 0.000000001 ) /* touching is containing */ && ( (*this_).top < (*that).top + 0.000000001 ) && ( rect_this_right + 0.000000001 > rect_that_right ) && ( rect_this_bottom + 0.000000001 > rect_that_bottom ) ) { result = true; } else { result = false; } return result; } static inline void geometry_rectangle_init_by_corners ( geometry_rectangle_t *this_, double x1, double y1, double x2, double y2 ) { if ( x1 < x2 ) { (*this_).left = x1; (*this_).width = x2-x1; } else { (*this_).left = x2; (*this_).width = x1-x2; } if ( y1 < y2 ) { (*this_).top = y1; (*this_).height = y2-y1; } else { (*this_).top = y2; (*this_).height = y1-y2; } } static inline void geometry_rectangle_destroy ( geometry_rectangle_t *this_ ) { } static inline double geometry_rectangle_get_left ( const geometry_rectangle_t *this_ ) { return (*this_).left; } static inline double geometry_rectangle_get_top ( const geometry_rectangle_t *this_ ) { return (*this_).top; } static inline double geometry_rectangle_get_right ( const geometry_rectangle_t *this_ ) { return (*this_).left + (*this_).width; } static inline double geometry_rectangle_get_bottom ( const geometry_rectangle_t *this_ ) { return (*this_).top + (*this_).height; } static inline double geometry_rectangle_get_width ( const geometry_rectangle_t *this_ ) { return (*this_).width; } static inline double geometry_rectangle_get_height ( const geometry_rectangle_t *this_ ) { return (*this_).height; } static inline double geometry_rectangle_get_center_x ( const geometry_rectangle_t *this_ ) { return (*this_).left + 0.5*(*this_).width; } static inline double geometry_rectangle_get_center_y ( const geometry_rectangle_t *this_ ) { return (*this_).top + 0.5*(*this_).height; } static inline geometry_point_t geometry_rectangle_get_center ( const geometry_rectangle_t *this_ ) { geometry_point_t result; geometry_point_init ( &result, (*this_).left + 0.5*(*this_).width, (*this_).top + 0.5*(*this_).height ); return result; } static inline geometry_dimensions_t geometry_rectangle_get_dimensions ( const geometry_rectangle_t *this_ ) { geometry_dimensions_t result; geometry_dimensions_init ( &result, (*this_).width, (*this_).height ); return result; } static inline double geometry_rectangle_get_area ( const geometry_rectangle_t *this_ ) { return (*this_).width * (*this_).height; } static inline bool geometry_rectangle_contains ( const geometry_rectangle_t *this_, double x, double y ) { return (( (*this_).left <= x )&&( x < (*this_).left + (*this_).width )&&( (*this_).top <= y )&&( y < (*this_).top + (*this_).height )); } static inline double geometry_rectangle_calc_chess_distance ( const geometry_rectangle_t *this_, double x, double y ) { double result = 0.0; if ( x < (*this_).left ) { result += ( (*this_).left - x ); } else if ( x > (*this_).left + (*this_).width ) { result += ( x - ((*this_).left + (*this_).width) ); } if ( y < (*this_).top ) { result += ( (*this_).top - y ); } else if ( y > (*this_).top + (*this_).height ) { result += ( y - ((*this_).top + (*this_).height) ); } return result; } static inline bool geometry_rectangle_is_empty ( const geometry_rectangle_t *this_ ) { return ( ( (*this_).width < 0.000000001 )||( (*this_).height < 0.000000001 ) ); } static inline double geometry_rectangle_get_intersect_area ( const geometry_rectangle_t *this_, const geometry_rectangle_t *that ) { geometry_rectangle_t intersect; geometry_rectangle_init_by_intersect( &intersect, this_, that ); return geometry_rectangle_get_area(&intersect); } static inline void geometry_rectangle_shift ( geometry_rectangle_t *this_, double delta_x, double delta_y ) { (*this_).left += delta_x; (*this_).top += delta_y; } static inline void geometry_rectangle_enlarge ( geometry_rectangle_t *this_, double delta_width, double delta_height ) { (*this_).width += delta_width; if ( (*this_).width < 0.0 ) { (*this_).width = 0.0; } (*this_).height += delta_height; if ( (*this_).height < 0.0 ) { (*this_).height = 0.0; } } static inline void geometry_rectangle_expand_4dir ( geometry_rectangle_t *this_, double delta_width, double delta_height ) { const double double_delta_width = 2.0 * delta_width; (*this_).width += double_delta_width; (*this_).left -= delta_width; if ( (*this_).width < 0.0 ) { (*this_).left += 0.5 * (*this_).width; (*this_).width = 0.0; } const double double_delta_height = 2.0 * delta_height; (*this_).height += double_delta_height; (*this_).top -= delta_height; if ( (*this_).height < 0.0 ) { (*this_).top += 0.5 * (*this_).height; (*this_).height = 0.0; } } static inline void geometry_rectangle_set_left ( geometry_rectangle_t *this_, double left ) { (*this_).left = left; } static inline void geometry_rectangle_set_top ( geometry_rectangle_t *this_, double top ) { (*this_).top = top; } static inline void geometry_rectangle_set_width ( geometry_rectangle_t *this_, double width ) { (*this_).width = width; } static inline void geometry_rectangle_set_height ( geometry_rectangle_t *this_, double height ) { (*this_).height = height; } static inline void geometry_rectangle_trace ( const geometry_rectangle_t *this_ ) { TRACE_INFO( "geometry_rectangle_t" ); TRACE_INFO_INT( "- left:", (*this_).left ); TRACE_INFO_INT( "- top:", (*this_).top ); TRACE_INFO_INT( "- width:", (*this_).width ); TRACE_INFO_INT( "- height:", (*this_).height ); } /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/util/geometry/geometry_v_align.h000066400000000000000000000034401415120503000263340ustar00rootroot00000000000000/* File: geometry_v_align.h; Copyright and License: see below */ #ifndef GEOMETRY_V_ALIGN_H #define GEOMETRY_V_ALIGN_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines the vertical alignment of geometry objects */ /*! * \brief alignment constants of vertical alignment * */ enum geometry_v_align_enum { GEOMETRY_V_ALIGN_TOP, GEOMETRY_V_ALIGN_CENTER, GEOMETRY_V_ALIGN_BOTTOM, }; typedef enum geometry_v_align_enum geometry_v_align_t; /*! * \brief gets the top coordinate of an aligned object * * \param this_ pointer to own object attributes * \param height height of object to be aligned * \param reference_top top coordinate of object to which to align to * \param reference_height height of object to which to align to * \return top coordinate of aligned object */ static inline double geometry_v_align_get_top ( const geometry_v_align_t *this_, double height, double reference_top, double reference_height ); #include "util/geometry/geometry_v_align.inl" #endif /* GEOMETRY_V_ALIGN_H */ /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/include/util/geometry/geometry_v_align.inl000066400000000000000000000026621415120503000266740ustar00rootroot00000000000000/* File: geometry_v_align.inl; Copyright and License: see below */ #include "trace.h" #include "tslog.h" static inline double geometry_v_align_get_top ( const geometry_v_align_t *this_, double height, double reference_top, double reference_height ) { double top; switch ( *this_ ) { case GEOMETRY_V_ALIGN_TOP: { top = reference_top; } break; case GEOMETRY_V_ALIGN_CENTER: { top = reference_top + 0.5 * ( reference_height - height ); } break; case GEOMETRY_V_ALIGN_BOTTOM: { top = reference_top + reference_height - height; } break; default: { TSLOG_ERROR("unknown geometry_v_align_t in geometry_v_align_get_top()"); assert(0); top = 0.0; } break; } return top; } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/000077500000000000000000000000001415120503000176755ustar00rootroot00000000000000crystal-facet-uml-1.34.1/pencil/source/draw/000077500000000000000000000000001415120503000206325ustar00rootroot00000000000000crystal-facet-uml-1.34.1/pencil/source/draw/draw_classifier_contour.c000066400000000000000000000714111415120503000257140ustar00rootroot00000000000000/* File: draw_classifier_contour.c; Copyright and License: see below */ #include "draw/draw_classifier_contour.h" #include "draw/draw_classifier_icon.h" #include "trace.h" #include #include #include /*! where to place the control points of a bezier curve to get a good approximation for a 90 degree curve */ const static double BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE = 0.552284749831; const static double SINUS_OF_45_DEGREE = 0.707106781; geometry_rectangle_t draw_classifier_contour_calc_inner_area ( const draw_classifier_contour_t *this_, data_classifier_type_t classifier_type, const geometry_rectangle_t *outer_bounds, const pencil_size_t *pencil_size ) { TRACE_BEGIN(); assert ( NULL != outer_bounds ); assert ( NULL != pencil_size ); geometry_rectangle_t result; geometry_rectangle_init_empty( &result ); double gap = pencil_size_get_standard_object_border( pencil_size ); double double_gap = 2.0 * gap; /* a line has the gap distance on both sides to the next object */ switch ( classifier_type ) { case DATA_CLASSIFIER_TYPE_USE_CASE: { /* within a use case, space is limited (double_gap is the border on each side): */ double inner_x_radius = 0.5 * geometry_rectangle_get_width( outer_bounds ) - double_gap; double inner_y_radius = 0.5 * geometry_rectangle_get_height( outer_bounds ) - double_gap; double h_offset = (1.0 - SINUS_OF_45_DEGREE) * inner_x_radius; double v_offset = (1.0 - SINUS_OF_45_DEGREE) * inner_y_radius; geometry_rectangle_replace( &result, outer_bounds ); geometry_rectangle_expand_4dir( &result, -double_gap - h_offset, -double_gap - v_offset ); } break; case DATA_CLASSIFIER_TYPE_NODE: { /* the 3d border of a node shrinks the space */ double offset_3d = double_gap; geometry_rectangle_replace( &result, outer_bounds ); geometry_rectangle_enlarge( &result, -2.0 * double_gap - offset_3d, -2.0 * double_gap - offset_3d ); geometry_rectangle_shift( &result, double_gap, double_gap + offset_3d ); } break; case DATA_CLASSIFIER_TYPE_ACTOR: case DATA_CLASSIFIER_TYPE_DYN_INITIAL_NODE: case DATA_CLASSIFIER_TYPE_DYN_FINAL_NODE: case DATA_CLASSIFIER_TYPE_DYN_FORK_NODE: case DATA_CLASSIFIER_TYPE_DYN_JOIN_NODE: case DATA_CLASSIFIER_TYPE_DYN_SHALLOW_HISTORY: case DATA_CLASSIFIER_TYPE_DYN_DEEP_HISTORY: case DATA_CLASSIFIER_TYPE_DYN_ACCEPT_TIME_EVENT: { /* the symbol icon height is part of the shape border */ double symbol_icon_height = pencil_size_get_classifier_symbol_height( pencil_size ); geometry_rectangle_replace( &result, outer_bounds ); geometry_rectangle_enlarge( &result, -2.0 * double_gap, -2.0 * double_gap - symbol_icon_height ); geometry_rectangle_shift( &result, double_gap, double_gap + symbol_icon_height ); } break; case DATA_CLASSIFIER_TYPE_DIAGRAM_REFERENCE: /* and */ case DATA_CLASSIFIER_TYPE_INTERACTION: /* and */ case DATA_CLASSIFIER_TYPE_PACKAGE: { double top_ornament_height = pencil_size_get_standard_font_size( pencil_size ); geometry_rectangle_replace( &result, outer_bounds ); geometry_rectangle_enlarge( &result, -2.0 * double_gap, -2.0 * double_gap - top_ornament_height ); geometry_rectangle_shift( &result, double_gap, double_gap + top_ornament_height ); } break; case DATA_CLASSIFIER_TYPE_BLOCK: case DATA_CLASSIFIER_TYPE_REQUIREMENT: case DATA_CLASSIFIER_TYPE_DEPRECATED_FEATURE: case DATA_CLASSIFIER_TYPE_SUBSYSTEM: case DATA_CLASSIFIER_TYPE_ACTIVITY: case DATA_CLASSIFIER_TYPE_STATE: case DATA_CLASSIFIER_TYPE_COMPONENT: case DATA_CLASSIFIER_TYPE_PART: case DATA_CLASSIFIER_TYPE_INTERFACE: case DATA_CLASSIFIER_TYPE_CLASS: case DATA_CLASSIFIER_TYPE_OBJECT: case DATA_CLASSIFIER_TYPE_ARTIFACT: case DATA_CLASSIFIER_TYPE_COMMENT: case DATA_CLASSIFIER_TYPE_CONSTRAINT_BLOCK: case DATA_CLASSIFIER_TYPE_DYN_INTERRUPTABLE_REGION: { /* standard size */ geometry_rectangle_replace( &result, outer_bounds ); geometry_rectangle_expand_4dir( &result, -double_gap, -double_gap ); } break; case DATA_CLASSIFIER_TYPE_DYN_DECISION_NODE: { /* within a decision rhombus, space is limited by factor 2 per dimension: */ double half_outer_width = 0.5 * geometry_rectangle_get_width( outer_bounds ) - double_gap; double half_outer_height = 0.5 * geometry_rectangle_get_height( outer_bounds ) - double_gap; double h_offset = 0.5 * half_outer_width; double v_offset = 0.5 * half_outer_height; geometry_rectangle_replace( &result, outer_bounds ); geometry_rectangle_expand_4dir( &result, -double_gap - h_offset, -double_gap - v_offset ); } break; case DATA_CLASSIFIER_TYPE_DYN_ACCEPT_EVENT : { /* within an accept event, space is limited (double_gap is the border on each side): */ double half_outer_height = 0.5 * geometry_rectangle_get_height( outer_bounds ) - double_gap; double horizontal_offset = half_outer_height; geometry_rectangle_replace( &result, outer_bounds ); geometry_rectangle_enlarge( &result, -2.0 * double_gap - horizontal_offset, -2.0 * double_gap ); geometry_rectangle_shift( &result, double_gap + horizontal_offset, double_gap ); } break; case DATA_CLASSIFIER_TYPE_DYN_SEND_SIGNAL: { /* within a send signal, space is limited (double_gap is the border on each side): */ double half_outer_height = 0.5 * geometry_rectangle_get_height( outer_bounds ) - double_gap; double horizontal_offset = half_outer_height; geometry_rectangle_replace( &result, outer_bounds ); geometry_rectangle_enlarge( &result, -2.0 * double_gap - horizontal_offset, -2.0 * double_gap ); geometry_rectangle_shift( &result, double_gap, double_gap ); } break; default: { TSLOG_ERROR("unknown data_classifier_type_t in draw_classifier_contour_get_shape_border_dimensions()"); } break; } TRACE_END(); return result; } geometry_rectangle_t draw_classifier_contour_calc_outer_bounds ( const draw_classifier_contour_t *this_, data_classifier_type_t classifier_type, const geometry_rectangle_t *inner_area, const pencil_size_t *pencil_size ) { TRACE_BEGIN(); assert ( NULL != inner_area ); assert ( NULL != pencil_size ); geometry_rectangle_t result; geometry_rectangle_init_empty( &result ); double gap = pencil_size_get_standard_object_border( pencil_size ); double double_gap = 2.0 * gap; /* a line has the gap distance on both sides to the next object */ switch ( classifier_type ) { case DATA_CLASSIFIER_TYPE_USE_CASE: { /* within a use case, space is limited (double_gap is the border on each side): */ double half_inner_width = 0.5 * geometry_rectangle_get_width( inner_area ); double half_inner_height = 0.5 * geometry_rectangle_get_height( inner_area ); double h_offset = half_inner_width * ( 1.0 / SINUS_OF_45_DEGREE - 1.0 ); double v_offset = half_inner_height * ( 1.0 / SINUS_OF_45_DEGREE - 1.0 ); geometry_rectangle_replace( &result, inner_area ); geometry_rectangle_expand_4dir( &result, +double_gap + h_offset, +double_gap + v_offset ); } break; case DATA_CLASSIFIER_TYPE_NODE: { /* the 3d border of a node shrinks the space */ double offset_3d = double_gap; geometry_rectangle_replace( &result, inner_area ); geometry_rectangle_enlarge( &result, +2.0 * double_gap + offset_3d, +2.0 * double_gap + offset_3d ); geometry_rectangle_shift( &result, -double_gap, -double_gap - offset_3d ); } break; case DATA_CLASSIFIER_TYPE_ACTOR: case DATA_CLASSIFIER_TYPE_DYN_INITIAL_NODE: case DATA_CLASSIFIER_TYPE_DYN_FINAL_NODE: case DATA_CLASSIFIER_TYPE_DYN_FORK_NODE: case DATA_CLASSIFIER_TYPE_DYN_JOIN_NODE: case DATA_CLASSIFIER_TYPE_DYN_SHALLOW_HISTORY: case DATA_CLASSIFIER_TYPE_DYN_DEEP_HISTORY: case DATA_CLASSIFIER_TYPE_DYN_ACCEPT_TIME_EVENT: { /* the symbol icon height is part of the shape border */ double symbol_icon_height = pencil_size_get_classifier_symbol_height( pencil_size ); geometry_rectangle_replace( &result, inner_area ); geometry_rectangle_enlarge( &result, +2.0 * double_gap, +2.0 * double_gap + symbol_icon_height ); geometry_rectangle_shift( &result, -double_gap, -double_gap - symbol_icon_height ); } break; case DATA_CLASSIFIER_TYPE_DIAGRAM_REFERENCE: /* and */ case DATA_CLASSIFIER_TYPE_INTERACTION: /* and */ case DATA_CLASSIFIER_TYPE_PACKAGE: { double top_ornament_height = pencil_size_get_standard_font_size( pencil_size ); geometry_rectangle_replace( &result, inner_area ); geometry_rectangle_enlarge( &result, +2.0 * double_gap, +2.0 * double_gap + top_ornament_height ); geometry_rectangle_shift( &result, -double_gap, -double_gap - top_ornament_height ); } break; case DATA_CLASSIFIER_TYPE_BLOCK: case DATA_CLASSIFIER_TYPE_REQUIREMENT: case DATA_CLASSIFIER_TYPE_DEPRECATED_FEATURE: case DATA_CLASSIFIER_TYPE_SUBSYSTEM: case DATA_CLASSIFIER_TYPE_ACTIVITY: case DATA_CLASSIFIER_TYPE_STATE: case DATA_CLASSIFIER_TYPE_COMPONENT: case DATA_CLASSIFIER_TYPE_PART: case DATA_CLASSIFIER_TYPE_INTERFACE: case DATA_CLASSIFIER_TYPE_CLASS: case DATA_CLASSIFIER_TYPE_OBJECT: case DATA_CLASSIFIER_TYPE_ARTIFACT: case DATA_CLASSIFIER_TYPE_COMMENT: case DATA_CLASSIFIER_TYPE_CONSTRAINT_BLOCK: case DATA_CLASSIFIER_TYPE_DYN_INTERRUPTABLE_REGION: { /* standard size */ geometry_rectangle_replace( &result, inner_area ); geometry_rectangle_expand_4dir( &result, +double_gap, +double_gap ); } break; case DATA_CLASSIFIER_TYPE_DYN_DECISION_NODE: { /* within a decision rhombus, space is limited by factor 2 per dimension: */ double half_inner_width = 0.5 * geometry_rectangle_get_width( inner_area ); double half_inner_height = 0.5 * geometry_rectangle_get_height( inner_area ); double h_offset = half_inner_width; double v_offset = half_inner_height; geometry_rectangle_replace( &result, inner_area ); geometry_rectangle_expand_4dir( &result, +double_gap + h_offset, +double_gap + v_offset ); } break; case DATA_CLASSIFIER_TYPE_DYN_ACCEPT_EVENT : { /* within an accept event, space is limited (double_gap is the border on each side): */ double half_inner_height = 0.5 * geometry_rectangle_get_height( inner_area ); double horizontal_offset = half_inner_height; geometry_rectangle_replace( &result, inner_area ); geometry_rectangle_enlarge( &result, +2.0 * double_gap + horizontal_offset, +2.0 * double_gap ); geometry_rectangle_shift( &result, -double_gap - horizontal_offset, -double_gap ); } break; case DATA_CLASSIFIER_TYPE_DYN_SEND_SIGNAL: { /* within a send signal, space is limited (double_gap is the border on each side): */ double half_inner_height = 0.5 * geometry_rectangle_get_height( inner_area ); double horizontal_offset = half_inner_height; geometry_rectangle_replace( &result, inner_area ); geometry_rectangle_enlarge( &result, +2.0 * double_gap + horizontal_offset, +2.0 * double_gap ); geometry_rectangle_shift( &result, -double_gap, -double_gap ); } break; default: { TSLOG_ERROR("unknown data_classifier_type_t in draw_classifier_contour_get_shape_border_dimensions()"); } break; } TRACE_END(); return result; } void draw_classifier_contour_draw_rounded_rect ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, bool dashed_line, const pencil_size_t *pencil_size, cairo_t *cr ) { TRACE_BEGIN(); assert ( NULL != outer_bounds ); assert ( NULL != pencil_size ); assert ( NULL != cr ); const double gap = pencil_size_get_standard_object_border( pencil_size ); const double border_left = geometry_rectangle_get_left ( outer_bounds ) + gap; const double border_top = geometry_rectangle_get_top ( outer_bounds ) + gap; const double border_width = geometry_rectangle_get_width ( outer_bounds ) - gap - gap; const double border_height = geometry_rectangle_get_height ( outer_bounds ) - gap - gap; const double border_bottom = border_top + border_height; const double border_right = border_left + border_width; const double corner_radius = 6.0 * gap; const double ctrl_offset = corner_radius * (1.0-BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE); /* set dashes */ if ( dashed_line ) { double dashes[2]; dashes[0] = 2.0 * pencil_size_get_line_dash_length( pencil_size ); dashes[1] = 1.0 * pencil_size_get_line_dash_length( pencil_size ); cairo_set_dash ( cr, dashes, 2, 0.0 ); } cairo_move_to ( cr, border_right - corner_radius, border_bottom ); cairo_line_to ( cr, border_left + corner_radius, border_bottom ); cairo_curve_to ( cr, border_left + ctrl_offset, border_bottom, border_left, border_bottom - ctrl_offset, border_left /* end point x */, border_bottom - corner_radius /* end point y */ ); cairo_line_to ( cr, border_left, border_top + corner_radius ); cairo_curve_to ( cr, border_left, border_top + ctrl_offset, border_left + ctrl_offset, border_top, border_left + corner_radius /* end point x */, border_top /* end point y */ ); cairo_line_to ( cr, border_right - corner_radius, border_top ); cairo_curve_to ( cr, border_right - ctrl_offset, border_top, border_right, border_top + ctrl_offset, border_right /* end point x */, border_top + corner_radius /* end point y */ ); cairo_line_to ( cr, border_right, border_bottom - corner_radius ); cairo_curve_to ( cr, border_right, border_bottom - ctrl_offset, border_right - ctrl_offset, border_bottom, border_right - corner_radius /* end point x */, border_bottom /* end point y */ ); cairo_stroke (cr); /* reset dashes */ if ( dashed_line ) { cairo_set_dash ( cr, NULL, 0, 0.0 ); } TRACE_END(); } void draw_classifier_contour_draw_ellipse ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, const pencil_size_t *pencil_size, cairo_t *cr ) { TRACE_BEGIN(); assert ( NULL != outer_bounds ); assert ( NULL != pencil_size ); assert ( NULL != cr ); const double gap = pencil_size_get_standard_object_border( pencil_size ); const double border_left = geometry_rectangle_get_left ( outer_bounds ) + gap; const double border_top = geometry_rectangle_get_top ( outer_bounds ) + gap; const double border_width = geometry_rectangle_get_width ( outer_bounds ) - gap - gap; const double border_height = geometry_rectangle_get_height ( outer_bounds ) - gap - gap; const double border_bottom = border_top + border_height; const double border_right = border_left + border_width; const double half_width = 0.5 * border_width; const double half_height = 0.5 * border_height; const double center_x = border_left + half_width; const double center_y = border_top + half_height; const double ctrl_xoffset = half_width * (1.0-BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE); const double ctrl_yoffset = half_height * (1.0-BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE); cairo_move_to ( cr, center_x, border_bottom ); cairo_curve_to ( cr, border_left + ctrl_xoffset, border_bottom, border_left, border_bottom - ctrl_yoffset, border_left /* end point x */, center_y /* end point y */ ); cairo_curve_to ( cr, border_left, border_top + ctrl_yoffset, border_left + ctrl_xoffset, border_top, center_x /* end point x */, border_top /* end point y */ ); cairo_curve_to ( cr, border_right - ctrl_xoffset, border_top, border_right, border_top + ctrl_yoffset, border_right /* end point x */, center_y /* end point y */ ); cairo_curve_to ( cr, border_right, border_bottom - ctrl_yoffset, border_right - ctrl_xoffset, border_bottom, center_x /* end point x */, border_bottom /* end point y */ ); cairo_stroke (cr); TRACE_END(); } void draw_classifier_contour_draw_rhombus ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, const pencil_size_t *pencil_size, cairo_t *cr ) { TRACE_BEGIN(); assert ( NULL != outer_bounds ); assert ( NULL != pencil_size ); assert ( NULL != cr ); const double gap = pencil_size_get_standard_object_border( pencil_size ); const double border_left = geometry_rectangle_get_left ( outer_bounds ) + gap; const double border_top = geometry_rectangle_get_top ( outer_bounds ) + gap; const double border_width = geometry_rectangle_get_width ( outer_bounds ) - gap - gap; const double border_height = geometry_rectangle_get_height ( outer_bounds ) - gap - gap; const double border_bottom = border_top + border_height; const double border_right = border_left + border_width; const double center_x = geometry_rectangle_get_center_x ( outer_bounds ); const double center_y = geometry_rectangle_get_center_y ( outer_bounds ); cairo_move_to ( cr, center_x, border_bottom ); cairo_line_to ( cr, border_left, center_y ); cairo_line_to ( cr, center_x, border_top ); cairo_line_to ( cr, border_right, center_y ); cairo_line_to ( cr, center_x, border_bottom ); cairo_stroke (cr); TRACE_END(); } void draw_classifier_contour_draw_3d_box ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, const pencil_size_t *pencil_size, cairo_t *cr ) { TRACE_BEGIN(); assert ( NULL != outer_bounds ); assert ( NULL != pencil_size ); assert ( NULL != cr ); const double gap = pencil_size_get_standard_object_border( pencil_size ); const double border_left = geometry_rectangle_get_left ( outer_bounds ) + gap; const double border_top = geometry_rectangle_get_top ( outer_bounds ) + gap; const double border_width = geometry_rectangle_get_width ( outer_bounds ) - gap - gap; const double border_height = geometry_rectangle_get_height ( outer_bounds ) - gap - gap; const double border_bottom = border_top + border_height; const double border_right = border_left + border_width; const double offset_3d = 2.0*gap; cairo_rectangle ( cr, border_left, border_top+offset_3d, border_width-offset_3d, border_height-offset_3d ); cairo_stroke (cr); cairo_move_to ( cr, border_left, border_top+offset_3d ); cairo_line_to ( cr, border_left+offset_3d, border_top ); cairo_line_to ( cr, border_right, border_top ); cairo_line_to ( cr, border_right, border_bottom-offset_3d ); cairo_line_to ( cr, border_right-offset_3d, border_bottom ); cairo_stroke (cr); cairo_move_to ( cr, border_right, border_top ); cairo_line_to ( cr, border_right-offset_3d, border_top+offset_3d ); cairo_stroke (cr); TRACE_END(); } void draw_classifier_contour_draw_accept_event ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, const pencil_size_t *pencil_size, cairo_t *cr ) { TRACE_BEGIN(); assert ( NULL != outer_bounds ); assert ( NULL != pencil_size ); assert ( NULL != cr ); const double gap = pencil_size_get_standard_object_border( pencil_size ); const double border_left = geometry_rectangle_get_left ( outer_bounds ) + gap; const double border_top = geometry_rectangle_get_top ( outer_bounds ) + gap; const double border_width = geometry_rectangle_get_width ( outer_bounds ) - gap - gap; const double border_height = geometry_rectangle_get_height ( outer_bounds ) - gap - gap; const double border_bottom = border_top + border_height; const double border_right = border_left + border_width; const double center_y = geometry_rectangle_get_center_y ( outer_bounds ); const double x_indent = border_height / 2.0; cairo_move_to ( cr, border_right, border_bottom ); cairo_line_to ( cr, border_right, border_top ); cairo_line_to ( cr, border_left, border_top ); cairo_line_to ( cr, border_left + x_indent, center_y ); cairo_line_to ( cr, border_left, border_bottom ); cairo_line_to ( cr, border_right, border_bottom ); cairo_stroke (cr); TRACE_END(); } void draw_classifier_contour_draw_send_signal ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, const pencil_size_t *pencil_size, cairo_t *cr ) { TRACE_BEGIN(); assert ( NULL != outer_bounds ); assert ( NULL != pencil_size ); assert ( NULL != cr ); const double gap = pencil_size_get_standard_object_border( pencil_size ); const double border_left = geometry_rectangle_get_left ( outer_bounds ) + gap; const double border_top = geometry_rectangle_get_top ( outer_bounds ) + gap; const double border_width = geometry_rectangle_get_width ( outer_bounds ) - gap - gap; const double border_height = geometry_rectangle_get_height ( outer_bounds ) - gap - gap; const double border_bottom = border_top + border_height; const double border_right = border_left + border_width; const double center_y = geometry_rectangle_get_center_y ( outer_bounds ); const double x_indent = border_height / 2.0; cairo_move_to ( cr, border_right - x_indent, border_bottom ); cairo_line_to ( cr, border_right, center_y ); cairo_line_to ( cr, border_right - x_indent, border_top ); cairo_line_to ( cr, border_left, border_top ); cairo_line_to ( cr, border_left, border_bottom ); cairo_line_to ( cr, border_right - x_indent, border_bottom ); cairo_stroke (cr); TRACE_END(); } void draw_classifier_contour_draw_package ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, const geometry_rectangle_t *label_box, const pencil_size_t *pencil_size, cairo_t *cr ) { TRACE_BEGIN(); assert ( NULL != outer_bounds ); assert ( NULL != pencil_size ); assert ( NULL != cr ); const double gap = pencil_size_get_standard_object_border( pencil_size ); const double border_left = geometry_rectangle_get_left ( outer_bounds ) + gap; const double border_top = geometry_rectangle_get_top ( outer_bounds ) + gap; const double border_width = geometry_rectangle_get_width ( outer_bounds ) - gap - gap; const double border_height = geometry_rectangle_get_height ( outer_bounds ) - gap - gap; double tab_width; double tab_height; const bool label_in_tab = ( geometry_rectangle_get_top( label_box ) < (border_top + gap + gap) ); if ( label_in_tab ) { tab_width = geometry_rectangle_get_width ( label_box ) + gap + gap; tab_height = geometry_rectangle_get_height ( label_box ) + gap; } else { tab_width = border_width/3.0; tab_height = pencil_size_get_standard_font_size( pencil_size ); } cairo_rectangle ( cr, border_left, border_top, tab_width, tab_height ); cairo_rectangle ( cr, border_left, border_top+tab_height, border_width, border_height-tab_height ); cairo_stroke (cr); TRACE_END(); } void draw_classifier_contour_draw_diagram_ref ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, const pencil_size_t *pencil_size, cairo_t *cr ) { TRACE_BEGIN(); assert ( NULL != outer_bounds ); assert ( NULL != pencil_size ); assert ( NULL != cr ); const double gap = pencil_size_get_standard_object_border( pencil_size ); const double border_left = geometry_rectangle_get_left ( outer_bounds ) + gap; const double border_top = geometry_rectangle_get_top ( outer_bounds ) + gap; const double border_width = geometry_rectangle_get_width ( outer_bounds ) - gap - gap; const double border_height = geometry_rectangle_get_height ( outer_bounds ) - gap - gap; const double title_corner_height = pencil_size_get_standard_font_size( pencil_size ); const double title_corner_edge45 = 0.4 * title_corner_height; const double title_corner_width = border_width/5.0; cairo_rectangle ( cr, border_left, border_top, border_width, border_height ); cairo_move_to ( cr, border_left, border_top+title_corner_height ); cairo_line_to ( cr, border_left+title_corner_width - title_corner_edge45, border_top+title_corner_height ); cairo_line_to ( cr, border_left+title_corner_width, border_top+title_corner_height-title_corner_edge45 ); cairo_line_to ( cr, border_left+title_corner_width, border_top ); cairo_stroke (cr); TRACE_END(); } void draw_classifier_contour_draw_comment ( const draw_classifier_contour_t *this_, const geometry_rectangle_t *outer_bounds, const pencil_size_t *pencil_size, cairo_t *cr ) { TRACE_BEGIN(); assert ( NULL != outer_bounds ); assert ( NULL != pencil_size ); assert ( NULL != cr ); const double gap = pencil_size_get_standard_object_border( pencil_size ); const double border_left = geometry_rectangle_get_left ( outer_bounds ) + gap; const double border_top = geometry_rectangle_get_top ( outer_bounds ) + gap; const double border_width = geometry_rectangle_get_width ( outer_bounds ) - gap - gap; const double border_height = geometry_rectangle_get_height ( outer_bounds ) - gap - gap; const double corner_edge = pencil_size_get_standard_font_size( pencil_size ); const double border_bottom = border_top + border_height; const double border_right = border_left + border_width; cairo_move_to ( cr, border_right, border_top + corner_edge ); cairo_line_to ( cr, border_right - corner_edge, border_top + corner_edge ); cairo_line_to ( cr, border_right - corner_edge, border_top ); cairo_line_to ( cr, border_left, border_top ); cairo_line_to ( cr, border_left, border_bottom ); cairo_line_to ( cr, border_right, border_bottom ); cairo_line_to ( cr, border_right, border_top + corner_edge ); cairo_line_to ( cr, border_right - corner_edge, border_top ); cairo_stroke (cr); TRACE_END(); } /* Copyright 2016-2021 Andreas Warnke http://www.apache.org/licenses/LICENSE-2.0 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/draw/draw_classifier_icon.c000066400000000000000000000442601415120503000251550ustar00rootroot00000000000000/* File: draw_classifier_icon.c; Copyright and License: see below */ #include "draw/draw_classifier_icon.h" #include "pencil_layout_data.h" #include "trace.h" #include #include #include /*! where to place the control points of a bezier curve to get a good approximation for a 90 degree curve */ const static double BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE = 0.552284749831; const double DRAW_CLASSIFIER_ICON_ARTIFACT_ICON_WIDTH_TO_HEIGHT = 0.7; const double DRAW_CLASSIFIER_ICON_COMPONENT_ICON_WIDTH_TO_HEIGHT = 1.4; void draw_classifier_icon_draw_component ( const draw_classifier_icon_t *this_, geometry_rectangle_t bounds, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != cr ); /* determine linewidth to avoid that drawings overlap to the outside of bounds */ { const double ln_w = cairo_get_line_width( cr ); geometry_rectangle_enlarge( &bounds, -ln_w, -ln_w ); geometry_rectangle_shift( &bounds, ln_w/2.0, ln_w/2.0 ); } /* calculate component bounds */ const double comp_right = geometry_rectangle_get_right( &bounds ); const double comp_top = geometry_rectangle_get_top( &bounds ); const double comp_bottom = geometry_rectangle_get_bottom( &bounds ); const double comp_height = geometry_rectangle_get_height( &bounds ); const double port_half_width = comp_height * 0.2; const double comp_left = geometry_rectangle_get_left( &bounds ) + port_half_width; //const double comp_width = geometry_rectangle_get_width( &bounds ) - port_half_width; /* calculate bounds of the two ports */ const double port_left = comp_left - port_half_width; const double port_width = 2.0*port_half_width; const double port_height = 0.2*comp_height; const double port1_top = comp_top + 0.2*comp_height; const double port2_top = comp_top + 0.6*comp_height; /* draw the icon */ cairo_move_to ( cr, comp_left, port1_top ); cairo_line_to ( cr, comp_left, comp_top ); cairo_line_to ( cr, comp_right, comp_top ); cairo_line_to ( cr, comp_right, comp_bottom ); cairo_line_to ( cr, comp_left, comp_bottom ); cairo_line_to ( cr, comp_left, port2_top + port_height ); cairo_stroke (cr); cairo_move_to ( cr, comp_left, port2_top ); cairo_line_to ( cr, comp_left, port1_top + port_height ); cairo_stroke (cr); cairo_rectangle ( cr, port_left, port1_top, port_width, port_height ); cairo_stroke (cr); cairo_rectangle ( cr, port_left, port2_top, port_width, port_height ); cairo_stroke (cr); #ifdef PENCIL_LAYOUT_DATA_DRAW_FOR_DEBUG /* draw the rectangle */ { cairo_set_source_rgba( cr, 1.0, 0.5, 0.6, 0.5 ); cairo_rectangle ( cr, geometry_rectangle_get_left ( &bounds ), geometry_rectangle_get_top ( &bounds ), geometry_rectangle_get_width ( &bounds ), geometry_rectangle_get_height ( &bounds ) ); cairo_stroke (cr); cairo_set_source_rgba( cr, 0.0, 0.0, 0.0, 1.0 ); } #endif TRACE_END(); } void draw_classifier_icon_draw_artifact ( const draw_classifier_icon_t *this_, geometry_rectangle_t bounds, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != cr ); /* determine linewith to avoid that drawings overlap to the outside of bounds */ { const double ln_w = cairo_get_line_width( cr ); geometry_rectangle_enlarge( &bounds, -ln_w, -ln_w ); geometry_rectangle_shift( &bounds, ln_w/2.0, ln_w/2.0 ); } /* calculate artifact bounds */ const double art_left = geometry_rectangle_get_left( &bounds ); const double art_right = geometry_rectangle_get_right( &bounds ); const double art_top = geometry_rectangle_get_top( &bounds ); const double art_bottom = geometry_rectangle_get_bottom( &bounds ); const double art_height = geometry_rectangle_get_height( &bounds ); //const double art_width = geometry_rectangle_get_width( &bounds ); const double art_corner_edge = art_height * 0.3; /* draw the icon */ cairo_move_to ( cr, art_right, art_top + art_corner_edge ); cairo_line_to ( cr, art_right - art_corner_edge, art_top + art_corner_edge ); cairo_line_to ( cr, art_right - art_corner_edge, art_top ); cairo_line_to ( cr, art_left, art_top ); cairo_line_to ( cr, art_left, art_bottom ); cairo_line_to ( cr, art_right, art_bottom ); cairo_line_to ( cr, art_right, art_top + art_corner_edge ); cairo_line_to ( cr, art_right - art_corner_edge, art_top ); cairo_stroke (cr); #ifdef PENCIL_LAYOUT_DATA_DRAW_FOR_DEBUG /* draw the rectangle */ { cairo_set_source_rgba( cr, 1.0, 0.5, 0.6, 0.5 ); cairo_rectangle ( cr, geometry_rectangle_get_left ( &bounds ), geometry_rectangle_get_top ( &bounds ), geometry_rectangle_get_width ( &bounds ), geometry_rectangle_get_height ( &bounds ) ); cairo_stroke (cr); cairo_set_source_rgba( cr, 0.0, 0.0, 0.0, 1.0 ); } #endif TRACE_END(); } void draw_classifier_icon_draw_actor ( const draw_classifier_icon_t *this_, geometry_rectangle_t bounds, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != cr ); /* determine linewith to avoid that drawings overlap to the outside of bounds */ { const double ln_w = cairo_get_line_width( cr ); geometry_rectangle_enlarge( &bounds, -ln_w, -ln_w ); geometry_rectangle_shift( &bounds, ln_w/2.0, ln_w/2.0 ); } /* calculate actor bounds */ const double act_left = geometry_rectangle_get_left( &bounds ); const double act_right = geometry_rectangle_get_right( &bounds ); const double act_top = geometry_rectangle_get_top( &bounds ); const double act_bottom = geometry_rectangle_get_bottom( &bounds ); const double act_height = geometry_rectangle_get_height( &bounds ); const double act_width = geometry_rectangle_get_width( &bounds ); /* draw the icon */ const double radius = act_width/2.0; const double ctrl_offset = radius * (1.0-BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE); const double head_bottom = act_top + act_height/3.0; const double leg_top = act_top + act_height*0.6; const double arm_top = act_top + act_height*0.45; cairo_move_to ( cr, act_left + radius, head_bottom ); cairo_curve_to ( cr, act_left + ctrl_offset, head_bottom, act_left, head_bottom - ctrl_offset, act_left /* end point x */, act_top + radius /* end point y */ ); cairo_curve_to ( cr, act_left, act_top + ctrl_offset, act_left + ctrl_offset, act_top, act_left + radius /* end point x */, act_top /* end point y */ ); cairo_curve_to ( cr, act_right - ctrl_offset, act_top, act_right, act_top + ctrl_offset, act_right /* end point x */, act_top + radius /* end point y */ ); cairo_curve_to ( cr, act_right, head_bottom - ctrl_offset, act_right - ctrl_offset, head_bottom, act_left + radius /* end point x */, head_bottom /* end point y */ ); cairo_line_to ( cr, act_left + radius, leg_top ); cairo_line_to ( cr, act_left, act_bottom ); cairo_move_to ( cr, act_right, act_bottom ); cairo_line_to ( cr, act_left + radius, leg_top ); cairo_move_to ( cr, act_right, arm_top ); cairo_line_to ( cr, act_left, arm_top ); cairo_stroke (cr); #ifdef PENCIL_LAYOUT_DATA_DRAW_FOR_DEBUG /* draw the rectangle */ { cairo_set_source_rgba( cr, 1.0, 0.5, 0.6, 0.5 ); cairo_rectangle ( cr, geometry_rectangle_get_left ( &bounds ), geometry_rectangle_get_top ( &bounds ), geometry_rectangle_get_width ( &bounds ), geometry_rectangle_get_height ( &bounds ) ); cairo_stroke (cr); cairo_set_source_rgba( cr, 0.0, 0.0, 0.0, 1.0 ); } #endif TRACE_END(); } void draw_classifier_icon_draw_circle ( const draw_classifier_icon_t *this_, geometry_rectangle_t bounds, const pencil_size_t *pencil_size, bool stroke, bool fill, bool shallow_history, bool deep_history, cairo_t *cr ) { TRACE_BEGIN(); assert ( NULL != pencil_size ); assert ( NULL != cr ); /* determine linewith to avoid that drawings overlap to the outside of bounds */ { const double ln_w = cairo_get_line_width( cr ); geometry_rectangle_enlarge( &bounds, -ln_w, -ln_w ); geometry_rectangle_shift( &bounds, ln_w/2.0, ln_w/2.0 ); } const double circle_top = geometry_rectangle_get_top( &bounds ); const double circle_bottom = geometry_rectangle_get_bottom( &bounds ); const double center_x = geometry_rectangle_get_center_x( &bounds ); const double center_y = geometry_rectangle_get_center_y( &bounds ); const double circle_left = geometry_rectangle_get_left( &bounds ); const double circle_right = geometry_rectangle_get_right( &bounds ); const double circle_width = geometry_rectangle_get_width( &bounds ); const double circle_height = geometry_rectangle_get_height( &bounds ); const double circle_x_radius = center_x - circle_left; const double circle_y_radius = center_y - circle_top; const double gap = pencil_size_get_standard_object_border( pencil_size ); if ( stroke ) { const double ctrl_x_offset = circle_x_radius * (1.0-BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE); const double ctrl_y_offset = circle_y_radius * (1.0-BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE); cairo_move_to ( cr, center_x, circle_bottom ); cairo_curve_to ( cr, circle_left + ctrl_x_offset, circle_bottom, circle_left, circle_bottom - ctrl_y_offset, circle_left /* end point x */, center_y /* end point y */ ); cairo_curve_to ( cr, circle_left, circle_top + ctrl_y_offset, circle_left + ctrl_x_offset, circle_top, center_x /* end point x */, circle_top /* end point y */ ); cairo_curve_to ( cr, circle_right - ctrl_x_offset, circle_top, circle_right, circle_top + ctrl_y_offset, circle_right /* end point x */, center_y /* end point y */ ); cairo_curve_to ( cr, circle_right, circle_bottom - ctrl_y_offset, circle_right - ctrl_x_offset, circle_bottom, center_x /* end point x */, circle_bottom /* end point y */ ); cairo_stroke (cr); } if ( fill ) { const double circle2_x_radius = circle_x_radius - gap; const double circle2_y_radius = circle_y_radius - gap; const double circle2_top = circle_top + gap; const double circle2_bottom = circle_bottom - gap; const double circle2_left = circle_left + gap; const double circle2_right = circle_right - gap; const double ctrl2_x_offset = circle2_x_radius * (1.0-BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE); const double ctrl2_y_offset = circle2_y_radius * (1.0-BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE); /* draw a smaller filled circle */ cairo_move_to ( cr, center_x, circle2_bottom ); cairo_curve_to ( cr, circle2_left + ctrl2_x_offset, circle2_bottom, circle2_left, circle2_bottom - ctrl2_y_offset, circle2_left /* end point x */, center_y /* end point y */ ); cairo_curve_to ( cr, circle2_left, circle2_top + ctrl2_y_offset, circle2_left + ctrl2_x_offset, circle2_top, center_x /* end point x */, circle2_top /* end point y */ ); cairo_curve_to ( cr, circle2_right - ctrl2_x_offset, circle2_top, circle2_right, circle2_top + ctrl2_y_offset, circle2_right /* end point x */, center_y /* end point y */ ); cairo_curve_to ( cr, circle2_right, circle2_bottom - ctrl2_y_offset, circle2_right - ctrl2_x_offset, circle2_bottom, center_x /* end point x */, circle2_bottom /* end point y */ ); cairo_fill (cr); } if ( shallow_history ) { const double quarter_x_font = 0.15 * circle_width; const double quarter_y_font = 0.15 * circle_height; cairo_move_to ( cr, center_x - quarter_x_font, center_y - 2.0 * quarter_y_font ); cairo_line_to ( cr, center_x - quarter_x_font, center_y + 2.0 * quarter_y_font ); cairo_move_to ( cr, center_x - quarter_x_font, center_y ); cairo_line_to ( cr, center_x + quarter_x_font, center_y ); cairo_move_to ( cr, center_x + quarter_x_font, center_y - 2.0 * quarter_y_font ); cairo_line_to ( cr, center_x + quarter_x_font, center_y + 2.0 * quarter_y_font ); cairo_stroke (cr); } else if ( deep_history ) { const double quarter_x_font = 0.15 * circle_width; const double quarter_y_font = 0.15 * circle_height; cairo_move_to ( cr, center_x - 1.5 * quarter_x_font, center_y - 2.0 * quarter_y_font ); cairo_line_to ( cr, center_x - 1.5 * quarter_x_font, center_y + 2.0 * quarter_y_font ); cairo_move_to ( cr, center_x - 1.5 * quarter_x_font, center_y ); cairo_line_to ( cr, center_x + 0.3 * quarter_x_font, center_y ); cairo_move_to ( cr, center_x + 0.3 * quarter_x_font, center_y - 2.0 * quarter_y_font ); cairo_line_to ( cr, center_x + 0.3 * quarter_x_font, center_y + 2.0 * quarter_y_font ); cairo_stroke (cr); cairo_move_to ( cr, center_x + 1.5 * quarter_x_font, center_y - 2.0 * quarter_y_font ); cairo_line_to ( cr, center_x + 1.5 * quarter_x_font, center_y ); cairo_move_to ( cr, center_x + 0.8 * quarter_x_font, center_y - 1.6 * quarter_y_font ); cairo_line_to ( cr, center_x + 2.2 * quarter_x_font, center_y - 0.4 * quarter_y_font ); cairo_move_to ( cr, center_x + 2.2 * quarter_x_font, center_y - 1.6 * quarter_y_font ); cairo_line_to ( cr, center_x + 0.8 * quarter_x_font, center_y - 0.4 * quarter_y_font ); cairo_stroke (cr); } #ifdef PENCIL_LAYOUT_DATA_DRAW_FOR_DEBUG /* draw the rectangle */ { cairo_set_source_rgba( cr, 1.0, 0.5, 0.6, 0.5 ); cairo_rectangle ( cr, geometry_rectangle_get_left ( &bounds ), geometry_rectangle_get_top ( &bounds ), geometry_rectangle_get_width ( &bounds ), geometry_rectangle_get_height ( &bounds ) ); cairo_stroke (cr); cairo_set_source_rgba( cr, 0.0, 0.0, 0.0, 1.0 ); } #endif TRACE_END(); } void draw_classifier_icon_draw_time ( const draw_classifier_icon_t *this_, geometry_rectangle_t bounds, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != cr ); /* determine linewith to avoid that drawings overlap to the outside of bounds */ { const double ln_w = cairo_get_line_width( cr ); geometry_rectangle_enlarge( &bounds, -ln_w, -ln_w ); geometry_rectangle_shift( &bounds, ln_w/2.0, ln_w/2.0 ); } const double top = geometry_rectangle_get_top( &bounds ); const double bottom = geometry_rectangle_get_bottom( &bounds ); const double left = geometry_rectangle_get_left( &bounds ); const double right = geometry_rectangle_get_right( &bounds ); cairo_move_to ( cr, right, bottom ); cairo_line_to ( cr, left, top ); cairo_line_to ( cr, right, top ); cairo_line_to ( cr, left, bottom ); cairo_line_to ( cr, right, bottom ); cairo_stroke (cr); #ifdef PENCIL_LAYOUT_DATA_DRAW_FOR_DEBUG /* draw the rectangle */ { cairo_set_source_rgba( cr, 1.0, 0.5, 0.6, 0.5 ); cairo_rectangle ( cr, geometry_rectangle_get_left ( &bounds ), geometry_rectangle_get_top ( &bounds ), geometry_rectangle_get_width ( &bounds ), geometry_rectangle_get_height ( &bounds ) ); cairo_stroke (cr); cairo_set_source_rgba( cr, 0.0, 0.0, 0.0, 1.0 ); } #endif TRACE_END(); } void draw_classifier_icon_draw_sync ( const draw_classifier_icon_t *this_, geometry_rectangle_t bounds, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != cr ); /* when filling rectangles, no line overlaps the bounds due to its line width */ const double left = geometry_rectangle_get_left( &bounds ); const double top = geometry_rectangle_get_top( &bounds ); const double width = geometry_rectangle_get_width( &bounds ); const double height = geometry_rectangle_get_height( &bounds ); cairo_rectangle ( cr, left, top, width, height ); cairo_fill (cr); #ifdef PENCIL_LAYOUT_DATA_DRAW_FOR_DEBUG /* draw the rectangle */ { cairo_set_source_rgba( cr, 1.0, 0.5, 0.6, 0.5 ); cairo_rectangle ( cr, geometry_rectangle_get_left ( &bounds ), geometry_rectangle_get_top ( &bounds ), geometry_rectangle_get_width ( &bounds ), geometry_rectangle_get_height ( &bounds ) ); cairo_stroke (cr); cairo_set_source_rgba( cr, 0.0, 0.0, 0.0, 1.0 ); } #endif TRACE_END(); } /* Copyright 2016-2021 Andreas Warnke http://www.apache.org/licenses/LICENSE-2.0 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/draw/draw_classifier_label.c000066400000000000000000000414571415120503000253110ustar00rootroot00000000000000/* File: draw_classifier_label.c; Copyright and License: see below */ #include "draw/draw_classifier_label.h" #include "trace.h" #include "data_classifier.h" #include "data_diagramelement.h" #include "util/string/utf8stringbuf.h" #include "util/string/utf8string.h" #include #include #include #include static const int DRAW_CLASSIFIER_PANGO_UNLIMITED_WIDTH = -1; static const int DRAW_CLASSIFIER_PANGO_AUTO_DETECT_LENGTH = -1; #define DRAW_CLASSIFIER_LEFT_POINTING_GUILLEMENTS "\xc2\xab" #define DRAW_CLASSIFIER_RIGHT_POINTING_GUILLEMENTS "\xc2\xbb" #define DRAW_CLASSIFIER_COLON ":" void draw_classifier_label_get_stereotype_and_name_dimensions( const draw_classifier_label_t *this_, const data_visible_classifier_t *visible_classifier, const geometry_dimensions_t *proposed_bounds, const pencil_size_t *pencil_size, PangoLayout *font_layout, double *out_text_width, double *out_text_height ) { TRACE_BEGIN(); assert( NULL != visible_classifier ); assert( NULL != proposed_bounds ); assert( NULL != pencil_size ); assert( NULL != font_layout ); assert( NULL != out_text_width ); assert( NULL != out_text_height ); if ( data_visible_classifier_is_valid( visible_classifier ) ) { const data_classifier_t *classifier; const data_diagramelement_t *diagramelement; classifier = data_visible_classifier_get_classifier_const( visible_classifier ); diagramelement = data_visible_classifier_get_diagramelement_const( visible_classifier ); data_diagramelement_flag_t display_flags; display_flags = data_diagramelement_get_display_flags( diagramelement ); /* stereotype text */ int text1_height = 0; int text1_width = 0; { if ( 0 != utf8string_get_length( data_classifier_get_stereotype_const( classifier ) ) ) { /* prepare text */ char stereotype_text[DATA_CLASSIFIER_MAX_STEREOTYPE_SIZE+4]; utf8stringbuf_t stereotype_buf = UTF8STRINGBUF(stereotype_text); utf8stringbuf_copy_str( stereotype_buf, DRAW_CLASSIFIER_LEFT_POINTING_GUILLEMENTS ); utf8stringbuf_append_str( stereotype_buf, data_classifier_get_stereotype_const( classifier ) ); utf8stringbuf_append_str( stereotype_buf, DRAW_CLASSIFIER_RIGHT_POINTING_GUILLEMENTS ); /* determine text width and height */ pango_layout_set_font_description (font_layout, pencil_size_get_standard_font_description(pencil_size) ); pango_layout_set_text (font_layout, utf8stringbuf_get_string( stereotype_buf ), DRAW_CLASSIFIER_PANGO_AUTO_DETECT_LENGTH ); pango_layout_get_pixel_size (font_layout, &text1_width, &text1_height); } } /* draw name text */ int text2_width; int text2_height; double space_for_line; { int proposed_pango_width = geometry_dimensions_get_width( proposed_bounds ); /* prepare text */ char name_text[DATA_CLASSIFIER_MAX_NAME_SIZE + 1 ]; utf8stringbuf_t name_buf = UTF8STRINGBUF(name_text); if ( 0 != ( display_flags & DATA_DIAGRAMELEMENT_FLAG_ANONYMOUS_INSTANCE ) ) { utf8stringbuf_copy_str( name_buf, DRAW_CLASSIFIER_COLON ); } else { utf8stringbuf_clear( name_buf ); } utf8stringbuf_append_str( name_buf, data_classifier_get_name_const( classifier ) ); /* determine text width and height */ pango_layout_set_font_description (font_layout, pencil_size_get_title_font_description(pencil_size) ); pango_layout_set_text ( font_layout, utf8stringbuf_get_string( name_buf ), DRAW_CLASSIFIER_PANGO_AUTO_DETECT_LENGTH ); pango_layout_set_width(font_layout, proposed_pango_width * PANGO_SCALE ); pango_layout_get_pixel_size (font_layout, &text2_width, &text2_height); /* restore pango context */ pango_layout_set_width(font_layout, DRAW_CLASSIFIER_PANGO_UNLIMITED_WIDTH ); /* for space between stereotype and name */ text2_height += pencil_size_get_font_line_gap( pencil_size ); /* for underscores under object instance names, add 2 * gap: */ space_for_line = 2.0 * pencil_size_get_standard_object_border( pencil_size ); } /* draw description text */ int text3_width = 0; int text3_height = 0; if ( DATA_CLASSIFIER_TYPE_COMMENT == data_classifier_get_main_type ( classifier ) ) { pango_layout_set_font_description (font_layout, pencil_size_get_standard_font_description(pencil_size) ); pango_layout_set_text ( font_layout, data_classifier_get_description_const( classifier ), DRAW_CLASSIFIER_PANGO_AUTO_DETECT_LENGTH ); pango_layout_get_pixel_size (font_layout, &text3_width, &text3_height); } *out_text_height = text1_height + text2_height + space_for_line + text3_height; double intermediate_max_w; intermediate_max_w = ( text1_width > text2_width ) ? text1_width : text2_width; *out_text_width = ( intermediate_max_w > text3_width ) ? intermediate_max_w : text3_width; } else { TSLOG_ERROR("invalid visible classifier in draw_classifier_label_get_stereotype_and_name_dimensions()"); *out_text_width = 0.0; *out_text_height = 0.0; } TRACE_END(); } void draw_classifier_label_draw_stereotype_and_name( const draw_classifier_label_t *this_, const data_visible_classifier_t *visible_classifier, const geometry_rectangle_t *label_box, const pencil_size_t *pencil_size, PangoLayout *font_layout, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != visible_classifier ); assert( NULL != label_box ); assert( NULL != pencil_size ); assert( NULL != font_layout ); assert( NULL != cr ); /* define names for input data: */ const data_classifier_t *classifier; const data_diagramelement_t *diagramelement; classifier = data_visible_classifier_get_classifier_const( visible_classifier ); diagramelement = data_visible_classifier_get_diagramelement_const( visible_classifier ); const data_classifier_type_t classifier_type = data_classifier_get_main_type( classifier ); const data_diagramelement_flag_t display_flags = data_diagramelement_get_display_flags( diagramelement ); const double left = geometry_rectangle_get_left( label_box ); const double top = geometry_rectangle_get_top( label_box ); const double width = geometry_rectangle_get_width( label_box ); const double f_line_gap = pencil_size_get_font_line_gap( pencil_size ); /* draw stereotype text */ int text1_height = 0; { if ( 0 != utf8string_get_length( data_classifier_get_stereotype_const( classifier ) ) ) { /* prepare text */ char stereotype_text[DATA_CLASSIFIER_MAX_STEREOTYPE_SIZE+4]; utf8stringbuf_t stereotype_buf = UTF8STRINGBUF(stereotype_text); utf8stringbuf_copy_str( stereotype_buf, DRAW_CLASSIFIER_LEFT_POINTING_GUILLEMENTS ); utf8stringbuf_append_str( stereotype_buf, data_classifier_get_stereotype_const( classifier ) ); utf8stringbuf_append_str( stereotype_buf, DRAW_CLASSIFIER_RIGHT_POINTING_GUILLEMENTS ); int text1_width; pango_layout_set_font_description (font_layout, pencil_size_get_standard_font_description(pencil_size) ); pango_layout_set_text ( font_layout, utf8stringbuf_get_string( stereotype_buf ), DRAW_CLASSIFIER_PANGO_AUTO_DETECT_LENGTH ); pango_layout_get_pixel_size (font_layout, &text1_width, &text1_height); cairo_move_to ( cr, left + 0.5*( width - text1_width ), top ); pango_cairo_show_layout (cr, font_layout); } } /* draw name text */ int text2_height = 0; { /* prepare text */ char name_text[DATA_CLASSIFIER_MAX_NAME_SIZE + 1 ]; utf8stringbuf_t name_buf = UTF8STRINGBUF(name_text); if ( 0 != ( display_flags & DATA_DIAGRAMELEMENT_FLAG_ANONYMOUS_INSTANCE ) ) { utf8stringbuf_copy_str( name_buf, DRAW_CLASSIFIER_COLON ); } else { utf8stringbuf_clear( name_buf ); } utf8stringbuf_append_str( name_buf, data_classifier_get_name_const( classifier ) ); int text2_width; double f_size = pencil_size_get_standard_font_size( pencil_size ); pango_layout_set_font_description (font_layout, pencil_size_get_title_font_description(pencil_size) ); pango_layout_set_text ( font_layout, utf8stringbuf_get_string( name_buf ), DRAW_CLASSIFIER_PANGO_AUTO_DETECT_LENGTH ); pango_layout_set_width(font_layout, (width+f_size) * PANGO_SCALE ); /* add gap to avoid line breaks by rounding errors and whitespace character widths */ pango_layout_get_pixel_size (font_layout, &text2_width, &text2_height); /* draw text */ cairo_move_to ( cr, left + 0.5*( width - text2_width ), top+text1_height+f_line_gap ); pango_cairo_show_layout (cr, font_layout); /* restore pango context */ pango_layout_set_width(font_layout, DRAW_CLASSIFIER_PANGO_UNLIMITED_WIDTH); /* underline instances */ if ( 0 != ( display_flags & ( DATA_DIAGRAMELEMENT_FLAG_ANONYMOUS_INSTANCE | DATA_DIAGRAMELEMENT_FLAG_NAMED_INSTANCE ) ) ) { cairo_move_to ( cr, left + 0.5*( width - text2_width ), top+text1_height+f_line_gap+text2_height ); cairo_line_to ( cr, left + 0.5*( width + text2_width ), top+text1_height+f_line_gap+text2_height ); cairo_stroke (cr); } } /* draw description text */ if ( DATA_CLASSIFIER_TYPE_COMMENT == classifier_type ) { int text3_width; int text3_height; pango_layout_set_font_description (font_layout, pencil_size_get_standard_font_description(pencil_size) ); pango_layout_set_text ( font_layout, data_classifier_get_description_const( classifier ), DRAW_CLASSIFIER_PANGO_AUTO_DETECT_LENGTH ); pango_layout_get_pixel_size (font_layout, &text3_width, &text3_height); /* draw text */ cairo_move_to ( cr, left + 0.5*( width - text3_width ), top+text1_height+f_line_gap+text2_height+f_line_gap ); pango_cairo_show_layout (cr, font_layout); } TRACE_END(); } void draw_classifier_label_draw_id( const draw_classifier_label_t *this_, const data_visible_classifier_t *visible_classifier, const geometry_rectangle_t *classifier_bounds, const pencil_size_t *pencil_size, PangoLayout *font_layout, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != visible_classifier ); assert( NULL != classifier_bounds ); assert( NULL != pencil_size ); assert( NULL != font_layout ); assert( NULL != cr ); /* define names for input data: */ const double left = geometry_rectangle_get_left ( classifier_bounds ); const double top = geometry_rectangle_get_top ( classifier_bounds ); const double width = geometry_rectangle_get_width ( classifier_bounds ); const double height = geometry_rectangle_get_height ( classifier_bounds ); const double gap = pencil_size_get_standard_object_border( pencil_size ); const data_classifier_t *classifier; classifier = data_visible_classifier_get_classifier_const( visible_classifier ); const data_classifier_type_t classifier_type = data_classifier_get_main_type( classifier ); /* prepare text */ const data_id_t the_id = data_classifier_get_data_id( classifier ); char id_buf[DATA_ID_MAX_UTF8STRING_SIZE+5]; utf8stringbuf_t id_str = UTF8STRINGBUF( id_buf ); utf8stringbuf_copy_str( id_str, "{id=" ); data_id_to_utf8stringbuf( &the_id, id_str ); utf8stringbuf_append_str( id_str, "}" ); /* determine text dimension */ int text4_width; int text4_height; pango_layout_set_font_description (font_layout, pencil_size_get_footnote_font_description(pencil_size) ); pango_layout_set_text (font_layout, utf8stringbuf_get_string( id_str ), -1); pango_layout_get_pixel_size (font_layout, &text4_width, &text4_height); /* position the text */ int x_gap = 0; int y_gap = 0; switch ( classifier_type ) { case DATA_CLASSIFIER_TYPE_BLOCK: case DATA_CLASSIFIER_TYPE_REQUIREMENT: case DATA_CLASSIFIER_TYPE_SUBSYSTEM: case DATA_CLASSIFIER_TYPE_DIAGRAM_REFERENCE: case DATA_CLASSIFIER_TYPE_COMPONENT: case DATA_CLASSIFIER_TYPE_PART: case DATA_CLASSIFIER_TYPE_INTERFACE: case DATA_CLASSIFIER_TYPE_PACKAGE: case DATA_CLASSIFIER_TYPE_CLASS: case DATA_CLASSIFIER_TYPE_OBJECT: case DATA_CLASSIFIER_TYPE_ARTIFACT: case DATA_CLASSIFIER_TYPE_COMMENT: case DATA_CLASSIFIER_TYPE_DYN_ACCEPT_EVENT: { /* there is a border line */ x_gap = 2*gap; y_gap = 2*gap; } break; case DATA_CLASSIFIER_TYPE_NODE: { /* there is a 3D border line */ x_gap = 4*gap; y_gap = 2*gap; } break; case DATA_CLASSIFIER_TYPE_CONSTRAINT_BLOCK: case DATA_CLASSIFIER_TYPE_ACTIVITY: case DATA_CLASSIFIER_TYPE_STATE: case DATA_CLASSIFIER_TYPE_DYN_INTERRUPTABLE_REGION: { /* there is a border line with a round corner */ x_gap = 7*gap; y_gap = 2*gap; } break; case DATA_CLASSIFIER_TYPE_ACTOR: case DATA_CLASSIFIER_TYPE_DYN_INITIAL_NODE: case DATA_CLASSIFIER_TYPE_DYN_FINAL_NODE: case DATA_CLASSIFIER_TYPE_DYN_FORK_NODE: case DATA_CLASSIFIER_TYPE_DYN_JOIN_NODE: case DATA_CLASSIFIER_TYPE_DYN_SHALLOW_HISTORY: case DATA_CLASSIFIER_TYPE_DYN_DEEP_HISTORY: case DATA_CLASSIFIER_TYPE_DYN_ACCEPT_TIME_EVENT: { /* position the text right-bottom of the icon */ x_gap = (width - pencil_size_get_classifier_symbol_height( pencil_size ))/2 - text4_width; y_gap = 0; } break; case DATA_CLASSIFIER_TYPE_USE_CASE: case DATA_CLASSIFIER_TYPE_DYN_DECISION_NODE: { /* there is a chance that the bottom-right corner is empty */ x_gap = 0; y_gap = 0; } break; case DATA_CLASSIFIER_TYPE_DYN_SEND_SIGNAL: { /* the send signal has a 45 degree edge */ x_gap = height/2; y_gap = 2*gap; } break; default: { TSLOG_ERROR("unknown data_classifier_type_t in pencil_classifier_composer_draw()"); } break; } /* draw text */ GdkRGBA grey_color; grey_color = pencil_size_get_gray_out_color( pencil_size ); cairo_set_source_rgba( cr, grey_color.red, grey_color.green, grey_color.blue, grey_color.alpha ); cairo_move_to ( cr, left + width - text4_width - x_gap, top + height - text4_height - y_gap ); pango_cairo_show_layout (cr, font_layout); TRACE_END(); } /* Copyright 2016-2021 Andreas Warnke http://www.apache.org/licenses/LICENSE-2.0 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/draw/draw_feature_label.c000066400000000000000000000114451415120503000246120ustar00rootroot00000000000000/* File: draw_feature_label.c; Copyright and License: see below */ #include "draw/draw_feature_label.h" #include "trace.h" #include "data_classifier.h" #include "data_diagramelement.h" #include "util/string/utf8stringbuf.h" #include "util/string/utf8string.h" #include #include #include #include static const int DRAW_LABEL_PANGO_AUTO_DETECT_LENGTH = -1; void draw_feature_label_get_key_and_value_dimensions ( const draw_feature_label_t *this_, const data_feature_t *feature, const pencil_size_t *pencil_size, PangoLayout *font_layout, double *out_text_width, double *out_text_height ) { TRACE_BEGIN(); assert( NULL != feature ); assert( NULL != pencil_size ); assert( NULL != font_layout ); assert( NULL != out_text_width ); assert( NULL != out_text_height ); if ( data_feature_is_valid( feature ) ) { /* draw text - except for lifelines */ int text_width = 0; int text_height = 0; if ( DATA_FEATURE_TYPE_LIFELINE != data_feature_get_main_type (feature) ) { /* prepare text */ char label_text[DATA_FEATURE_MAX_KEY_SIZE + DATA_FEATURE_MAX_VALUE_SIZE + 2 ]; utf8stringbuf_t label_buf = UTF8STRINGBUF(label_text); utf8stringbuf_copy_str( label_buf, data_feature_get_key_const( feature ) ); if ( data_feature_has_value( feature ) ) { utf8stringbuf_append_str( label_buf, ": " ); utf8stringbuf_append_str( label_buf, data_feature_get_value_const( feature ) ); } /* determine text width and height */ pango_layout_set_font_description (font_layout, pencil_size_get_standard_font_description(pencil_size) ); pango_layout_set_text (font_layout, utf8stringbuf_get_string( label_buf ), DRAW_LABEL_PANGO_AUTO_DETECT_LENGTH ); pango_layout_get_pixel_size (font_layout, &text_width, &text_height); } *out_text_width = text_width; *out_text_height = text_height; } else { TSLOG_ERROR("invalid feature in draw_feature_label_get_key_and_value_dimensions()"); *out_text_width = 0.0; *out_text_height = 0.0; } TRACE_END(); } void draw_feature_label_draw_key_and_value ( const draw_feature_label_t *this_, const data_feature_t *feature, const geometry_rectangle_t *label_box, const pencil_size_t *pencil_size, PangoLayout *font_layout, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != feature ); assert( NULL != label_box ); assert( NULL != pencil_size ); assert( NULL != font_layout ); assert( NULL != cr ); /* define names for input data: */ const double left = geometry_rectangle_get_left( label_box ); const double top = geometry_rectangle_get_top( label_box ); /* draw text - except for lifelines */ if ( DATA_FEATURE_TYPE_LIFELINE != data_feature_get_main_type (feature) ) { /* prepare text */ char label_text[DATA_FEATURE_MAX_KEY_SIZE + DATA_FEATURE_MAX_VALUE_SIZE + 2 ]; utf8stringbuf_t label_buf = UTF8STRINGBUF(label_text); utf8stringbuf_copy_str( label_buf, data_feature_get_key_const( feature ) ); if ( data_feature_has_value( feature ) ) { utf8stringbuf_append_str( label_buf, ": " ); utf8stringbuf_append_str( label_buf, data_feature_get_value_const( feature ) ); } pango_layout_set_font_description (font_layout, pencil_size_get_standard_font_description(pencil_size) ); pango_layout_set_text (font_layout, utf8stringbuf_get_string( label_buf ), DRAW_LABEL_PANGO_AUTO_DETECT_LENGTH); /* draw text */ cairo_move_to ( cr, left, top ); pango_cairo_show_layout (cr, font_layout); } TRACE_END(); } /* Copyright 2017-2021 Andreas Warnke http://www.apache.org/licenses/LICENSE-2.0 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/draw/draw_relationship_label.c000066400000000000000000000222031415120503000256520ustar00rootroot00000000000000 /* File: draw_relationship_label.c; Copyright and License: see below */ #include "draw/draw_relationship_label.h" #include "trace.h" #include "data_classifier.h" #include "data_diagramelement.h" #include "util/string/utf8stringbuf.h" #include "util/string/utf8string.h" #include #include #include #include static const int DRAW_RELATIONSHIP_PANGO_AUTO_DETECT_LENGTH = -1; #define DRAW_RELATIONSHIP_LEFT_GUILLEMENTS "\xc2\xab" #define DRAW_RELATIONSHIP_RIGHT_GUILLEMENTS "\xc2\xbb" void draw_relationship_label_get_type_and_name_dimensions ( const draw_relationship_label_t *this_, const data_relationship_t *relationship, const pencil_size_t *pencil_size, PangoLayout *font_layout, double *out_text_width, double *out_text_height ) { TRACE_BEGIN(); assert( NULL != relationship ); assert( NULL != pencil_size ); assert( NULL != font_layout ); assert( NULL != out_text_width ); assert( NULL != out_text_height ); if ( data_relationship_is_valid( relationship ) ) { /* define names for input data */ const double f_line_gap = pencil_size_get_font_line_gap( pencil_size ); /* calc dimensions of typename as stereotype, */ /* needed for relations that look like DATA_RELATIONSHIP_TYPE_UML_DEPENDENCY */ int text3_height = 0; int text3_width = 0; { const char *type_text; switch ( data_relationship_get_main_type( relationship ) ) { case DATA_RELATIONSHIP_TYPE_UML_EXTEND: { type_text = DRAW_RELATIONSHIP_LEFT_GUILLEMENTS "extends" DRAW_RELATIONSHIP_RIGHT_GUILLEMENTS; } break; case DATA_RELATIONSHIP_TYPE_UML_INCLUDE: { type_text = DRAW_RELATIONSHIP_LEFT_GUILLEMENTS "includes" DRAW_RELATIONSHIP_RIGHT_GUILLEMENTS; } break; case DATA_RELATIONSHIP_TYPE_UML_DEPLOY: { type_text = DRAW_RELATIONSHIP_LEFT_GUILLEMENTS "deploy" DRAW_RELATIONSHIP_RIGHT_GUILLEMENTS; } break; case DATA_RELATIONSHIP_TYPE_UML_MANIFEST: { type_text = DRAW_RELATIONSHIP_LEFT_GUILLEMENTS "manifest" DRAW_RELATIONSHIP_RIGHT_GUILLEMENTS; } break; case DATA_RELATIONSHIP_TYPE_UML_REFINE: { type_text = DRAW_RELATIONSHIP_LEFT_GUILLEMENTS "refine" DRAW_RELATIONSHIP_RIGHT_GUILLEMENTS; } break; case DATA_RELATIONSHIP_TYPE_UML_TRACE: { type_text = DRAW_RELATIONSHIP_LEFT_GUILLEMENTS "trace" DRAW_RELATIONSHIP_RIGHT_GUILLEMENTS; } break; default: { /* other types do not show their type */ type_text = NULL; } break; } if ( NULL != type_text ) { pango_layout_set_font_description (font_layout, pencil_size_get_footnote_font_description(pencil_size) ); pango_layout_set_text (font_layout, type_text, DRAW_RELATIONSHIP_PANGO_AUTO_DETECT_LENGTH); pango_layout_get_pixel_size (font_layout, &text3_width, &text3_height); } } /* calc name text dimensions */ int text2_height = 0; int text2_width = 0; if ( 0 != utf8string_get_length( data_relationship_get_name_const( relationship ) )) { pango_layout_set_font_description (font_layout, pencil_size_get_standard_font_description(pencil_size) ); pango_layout_set_text( font_layout, data_relationship_get_name_const( relationship ), DRAW_RELATIONSHIP_PANGO_AUTO_DETECT_LENGTH ); pango_layout_get_pixel_size (font_layout, &text2_width, &text2_height); } *out_text_height = text3_height + f_line_gap + text2_height; *out_text_width = ( text2_width > text3_width ) ? text2_width : text3_width; } else { TSLOG_ERROR("invalid relationship in draw_relationship_label_get_type_and_name_dimensions()"); *out_text_width = 0.0; *out_text_height = 0.0; } TRACE_END(); } void draw_relationship_label_draw_type_and_name ( const draw_relationship_label_t *this_, const data_relationship_t *relationship, const geometry_rectangle_t *label_box, const pencil_size_t *pencil_size, PangoLayout *font_layout, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != relationship ); assert( NULL != label_box ); assert( NULL != pencil_size ); assert( NULL != font_layout ); assert( NULL != cr ); /* define names for input data */ const double center_x = geometry_rectangle_get_center_x( label_box ); const double top = geometry_rectangle_get_top( label_box ); const double f_line_gap = pencil_size_get_font_line_gap( pencil_size ); /* draw the typename as stereotype, */ /* needed for relations that look like DATA_RELATIONSHIP_TYPE_UML_DEPENDENCY */ int text3_height = 0; { const char *type_text; switch ( data_relationship_get_main_type( relationship ) ) { case DATA_RELATIONSHIP_TYPE_UML_EXTEND: { type_text = DRAW_RELATIONSHIP_LEFT_GUILLEMENTS "extends" DRAW_RELATIONSHIP_RIGHT_GUILLEMENTS; } break; case DATA_RELATIONSHIP_TYPE_UML_INCLUDE: { type_text = DRAW_RELATIONSHIP_LEFT_GUILLEMENTS "includes" DRAW_RELATIONSHIP_RIGHT_GUILLEMENTS; } break; case DATA_RELATIONSHIP_TYPE_UML_DEPLOY: { type_text = DRAW_RELATIONSHIP_LEFT_GUILLEMENTS "deploy" DRAW_RELATIONSHIP_RIGHT_GUILLEMENTS; } break; case DATA_RELATIONSHIP_TYPE_UML_MANIFEST: { type_text = DRAW_RELATIONSHIP_LEFT_GUILLEMENTS "manifest" DRAW_RELATIONSHIP_RIGHT_GUILLEMENTS; } break; case DATA_RELATIONSHIP_TYPE_UML_REFINE: { type_text = DRAW_RELATIONSHIP_LEFT_GUILLEMENTS "refine" DRAW_RELATIONSHIP_RIGHT_GUILLEMENTS; } break; case DATA_RELATIONSHIP_TYPE_UML_TRACE: { type_text = DRAW_RELATIONSHIP_LEFT_GUILLEMENTS "trace" DRAW_RELATIONSHIP_RIGHT_GUILLEMENTS; } break; default: { /* other types do not show their type */ type_text = NULL; } break; } if ( NULL != type_text ) { int text3_width; pango_layout_set_font_description (font_layout, pencil_size_get_footnote_font_description(pencil_size) ); pango_layout_set_text (font_layout, type_text, DRAW_RELATIONSHIP_PANGO_AUTO_DETECT_LENGTH); pango_layout_get_pixel_size (font_layout, &text3_width, &text3_height); /* draw text */ cairo_move_to ( cr, center_x - 0.5*text3_width, top ); pango_cairo_show_layout (cr, font_layout); } } /* draw name text */ if ( 0 != utf8string_get_length( data_relationship_get_name_const( relationship ) )) { int text2_height; int text2_width; pango_layout_set_font_description (font_layout, pencil_size_get_standard_font_description(pencil_size) ); pango_layout_set_text( font_layout, data_relationship_get_name_const( relationship ), DRAW_RELATIONSHIP_PANGO_AUTO_DETECT_LENGTH ); pango_layout_get_pixel_size (font_layout, &text2_width, &text2_height); /* draw text */ cairo_move_to ( cr, center_x - 0.5*text2_width, top + text3_height + f_line_gap ); pango_cairo_show_layout (cr, font_layout); } TRACE_END(); } /* Copyright 2017-2021 Andreas Warnke http://www.apache.org/licenses/LICENSE-2.0 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/pencil_classifier_1d_layouter.c000066400000000000000000001001031415120503000260220ustar00rootroot00000000000000/* File: pencil_classifier_1d_layouter.c; Copyright and License: see below */ #include "pencil_classifier_1d_layouter.h" #include "trace.h" #include #include #include #include void pencil_classifier_1d_layouter_init( pencil_classifier_1d_layouter_t *this_, pencil_layout_data_t *layout_data, const pencil_size_t *pencil_size ) { TRACE_BEGIN(); assert( NULL != layout_data ); assert( NULL != pencil_size ); (*this_).layout_data = layout_data; (*this_).pencil_size = pencil_size; pencil_classifier_composer_init( &((*this_).classifier_composer) ); /* get draw area */ { const layout_diagram_t *const diagram_layout = pencil_layout_data_get_diagram_ptr( (*this_).layout_data ); (*this_).diagram_draw_area = layout_diagram_get_draw_area_const( diagram_layout ); } TRACE_END(); } void pencil_classifier_1d_layouter_destroy( pencil_classifier_1d_layouter_t *this_ ) { TRACE_BEGIN(); pencil_classifier_composer_destroy( &((*this_).classifier_composer) ); TRACE_END(); } void pencil_classifier_1d_layouter_layout_for_list( pencil_classifier_1d_layouter_t *this_, PangoLayout *font_layout ) { TRACE_BEGIN(); /* get preferred object distance */ const double obj_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size ); /* const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size ); */ /* get the draw coordinates */ geometry_rectangle_t draw_area; geometry_rectangle_copy( &draw_area, (*this_).diagram_draw_area ); geometry_rectangle_enlarge( &draw_area, 0.0, (- obj_dist) ); double diag_w = geometry_rectangle_get_width( &draw_area ); double diag_h = geometry_rectangle_get_height( &draw_area ); const double phi = 1.6180339; /* minor=0.618, major=1.0, sum=1.618 => (sum/major)==(major/minor) */ const double golden_ratio_width = diag_w/phi; const double golden_ratio_height = diag_h/phi; /* sort the classifiers according to their list_order */ universal_array_index_sorter_t sorted_classifiers; universal_array_index_sorter_init( &sorted_classifiers ); /* calculate preferred classifier bounds/envelopes */ const uint_fast32_t c_count = pencil_layout_data_get_visible_classifier_count( (*this_).layout_data ); for ( uint_fast32_t plain_idx = 0; plain_idx < c_count; plain_idx ++ ) { layout_visible_classifier_t *const visible_classifier1 = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, plain_idx ); const data_visible_classifier_t *const visible_classifier_data = layout_visible_classifier_get_data_const ( visible_classifier1 ); const data_classifier_t *const classifier1 = data_visible_classifier_get_classifier_const( visible_classifier_data ); /* sort the classifiers according to their list_order */ { const double weight = (const double) data_classifier_get_list_order( classifier1 ); const int insert_err = universal_array_index_sorter_insert( &sorted_classifiers, plain_idx, weight ); if ( 0 != insert_err ) { TSLOG_ERROR ( "universal_array_index_sorter_t list is full." ); } } /* set the preferred bounds, space and label_box of the classifier layout */ { geometry_rectangle_t envelope_box; geometry_rectangle_init( &envelope_box, 0.0, 0.0, golden_ratio_width, (golden_ratio_height/c_count) ); const bool has_contained_children = false; /* this diagram type does not embrace children */ pencil_classifier_composer_set_envelope_box( &((*this_).classifier_composer), &envelope_box, has_contained_children, (*this_).pencil_size, font_layout, visible_classifier1 ); geometry_rectangle_destroy( &envelope_box ); } } /* layout list */ pencil_classifier_1d_layouter_private_layout_vertical( this_, &sorted_classifiers, &draw_area, GEOMETRY_H_ALIGN_CENTER ); /* cleanup sorted array indices and area-rectangles */ universal_array_index_sorter_destroy( &sorted_classifiers ); geometry_rectangle_destroy( &draw_area ); TRACE_END(); } void pencil_classifier_1d_layouter_layout_for_sequence( pencil_classifier_1d_layouter_t *this_, PangoLayout *font_layout ) { TRACE_BEGIN(); /* get preferred object distance */ const double obj_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size ); /* const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size ); */ /* get the diagram coordinates */ geometry_rectangle_t draw_area; geometry_rectangle_copy( &draw_area, (*this_).diagram_draw_area ); geometry_rectangle_shift( &draw_area, obj_dist, 0.0 ); geometry_rectangle_enlarge( &draw_area, (-2.0 * obj_dist), (- obj_dist) ); double diag_w = geometry_rectangle_get_width( &draw_area ); double diag_h = geometry_rectangle_get_height( &draw_area ); const double phi = 1.6180339; /* minor=0.618, major=1.0, sum=1.618 => (sum/major)==(major/minor) */ const double minor_ratio = (1.0 - 0.6180339); const double golden_ratio_width = diag_w/phi; const double minor_minor_height = diag_h * minor_ratio * minor_ratio; const double half_minor_width = diag_w * minor_ratio * 0.5; geometry_rectangle_t left_area; geometry_rectangle_copy( &left_area, &draw_area ); geometry_rectangle_enlarge( &left_area, (- half_minor_width), 0.0 ); geometry_rectangle_t right_column; geometry_rectangle_copy( &right_column, &draw_area ); geometry_rectangle_shift( &right_column, (diag_w-half_minor_width), minor_minor_height ); geometry_rectangle_enlarge( &right_column, (half_minor_width-diag_w), (- minor_minor_height) ); /* sort the classifiers according to their list_order */ universal_array_index_sorter_t sorted_notes_reqs; universal_array_index_sorter_init( &sorted_notes_reqs ); universal_array_index_sorter_t sorted_diag_refs; universal_array_index_sorter_init( &sorted_diag_refs ); universal_array_index_sorter_t sorted_acting_classifiers; universal_array_index_sorter_init( &sorted_acting_classifiers ); /* calculate preferred classifier bounds */ const uint_fast32_t c_count = pencil_layout_data_get_visible_classifier_count( (*this_).layout_data ); for ( uint_fast32_t plain_idx = 0; plain_idx < c_count; plain_idx ++ ) { layout_visible_classifier_t *const visible_classifier1 = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, plain_idx ); const data_visible_classifier_t *const visible_classifier_data = layout_visible_classifier_get_data_const ( visible_classifier1 ); const data_classifier_t *const classifier1 = data_visible_classifier_get_classifier_const( visible_classifier_data ); const data_classifier_type_t c1_type = data_classifier_get_main_type ( classifier1 ); /* check classifier type and sort into corresponding list */ { int insert_err = 0; const double weight = (const double) data_classifier_get_list_order( classifier1 ); if (( c1_type == DATA_CLASSIFIER_TYPE_REQUIREMENT ) || ( c1_type == DATA_CLASSIFIER_TYPE_COMMENT )) { insert_err = universal_array_index_sorter_insert( &sorted_notes_reqs, plain_idx, weight ); } else if ( c1_type == DATA_CLASSIFIER_TYPE_DIAGRAM_REFERENCE ) { insert_err = universal_array_index_sorter_insert( &sorted_diag_refs, plain_idx, weight ); } else { insert_err = universal_array_index_sorter_insert( &sorted_acting_classifiers, plain_idx, weight ); } if ( 0 != insert_err ) { TSLOG_ERROR ( "universal_array_index_sorter_t list is full." ); } } /* set the preferred bounds, space and label_box of the classifier layout */ { geometry_rectangle_t envelope_box; if ( c1_type == DATA_CLASSIFIER_TYPE_DIAGRAM_REFERENCE ) { geometry_rectangle_init( &envelope_box, 0.0, 0.0, (diag_w-half_minor_width), (minor_minor_height/2.0) ); } else { geometry_rectangle_init( &envelope_box, 0.0, 0.0, (golden_ratio_width/c_count), minor_minor_height ); } const bool has_contained_children = false; /* this diagram type does not embrace children */ pencil_classifier_composer_set_envelope_box( &((*this_).classifier_composer), &envelope_box, has_contained_children, (*this_).pencil_size, font_layout, visible_classifier1 ); geometry_rectangle_destroy( &envelope_box ); } } assert( c_count == universal_array_index_sorter_get_count( &sorted_notes_reqs ) + universal_array_index_sorter_get_count( &sorted_diag_refs ) + universal_array_index_sorter_get_count( &sorted_acting_classifiers ) ); /* layout acting classifiers */ pencil_classifier_1d_layouter_private_layout_horizontal( this_, &sorted_acting_classifiers, &left_area, GEOMETRY_V_ALIGN_TOP ); /* layout digram references */ pencil_classifier_1d_layouter_private_linear_vertical( this_, &sorted_diag_refs, &left_area, GEOMETRY_H_ALIGN_LEFT ); /* layout notes/comments and requirements */ pencil_classifier_1d_layouter_private_linear_vertical( this_, &sorted_notes_reqs, &right_column, GEOMETRY_H_ALIGN_RIGHT ); /* cleanup sorted array indices and area-rectangles */ universal_array_index_sorter_destroy( &sorted_acting_classifiers ); universal_array_index_sorter_destroy( &sorted_diag_refs ); universal_array_index_sorter_destroy( &sorted_notes_reqs ); geometry_rectangle_destroy( &right_column ); geometry_rectangle_destroy( &left_area ); geometry_rectangle_destroy( &draw_area ); TRACE_END(); } void pencil_classifier_1d_layouter_layout_for_timing( pencil_classifier_1d_layouter_t *this_, PangoLayout *font_layout ) { TRACE_BEGIN(); /* get preferred object distance */ const double obj_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size ); /* const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size ); */ /* get the diagram coordinates */ geometry_rectangle_t draw_area; geometry_rectangle_copy( &draw_area, (*this_).diagram_draw_area ); geometry_rectangle_shift( &draw_area, obj_dist, 0.0 ); geometry_rectangle_enlarge( &draw_area, (-2.0 * obj_dist), (- obj_dist) ); const double diag_w = geometry_rectangle_get_width( &draw_area ); const double diag_h = geometry_rectangle_get_height( &draw_area ); const double phi = 1.6180339; /* minor=0.618, major=1.0, sum=1.618 => (sum/major)==(major/minor) */ const double minor_ratio = (1.0 - 0.6180339); const double golden_ratio_width = diag_w/phi; const double golden_ratio_height = diag_h/phi; const double minor_minor_width = diag_w * minor_ratio * minor_ratio; const double minor_minor_height = diag_h * minor_ratio * minor_ratio; geometry_rectangle_t top_row; geometry_rectangle_copy( &top_row, &draw_area ); geometry_rectangle_shift( &top_row, minor_minor_width, 0.0 ); geometry_rectangle_enlarge( &top_row, (- minor_minor_width), (minor_minor_width-diag_h) ); geometry_rectangle_t center_area; geometry_rectangle_copy( ¢er_area, &draw_area ); geometry_rectangle_shift( ¢er_area, 0.0, minor_minor_height ); geometry_rectangle_enlarge( ¢er_area, 0.0, (- minor_minor_height) ); /* sort the classifiers according to their list_order */ universal_array_index_sorter_t sorted_notes_reqs; universal_array_index_sorter_init( &sorted_notes_reqs ); universal_array_index_sorter_t sorted_acting_classifiers; universal_array_index_sorter_init( &sorted_acting_classifiers ); /* calculate preferred classifier bounds */ const uint_fast32_t c_count = pencil_layout_data_get_visible_classifier_count( (*this_).layout_data ); for ( uint_fast32_t plain_idx = 0; plain_idx < c_count; plain_idx ++ ) { layout_visible_classifier_t *const visible_classifier1 = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, plain_idx ); const data_visible_classifier_t *const visible_classifier_data = layout_visible_classifier_get_data_const ( visible_classifier1 ); const data_classifier_t *const classifier1 = data_visible_classifier_get_classifier_const( visible_classifier_data ); const data_classifier_type_t c1_type = data_classifier_get_main_type ( classifier1 ); /* check classifier type and sort into corresponding list */ { int insert_err = 0; const double weight = (const double) data_classifier_get_list_order( classifier1 ); if (( c1_type == DATA_CLASSIFIER_TYPE_REQUIREMENT ) || ( c1_type == DATA_CLASSIFIER_TYPE_COMMENT )) { insert_err = universal_array_index_sorter_insert( &sorted_notes_reqs, plain_idx, weight ); } else { insert_err = universal_array_index_sorter_insert( &sorted_acting_classifiers, plain_idx, weight ); } if ( 0 != insert_err ) { TSLOG_ERROR ( "universal_array_index_sorter_t list is full." ); } } /* set the preferred bounds, space and label_box of the classifier layout */ { geometry_rectangle_t envelope_box; geometry_rectangle_init( &envelope_box, 0.0, 0.0, ((diag_w-golden_ratio_width)/2.0), (golden_ratio_height/c_count) ); const bool has_contained_children = false; /* this diagram type does not embrace children */ pencil_classifier_composer_set_envelope_box( &((*this_).classifier_composer), &envelope_box, has_contained_children, (*this_).pencil_size, font_layout, visible_classifier1 ); geometry_rectangle_destroy( &envelope_box ); } } assert( c_count == universal_array_index_sorter_get_count( &sorted_notes_reqs ) + universal_array_index_sorter_get_count( &sorted_acting_classifiers ) ); /* layout acting classifiers */ pencil_classifier_1d_layouter_private_layout_vertical( this_, &sorted_acting_classifiers, ¢er_area, GEOMETRY_H_ALIGN_LEFT ); /* layout notes/comments and requirements */ pencil_classifier_1d_layouter_private_linear_horizontal( this_, &sorted_notes_reqs, &top_row, GEOMETRY_V_ALIGN_TOP ); /* cleanup sorted array indices and area-rectangles */ universal_array_index_sorter_destroy( &sorted_acting_classifiers ); universal_array_index_sorter_destroy( &sorted_notes_reqs ); geometry_rectangle_destroy( ¢er_area ); geometry_rectangle_destroy( &top_row ); geometry_rectangle_destroy( &draw_area ); TRACE_END(); } void pencil_classifier_1d_layouter_private_layout_horizontal( const pencil_classifier_1d_layouter_t *this_, const universal_array_index_sorter_t *classifier_list, const geometry_rectangle_t *dest_rect, geometry_v_align_t v_alignment ) { TRACE_BEGIN(); /* get the destination rectangle coordinates */ const double diag_x = geometry_rectangle_get_left( dest_rect ); const double diag_w = geometry_rectangle_get_width( dest_rect ); /* calculate sum of wished envelope widths */ double total_wish_width = 0.0; const uint_fast32_t count_classifiers = universal_array_index_sorter_get_count ( classifier_list ); for ( uint_fast32_t sort_idx = 0; sort_idx < count_classifiers; sort_idx ++ ) { uint_fast32_t index = universal_array_index_sorter_get_array_index( classifier_list, sort_idx ); const layout_visible_classifier_t *const visible_classifier1 = pencil_layout_data_get_visible_classifier_const( (*this_).layout_data, index ); /* update sum of wished envelope widths */ const geometry_rectangle_t envelope = layout_visible_classifier_get_envelope_box( visible_classifier1 ); total_wish_width += geometry_rectangle_get_width( &envelope ); } const double dx_spaces = (count_classifiers==0) ? diag_w : ((diag_w - total_wish_width)/count_classifiers); /* update the classifier coordinates */ double current_x = diag_x; for ( uint_fast32_t sort_idx = 0; sort_idx < count_classifiers; sort_idx ++ ) { const uint_fast32_t index = universal_array_index_sorter_get_array_index( classifier_list, sort_idx ); layout_visible_classifier_t *const visible_classifier2 = pencil_layout_data_get_visible_classifier_ptr ( (*this_).layout_data, index ); const geometry_rectangle_t envelope = layout_visible_classifier_get_envelope_box( visible_classifier2 ); const double envelope_top = geometry_rectangle_get_top( &envelope ); const double envelope_height = geometry_rectangle_get_height( &envelope ); const double envelope_left = geometry_rectangle_get_left( &envelope ); const double envelope_width = geometry_rectangle_get_width( &envelope ); const double dest_top = geometry_v_align_get_top( &v_alignment, envelope_height, geometry_rectangle_get_top( dest_rect ), geometry_rectangle_get_height( dest_rect ) ); const double delta_y = dest_top - envelope_top; if ( dx_spaces > 0.0 ) { /* equal spaces if there are spaces */ const double delta_x = current_x + (dx_spaces/2.0) - envelope_left; layout_visible_classifier_shift( visible_classifier2, delta_x, delta_y ); current_x += dx_spaces + envelope_width; } else { /* const double wish2avail_ratio = (diag_h == 0.0) ? 1.0 : (total_wish_width/diag_h); */ const double avail2wish_ratio = (total_wish_width == 0.0) ? 1.0 : (diag_w/total_wish_width); const double available_width = envelope_width * avail2wish_ratio; const double x_align_ratio = (count_classifiers==1) ? 0.5 : sort_idx/(count_classifiers-1.0); const double x_align_envelope = envelope_width * x_align_ratio; const double x_align_available = available_width * x_align_ratio; const double delta_x = (current_x+x_align_available) - (envelope_left+x_align_envelope); layout_visible_classifier_shift( visible_classifier2, delta_x, delta_y ); current_x += available_width; } } TRACE_END(); } void pencil_classifier_1d_layouter_private_layout_vertical( const pencil_classifier_1d_layouter_t *this_, const universal_array_index_sorter_t *classifier_list, const geometry_rectangle_t *dest_rect, geometry_h_align_t h_alignment ) { TRACE_BEGIN(); /* get the destination rectangle coordinates */ const double diag_y = geometry_rectangle_get_top( dest_rect ); const double diag_h = geometry_rectangle_get_height( dest_rect ); /* calculate sum of wished envelope heights */ double total_wish_height = 0.0; const uint_fast32_t count_classifiers = universal_array_index_sorter_get_count ( classifier_list ); for ( uint_fast32_t sort_idx = 0; sort_idx < count_classifiers; sort_idx ++ ) { const uint_fast32_t index = universal_array_index_sorter_get_array_index( classifier_list, sort_idx ); const layout_visible_classifier_t *const visible_classifier1 = pencil_layout_data_get_visible_classifier_const( (*this_).layout_data, index ); /* update sum of wished envelope heights */ const geometry_rectangle_t envelope = layout_visible_classifier_get_envelope_box( visible_classifier1 ); total_wish_height += geometry_rectangle_get_height( &envelope ); } const double dy_spaces = (count_classifiers==0) ? diag_h : ((diag_h - total_wish_height)/count_classifiers); /* update the classifier coordinates */ double current_y = diag_y; for ( uint_fast32_t sort_idx = 0; sort_idx < count_classifiers; sort_idx ++ ) { const uint_fast32_t index = universal_array_index_sorter_get_array_index( classifier_list, sort_idx ); layout_visible_classifier_t *const visible_classifier2 = pencil_layout_data_get_visible_classifier_ptr ( (*this_).layout_data, index ); const geometry_rectangle_t envelope = layout_visible_classifier_get_envelope_box( visible_classifier2 ); const double envelope_top = geometry_rectangle_get_top( &envelope ); const double envelope_height = geometry_rectangle_get_height( &envelope ); const double envelope_left = geometry_rectangle_get_left( &envelope ); const double envelope_width = geometry_rectangle_get_width( &envelope ); const double dest_left = geometry_h_align_get_left( &h_alignment, envelope_width, geometry_rectangle_get_left( dest_rect ), geometry_rectangle_get_width( dest_rect ) ); const double delta_x = dest_left - envelope_left; if ( dy_spaces > 0.0 ) { /* equal spaces if there are spaces */ const double delta_y = current_y + (dy_spaces/2.0) - envelope_top; layout_visible_classifier_shift( visible_classifier2, delta_x, delta_y ); current_y += dy_spaces + envelope_height; } else { /* keep available-to-wish ratio if classifiers overlap */ /* const double wish2avail_ratio = (diag_h == 0.0) ? 1.0 : (total_wish_height/diag_h); */ const double avail2wish_ratio = (total_wish_height == 0.0) ? 1.0 : (diag_h/total_wish_height); const double available_height = envelope_height * avail2wish_ratio; const double y_align_ratio = (count_classifiers==1) ? 0.5 : sort_idx/(count_classifiers-1.0); const double y_align_envelope = envelope_height * y_align_ratio; const double y_align_available = available_height * y_align_ratio; const double delta_y = (current_y+y_align_available) - (envelope_top+y_align_envelope); layout_visible_classifier_shift( visible_classifier2, delta_x, delta_y ); current_y += available_height; } } TRACE_END(); } void pencil_classifier_1d_layouter_private_linear_horizontal( const pencil_classifier_1d_layouter_t *this_, const universal_array_index_sorter_t *classifier_list, const geometry_rectangle_t *dest_rect, geometry_v_align_t v_alignment ) { TRACE_BEGIN(); /* get the destination rectangle coordinates */ const double diag_x = geometry_rectangle_get_left( (*this_).diagram_draw_area ); const double diag_w = geometry_rectangle_get_width( (*this_).diagram_draw_area ); const double dest_left = geometry_rectangle_get_left( dest_rect ); const double dest_right = geometry_rectangle_get_right( dest_rect ); /* update the classifier coordinates */ const uint_fast32_t count_classifiers = universal_array_index_sorter_get_count ( classifier_list ); for ( uint_fast32_t sort_idx = 0; sort_idx < count_classifiers; sort_idx ++ ) { uint_fast32_t index = universal_array_index_sorter_get_array_index( classifier_list, sort_idx ); layout_visible_classifier_t *const visible_classifier2 = pencil_layout_data_get_visible_classifier_ptr ( (*this_).layout_data, index ); /* get envelope */ const geometry_rectangle_t envelope = layout_visible_classifier_get_envelope_box( visible_classifier2 ); const double envelope_top = geometry_rectangle_get_top( &envelope ); const double envelope_height = geometry_rectangle_get_height( &envelope ); const double envelope_left = geometry_rectangle_get_left( &envelope ); const double envelope_width = geometry_rectangle_get_width( &envelope ); /* calc x */ const data_visible_classifier_t *const visible_classifier_data = layout_visible_classifier_get_data_const ( visible_classifier2 ); const data_classifier_t *const classifier2 = data_visible_classifier_get_classifier_const( visible_classifier_data ); const int32_t list_order = data_classifier_get_list_order( classifier2 ); const double x_value_rel = (list_order/((double)UINT32_MAX))+0.5; double new_left = diag_x + (diag_w-envelope_width)*x_value_rel; if ( (new_left+envelope_width) > dest_right ) { new_left = dest_right - envelope_width; } if ( new_left < dest_left ) { new_left = dest_left; } const double delta_x = new_left - envelope_left; /* calc y */ const double dest_top = geometry_v_align_get_top( &v_alignment, envelope_height, geometry_rectangle_get_top( dest_rect ), geometry_rectangle_get_height( dest_rect ) ); const double delta_y = dest_top - envelope_top; layout_visible_classifier_shift( visible_classifier2, delta_x, delta_y ); } TRACE_END(); } void pencil_classifier_1d_layouter_private_linear_vertical( const pencil_classifier_1d_layouter_t *this_, const universal_array_index_sorter_t *classifier_list, const geometry_rectangle_t *dest_rect, geometry_h_align_t h_alignment ) { TRACE_BEGIN(); /* get the destination rectangle coordinates */ const double diag_y = geometry_rectangle_get_top( (*this_).diagram_draw_area ); const double diag_h = geometry_rectangle_get_height( (*this_).diagram_draw_area ); const double dest_top = geometry_rectangle_get_top( dest_rect ); const double dest_bottom = geometry_rectangle_get_bottom( dest_rect ); /* update the classifier coordinates */ const uint_fast32_t count_classifiers = universal_array_index_sorter_get_count ( classifier_list ); for ( uint_fast32_t sort_idx = 0; sort_idx < count_classifiers; sort_idx ++ ) { const uint_fast32_t index = universal_array_index_sorter_get_array_index( classifier_list, sort_idx ); layout_visible_classifier_t *const visible_classifier2 = pencil_layout_data_get_visible_classifier_ptr ( (*this_).layout_data, index ); /* get envelope */ const geometry_rectangle_t envelope = layout_visible_classifier_get_envelope_box( visible_classifier2 ); const double envelope_top = geometry_rectangle_get_top( &envelope ); const double envelope_height = geometry_rectangle_get_height( &envelope ); const double envelope_left = geometry_rectangle_get_left( &envelope ); const double envelope_width = geometry_rectangle_get_width( &envelope ); /* calc x */ const double dest_left = geometry_h_align_get_left( &h_alignment, envelope_width, geometry_rectangle_get_left( dest_rect ), geometry_rectangle_get_width( dest_rect ) ); const double delta_x = dest_left - envelope_left; /* calc y */ const data_visible_classifier_t *const visible_classifier_data = layout_visible_classifier_get_data_const ( visible_classifier2 ); const data_classifier_t *const classifier2 = data_visible_classifier_get_classifier_const( visible_classifier_data ); const int32_t list_order = data_classifier_get_list_order( classifier2 ); const double y_value_rel = (list_order/((double)UINT32_MAX))+0.5; double new_top = diag_y + (diag_h-envelope_height)*y_value_rel; if ( (new_top+envelope_height) > dest_bottom ) { new_top = dest_bottom - envelope_height; } if ( new_top < dest_top ) { new_top = dest_top; } const double delta_y = new_top - envelope_top; layout_visible_classifier_shift( visible_classifier2, delta_x, delta_y ); } TRACE_END(); } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/pencil_classifier_2d_layouter.c000066400000000000000000001512361415120503000260400ustar00rootroot00000000000000/* File: pencil_classifier_2d_layouter.c; Copyright and License: see below */ #include "pencil_classifier_2d_layouter.h" #include "trace.h" #include #include #include #include void pencil_classifier_2d_layouter_init( pencil_classifier_2d_layouter_t *this_, pencil_layout_data_t *layout_data, const pencil_size_t *pencil_size, geometry_dimensions_t *default_classifier_size, geometry_non_linear_scale_t *x_scale, geometry_non_linear_scale_t *y_scale, pencil_feature_layouter_t *feature_layouter ) { TRACE_BEGIN(); assert( NULL != layout_data ); assert( NULL != pencil_size ); assert( NULL != default_classifier_size ); assert( NULL != x_scale ); assert( NULL != y_scale ); assert( NULL != feature_layouter ); (*this_).layout_data = layout_data; (*this_).pencil_size = pencil_size; (*this_).default_classifier_size = default_classifier_size; (*this_).x_scale = x_scale; (*this_).y_scale = y_scale; (*this_).feature_layouter = feature_layouter; pencil_classifier_composer_init( &((*this_).classifier_composer) ); /* get draw area */ { layout_diagram_t *diagram_layout; diagram_layout = pencil_layout_data_get_diagram_ptr( (*this_).layout_data ); (*this_).diagram_draw_area = layout_diagram_get_draw_area_const( diagram_layout ); } TRACE_END(); } void pencil_classifier_2d_layouter_destroy( pencil_classifier_2d_layouter_t *this_ ) { TRACE_BEGIN(); pencil_classifier_composer_destroy( &((*this_).classifier_composer) ); TRACE_END(); } /* ================================ INITIAL LAYOUT ================================ */ void pencil_classifier_2d_layouter_estimate_bounds( pencil_classifier_2d_layouter_t *this_, PangoLayout *font_layout ) { TRACE_BEGIN(); /* store the classifier bounds into input_data_layouter_t */ const uint32_t count_clasfy = pencil_layout_data_get_visible_classifier_count ( (*this_).layout_data ); for ( uint32_t index = 0; index < count_clasfy; index ++ ) { layout_visible_classifier_t *const classifier_layout = pencil_layout_data_get_visible_classifier_ptr ( (*this_).layout_data, index ); /* set the bounds, space and label_box of the classifier layout */ { const bool shows_contained_children = false; /* if classifier has children, this will be updated later */ /* when calling pencil_classifier_composer_set_space_and_label */ /* init by default size */ { geometry_rectangle_t envelope; geometry_rectangle_init( &envelope, 0.0, 0.0, geometry_dimensions_get_width( (*this_).default_classifier_size ), geometry_dimensions_get_height( (*this_).default_classifier_size ) ); pencil_classifier_composer_set_envelope_box( &((*this_).classifier_composer), &envelope, shows_contained_children, (*this_).pencil_size, font_layout, classifier_layout ); geometry_rectangle_destroy( &envelope ); } /* check if inner space is big enough for contained features */ { geometry_dimensions_t features_dim; geometry_dimensions_init_empty( &features_dim ); pencil_feature_layouter_calculate_features_bounds( (*this_).feature_layouter, layout_visible_classifier_get_diagramelement_id( classifier_layout ), font_layout, &features_dim ); const geometry_rectangle_t *const space_rect = layout_visible_classifier_get_space_const( classifier_layout ); const geometry_dimensions_t space_dim = geometry_rectangle_get_dimensions( space_rect ); if ( ! geometry_dimensions_can_contain( &space_dim, &features_dim ) ) { geometry_rectangle_t new_space; geometry_rectangle_copy( &new_space, space_rect ); const double delta_width = geometry_dimensions_get_width( &features_dim ) - geometry_rectangle_get_width( space_rect ); const double delta_height = geometry_dimensions_get_height( &features_dim ) - geometry_rectangle_get_height( space_rect ); geometry_rectangle_expand_4dir( &new_space, (delta_width<0.0) ? 0.0 : 0.5*delta_width, (delta_height<0.0) ? 0.0 : 0.5*delta_height ); pencil_classifier_composer_expand_space( &((*this_).classifier_composer), &new_space, shows_contained_children, (*this_).pencil_size, font_layout, classifier_layout ); geometry_rectangle_destroy( &new_space ); } geometry_dimensions_destroy( &features_dim ); } } /* move the classifier rectangles to the target location */ { const data_visible_classifier_t *const visible_classifier2 = layout_visible_classifier_get_data_const ( classifier_layout ); const data_classifier_t *const classifier2 = data_visible_classifier_get_classifier_const( visible_classifier2 ); const geometry_rectangle_t *const classifier_symbol_box = layout_visible_classifier_get_symbol_box_const( classifier_layout ); const double act_center_x = geometry_rectangle_get_center_x( classifier_symbol_box ); const double act_center_y = geometry_rectangle_get_center_y( classifier_symbol_box ); const int32_t order_x = data_classifier_get_x_order( classifier2 ); const int32_t order_y = data_classifier_get_y_order( classifier2 ); const double center_x = geometry_non_linear_scale_get_location( (*this_).x_scale, order_x ); const double center_y = geometry_non_linear_scale_get_location( (*this_).y_scale, order_y ); layout_visible_classifier_shift( classifier_layout, center_x-act_center_x, center_y-act_center_y ); } } TRACE_END(); } /* ================================ MOVE TO AVOID OVERLAPS ================================ */ void pencil_classifier_2d_layouter_move_to_avoid_overlaps ( pencil_classifier_2d_layouter_t *this_ ) { TRACE_BEGIN(); assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) PENCIL_LAYOUT_DATA_MAX_CLASSIFIERS ); universal_array_index_sorter_t sorted; universal_array_index_sorter_init( &sorted ); /* sort the classifiers by their movement-needs */ pencil_classifier_2d_layouter_private_propose_move_processing_order ( this_, &sorted ); /* move the classifiers */ uint32_t count_sorted; count_sorted = universal_array_index_sorter_get_count( &sorted ); for ( uint32_t sort_index = 0; sort_index < count_sorted; sort_index ++ ) { /* declaration of list of options */ uint32_t solutions_count = 0; static const uint32_t SOLUTIONS_MAX = 6; double solution_move_dx[6]; double solution_move_dy[6]; /* propose options of moving left/right/up/down */ pencil_classifier_2d_layouter_private_propose_4dir_move_solutions( this_, &sorted, sort_index, SOLUTIONS_MAX-1, solution_move_dx, solution_move_dy, &solutions_count ); /* propose options of moving close at origin-area */ pencil_classifier_2d_layouter_private_propose_anchored_solution( this_, &sorted, sort_index, &(solution_move_dx[solutions_count]), &(solution_move_dy[solutions_count]) ); solutions_count ++; /* select best option */ uint32_t index_of_best; if ( 1 == solutions_count ) { index_of_best = 0; } else { pencil_classifier_2d_layouter_private_select_move_solution( this_, &sorted, sort_index, solutions_count, solution_move_dx, solution_move_dy, &index_of_best ); } /* perform best option */ uint32_t index; index = universal_array_index_sorter_get_array_index( &sorted, sort_index ); /* move the classifier */ layout_visible_classifier_t *the_classifier; the_classifier = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, index ); layout_visible_classifier_shift( the_classifier, solution_move_dx[index_of_best], solution_move_dy[index_of_best] ); } universal_array_index_sorter_destroy( &sorted ); TRACE_END(); } void pencil_classifier_2d_layouter_private_propose_move_processing_order ( pencil_classifier_2d_layouter_t *this_, universal_array_index_sorter_t *out_sorted ) { TRACE_BEGIN(); assert ( NULL != out_sorted ); assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) DATA_VISIBLE_SET_MAX_CLASSIFIERS ); /* sort the classifiers by their movement-needs */ uint32_t count_clasfy; count_clasfy = pencil_layout_data_get_visible_classifier_count ( (*this_).layout_data ); for ( uint32_t index = 0; index < count_clasfy; index ++ ) { const layout_visible_classifier_t *const the_classifier = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, index ); const geometry_rectangle_t *const classifier_envelope_box = layout_visible_classifier_get_envelope_box_const( the_classifier ); int64_t simpleness = 0; /* the lower the number, the ealier the classifier will be processed. Unit is area(=square-length). */ /* reduce simpleness by area outside the diagram border: the more outside diagram area, the earlier it should be moved */ { geometry_rectangle_t border_intersect; int intersect_error2; intersect_error2 = geometry_rectangle_init_by_intersect( &border_intersect, classifier_envelope_box, (*this_).diagram_draw_area ); if ( 0 != intersect_error2 ) { TSLOG_WARNING( "a rectangle to be drawn is completely outside the diagram area" ); } simpleness += 16.0 * geometry_rectangle_get_area( &border_intersect ); simpleness -= 16.0 * geometry_rectangle_get_area( classifier_envelope_box ); geometry_rectangle_destroy( &border_intersect ); } /* reduce simpleness by intersects with other rectangles: the more intersects, the earlier it should be moved */ for ( uint32_t probe_index = 0; probe_index < count_clasfy; probe_index ++ ) { layout_visible_classifier_t *probe_classifier; probe_classifier = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, probe_index ); const geometry_rectangle_t *const probe_envelope_box = layout_visible_classifier_get_envelope_box_const( probe_classifier ); geometry_rectangle_t intersect; int intersect_error; intersect_error = geometry_rectangle_init_by_intersect( &intersect, classifier_envelope_box, probe_envelope_box ); if ( 0 == intersect_error ) { simpleness -= geometry_rectangle_get_area( &intersect ); } geometry_rectangle_destroy( &intersect ); } /* reduce simpleness by own size: the bigger the object, the earlier it should be moved */ { const double default_classifier_area = geometry_dimensions_get_area( (*this_).default_classifier_size ); const double classifier_area = geometry_rectangle_get_area( classifier_envelope_box ); if (( default_classifier_area > 0.000000001 )&&( classifier_area > 0.000000001 )) { simpleness -= default_classifier_area * ( classifier_area / ( classifier_area + default_classifier_area )); } } /* increase simpleness if contained children: if embracing children later, layouting problems might get solved */ { const double default_classifier_area = geometry_dimensions_get_area( (*this_).default_classifier_size ); const uint32_t descendant_count = pencil_layout_data_count_descendants( (*this_).layout_data, the_classifier ); if ( descendant_count != 0 ) { simpleness += default_classifier_area; } } int insert_error; insert_error = universal_array_index_sorter_insert( out_sorted, index, simpleness ); if ( 0 != insert_error ) { TSLOG_WARNING( "not all rectangles are moved" ); } } TRACE_END(); } /*! * \brief constants for directions of moving objects */ enum pencil_classifier_2d_layouter_private_move_enum { PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_NOT = 0, /*!< only move to visible arey - nothing more */ PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_UP_MIN = 1, /*!< moves up the minimum distance (up means smaller y-values) */ PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_DOWN_MIN = 2, PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_LEFT_MIN = 3, PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_RIGHT_MIN = 4, PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_MAX = 5, /*!< constant defining the total number of available options */ }; void pencil_classifier_2d_layouter_private_propose_4dir_move_solutions( pencil_classifier_2d_layouter_t *this_, const universal_array_index_sorter_t *sorted, uint32_t sort_index, uint32_t solutions_max, double out_solution_move_dx[], double out_solution_move_dy[], uint32_t *out_solutions_count ) { TRACE_BEGIN(); assert ( NULL != sorted ); assert ( universal_array_index_sorter_get_count( sorted ) > sort_index ); assert ( NULL != out_solution_move_dx ); assert ( NULL != out_solution_move_dy ); assert ( NULL != out_solutions_count ); assert ( 1 <= solutions_max ); /* general requirement to report at least one option */ assert ( (unsigned int) PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_MAX <= solutions_max ); /* current implementation requires at least 5 options */ /* get classifier to move */ const uint32_t index = universal_array_index_sorter_get_array_index( sorted, sort_index ); const layout_visible_classifier_t *const the_classifier = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, index ); const geometry_rectangle_t *const classifier_envelope_box = layout_visible_classifier_get_envelope_box_const( the_classifier ); double top = geometry_rectangle_get_top ( classifier_envelope_box ); double bottom = geometry_rectangle_get_bottom ( classifier_envelope_box ); double left = geometry_rectangle_get_left ( classifier_envelope_box ); double right = geometry_rectangle_get_right ( classifier_envelope_box ); /* choose distance */ double shift_x = 0.0; double shift_y = 0.0; /* check overlap to diagram boundary */ { if ( bottom > geometry_rectangle_get_bottom( (*this_).diagram_draw_area ) ) { shift_y = geometry_rectangle_get_bottom( (*this_).diagram_draw_area ) - bottom; } if ( top < geometry_rectangle_get_top( (*this_).diagram_draw_area ) ) { shift_y = geometry_rectangle_get_top( (*this_).diagram_draw_area ) - top; } if ( right > geometry_rectangle_get_right( (*this_).diagram_draw_area ) ) { shift_x = geometry_rectangle_get_right( (*this_).diagram_draw_area ) - right; } if ( left < geometry_rectangle_get_left( (*this_).diagram_draw_area ) ) { shift_x = geometry_rectangle_get_left( (*this_).diagram_draw_area ) - left; } } *out_solutions_count = 1; out_solution_move_dx[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_NOT] = shift_x; out_solution_move_dy[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_NOT] = shift_y; /* determine minimum and comfort distances between classifiers */ const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size ); out_solution_move_dx[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_UP_MIN] = shift_x; out_solution_move_dy[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_UP_MIN] = shift_y; out_solution_move_dx[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_DOWN_MIN] = shift_x; out_solution_move_dy[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_DOWN_MIN] = shift_y; out_solution_move_dx[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_LEFT_MIN] = shift_x; out_solution_move_dy[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_LEFT_MIN] = shift_y; out_solution_move_dx[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_RIGHT_MIN] = shift_x; out_solution_move_dy[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_RIGHT_MIN] = shift_y; /* adjust information on current rectangle */ top += shift_y; bottom += shift_y; left += shift_x; right += shift_x; /* check overlap to already moved classifiers */ for ( uint32_t probe_sort_index = 0; probe_sort_index < sort_index; probe_sort_index ++ ) { /* get classifier to check overlaps */ const uint32_t probe_index = universal_array_index_sorter_get_array_index( sorted, probe_sort_index ); const layout_visible_classifier_t *const the_probe = pencil_layout_data_get_visible_classifier_const( (*this_).layout_data, probe_index ); const geometry_rectangle_t *const probe_envelope_box = layout_visible_classifier_get_envelope_box_const( the_probe ); const double probe_top = geometry_rectangle_get_top ( probe_envelope_box ); const double probe_bottom = geometry_rectangle_get_bottom ( probe_envelope_box ); const double probe_left = geometry_rectangle_get_left ( probe_envelope_box ); const double probe_right = geometry_rectangle_get_right ( probe_envelope_box ); if ( probe_right < left ) { /* no overlap, finished. */ } else if ( probe_left > right ) { /* no overlap, finished. */ } else if ( probe_bottom < top ) { /* no overlap, finished. */ } else if ( probe_top > bottom ) { /* no overlap, finished. */ } else if ( pencil_layout_data_is_ancestor( (*this_).layout_data, the_probe, the_classifier ) ) { /* overlapping the parent is ok, finished */ } else if ( pencil_layout_data_is_ancestor( (*this_).layout_data, the_classifier, the_probe ) ) { /* overlapping the child is ok, finished */ } else { /* there is an overlap - at least when considering the comfort zone */ double my_shift_x_left_min; my_shift_x_left_min = probe_left - right - gap; if ( my_shift_x_left_min < out_solution_move_dx[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_LEFT_MIN] ) { out_solution_move_dx[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_LEFT_MIN] = my_shift_x_left_min; } double my_shift_x_right_min; my_shift_x_right_min = probe_right - left + gap; if ( my_shift_x_right_min > out_solution_move_dx[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_RIGHT_MIN] ) { out_solution_move_dx[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_RIGHT_MIN] = my_shift_x_right_min; } double my_shift_y_up_min; my_shift_y_up_min = probe_top - bottom - gap; if ( my_shift_y_up_min < out_solution_move_dy[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_UP_MIN] ) { out_solution_move_dy[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_UP_MIN] = my_shift_y_up_min; } double my_shift_y_down_min; my_shift_y_down_min = probe_bottom - top + gap; if ( my_shift_y_down_min > out_solution_move_dy[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_DOWN_MIN] ) { out_solution_move_dy[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_DOWN_MIN] = my_shift_y_down_min; } *out_solutions_count = PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_MAX; /* trace */ const data_visible_classifier_t *visible_classifier_data; visible_classifier_data = layout_visible_classifier_get_data_const ( the_probe ); if (( visible_classifier_data != NULL ) && ( data_visible_classifier_is_valid( visible_classifier_data ) )) { const data_classifier_t *classifier_p; classifier_p = data_visible_classifier_get_classifier_const( visible_classifier_data ); TRACE_INFO_STR( "- overlaps:", data_classifier_get_name_const( classifier_p ) ); } } } /* trace */ const data_visible_classifier_t *visible_classifier; visible_classifier = layout_visible_classifier_get_data_const ( the_classifier ); const data_classifier_t *classifier; classifier = data_visible_classifier_get_classifier_const( visible_classifier ); TRACE_INFO_STR( "classifier:", data_classifier_get_name_const( classifier ) ); TRACE_END(); } void pencil_classifier_2d_layouter_private_propose_anchored_solution( pencil_classifier_2d_layouter_t *this_, const universal_array_index_sorter_t *sorted, uint32_t sort_index, double * out_solution_move_dx, double * out_solution_move_dy ) { TRACE_BEGIN(); assert ( NULL != sorted ); assert ( universal_array_index_sorter_get_count( sorted ) > sort_index ); assert ( NULL != out_solution_move_dx ); assert ( NULL != out_solution_move_dy ); /* get classifier to move */ const uint32_t index = universal_array_index_sorter_get_array_index( sorted, sort_index ); const layout_visible_classifier_t *const the_classifier = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, index ); /* determine the space needed for the solution */ const geometry_rectangle_t *const classifier_envelope_box = layout_visible_classifier_get_envelope_box_const( the_classifier ); const double width = geometry_rectangle_get_width( classifier_envelope_box ); const double height = geometry_rectangle_get_height( classifier_envelope_box ); const double gap = pencil_size_get_preferred_object_distance( (*this_).pencil_size ); /* wish a solution area */ geometry_rectangle_t classifier_solution_area; geometry_rectangle_init ( &classifier_solution_area, geometry_rectangle_get_left( classifier_envelope_box ) - 0.5*width - gap, geometry_rectangle_get_top( classifier_envelope_box ) - 0.5*height - gap, 2.0*width + 2.0*gap, 2.0*height + 2.0*gap ); /* shrink solution area to diagram_draw_area */ geometry_rectangle_init_by_intersect( &classifier_solution_area, &classifier_solution_area, (*this_).diagram_draw_area ); /* check overlap to already moved classifiers */ for ( uint32_t probe_sort_index = 0; probe_sort_index < sort_index; probe_sort_index ++ ) { /* get classifier to check overlaps */ const uint32_t probe_index = universal_array_index_sorter_get_array_index( sorted, probe_sort_index ); const layout_visible_classifier_t *const the_probe = pencil_layout_data_get_visible_classifier_const( (*this_).layout_data, probe_index ); geometry_rectangle_t probe_total_bounds; geometry_rectangle_init_by_bounds( &probe_total_bounds, layout_visible_classifier_get_label_box_const( the_probe ), layout_visible_classifier_get_envelope_box_const( the_probe ) ); geometry_rectangle_init_by_difference( &classifier_solution_area, &classifier_solution_area, &probe_total_bounds ); } /* reduce the biggest free/unoccupied box by gap */ geometry_rectangle_shift ( &classifier_solution_area, gap, gap ); geometry_rectangle_enlarge ( &classifier_solution_area, -2.0*gap, -2.0*gap ); /* move - but not to eager - only the minumum distance */ const bool is_x_contained = ( geometry_rectangle_get_left( &classifier_solution_area ) < geometry_rectangle_get_left( classifier_envelope_box ) ) && ( geometry_rectangle_get_right( classifier_envelope_box ) < geometry_rectangle_get_right( &classifier_solution_area ) ); const bool is_y_contained = ( geometry_rectangle_get_top( &classifier_solution_area ) < geometry_rectangle_get_top( classifier_envelope_box ) ) && ( geometry_rectangle_get_bottom( classifier_envelope_box ) < geometry_rectangle_get_bottom( &classifier_solution_area ) ); if ( is_x_contained ) { *out_solution_move_dx = 0.0; } else { const double sol_center_x = geometry_rectangle_get_center_x( &classifier_solution_area ); const double cur_center_x = geometry_rectangle_get_center_x( classifier_envelope_box ); *out_solution_move_dx = ( sol_center_x < cur_center_x ) ? geometry_rectangle_get_right( &classifier_solution_area ) - geometry_rectangle_get_right( classifier_envelope_box ) : geometry_rectangle_get_left( &classifier_solution_area ) - geometry_rectangle_get_left( classifier_envelope_box ); geometry_rectangle_trace( &classifier_solution_area ); geometry_rectangle_trace( classifier_envelope_box ); } if ( is_y_contained ) { *out_solution_move_dy = 0.0; } else { const double sol_center_y = geometry_rectangle_get_center_y( &classifier_solution_area ); const double cur_center_y = geometry_rectangle_get_center_y( classifier_envelope_box ); *out_solution_move_dy = ( sol_center_y < cur_center_y ) ? geometry_rectangle_get_bottom( &classifier_solution_area ) - geometry_rectangle_get_bottom( classifier_envelope_box ) : geometry_rectangle_get_top( &classifier_solution_area ) - geometry_rectangle_get_top( classifier_envelope_box ); } /* trace */ const data_visible_classifier_t *visible_classifier; visible_classifier = layout_visible_classifier_get_data_const ( the_classifier ); const data_classifier_t *classifier; classifier = data_visible_classifier_get_classifier_const( visible_classifier ); TRACE_INFO_STR( "classifier:", data_classifier_get_name_const( classifier ) ); TRACE_END(); } void pencil_classifier_2d_layouter_private_select_move_solution( pencil_classifier_2d_layouter_t *this_, const universal_array_index_sorter_t *sorted, uint32_t sort_index, uint32_t solutions_count, const double solution_move_dx[], const double solution_move_dy[], uint32_t *out_index_of_best ) { TRACE_BEGIN(); assert ( NULL != sorted ); assert ( universal_array_index_sorter_get_count( sorted ) > sort_index ); assert ( NULL != solution_move_dx ); assert ( NULL != solution_move_dy ); assert ( NULL != out_index_of_best ); assert ( 1 <= solutions_count ); /* define potential solution and rating */ uint32_t index_of_best; double debts_of_best; index_of_best = 0; /* in case of doubts, take the first solution */ debts_of_best = 1000000000.0; /* get classifier to move */ const uint32_t index = universal_array_index_sorter_get_array_index( sorted, sort_index ); const layout_visible_classifier_t *const the_classifier = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, index ); const geometry_rectangle_t *const classifier_envelope_box = layout_visible_classifier_get_envelope_box_const( the_classifier ); /* check all solutions */ for ( uint32_t solution_index = 0; solution_index < solutions_count; solution_index ++ ) { /* calculate the solution rectangle */ geometry_rectangle_t solution_bounds; geometry_rectangle_copy( &solution_bounds, classifier_envelope_box ); geometry_rectangle_shift ( &solution_bounds, solution_move_dx[solution_index], solution_move_dy[solution_index] ); /* evalute the debts of this solution */ double debts_of_current; debts_of_current = 0.0; /* add move distance as debt */ debts_of_current += fabs ( solution_move_dx[solution_index] ); debts_of_current += fabs ( solution_move_dy[solution_index] ); /* add debts for overlap to diagram boundary */ { static const double DIAG_BOUNDS_SEVERITY = 32.0; double current_area = geometry_rectangle_get_area ( &solution_bounds ); geometry_rectangle_t intersect; geometry_rectangle_init_by_intersect( &intersect, &solution_bounds, (*this_).diagram_draw_area ); double intersect_area = geometry_rectangle_get_area ( &intersect ); debts_of_current += DIAG_BOUNDS_SEVERITY * ( current_area - intersect_area ); } /* check overlap to other classifiers */ for ( uint32_t probe_sort_index = 0; probe_sort_index < universal_array_index_sorter_get_count( sorted ); probe_sort_index ++ ) { if ( probe_sort_index != sort_index ) /* skip self */ { /* get classifier to check overlaps */ const uint32_t probe_index = universal_array_index_sorter_get_array_index( sorted, probe_sort_index ); const layout_visible_classifier_t *const the_probe = pencil_layout_data_get_visible_classifier_const( (*this_).layout_data, probe_index ); const geometry_rectangle_t *const probe_envelope_box = layout_visible_classifier_get_envelope_box_const( the_probe ); geometry_rectangle_t probe_intersect; const int intersect_err = geometry_rectangle_init_by_intersect( &probe_intersect, &solution_bounds, probe_envelope_box ); if ( 0 == intersect_err ) { /* there is an intersect */ if ( pencil_layout_data_is_ancestor( (*this_).layout_data, the_classifier, the_probe ) ) { /* no debt: parent my overlap children */ } else if ( pencil_layout_data_is_ancestor( (*this_).layout_data, the_probe, the_classifier ) ) { /* no debt: child may overlap parent */ } else { /* already processed classifiers have higher severity because these do not move anymore */ const double severity = ( probe_sort_index < sort_index ) ? 4.0 : 1.0; const double probe_intersect_area = geometry_rectangle_get_area ( &probe_intersect ); debts_of_current += severity * probe_intersect_area; } } /* else no intersect/overlap */ } } /* finish evaluating this solution */ geometry_rectangle_destroy( &solution_bounds ); if ( debts_of_current < debts_of_best ) { debts_of_best = debts_of_current; index_of_best = solution_index; } } *out_index_of_best = index_of_best; TRACE_END(); } /* ================================ EMBRACE CHILDREN STEP BY STEP ================================ */ void pencil_classifier_2d_layouter_embrace_children( pencil_classifier_2d_layouter_t *this_, PangoLayout *font_layout ) { TRACE_BEGIN(); assert( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS ); universal_array_index_sorter_t sorted_relationships; universal_array_index_sorter_init( &sorted_relationships ); /* sort the relationships by their number of descendants */ pencil_classifier_2d_layouter_private_propose_embracing_order ( this_, &sorted_relationships ); /* init the set of classifiers that has embraced children */ data_small_set_t has_embraced_children; data_small_set_init( &has_embraced_children ); /* move the classifiers */ const uint32_t count_sorted = universal_array_index_sorter_get_count( &sorted_relationships ); for ( uint32_t rel_sort_idx = 0; rel_sort_idx < count_sorted; rel_sort_idx ++ ) { const uint32_t rel_idx = universal_array_index_sorter_get_array_index( &sorted_relationships, rel_sort_idx ); layout_relationship_t *const the_relationship = pencil_layout_data_get_relationship_ptr( (*this_).layout_data, rel_idx ); assert ( the_relationship != NULL ); const data_relationship_t *const rel_data = layout_relationship_get_data_const ( the_relationship ); assert ( rel_data != NULL ); const data_id_t rel_from_id = data_relationship_get_from_classifier_data_id ( rel_data ); const int failure = pencil_classifier_2d_layouter_private_try_embrace_child( this_, the_relationship, ! data_small_set_contains( &has_embraced_children, rel_from_id ), font_layout ); if ( ! failure ) { /* only in case of success, children are counted as embraced */ data_small_set_add_obj( &has_embraced_children, rel_from_id ); } } data_small_set_destroy( &has_embraced_children ); universal_array_index_sorter_destroy( &sorted_relationships ); TRACE_END(); } void pencil_classifier_2d_layouter_private_propose_embracing_order ( pencil_classifier_2d_layouter_t *this_, universal_array_index_sorter_t *out_sorted ) { TRACE_BEGIN(); assert( NULL != out_sorted ); const uint32_t rel_count = pencil_layout_data_get_relationship_count( (*this_).layout_data ); for ( uint32_t rel_idx = 0; rel_idx < rel_count; rel_idx ++ ) { const layout_relationship_t *const the_relationship = pencil_layout_data_get_relationship_ptr( (*this_).layout_data, rel_idx ); /* count the descendants */ const layout_visible_classifier_t *const from_classifier = layout_relationship_get_from_classifier_ptr( the_relationship ); const uint32_t from_descendant_count = pencil_layout_data_count_descendants( (*this_).layout_data, from_classifier ); /* sort it into the array by the number of decendants: */ /* the less descendants the earlier it shall be processed. */ const int err = universal_array_index_sorter_insert( out_sorted, rel_idx, (double)from_descendant_count ); if ( 0 != err ) { TSLOG_ERROR ( "universal_array_index_sorter_t list is full." ); } } TRACE_END(); } int pencil_classifier_2d_layouter_private_try_embrace_child( pencil_classifier_2d_layouter_t *this_, layout_relationship_t *the_relationship, bool move, PangoLayout *font_layout ) { TRACE_BEGIN(); assert( NULL != the_relationship ); int result_err = -1; const data_relationship_type_t the_type = data_relationship_get_main_type ( layout_relationship_get_data_const( the_relationship )); if ( DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT == the_type ) { layout_visible_classifier_t *const from_classifier = layout_relationship_get_from_classifier_ptr( the_relationship ); const layout_visible_classifier_t *const to_classifier = layout_relationship_get_to_classifier_ptr( the_relationship ); if ( from_classifier != to_classifier ) { layout_visible_classifier_t probe_parent_layout; layout_visible_classifier_copy( &probe_parent_layout, from_classifier ); const geometry_rectangle_t * parent_space = layout_visible_classifier_get_space_const( &probe_parent_layout ); const geometry_rectangle_t child_envelope = layout_visible_classifier_get_envelope_box( to_classifier ); geometry_rectangle_t probe_space; if ( move ) { geometry_rectangle_copy( &probe_space, &child_envelope ); } else { geometry_rectangle_init_by_bounds( &probe_space, parent_space, &child_envelope ); } pencil_classifier_composer_expand_space( &((*this_).classifier_composer), &probe_space, true, /* = shows_contained_children */ (*this_).pencil_size, font_layout, &probe_parent_layout ); const geometry_rectangle_t probe_parent_envelope = layout_visible_classifier_get_envelope_box( &probe_parent_layout ); /* check what else would be embraced */ bool illegal_overlap = false; const uint32_t count_clasfy = pencil_layout_data_get_visible_classifier_count ( (*this_).layout_data ); for ( uint32_t c_index = 0; c_index < count_clasfy; c_index ++ ) { layout_visible_classifier_t *probe_classifier; probe_classifier = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, c_index ); if (( probe_classifier != from_classifier )&&( probe_classifier != to_classifier )) { if ( pencil_layout_data_is_ancestor( (*this_).layout_data, from_classifier, probe_classifier ) ) { /* it is ok to embrace also other children, no illegal_overlap */ } else if ( pencil_layout_data_is_ancestor( (*this_).layout_data, probe_classifier, from_classifier ) ) { /* it is ok if parent is already contained in grand-parent classifier, no illegal_overlap */ } else { const geometry_rectangle_t *const current_envelope_box = layout_visible_classifier_get_envelope_box_const ( probe_classifier ); illegal_overlap |= geometry_rectangle_is_intersecting( current_envelope_box, &probe_parent_envelope ); } } } /* check overlap to diagram boundary */ if ( ! geometry_rectangle_is_containing ( (*this_).diagram_draw_area, &probe_parent_envelope ) ) { illegal_overlap = true; } /* cancel or commit */ if ( ! illegal_overlap ) { layout_visible_classifier_replacemove( from_classifier, &probe_parent_layout ); result_err = 0; } else { layout_visible_classifier_destroy( &probe_parent_layout ); } /* cleanup */ geometry_rectangle_destroy( &probe_space ); } else { TRACE_INFO( "Classifier contains itself" ); } } /* else this is not a parent child relationship */ TRACE_END_ERR( result_err ); return result_err; } /* ================================ EMBRACE CHILDREN COMMON ================================ */ void pencil_classifier_2d_layouter_hide_relations_of_embraced_children( pencil_classifier_2d_layouter_t *this_ ) { TRACE_BEGIN(); /* search containment relations */ const uint32_t rel_count = pencil_layout_data_get_relationship_count( (*this_).layout_data ); for ( uint32_t rel_idx = 0; rel_idx < rel_count; rel_idx ++ ) { const layout_relationship_t *const the_relationship = pencil_layout_data_get_relationship_const( (*this_).layout_data, rel_idx ); const data_relationship_t *const the_rel_data = layout_relationship_get_data_const( the_relationship ); const data_relationship_type_t the_type = data_relationship_get_main_type ( the_rel_data ); const pencil_visibility_t visibility = layout_relationship_get_visibility( the_relationship ); if (( DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT == the_type ) && (( PENCIL_VISIBILITY_SHOW == visibility )||(PENCIL_VISIBILITY_GRAY_OUT == visibility) )) { const layout_visible_classifier_t *const from_classifier = layout_relationship_get_from_classifier_ptr( the_relationship ); const layout_visible_classifier_t *const to_classifier = layout_relationship_get_to_classifier_ptr( the_relationship ); if ( from_classifier != to_classifier ) { const geometry_rectangle_t *const parent_space = layout_visible_classifier_get_space_const ( from_classifier ); const geometry_rectangle_t *const child_symbol_box = layout_visible_classifier_get_symbol_box_const ( to_classifier ); /* hide if parent embraced child(symbol) completely */ if ( geometry_rectangle_is_containing( parent_space, child_symbol_box ) ) { pencil_layout_data_set_relationship_visibility( (*this_).layout_data, rel_idx, PENCIL_VISIBILITY_IMPLICIT ); TRACE_INFO( "Containment relation is PENCIL_VISIBILITY_IMPLICIT" ); } } } } TRACE_END(); } /* ================================ EMBRACE AND MOVE CHILDREN TOGETHER ================================ */ void pencil_classifier_2d_layouter_move_and_embrace_children( pencil_classifier_2d_layouter_t *this_, PangoLayout *font_layout ) { TRACE_BEGIN(); assert( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) PENCIL_LAYOUT_DATA_MAX_CLASSIFIERS ); const double TAKE_RATIO = (1.0/3.0); const double LEAVE_RATIO = (1.0-TAKE_RATIO); /* const double gap = pencil_size_get_preferred_object_distance( (*this_).pencil_size ); */ universal_array_index_sorter_t sorted_classifiers; universal_array_index_sorter_init( &sorted_classifiers ); /* sort the classifiers by their need to move and to embrace */ pencil_classifier_2d_layouter_private_propose_move_embrace_order ( this_, &sorted_classifiers ); /* small-move and embrace the child classifiers */ const uint32_t count_sorted = universal_array_index_sorter_get_count( &sorted_classifiers ); for ( uint32_t classifier_sort_idx = 0; classifier_sort_idx < count_sorted; classifier_sort_idx ++ ) { const uint32_t classifier_idx = universal_array_index_sorter_get_array_index( &sorted_classifiers, classifier_sort_idx ); layout_visible_classifier_t *const the_classifier = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, classifier_idx ); /* only if the classifier has children */ const uint32_t child_count = pencil_layout_data_count_descendants ( (*this_).layout_data, the_classifier ); if ( child_count > 0 ) { /* get envelope rectangle of all children */ const geometry_rectangle_t children_envelope = pencil_classifier_2d_layouter_private_calc_descendant_envelope( this_, the_classifier ); /* determine outer space around children envelope rectangle */ const geometry_rectangle_t outer_space = pencil_classifier_2d_layouter_private_calc_outer_space( this_, &children_envelope, the_classifier ); /* place the children into the (probe-)parent */ layout_visible_classifier_t probe_parent_layout; layout_visible_classifier_copy( &probe_parent_layout, the_classifier ); pencil_classifier_composer_expand_space( &((*this_).classifier_composer), &children_envelope, true, /* = shows_contained_children */ (*this_).pencil_size, font_layout, &probe_parent_layout ); const geometry_rectangle_t probe_parent_envelope = layout_visible_classifier_get_envelope_box( &probe_parent_layout ); /* check if parent fits into into outer_space */ const double outer_border_x = (geometry_rectangle_get_width( &outer_space ) - geometry_rectangle_get_width(&probe_parent_envelope))/2.0; const double outer_border_y = (geometry_rectangle_get_height( &outer_space ) - geometry_rectangle_get_height(&probe_parent_envelope))/2.0; if (( outer_border_x > 0.0 )&&( outer_border_y > 0.0 )) { /* prepare to move+expand the parent */ geometry_rectangle_t new_envelope; geometry_rectangle_copy( &new_envelope, &outer_space ); geometry_rectangle_shift( &new_envelope, (LEAVE_RATIO*outer_border_x), (LEAVE_RATIO*outer_border_y) ); geometry_rectangle_enlarge( &new_envelope, -2.0*(LEAVE_RATIO*outer_border_x), -2.0*(LEAVE_RATIO*outer_border_y) ); /* move+expand the parent */ pencil_classifier_composer_set_envelope_box( &((*this_).classifier_composer), &new_envelope, true, /* = shows_contained_children */ (*this_).pencil_size, font_layout, the_classifier ); /* cleanup move+expand the parent */ geometry_rectangle_destroy( &new_envelope ); /* determine the descendants move deltas */ const geometry_rectangle_t *const parent_new_space = layout_visible_classifier_get_space_const( the_classifier ); const double descendant_add_dx = geometry_rectangle_get_center_x( parent_new_space ) - geometry_rectangle_get_center_x( &children_envelope ); const double descendant_add_dy = geometry_rectangle_get_center_y( parent_new_space ) - geometry_rectangle_get_center_y( &children_envelope ); /* move the descendants */ pencil_classifier_2d_layouter_private_move_descendants( this_, the_classifier, descendant_add_dx, descendant_add_dy ); } /* cleanup */ layout_visible_classifier_destroy( &probe_parent_layout ); } } universal_array_index_sorter_destroy( &sorted_classifiers ); TRACE_END(); } void pencil_classifier_2d_layouter_private_propose_move_embrace_order ( pencil_classifier_2d_layouter_t *this_, universal_array_index_sorter_t *out_sorted ) { TRACE_BEGIN(); assert ( NULL != out_sorted ); assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) DATA_VISIBLE_SET_MAX_CLASSIFIERS ); /* sort the classifiers by their movement-needs */ const uint32_t count_classifiers = pencil_layout_data_get_visible_classifier_count ( (*this_).layout_data ); for ( uint32_t index = 0; index < count_classifiers; index ++ ) { const layout_visible_classifier_t *const the_classifier = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, index ); int64_t lazy_move = 0; /* grand-parents must be moved after parents (becasue parents are not yet well layouted) */ const uint32_t child_count = pencil_layout_data_count_descendants ( (*this_).layout_data, the_classifier ); lazy_move = child_count; int insert_error; insert_error = universal_array_index_sorter_insert( out_sorted, index, lazy_move ); if ( 0 != insert_error ) { TSLOG_WARNING( "not all rectangles are grown" ); } } TRACE_END(); } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/pencil_classifier_composer.c000066400000000000000000001453711415120503000254410ustar00rootroot00000000000000/* File: pencil_classifier_composer.c; Copyright and License: see below */ #include "pencil_classifier_composer.h" #include "trace.h" #include "util/string/utf8stringbuf.h" #include "util/string/utf8string.h" #include #include #include #include void pencil_classifier_composer_init( pencil_classifier_composer_t *this_ ) { TRACE_BEGIN(); pencil_marker_init( &((*this_).marker) ); data_rules_init ( &((*this_).data_rules) ); draw_classifier_icon_init( &((*this_).draw_classifier_icon) ); draw_classifier_label_init( &((*this_).draw_classifier_label) ); draw_classifier_contour_init( &((*this_).draw_classifier_contour) ); TRACE_END(); } void pencil_classifier_composer_destroy( pencil_classifier_composer_t *this_ ) { TRACE_BEGIN(); draw_classifier_icon_destroy( &((*this_).draw_classifier_icon) ); draw_classifier_label_destroy( &((*this_).draw_classifier_label) ); draw_classifier_contour_destroy( &((*this_).draw_classifier_contour) ); data_rules_destroy ( &((*this_).data_rules) ); pencil_marker_destroy( &((*this_).marker) ); TRACE_END(); } void pencil_classifier_composer_draw ( const pencil_classifier_composer_t *this_, const layout_visible_classifier_t *layouted_classifier, data_id_t mark_focused, data_id_t mark_highlighted, const data_small_set_t *mark_selected, const pencil_layout_data_t *layout_data, const pencil_size_t *pencil_size, PangoLayout *font_layout, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != pencil_size ); assert( NULL != layouted_classifier ); assert( NULL != layout_data ); assert( NULL != font_layout ); assert( NULL != cr ); const data_visible_classifier_t *const visible_classifier = layout_visible_classifier_get_data_const( layouted_classifier ); const geometry_rectangle_t *const classifier_symbol_box = layout_visible_classifier_get_symbol_box_const( layouted_classifier ); const data_classifier_t *const classifier = data_visible_classifier_get_classifier_const( visible_classifier ); const data_diagramelement_t *const diagramelement = data_visible_classifier_get_diagramelement_const( visible_classifier ); const data_classifier_type_t classifier_type = data_classifier_get_main_type( classifier ); const double gap = pencil_size_get_standard_object_border( pencil_size ); /* draw id */ draw_classifier_label_draw_id( &((*this_).draw_classifier_label), visible_classifier, classifier_symbol_box, pencil_size, font_layout, cr ); /* draw the classifier */ { const data_diagramelement_flag_t display_flags = data_diagramelement_get_display_flags( diagramelement ); TRACE_INFO_INT("drawing classifier id", data_classifier_get_row_id( classifier ) ); const double std_line_width = pencil_size_get_standard_line_width( pencil_size ); cairo_set_line_width( cr, std_line_width ); /* set color */ GdkRGBA foreground_color; { if ( data_id_equals_id( &mark_highlighted, DATA_TABLE_DIAGRAMELEMENT, data_diagramelement_get_row_id( diagramelement ) ) ) { foreground_color = pencil_size_get_highlight_color( pencil_size ); } else if ( 0 != ( display_flags & DATA_DIAGRAMELEMENT_FLAG_GRAY_OUT )) { foreground_color = pencil_size_get_gray_out_color( pencil_size ); } else { foreground_color = pencil_size_get_standard_color( pencil_size ); } cairo_set_source_rgba( cr, foreground_color.red, foreground_color.green, foreground_color.blue, foreground_color.alpha ); } /* highlight */ if ( 0 != ( display_flags & DATA_DIAGRAMELEMENT_FLAG_EMPHASIS )) { const GdkRGBA emph_color = pencil_size_get_emphasized_bgcolor( pencil_size ); cairo_set_source_rgba( cr, emph_color.red, emph_color.green, emph_color.blue, emph_color.alpha ); const geometry_rectangle_t *const box = layout_visible_classifier_get_label_box_const( layouted_classifier ); cairo_rectangle ( cr, geometry_rectangle_get_left(box), geometry_rectangle_get_top(box), geometry_rectangle_get_width(box), geometry_rectangle_get_height(box) ); cairo_fill (cr); cairo_set_source_rgba( cr, foreground_color.red, foreground_color.green, foreground_color.blue, foreground_color.alpha ); } /* draw label */ draw_classifier_label_draw_stereotype_and_name( &((*this_).draw_classifier_label), visible_classifier, layout_visible_classifier_get_label_box_const( layouted_classifier ), pencil_size, font_layout, cr ); /* draw rectangle */ geometry_rectangle_t classifier_icon_box; { geometry_rectangle_copy( &classifier_icon_box, classifier_symbol_box ); geometry_rectangle_enlarge( &classifier_icon_box, -2.0*gap, -2.0*gap ); geometry_rectangle_shift( &classifier_icon_box, gap, gap ); } const double icon_left = geometry_rectangle_get_left ( &classifier_icon_box ); const double icon_top = geometry_rectangle_get_top ( &classifier_icon_box ); const double icon_width = geometry_rectangle_get_width ( &classifier_icon_box ); const double icon_height = geometry_rectangle_get_height ( &classifier_icon_box ); switch ( classifier_type ) { case DATA_CLASSIFIER_TYPE_REQUIREMENT: /* SysML */ case DATA_CLASSIFIER_TYPE_PART: { draw_classifier_contour_draw_rect ( &((*this_).draw_classifier_contour), classifier_symbol_box, pencil_size, cr ); } break; case DATA_CLASSIFIER_TYPE_BLOCK: /* SysML */ case DATA_CLASSIFIER_TYPE_CLASS: case DATA_CLASSIFIER_TYPE_OBJECT: case DATA_CLASSIFIER_TYPE_INTERFACE: { draw_classifier_contour_draw_rect ( &((*this_).draw_classifier_contour), classifier_symbol_box, pencil_size, cr ); pencil_classifier_composer_private_draw_feature_compartments( this_, layouted_classifier, layout_data, pencil_size, cr ); } break; case DATA_CLASSIFIER_TYPE_COMPONENT: { draw_classifier_contour_draw_rect ( &((*this_).draw_classifier_contour), classifier_symbol_box, pencil_size, cr ); /* draw icon */ const double component_icon_height = pencil_size_get_title_font_size( pencil_size ); const geometry_rectangle_t icon_bounds = draw_classifier_icon_get_component_bounds( &((*this_).draw_classifier_icon), icon_left + icon_width - gap, /* x */ icon_top + gap, /* y */ GEOMETRY_H_ALIGN_RIGHT, GEOMETRY_V_ALIGN_TOP, component_icon_height ); draw_classifier_icon_draw_component ( &((*this_).draw_classifier_icon), icon_bounds, cr ); } break; case DATA_CLASSIFIER_TYPE_ARTIFACT: { draw_classifier_contour_draw_rect ( &((*this_).draw_classifier_contour), classifier_symbol_box, pencil_size, cr ); /* draw icon */ const double artifact_icon_height = pencil_size_get_title_font_size( pencil_size ); const geometry_rectangle_t icon_bounds = draw_classifier_icon_get_artifact_bounds( &((*this_).draw_classifier_icon), icon_left + icon_width - gap, /* x */ icon_top + gap, /* y */ GEOMETRY_H_ALIGN_RIGHT, GEOMETRY_V_ALIGN_TOP, artifact_icon_height ); draw_classifier_icon_draw_artifact ( &((*this_).draw_classifier_icon), icon_bounds, cr ); } break; case DATA_CLASSIFIER_TYPE_ACTIVITY: case DATA_CLASSIFIER_TYPE_STATE: case DATA_CLASSIFIER_TYPE_CONSTRAINT_BLOCK: { draw_classifier_contour_draw_rounded_rect ( &((*this_).draw_classifier_contour), classifier_symbol_box, false, pencil_size, cr ); pencil_classifier_composer_private_draw_feature_compartments ( this_, layouted_classifier, layout_data, pencil_size, cr ); } break; case DATA_CLASSIFIER_TYPE_DYN_INTERRUPTABLE_REGION: { draw_classifier_contour_draw_rounded_rect ( &((*this_).draw_classifier_contour), classifier_symbol_box, true, pencil_size, cr ); } break; case DATA_CLASSIFIER_TYPE_USE_CASE: { draw_classifier_contour_draw_ellipse ( &((*this_).draw_classifier_contour), classifier_symbol_box, pencil_size, cr ); pencil_classifier_composer_private_draw_feature_compartments ( this_, layouted_classifier, layout_data, pencil_size, cr ); } break; case DATA_CLASSIFIER_TYPE_NODE: { draw_classifier_contour_draw_3d_box ( &((*this_).draw_classifier_contour), classifier_symbol_box, pencil_size, cr ); } break; case DATA_CLASSIFIER_TYPE_ACTOR: { const double actor_height = icon_height; const double half_width = 0.5 * icon_width; const geometry_rectangle_t icon_bounds = draw_classifier_icon_get_actor_bounds( &((*this_).draw_classifier_icon), icon_left + half_width, icon_top, GEOMETRY_H_ALIGN_CENTER, GEOMETRY_V_ALIGN_TOP, actor_height ); draw_classifier_icon_draw_actor ( &((*this_).draw_classifier_icon), icon_bounds, cr ); } break; case DATA_CLASSIFIER_TYPE_DYN_INITIAL_NODE: case DATA_CLASSIFIER_TYPE_DYN_FINAL_NODE: case DATA_CLASSIFIER_TYPE_DYN_SHALLOW_HISTORY: case DATA_CLASSIFIER_TYPE_DYN_DEEP_HISTORY: { const double circle_diameter = icon_height; const double half_width = 0.5 * icon_width; const geometry_rectangle_t icon_bounds = draw_classifier_icon_get_circle_bounds( &((*this_).draw_classifier_icon), icon_left + half_width, icon_top, GEOMETRY_H_ALIGN_CENTER, GEOMETRY_V_ALIGN_TOP, circle_diameter ); const bool stroke = ( classifier_type != DATA_CLASSIFIER_TYPE_DYN_INITIAL_NODE ); const bool fill = ( ( classifier_type == DATA_CLASSIFIER_TYPE_DYN_INITIAL_NODE ) || ( classifier_type == DATA_CLASSIFIER_TYPE_DYN_FINAL_NODE ) ); const bool shallow_history = ( classifier_type == DATA_CLASSIFIER_TYPE_DYN_SHALLOW_HISTORY ); const bool deep_history = ( classifier_type == DATA_CLASSIFIER_TYPE_DYN_DEEP_HISTORY ); draw_classifier_icon_draw_circle( &((*this_).draw_classifier_icon), icon_bounds, pencil_size, stroke, fill, shallow_history, deep_history, cr ); } break; case DATA_CLASSIFIER_TYPE_DYN_ACCEPT_EVENT : { draw_classifier_contour_draw_accept_event ( &((*this_).draw_classifier_contour), classifier_symbol_box, pencil_size, cr ); } break; case DATA_CLASSIFIER_TYPE_DYN_SEND_SIGNAL: { draw_classifier_contour_draw_send_signal ( &((*this_).draw_classifier_contour), classifier_symbol_box, pencil_size, cr ); } break; case DATA_CLASSIFIER_TYPE_DYN_ACCEPT_TIME_EVENT: { const double time_icon_height = icon_height; const double half_width = 0.5 * icon_width; const geometry_rectangle_t icon_bounds = draw_classifier_icon_get_time_bounds( &((*this_).draw_classifier_icon), icon_left + half_width, icon_top, GEOMETRY_H_ALIGN_CENTER, GEOMETRY_V_ALIGN_TOP, time_icon_height ); draw_classifier_icon_draw_time ( &((*this_).draw_classifier_icon), icon_bounds, cr ); } break; case DATA_CLASSIFIER_TYPE_DYN_FORK_NODE: case DATA_CLASSIFIER_TYPE_DYN_JOIN_NODE: { const double box_icon_height = icon_height; const double half_width = 0.5 * icon_width; const geometry_rectangle_t icon_bounds = draw_classifier_icon_get_sync_bounds( &((*this_).draw_classifier_icon), icon_left + half_width, icon_top, GEOMETRY_H_ALIGN_CENTER, GEOMETRY_V_ALIGN_TOP, box_icon_height, pencil_size ); draw_classifier_icon_draw_sync ( &((*this_).draw_classifier_icon), icon_bounds, cr ); } break; case DATA_CLASSIFIER_TYPE_DYN_DECISION_NODE: { draw_classifier_contour_draw_rhombus ( &((*this_).draw_classifier_contour), classifier_symbol_box, pencil_size, cr ); } break; case DATA_CLASSIFIER_TYPE_SUBSYSTEM: { draw_classifier_contour_draw_rect ( &((*this_).draw_classifier_contour), classifier_symbol_box, pencil_size, cr ); } break; case DATA_CLASSIFIER_TYPE_DIAGRAM_REFERENCE: { draw_classifier_contour_draw_diagram_ref ( &((*this_).draw_classifier_contour), classifier_symbol_box, pencil_size, cr ); } break; case DATA_CLASSIFIER_TYPE_PACKAGE: { const geometry_rectangle_t *const classifier_label_box = layout_visible_classifier_get_label_box_const( layouted_classifier ); draw_classifier_contour_draw_package( &((*this_).draw_classifier_contour), classifier_symbol_box, classifier_label_box, pencil_size, cr ); } break; case DATA_CLASSIFIER_TYPE_COMMENT: { draw_classifier_contour_draw_comment ( &((*this_).draw_classifier_contour), classifier_symbol_box, pencil_size, cr ); } break; default: { TSLOG_ERROR("unknown data_classifier_type_t in pencil_classifier_composer_draw()"); } break; } #ifdef PENCIL_LAYOUT_DATA_DRAW_FOR_DEBUG /* draw the rectangles */ { const geometry_rectangle_t *const classifier_space = layout_visible_classifier_get_space_const( layouted_classifier ); const geometry_rectangle_t *const classifier_label_box = layout_visible_classifier_get_label_box_const( layouted_classifier ); cairo_set_source_rgba( cr, 1.0, 0.5, 0.6, 0.5 ); cairo_rectangle ( cr, geometry_rectangle_get_left ( classifier_symbol_box ), geometry_rectangle_get_top ( classifier_symbol_box ), geometry_rectangle_get_width ( classifier_symbol_box ), geometry_rectangle_get_height ( classifier_symbol_box ) ); cairo_rectangle ( cr, geometry_rectangle_get_left ( classifier_space ), geometry_rectangle_get_top ( classifier_space ), geometry_rectangle_get_width ( classifier_space ), geometry_rectangle_get_height ( classifier_space ) ); cairo_rectangle ( cr, geometry_rectangle_get_left ( classifier_label_box ), geometry_rectangle_get_top ( classifier_label_box ), geometry_rectangle_get_width ( classifier_label_box ), geometry_rectangle_get_height ( classifier_label_box ) ); cairo_stroke (cr); } #endif if ( data_small_set_contains_row_id( mark_selected, DATA_TABLE_DIAGRAMELEMENT, data_diagramelement_get_row_id(diagramelement) ) ) { pencil_marker_mark_selected_rectangle( &((*this_).marker), *classifier_symbol_box, cr ); } if ( data_id_equals_id( &mark_focused, DATA_TABLE_DIAGRAMELEMENT, data_diagramelement_get_row_id(diagramelement) ) || data_id_equals_id( &mark_focused, DATA_TABLE_CLASSIFIER, data_classifier_get_row_id(classifier) ) ) { pencil_marker_mark_focused_rectangle( &((*this_).marker), *classifier_symbol_box, cr ); } } TRACE_END(); } int pencil_classifier_composer_expand_space ( const pencil_classifier_composer_t *this_, const geometry_rectangle_t *space, bool shows_contained_children, const pencil_size_t *pencil_size, PangoLayout *font_layout, layout_visible_classifier_t *io_classifier_layout ) { TRACE_BEGIN(); assert( NULL != space ); assert( NULL != pencil_size ); assert( NULL != font_layout ); assert( NULL != io_classifier_layout ); /* get data that shall be layouted/composed */ const data_visible_classifier_t *const visible_classifier = layout_visible_classifier_get_data_const( io_classifier_layout ); const data_classifier_t *const classifier = data_visible_classifier_get_classifier_const( visible_classifier ); const data_classifier_type_t classifier_type = data_classifier_get_main_type( classifier ); TRACE_INFO_INT("expanding bounds of classifier id:", data_classifier_get_row_id( classifier ) ); TRACE_INFO_INT_INT("expanding bounds of classifier type, children:", classifier_type, shows_contained_children?1:0 ); /* determine icon space */ const geometry_dimensions_t icon_dim = draw_classifier_icon_get_icon_dimensions( &((*this_).draw_classifier_icon), classifier_type, pencil_size ); /* determine border sizes of the main line (label and optionally icon) */ geometry_rectangle_t label_rect; geometry_rectangle_init_empty( &label_rect ); geometry_rectangle_t label_compartment; geometry_rectangle_init_empty( &label_compartment ); const geometry_rectangle_t *space_and_label_fake = space; /* fake space_and_label to be identical to requested space */ const int area_too_small = pencil_classifier_composer_private_get_label_box( this_, visible_classifier, shows_contained_children, space_and_label_fake, &icon_dim, pencil_size, font_layout, &label_rect, &label_compartment ); if ( area_too_small != 0 ) { TRACE_INFO("new width is defined by label-and-icon, not by requested inner space" ); } const double label_top = geometry_rectangle_get_top( space ) - geometry_rectangle_get_height( &label_compartment ); geometry_rectangle_set_top( &label_rect, label_top ); geometry_rectangle_set_top( &label_compartment, label_top ); /* sizes of geometric objects are determined, */ /* now position the geometric objects */ { const bool is_fix_sized_symbol = draw_classifier_icon_is_fix_sized_symbol( &((*this_).draw_classifier_icon), classifier_type ); if ( is_fix_sized_symbol ) { TRACE_INFO("calculating symbol box for fixed-sized icon..." ); const double symbol_height = pencil_size_get_classifier_symbol_height( pencil_size ); const double symbol_width = symbol_height; /* calculate symbol bounds */ const geometry_h_align_t H_CENTER = GEOMETRY_H_ALIGN_CENTER; const double symbol_left = geometry_h_align_get_left( &H_CENTER, symbol_width, geometry_rectangle_get_left( space ), geometry_rectangle_get_width( space ) ); const double symbol_top = geometry_rectangle_get_top( &label_compartment ) - symbol_height; geometry_rectangle_t classifier_symbol_box; geometry_rectangle_init( &classifier_symbol_box, symbol_left, symbol_top, symbol_width, symbol_height ); layout_visible_classifier_set_symbol_box( io_classifier_layout, &classifier_symbol_box ); geometry_rectangle_destroy( &classifier_symbol_box ); } else { TRACE_INFO("calculating symbol box as envelope around label and space..." ); /* calculate symbol bounds */ geometry_rectangle_t inner_area; if ( area_too_small ) { geometry_rectangle_init( &inner_area, geometry_rectangle_get_left( &label_compartment ), geometry_rectangle_get_top( &label_compartment ), geometry_rectangle_get_width( &label_compartment ), geometry_rectangle_get_height( &label_compartment ) + geometry_rectangle_get_height( space ) ); } else { geometry_rectangle_copy( &inner_area, space ); geometry_rectangle_shift( &inner_area, 0.0, -geometry_rectangle_get_height( &label_compartment ) ); geometry_rectangle_enlarge( &inner_area, 0.0, geometry_rectangle_get_height( &label_compartment ) ); } const geometry_rectangle_t envelope = draw_classifier_contour_calc_outer_bounds( &((*this_).draw_classifier_contour), classifier_type, &inner_area, pencil_size ); layout_visible_classifier_set_symbol_box( io_classifier_layout, &envelope ); geometry_rectangle_destroy( &inner_area ); } /* calculate label_box */ layout_visible_classifier_set_label_box( io_classifier_layout, &label_rect ); layout_visible_classifier_set_label_anchor( io_classifier_layout, GEOMETRY_H_ALIGN_CENTER, GEOMETRY_V_ALIGN_TOP ); /* calculate space */ /* get the symbol and label boxes and inner space rectangles to modify */ geometry_rectangle_t classifier_space; geometry_rectangle_init( &classifier_space, geometry_rectangle_get_left( &label_compartment ), geometry_rectangle_get_top( space ), geometry_rectangle_get_width( &label_compartment ), geometry_rectangle_get_height( space ) ); layout_visible_classifier_set_space( io_classifier_layout, &classifier_space ); geometry_rectangle_destroy( &classifier_space ); } TRACE_INFO("==== symbol_box ====" ); geometry_rectangle_trace( layout_visible_classifier_get_symbol_box_const( io_classifier_layout ) ); TRACE_INFO("==== label_box ====" ); geometry_rectangle_trace( &label_rect ); TRACE_INFO("==== space =====" ); geometry_rectangle_trace( layout_visible_classifier_get_space_const( io_classifier_layout ) ); geometry_rectangle_destroy( &label_rect ); geometry_rectangle_destroy( &label_compartment ); TRACE_END_ERR(area_too_small); return area_too_small; } int pencil_classifier_composer_set_envelope_box( const pencil_classifier_composer_t *this_, const geometry_rectangle_t *envelope, bool shows_contained_children, const pencil_size_t *pencil_size, PangoLayout *font_layout, layout_visible_classifier_t *io_classifier_layout ) { TRACE_BEGIN(); assert( NULL != envelope ); assert( NULL != pencil_size ); assert( NULL != font_layout ); assert( NULL != io_classifier_layout ); /* get data that shall be layouted/composed */ const data_visible_classifier_t *const visible_classifier = layout_visible_classifier_get_data_const( io_classifier_layout ); const data_classifier_t *const classifier = data_visible_classifier_get_classifier_const( visible_classifier ); const data_classifier_type_t classifier_type = data_classifier_get_main_type( classifier ); TRACE_INFO_INT("calculating bounds of classifier id, type:", data_classifier_get_row_id( classifier ) ); TRACE_INFO_INT_INT("calculating bounds of classifier type, children:", classifier_type, shows_contained_children?1:0 ); /* determine icon space */ const geometry_dimensions_t icon_dim = draw_classifier_icon_get_icon_dimensions( &((*this_).draw_classifier_icon), classifier_type, pencil_size ); /* determine border sizes of the classifier-shape */ const geometry_rectangle_t space_and_label = draw_classifier_contour_calc_inner_area( &((*this_).draw_classifier_contour), classifier_type, envelope, pencil_size ); /* determine border sizes of the main line (label and optionally icon) */ geometry_rectangle_t label_rect; geometry_rectangle_init_empty( &label_rect ); geometry_rectangle_t label_compartment; geometry_rectangle_init_empty( &label_compartment ); const int area_too_small = pencil_classifier_composer_private_get_label_box( this_, visible_classifier, shows_contained_children, &space_and_label, &icon_dim, pencil_size, font_layout, &label_rect, &label_compartment ); /* if label fits into space_and_label */ if ( 0 == area_too_small ) { const bool is_fix_sized_symbol = draw_classifier_icon_is_fix_sized_symbol( &((*this_).draw_classifier_icon), classifier_type ); /* get the symbol and label boxes and inner space rectangles to modify */ geometry_rectangle_t classifier_space; geometry_rectangle_copy( &classifier_space, &space_and_label ); if ( is_fix_sized_symbol ) { TRACE_INFO("calculating symbol box for fixed-sized icon..." ); const double symbol_height = pencil_size_get_classifier_symbol_height( pencil_size ); const double symbol_width = symbol_height; /* calculate symbol bounds */ const geometry_h_align_t H_CENTER = GEOMETRY_H_ALIGN_CENTER; const double symbol_left = geometry_h_align_get_left( &H_CENTER, symbol_width, geometry_rectangle_get_left( &space_and_label ), geometry_rectangle_get_width( &space_and_label ) ); const double symbol_top = geometry_rectangle_get_top( &label_compartment ) - symbol_height; geometry_rectangle_t classifier_symbol_box; geometry_rectangle_init( &classifier_symbol_box, symbol_left, symbol_top, symbol_width, symbol_height ); layout_visible_classifier_set_symbol_box( io_classifier_layout, &classifier_symbol_box ); geometry_rectangle_destroy( &classifier_symbol_box ); /* calculate space */ const double label_and_symbol_height = geometry_rectangle_get_height( &label_compartment ) + symbol_height; geometry_rectangle_shift( &classifier_space, 0.0, label_and_symbol_height ); geometry_rectangle_enlarge( &classifier_space, 0.0, -label_and_symbol_height ); } else { TRACE_INFO("calculating symbol box as envelope around label and space..." ); /* calculate symbol bounds */ layout_visible_classifier_set_symbol_box( io_classifier_layout, envelope ); /* calculate space */ geometry_rectangle_shift( &classifier_space, 0.0, geometry_rectangle_get_height( &label_compartment ) ); geometry_rectangle_enlarge( &classifier_space, 0.0, -geometry_rectangle_get_height( &label_compartment ) ); } layout_visible_classifier_set_space( io_classifier_layout, &classifier_space ); /* calculate label_box */ layout_visible_classifier_set_label_box( io_classifier_layout, &label_rect ); layout_visible_classifier_set_label_anchor( io_classifier_layout, GEOMETRY_H_ALIGN_CENTER, GEOMETRY_V_ALIGN_TOP ); TRACE_INFO("==== symbol_box ====" ); geometry_rectangle_trace( layout_visible_classifier_get_symbol_box_const( io_classifier_layout ) ); TRACE_INFO("==== label_box ====" ); geometry_rectangle_trace( &label_rect ); TRACE_INFO("==== space =====" ); geometry_rectangle_trace( &classifier_space ); geometry_rectangle_destroy( &classifier_space ); } else { geometry_rectangle_t space_guess; /* guess the inner space based on current text height */ geometry_rectangle_copy( &space_guess, &space_and_label ); geometry_rectangle_shift( &space_guess, 0.0, geometry_rectangle_get_height( &label_compartment ) ); geometry_rectangle_enlarge( &space_guess, 0.0, -geometry_rectangle_get_height( &label_compartment ) ); TRACE_INFO("==== space_guess====" ); geometry_rectangle_trace( &space_guess ); pencil_classifier_composer_expand_space( this_, &space_guess, shows_contained_children, pencil_size, font_layout, io_classifier_layout ); geometry_rectangle_destroy( &space_guess ); /* shift/center to requested position after resizing beyond requested size */ const geometry_rectangle_t current_envelope = layout_visible_classifier_get_envelope_box( io_classifier_layout ); const double shift_to_right = geometry_rectangle_get_center_x( envelope ) - geometry_rectangle_get_center_x( ¤t_envelope ); const double shift_to_bottom = geometry_rectangle_get_center_y( envelope ) - geometry_rectangle_get_center_y( ¤t_envelope ); layout_visible_classifier_shift( io_classifier_layout, shift_to_right, shift_to_bottom ); } geometry_rectangle_destroy( &label_rect ); geometry_rectangle_destroy( &label_compartment ); TRACE_END_ERR( area_too_small ); return area_too_small; } static inline double PENCIL_MAX_OF_2 ( double a, double b ) { return (a (proposed_label_width + 0.0001) ) { TRACE_INFO_INT_INT("label does not fit to provided width", (int)text_width, (int)proposed_label_width ); result = 1; } const double proposed_label_height = geometry_rectangle_get_height( space_and_label ); if ( text_height > (proposed_label_height + 0.0001) ) { TRACE_INFO_INT_INT("label does not fit to provided height", (int)text_height, (int)proposed_label_height ); result = 1; } } if ( ! is_fix_sized_symbol ) { double top_border = geometry_rectangle_get_top( space_and_label ); /* calculate label_compartment */ { const double min_required_width = text_width + icon_gap + geometry_dimensions_get_width( icon_dim ); const double comp_width = PENCIL_MAX_OF_2( min_required_width, geometry_rectangle_get_width( space_and_label ) ); const geometry_h_align_t compartment_h_align = GEOMETRY_H_ALIGN_CENTER; const double comp_left = geometry_h_align_get_left( &compartment_h_align, comp_width, geometry_rectangle_get_left( space_and_label ), geometry_rectangle_get_width( space_and_label ) ); geometry_rectangle_reinit( out_label_compartment, comp_left, top_border, comp_width, text_height ); } /* calculate label_box */ const bool is_package_with_contents = (classifier_type == DATA_CLASSIFIER_TYPE_PACKAGE) && shows_contained_children; if ( is_package_with_contents ) { const geometry_rectangle_t envelope = draw_classifier_contour_calc_outer_bounds( &((*this_).draw_classifier_contour), classifier_type, out_label_compartment, pencil_size ); geometry_rectangle_reinit( out_label_box, geometry_rectangle_get_left( &envelope ) + 2.0 * gap, geometry_rectangle_get_top( &envelope ) + 2.0 * gap, text_width, text_height ); } else { const geometry_h_align_t text_h_align = GEOMETRY_H_ALIGN_CENTER; const double text_left = geometry_h_align_get_left( &text_h_align, text_width, geometry_rectangle_get_left( space_and_label ), geometry_rectangle_get_width( space_and_label ) - icon_gap - geometry_dimensions_get_width( icon_dim ) ); geometry_rectangle_reinit( out_label_box, text_left, top_border, text_width, text_height ); } } else { /*const double symbol_height = pencil_size_get_classifier_symbol_height( pencil_size );*/ /* calculate text position */ const geometry_h_align_t text_h_align = GEOMETRY_H_ALIGN_CENTER; const double text_left = geometry_h_align_get_left( &text_h_align, text_width, geometry_rectangle_get_left( space_and_label ), geometry_rectangle_get_width( space_and_label ) ); const double text_top = geometry_rectangle_get_top( space_and_label ) /*+ symbol_height*/; /* calculate label_compartment */ const double comp_width = PENCIL_MAX_OF_2( text_width, geometry_rectangle_get_width( space_and_label ) ); const geometry_h_align_t compartment_h_align = GEOMETRY_H_ALIGN_CENTER; const double comp_left = geometry_h_align_get_left( &compartment_h_align, comp_width, geometry_rectangle_get_left( space_and_label ), geometry_rectangle_get_width( space_and_label ) ); geometry_rectangle_reinit( out_label_compartment, comp_left, text_top, comp_width, text_height ); /* calculate label_box */ geometry_rectangle_reinit( out_label_box, text_left, text_top, text_width, text_height ); } TRACE_END_ERR( result ); return result; } void pencil_classifier_composer_private_draw_feature_compartments ( const pencil_classifier_composer_t *this_, const layout_visible_classifier_t *layouted_classifier, const pencil_layout_data_t *layout_data, const pencil_size_t *pencil_size, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != layouted_classifier ); assert( NULL != layout_data ); assert( NULL != pencil_size ); assert( NULL != cr ); /* determine number of properties and operations */ uint32_t count_properties = 0; uint32_t count_operations = 0; { /* define names for input data */ const data_row_id_t diagele_id = layout_visible_classifier_get_diagramelement_id ( layouted_classifier ); const uint32_t num_features = pencil_layout_data_get_feature_count ( layout_data ); for ( uint32_t f_probe_idx = 0; f_probe_idx < num_features; f_probe_idx ++ ) { const layout_feature_t *const f_probe_layout = pencil_layout_data_get_feature_const ( layout_data, f_probe_idx ); assert ( NULL != f_probe_layout ); const layout_visible_classifier_t *const probe_vis_classfy = layout_feature_get_classifier_const ( f_probe_layout ); assert ( NULL != probe_vis_classfy ); /* check if this f_probe_layout has the same diagram element id as the_feature */ if ( diagele_id == layout_visible_classifier_get_diagramelement_id ( probe_vis_classfy ) ) { /* this is a feature of the current layouted_classifier */ /* define names for input data */ const data_feature_t *const f_probe_data = layout_feature_get_data_const ( f_probe_layout ); assert ( NULL != f_probe_data ); const data_feature_type_t f_probe_type = data_feature_get_main_type ( f_probe_data ); if ( DATA_FEATURE_TYPE_PROPERTY == f_probe_type ) { count_properties ++; } else if ( DATA_FEATURE_TYPE_OPERATION == f_probe_type ) { count_operations ++; } } } } /* draw compartments if there are features */ if (( count_properties != 0 )||( count_operations != 0 )) { /* define names for input data */ const geometry_rectangle_t *const classifier_symbol_box = layout_visible_classifier_get_symbol_box_const( layouted_classifier ); const geometry_rectangle_t *const classifier_space = layout_visible_classifier_get_space_const( layouted_classifier ); const double feature_height = pencil_size_get_standard_font_size( pencil_size ) + pencil_size_get_font_line_gap( pencil_size ); const double gap = pencil_size_get_standard_object_border( pencil_size ); const double y_coordinate_1 = geometry_rectangle_get_top( classifier_space ); const double y_coordinate_2 = geometry_rectangle_get_top( classifier_space ) + ( count_properties * feature_height ) + ( 2.0 * gap ); draw_classifier_contour_draw_compartment_line ( &((*this_).draw_classifier_contour), classifier_symbol_box, y_coordinate_1, pencil_size, cr ); draw_classifier_contour_draw_compartment_line ( &((*this_).draw_classifier_contour), classifier_symbol_box, y_coordinate_2, pencil_size, cr ); /* const double y_coordinate_3 = geometry_rectangle_get_top( classifier_space ) + ( (count_properties+count_operations) * feature_height ) + ( 4.0 * gap ); draw_classifier_contour_draw_compartment_line ( &((*this_).draw_classifier_contour), classifier_symbol_box, y_coordinate_3, pencil_size, cr ); */ } TRACE_END(); } /* Copyright 2016-2021 Andreas Warnke http://www.apache.org/licenses/LICENSE-2.0 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/pencil_diagram_maker.c000066400000000000000000000434241415120503000241650ustar00rootroot00000000000000/* File: pencil_diagram_maker.c; Copyright and License: see below */ #include "pencil_diagram_maker.h" #include "trace.h" #include #include #include #include void pencil_diagram_maker_draw ( pencil_diagram_maker_t *this_, data_id_t mark_focused, data_id_t mark_highlighted, const data_small_set_t *mark_selected, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != mark_selected ); assert( NULL != cr ); PangoLayout *layout; layout = pango_cairo_create_layout (cr); /* get layout data object */ const pencil_layout_data_t *const layout_data = pencil_layouter_get_layout_data_const ( &((*this_).layouter) ); /* get diagram bounds */ const layout_diagram_t *const diagram_layout = pencil_layout_data_get_diagram_const( layout_data ); const geometry_rectangle_t *const diagram_bounds = layout_diagram_get_bounds_const ( diagram_layout ); double width = geometry_rectangle_get_width ( diagram_bounds ); double height = geometry_rectangle_get_height ( diagram_bounds ); const pencil_size_t *const pencil_size = pencil_layouter_get_pencil_size_ptr( &((*this_).layouter) ); /* draw diagram */ const data_diagram_t *diag = data_visible_set_get_diagram_const( (*this_).input_data ); pencil_diagram_painter_draw ( &((*this_).diagram_painter), diagram_layout, data_id_equals_id( &mark_focused, DATA_TABLE_DIAGRAM, data_diagram_get_row_id(diag) ), data_id_equals_id( &mark_highlighted, DATA_TABLE_DIAGRAM, data_diagram_get_row_id(diag) ), data_small_set_contains_row_id( mark_selected, DATA_TABLE_DIAGRAM, data_diagram_get_row_id(diag) ), pencil_size, layout, cr ); if (( width > 20.0 ) && ( height > 20.0 )) { /* draw all contained classifiers */ pencil_diagram_maker_private_draw_classifiers ( this_, mark_focused, mark_highlighted, mark_selected, layout, cr ); /* draw all contained features */ pencil_diagram_maker_private_draw_features ( this_, mark_focused, mark_highlighted, mark_selected, layout, cr ); /* draw all contained relationships */ pencil_diagram_maker_private_draw_relationships ( this_, mark_focused, mark_highlighted, mark_selected, layout, cr ); } g_object_unref (layout); TRACE_END(); } void pencil_diagram_maker_private_draw_classifiers ( pencil_diagram_maker_t *this_, data_id_t mark_focused, data_id_t mark_highlighted, const data_small_set_t *mark_selected, PangoLayout *layout, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != mark_selected ); assert( NULL != cr ); const pencil_layout_data_t *const layout_data = pencil_layouter_get_layout_data_const ( &((*this_).layouter) ); /* iterate over all classifiers */ const uint32_t count = pencil_layout_data_get_visible_classifier_count ( layout_data ); for ( uint32_t index = 0; index < count; index ++ ) { const layout_visible_classifier_t *const classifier_layout = pencil_layout_data_get_visible_classifier_const( layout_data, index ); const pencil_size_t *const pencil_size = pencil_layouter_get_pencil_size_ptr( &((*this_).layouter) ); pencil_classifier_composer_draw( &((*this_).classifier_painter), classifier_layout, mark_focused, mark_highlighted, mark_selected, layout_data, pencil_size, layout, cr ); } TRACE_END(); } void pencil_diagram_maker_private_draw_features ( pencil_diagram_maker_t *this_, data_id_t mark_focused, data_id_t mark_highlighted, const data_small_set_t *mark_selected, PangoLayout *layout, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != mark_selected ); assert( NULL != cr ); const pencil_layout_data_t *const layout_data = pencil_layouter_get_layout_data_const ( &((*this_).layouter) ); /* iterate over all features */ const uint32_t count = pencil_layout_data_get_feature_count ( layout_data ); for ( uint32_t f_idx = 0; f_idx < count; f_idx ++ ) { /* get feature */ const layout_feature_t *const the_feature = pencil_layout_data_get_feature_const( layout_data, f_idx ); /* determine display flags of diagramelement */ const layout_visible_classifier_t *const classifier_layout = layout_feature_get_classifier_const ( the_feature ); const data_diagramelement_t *const diagramelement = layout_visible_classifier_get_diagramelement_const( classifier_layout ); const data_diagramelement_flag_t display_flags = data_diagramelement_get_display_flags( diagramelement ); /* draw features */ pencil_feature_painter_draw ( &((*this_).feature_painter), the_feature, data_id_equals_id( &mark_focused, DATA_TABLE_FEATURE, layout_feature_get_feature_id(the_feature) ), data_id_equals_id( &mark_highlighted, DATA_TABLE_FEATURE, layout_feature_get_feature_id( the_feature ) ), data_small_set_contains_row_id( mark_selected, DATA_TABLE_FEATURE, layout_feature_get_feature_id(the_feature) ), (0 != ( display_flags & DATA_DIAGRAMELEMENT_FLAG_GRAY_OUT )), pencil_layouter_get_pencil_size_ptr( &((*this_).layouter) ), layout, cr ); } TRACE_END(); } void pencil_diagram_maker_private_draw_relationships ( pencil_diagram_maker_t *this_, data_id_t mark_focused, data_id_t mark_highlighted, const data_small_set_t *mark_selected, PangoLayout *layout, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != mark_selected ); assert( NULL != cr ); const pencil_layout_data_t *const layout_data = pencil_layouter_get_layout_data_const ( &((*this_).layouter) ); const uint32_t rel_count = pencil_layout_data_get_relationship_count ( layout_data ); for ( uint32_t index = 0; index < rel_count; index ++ ) { pencil_visibility_t show_relation; const layout_relationship_t *const relationship_layout = pencil_layout_data_get_relationship_const ( layout_data, index ); const data_relationship_t *const the_relationship = layout_relationship_get_data_const ( relationship_layout ); show_relation = layout_relationship_get_visibility ( relationship_layout ); if ( PENCIL_VISIBILITY_IMPLICIT == show_relation ) { if ( data_id_equals_id( &mark_focused, DATA_TABLE_RELATIONSHIP, data_relationship_get_row_id(the_relationship) ) || data_id_equals_id( &mark_highlighted, DATA_TABLE_RELATIONSHIP, data_relationship_get_row_id(the_relationship) ) || data_small_set_contains_row_id( mark_selected, DATA_TABLE_RELATIONSHIP, data_relationship_get_row_id(the_relationship) ) ) { /* the implicit relationship is focused or marked or highlighted */ show_relation = PENCIL_VISIBILITY_SHOW; } else { if ( DATA_TABLE_DIAGRAMELEMENT == data_id_get_table( &mark_highlighted ) ) { const data_row_id_t diagramelement_id = data_id_get_row_id( &mark_highlighted ); const data_visible_classifier_t *visible_clsfy = data_visible_set_get_visible_classifier_by_id_const ( (*this_).input_data, diagramelement_id ); if ( visible_clsfy != NULL ) { if ( data_visible_classifier_is_valid( visible_clsfy ) ) { const data_classifier_t *classifier = data_visible_classifier_get_classifier_const( visible_clsfy ); if (( data_classifier_get_row_id( classifier ) == data_relationship_get_from_classifier_row_id( the_relationship ) ) ||( data_classifier_get_row_id( classifier ) == data_relationship_get_to_classifier_row_id( the_relationship ) )) { /* the implicit relationship has highlighted from or to classifier */ show_relation = PENCIL_VISIBILITY_SHOW; } } } } } } if (( PENCIL_VISIBILITY_SHOW == show_relation )||( PENCIL_VISIBILITY_GRAY_OUT == show_relation )) { const pencil_size_t *const pencil_size = pencil_layouter_get_pencil_size_ptr( &((*this_).layouter) ); pencil_relationship_painter_draw ( &((*this_).relationship_painter), relationship_layout, data_id_equals_id( &mark_focused, DATA_TABLE_RELATIONSHIP, data_relationship_get_row_id(the_relationship) ), data_id_equals_id( &mark_highlighted, DATA_TABLE_RELATIONSHIP, data_relationship_get_row_id( the_relationship ) ), data_small_set_contains_row_id( mark_selected, DATA_TABLE_RELATIONSHIP, data_relationship_get_row_id(the_relationship) ), pencil_size, layout, cr ); } } TRACE_END(); } static const double snap_to_grid_distance_for_dropping = 3.15; /* plus/minus three pixels shall snap to grid */ /* this is the expected accuracy for mouse input devices */ /* this value is bigger than snap_to_grid_distance_for_drag_marker */ /* to ensure object really snaps when marked so */ pencil_error_t pencil_diagram_maker_get_order_at_pos ( const pencil_diagram_maker_t *this_, data_id_t obj_id, double x, double y, layout_order_t* out_layout_order ) { TRACE_BEGIN(); assert( NULL != out_layout_order ); pencil_error_t result = PENCIL_ERROR_NONE; const data_table_t table = data_id_get_table ( &obj_id ); switch ( table ) { case DATA_TABLE_CLASSIFIER: { const data_row_id_t classifier_id = data_id_get_row_id ( &obj_id ); const data_classifier_t *const the_classifier = data_visible_set_get_classifier_by_id_const ( (*this_).input_data, classifier_id ); const data_classifier_type_t c_type = (NULL == the_classifier) ? DATA_CLASSIFIER_TYPE_CLASS /* for new or unknown objects, assume class */ : data_classifier_get_main_type( the_classifier ); result = pencil_layouter_get_classifier_order_at_pos ( &((*this_).layouter), c_type, x, y, snap_to_grid_distance_for_dropping, out_layout_order ); } break; case DATA_TABLE_FEATURE: { const data_row_id_t feature_id = data_id_get_row_id ( &obj_id ); const data_feature_t *const the_feature = data_visible_set_get_feature_by_id_const ( (*this_).input_data, feature_id ); if( NULL != the_feature ) { result = pencil_layouter_get_feature_order_at_pos ( &((*this_).layouter), the_feature, x, y, out_layout_order ); } else { TSLOG_ANOMALY( "feature to move does not exist in input_data." ); layout_order_init_empty( out_layout_order ); result = PENCIL_ERROR_UNKNOWN_OBJECT; } } break; case DATA_TABLE_RELATIONSHIP: { result = pencil_layouter_get_relationship_order_at_pos ( &((*this_).layouter), x, y, out_layout_order ); } break; case DATA_TABLE_DIAGRAMELEMENT: { TSLOG_WARNING( "not implemented to move diagramelements. use the classifier instead." ); layout_order_init_empty( out_layout_order ); result = PENCIL_ERROR_UNKNOWN_OBJECT; } break; case DATA_TABLE_DIAGRAM: { /* pencil cannot move diagrams */ TSLOG_WARNING( "object to be re-positioned has unexpected type: diagram" ); layout_order_init_empty( out_layout_order ); result = PENCIL_ERROR_UNKNOWN_OBJECT; } break; default: { TSLOG_WARNING( "object to be re-positioned has illegal type" ); layout_order_init_empty( out_layout_order ); result = PENCIL_ERROR_UNKNOWN_OBJECT; } break; } TRACE_END_ERR(result); return result; } pencil_error_t pencil_diagram_maker_get_feature_order_at_pos ( const pencil_diagram_maker_t *this_, const data_feature_t *feature_ptr, double x, double y, layout_order_t* out_layout_order ) { TRACE_BEGIN(); assert( NULL != feature_ptr ); assert( NULL != out_layout_order ); const pencil_error_t result = pencil_layouter_get_feature_order_at_pos ( &((*this_).layouter), feature_ptr, x, y, out_layout_order ); TRACE_END_ERR(result); return result; } /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/pencil_diagram_painter.c000066400000000000000000000215511415120503000245250ustar00rootroot00000000000000/* File: pencil_diagram_painter.c; Copyright and License: see below */ #include "pencil_diagram_painter.h" #include "trace.h" #include #include #include #include void pencil_diagram_painter_init( pencil_diagram_painter_t *this_ ) { TRACE_BEGIN(); pencil_marker_init( &((*this_).marker) ); TRACE_END(); } void pencil_diagram_painter_destroy( pencil_diagram_painter_t *this_ ) { TRACE_BEGIN(); pencil_marker_destroy( &((*this_).marker) ); TRACE_END(); } void pencil_diagram_painter_draw ( const pencil_diagram_painter_t *this_, const layout_diagram_t *layouted_diagram, bool mark_focused, bool mark_highlighted, bool mark_selected, const pencil_size_t *pencil_size, PangoLayout *font_layout, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != pencil_size ); assert( NULL != layouted_diagram ); assert( NULL != font_layout ); assert( NULL != cr ); const data_diagram_t *const the_diagram = layout_diagram_get_data_const( layouted_diagram ); const geometry_rectangle_t *const diagram_bounds = layout_diagram_get_bounds_const( layouted_diagram ); const double left = geometry_rectangle_get_left ( diagram_bounds ); const double top = geometry_rectangle_get_top ( diagram_bounds ); const double right = geometry_rectangle_get_right ( diagram_bounds ); const double bottom = geometry_rectangle_get_bottom ( diagram_bounds ); const double width = geometry_rectangle_get_width ( diagram_bounds ); const double height = geometry_rectangle_get_height ( diagram_bounds ); TRACE_INFO_INT( "w", (int)(width) ); TRACE_INFO_INT( "h", (int)(height) ); const double gap = pencil_size_get_standard_object_border( pencil_size ); const double f_line_gap = pencil_size_get_font_line_gap( pencil_size ); const double f_tab_size = pencil_size_get_font_tab_size( pencil_size ); /* draw diagram border and name */ { TRACE_INFO_INT("drawing diagram id",data_diagram_get_row_id(the_diagram)); const double std_line_width = pencil_size_get_standard_line_width( pencil_size ); cairo_set_line_width( cr, std_line_width ); if ( data_diagram_is_valid(the_diagram) ) { /* draw border line */ if ( mark_highlighted ) { GdkRGBA highlight_color; highlight_color = pencil_size_get_highlight_color( pencil_size ); cairo_set_source_rgba( cr, highlight_color.red, highlight_color.green, highlight_color.blue, highlight_color.alpha ); } else { GdkRGBA standard_color; standard_color = pencil_size_get_standard_color( pencil_size ); cairo_set_source_rgba( cr, standard_color.red, standard_color.green, standard_color.blue, standard_color.alpha ); } cairo_rectangle ( cr, left+gap, top+gap, width-2.0*gap, height-2.0*gap ); cairo_stroke (cr); /* draw title corner */ int text_width; int text_height; pango_layout_set_font_description (font_layout, pencil_size_get_standard_font_description(pencil_size) ); pango_layout_set_text (font_layout, data_diagram_get_name_const( the_diagram ), -1); pango_layout_get_pixel_size (font_layout, &text_width, &text_height); cairo_move_to ( cr, left + gap + f_tab_size, top+gap ); pango_cairo_show_layout (cr, font_layout); double title_corner_height = text_height+f_line_gap; double title_corner_edge45 = 0.4 * title_corner_height; double title_corner_width = text_width + gap + 2.0*f_tab_size + title_corner_edge45; if ( title_corner_width > width*0.9 ) { title_corner_width = width*0.9; } cairo_move_to ( cr, left+gap, top+gap+title_corner_height ); cairo_line_to ( cr, left+gap+title_corner_width - title_corner_edge45, top+gap+title_corner_height ); cairo_line_to ( cr, left+gap+title_corner_width, top+gap+title_corner_height-title_corner_edge45 ); cairo_line_to ( cr, left+gap+title_corner_width, top+gap ); cairo_stroke (cr); } else { /* draw cross line */ GdkRGBA standard_color; standard_color = pencil_size_get_standard_color( pencil_size ); cairo_set_source_rgba( cr, standard_color.red, standard_color.green, standard_color.blue, standard_color.alpha ); cairo_move_to ( cr, left, top ); cairo_line_to ( cr, right, bottom ); cairo_move_to ( cr, left, bottom ); cairo_line_to ( cr, right, top ); cairo_stroke (cr); } } /* draw id */ { /* prepare text */ const data_id_t the_id = data_diagram_get_data_id(the_diagram); char id_buf[DATA_ID_MAX_UTF8STRING_SIZE+5]; utf8stringbuf_t id_str = UTF8STRINGBUF( id_buf ); utf8stringbuf_copy_str( id_str, "{id=" ); data_id_to_utf8stringbuf( &the_id, id_str ); utf8stringbuf_append_str( id_str, "}" ); int text4_width; int text4_height; pango_layout_set_font_description (font_layout, pencil_size_get_footnote_font_description(pencil_size) ); pango_layout_set_text (font_layout, utf8stringbuf_get_string( id_str ), -1); pango_layout_get_pixel_size (font_layout, &text4_width, &text4_height); /* draw text */ GdkRGBA grey_color; grey_color = pencil_size_get_gray_out_color( pencil_size ); cairo_set_source_rgba( cr, grey_color.red, grey_color.green, grey_color.blue, grey_color.alpha ); cairo_move_to ( cr, left + width - text4_width - gap - gap, top + gap ); pango_cairo_show_layout (cr, font_layout); } /* mark focused and highlighted */ { if ( mark_focused ) { pencil_marker_mark_focused_rectangle( &((*this_).marker), *diagram_bounds, cr ); } if ( mark_selected ) { geometry_rectangle_t selected_rect; geometry_rectangle_init( &selected_rect, left+gap, top+gap, width-2.0*gap, height-2.0*gap ); pencil_marker_mark_selected_rectangle( &((*this_).marker), selected_rect, cr ); geometry_rectangle_destroy( &selected_rect ); } } TRACE_END(); } void pencil_diagram_painter_get_drawing_space ( const pencil_diagram_painter_t *this_, const data_diagram_t *the_diagram, const pencil_size_t *pencil_size, const geometry_rectangle_t *diagram_bounds, geometry_rectangle_t *out_diagram_space ) { TRACE_BEGIN(); assert( NULL != pencil_size ); assert( NULL != the_diagram ); assert( NULL != out_diagram_space ); assert( NULL != diagram_bounds ); /* determine diagram bounds */ const double left = geometry_rectangle_get_left ( diagram_bounds ); const double top = geometry_rectangle_get_top ( diagram_bounds ); const double width = geometry_rectangle_get_width ( diagram_bounds ); const double height = geometry_rectangle_get_height ( diagram_bounds ); const double gap = pencil_size_get_standard_object_border( pencil_size ); /* font metrics */ const double f_size = pencil_size_get_standard_font_size( pencil_size ); const double f_line_gap = pencil_size_get_font_line_gap( pencil_size ); const double f_size_guess = f_size + 4.0 * f_line_gap; /* here, we do not have a pango layout object to determine the real font size */ /* calculate new sizes */ const double space_width = width-2.0*gap; const double space_height = height-2.0*gap-f_size_guess-f_line_gap; if ( ( space_width <= 0.0 ) || ( space_height <= 0.0 ) ) { geometry_rectangle_reinit_empty( out_diagram_space ); } else { geometry_rectangle_reinit( out_diagram_space, left+gap, top+gap+f_size_guess+f_line_gap, space_width, space_height ); } TRACE_END(); } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/pencil_feat_label_layouter.c000066400000000000000000000262731415120503000254070ustar00rootroot00000000000000/* File: pencil_feat_label_layouter.c; Copyright and License: see below */ #include "pencil_feat_label_layouter.h" #include "trace.h" #include "util/string/utf8string.h" void pencil_feat_label_layouter_init( pencil_feat_label_layouter_t *this_, pencil_layout_data_t *layout_data, pencil_size_t *pencil_size ) { TRACE_BEGIN(); assert( NULL != layout_data ); assert( NULL != pencil_size ); (*this_).layout_data = layout_data; (*this_).pencil_size = pencil_size; draw_feature_label_init( &((*this_).draw_feature_label) ); pencil_label_layout_helper_init ( &((*this_).label_layout_helper) ); TRACE_END(); } void pencil_feat_label_layouter_destroy( pencil_feat_label_layouter_t *this_ ) { TRACE_BEGIN(); pencil_label_layout_helper_destroy ( &((*this_).label_layout_helper) ); draw_feature_label_destroy( &((*this_).draw_feature_label) ); TRACE_END(); } void pencil_feat_label_layouter_do_layout ( pencil_feat_label_layouter_t *this_, PangoLayout *font_layout ) { TRACE_BEGIN(); assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) PENCIL_LAYOUT_DATA_MAX_FEATURES ); assert( NULL != font_layout ); universal_array_index_sorter_t sorted; universal_array_index_sorter_init( &sorted ); /* sort the features by their label-box layouting needs, drop invisible relations */ pencil_feat_label_layouter_private_propose_processing_order ( this_, &sorted ); /* layout the features label-boxes */ const uint32_t count_sorted = universal_array_index_sorter_get_count( &sorted ); for ( uint32_t sort_index = 0; sort_index < count_sorted; sort_index ++ ) { /* determine pointer to feature */ const uint32_t index = universal_array_index_sorter_get_array_index( &sorted, sort_index ); layout_feature_t *current_feature; current_feature = pencil_layout_data_get_feature_ptr( (*this_).layout_data, index ); geometry_point_t feature_middle = layout_feature_get_symbol_middle ( current_feature ); /* declaration of list of options */ uint32_t solutions_count = 0; static const uint32_t SOLUTIONS_MAX = 8; geometry_rectangle_t solution[8]; /* propose options */ pencil_feat_label_layouter_private_propose_solutions ( this_, current_feature, font_layout, SOLUTIONS_MAX, solution, &solutions_count ); /* select best option */ uint32_t index_of_best; if ( 1 == solutions_count ) { index_of_best = 0; } else { pencil_label_layout_helper_select_solution ( &((*this_).label_layout_helper), (*this_).layout_data, feature_middle, solutions_count, solution, &index_of_best ); } /* store best option to (*this_).layout_data */ layout_feature_set_label_box( current_feature, &(solution[index_of_best]) ); } universal_array_index_sorter_destroy( &sorted ); TRACE_END(); } void pencil_feat_label_layouter_private_propose_processing_order ( pencil_feat_label_layouter_t *this_, universal_array_index_sorter_t *out_sorted ) { TRACE_BEGIN(); assert( NULL != out_sorted ); /* sort the features by their label-box: the less simple, the earlier it shall be processed */ const uint32_t count_features = pencil_layout_data_get_feature_count ( (*this_).layout_data ); for ( uint32_t index = 0; index < count_features; index ++ ) { const layout_feature_t *const current_feature = pencil_layout_data_get_feature_ptr ( (*this_).layout_data, index ); const data_feature_t *const feature_data = layout_feature_get_data_const ( current_feature ); assert( NULL != feature_data ); const data_feature_type_t current_type = data_feature_get_main_type( feature_data ); int64_t simpleness = 0; /* determine simpleness by length of label */ simpleness -= utf8string_get_length( data_feature_get_key_const( feature_data ) ); simpleness -= utf8string_get_length( data_feature_get_value_const( feature_data ) ); /* do the properties and operations first, they have a fixed positiion given by the classifier */ if (( DATA_FEATURE_TYPE_PROPERTY == current_type )||( DATA_FEATURE_TYPE_OPERATION == current_type )) { simpleness = -100000; } /* insert relation to sorted array - except for lifelines which have no label */ if ( DATA_FEATURE_TYPE_LIFELINE != current_type ) { const int insert_error = universal_array_index_sorter_insert( out_sorted, index, simpleness ); if ( 0 != insert_error ) { TSLOG_WARNING( "not all relationship label-boxes are layouted" ); } } } TRACE_END(); } void pencil_feat_label_layouter_private_propose_solutions ( pencil_feat_label_layouter_t *this_, layout_feature_t *current_feature, PangoLayout *font_layout, uint32_t solutions_max, geometry_rectangle_t out_solutions[], uint32_t *out_solutions_count ) { TRACE_BEGIN(); assert( NULL != current_feature ); assert( NULL != font_layout ); assert( NULL != out_solutions ); assert( NULL != out_solutions_count ); const data_feature_t *feature_data = layout_feature_get_data_const ( current_feature ); assert( NULL != feature_data ); const data_feature_type_t current_type = data_feature_get_main_type( feature_data ); if (( DATA_FEATURE_TYPE_PROPERTY == current_type )||( DATA_FEATURE_TYPE_OPERATION == current_type )) { /* the label-box is identical to the feature bounds */ assert( solutions_max >= 1 ); geometry_rectangle_copy( &(out_solutions[0]), layout_feature_get_symbol_box_const ( current_feature ) ); *out_solutions_count = 1; } else { /* key and value dimensions */ double text_width; double text_height; draw_feature_label_get_key_and_value_dimensions( &((*this_).draw_feature_label), feature_data, (*this_).pencil_size, font_layout, &text_width, &text_height ); const double half_width = text_width/2.0; const double half_height = text_height/2.0; const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size ); const geometry_rectangle_t *const bounds = layout_feature_get_symbol_box_const ( current_feature ); const double left = geometry_rectangle_get_left( bounds ); const double top = geometry_rectangle_get_top( bounds ); const double center_x = geometry_rectangle_get_center_x( bounds ); const double center_y = geometry_rectangle_get_center_y( bounds ); const double bottom = geometry_rectangle_get_bottom( bounds ); const double right = geometry_rectangle_get_right( bounds ); assert( solutions_max >= 8 ); /* top */ geometry_rectangle_init( &(out_solutions[0]), center_x - half_width, top - text_height - gap, text_width, text_height ); /* bottom */ geometry_rectangle_init( &(out_solutions[1]), center_x - half_width, bottom + gap, text_width, text_height ); /* left */ geometry_rectangle_init( &(out_solutions[2]), left - text_width - gap, center_y - half_height, text_width, text_height ); /* right */ geometry_rectangle_init( &(out_solutions[3]), right + gap, center_y - half_height, text_width, text_height ); /* top-left */ geometry_rectangle_init( &(out_solutions[4]), left - text_width, top - text_height, text_width, text_height ); /* top-right */ geometry_rectangle_init( &(out_solutions[5]), right, top - text_height, text_width, text_height ); /* bottom-left */ geometry_rectangle_init( &(out_solutions[6]), left - text_width, bottom, text_width, text_height ); /* bottom-right */ geometry_rectangle_init( &(out_solutions[7]), right, bottom, text_width, text_height ); *out_solutions_count = 8; } TRACE_END(); } /* * Copyright 2019-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/pencil_feature_layouter.c000066400000000000000000000710131415120503000247540ustar00rootroot00000000000000/* File: pencil_feature_layouter.c; Copyright and License: see below */ #include "pencil_feature_layouter.h" #include "trace.h" #include #include #include #include void pencil_feature_layouter_init( pencil_feature_layouter_t *this_, pencil_layout_data_t *layout_data, pencil_size_t *pencil_size ) { TRACE_BEGIN(); assert( NULL != layout_data ); assert( NULL != pencil_size ); (*this_).layout_data = layout_data; (*this_).pencil_size = pencil_size; data_rules_init( &((*this_).rules) ); pencil_feature_painter_init( &((*this_).feature_painter) ); TRACE_END(); } void pencil_feature_layouter_destroy( pencil_feature_layouter_t *this_ ) { TRACE_BEGIN(); data_rules_destroy( &((*this_).rules) ); pencil_feature_painter_destroy( &((*this_).feature_painter) ); TRACE_END(); } void pencil_feature_layouter_do_layout ( pencil_feature_layouter_t *this_, PangoLayout *font_layout ) { TRACE_BEGIN(); assert( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) PENCIL_LAYOUT_DATA_MAX_FEATURES ); /* get diagram draw area */ const geometry_rectangle_t *diagram_draw_area; data_diagram_type_t diag_type; { layout_diagram_t *diagram_layout; diagram_layout = pencil_layout_data_get_diagram_ptr( (*this_).layout_data ); diagram_draw_area = layout_diagram_get_draw_area_const( diagram_layout ); const data_diagram_t *diagram_data; diagram_data = layout_diagram_get_data_const ( diagram_layout ); diag_type = data_diagram_get_diagram_type ( diagram_data ); } /* layout the unsorted features */ const uint32_t count_features = pencil_layout_data_get_feature_count ( (*this_).layout_data ); for ( uint32_t f_idx = 0; f_idx < count_features; f_idx ++ ) { layout_feature_t *const feature_layout = pencil_layout_data_get_feature_ptr ( (*this_).layout_data, f_idx ); const data_feature_t *const the_feature = layout_feature_get_data_const ( feature_layout ); const layout_visible_classifier_t *const layout_classifier = layout_feature_get_classifier_const ( feature_layout ); const data_classifier_t *const classifier = layout_visible_classifier_get_classifier_const( layout_classifier ); const data_classifier_type_t classifier_type = data_classifier_get_main_type( classifier ); const geometry_rectangle_t *const c_symbol_box = layout_visible_classifier_get_symbol_box_const ( layout_classifier ); switch ( data_feature_get_main_type (the_feature) ) { case DATA_FEATURE_TYPE_LIFELINE: { /* layout lifeline feature next to parent classifier */ pencil_feature_layouter_private_layout_lifeline ( this_, diagram_draw_area, diag_type, classifier_type, c_symbol_box, feature_layout ); } break; case DATA_FEATURE_TYPE_PORT: /* or */ case DATA_FEATURE_TYPE_IN_PORT_PIN: /* or */ case DATA_FEATURE_TYPE_OUT_PORT_PIN: /* or */ case DATA_FEATURE_TYPE_ENTRY: /* or */ case DATA_FEATURE_TYPE_EXIT: { /* layout port feature onto parent classifier box */ pencil_feature_layouter_private_layout_port_pin ( this_, classifier_type, c_symbol_box, the_feature, font_layout, feature_layout ); } break; case DATA_FEATURE_TYPE_PROVIDED_INTERFACE: /* or */ case DATA_FEATURE_TYPE_REQUIRED_INTERFACE: { /* layout interface feature close to parent classifier */ pencil_feature_layouter_private_layout_interface ( this_, c_symbol_box, the_feature, font_layout, feature_layout ); } break; case DATA_FEATURE_TYPE_PROPERTY: /* or */ case DATA_FEATURE_TYPE_OPERATION: { /* layout property or operation feature within the space area */ const geometry_rectangle_t *const c_space = layout_visible_classifier_get_space_const ( layout_classifier ); pencil_feature_layouter_private_layout_prop_or_op ( this_, c_space, the_feature, font_layout, feature_layout ); } break; default: { TSLOG_ERROR("invalid feature type in pencil_feature_layouter_do_layout"); layout_feature_set_symbol_box ( feature_layout, c_symbol_box ); layout_feature_set_label_box ( feature_layout, c_symbol_box ); layout_feature_set_icon_direction ( feature_layout, GEOMETRY_DIRECTION_CENTER ); } break; } } TRACE_END(); } void pencil_feature_layouter_private_layout_lifeline ( pencil_feature_layouter_t *this_, const geometry_rectangle_t *diagram_space, data_diagram_type_t diagram_type, data_classifier_type_t classifier_type, const geometry_rectangle_t *classifier_symbol_box, layout_feature_t *out_feature_layout ) { TRACE_BEGIN(); assert ( NULL != diagram_space ); assert ( NULL != classifier_symbol_box ); assert ( NULL != out_feature_layout ); /* get preferred object distance */ const double obj_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size ); const bool lifeline_has_semantics = data_rules_classifier_has_scenario_semantics( &((*this_).rules), diagram_type, classifier_type ); if (( DATA_DIAGRAM_TYPE_UML_TIMING_DIAGRAM == diagram_type ) && lifeline_has_semantics ) { layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_RIGHT ); const double c_right = geometry_rectangle_get_right( classifier_symbol_box ); const double c_top = geometry_rectangle_get_top( classifier_symbol_box ); const double c_height = geometry_rectangle_get_height( classifier_symbol_box ); const double dda_right = geometry_rectangle_get_right ( diagram_space ); geometry_rectangle_t lifeline_bounds; geometry_rectangle_init ( &lifeline_bounds, c_right, c_top + (0.375 * c_height), dda_right - c_right - obj_dist, 0.25 * c_height ); layout_feature_set_symbol_box ( out_feature_layout, &lifeline_bounds ); layout_feature_set_label_box ( out_feature_layout, &lifeline_bounds ); } else if (( DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM == diagram_type ) && lifeline_has_semantics ) { layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_DOWN ); const double c_bottom = geometry_rectangle_get_bottom( classifier_symbol_box ); const double c_left = geometry_rectangle_get_left( classifier_symbol_box ); const double c_width = geometry_rectangle_get_width( classifier_symbol_box ); const double dda_bottom = geometry_rectangle_get_bottom ( diagram_space ); geometry_rectangle_t lifeline_bounds; geometry_rectangle_init ( &lifeline_bounds, c_left + (0.375 * c_width), c_bottom, 0.25 * c_width, dda_bottom - c_bottom - obj_dist ); layout_feature_set_symbol_box ( out_feature_layout, &lifeline_bounds ); layout_feature_set_label_box ( out_feature_layout, &lifeline_bounds ); } else /*if (( DATA_DIAGRAM_TYPE_UML_COMMUNICATION_DIAGRAM == diagram_type )||( DATA_DIAGRAM_TYPE_INTERACTION_OVERVIEW_DIAGRAM == diagram_type ))*/ { layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_CENTER ); layout_feature_set_symbol_box ( out_feature_layout, classifier_symbol_box ); layout_feature_set_label_box ( out_feature_layout, classifier_symbol_box ); } TRACE_END(); } void pencil_feature_layouter_private_layout_port_pin ( pencil_feature_layouter_t *this_, data_classifier_type_t classifier_type, const geometry_rectangle_t *classifier_symbol_box, const data_feature_t *the_feature, PangoLayout *font_layout, layout_feature_t *out_feature_layout ) { TRACE_BEGIN(); assert ( NULL != classifier_symbol_box ); assert ( NULL != the_feature ); assert ( NULL != font_layout ); assert ( NULL != out_feature_layout ); /* get preferred object distance */ const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size ); const double port_icon_size = pencil_size_get_standard_font_size( (*this_).pencil_size ); /* determine the coordinates of the box-line */ geometry_rectangle_t classifier_box; geometry_rectangle_copy( &classifier_box, classifier_symbol_box ); geometry_rectangle_shift( &classifier_box, gap, gap ); geometry_rectangle_enlarge( &classifier_box, -2.0*gap, -2.0*gap ); const int32_t list_order = data_feature_get_list_order( the_feature ); /* position the port icon */ const bool is_sysml_constraint_block = (classifier_type == DATA_CLASSIFIER_TYPE_CONSTRAINT_BLOCK); const bool is_behavioral = data_classifier_type_is_behavioral( classifier_type ); const data_feature_type_t feat_type = data_feature_get_main_type( the_feature ); const bool is_state_entry_exit = (( feat_type == DATA_FEATURE_TYPE_ENTRY )||( feat_type == DATA_FEATURE_TYPE_EXIT )); const double outwards_distance = is_sysml_constraint_block ? 0.0 : (is_behavioral&&(!is_state_entry_exit)) ? port_icon_size : (0.5*port_icon_size); double port_icon_left; double port_icon_top; const double show_arrow_in = ( feat_type == DATA_FEATURE_TYPE_IN_PORT_PIN ); const double show_arrow_out = ( feat_type == DATA_FEATURE_TYPE_OUT_PORT_PIN ); geometry_direction_t arrow_dir = GEOMETRY_DIRECTION_CENTER; if ( list_order < 0 ) { static const int32_t INT32_MIN_HALF = INT32_MIN/2; if ( list_order < INT32_MIN_HALF ) /* SHOW ON RIGHT BORDER */ { const double y_pos_rel = (list_order - INT32_MIN_HALF) / ((double)(INT32_MIN_HALF)); port_icon_left = geometry_rectangle_get_right( &classifier_box ) - port_icon_size + outwards_distance; port_icon_top = geometry_rectangle_get_top( &classifier_box ) + y_pos_rel * ( geometry_rectangle_get_height( &classifier_box ) - port_icon_size ); arrow_dir = show_arrow_in ? GEOMETRY_DIRECTION_LEFT : show_arrow_out ? GEOMETRY_DIRECTION_RIGHT : GEOMETRY_DIRECTION_CENTER; } else /* SHOW ON TOP BORDER */ { const double x_pos_rel = (list_order) / ((double)(INT32_MIN_HALF)); port_icon_left = geometry_rectangle_get_left( &classifier_box ) + x_pos_rel * ( geometry_rectangle_get_width( &classifier_box ) - port_icon_size ); port_icon_top = geometry_rectangle_get_top( &classifier_box ) - outwards_distance; arrow_dir = show_arrow_in ? GEOMETRY_DIRECTION_DOWN : show_arrow_out ? GEOMETRY_DIRECTION_UP : GEOMETRY_DIRECTION_CENTER; } } else { static const int32_t INT32_MAX_HALF = (INT32_MAX/2)+1; /* round to ceiling */ if ( list_order < INT32_MAX_HALF ) /* SHOW ON LEFT BORDER */ { const double y_pos_rel = (list_order) / ((double)(INT32_MAX_HALF)); port_icon_left = geometry_rectangle_get_left( &classifier_box ) - outwards_distance; port_icon_top = geometry_rectangle_get_top( &classifier_box ) + y_pos_rel * ( geometry_rectangle_get_height( &classifier_box ) - port_icon_size ); arrow_dir = show_arrow_in ? GEOMETRY_DIRECTION_RIGHT : show_arrow_out ? GEOMETRY_DIRECTION_LEFT : GEOMETRY_DIRECTION_CENTER; } else /* SHOW ON BOTTOM BORDER */ { const double x_pos_rel = (list_order - INT32_MAX_HALF) / ((double)(INT32_MAX_HALF)); port_icon_left = geometry_rectangle_get_left( &classifier_box ) + x_pos_rel * ( geometry_rectangle_get_width( &classifier_box ) - port_icon_size ); port_icon_top = geometry_rectangle_get_bottom( &classifier_box ) - port_icon_size + outwards_distance; arrow_dir = show_arrow_in ? GEOMETRY_DIRECTION_UP : show_arrow_out ? GEOMETRY_DIRECTION_DOWN : GEOMETRY_DIRECTION_CENTER; } } /* set feature bounding box */ geometry_rectangle_t f_bounds; geometry_rectangle_init ( &f_bounds, port_icon_left, port_icon_top, port_icon_size, port_icon_size ); layout_feature_set_symbol_box ( out_feature_layout, &f_bounds ); layout_feature_set_label_box ( out_feature_layout, &f_bounds ); layout_feature_set_icon_direction ( out_feature_layout, arrow_dir ); TRACE_END(); } void pencil_feature_layouter_private_layout_interface ( pencil_feature_layouter_t *this_, const geometry_rectangle_t *classifier_symbol_box, const data_feature_t *the_feature, PangoLayout *font_layout, layout_feature_t *out_feature_layout ) { TRACE_BEGIN(); assert ( NULL != classifier_symbol_box ); assert ( NULL != the_feature ); assert ( NULL != font_layout ); assert ( NULL != out_feature_layout ); /* get preferred object size + distance */ const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size ); const double interface_icon_size = pencil_size_get_standard_font_size( (*this_).pencil_size ); const double interface_distance = 2.001 * pencil_size_get_preferred_object_distance( (*this_).pencil_size ) + gap; /* min dist formula as in relationship layouter */ const int32_t list_order = data_feature_get_list_order( the_feature ); /* position the interface icon */ if ( list_order < 0 ) { static const int32_t INT32_MIN_HALF = INT32_MIN/2; if ( list_order < INT32_MIN_HALF ) /* SHOW ON RIGHT BORDER */ { const double y_pos_rel = (list_order - INT32_MIN_HALF) / ((double)(INT32_MIN_HALF)); geometry_rectangle_t f_bounds; geometry_rectangle_init ( &f_bounds, geometry_rectangle_get_right( classifier_symbol_box ) + interface_distance, geometry_rectangle_get_top( classifier_symbol_box ) + y_pos_rel * ( geometry_rectangle_get_height( classifier_symbol_box ) - interface_icon_size ), interface_icon_size, interface_icon_size ); layout_feature_set_symbol_box ( out_feature_layout, &f_bounds ); layout_feature_set_label_box ( out_feature_layout, &f_bounds ); layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_RIGHT ); } else /* SHOW ON TOP BORDER */ { const double x_pos_rel = (list_order) / ((double)(INT32_MIN_HALF)); geometry_rectangle_t f_bounds; geometry_rectangle_init ( &f_bounds, geometry_rectangle_get_left( classifier_symbol_box ) + x_pos_rel * ( geometry_rectangle_get_width( classifier_symbol_box ) - interface_icon_size ), geometry_rectangle_get_top( classifier_symbol_box ) - interface_distance - interface_icon_size, interface_icon_size, interface_icon_size ); layout_feature_set_symbol_box ( out_feature_layout, &f_bounds ); layout_feature_set_label_box ( out_feature_layout, &f_bounds ); layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_UP ); } } else { static const int32_t INT32_MAX_HALF = (INT32_MAX/2)+1; /* round to ceiling */ if ( list_order < INT32_MAX_HALF ) /* SHOW ON LEFT BORDER */ { const double y_pos_rel = (list_order) / ((double)(INT32_MAX_HALF)); geometry_rectangle_t f_bounds; geometry_rectangle_init ( &f_bounds, geometry_rectangle_get_left( classifier_symbol_box ) - interface_distance - interface_icon_size, geometry_rectangle_get_top( classifier_symbol_box ) + y_pos_rel * ( geometry_rectangle_get_height( classifier_symbol_box ) - interface_icon_size ), interface_icon_size, interface_icon_size ); layout_feature_set_symbol_box ( out_feature_layout, &f_bounds ); layout_feature_set_label_box ( out_feature_layout, &f_bounds ); layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_LEFT ); } else /* SHOW ON BOTTOM BORDER */ { const double x_pos_rel = (list_order - INT32_MAX_HALF) / ((double)(INT32_MAX_HALF)); geometry_rectangle_t f_bounds; geometry_rectangle_init ( &f_bounds, geometry_rectangle_get_left( classifier_symbol_box ) + x_pos_rel * ( geometry_rectangle_get_width( classifier_symbol_box ) - interface_icon_size ), geometry_rectangle_get_bottom( classifier_symbol_box ) + interface_distance, interface_icon_size, interface_icon_size ); layout_feature_set_symbol_box ( out_feature_layout, &f_bounds ); layout_feature_set_label_box ( out_feature_layout, &f_bounds ); layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_DOWN ); } } if ( DATA_FEATURE_TYPE_PROVIDED_INTERFACE == data_feature_get_main_type (the_feature) ) { /* a provided interface has no direction, it is a circle */ layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_CENTER ); } TRACE_END(); } void pencil_feature_layouter_private_layout_prop_or_op ( pencil_feature_layouter_t *this_, const geometry_rectangle_t *classifier_space, const data_feature_t *the_feature, PangoLayout *font_layout, layout_feature_t *out_feature_layout ) { TRACE_BEGIN(); assert ( NULL != classifier_space ); assert ( NULL != the_feature ); assert ( NULL != font_layout ); assert ( NULL != out_feature_layout ); /* define names for input data */ const layout_visible_classifier_t * const vis_classfy = layout_feature_get_classifier_const ( out_feature_layout ); assert ( NULL != vis_classfy ); const data_row_id_t diagele_id = layout_visible_classifier_get_diagramelement_id ( vis_classfy ); /* determine number of features above the current */ uint32_t count_features_above = 0; { const uint32_t num_features = pencil_layout_data_get_feature_count ( (*this_).layout_data ); for ( uint32_t f_probe_idx = 0; f_probe_idx < num_features; f_probe_idx ++ ) { const layout_feature_t *const f_probe_layout = pencil_layout_data_get_feature_ptr ( (*this_).layout_data, f_probe_idx ); assert ( NULL != f_probe_layout ); const layout_visible_classifier_t *const probe_vis_classfy = layout_feature_get_classifier_const ( f_probe_layout ); assert ( NULL != probe_vis_classfy ); /* check if this f_probe_layout has the same diagram element id as the_feature */ if ( diagele_id == layout_visible_classifier_get_diagramelement_id ( probe_vis_classfy ) ) { /* this is a feature of the same visible_classifier_t */ /* define names for input data */ const data_feature_t *f_probe_data; f_probe_data = layout_feature_get_data_const ( f_probe_layout ); assert ( NULL != f_probe_data ); const data_feature_type_t f_probe_type = data_feature_get_main_type ( f_probe_data ); const bool property_or_operation = ( DATA_FEATURE_TYPE_PROPERTY == f_probe_type ) || ( DATA_FEATURE_TYPE_OPERATION == f_probe_type ); if ( property_or_operation ) { const bool is_above = (( data_feature_get_list_order( f_probe_data ) < data_feature_get_list_order( the_feature )) || (( data_feature_get_list_order( f_probe_data ) == data_feature_get_list_order( the_feature ) ) && ( data_feature_get_row_id( f_probe_data ) < data_feature_get_row_id( the_feature ) ))); if ( is_above ) { count_features_above ++; } } } } } /* determine compartments above the current */ const data_feature_type_t f_type = data_feature_get_main_type (the_feature); const uint32_t count_compartments_above = (DATA_FEATURE_TYPE_OPERATION==f_type)?1:0; /* first compartment for properties, second for operations */ /* determine the minimum bounds of the feature */ geometry_dimensions_t f_min_bounds; pencil_feature_painter_get_minimum_bounds ( &((*this_).feature_painter), the_feature, (*this_).pencil_size, font_layout, &f_min_bounds ); /* layout feature into parent classifier */ const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size ); const double top = geometry_rectangle_get_top( classifier_space ) + ( count_features_above * geometry_dimensions_get_height( &f_min_bounds ) ) + ( count_compartments_above * 2 * gap ) + gap /* distance to the line on top of the first feature */; geometry_rectangle_t f_bounds; geometry_rectangle_init ( &f_bounds, geometry_rectangle_get_left( classifier_space ), top, //geometry_rectangle_get_width( classifier_space ), geometry_dimensions_get_width( &f_min_bounds ), geometry_dimensions_get_height( &f_min_bounds ) ); layout_feature_set_symbol_box ( out_feature_layout, &f_bounds ); layout_feature_set_label_box ( out_feature_layout, &f_bounds ); layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_CENTER ); /* dummy direction */ TRACE_END(); } void pencil_feature_layouter_calculate_features_bounds ( pencil_feature_layouter_t *this_, data_row_id_t diagramelement_id, PangoLayout *font_layout, geometry_dimensions_t *out_features_bounds ) { TRACE_BEGIN(); assert( NULL != font_layout ); assert( NULL != out_features_bounds ); double width = 0.0; double height = 0.0; /* search all contained features */ const uint32_t count_features = pencil_layout_data_get_feature_count ( (*this_).layout_data ); for ( uint32_t f_idx = 0; f_idx < count_features; f_idx ++ ) { const layout_feature_t *const feature_layout = pencil_layout_data_get_feature_ptr ( (*this_).layout_data, f_idx ); const data_feature_t *const the_feature = layout_feature_get_data_const ( feature_layout ); const layout_visible_classifier_t *const layout_classifier = layout_feature_get_classifier_const ( feature_layout ); const bool property_or_operation = ( DATA_FEATURE_TYPE_PROPERTY == data_feature_get_main_type ( the_feature ) ) || ( DATA_FEATURE_TYPE_OPERATION == data_feature_get_main_type ( the_feature ) ); if (( diagramelement_id == layout_visible_classifier_get_diagramelement_id( layout_classifier ) ) && property_or_operation ) { geometry_dimensions_t min_feature_bounds; geometry_dimensions_init_empty( &min_feature_bounds ); pencil_feature_painter_get_minimum_bounds ( &((*this_).feature_painter), the_feature, (*this_).pencil_size, font_layout, &min_feature_bounds ); double current_w = geometry_dimensions_get_width( &min_feature_bounds ); width = ( width < current_w ) ? current_w : width; height += geometry_dimensions_get_height( &min_feature_bounds ); geometry_dimensions_destroy( &min_feature_bounds ); } } const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size ); const double sum_of_gaps = 4.0 * gap; /* gaps above and below the compartment lines */ geometry_dimensions_reinit( out_features_bounds, width, height + sum_of_gaps ); TRACE_END(); } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/pencil_feature_painter.c000066400000000000000000000552371415120503000245640ustar00rootroot00000000000000/* File: pencil_feature_painter.c; Copyright and License: see below */ #include "pencil_feature_painter.h" #include "pencil_layout_data.h" #include "trace.h" #include #include #include #include /*! where to place the control points of a bezier curve to get a good approximation for a 90 degree curve */ const static double BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE = 0.552284749831; const static double SINE_OF_45_DEGREE = 0.707106781187; void pencil_feature_painter_init( pencil_feature_painter_t *this_ ) { TRACE_BEGIN(); pencil_marker_init( &((*this_).marker) ); draw_feature_label_init( &((*this_).draw_feature_label) ); TRACE_END(); } void pencil_feature_painter_destroy( pencil_feature_painter_t *this_ ) { TRACE_BEGIN(); draw_feature_label_destroy( &((*this_).draw_feature_label) ); pencil_marker_destroy( &((*this_).marker) ); TRACE_END(); } void pencil_feature_painter_draw ( pencil_feature_painter_t *this_, const layout_feature_t *layouted_feature, bool mark_focused, bool mark_highlighted, bool mark_selected, bool gray_out, const pencil_size_t *pencil_size, PangoLayout *layout, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != pencil_size ); assert( NULL != layouted_feature ); assert( NULL != layout ); assert( NULL != cr ); const data_feature_t *the_feature = layout_feature_get_data_const( layouted_feature ); const geometry_rectangle_t *const feature_symbol_box = layout_feature_get_symbol_box_const( layouted_feature ); if ( data_feature_is_valid( the_feature ) ) { TRACE_INFO_INT("drawing feature id", data_feature_get_row_id( the_feature ) ); /* select color */ GdkRGBA foreground_color; { if ( mark_highlighted ) { foreground_color = pencil_size_get_highlight_color( pencil_size ); } else if ( gray_out ) { foreground_color = pencil_size_get_gray_out_color( pencil_size ); } else { foreground_color = pencil_size_get_standard_color( pencil_size ); } cairo_set_source_rgba( cr, foreground_color.red, foreground_color.green, foreground_color.blue, foreground_color.alpha ); } switch ( data_feature_get_main_type (the_feature) ) { case DATA_FEATURE_TYPE_PORT: /* or */ case DATA_FEATURE_TYPE_IN_PORT_PIN: /* or */ case DATA_FEATURE_TYPE_OUT_PORT_PIN: { pencil_feature_painter_private_draw_port_pin_icon ( this_, layouted_feature, pencil_size, foreground_color, cr ); } break; case DATA_FEATURE_TYPE_ENTRY: /* or */ case DATA_FEATURE_TYPE_EXIT: { pencil_feature_painter_private_draw_entry_exit_icon ( this_, layouted_feature, pencil_size, foreground_color, cr ); } break; case DATA_FEATURE_TYPE_PROVIDED_INTERFACE: /* or */ case DATA_FEATURE_TYPE_REQUIRED_INTERFACE: { pencil_feature_painter_private_draw_interface_icon ( this_, layouted_feature, pencil_size, cr ); } break; case DATA_FEATURE_TYPE_LIFELINE: { pencil_feature_painter_private_draw_lifeline_icon ( this_, layouted_feature, mark_highlighted, pencil_size, cr ); } break; case DATA_FEATURE_TYPE_PROPERTY: /* or */ case DATA_FEATURE_TYPE_OPERATION: { /* no icon */ } break; default: { TSLOG_ERROR("invalid feature type in pencil_feature_painter_draw"); } break; } /* draw the label */ draw_feature_label_draw_key_and_value ( &((*this_).draw_feature_label), layout_feature_get_data_const( layouted_feature ), layout_feature_get_label_box_const( layouted_feature ), pencil_size, layout, cr ); #ifdef PENCIL_LAYOUT_DATA_DRAW_FOR_DEBUG /* draw the rectangles */ { const geometry_rectangle_t *const feature_label_box = layout_feature_get_label_box_const ( layouted_feature ); cairo_set_source_rgba( cr, 0.5, 0.7, 1.0, 0.5 ); cairo_rectangle ( cr, geometry_rectangle_get_left ( feature_symbol_box ), geometry_rectangle_get_top ( feature_symbol_box ), geometry_rectangle_get_width ( feature_symbol_box ), geometry_rectangle_get_height ( feature_symbol_box ) ); cairo_rectangle ( cr, geometry_rectangle_get_left ( feature_label_box ), geometry_rectangle_get_top ( feature_label_box ), geometry_rectangle_get_width ( feature_label_box ), geometry_rectangle_get_height ( feature_label_box ) ); cairo_stroke (cr); } #endif if ( mark_selected ) { pencil_marker_mark_selected_rectangle( &((*this_).marker), *feature_symbol_box, cr ); } if ( mark_focused ) { pencil_marker_mark_focused_rectangle( &((*this_).marker), *feature_symbol_box, cr ); } } else { TSLOG_ERROR("invalid visible feature in array!"); } TRACE_END(); } void pencil_feature_painter_private_draw_lifeline_icon ( pencil_feature_painter_t *this_, const layout_feature_t *layouted_feature, bool marked, const pencil_size_t *pencil_size, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != pencil_size ); assert( NULL != layouted_feature ); assert( NULL != cr ); const geometry_rectangle_t *const feature_symbol_box = layout_feature_get_symbol_box_const( layouted_feature ); const double left = geometry_rectangle_get_left ( feature_symbol_box ); const double top = geometry_rectangle_get_top ( feature_symbol_box ); const double width = geometry_rectangle_get_width ( feature_symbol_box ); const double height = geometry_rectangle_get_height ( feature_symbol_box ); double dashes[2]; dashes[0] = 2.0 * pencil_size_get_line_dash_length( pencil_size ); dashes[1] = 1.0 * pencil_size_get_line_dash_length( pencil_size ); cairo_set_dash ( cr, dashes, 2, 0.0 ); if ( GEOMETRY_DIRECTION_RIGHT == layout_feature_get_icon_direction( layouted_feature ) ) { /* lineline in timing diagrams */ const double center_y = geometry_rectangle_get_center_y ( feature_symbol_box ); cairo_move_to ( cr, left, center_y ); cairo_line_to ( cr, left + width, center_y ); cairo_stroke (cr); } else if ( GEOMETRY_DIRECTION_DOWN == layout_feature_get_icon_direction( layouted_feature ) ) { /* lifeline in sequence diagrams */ const double center_x = geometry_rectangle_get_center_x ( feature_symbol_box ); cairo_move_to ( cr, center_x, top ); cairo_line_to ( cr, center_x, top + height ); cairo_stroke (cr); } else { /* lifeline in communication diagrams, only drawn if highlighted: */ if ( marked ) { cairo_move_to ( cr, left, top ); cairo_line_to ( cr, left, top + height ); cairo_line_to ( cr, left + width, top + height ); cairo_line_to ( cr, left + width, top ); cairo_line_to ( cr, left, top ); cairo_stroke (cr); } } cairo_set_dash ( cr, NULL, 0, 0.0 ); TRACE_END(); } void pencil_feature_painter_private_draw_port_pin_icon ( pencil_feature_painter_t *this_, const layout_feature_t *layouted_feature, const pencil_size_t *pencil_size, GdkRGBA foreground_color, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != pencil_size ); assert( NULL != layouted_feature ); assert( NULL != cr ); const geometry_rectangle_t *const symbol_box_bounds = layout_feature_get_symbol_box_const( layouted_feature ); const double left = geometry_rectangle_get_left ( symbol_box_bounds ); const double top = geometry_rectangle_get_top ( symbol_box_bounds ); const double width = geometry_rectangle_get_width ( symbol_box_bounds ); const double height = geometry_rectangle_get_height ( symbol_box_bounds ); cairo_rectangle ( cr, left, top, width, height ); /* Note: It is possible to read out the current color and set it again */ /* but the interface for that looks like this might result in 1 additional memory allocation */ /* which shall be avoided */ /* cairo_pattern_t *const defined_color = cairo_get_source( cr ); */ /* cairo_pattern_reference( defined_color ); */ /* ... */ /* cairo_set_source( cr, defined_color ); */ /* cairo_pattern_destroy( defined_color ); */ cairo_set_source_rgba( cr, 1.0, 1.0, 1.0, 1.0 ); /* white background */ cairo_fill_preserve (cr); cairo_set_source_rgba( cr, foreground_color.red, foreground_color.green, foreground_color.blue, foreground_color.alpha ); cairo_stroke (cr); /* draw the arrow */ const double center_x = geometry_rectangle_get_center_x ( symbol_box_bounds ); const double center_y = geometry_rectangle_get_center_y ( symbol_box_bounds ); const double h_arrow_left = left + 0.25*width; const double h_arrow_right = left + 0.75*width; const double h_arrow_top = top + 0.25*height; const double h_arrow_bottom = top + 0.75*height; const double v_arrow_left = left + 0.25*width; const double v_arrow_right = left + 0.75*width; const double v_arrow_top = top + 0.25*height; const double v_arrow_bottom = top + 0.75*height; switch ( layout_feature_get_icon_direction( layouted_feature ) ) { case GEOMETRY_DIRECTION_LEFT: { cairo_move_to ( cr, h_arrow_left, center_y ); cairo_line_to ( cr, h_arrow_right, center_y ); cairo_move_to ( cr, h_arrow_right, h_arrow_top ); cairo_line_to ( cr, h_arrow_left, center_y ); cairo_line_to ( cr, h_arrow_right, h_arrow_bottom ); cairo_stroke (cr); } break; case GEOMETRY_DIRECTION_UP: { cairo_move_to ( cr, center_x, v_arrow_top ); cairo_line_to ( cr, center_x, v_arrow_bottom ); cairo_move_to ( cr, v_arrow_left, v_arrow_bottom ); cairo_line_to ( cr, center_x, v_arrow_top ); cairo_line_to ( cr, v_arrow_right, v_arrow_bottom ); cairo_stroke (cr); } break; case GEOMETRY_DIRECTION_RIGHT: { cairo_move_to ( cr, h_arrow_right, center_y ); cairo_line_to ( cr, h_arrow_left, center_y ); cairo_move_to ( cr, h_arrow_left, h_arrow_top ); cairo_line_to ( cr, h_arrow_right, center_y ); cairo_line_to ( cr, h_arrow_left, h_arrow_bottom ); cairo_stroke (cr); } break; case GEOMETRY_DIRECTION_DOWN: { cairo_move_to ( cr, center_x, v_arrow_bottom ); cairo_line_to ( cr, center_x, v_arrow_top ); cairo_move_to ( cr, v_arrow_left, v_arrow_top ); cairo_line_to ( cr, center_x, v_arrow_bottom ); cairo_line_to ( cr, v_arrow_right, v_arrow_top ); cairo_stroke (cr); } break; case GEOMETRY_DIRECTION_CENTER: { /* no arrow */ } break; default: { TSLOG_ERROR( "unexpected value in geometry_direction_t." ); } break; } TRACE_END(); } void pencil_feature_painter_private_draw_entry_exit_icon ( pencil_feature_painter_t *this_, const layout_feature_t *layouted_feature, const pencil_size_t *pencil_size, GdkRGBA foreground_color, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != pencil_size ); assert( NULL != layouted_feature ); assert( NULL != cr ); const data_feature_t *the_feature = layout_feature_get_data_const( layouted_feature ); const geometry_rectangle_t *const symbol_box_bounds = layout_feature_get_symbol_box_const( layouted_feature ); const double left = geometry_rectangle_get_left ( symbol_box_bounds ); const double top = geometry_rectangle_get_top ( symbol_box_bounds ); const double center_x = geometry_rectangle_get_center_x( symbol_box_bounds ); const double center_y = geometry_rectangle_get_center_y( symbol_box_bounds ); const double circle_x_radius = center_x - left; const double circle_y_radius = center_y - top; const double bottom = geometry_rectangle_get_bottom( symbol_box_bounds ); const double right = geometry_rectangle_get_right( symbol_box_bounds ); const double ctrl_x_offset = circle_x_radius * (1.0-BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE); const double ctrl_y_offset = circle_y_radius * (1.0-BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE); cairo_move_to ( cr, center_x, bottom ); cairo_curve_to ( cr, left + ctrl_x_offset, bottom, left, bottom - ctrl_y_offset, left /* end point x */, center_y /* end point y */ ); cairo_curve_to ( cr, left, top + ctrl_y_offset, left + ctrl_x_offset, top, center_x /* end point x */, top /* end point y */ ); cairo_curve_to ( cr, right - ctrl_x_offset, top, right, top + ctrl_y_offset, right /* end point x */, center_y /* end point y */ ); cairo_curve_to ( cr, right, bottom - ctrl_y_offset, right - ctrl_x_offset, bottom, center_x /* end point x */, bottom /* end point y */ ); cairo_set_source_rgba( cr, 1.0, 1.0, 1.0, 1.0 ); /* white background */ cairo_fill_preserve (cr); cairo_set_source_rgba( cr, foreground_color.red, foreground_color.green, foreground_color.blue, foreground_color.alpha ); cairo_stroke (cr); /* draw X of exit icon */ if ( data_feature_get_main_type( the_feature ) == DATA_FEATURE_TYPE_EXIT ) { const double half_width = geometry_rectangle_get_width ( symbol_box_bounds )/2.0; const double half_height = geometry_rectangle_get_height ( symbol_box_bounds )/2.0; const double cross_end_dx = half_width * SINE_OF_45_DEGREE; const double cross_end_dy = half_height * SINE_OF_45_DEGREE; cairo_move_to ( cr, center_x + cross_end_dx, center_y - cross_end_dy ); cairo_line_to ( cr, center_x - cross_end_dx, center_y + cross_end_dy ); cairo_move_to ( cr, center_x - cross_end_dx, center_y - cross_end_dy ); cairo_line_to ( cr, center_x + cross_end_dx, center_y + cross_end_dy ); cairo_stroke (cr); } TRACE_END(); } void pencil_feature_painter_private_draw_interface_icon ( pencil_feature_painter_t *this_, const layout_feature_t *layouted_feature, const pencil_size_t *pencil_size, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != pencil_size ); assert( NULL != layouted_feature ); assert( NULL != cr ); const geometry_rectangle_t *const symbol_box_bounds = layout_feature_get_symbol_box_const( layouted_feature ); const double left = geometry_rectangle_get_left ( symbol_box_bounds ); const double top = geometry_rectangle_get_top ( symbol_box_bounds ); const double width = geometry_rectangle_get_width ( symbol_box_bounds ); const double height = geometry_rectangle_get_height ( symbol_box_bounds ); double bottom = top + height; double right = left + width; double half_width = 0.5 * width; double half_height = 0.5 * height; double center_x = left + half_width; double center_y = top + half_height; double ctrl_xoffset = half_width * (1.0-BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE); double ctrl_yoffset = half_height * (1.0-BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE); switch ( layout_feature_get_icon_direction( layouted_feature ) ) { case GEOMETRY_DIRECTION_LEFT: { cairo_move_to ( cr, center_x, top ); cairo_curve_to ( cr, right - ctrl_xoffset, top, right, top + ctrl_yoffset, right /* end point x */, center_y /* end point y */ ); cairo_curve_to ( cr, right, bottom - ctrl_yoffset, right - ctrl_xoffset, bottom, center_x /* end point x */, bottom /* end point y */ ); cairo_stroke (cr); } break; case GEOMETRY_DIRECTION_UP: { cairo_move_to ( cr, right, center_y ); cairo_curve_to ( cr, right, bottom - ctrl_yoffset, right - ctrl_xoffset, bottom, center_x /* end point x */, bottom /* end point y */ ); cairo_curve_to ( cr, left + ctrl_xoffset, bottom, left, bottom - ctrl_yoffset, left /* end point x */, center_y /* end point y */ ); cairo_stroke (cr); } break; case GEOMETRY_DIRECTION_RIGHT: { cairo_move_to ( cr, center_x, bottom ); cairo_curve_to ( cr, left + ctrl_xoffset, bottom, left, bottom - ctrl_yoffset, left /* end point x */, center_y /* end point y */ ); cairo_curve_to ( cr, left, top + ctrl_yoffset, left + ctrl_xoffset, top, center_x /* end point x */, top /* end point y */ ); cairo_stroke (cr); } break; case GEOMETRY_DIRECTION_DOWN: { cairo_move_to ( cr, left, center_y ); cairo_curve_to ( cr, left, top + ctrl_yoffset, left + ctrl_xoffset, top, center_x /* end point x */, top /* end point y */ ); cairo_curve_to ( cr, right - ctrl_xoffset, top, right, top + ctrl_yoffset, right /* end point x */, center_y /* end point y */ ); cairo_stroke (cr); } break; case GEOMETRY_DIRECTION_CENTER: { cairo_move_to ( cr, center_x, bottom ); cairo_curve_to ( cr, left + ctrl_xoffset, bottom, left, bottom - ctrl_yoffset, left /* end point x */, center_y /* end point y */ ); cairo_curve_to ( cr, left, top + ctrl_yoffset, left + ctrl_xoffset, top, center_x /* end point x */, top /* end point y */ ); cairo_curve_to ( cr, right - ctrl_xoffset, top, right, top + ctrl_yoffset, right /* end point x */, center_y /* end point y */ ); cairo_curve_to ( cr, right, bottom - ctrl_yoffset, right - ctrl_xoffset, bottom, center_x /* end point x */, bottom /* end point y */ ); cairo_stroke (cr); } break; default: { TSLOG_ERROR( "unexpected value in geometry_direction_t." ); } break; } TRACE_END(); } void pencil_feature_painter_get_minimum_bounds ( pencil_feature_painter_t *this_, const data_feature_t *the_feature, const pencil_size_t *pencil_size, PangoLayout *font_layout, geometry_dimensions_t *out_feature_bounds ) { TRACE_BEGIN(); assert( NULL != the_feature ); assert( NULL != pencil_size ); assert( NULL != font_layout ); assert( NULL != out_feature_bounds ); const double gap = pencil_size_get_standard_object_border( pencil_size ); double width = 2.0 * gap; double height = 0.0; if ( data_feature_is_valid( the_feature ) ) { TRACE_INFO_INT("calculating minimum bounds of feature id", data_feature_get_row_id( the_feature ) ); /* layout text */ int text2_width; int text2_height; { /* prepare text */ char label_text[DATA_FEATURE_MAX_KEY_SIZE + DATA_FEATURE_MAX_VALUE_SIZE + 2 ]; utf8stringbuf_t label_buf = UTF8STRINGBUF(label_text); utf8stringbuf_copy_str( label_buf, data_feature_get_key_const( the_feature ) ); if ( data_feature_has_value( the_feature ) ) { utf8stringbuf_append_str( label_buf, ": " ); utf8stringbuf_append_str( label_buf, data_feature_get_value_const( the_feature ) ); } /* determine text width and height */ pango_layout_set_font_description (font_layout, pencil_size_get_standard_font_description(pencil_size) ); pango_layout_set_text (font_layout, utf8stringbuf_get_string( label_buf ), -1); pango_layout_get_pixel_size (font_layout, &text2_width, &text2_height); } /* for the height, ignore the actual height (text2_height) and return the standard font height + line gap */ const double lineheight = pencil_size_get_standard_font_size( pencil_size ) + pencil_size_get_font_line_gap( pencil_size ); height += lineheight; /*height += text2_height;*/ width += text2_width; } else { TSLOG_ERROR("invalid feature in array!"); } geometry_dimensions_reinit( out_feature_bounds, width, height ); TRACE_END(); } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/pencil_label_layout_helper.c000066400000000000000000000202041415120503000254040ustar00rootroot00000000000000/* File: pencil_label_layout_helper.c; Copyright and License: see below */ #include "pencil_label_layout_helper.h" #include "trace.h" #include "util/string/utf8string.h" void pencil_label_layout_helper_init( pencil_label_layout_helper_t *this_ ) { TRACE_BEGIN(); TRACE_END(); } void pencil_label_layout_helper_destroy( pencil_label_layout_helper_t *this_ ) { TRACE_BEGIN(); TRACE_END(); } void pencil_label_layout_helper_select_solution ( pencil_label_layout_helper_t *this_, pencil_layout_data_t *layout_data, geometry_point_t target_point, uint32_t solutions_count, const geometry_rectangle_t solutions[], uint32_t *out_index_of_best ) { TRACE_BEGIN(); assert( NULL != solutions ); assert( solutions_count >= 1 ); assert( NULL != out_index_of_best ); /* get draw area */ const layout_diagram_t *const diagram_layout = pencil_layout_data_get_diagram_ptr( layout_data ); const geometry_rectangle_t *const diagram_draw_area = layout_diagram_get_draw_area_const( diagram_layout ); /* define potential solution and rating */ uint32_t index_of_best = 0; double debts_of_best = DBL_MAX; /* evaluate the solutions by their overlaps with classifiers */ for ( uint32_t solution_idx = 0; solution_idx < solutions_count; solution_idx ++ ) { /* evalute the debts of this solution */ double debts_of_current = 0.0; const geometry_rectangle_t * const current_solution = &(solutions[solution_idx]); /* avoid alternating solutions in case their debts are identical */ debts_of_current += 0.1 * solution_idx; /* check distance to target point */ const geometry_point_t solution_middle = geometry_rectangle_get_center( current_solution ); debts_of_current += geometry_point_calc_chess_distance ( &target_point, &solution_middle ); /* add debts for overlap to diagram boundary */ if ( ! geometry_rectangle_is_containing( diagram_draw_area, current_solution ) ) { debts_of_current += 100.0 * geometry_rectangle_get_area(diagram_draw_area); /* high debt */ } /* iterate over all classifiers */ const uint32_t count_clasfy = pencil_layout_data_get_visible_classifier_count ( layout_data ); for ( uint32_t clasfy_index = 0; clasfy_index < count_clasfy; clasfy_index ++ ) { const layout_visible_classifier_t *const probe_classifier = pencil_layout_data_get_visible_classifier_ptr( layout_data, clasfy_index ); const geometry_rectangle_t *const classifier_symbol_box = layout_visible_classifier_get_symbol_box_const( probe_classifier ); if ( geometry_rectangle_is_intersecting( current_solution, classifier_symbol_box ) ) { /* overlaps to the symbol box are bad only if not contained in space area */ const geometry_rectangle_t *const classifier_space = layout_visible_classifier_get_space_const( probe_classifier ); if ( ! geometry_rectangle_is_containing( classifier_space, current_solution ) ) { debts_of_current += geometry_rectangle_get_intersect_area( current_solution, classifier_symbol_box ); /* low debt */ } } const geometry_rectangle_t *const classifier_label_box = layout_visible_classifier_get_label_box_const( probe_classifier ); if ( geometry_rectangle_is_intersecting( current_solution, classifier_label_box ) ) { debts_of_current += 100.0 * geometry_rectangle_get_intersect_area( current_solution, classifier_label_box ); /* medium debt */ } } /* iterate over all features */ const uint32_t count_feat = pencil_layout_data_get_feature_count ( layout_data ); for ( uint32_t feat_index = 0; feat_index < count_feat; feat_index ++ ) { const layout_feature_t *const probe_feature = pencil_layout_data_get_feature_ptr( layout_data, feat_index ); const data_feature_t *const probe_f_data = layout_feature_get_data_const( probe_feature ); const geometry_rectangle_t *const feature_symbol_box = layout_feature_get_symbol_box_const( probe_feature ); if ( geometry_rectangle_is_intersecting( current_solution, feature_symbol_box ) ) { if ( DATA_FEATURE_TYPE_LIFELINE == data_feature_get_main_type( probe_f_data ) ) { debts_of_current += geometry_rectangle_get_intersect_area( current_solution, feature_symbol_box ); /* low debt */ } else { debts_of_current += 100.0 * geometry_rectangle_get_intersect_area( current_solution, feature_symbol_box ); /* medium debt */ } } const geometry_rectangle_t *const feature_label_box = layout_feature_get_label_box_const( probe_feature ); if ( geometry_rectangle_is_intersecting( current_solution, feature_label_box ) ) { debts_of_current += 100.0 * geometry_rectangle_get_intersect_area( current_solution, feature_label_box ); /* medium debt */ } } /* iterate over all relationships */ const uint32_t count_relations = pencil_layout_data_get_relationship_count ( layout_data ); for ( uint32_t rel_index = 0; rel_index < count_relations; rel_index ++ ) { /* add debts if intersects */ const layout_relationship_t *const probe_relationship = pencil_layout_data_get_relationship_ptr( layout_data, rel_index ); if (( PENCIL_VISIBILITY_SHOW == layout_relationship_get_visibility( probe_relationship ) ) || ( PENCIL_VISIBILITY_GRAY_OUT == layout_relationship_get_visibility( probe_relationship ) )) { const geometry_connector_t *const probe_shape = layout_relationship_get_shape_const( probe_relationship ); if ( geometry_connector_is_intersecting_rectangle( probe_shape, current_solution ) ) { debts_of_current += geometry_rectangle_get_area( current_solution ); /* relationship bounds intersects are not so bad ... low debt */ } const geometry_rectangle_t *const relationship_label_box = layout_relationship_get_label_box_const( probe_relationship ); if ( geometry_rectangle_is_intersecting( current_solution, relationship_label_box ) ) { debts_of_current += 100.0 * geometry_rectangle_get_intersect_area( current_solution, relationship_label_box ); /* medium debt */ } } } /* update best solution */ if ( debts_of_current < debts_of_best ) { index_of_best = solution_idx; debts_of_best = debts_of_current; } } /* static unsigned int random; random ++; index_of_best = random % solutions_count; */ /* output the best */ TRACE_INFO_INT_INT("label layout idx, debt:", index_of_best, (int32_t)debts_of_best) *out_index_of_best = index_of_best; TRACE_END(); } /* * Copyright 2019-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/pencil_layout_data.c000066400000000000000000001220771415120503000237120ustar00rootroot00000000000000/* File: pencil_layout_data.c; Copyright and License: see below */ #include "pencil_layout_data.h" #include "trace.h" #include "tslog.h" #include void pencil_layout_data_init( pencil_layout_data_t *this_, const data_visible_set_t *input_data ) { TRACE_BEGIN(); assert ( NULL != input_data ); TRACE_INFO_INT( "sizeof(pencil_layout_data_t):", sizeof(pencil_layout_data_t) ); data_rules_init ( &((*this_).filter_rules) ); /* init input data */ (*this_).input_data = input_data; /* initialite the layout data objects */ pencil_layout_data_private_init_diagram( this_ ); pencil_layout_data_private_init_classifiers( this_ ); pencil_layout_data_private_init_features( this_ ); pencil_layout_data_private_init_relationships( this_ ); if ( data_visible_set_is_valid( input_data ) ) { assert ( pencil_layout_data_is_valid( this_ ) ); } TRACE_END(); } void pencil_layout_data_private_init_diagram( pencil_layout_data_t *this_ ) { TRACE_BEGIN(); assert ( NULL != (*this_).input_data ); layout_diagram_init ( &((*this_).diagram_layout), data_visible_set_get_diagram_const( (*this_).input_data ) ); (*this_).diagram_valid = layout_diagram_is_valid( &((*this_).diagram_layout) ); TRACE_INFO_INT ( "diagram data objects:", 1 ); TRACE_INFO_INT ( "diagram ignored objects:", 0 ); /* we do not ignore diagram objects */ TRACE_INFO_INT ( "layout_diagram objects:", 1 ); TRACE_END(); } void pencil_layout_data_private_init_classifiers( pencil_layout_data_t *this_ ) { TRACE_BEGIN(); assert ( NULL != (*this_).input_data ); const uint_fast32_t data_classifier_count = data_visible_set_get_visible_classifier_count( (*this_).input_data ); (*this_).visible_classifier_count = 0; assert ( data_classifier_count <= PENCIL_LAYOUT_DATA_MAX_CLASSIFIERS ); for ( uint_fast32_t c_idx = 0; c_idx < data_classifier_count; c_idx ++ ) { const data_visible_classifier_t *const classifier_data = data_visible_set_get_visible_classifier_const( (*this_).input_data, c_idx ); if ( ( NULL != classifier_data ) && data_visible_classifier_is_valid( classifier_data ) ) { layout_visible_classifier_init( &((*this_).visible_classifier_layout[(*this_).visible_classifier_count]), classifier_data ); (*this_).visible_classifier_count ++; } else { TSLOG_ERROR("error in input_data: illegal classifier."); assert(false); } } /* end for all classifier_data */ TRACE_INFO_INT ( "classifier data objects:", data_classifier_count ); TRACE_INFO_INT ( "classifier ignored objects:", data_classifier_count - (*this_).visible_classifier_count ); TRACE_INFO_INT ( "layout_v._classifier objects:", (*this_).visible_classifier_count ); TRACE_END(); } void pencil_layout_data_private_init_features( pencil_layout_data_t *this_ ) { TRACE_BEGIN(); assert ( NULL != (*this_).input_data ); const uint_fast32_t data_feature_count = data_visible_set_get_feature_count( (*this_).input_data ); uint_fast32_t debug_dropped_features; debug_dropped_features = 0; uint_fast32_t warn_dropped_features; warn_dropped_features = 0; (*this_).feature_count = 0; for ( uint_fast32_t f_idx = 0; f_idx < data_feature_count; f_idx ++ ) { const data_feature_t *const feature_data = data_visible_set_get_feature_const( (*this_).input_data, f_idx ); uint_fast32_t layout_feature_count = 0; if ( ( NULL != feature_data ) && data_feature_is_valid( feature_data ) ) { const data_row_id_t feature_id = data_feature_get_row_id( feature_data ); const bool show = data_rules_diagram_shows_feature ( &((*this_).filter_rules), (*this_).input_data, feature_id ); if ( show ) { for ( uint_fast32_t c_idx2 = 0; c_idx2 < (*this_).visible_classifier_count; c_idx2 ++ ) { layout_visible_classifier_t *const parent_classifier = &((*this_).visible_classifier_layout[c_idx2]); const bool one_parent_found = data_rules_vis_classifier_has_feature ( &((*this_).filter_rules), layout_visible_classifier_get_data_const( parent_classifier ), feature_data ); if ( one_parent_found ) { if ( (*this_).feature_count < PENCIL_LAYOUT_DATA_MAX_FEATURES ) { layout_feature_init( &((*this_).feature_layout[(*this_).feature_count]), feature_data, parent_classifier ); (*this_).feature_count ++; layout_feature_count ++; } else { warn_dropped_features ++; } } /* one_parent_found */ } /* end search-for parent_classifier */ } } else { TSLOG_ERROR("error in input_data: illegal feature."); assert(false); } if ( layout_feature_count == 0 ) { /* no warning here, dropping features - e.g. lifelines for other diagrams - is ok */ debug_dropped_features ++; } } /* end for all feature_data */ TRACE_INFO_INT ( "feature data objects:", data_feature_count ); TRACE_INFO_INT ( "feature ignored objects:", debug_dropped_features ); TRACE_INFO_INT ( "layout_feature objects:", (*this_).feature_count ); if ( 0 != warn_dropped_features ) { TSLOG_WARNING_INT( "PENCIL_LAYOUT_DATA_MAX_FEATURES exceeded, layout_features not visible:", warn_dropped_features ); } TRACE_END(); } void pencil_layout_data_private_init_relationships( pencil_layout_data_t *this_ ) { TRACE_BEGIN(); assert ( NULL != (*this_).input_data ); const uint32_t data_relationship_count = data_visible_set_get_relationship_count( (*this_).input_data ); uint32_t debug_dropped_relationships; debug_dropped_relationships = 0; uint32_t warn_dropped_relationships; warn_dropped_relationships = 0; (*this_).relationship_count = 0; for ( uint32_t r_idx = 0; r_idx < data_relationship_count; r_idx ++ ) { const data_relationship_t *relationship_data; relationship_data = data_visible_set_get_relationship_const( (*this_).input_data, r_idx ); uint32_t layout_relationship_count = 0; if ( ( NULL != relationship_data ) && data_relationship_is_valid( relationship_data ) ) { const bool show = data_rules_diagram_shows_relationship ( &((*this_).filter_rules), (*this_).input_data, data_relationship_get_row_id( relationship_data ) ); if ( show ) { layout_relationship_count = pencil_layout_data_private_init_relationship( this_, relationship_data, &warn_dropped_relationships ); } } else { TSLOG_ERROR("error in input_data: illegal relationship."); assert(false); } if ( layout_relationship_count == 0 ) { /* no warning here, dropping relationships - e.g. only one end-object visible in current diagram - is ok */ debug_dropped_relationships ++; } } /* end for all relationship_data */ TRACE_INFO_INT ( "relationship data objects:", data_relationship_count ); TRACE_INFO_INT ( "relationship ignored objects:", debug_dropped_relationships ); TRACE_INFO_INT ( "layout_relationship objects:", (*this_).relationship_count ); if ( 0 != warn_dropped_relationships ) { TSLOG_WARNING_INT( "PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS exceeded, layout_relationships not visible:", warn_dropped_relationships ); } TRACE_END(); } uint32_t pencil_layout_data_private_init_relationship( pencil_layout_data_t *this_, const data_relationship_t *relationship_data, uint32_t *io_dropped_relationships ) { TRACE_BEGIN(); assert ( NULL != (*this_).input_data ); assert ( NULL != relationship_data ); assert ( NULL != io_dropped_relationships ); uint32_t layout_relationship_count = 0; const data_row_id_t from_classifier_id = data_relationship_get_from_classifier_row_id( relationship_data ); const data_row_id_t to_classifier_id = data_relationship_get_to_classifier_row_id( relationship_data ); const data_row_id_t from_feature_id = data_relationship_get_from_feature_row_id( relationship_data ); const data_row_id_t to_feature_id = data_relationship_get_to_feature_row_id( relationship_data ); if ( DATA_ROW_ID_VOID == from_feature_id ) /* search source(from) in classifiers */ { for ( uint32_t c_idx3 = 0; c_idx3 < (*this_).visible_classifier_count; c_idx3 ++ ) { layout_visible_classifier_t *const probe3_classifier = &((*this_).visible_classifier_layout[c_idx3]); const bool one_from_classifier_found = ( from_classifier_id == layout_visible_classifier_get_classifier_id( probe3_classifier ) ); if ( one_from_classifier_found ) { if ( DATA_ROW_ID_VOID == to_feature_id ) /* search destination(to) in classifiers */ { for ( uint32_t c_idx4 = 0; c_idx4 < (*this_).visible_classifier_count; c_idx4 ++ ) { layout_visible_classifier_t *probe4_classifier; probe4_classifier = &((*this_).visible_classifier_layout[c_idx4]); const bool one_to_classifier_found = ( to_classifier_id == layout_visible_classifier_get_classifier_id( probe4_classifier ) ); if ( one_to_classifier_found ) { if ( (*this_).relationship_count < PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS ) { layout_relationship_init( &((*this_).relationship_layout[(*this_).relationship_count]), relationship_data, probe3_classifier, probe4_classifier, NULL, NULL ); (*this_).relationship_count ++; layout_relationship_count ++; } else { (*io_dropped_relationships) ++; } } /* one_to_classifier_found */ } /* end search-for to_classifier */ } else /* search destination(to) in features */ { for ( uint32_t f_idx4 = 0; f_idx4 < (*this_).feature_count; f_idx4 ++ ) { layout_feature_t *const probe4_feature = &((*this_).feature_layout[f_idx4]); const bool one_to_feature_found = ( to_feature_id == layout_feature_get_feature_id( probe4_feature ) ); if ( one_to_feature_found ) { const bool to_feature_ok = ( to_classifier_id == data_feature_get_classifier_row_id(layout_feature_get_data_const( probe4_feature )) ); if ( to_feature_ok ) { if ( (*this_).relationship_count < PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS ) { layout_relationship_init( &((*this_).relationship_layout[(*this_).relationship_count]), relationship_data, probe3_classifier, layout_feature_get_classifier_ptr( probe4_feature ), NULL, probe4_feature ); (*this_).relationship_count ++; layout_relationship_count ++; } else { (*io_dropped_relationships) ++; } } else { TSLOG_ERROR("error in input_data: relationship links to feature and inconsistent classifier."); } } /* one_to_feature_found */ } /* end search-for to_feature */ } } /* one_from_classifier_found */ } /* end search-for from_classifier */ } else /* search source(from) in features */ { for ( uint32_t f_idx3 = 0; f_idx3 < (*this_).feature_count; f_idx3 ++ ) { layout_feature_t *probe3_feature; probe3_feature = &((*this_).feature_layout[f_idx3]); const bool one_from_feature_found = ( from_feature_id == layout_feature_get_feature_id( probe3_feature ) ); if ( one_from_feature_found ) { const bool from_feature_ok = ( from_classifier_id == data_feature_get_classifier_row_id(layout_feature_get_data_const( probe3_feature )) ); if ( from_feature_ok ) { if ( DATA_ROW_ID_VOID == to_feature_id ) /* search destination(to) in classifiers */ { for ( uint32_t c_idx5 = 0; c_idx5 < (*this_).visible_classifier_count; c_idx5 ++ ) { layout_visible_classifier_t *const probe5_classifier = &((*this_).visible_classifier_layout[c_idx5]); const bool one_to_classifier_found = ( to_classifier_id == layout_visible_classifier_get_classifier_id( probe5_classifier ) ); if ( one_to_classifier_found ) { if ( (*this_).relationship_count < PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS ) { layout_relationship_init( &((*this_).relationship_layout[(*this_).relationship_count]), relationship_data, layout_feature_get_classifier_ptr( probe3_feature ), probe5_classifier, probe3_feature, NULL ); (*this_).relationship_count ++; layout_relationship_count ++; } else { (*io_dropped_relationships) ++; } } /* one_to_classifier_found */ } /* end search-for to_classifier */ } else /* search destination(to) in features */ { for ( uint32_t f_idx5 = 0; f_idx5 < (*this_).feature_count; f_idx5 ++ ) { layout_feature_t *const probe5_feature = &((*this_).feature_layout[f_idx5]); const bool one_to_feature_found = ( to_feature_id == layout_feature_get_feature_id( probe5_feature ) ); if ( one_to_feature_found ) { const bool to_feature_ok = ( to_classifier_id == data_feature_get_classifier_row_id(layout_feature_get_data_const( probe5_feature )) ); if ( to_feature_ok ) { if ( (*this_).relationship_count < PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS ) { layout_relationship_init( &((*this_).relationship_layout[(*this_).relationship_count]), relationship_data, layout_feature_get_classifier_ptr( probe3_feature ), layout_feature_get_classifier_ptr( probe5_feature ), probe3_feature, probe5_feature ); (*this_).relationship_count ++; layout_relationship_count ++; } else { (*io_dropped_relationships) ++; } } else { TSLOG_ERROR("error in input_data: relationship links to feature and inconsistent classifier."); } } /* one_to_feature_found */ } /* end search-for to_feature */ } } else { TSLOG_ERROR("error in input_data: relationship links from feature and inconsistent classifier."); } } /* one_from_feature_found */ } /* end search-for from_feature */ } /* endif: search source(from) */ TRACE_END(); return layout_relationship_count; } void pencil_layout_data_destroy( pencil_layout_data_t *this_ ) { TRACE_BEGIN(); assert( (*this_).visible_classifier_count <= PENCIL_LAYOUT_DATA_MAX_CLASSIFIERS ); assert( (*this_).feature_count <= PENCIL_LAYOUT_DATA_MAX_FEATURES ); assert( (*this_).relationship_count <= PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS ); data_rules_destroy ( &((*this_).filter_rules) ); if ( (*this_).diagram_valid ) { layout_diagram_destroy ( &((*this_).diagram_layout) ); } for ( uint_fast32_t c_idx = 0; c_idx < (*this_).visible_classifier_count; c_idx ++ ) { layout_visible_classifier_destroy( &((*this_).visible_classifier_layout[c_idx]) ); } for ( uint_fast32_t f_idx = 0; f_idx < (*this_).feature_count; f_idx ++ ) { layout_feature_destroy( &((*this_).feature_layout[f_idx]) ); } for ( uint_fast32_t r_idx = 0; r_idx < (*this_).relationship_count; r_idx ++ ) { layout_relationship_destroy( &((*this_).relationship_layout[r_idx]) ); } TRACE_END(); } /* ================================ misc ================================ */ bool pencil_layout_data_is_valid ( const pencil_layout_data_t *this_ ) { bool result = true; /* check input data */ if ( NULL == (*this_).input_data ) { result = false; } else { if ( ! data_visible_set_is_valid( (*this_).input_data ) ) { result = false; } } /* check diagram */ if ( ! (*this_).diagram_valid ) { result = false; } else { if ( ! layout_diagram_is_valid( &((*this_).diagram_layout) ) ) { result = false; } } /* check classifiers */ if ( (*this_).visible_classifier_count > PENCIL_LAYOUT_DATA_MAX_CLASSIFIERS ) { /* if the object is already initialized, this is a severe error */ result = false; } else { for ( uint_fast32_t c_idx = 0; c_idx < (*this_).visible_classifier_count; c_idx ++ ) { const layout_visible_classifier_t *current = &((*this_).visible_classifier_layout[c_idx]); if ( ! layout_visible_classifier_is_valid( current ) ) { result = false; } } } /* check features */ if ( (*this_).feature_count > PENCIL_LAYOUT_DATA_MAX_FEATURES ) { /* if the object is already initialized, this is a severe error */ result = false; } else { for ( uint_fast32_t f_idx = 0; f_idx < (*this_).feature_count; f_idx ++ ) { const layout_feature_t *current = &((*this_).feature_layout[f_idx]); if ( ! layout_feature_is_valid( current ) ) { result = false; } } } /* check relationships */ if ( (*this_).relationship_count > PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS ) { /* if the object is already initialized, this is a severe error */ result = false; } else { for ( uint_fast32_t r_idx = 0; r_idx < (*this_).relationship_count; r_idx ++ ) { const layout_relationship_t *current = &((*this_).relationship_layout[r_idx]); if ( ! layout_relationship_is_valid( current ) ) { result = false; } } } return result; } #ifndef NDEBUG #define PENCIL_LAYOUT_DATA_STATS_WITH_WARNINGS #else /* REMOVE ME */ #define PENCIL_LAYOUT_DATA_STATS_WITH_WARNINGS #endif void pencil_layout_data_get_statistics ( const pencil_layout_data_t *this_, data_stat_t *io_layout_stat ) { TRACE_BEGIN(); assert( (*this_).visible_classifier_count <= PENCIL_LAYOUT_DATA_MAX_CLASSIFIERS ); assert( (*this_).feature_count <= PENCIL_LAYOUT_DATA_MAX_FEATURES ); assert( (*this_).relationship_count <= PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS ); assert( io_layout_stat != NULL ); /* check if diagram is valid */ if ( (*this_).diagram_valid ) { data_stat_inc_count( io_layout_stat, DATA_TABLE_DIAGRAM, DATA_STAT_SERIES_EXPORTED ); const geometry_rectangle_t *const diag_bounds = layout_diagram_get_bounds_const( &((*this_).diagram_layout) ); const geometry_rectangle_t *const diag_space = layout_diagram_get_draw_area_const( &((*this_).diagram_layout) ); /* check classifiers against diagram */ for ( uint_fast32_t c_idx = 0; c_idx < (*this_).visible_classifier_count; c_idx ++ ) { const layout_visible_classifier_t *const classifier = &((*this_).visible_classifier_layout[c_idx]); const geometry_rectangle_t *const c_symbox = layout_visible_classifier_get_symbol_box_const( classifier ); const geometry_rectangle_t *const c_label = layout_visible_classifier_get_label_box_const( classifier ); #ifdef PENCIL_LAYOUT_DATA_STATS_WITH_WARNINGS const geometry_rectangle_t *const c_space = layout_visible_classifier_get_space_const( classifier ); #endif if ( geometry_rectangle_is_containing( diag_space, c_symbox ) && geometry_rectangle_is_containing( diag_space, c_label ) ) { data_stat_inc_count( io_layout_stat, DATA_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_EXPORTED ); #ifdef PENCIL_LAYOUT_DATA_STATS_WITH_WARNINGS /* check current classifier against already processed classifiers */ for ( uint_fast32_t probe_idx = 0; probe_idx < c_idx; probe_idx ++ ) { const layout_visible_classifier_t *const probe = &((*this_).visible_classifier_layout[probe_idx]); const geometry_rectangle_t *const probe_symbox = layout_visible_classifier_get_symbol_box_const( probe ); const geometry_rectangle_t *const probe_label = layout_visible_classifier_get_label_box_const( probe ); const geometry_rectangle_t *const probe_space = layout_visible_classifier_get_space_const( probe ); const bool symbox_overlaps = geometry_rectangle_is_intersecting( c_symbox, probe_symbox ); const bool mixed_overlaps = ( geometry_rectangle_is_intersecting( c_symbox, probe_label ) || geometry_rectangle_is_intersecting( c_label, probe_symbox ) ); const bool label_overlaps = geometry_rectangle_is_intersecting( c_label, probe_label ); if ( symbox_overlaps || mixed_overlaps || label_overlaps ) { const bool probe_is_ancestor = pencil_layout_data_is_ancestor( this_, probe, /* ancestor */ classifier /* descendant */ ); const bool probe_is_descendant = pencil_layout_data_is_ancestor( this_, classifier, /* ancestor */ probe /* descendant */ ); const bool probe_contains_c = ( geometry_rectangle_is_containing( probe_space, c_symbox ) && geometry_rectangle_is_containing( probe_space, c_label ) ); const bool c_contains_probe = ( geometry_rectangle_is_containing( c_space, probe_symbox ) && geometry_rectangle_is_containing( c_space, probe_label ) ); if ( probe_is_ancestor && probe_contains_c ) { /* ok */ } else if ( probe_is_descendant && c_contains_probe ) { /* ok */ } else { data_stat_inc_count( io_layout_stat, DATA_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_WARNING ); } } } #endif } else if ( geometry_rectangle_is_containing( diag_bounds, c_symbox ) && geometry_rectangle_is_containing( diag_bounds, c_label ) ) { data_stat_inc_count( io_layout_stat, DATA_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_EXPORTED ); data_stat_inc_count( io_layout_stat, DATA_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_WARNING ); } else { data_stat_inc_count( io_layout_stat, DATA_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_ERROR ); } } /* check features against diagram */ for ( uint_fast32_t f_idx = 0; f_idx < (*this_).feature_count; f_idx ++ ) { const layout_feature_t *const feature = &((*this_).feature_layout[f_idx]); const geometry_rectangle_t *const f_symbox = layout_feature_get_symbol_box_const( feature ); const geometry_rectangle_t *const f_label = layout_feature_get_label_box_const( feature ); if ( ( geometry_rectangle_is_empty( f_symbox ) || geometry_rectangle_is_containing( diag_space, f_symbox )) && geometry_rectangle_is_containing( diag_space, f_label ) ) { data_stat_inc_count( io_layout_stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_EXPORTED ); #ifdef PENCIL_LAYOUT_DATA_STATS_WITH_WARNINGS /* check features against classifiers */ for ( uint_fast32_t probe_idx = 0; probe_idx < (*this_).visible_classifier_count; probe_idx ++ ) { const layout_visible_classifier_t *const probe = &((*this_).visible_classifier_layout[probe_idx]); const geometry_rectangle_t *const probe_symbox = layout_visible_classifier_get_symbol_box_const( probe ); const geometry_rectangle_t *const probe_label = layout_visible_classifier_get_label_box_const( probe ); const geometry_rectangle_t *const c_space = layout_visible_classifier_get_space_const( probe ); const bool symbox_overlaps = geometry_rectangle_is_intersecting( f_symbox, probe_symbox ) && ( ! geometry_rectangle_is_containing( c_space, f_symbox ) ); const bool f_sym_overlaps_c_label = geometry_rectangle_is_intersecting( f_symbox, probe_label ); const bool f_label_overlaps_c_sym = geometry_rectangle_is_intersecting( f_label, probe_symbox ) && ( ! geometry_rectangle_is_containing( c_space, f_label ) ); const bool label_overlaps = geometry_rectangle_is_intersecting( f_label, probe_label ); if ( f_sym_overlaps_c_label || f_label_overlaps_c_sym || label_overlaps ) { data_stat_inc_count( io_layout_stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_WARNING ); } else if ( symbox_overlaps ) { const layout_visible_classifier_t *const f_parent = layout_feature_get_classifier_const ( feature ); const bool probe_is_parent = layout_visible_classifier_is_equal_diagramelement_id( f_parent, probe ); if ( probe_is_parent ) { /* ok */ } else { data_stat_inc_count( io_layout_stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_WARNING ); } } } /* check current feature against already processed features */ for ( uint_fast32_t probe_idx = 0; probe_idx < f_idx; probe_idx ++ ) { const layout_feature_t *const probe = &((*this_).feature_layout[probe_idx]); const data_feature_t *const probe_data = layout_feature_get_data_const( probe ); const geometry_rectangle_t *const probe_symbox = layout_feature_get_symbol_box_const( probe ); const geometry_rectangle_t *const probe_label = layout_feature_get_label_box_const( probe ); if ( DATA_FEATURE_TYPE_LIFELINE != data_feature_get_main_type( probe_data ) ) { const bool symbox_overlaps = geometry_rectangle_is_intersecting( f_symbox, probe_symbox ); const bool mixed_overlaps = ( geometry_rectangle_is_intersecting( f_symbox, probe_label ) || geometry_rectangle_is_intersecting( f_label, probe_symbox ) ); const bool label_overlaps = geometry_rectangle_is_intersecting( f_label, probe_label ); if ( mixed_overlaps || label_overlaps ) { data_stat_inc_count( io_layout_stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_WARNING ); } else if ( symbox_overlaps ) { const layout_visible_classifier_t *const f_parent = layout_feature_get_classifier_const ( feature ); const layout_visible_classifier_t *const probe_parent = layout_feature_get_classifier_const ( probe ); const bool same_parent = layout_visible_classifier_is_equal_diagramelement_id( f_parent, probe_parent ); if ( same_parent ) { /* ok, not a layouting issue */ } else { data_stat_inc_count( io_layout_stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_WARNING ); } } } } #endif } else if ( geometry_rectangle_is_containing( diag_bounds, f_symbox ) && geometry_rectangle_is_containing( diag_bounds, f_label ) ) { data_stat_inc_count( io_layout_stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_EXPORTED ); data_stat_inc_count( io_layout_stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_WARNING ); } else { data_stat_inc_count( io_layout_stat, DATA_TABLE_FEATURE, DATA_STAT_SERIES_ERROR ); } } /* check relationships against diagram */ for ( uint_fast32_t r_idx = 0; r_idx < (*this_).relationship_count; r_idx ++ ) { const layout_relationship_t *const relationship = &((*this_).relationship_layout[r_idx]); const geometry_rectangle_t *const r_label = layout_relationship_get_label_box_const( relationship ); const geometry_connector_t *const r_shape = layout_relationship_get_shape_const( relationship ); const geometry_rectangle_t r_bounds = geometry_connector_get_bounding_rectangle( r_shape ); if ( geometry_rectangle_is_containing( diag_space, &r_bounds ) && geometry_rectangle_is_containing( diag_space, r_label ) ) { data_stat_inc_count( io_layout_stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_EXPORTED ); #ifdef PENCIL_LAYOUT_DATA_STATS_WITH_WARNINGS /* check relationships against classifiers */ for ( uint_fast32_t probe_idx = 0; probe_idx < (*this_).visible_classifier_count; probe_idx ++ ) { const layout_visible_classifier_t *const probe = &((*this_).visible_classifier_layout[probe_idx]); const geometry_rectangle_t *const probe_symbox = layout_visible_classifier_get_symbol_box_const( probe ); const geometry_rectangle_t *const probe_label = layout_visible_classifier_get_label_box_const( probe ); const geometry_rectangle_t *const probe_space = layout_visible_classifier_get_space_const( probe ); const bool label_overlaps_label = geometry_rectangle_is_intersecting( r_label, probe_label ); const bool label_overlaps_symbox = ( geometry_rectangle_is_intersecting( r_label, probe_symbox ) && ! geometry_rectangle_is_containing( probe_space, r_label ) ); const bool shape_overlaps_label = geometry_connector_is_intersecting_rectangle( r_shape, probe_label ); if ( label_overlaps_label || label_overlaps_symbox || shape_overlaps_label ) { data_stat_inc_count( io_layout_stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_WARNING ); } } /* check relationships against features */ for ( uint_fast32_t probe_idx = 0; probe_idx < (*this_).feature_count; probe_idx ++ ) { const layout_feature_t *const probe = &((*this_).feature_layout[probe_idx]); const data_feature_t *const probe_data = layout_feature_get_data_const( probe ); const geometry_rectangle_t *const probe_symbox = layout_feature_get_symbol_box_const( probe ); const geometry_rectangle_t *const probe_label = layout_feature_get_label_box_const( probe ); if ( DATA_FEATURE_TYPE_LIFELINE != data_feature_get_main_type( probe_data ) ) { const bool label_overlaps_label = geometry_rectangle_is_intersecting( r_label, probe_label ); const bool label_overlaps_symbox = geometry_rectangle_is_intersecting( r_label, probe_symbox ); const bool shape_overlaps_label = geometry_connector_is_intersecting_rectangle( r_shape, probe_label ); if ( label_overlaps_label || label_overlaps_symbox || shape_overlaps_label ) { data_stat_inc_count( io_layout_stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_WARNING ); } } } /* check current relationship against already processed relationships */ for ( uint_fast32_t probe_idx = 0; probe_idx < r_idx; probe_idx ++ ) { const layout_relationship_t *const probe = &((*this_).relationship_layout[probe_idx]); const geometry_rectangle_t *const probe_label = layout_relationship_get_label_box_const( probe ); const geometry_connector_t *const probe_shape = layout_relationship_get_shape_const( probe ); const bool label_overlaps = geometry_rectangle_is_intersecting( r_label, probe_label ); const bool mixed_overlaps = ( geometry_connector_is_intersecting_rectangle( r_shape, probe_label ) || geometry_connector_is_intersecting_rectangle( probe_shape, r_label ) ); if ( label_overlaps || mixed_overlaps ) { data_stat_inc_count( io_layout_stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_WARNING ); } } #endif } else if ( geometry_rectangle_is_containing( diag_bounds, &r_bounds ) && geometry_rectangle_is_containing( diag_bounds, r_label ) ) { data_stat_inc_count( io_layout_stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_EXPORTED ); data_stat_inc_count( io_layout_stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_WARNING ); } else { data_stat_inc_count( io_layout_stat, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_ERROR ); } } } else { data_stat_inc_count( io_layout_stat, DATA_TABLE_DIAGRAM, DATA_STAT_SERIES_ERROR ); } TRACE_END(); } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/pencil_layouter.c000066400000000000000000001363031415120503000232450ustar00rootroot00000000000000/* File: pencil_layouter.c; Copyright and License: see below */ #include "pencil_layouter.h" #include "trace.h" #include #include #include #include void pencil_layouter_init( pencil_layouter_t *this_, const data_visible_set_t *input_data ) { TRACE_BEGIN(); assert( NULL != input_data ); pencil_size_init_empty( &((*this_).pencil_size) ); geometry_non_linear_scale_init( &((*this_).x_scale), 0.0, 1.0 ); geometry_non_linear_scale_init( &((*this_).y_scale), 0.0, 1.0 ); geometry_dimensions_init_empty( &((*this_).default_classifier_size) ); data_rules_init( &((*this_).rules) ); pencil_layout_data_init( &((*this_).layout_data), input_data ); pencil_diagram_painter_init( &((*this_).diagram_painter) ); pencil_feature_layouter_init( &((*this_).feature_layouter), &((*this_).layout_data), &((*this_).pencil_size) ); pencil_feat_label_layouter_init( &((*this_).feature_label_layouter), &((*this_).layout_data), &((*this_).pencil_size) ); pencil_classifier_2d_layouter_init( &((*this_).pencil_classifier_2d_layouter), &((*this_).layout_data), &((*this_).pencil_size), &((*this_).default_classifier_size), &((*this_).x_scale), &((*this_).y_scale), &((*this_).feature_layouter) ); pencil_classifier_1d_layouter_init( &((*this_).pencil_classifier_1d_layouter), &((*this_).layout_data), &((*this_).pencil_size) ); pencil_relationship_layouter_init( &((*this_).pencil_relationship_layouter), &((*this_).layout_data), &((*this_).pencil_size) ); pencil_rel_label_layouter_init( &((*this_).relationship_label_layouter), &((*this_).layout_data), &((*this_).pencil_size) ); TRACE_END(); } void pencil_layouter_reinit( pencil_layouter_t *this_, const data_visible_set_t *input_data ) { TRACE_BEGIN(); assert( NULL != input_data ); /* re-initialize the layout data objects */ pencil_layout_data_reinit( &((*this_).layout_data), input_data ); TRACE_END(); } void pencil_layouter_destroy( pencil_layouter_t *this_ ) { TRACE_BEGIN(); pencil_rel_label_layouter_destroy( &((*this_).relationship_label_layouter) ); pencil_relationship_layouter_destroy( &((*this_).pencil_relationship_layouter) ); pencil_classifier_1d_layouter_destroy( &((*this_).pencil_classifier_1d_layouter) ); pencil_classifier_2d_layouter_destroy( &((*this_).pencil_classifier_2d_layouter) ); pencil_feat_label_layouter_destroy( &((*this_).feature_label_layouter) ); pencil_feature_layouter_destroy( &((*this_).feature_layouter) ); pencil_diagram_painter_destroy( &((*this_).diagram_painter) ); pencil_size_destroy( &((*this_).pencil_size) ); geometry_non_linear_scale_destroy( &((*this_).x_scale) ); geometry_non_linear_scale_destroy( &((*this_).y_scale) ); geometry_dimensions_destroy( &((*this_).default_classifier_size) ); data_rules_destroy( &((*this_).rules) ); pencil_layout_data_destroy( &((*this_).layout_data) ); TRACE_END(); } void pencil_layouter_define_grid ( pencil_layouter_t *this_, geometry_rectangle_t diagram_bounds ) { TRACE_BEGIN(); /* get the diagram data */ layout_diagram_t *the_diagram; the_diagram = pencil_layout_data_get_diagram_ptr( &((*this_).layout_data) ); const data_diagram_t *const diagram_data = layout_diagram_get_data_const ( the_diagram ); /* update the bounding rectangle */ geometry_rectangle_trace ( &diagram_bounds ); layout_diagram_set_bounds( the_diagram, &diagram_bounds ); /* calculate the pencil-sizes and the drawing rectangle */ const double width = geometry_rectangle_get_width ( &diagram_bounds ); const double height = geometry_rectangle_get_height ( &diagram_bounds ); pencil_size_reinit( &((*this_).pencil_size), width, height ); geometry_rectangle_t diagram_draw_area; geometry_rectangle_init_empty( &diagram_draw_area ); pencil_diagram_painter_get_drawing_space ( &((*this_).diagram_painter), diagram_data, &((*this_).pencil_size), &diagram_bounds, &diagram_draw_area ); layout_diagram_set_draw_area( the_diagram, &diagram_draw_area ); geometry_rectangle_destroy( &diagram_draw_area ); /* calculate the axis scales */ geometry_rectangle_trace ( &diagram_draw_area ); const double draw_left = geometry_rectangle_get_left ( &diagram_draw_area ); const double draw_top = geometry_rectangle_get_top ( &diagram_draw_area ); const double draw_right = geometry_rectangle_get_right ( &diagram_draw_area ); const double draw_bottom = geometry_rectangle_get_bottom ( &diagram_draw_area ); geometry_non_linear_scale_reinit( &((*this_).x_scale), draw_left, draw_right ); geometry_non_linear_scale_reinit( &((*this_).y_scale), draw_top, draw_bottom ); /* iterate over all classifiers */ const uint32_t count = pencil_layout_data_get_visible_classifier_count ( &((*this_).layout_data) ); for ( uint32_t index = 0; index < count; index ++ ) { const layout_visible_classifier_t *const visible_classifier = pencil_layout_data_get_visible_classifier_ptr ( &((*this_).layout_data), index ); const data_classifier_t *const classifier_data = layout_visible_classifier_get_classifier_const( visible_classifier ); const uint32_t visible_descendants = pencil_layout_data_count_descendants( &((*this_).layout_data), visible_classifier ); /* adjust the non-linear scales for this classifier (if no contained descendants) */ if ( 0 == visible_descendants ) { geometry_non_linear_scale_add_order ( &((*this_).x_scale), data_classifier_get_x_order( classifier_data ) ); geometry_non_linear_scale_add_order ( &((*this_).y_scale), data_classifier_get_y_order( classifier_data ) ); } } TRACE_END(); } void pencil_layouter_layout_elements ( pencil_layouter_t *this_, PangoLayout *font_layout, data_stat_t *io_layout_stat ) { TRACE_BEGIN(); assert( font_layout != NULL ); /* get the diagram data */ const layout_diagram_t *const the_diagram = pencil_layout_data_get_diagram_ptr( &((*this_).layout_data) ); const data_diagram_t *const diagram_data = layout_diagram_get_data_const ( the_diagram ); const data_diagram_type_t diag_type = data_diagram_get_diagram_type ( diagram_data ); /* adjust the default classifier rectangle */ pencil_layouter_private_propose_default_classifier_size( this_ ); /* store the classifier bounds into input_data_layouter_t */ if ( DATA_DIAGRAM_TYPE_LIST == diag_type ) { /* calculate the classifier shapes */ pencil_classifier_1d_layouter_layout_for_list( &((*this_).pencil_classifier_1d_layouter), font_layout ); /* calculate the feature shapes */ pencil_feature_layouter_do_layout( &((*this_).feature_layouter), font_layout ); /* hide relationships in simple list and box diagrams */ pencil_relationship_layouter_layout_void( &((*this_).pencil_relationship_layouter) ); /* layout labels of features */ pencil_feat_label_layouter_do_layout( &((*this_).feature_label_layouter), font_layout ); } else if ( DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM == diag_type ) { /* calculate the classifier shapes */ pencil_classifier_1d_layouter_layout_for_sequence( &((*this_).pencil_classifier_1d_layouter), font_layout ); /* calculate the feature shapes */ pencil_feature_layouter_do_layout( &((*this_).feature_layouter), font_layout ); /* calculate the relationship shapes for a sequence diagram */ pencil_relationship_layouter_layout_for_sequence( &((*this_).pencil_relationship_layouter) ); /* layout labels of relationships */ pencil_rel_label_layouter_do_layout( &((*this_).relationship_label_layouter), font_layout ); } else if ( DATA_DIAGRAM_TYPE_UML_TIMING_DIAGRAM == diag_type ) { /* calculate the classifier shapes */ pencil_classifier_1d_layouter_layout_for_timing( &((*this_).pencil_classifier_1d_layouter), font_layout ); /* calculate the feature shapes */ pencil_feature_layouter_do_layout( &((*this_).feature_layouter), font_layout ); /* calculate the relationship shapes for a timing diagram */ pencil_relationship_layouter_layout_for_timing( &((*this_).pencil_relationship_layouter) ); /* layout labels of relationships */ pencil_rel_label_layouter_do_layout( &((*this_).relationship_label_layouter), font_layout ); } else { /* store the classifier bounds into input_data_layouter_t */ pencil_classifier_2d_layouter_estimate_bounds( &((*this_).pencil_classifier_2d_layouter), font_layout ); /* move the classifiers to avoid overlaps */ pencil_classifier_2d_layouter_move_to_avoid_overlaps( &((*this_).pencil_classifier_2d_layouter) ); /* parent classifiers embrace their children step by step */ pencil_classifier_2d_layouter_embrace_children( &((*this_).pencil_classifier_2d_layouter), font_layout ); /* classifiers embrace all children at once and move them if there is space available */ pencil_classifier_2d_layouter_move_and_embrace_children( &((*this_).pencil_classifier_2d_layouter), font_layout ); /* calculate the feature shapes */ pencil_feature_layouter_do_layout( &((*this_).feature_layouter), font_layout ); if ( DATA_DIAGRAM_TYPE_BOX_DIAGRAM == diag_type ) { /* hide relationships in simple list and box diagrams */ pencil_relationship_layouter_layout_void( &((*this_).pencil_relationship_layouter) ); } else if (( DATA_DIAGRAM_TYPE_UML_COMMUNICATION_DIAGRAM == diag_type )||( DATA_DIAGRAM_TYPE_INTERACTION_OVERVIEW_DIAGRAM == diag_type )) { /* calculate the relationship shapes for a communication diagram or an interaction overview diagram (scenario-relations only) */ pencil_relationship_layouter_layout_for_communication( &((*this_).pencil_relationship_layouter) ); } else { /* calculate the relationship shapes */ pencil_relationship_layouter_layout_standard( &((*this_).pencil_relationship_layouter) ); } /* hide containment relationships if children are embraced */ pencil_classifier_2d_layouter_hide_relations_of_embraced_children( &((*this_).pencil_classifier_2d_layouter) ); /* layout labels of features and relationships */ pencil_feat_label_layouter_do_layout( &((*this_).feature_label_layouter), font_layout ); pencil_rel_label_layouter_do_layout( &((*this_).relationship_label_layouter), font_layout ); } if ( io_layout_stat != NULL ) { pencil_layout_data_get_statistics( &((*this_).layout_data), io_layout_stat ); } TRACE_END(); } void pencil_layouter_private_propose_default_classifier_size ( pencil_layouter_t *this_ ) { TRACE_BEGIN(); /* determine grid cell size */ const double grid_width = geometry_non_linear_scale_get_grid_distances ( &((*this_).x_scale) ); const double grid_height = geometry_non_linear_scale_get_grid_distances ( &((*this_).y_scale) ); double cell_width = grid_width; double cell_height = grid_height; /* check if the grid has enough points for all classifiers */ const uint_fast32_t interv_count_x = geometry_non_linear_scale_get_grid_intervals ( &((*this_).x_scale) ); const uint_fast32_t interv_count_y = geometry_non_linear_scale_get_grid_intervals ( &((*this_).y_scale) ); const uint_fast32_t inner_point_count = (interv_count_x-1)*(interv_count_y-1); const uint_fast32_t c_count = pencil_layout_data_get_visible_classifier_count ( &((*this_).layout_data) ); if ( inner_point_count < c_count ) { /* many classifiers share the same location */ /* default size is calculated based on count and size, not on grid */ /* get the diagram data */ const layout_diagram_t *const the_diagram = pencil_layout_data_get_diagram_ptr( &((*this_).layout_data) ); const geometry_rectangle_t *const diagram_draw_area = layout_diagram_get_draw_area_const( the_diagram ); const double draw_width = geometry_rectangle_get_width ( diagram_draw_area ); const double draw_height = geometry_rectangle_get_height ( diagram_draw_area ); const uint_fast32_t border = 1; uint_fast32_t rows; uint_fast32_t columns; if ( c_count <= 6 ) { columns = 2; rows = (c_count+1)/2; } else if ( c_count <= 12 ) { columns = 3; rows = (c_count+2)/3; } else if ( c_count <= 24 ) { columns = 4; rows = (c_count+3)/4; } else { columns = 5; rows = (c_count+4)/5; } cell_width = draw_width / (columns+border); cell_height = draw_height / (rows+border); } /* determine standard gap between objects */ const double gap = pencil_size_get_preferred_object_distance( &((*this_).pencil_size) ); /* set the default size to grid cell minus a gap on each side, minus extra gap on top for containers */ geometry_dimensions_t *const default_size = &((*this_).default_classifier_size); geometry_dimensions_reinit( default_size, cell_width, cell_height ); const double x_space = 3.0 * gap; /* space for enclosing parents and for relationships */ const double y_space = 4.0 * gap; /* space for enclosing parents (including title-line) and for relationships */ geometry_dimensions_expand ( default_size, -x_space, -y_space ); /* ensures non-negative values */ /* for aesthetic reasons, ensure that the default dimension is more wide than high */ const double w = geometry_dimensions_get_width( default_size ); const double h = geometry_dimensions_get_height( default_size ); if ( w * 0.75 < h ) { geometry_dimensions_reinit( default_size, w, w * 0.75 ); } TRACE_END(); } pencil_error_t pencil_layouter_get_object_id_at_pos ( const pencil_layouter_t *this_, double x, double y, double snap_distance, pencil_type_filter_t filter, data_id_pair_t* out_selected_id, data_id_pair_t* out_surrounding_id ) { TRACE_BEGIN(); assert( NULL != out_selected_id ); assert( NULL != out_surrounding_id ); pencil_error_t result = PENCIL_ERROR_NONE; data_id_pair_reinit_void( out_selected_id ); data_id_pair_reinit_void( out_surrounding_id ); const layout_diagram_t *the_diagram; the_diagram = pencil_layout_data_get_diagram_const( &((*this_).layout_data) ); const data_diagram_t *diagram_data; diagram_data = layout_diagram_get_data_const ( the_diagram ); /* get bounding box */ const geometry_rectangle_t *diagram_bounds; diagram_bounds = layout_diagram_get_bounds_const( the_diagram ); if ( geometry_rectangle_contains( diagram_bounds, x, y ) ) { /* check the relationship shapes */ { result = pencil_layouter_private_get_relationship_id_at_pos( this_, x, y, snap_distance, out_selected_id ); } /* determine a feature at the given position */ if ( ! data_id_pair_is_valid( out_selected_id ) ) { result = pencil_layouter_private_get_feature_id_at_pos( this_, x, y, filter, out_selected_id, out_surrounding_id ); } /* determine a classifier at the given position */ if ( ! data_id_pair_is_valid( out_selected_id ) ) { result = pencil_layouter_private_get_classifier_id_at_pos( this_, x, y, out_selected_id, out_surrounding_id ); } /* fallback: return the diagram */ if ( ! data_id_pair_is_valid( out_selected_id ) ) { data_id_pair_reinit_by_table_and_id ( out_selected_id, DATA_TABLE_DIAGRAM, data_diagram_get_row_id(diagram_data), DATA_TABLE_VOID, DATA_ROW_ID_VOID ); } if ( ! data_id_pair_is_valid( out_surrounding_id ) ) { data_id_pair_reinit_by_table_and_id ( out_surrounding_id, DATA_TABLE_DIAGRAM, data_diagram_get_row_id(diagram_data), DATA_TABLE_VOID, DATA_ROW_ID_VOID ); } } else { TRACE_INFO( "given location outside diagram or no diagram chosen" ); result = PENCIL_ERROR_OUT_OF_BOUNDS; } TRACE_END_ERR( result ); return result; } pencil_error_t pencil_layouter_private_get_classifier_id_at_pos ( const pencil_layouter_t *this_, double x, double y, data_id_pair_t* out_selected_id, data_id_pair_t* out_surrounding_id ) { TRACE_BEGIN(); assert( NULL != out_selected_id ); assert( NULL != out_surrounding_id ); pencil_error_t result = PENCIL_ERROR_OUT_OF_BOUNDS; /* get draw area */ const layout_diagram_t *const the_diagram = pencil_layout_data_get_diagram_const( &((*this_).layout_data) ); const geometry_rectangle_t *const diagram_draw_area = layout_diagram_get_draw_area_const( the_diagram ); if ( geometry_rectangle_contains( diagram_draw_area, x, y ) ) { /* iterate over all classifiers */ const uint32_t count = pencil_layout_data_get_visible_classifier_count ( &((*this_).layout_data) ); double surrounding_classifier_area = geometry_rectangle_get_area( diagram_draw_area ); for ( uint32_t index = 0; index < count; index ++ ) { const layout_visible_classifier_t *const visible_classifier = pencil_layout_data_get_visible_classifier_const ( &((*this_).layout_data), index ); const geometry_rectangle_t *const classifier_symbol_box = layout_visible_classifier_get_symbol_box_const ( visible_classifier ); const geometry_rectangle_t *const classifier_space = layout_visible_classifier_get_space_const ( visible_classifier ); if ( geometry_rectangle_contains( classifier_symbol_box, x, y ) ) { if ( geometry_rectangle_contains( classifier_space, x, y ) ) { /* surrounding classifier is found. select it if it is the smallest found area */ const double current_classifier_area = geometry_rectangle_get_area( classifier_space ); if ( current_classifier_area < surrounding_classifier_area ) { surrounding_classifier_area = current_classifier_area; data_id_pair_reinit_by_table_and_id ( out_surrounding_id, DATA_TABLE_DIAGRAMELEMENT, layout_visible_classifier_get_diagramelement_id( visible_classifier ), DATA_TABLE_CLASSIFIER, layout_visible_classifier_get_classifier_id( visible_classifier ) ); } } else { /* classifier is found */ data_id_pair_reinit_by_table_and_id ( out_selected_id, DATA_TABLE_DIAGRAMELEMENT, layout_visible_classifier_get_diagramelement_id( visible_classifier ), DATA_TABLE_CLASSIFIER, layout_visible_classifier_get_classifier_id( visible_classifier ) ); result = PENCIL_ERROR_NONE; } } } } TRACE_END_ERR( result ); return result; } pencil_error_t pencil_layouter_private_get_feature_id_at_pos ( const pencil_layouter_t *this_, double x, double y, pencil_type_filter_t filter, data_id_pair_t* out_selected_id, data_id_pair_t* out_surrounding_id ) { TRACE_BEGIN(); assert( NULL != out_selected_id ); assert( NULL != out_surrounding_id ); pencil_error_t result = PENCIL_ERROR_OUT_OF_BOUNDS; /* check all contained features */ const uint32_t f_count = pencil_layout_data_get_feature_count( &((*this_).layout_data) ); for ( uint32_t f_idx = 0; f_idx < f_count; f_idx ++ ) { const layout_feature_t *const the_feature = pencil_layout_data_get_feature_const ( &((*this_).layout_data), f_idx ); const geometry_rectangle_t *const feature_symbol_box = layout_feature_get_symbol_box_const ( the_feature ); if ( geometry_rectangle_contains( feature_symbol_box, x, y ) ) { /* feature is found */ const data_feature_t *const data_feature = layout_feature_get_data_const ( the_feature ); const layout_visible_classifier_t *const layout_classifier = layout_feature_get_classifier_const ( the_feature ); if (( PENCIL_TYPE_FILTER_LIFELINE == filter ) &&( DATA_FEATURE_TYPE_LIFELINE == data_feature_get_main_type( data_feature ) )) { data_id_pair_reinit_by_table_and_id ( out_selected_id, DATA_TABLE_DIAGRAMELEMENT, layout_visible_classifier_get_diagramelement_id( layout_classifier ), DATA_TABLE_CLASSIFIER, layout_visible_classifier_get_classifier_id( layout_classifier ) ); } else { data_id_pair_reinit_by_table_and_id ( out_selected_id, DATA_TABLE_FEATURE, layout_feature_get_feature_id( the_feature ), DATA_TABLE_CLASSIFIER, data_feature_get_classifier_row_id( data_feature ) ); } data_id_pair_reinit_by_table_and_id ( out_surrounding_id, DATA_TABLE_DIAGRAMELEMENT, layout_visible_classifier_get_diagramelement_id( layout_classifier ), DATA_TABLE_CLASSIFIER, layout_visible_classifier_get_classifier_id( layout_classifier ) ); result = PENCIL_ERROR_NONE; } } TRACE_END_ERR( result ); return result; } pencil_error_t pencil_layouter_private_get_relationship_id_at_pos ( const pencil_layouter_t *this_, double x, double y, double snap_distance, data_id_pair_t* out_selected_id ) { TRACE_BEGIN(); assert( NULL != out_selected_id ); pencil_error_t result = PENCIL_ERROR_OUT_OF_BOUNDS; const uint32_t count_relations = pencil_layout_data_get_relationship_count ( &((*this_).layout_data) ); uint32_t matching_relations_found = 0; for ( uint32_t rel_index = 0; rel_index < count_relations; rel_index ++ ) { const layout_relationship_t *const the_relationship = pencil_layout_data_get_relationship_const( &((*this_).layout_data), rel_index ); const geometry_connector_t *const relationship_shape = layout_relationship_get_shape_const( the_relationship ); if ( geometry_connector_is_close( relationship_shape, x, y, snap_distance ) ) { /* ensure that every relation at that location can be selected by small mouse movements */ if ( ((uint32_t)(x+y))%(matching_relations_found+1) == 0 ) { const layout_relationship_t *current_relation; current_relation = pencil_layout_data_get_relationship_const ( &((*this_).layout_data), rel_index ); const data_relationship_t *relation_data; relation_data = layout_relationship_get_data_const( current_relation ); data_id_pair_reinit_by_table_and_id ( out_selected_id, DATA_TABLE_RELATIONSHIP, data_relationship_get_row_id( relation_data ), DATA_TABLE_VOID, DATA_ROW_ID_VOID ); result = PENCIL_ERROR_NONE; } matching_relations_found ++; } } TRACE_END_ERR( result ); return result; } pencil_error_t pencil_layouter_get_classifier_order_at_pos ( const pencil_layouter_t *this_, data_classifier_type_t c_type, double x, double y, double snap_distance, layout_order_t* out_layout_order ) { TRACE_BEGIN(); assert ( NULL != out_layout_order ); pencil_error_t result = PENCIL_ERROR_NONE; /* get the bounding box of the diagram */ const layout_diagram_t *const the_diagram = pencil_layout_data_get_diagram_const( &((*this_).layout_data) ); const geometry_rectangle_t *const diagram_bounds = layout_diagram_get_bounds_const( the_diagram ); const geometry_rectangle_t *const diagram_draw_area = layout_diagram_get_draw_area_const( the_diagram ); /* get the diagram type */ const data_diagram_t *const diagram_data = layout_diagram_get_data_const ( the_diagram ); const data_diagram_type_t diag_type = data_diagram_get_diagram_type ( diagram_data ); /* get the classifier type */ const bool scenario_semantics = data_rules_classifier_has_scenario_semantics( &((*this_).rules), diag_type, c_type ); if ( ! geometry_rectangle_contains( diagram_bounds, x, y ) ) { layout_order_init_empty( out_layout_order ); result = PENCIL_ERROR_OUT_OF_BOUNDS; } else { if ((( DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM == diag_type )&& scenario_semantics) || (( DATA_DIAGRAM_TYPE_UML_TIMING_DIAGRAM == diag_type)&&( ! scenario_semantics))) { /* classifiers are a horizontal list */ const double draw_left = geometry_rectangle_get_left(diagram_draw_area); const double draw_right = geometry_rectangle_get_right(diagram_draw_area); int32_t list_order; if ( x <= draw_left ) { list_order = INT32_MIN; } else if ( x >= draw_right ) { list_order = INT32_MAX; } else { list_order = ((uint32_t)(( x - draw_left ) / ( draw_right - draw_left ) * UINT32_MAX)); list_order += INT32_MIN; } layout_order_init_list( out_layout_order, list_order ); } else if ((( DATA_DIAGRAM_TYPE_UML_TIMING_DIAGRAM == diag_type )&& scenario_semantics) || ( DATA_DIAGRAM_TYPE_LIST == diag_type ) || (( DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM == diag_type)&&( ! scenario_semantics))) { /* classifiers are a vertical list */ const double draw_top = geometry_rectangle_get_top(diagram_draw_area); const double draw_bottom = geometry_rectangle_get_bottom(diagram_draw_area); int32_t list_order; if ( y <= draw_top ) { list_order = INT32_MIN; } else if ( y >= draw_bottom ) { list_order = INT32_MAX; } else { list_order = ((uint32_t)(( y - draw_top ) / ( draw_bottom - draw_top ) * UINT32_MAX)); list_order += INT32_MIN; } layout_order_init_list( out_layout_order, list_order ); } else { /* classifiers are x/y arranged */ const int32_t x_order = geometry_non_linear_scale_get_order( &((*this_).x_scale), x, snap_distance ); const int32_t y_order = geometry_non_linear_scale_get_order( &((*this_).y_scale), y, snap_distance ); layout_order_init_x_y( out_layout_order, x_order, y_order ); } } TRACE_END_ERR( result ); return result; } pencil_error_t pencil_layouter_get_feature_order_at_pos ( const pencil_layouter_t *this_, const data_feature_t *feature_ptr, double x, double y, layout_order_t* out_layout_order ) { TRACE_BEGIN(); assert ( NULL != out_layout_order ); assert ( NULL != feature_ptr ); pencil_error_t result = PENCIL_ERROR_NONE; /* get data of feature */ data_row_id_t parent_classifier_id; data_feature_type_t feature_type; feature_type = data_feature_get_main_type ( feature_ptr ); parent_classifier_id = data_feature_get_classifier_row_id ( feature_ptr ); /* get the bounding box of the diagram */ const layout_diagram_t *const the_diagram = pencil_layout_data_get_diagram_const( &((*this_).layout_data) ); const geometry_rectangle_t *const diagram_bounds = layout_diagram_get_bounds_const( the_diagram ); if ( ! geometry_rectangle_contains( diagram_bounds, x, y ) ) { layout_order_init_empty( out_layout_order ); result = PENCIL_ERROR_OUT_OF_BOUNDS; } else if ( DATA_ROW_ID_VOID == parent_classifier_id ) { TSLOG_WARNING( "feature to move has no parent classifier!" ); layout_order_init_empty( out_layout_order ); result = PENCIL_ERROR_UNKNOWN_OBJECT; } else { /* iterate over all classifiers, search the closest_parent_instance */ const layout_visible_classifier_t *closest_parent_instance = NULL; const uint32_t classfy_count = pencil_layout_data_get_visible_classifier_count ( &((*this_).layout_data) ); for ( uint32_t classfy_index = 0; classfy_index < classfy_count; classfy_index ++ ) { const layout_visible_classifier_t *const visible_classifier = pencil_layout_data_get_visible_classifier_const ( &((*this_).layout_data), classfy_index ); const data_row_id_t classfy_id = layout_visible_classifier_get_classifier_id ( visible_classifier ); if ( parent_classifier_id == classfy_id ) { if ( NULL == closest_parent_instance ) { closest_parent_instance = visible_classifier; } else { const geometry_rectangle_t *const classfier_symbol_box = layout_visible_classifier_get_symbol_box_const ( visible_classifier ); const geometry_rectangle_t *const closest_parent_symbol_box = layout_visible_classifier_get_symbol_box_const ( closest_parent_instance ); const double classfy_distance = geometry_rectangle_calc_chess_distance( classfier_symbol_box, x, y ); const double closest_parent_distance = geometry_rectangle_calc_chess_distance( closest_parent_symbol_box, x, y ); if ( classfy_distance < closest_parent_distance ) { closest_parent_instance = visible_classifier; } } } } if ( NULL != closest_parent_instance ) { switch (feature_type) { case DATA_FEATURE_TYPE_PROPERTY: /* or */ case DATA_FEATURE_TYPE_OPERATION: { int32_t max_order_above = INT32_MIN; int32_t min_order_below = INT32_MAX; /* iterate over all contained features */ const uint32_t f_count = pencil_layout_data_get_feature_count( &((*this_).layout_data) ); for ( uint32_t f_idx = 0; f_idx < f_count; f_idx ++ ) { /* check if feature belongs to same parent classifier */ const layout_feature_t *const the_feature = pencil_layout_data_get_feature_const ( &((*this_).layout_data), f_idx ); const layout_visible_classifier_t *const vis_classfy = layout_feature_get_classifier_const ( the_feature ); if ( closest_parent_instance == vis_classfy ) { /* check if feature is not the moved one */ const data_feature_t *const data_feature = layout_feature_get_data_const ( the_feature ); if ( data_feature_get_row_id ( feature_ptr ) != data_feature_get_row_id ( data_feature ) ) { const int32_t list_order = data_feature_get_list_order( data_feature ); const geometry_rectangle_t *const feature_symbol_box = layout_feature_get_symbol_box_const ( the_feature ); if ( y < geometry_rectangle_get_center_y( feature_symbol_box ) ) { if ( list_order < min_order_below ) { min_order_below = list_order; } } else { if ( list_order > max_order_above ) { max_order_above = list_order; } } } } } if ( max_order_above == INT32_MIN ) { if ( min_order_below == INT32_MAX ) { /* nothing above, nothing below */ layout_order_init_list( out_layout_order, 0 ); } else { /* nothing above */ layout_order_init_list( out_layout_order, min_order_below - 32768 ); } } else { if ( min_order_below == INT32_MAX ) { /* nothing below */ layout_order_init_list( out_layout_order, max_order_above + 32768 ); } else { /* regular interval */ layout_order_init_list( out_layout_order, (max_order_above + min_order_below)/2 ); } } } break; case DATA_FEATURE_TYPE_PORT: /* or */ case DATA_FEATURE_TYPE_PROVIDED_INTERFACE: /* or */ case DATA_FEATURE_TYPE_REQUIRED_INTERFACE: /* or */ case DATA_FEATURE_TYPE_IN_PORT_PIN: /* or */ case DATA_FEATURE_TYPE_OUT_PORT_PIN: /* or */ case DATA_FEATURE_TYPE_ENTRY: /* or */ case DATA_FEATURE_TYPE_EXIT: { const geometry_rectangle_t *const closest_parent_symbol_box = layout_visible_classifier_get_symbol_box_const ( closest_parent_instance ); const double center_x = geometry_rectangle_get_center_x( closest_parent_symbol_box ); const double center_y = geometry_rectangle_get_center_y( closest_parent_symbol_box ); const double width = geometry_rectangle_get_width( closest_parent_symbol_box ); const double height = geometry_rectangle_get_height( closest_parent_symbol_box ); const double delta_x = x - center_x; const double delty_y = y - center_y; const double relative_delta_x = delta_x * height; const double relative_delta_y = delty_y * width; const double distance_x = ( x < center_x ) ? (center_x - x) : (x - center_x); const double distance_y = ( y < center_y ) ? (center_y - y) : (y - center_y); const double relative_dist_x = distance_x * height; const double relative_dist_y = distance_y * width; int32_t order; if ( relative_dist_x > relative_dist_y ) { if ( x < center_x ) { /* x,y is on left side, order is between 0 and INT32_MAX/2 */ order = INT32_MAX*(relative_delta_y/(relative_dist_x+0.1)*0.25+0.25); } else { /* x,y is on right side, order is between INT32_MIN and INT32_MIN/2 */ order = INT32_MIN*(relative_delta_y/(relative_dist_x+0.1)*0.25+0.75); } } else { if ( y < center_y ) { /* x,y is on upper side, order is between INT32_MIN/2 and 0 */ order = INT32_MIN*(relative_delta_x/(relative_dist_y+0.1)*0.25+0.25); } else { /* x,y is on lower side, order is between INT32_MAX/2 and INT32_MAX */ order = INT32_MAX*(relative_delta_x/(relative_dist_y+0.1)*0.25+0.75); } } layout_order_init_list( out_layout_order, order ); } break; case DATA_FEATURE_TYPE_LIFELINE: { TRACE_INFO( "feature to move is a lifeline and therefore cannot move." ); layout_order_init_empty( out_layout_order ); result = PENCIL_ERROR_UNKNOWN_OBJECT; } break; default: { TSLOG_WARNING( "feature to move has illegal/unknown type!" ); layout_order_init_empty( out_layout_order ); result = PENCIL_ERROR_UNKNOWN_OBJECT; } break; } } else { TSLOG_WARNING( "parent classifier of feature is not visible; possibly array size too small?" ); layout_order_init_empty( out_layout_order ); result = PENCIL_ERROR_UNKNOWN_OBJECT; } } TRACE_END_ERR( result ); return result; } pencil_error_t pencil_layouter_get_relationship_order_at_pos ( const pencil_layouter_t *this_, double x, double y, layout_order_t* out_layout_order ) { TRACE_BEGIN(); assert ( NULL != out_layout_order ); pencil_error_t result = PENCIL_ERROR_NONE; /* get the bounding box of the diagram */ const layout_diagram_t *const the_diagram = pencil_layout_data_get_diagram_const( &((*this_).layout_data) ); const geometry_rectangle_t *const diagram_bounds = layout_diagram_get_bounds_const( the_diagram ); const geometry_rectangle_t *const diagram_draw_area = layout_diagram_get_draw_area_const( the_diagram ); /* get the diagram type */ const data_diagram_t *const diagram_data = layout_diagram_get_data_const ( the_diagram ); const data_diagram_type_t diag_type = data_diagram_get_diagram_type ( diagram_data ); if ( ! geometry_rectangle_contains( diagram_bounds, x, y ) ) { layout_order_init_empty( out_layout_order ); result = PENCIL_ERROR_OUT_OF_BOUNDS; } else { if (( DATA_DIAGRAM_TYPE_BOX_DIAGRAM == diag_type ) || ( DATA_DIAGRAM_TYPE_LIST == diag_type )) { /* relationships are hidden in lists and box-diagrams */ layout_order_init_empty( out_layout_order ); result = PENCIL_ERROR_OUT_OF_BOUNDS; } else if (( DATA_DIAGRAM_TYPE_UML_COMMUNICATION_DIAGRAM == diag_type )||( DATA_DIAGRAM_TYPE_INTERACTION_OVERVIEW_DIAGRAM == diag_type )) { /* communication diagrams and interaction overview diagrams do not care about list_orders of relationships */ layout_order_init_empty( out_layout_order ); } else if ( DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM == diag_type ) { const double draw_top = geometry_rectangle_get_top(diagram_draw_area); const double draw_bottom = geometry_rectangle_get_bottom(diagram_draw_area); int32_t list_order; if ( y <= draw_top ) { list_order = INT32_MIN; } else if ( y >= draw_bottom ) { list_order = INT32_MAX; } else { list_order = ((uint32_t)(( y - draw_top ) / ( draw_bottom - draw_top ) * UINT32_MAX)); list_order += INT32_MIN; } layout_order_init_list( out_layout_order, list_order ); } else if ( DATA_DIAGRAM_TYPE_UML_TIMING_DIAGRAM == diag_type ) { const double draw_left = geometry_rectangle_get_left(diagram_draw_area); const double draw_right = geometry_rectangle_get_right(diagram_draw_area); int32_t list_order; if ( x <= draw_left ) { list_order = INT32_MIN; } else if ( x >= draw_right ) { list_order = INT32_MAX; } else { list_order = ((uint32_t)(( x - draw_left ) / ( draw_right - draw_left ) * UINT32_MAX)); list_order += INT32_MIN; } layout_order_init_list( out_layout_order, list_order ); } else { /* all other diagram types do not care about list_orders of relationships */ layout_order_init_empty( out_layout_order ); } } TRACE_END_ERR( result ); return result; } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/pencil_marker.c000066400000000000000000000136271415120503000226650ustar00rootroot00000000000000/* File: pencil_marker.c; Copyright and License: see below */ #include "pencil_marker.h" #include "trace.h" #include #include #include #include void pencil_marker_init( pencil_marker_t *this_ ) { TRACE_BEGIN(); TRACE_END(); } void pencil_marker_destroy( pencil_marker_t *this_ ) { TRACE_BEGIN(); TRACE_END(); } void pencil_marker_mark_focused_rectangle ( const pencil_marker_t *this_, geometry_rectangle_t rect, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != cr ); static const double YELLOW_BOX_SIZE = 8.0; static const double TOTAL_SIZE = 9.0; static const double LINE_WIDTH = 1.0; static const double GAP = 1.0; const double left = floor(geometry_rectangle_get_left ( &rect )); /* floor needed to position on pixel boundary*/ const double top = floor(geometry_rectangle_get_top ( &rect )); const double right = floor(geometry_rectangle_get_right ( &rect )); const double bottom = floor(geometry_rectangle_get_bottom ( &rect )); /* gray lines */ cairo_set_source_rgba( cr, 0.55, 0.55, 0.55, 1.0 ); cairo_rectangle ( cr, left-GAP-LINE_WIDTH, top-GAP-TOTAL_SIZE, LINE_WIDTH, YELLOW_BOX_SIZE ); cairo_rectangle ( cr, left-GAP-TOTAL_SIZE, top-GAP-LINE_WIDTH, TOTAL_SIZE, LINE_WIDTH ); cairo_fill (cr); cairo_rectangle ( cr, right+GAP, top-GAP-TOTAL_SIZE, LINE_WIDTH, YELLOW_BOX_SIZE ); cairo_rectangle ( cr, right+GAP, top-GAP-LINE_WIDTH, TOTAL_SIZE, LINE_WIDTH ); cairo_fill (cr); cairo_rectangle ( cr, right+GAP, bottom+GAP+LINE_WIDTH, LINE_WIDTH, YELLOW_BOX_SIZE ); cairo_rectangle ( cr, right+GAP, bottom+GAP, TOTAL_SIZE, LINE_WIDTH ); cairo_fill (cr); cairo_rectangle ( cr, left-GAP-LINE_WIDTH, bottom+GAP+LINE_WIDTH, LINE_WIDTH, YELLOW_BOX_SIZE ); cairo_rectangle ( cr, left-GAP-TOTAL_SIZE, bottom+GAP, TOTAL_SIZE, LINE_WIDTH ); cairo_fill (cr); /* yellow box */ cairo_set_source_rgba( cr, 0.95, 1.0, 0.0, 1.0 ); cairo_rectangle ( cr, left-GAP-TOTAL_SIZE, top-GAP-TOTAL_SIZE, YELLOW_BOX_SIZE, YELLOW_BOX_SIZE ); cairo_fill (cr); cairo_rectangle ( cr, right+GAP+LINE_WIDTH, top-GAP-TOTAL_SIZE, YELLOW_BOX_SIZE, YELLOW_BOX_SIZE ); cairo_fill (cr); cairo_rectangle ( cr, left-GAP-TOTAL_SIZE, bottom+GAP+LINE_WIDTH, YELLOW_BOX_SIZE, YELLOW_BOX_SIZE ); cairo_fill (cr); cairo_rectangle ( cr, right+GAP+LINE_WIDTH, bottom+GAP+LINE_WIDTH, YELLOW_BOX_SIZE, YELLOW_BOX_SIZE ); cairo_fill (cr); TRACE_END(); } void pencil_marker_mark_selected_rectangle ( const pencil_marker_t *this_, geometry_rectangle_t rect, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != cr ); static const double EXPAND_OVER_BORDER = 2.0; static const double INNER_EDGE = 8.0; const double left = floor(geometry_rectangle_get_left ( &rect )); /* floor needed to position on pixel boundary*/ const double top = floor(geometry_rectangle_get_top ( &rect )); const double right = floor(geometry_rectangle_get_right ( &rect )); const double bottom = floor(geometry_rectangle_get_bottom ( &rect )); cairo_set_source_rgba( cr, 1.0, 0.3, 0.8, 1.0 ); cairo_move_to( cr, left+INNER_EDGE, top-EXPAND_OVER_BORDER ); cairo_line_to( cr, left-EXPAND_OVER_BORDER, top-EXPAND_OVER_BORDER ); cairo_line_to( cr, left-EXPAND_OVER_BORDER, top+INNER_EDGE ); cairo_close_path( cr ); cairo_fill (cr); cairo_move_to( cr, right-INNER_EDGE, top-EXPAND_OVER_BORDER ); cairo_line_to( cr, right+EXPAND_OVER_BORDER, top-EXPAND_OVER_BORDER ); cairo_line_to( cr, right+EXPAND_OVER_BORDER, top+INNER_EDGE ); cairo_close_path( cr ); cairo_fill (cr); cairo_move_to( cr, right-INNER_EDGE, bottom+EXPAND_OVER_BORDER ); cairo_line_to( cr, right+EXPAND_OVER_BORDER, bottom+EXPAND_OVER_BORDER ); cairo_line_to( cr, right+EXPAND_OVER_BORDER, bottom-INNER_EDGE ); cairo_close_path( cr ); cairo_fill (cr); cairo_move_to( cr, left-EXPAND_OVER_BORDER, bottom-INNER_EDGE ); cairo_line_to( cr, left-EXPAND_OVER_BORDER, bottom+EXPAND_OVER_BORDER ); cairo_line_to( cr, left+INNER_EDGE, bottom+EXPAND_OVER_BORDER ); cairo_close_path( cr ); cairo_fill (cr); const double width = right-left; static const double LINE_LENGTH = 16.0; static const double LINE_WIDTH = 1.0; if ( width > 2.0*EXPAND_OVER_BORDER + LINE_LENGTH ) { cairo_rectangle ( cr, left, bottom + EXPAND_OVER_BORDER - LINE_WIDTH, LINE_LENGTH, LINE_WIDTH ); cairo_rectangle ( cr, right - LINE_LENGTH, bottom + EXPAND_OVER_BORDER - LINE_WIDTH, LINE_LENGTH, LINE_WIDTH ); cairo_fill (cr); cairo_rectangle ( cr, left, top - EXPAND_OVER_BORDER, LINE_LENGTH, LINE_WIDTH ); cairo_rectangle ( cr, right - LINE_LENGTH, top - EXPAND_OVER_BORDER, LINE_LENGTH, LINE_WIDTH ); cairo_fill (cr); } const double height = bottom-top; if ( height > 2.0*EXPAND_OVER_BORDER + LINE_LENGTH ) { cairo_rectangle ( cr, left - EXPAND_OVER_BORDER, top, LINE_WIDTH, LINE_LENGTH ); cairo_rectangle ( cr, left - EXPAND_OVER_BORDER, bottom - LINE_LENGTH, LINE_WIDTH, LINE_LENGTH ); cairo_fill (cr); cairo_rectangle ( cr, right + EXPAND_OVER_BORDER - LINE_WIDTH, top, LINE_WIDTH, LINE_LENGTH ); cairo_rectangle ( cr, right + EXPAND_OVER_BORDER - LINE_WIDTH, bottom - LINE_LENGTH, LINE_WIDTH, LINE_LENGTH ); cairo_fill (cr); } TRACE_END(); } /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/pencil_rel_label_layouter.c000066400000000000000000000461351415120503000252510ustar00rootroot00000000000000/* File: pencil_rel_label_layouter.c; Copyright and License: see below */ #include "pencil_rel_label_layouter.h" #include "util/geometry/geometry_point.h" #include "util/geometry/geometry_direction.h" #include "trace.h" #include "util/string/utf8string.h" void pencil_rel_label_layouter_init( pencil_rel_label_layouter_t *this_, pencil_layout_data_t *layout_data, pencil_size_t *pencil_size ) { TRACE_BEGIN(); assert( NULL != layout_data ); assert( NULL != pencil_size ); (*this_).layout_data = layout_data; (*this_).pencil_size = pencil_size; draw_relationship_label_init( &((*this_).draw_relationship_label) ); pencil_label_layout_helper_init ( &((*this_).label_layout_helper) ); TRACE_END(); } void pencil_rel_label_layouter_destroy( pencil_rel_label_layouter_t *this_ ) { TRACE_BEGIN(); pencil_label_layout_helper_destroy ( &((*this_).label_layout_helper) ); draw_relationship_label_destroy( &((*this_).draw_relationship_label) ); TRACE_END(); } void pencil_rel_label_layouter_do_layout ( pencil_rel_label_layouter_t *this_, PangoLayout *font_layout ) { TRACE_BEGIN(); assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS ); assert( NULL != font_layout ); universal_array_index_sorter_t sorted; universal_array_index_sorter_init( &sorted ); /* sort the relationships by their label-box layouting needs, drop invisible relations */ pencil_rel_label_layouter_private_propose_processing_order ( this_, &sorted ); /* layout the relationship label-boxes */ const uint32_t count_sorted = universal_array_index_sorter_get_count( &sorted ); for ( uint32_t sort_index = 0; sort_index < count_sorted; sort_index ++ ) { /* determine pointer to relationship */ const uint32_t index = universal_array_index_sorter_get_array_index( &sorted, sort_index ); layout_relationship_t *const current_relation = pencil_layout_data_get_relationship_ptr ( (*this_).layout_data, index ); geometry_point_t relation_middle = layout_relationship_get_middle ( current_relation ); /* declaration of list of options */ uint32_t solutions_count = 0; static const uint32_t SOLUTIONS_MAX = 16; geometry_rectangle_t solution[16]; /* propose options */ pencil_rel_label_layouter_private_propose_solutions ( this_, current_relation, font_layout, SOLUTIONS_MAX, solution, &solutions_count ); /* select best option */ uint32_t index_of_best; if ( 1 == solutions_count ) { index_of_best = 0; } else { pencil_label_layout_helper_select_solution ( &((*this_).label_layout_helper), (*this_).layout_data, relation_middle, solutions_count, solution, &index_of_best ); } /* store best option to (*this_).layout_data */ layout_relationship_set_label_box( current_relation, &(solution[index_of_best]) ); } universal_array_index_sorter_destroy( &sorted ); TRACE_END(); } void pencil_rel_label_layouter_private_propose_processing_order ( pencil_rel_label_layouter_t *this_, universal_array_index_sorter_t *out_sorted ) { TRACE_BEGIN(); assert( NULL != out_sorted ); /* sort the relationships by their label-box: the less simple, the earlier it shall be processed */ const uint32_t count_relations = pencil_layout_data_get_relationship_count ( (*this_).layout_data ); for ( uint32_t index = 0; index < count_relations; index ++ ) { const layout_relationship_t *const current_relation = pencil_layout_data_get_relationship_ptr ( (*this_).layout_data, index ); const data_relationship_t *const relation_data = layout_relationship_get_data_const ( current_relation ); assert( NULL != relation_data ); int64_t simpleness = 0; /* determine simpleness by length of label */ simpleness -= utf8string_get_length( data_relationship_get_name_const( relation_data ) ); /* insert relation to sorted array, the simpler the more to the back */ if (( PENCIL_VISIBILITY_SHOW == layout_relationship_get_visibility ( current_relation ) ) || ( PENCIL_VISIBILITY_GRAY_OUT == layout_relationship_get_visibility ( current_relation ) )) { int insert_error; insert_error = universal_array_index_sorter_insert( out_sorted, index, simpleness ); if ( 0 != insert_error ) { TSLOG_WARNING( "not all relationship label-boxes are layouted" ); } } } TRACE_END(); } void pencil_rel_label_layouter_private_propose_solutions ( pencil_rel_label_layouter_t *this_, layout_relationship_t *current_relation, PangoLayout *font_layout, uint32_t solutions_max, geometry_rectangle_t out_solutions[], uint32_t *out_solutions_count) { TRACE_BEGIN(); assert( NULL != current_relation ); assert( NULL != font_layout ); assert( NULL != out_solutions ); assert( NULL != out_solutions_count ); const data_relationship_t *the_relationship = layout_relationship_get_data_const( current_relation ); { /* determine label dimensions */ double text_width; double text_height; draw_relationship_label_get_type_and_name_dimensions ( &((*this_).draw_relationship_label), the_relationship, (*this_).pencil_size, font_layout, &text_width, &text_height ); /* get layout data */ const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size ); const double object_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size ); /* get connector data */ const geometry_connector_t *const shape = layout_relationship_get_shape_const ( current_relation ); const double source_end_x = geometry_connector_get_source_end_x ( shape ); const double source_end_y = geometry_connector_get_source_end_y ( shape ); const double main_line_source_x = geometry_connector_get_main_line_source_x ( shape ); const double main_line_source_y = geometry_connector_get_main_line_source_y ( shape ); const double main_line_destination_x = geometry_connector_get_main_line_destination_x ( shape ); const double main_line_destination_y = geometry_connector_get_main_line_destination_y ( shape ); const double destination_end_x = geometry_connector_destination_end_x ( shape ); const double destination_end_y = geometry_connector_get_destination_end_y ( shape ); geometry_point_t src_end; geometry_point_t main_src; geometry_point_t main_dst; geometry_point_t dst_end; geometry_point_init ( &src_end, source_end_x, source_end_y ); geometry_point_init ( &main_src, main_line_source_x, main_line_source_y ); geometry_point_init ( &main_dst, main_line_destination_x, main_line_destination_y ); geometry_point_init ( &dst_end, destination_end_x, destination_end_y ); const geometry_direction_t src_dir = geometry_point_get_direction ( &src_end, &main_src ); const geometry_direction_t dst_dir = geometry_point_get_direction ( &main_dst, &dst_end ); geometry_rectangle_t main_line_rect; geometry_rectangle_init_by_corners ( &main_line_rect, main_line_source_x, main_line_source_y, main_line_destination_x, main_line_destination_y ); /* propose solutions */ assert( solutions_max >= 16 ); uint32_t solution_idx = 0; /* there are 0..2 solutions at the src line segment */ if ( geometry_point_calc_chess_distance( &src_end, &main_src ) > object_dist ) { /* this is a noteworthy line segment */ if ( ( src_dir == GEOMETRY_DIRECTION_UP ) || ( src_dir == GEOMETRY_DIRECTION_DOWN ) ) { /* right */ geometry_rectangle_init( &(out_solutions[solution_idx]), main_line_source_x + gap, (source_end_y + main_line_source_y - text_height) / 2.0, text_width, text_height ); solution_idx ++; /* left */ geometry_rectangle_init( &(out_solutions[solution_idx]), main_line_source_x - text_width - gap, (source_end_y + main_line_source_y - text_height) / 2.0, text_width, text_height ); solution_idx ++; } else { /* down */ geometry_rectangle_init( &(out_solutions[solution_idx]), (source_end_x + main_line_source_x - text_width) / 2.0, main_line_source_y + gap, text_width, text_height ); solution_idx ++; /* up */ geometry_rectangle_init( &(out_solutions[solution_idx]), (source_end_x + main_line_source_x - text_width) / 2.0, main_line_source_y - text_height - gap, text_width, text_height ); solution_idx ++; } } /* there are 4 solutions at the main line segment */ { /* left */ geometry_rectangle_init( &(out_solutions[solution_idx]), geometry_rectangle_get_left(&main_line_rect) - text_width - gap, (main_line_source_y + main_line_destination_y - text_height) / 2.0, text_width, text_height ); solution_idx ++; /* right */ geometry_rectangle_init( &(out_solutions[solution_idx]), geometry_rectangle_get_right(&main_line_rect) + gap, (main_line_source_y + main_line_destination_y - text_height) / 2.0, text_width, text_height ); solution_idx ++; /* up */ geometry_rectangle_init( &(out_solutions[solution_idx]), (main_line_source_x + main_line_destination_x - text_width) / 2.0, geometry_rectangle_get_top(&main_line_rect) - text_height - gap, text_width, text_height ); solution_idx ++; /* down */ geometry_rectangle_init( &(out_solutions[solution_idx]), (main_line_source_x + main_line_destination_x - text_width) / 2.0, geometry_rectangle_get_bottom(&main_line_rect) + gap, text_width, text_height ); solution_idx ++; } /* there are 0..2 solutions at the dst line segment */ if ( geometry_point_calc_chess_distance( &main_dst, &dst_end ) > object_dist ) { /* this is a noteworthy line segment */ if ( ( dst_dir == GEOMETRY_DIRECTION_UP ) || ( dst_dir == GEOMETRY_DIRECTION_DOWN ) ) { /* right */ geometry_rectangle_init( &(out_solutions[solution_idx]), main_line_destination_x + gap, (destination_end_y + main_line_destination_y - text_height) / 2.0, text_width, text_height ); solution_idx ++; /* left */ geometry_rectangle_init( &(out_solutions[solution_idx]), main_line_destination_x - text_width - gap, (destination_end_y + main_line_destination_y - text_height) / 2.0, text_width, text_height ); solution_idx ++; } else { /* down */ geometry_rectangle_init( &(out_solutions[solution_idx]), (destination_end_x + main_line_destination_x - text_width) / 2.0, main_line_destination_y + gap, text_width, text_height ); solution_idx ++; /* up */ geometry_rectangle_init( &(out_solutions[solution_idx]), (destination_end_x + main_line_destination_x - text_width) / 2.0, main_line_destination_y - text_height - gap, text_width, text_height ); solution_idx ++; } } /* 0..4 at main line source if source end line exists */ if ( src_dir != GEOMETRY_DIRECTION_CENTER ) { geometry_rectangle_init( &(out_solutions[solution_idx]), main_line_source_x - text_width - gap, main_line_source_y - text_height - gap, text_width, text_height ); solution_idx ++; geometry_rectangle_init( &(out_solutions[solution_idx]), main_line_source_x - text_width - gap, main_line_source_y + gap, text_width, text_height ); solution_idx ++; geometry_rectangle_init( &(out_solutions[solution_idx]), main_line_source_x + gap, main_line_source_y - text_height - gap, text_width, text_height ); solution_idx ++; geometry_rectangle_init( &(out_solutions[solution_idx]), main_line_source_x + gap, main_line_source_y + gap, text_width, text_height ); solution_idx ++; } /* 0..4 at main line destination if destination end line exists */ if ( dst_dir != GEOMETRY_DIRECTION_CENTER ) { geometry_rectangle_init( &(out_solutions[solution_idx]), main_line_destination_x - text_width - gap, main_line_destination_y - text_height - gap, text_width, text_height ); solution_idx ++; geometry_rectangle_init( &(out_solutions[solution_idx]), main_line_destination_x - text_width - gap, main_line_destination_y + gap, text_width, text_height ); solution_idx ++; geometry_rectangle_init( &(out_solutions[solution_idx]), main_line_destination_x + gap, main_line_destination_y - text_height - gap, text_width, text_height ); solution_idx ++; geometry_rectangle_init( &(out_solutions[solution_idx]), main_line_destination_x + gap, main_line_destination_y + gap, text_width, text_height ); solution_idx ++; } assert( solution_idx > 0 ); assert( solution_idx <= solutions_max ); *out_solutions_count = solution_idx; } TRACE_END(); } /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/pencil_relationship_layouter.c000066400000000000000000001707151415120503000260330ustar00rootroot00000000000000/* File: pencil_relationship_layouter.c; Copyright and License: see below */ #include "pencil_relationship_layouter.h" #include "trace.h" #include #include #include #include #include void pencil_relationship_layouter_init( pencil_relationship_layouter_t *this_, pencil_layout_data_t *layout_data, pencil_size_t *pencil_size ) { TRACE_BEGIN(); assert( NULL != layout_data ); assert( NULL != pencil_size ); (*this_).layout_data = layout_data; (*this_).pencil_size = pencil_size; pencil_relationship_painter_init( &((*this_).relationship_painter) ); TRACE_END(); } void pencil_relationship_layouter_destroy( pencil_relationship_layouter_t *this_ ) { TRACE_BEGIN(); pencil_relationship_painter_destroy( &((*this_).relationship_painter) ); TRACE_END(); } void pencil_relationship_layouter_private_do_layout ( pencil_relationship_layouter_t *this_ ) { TRACE_BEGIN(); assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS ); universal_array_index_sorter_t sorted; universal_array_index_sorter_init( &sorted ); /* sort the relationships by their movement-needs, drop invisible relations */ pencil_relationship_layouter_private_propose_processing_order ( this_, &sorted ); /* shape the relationships */ const uint32_t count_sorted = universal_array_index_sorter_get_count( &sorted ); for ( uint32_t sort_index = 0; sort_index < count_sorted; sort_index ++ ) { /* determine pointer to the_relationship */ const uint32_t index = universal_array_index_sorter_get_array_index( &sorted, sort_index ); layout_relationship_t *const current_relationship = pencil_layout_data_get_relationship_ptr( (*this_).layout_data, index ); /* declaration of list of options */ uint32_t solutions_count = 0; static const uint32_t SOLUTIONS_MAX = 8; geometry_connector_t solution[8]; /* propose options */ pencil_relationship_layouter_private_propose_solutions ( this_, &sorted, sort_index, SOLUTIONS_MAX, solution, &solutions_count ); /* select best option */ uint32_t index_of_best; if ( 1 == solutions_count ) { index_of_best = 0; } else { pencil_relationship_layouter_private_select_solution ( this_, &sorted, sort_index, solutions_count, solution, &index_of_best ); } /* store best option to (*this_).layout_data */ layout_relationship_set_shape( current_relationship, &(solution[index_of_best]) ); } universal_array_index_sorter_destroy( &sorted ); TRACE_END(); } void pencil_relationship_layouter_private_propose_processing_order ( pencil_relationship_layouter_t *this_, universal_array_index_sorter_t *out_sorted ) { TRACE_BEGIN(); assert ( NULL != out_sorted ); assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) DATA_VISIBLE_SET_MAX_RELATIONSHIPS ); /* get draw area */ const layout_diagram_t *const diagram_layout = pencil_layout_data_get_diagram_ptr( (*this_).layout_data ); const geometry_rectangle_t *const diagram_draw_area = layout_diagram_get_draw_area_const( diagram_layout ); /* sort the relationships by their shaping-needs: the less simple, the earlier it shall be processed */ const uint32_t count_relations = pencil_layout_data_get_relationship_count ( (*this_).layout_data ); for ( uint32_t index = 0; index < count_relations; index ++ ) { layout_relationship_t *const current_relation = pencil_layout_data_get_relationship_ptr ( (*this_).layout_data, index ); int64_t simpleness = 0; /* determine simpleness by relationship type */ { data_relationship_type_t reltype; reltype = data_relationship_get_main_type( layout_relationship_get_data_const ( current_relation )); if (( DATA_RELATIONSHIP_TYPE_UML_DEPENDENCY == reltype ) ||( DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT == reltype )) { /* containment may be solved by embracing, mere dependencies are unimportant */ simpleness += geometry_rectangle_get_width ( diagram_draw_area ); } } /* whatever is not visible is simple */ { if (( PENCIL_VISIBILITY_SHOW != layout_relationship_get_visibility ( current_relation ) ) && ( PENCIL_VISIBILITY_GRAY_OUT != layout_relationship_get_visibility ( current_relation ) )) { simpleness += 2 * geometry_rectangle_get_width ( diagram_draw_area ); } } /* determine simpleness by distance between source and destination */ { const geometry_rectangle_t *const source_rect = layout_relationship_get_from_symbol_box_const ( current_relation ); const geometry_rectangle_t *const dest_rect = layout_relationship_get_to_symbol_box_const ( current_relation ); simpleness -= fabs ( geometry_rectangle_get_center_x(source_rect) - geometry_rectangle_get_center_x(dest_rect) ); simpleness -= fabs ( geometry_rectangle_get_center_y(source_rect) - geometry_rectangle_get_center_y(dest_rect) ); } /* insert relation to sorted array, the simpler the more to the back */ { int insert_error; insert_error = universal_array_index_sorter_insert( out_sorted, index, simpleness ); if ( 0 != insert_error ) { TSLOG_WARNING( "not all relationships are shaped" ); } } } TRACE_END(); } void pencil_relationship_layouter_private_propose_solutions ( pencil_relationship_layouter_t *this_, const universal_array_index_sorter_t *sorted, uint32_t sort_index, uint32_t solutions_max, geometry_connector_t out_solutions[], uint32_t *out_solutions_count ) { TRACE_BEGIN(); assert ( NULL != sorted ); assert ( universal_array_index_sorter_get_count( sorted ) > sort_index ); assert ( NULL != out_solutions ); assert ( NULL != out_solutions_count ); assert ( 1 <= solutions_max ); /* general requirement to report at least one option */ assert ( 8 <= solutions_max ); /* current implementation requires at least 8 options */ /* get current relation */ const uint32_t index = universal_array_index_sorter_get_array_index( sorted, sort_index ); layout_relationship_t *const current_relation = pencil_layout_data_get_relationship_ptr ( (*this_).layout_data, index ); /* propose connections between source and destination */ { const geometry_rectangle_t *const source_rect = layout_relationship_get_from_symbol_box_const ( current_relation ); const geometry_rectangle_t *const dest_rect = layout_relationship_get_to_symbol_box_const ( current_relation ); uint32_t solutions_by_ZN; uint32_t solutions_by_L7; uint32_t solutions_by_UC; pencil_relationship_layouter_private_connect_rectangles_by_ZN ( this_, source_rect, dest_rect, solutions_max, &(out_solutions[0]), &solutions_by_ZN ); pencil_relationship_layouter_private_connect_rectangles_by_L7 ( this_, source_rect, dest_rect, solutions_max - solutions_by_ZN, &(out_solutions[solutions_by_ZN]), &solutions_by_L7 ); pencil_relationship_layouter_private_connect_rectangles_by_UC ( this_, source_rect, dest_rect, solutions_max - solutions_by_ZN - solutions_by_L7, &(out_solutions[solutions_by_ZN + solutions_by_L7]), &solutions_by_UC ); *out_solutions_count = solutions_by_ZN + solutions_by_L7 + solutions_by_UC; } TRACE_END(); } static const geometry_3dir_t PENCIL_BAD_V_PATTERN1 = { .first = GEOMETRY_DIRECTION_LEFT, .second = GEOMETRY_DIRECTION_DOWN, .third = GEOMETRY_DIRECTION_LEFT }; static const geometry_3dir_t PENCIL_BAD_V_PATTERN2 = { .first = GEOMETRY_DIRECTION_RIGHT, .second = GEOMETRY_DIRECTION_UP, .third = GEOMETRY_DIRECTION_RIGHT }; static const geometry_3dir_t PENCIL_BAD_H_PATTERN1 = { .first = GEOMETRY_DIRECTION_DOWN, .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_DOWN }; static const geometry_3dir_t PENCIL_BAD_H_PATTERN2 = { .first = GEOMETRY_DIRECTION_UP, .second = GEOMETRY_DIRECTION_LEFT, .third = GEOMETRY_DIRECTION_UP }; void pencil_relationship_layouter_private_select_solution ( pencil_relationship_layouter_t *this_, const universal_array_index_sorter_t *sorted, uint32_t sort_index, uint32_t solutions_count, const geometry_connector_t solutions[], uint32_t *out_index_of_best ) { TRACE_BEGIN(); assert ( NULL != sorted ); assert ( universal_array_index_sorter_get_count( sorted ) > sort_index ); assert ( NULL != solutions ); assert ( NULL != out_index_of_best ); assert ( 1 <= solutions_count ); /* get current relation data */ const uint32_t index = universal_array_index_sorter_get_array_index( sorted, sort_index ); const layout_relationship_t *const current_relation = pencil_layout_data_get_relationship_ptr ( (*this_).layout_data, index ); const data_relationship_t *const current_relation_data = layout_relationship_get_data_const ( current_relation ); /* get draw area */ const layout_diagram_t *const diagram_layout = pencil_layout_data_get_diagram_ptr( (*this_).layout_data ); const geometry_rectangle_t *const diagram_draw_area = layout_diagram_get_draw_area_const( diagram_layout ); /* define potential solution and rating */ uint32_t index_of_best = 0; double debts_of_best = DBL_MAX; /* evaluate the solutions by their overlaps with classifiers */ for ( uint32_t solution_idx = 0; solution_idx < solutions_count; solution_idx ++ ) { /* evalute the debts of this solution */ double debts_of_current = 0.0; const geometry_connector_t *const current_solution = &(solutions[solution_idx]); /* avoid alternating solutions in case their debts are identical */ debts_of_current += 0.1 * solution_idx; /* the more length, the more unwanted... */ debts_of_current += geometry_connector_get_length( current_solution ); /* prefer left-hand angles over right-handed */ bool bad_pattern_h = false; bool bad_pattern_v = false; { const geometry_3dir_t pattern = geometry_connector_get_directions( current_solution ); bad_pattern_v = geometry_3dir_equals( &pattern, &PENCIL_BAD_V_PATTERN1 ) || geometry_3dir_equals( &pattern, &PENCIL_BAD_V_PATTERN2 ); bad_pattern_h = geometry_3dir_equals( &pattern, &PENCIL_BAD_H_PATTERN1 ) || geometry_3dir_equals( &pattern, &PENCIL_BAD_H_PATTERN2 ); if ( bad_pattern_h || bad_pattern_v ) { const double current_len = geometry_connector_get_length( current_solution ); const double object_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size ); if ( current_len > ( 4.0 * object_dist ) ) { /* current_solution is a long path and right-handed */ debts_of_current += 0.2 * geometry_connector_get_length( current_solution ); } } } /* add debts for overlap to diagram boundary */ { const geometry_rectangle_t connectors_bounds = geometry_connector_get_bounding_rectangle( current_solution ); if ( ! geometry_rectangle_is_containing( diagram_draw_area, &connectors_bounds ) ) { debts_of_current += 1000000.0; } } /* iterate over all classifiers */ const uint32_t count_clasfy = pencil_layout_data_get_visible_classifier_count ( (*this_).layout_data ); for ( uint32_t clasfy_index = 0; clasfy_index < count_clasfy; clasfy_index ++ ) { const layout_visible_classifier_t *const probe_classifier = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, clasfy_index ); const geometry_rectangle_t *const classifier_symbol_box = layout_visible_classifier_get_symbol_box_const( probe_classifier ); if ( geometry_connector_is_intersecting_rectangle( current_solution, classifier_symbol_box ) ) { debts_of_current += 100000.0; } const geometry_rectangle_t *const classifier_label_box = layout_visible_classifier_get_label_box_const( probe_classifier ); if ( geometry_connector_is_intersecting_rectangle( current_solution, classifier_label_box ) ) { debts_of_current += 10000.0; } } /* iterate over the already created connectors (probe_sort_index < sort_index) */ for ( uint32_t probe_sort_index = 0; probe_sort_index < sort_index; probe_sort_index ++ ) { /* add debts if intersects */ const uint32_t probe_index = universal_array_index_sorter_get_array_index( sorted, probe_sort_index ); const layout_relationship_t *const probe_relationship = pencil_layout_data_get_relationship_ptr( (*this_).layout_data, probe_index ); const data_relationship_t *const probe_relation_data = layout_relationship_get_data_const ( probe_relationship ); const bool same_type = ( data_relationship_get_main_type( probe_relation_data ) == data_relationship_get_main_type( current_relation_data ) ); const bool same_from = ( data_relationship_get_from_classifier_row_id( probe_relation_data ) == data_relationship_get_from_classifier_row_id( current_relation_data ) ); const bool same_to = ( data_relationship_get_to_classifier_row_id( probe_relation_data ) == data_relationship_get_to_classifier_row_id( current_relation_data ) ); const bool one_same_end = ( same_from != same_to ); /* if probe and current have same type and (same source classifier xor same destination classifier), overlaps are ok */ if ( ! ( same_type && one_same_end ) ) { const geometry_connector_t *const probe_shape = layout_relationship_get_shape_const( probe_relationship ); const uint32_t intersects = geometry_connector_count_connector_intersects( current_solution, probe_shape ); debts_of_current += 1000.0 * intersects; if ( ( bad_pattern_h || bad_pattern_v ) && ( intersects > 0 ) ) { const geometry_3dir_t probe_pattern = geometry_connector_get_directions( probe_shape ); const bool bad_probe_v = geometry_3dir_equals( &probe_pattern, &PENCIL_BAD_V_PATTERN1 ) || geometry_3dir_equals( &probe_pattern, &PENCIL_BAD_V_PATTERN2 ); const bool bad_probe_h = geometry_3dir_equals( &probe_pattern, &PENCIL_BAD_H_PATTERN1 ) || geometry_3dir_equals( &probe_pattern, &PENCIL_BAD_H_PATTERN2 ); if (( bad_pattern_h && bad_probe_v )||( bad_pattern_v && bad_probe_h )) { debts_of_current += 1000000.0; } } } } /* update best solution */ if ( debts_of_current < debts_of_best ) { index_of_best = solution_idx; debts_of_best = debts_of_current; } } /* the best */ *out_index_of_best = index_of_best; geometry_connector_trace( &(solutions[index_of_best]) ); TRACE_END(); } void pencil_relationship_layouter_private_connect_rectangles_by_ZN ( pencil_relationship_layouter_t *this_, const geometry_rectangle_t *source_rect, const geometry_rectangle_t *dest_rect, uint32_t solutions_max, geometry_connector_t out_solutions[], uint32_t *out_solutions_count ) { TRACE_BEGIN(); assert( NULL != source_rect ); assert( NULL != dest_rect ); assert ( NULL != out_solutions ); assert ( NULL != out_solutions_count ); assert ( 2 <= solutions_max ); /* current implementation requires at least 2 options */ uint32_t solutions_count = 0; const double src_left = geometry_rectangle_get_left(source_rect); const double src_center_x = geometry_rectangle_get_center_x(source_rect); const double src_right = geometry_rectangle_get_right(source_rect); const double src_top = geometry_rectangle_get_top(source_rect); const double src_center_y = geometry_rectangle_get_center_y(source_rect); const double src_bottom = geometry_rectangle_get_bottom(source_rect); const double dst_left = geometry_rectangle_get_left(dest_rect); const double dst_center_x = geometry_rectangle_get_center_x(dest_rect); const double dst_right = geometry_rectangle_get_right(dest_rect); const double dst_top = geometry_rectangle_get_top(dest_rect); const double dst_center_y = geometry_rectangle_get_center_y(dest_rect); const double dst_bottom = geometry_rectangle_get_bottom(dest_rect); const double object_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size ); const double good_dist = 2.0 * object_dist; /* duplicate distance: once for each side of the line */ const double gap_dist = 0.499 * object_dist; /* half the object distance allows a line to pass between two objects */ /* if applicable, add a solution where main line is vertical */ { if ( dst_right + good_dist < src_left ) { double x_value; bool space_found; geometry_rectangle_t search_rect; geometry_rectangle_init_by_corners( &search_rect, src_left, src_center_y, dst_right, dst_center_y ); pencil_relationship_layouter_private_find_space_for_line ( this_, &search_rect, false /* horizontal_line */, gap_dist, &space_found, &x_value ); geometry_rectangle_destroy( &search_rect ); geometry_connector_reinit_vertical ( &(out_solutions[solutions_count]), src_left, src_center_y, dst_right, dst_center_y, x_value ); solutions_count ++; } else if ( dst_left - good_dist > src_right ) { double x_value; bool space_found; geometry_rectangle_t search_rect; geometry_rectangle_init_by_corners( &search_rect, src_right, src_center_y, dst_left, dst_center_y ); pencil_relationship_layouter_private_find_space_for_line ( this_, &search_rect, false /* horizontal_line */, gap_dist, &space_found, &x_value ); geometry_rectangle_destroy( &search_rect ); geometry_connector_reinit_vertical ( &(out_solutions[solutions_count]), src_right, src_center_y, dst_left, dst_center_y, x_value ); solutions_count ++; } } /* if applicable, add a solution where main line is horizontal */ { if ( dst_bottom + good_dist < src_top ) { double y_value; bool space_found; geometry_rectangle_t search_rect; geometry_rectangle_init_by_corners( &search_rect, src_center_x, src_top, dst_center_x, dst_bottom ); pencil_relationship_layouter_private_find_space_for_line ( this_, &search_rect, true /* horizontal_line */, gap_dist, &space_found, &y_value ); geometry_rectangle_destroy( &search_rect ); geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]), src_center_x, src_top, dst_center_x, dst_bottom, y_value ); solutions_count ++; } else if ( dst_top - good_dist > src_bottom ) { double y_value; bool space_found; geometry_rectangle_t search_rect; geometry_rectangle_init_by_corners( &search_rect, src_center_x, src_bottom, dst_center_x, dst_top ); pencil_relationship_layouter_private_find_space_for_line ( this_, &search_rect, true /* horizontal_line */, gap_dist, &space_found, &y_value ); geometry_rectangle_destroy( &search_rect ); geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]), src_center_x, src_bottom, dst_center_x, dst_top, y_value ); solutions_count ++; } } *out_solutions_count = solutions_count; TRACE_END(); } void pencil_relationship_layouter_private_connect_rectangles_by_UC ( pencil_relationship_layouter_t *this_, const geometry_rectangle_t *source_rect, const geometry_rectangle_t *dest_rect, uint32_t solutions_max, geometry_connector_t out_solutions[], uint32_t *out_solutions_count ) { TRACE_BEGIN(); assert( NULL != source_rect ); assert( NULL != dest_rect ); assert ( NULL != out_solutions ); assert ( NULL != out_solutions_count ); assert ( 4 <= solutions_max ); /* current implementation calculates exactly 4 options */ uint32_t solutions_count = 0; const double src_left = geometry_rectangle_get_left(source_rect); double src_center_x = geometry_rectangle_get_center_x(source_rect); const double src_right = geometry_rectangle_get_right(source_rect); const double src_top = geometry_rectangle_get_top(source_rect); double src_center_y = geometry_rectangle_get_center_y(source_rect); const double src_bottom = geometry_rectangle_get_bottom(source_rect); const double dst_left = geometry_rectangle_get_left(dest_rect); double dst_center_x = geometry_rectangle_get_center_x(dest_rect); const double dst_right = geometry_rectangle_get_right(dest_rect); const double dst_top = geometry_rectangle_get_top(dest_rect); double dst_center_y = geometry_rectangle_get_center_y(dest_rect); const double dst_bottom = geometry_rectangle_get_bottom(dest_rect); const double good_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size ); /* prevent that forward and retour are on same line */ if ( fabs( src_center_y - dst_center_y ) < 0.0001 ) { /* forward way is identical to retour - may be a relation to self */ src_center_y += good_dist/2.0; dst_center_y -= good_dist/2.0; } if ( fabs( src_center_x - dst_center_x ) < 0.0001 ) { /* forward way is identical to retour - may be a relation to self */ src_center_x -= good_dist/2.0; dst_center_x += good_dist/2.0; } /* connect via left side */ { geometry_connector_reinit_vertical( &(out_solutions[solutions_count]), src_left, src_center_y, dst_left, dst_center_y, fmin( src_left, dst_left ) - good_dist ); solutions_count ++; } /* connect via right side */ { geometry_connector_reinit_vertical( &(out_solutions[solutions_count]), src_right, src_center_y, dst_right, dst_center_y, fmax( src_right, dst_right ) + good_dist ); solutions_count ++; } /* connect via top side */ { geometry_connector_reinit_horizontal( &(out_solutions[solutions_count]), src_center_x, src_top, dst_center_x, dst_top, fmin( src_top, dst_top ) - good_dist ); solutions_count ++; } /* connect via bottom side */ { geometry_connector_reinit_horizontal( &(out_solutions[solutions_count]), src_center_x, src_bottom, dst_center_x, dst_bottom, fmax( src_bottom, dst_bottom ) + good_dist ); solutions_count ++; } *out_solutions_count = solutions_count; TRACE_END(); } void pencil_relationship_layouter_private_connect_rectangles_by_L7 ( pencil_relationship_layouter_t *this_, const geometry_rectangle_t *source_rect, const geometry_rectangle_t *dest_rect, uint32_t solutions_max, geometry_connector_t out_solutions[], uint32_t *out_solutions_count ) { TRACE_BEGIN(); assert( NULL != source_rect ); assert( NULL != dest_rect ); assert ( NULL != out_solutions ); assert ( NULL != out_solutions_count ); assert ( 2 <= solutions_max ); /* current implementation requires at least 2 options */ uint32_t solutions_count = 0; const double src_left = geometry_rectangle_get_left(source_rect); const double src_center_x = geometry_rectangle_get_center_x(source_rect); const double src_right = geometry_rectangle_get_right(source_rect); const double src_top = geometry_rectangle_get_top(source_rect); const double src_center_y = geometry_rectangle_get_center_y(source_rect); const double src_bottom = geometry_rectangle_get_bottom(source_rect); const double dst_left = geometry_rectangle_get_left(dest_rect); const double dst_center_x = geometry_rectangle_get_center_x(dest_rect); const double dst_right = geometry_rectangle_get_right(dest_rect); const double dst_top = geometry_rectangle_get_top(dest_rect); const double dst_center_y = geometry_rectangle_get_center_y(dest_rect); const double dst_bottom = geometry_rectangle_get_bottom(dest_rect); const double good_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size ); /* if applicable, add a solution from source to left */ if ( dst_center_x + good_dist < src_left ) { if ( dst_bottom + good_dist < src_center_y ) { geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]), src_left, src_center_y, dst_center_x, dst_bottom, src_center_y ); solutions_count ++; } else if ( dst_top - good_dist > src_center_y ) { geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]), src_left, src_center_y, dst_center_x, dst_top, src_center_y ); solutions_count ++; } } /* else-if applicable, add a solution from source to right */ else if ( dst_center_x - good_dist > src_right ) { if ( dst_bottom + good_dist < src_center_y ) { geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]), src_right, src_center_y, dst_center_x, dst_bottom, src_center_y ); solutions_count ++; } else if ( dst_top - good_dist > src_center_y ) { geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]), src_right, src_center_y, dst_center_x, dst_top, src_center_y ); solutions_count ++; } } /* if applicable, add a solution from source to upwards */ if ( dst_center_y + good_dist < src_top ) { if ( dst_right + good_dist < src_center_x ) { geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]), src_center_x, src_top, dst_right, dst_center_y, dst_center_y ); solutions_count ++; } else if ( dst_left - good_dist > src_center_x ) { geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]), src_center_x, src_top, dst_left, dst_center_y, dst_center_y ); solutions_count ++; } } /* else-if applicable, add a solution from source to downwards */ else if ( dst_center_y - good_dist > src_bottom ) { if ( dst_right + good_dist < src_center_x ) { geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]), src_center_x, src_bottom, dst_right, dst_center_y, dst_center_y ); solutions_count ++; } else if ( dst_left - good_dist > src_center_x ) { geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]), src_center_x, src_bottom, dst_left, dst_center_y, dst_center_y ); solutions_count ++; } } *out_solutions_count = solutions_count; TRACE_END(); } void pencil_relationship_layouter_private_find_space_for_line ( pencil_relationship_layouter_t *this_, const geometry_rectangle_t *search_rect, bool horizontal_line, double min_gap, bool *out_success, double *out_coordinate ) { TRACE_BEGIN(); assert ( NULL != search_rect ); assert ( NULL != out_success ); assert ( NULL != out_coordinate ); /* start two probes at the center and move these to the boundaries when discovering overlaps */ double smaller_probe; double greater_probe; double center; if ( horizontal_line ) { center = geometry_rectangle_get_center_y( search_rect ); smaller_probe = center; greater_probe = center; } else { center = geometry_rectangle_get_center_x( search_rect ); smaller_probe = center; greater_probe = center; } /* iterate over all classifiers */ const uint32_t count_classifiers = pencil_layout_data_get_visible_classifier_count ( (*this_).layout_data ); const uint32_t max_list_iteration = count_classifiers; /* in the worst case, each iteration moves the probes by one classifier */ bool hit = true; /* whenever the probes hit a rectangle, hit is set to true */ for ( uint32_t list_iteration = 0; (list_iteration < max_list_iteration) && hit; list_iteration ++ ) { hit = false; for ( uint32_t classifier_index = 0; classifier_index < count_classifiers; classifier_index ++ ) { const layout_visible_classifier_t *const the_classifier = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, classifier_index ); const geometry_rectangle_t *const classifier_symbol_box = layout_visible_classifier_get_symbol_box_const( the_classifier ); if ( geometry_rectangle_is_contiguous( search_rect, classifier_symbol_box ) ) { if ( horizontal_line ) { if ( ( geometry_rectangle_get_top(classifier_symbol_box) - min_gap < smaller_probe ) && ( geometry_rectangle_get_bottom(classifier_symbol_box) + min_gap > smaller_probe ) ) { smaller_probe = geometry_rectangle_get_top(classifier_symbol_box) - min_gap; hit = true; } if ( ( geometry_rectangle_get_top(classifier_symbol_box) - min_gap < greater_probe ) && ( geometry_rectangle_get_bottom(classifier_symbol_box) + min_gap > greater_probe ) ) { greater_probe = geometry_rectangle_get_bottom(classifier_symbol_box) + min_gap; hit = true; } } else { if ( ( geometry_rectangle_get_left(classifier_symbol_box) - min_gap < smaller_probe ) && ( geometry_rectangle_get_right(classifier_symbol_box) + min_gap > smaller_probe ) ) { smaller_probe = geometry_rectangle_get_left(classifier_symbol_box) - min_gap; hit = true; } if ( ( geometry_rectangle_get_left(classifier_symbol_box) - min_gap < greater_probe ) && ( geometry_rectangle_get_right(classifier_symbol_box) + min_gap > greater_probe ) ) { greater_probe = geometry_rectangle_get_right(classifier_symbol_box) + min_gap; hit = true; } } } } } /* check success */ if ( horizontal_line ) { if ( greater_probe > geometry_rectangle_get_bottom( search_rect ) ) { if ( smaller_probe < geometry_rectangle_get_top( search_rect ) ) { *out_success = false; *out_coordinate = center; } else { *out_success = true; *out_coordinate = smaller_probe; } } else { if ( smaller_probe < geometry_rectangle_get_top( search_rect ) ) { *out_success = true; *out_coordinate = greater_probe; } else { *out_success = true; if ( greater_probe - center > center - smaller_probe ) { *out_coordinate = smaller_probe; } else { *out_coordinate = greater_probe; } } } } else { if ( greater_probe > geometry_rectangle_get_right( search_rect ) ) { if ( smaller_probe < geometry_rectangle_get_left( search_rect ) ) { *out_success = false; *out_coordinate = center; } else { *out_success = true; *out_coordinate = smaller_probe; } } else { if ( smaller_probe < geometry_rectangle_get_left( search_rect ) ) { *out_success = true; *out_coordinate = greater_probe; } else { *out_success = true; if ( greater_probe - center > center - smaller_probe ) { *out_coordinate = smaller_probe; } else { *out_coordinate = greater_probe; } } } } TRACE_END(); } void pencil_relationship_layouter_private_make_all_visible ( pencil_relationship_layouter_t *this_ ) { TRACE_BEGIN(); /* determine visibility */ const uint32_t count_relations = pencil_layout_data_get_relationship_count ( (*this_).layout_data ); for ( uint32_t index = 0; index < count_relations; index ++ ) { layout_relationship_t *the_relation = pencil_layout_data_get_relationship_ptr ( (*this_).layout_data, index ); layout_visible_classifier_t *from_layout = layout_relationship_get_from_classifier_ptr ( the_relation ); layout_visible_classifier_t *to_layout = layout_relationship_get_to_classifier_ptr ( the_relation ); assert( from_layout != NULL ); assert( to_layout != NULL ); { const data_visible_classifier_t *from_data = layout_visible_classifier_get_data_const( from_layout ); const data_visible_classifier_t *to_data = layout_visible_classifier_get_data_const( to_layout ); const data_diagramelement_t *from_diagele = data_visible_classifier_get_diagramelement_const( from_data ); const data_diagramelement_t *to_diagele = data_visible_classifier_get_diagramelement_const( to_data ); data_diagramelement_flag_t from_flags = data_diagramelement_get_display_flags ( from_diagele ); data_diagramelement_flag_t to_flags = data_diagramelement_get_display_flags ( to_diagele ); if (( 0 != ( DATA_DIAGRAMELEMENT_FLAG_GRAY_OUT & from_flags )) || ( 0 != ( DATA_DIAGRAMELEMENT_FLAG_GRAY_OUT & to_flags ))) { layout_relationship_set_visibility ( the_relation, PENCIL_VISIBILITY_GRAY_OUT ); } else { layout_relationship_set_visibility ( the_relation, PENCIL_VISIBILITY_SHOW ); } } } TRACE_END(); } void pencil_relationship_layouter_layout_standard( pencil_relationship_layouter_t *this_ ) { TRACE_BEGIN(); pencil_relationship_layouter_private_make_all_visible( this_ ); pencil_relationship_layouter_private_do_layout ( this_ ); TRACE_END(); } void pencil_relationship_layouter_layout_void( pencil_relationship_layouter_t *this_ ) { TRACE_BEGIN(); /* hide all relationships */ const uint32_t count_relations = pencil_layout_data_get_relationship_count ( (*this_).layout_data ); for ( uint32_t index = 0; index < count_relations; index ++ ) { /* pencil_layout_data_set_relationship_visibility ( (*this_).layout_data, index, PENCIL_VISIBILITY_HIDE ); */ pencil_layout_data_set_relationship_visibility ( (*this_).layout_data, index, PENCIL_VISIBILITY_IMPLICIT ); } /* layout the relationships (needed for PENCIL_VISIBILITY_IMPLICIT) */ pencil_relationship_layouter_private_do_layout ( this_ ); TRACE_END(); } void pencil_relationship_layouter_layout_for_sequence( pencil_relationship_layouter_t *this_ ) { TRACE_BEGIN(); pencil_relationship_layouter_private_make_all_visible( this_ ); /* get draw area */ const layout_diagram_t *const diagram_layout = pencil_layout_data_get_diagram_const( (*this_).layout_data ); const geometry_rectangle_t *const diagram_draw_area = layout_diagram_get_draw_area_const( diagram_layout ); /* layout the relationships */ const uint32_t count_relations = pencil_layout_data_get_relationship_count( (*this_).layout_data ); TRACE_INFO_INT( "count_relations:", count_relations ); for ( uint32_t index = 0; index < count_relations; index ++ ) { /* get the relationship to layout */ layout_relationship_t *const the_relationship = pencil_layout_data_get_relationship_ptr( (*this_).layout_data, index ); /* adjust visibility */ if ( ( NULL == layout_relationship_get_from_feature_ptr( the_relationship ) ) && ( NULL == layout_relationship_get_to_feature_ptr( the_relationship ) ) ) { /* this is a globally visible relation, not local/scenario-based */ pencil_layout_data_set_relationship_visibility( (*this_).layout_data, index, PENCIL_VISIBILITY_IMPLICIT ); } /* calculate layout */ { /* determine y-coordinate */ const data_relationship_t *const the_relationdata = layout_relationship_get_data_const( the_relationship ); int32_t list_order = data_relationship_get_list_order( the_relationdata ); const double y_value_rel = (list_order/((double)UINT32_MAX))+0.5; const double draw_top = geometry_rectangle_get_top(diagram_draw_area); const double draw_bottom = geometry_rectangle_get_bottom(diagram_draw_area); const double y_value = ( (draw_bottom - draw_top) * y_value_rel ) + draw_top; /* get source and destination rectangles */ const geometry_rectangle_t *const source_rect = layout_relationship_get_from_symbol_box_const ( the_relationship ); const geometry_rectangle_t *const dest_rect = layout_relationship_get_to_symbol_box_const ( the_relationship ); /* calculate coordinates */ const double src_left = geometry_rectangle_get_left(source_rect); const double src_center_x = geometry_rectangle_get_center_x(source_rect); const double src_right = geometry_rectangle_get_right(source_rect); const double src_top = geometry_rectangle_get_top(source_rect); /*const double src_center_y = geometry_rectangle_get_center_y(source_rect);*/ const double src_bottom = geometry_rectangle_get_bottom(source_rect); const double dst_left = geometry_rectangle_get_left(dest_rect); const double dst_center_x = geometry_rectangle_get_center_x(dest_rect); const double dst_right = geometry_rectangle_get_right(dest_rect); const double dst_top = geometry_rectangle_get_top(dest_rect); /*const double dst_center_y = geometry_rectangle_get_center_y(dest_rect);*/ const double dst_bottom = geometry_rectangle_get_bottom(dest_rect); /* is interaction relation */ const data_relationship_type_t rel_type = data_relationship_get_main_type( the_relationdata ); const bool is_interaction = ( rel_type == DATA_RELATIONSHIP_TYPE_UML_ASYNC_CALL ) || ( rel_type == DATA_RELATIONSHIP_TYPE_UML_SYNC_CALL ) || ( rel_type == DATA_RELATIONSHIP_TYPE_UML_RETURN_CALL ) || ( rel_type == DATA_RELATIONSHIP_TYPE_UML_CONTROL_FLOW ) || ( rel_type == DATA_RELATIONSHIP_TYPE_UML_OBJECT_FLOW ) || ( rel_type == DATA_RELATIONSHIP_TYPE_UML_ASYNC_CALL ); const double src_from_y = ( y_value < src_top ) ? src_top : ( y_value > src_bottom ) ? src_bottom : y_value; const double dst_to_y = ( y_value < dst_top ) ? dst_top : ( y_value > dst_bottom ) ? dst_bottom : y_value; const double src_from_x = (( y_value < src_top )||( y_value > src_bottom )|| is_interaction ) ? src_center_x : ( src_center_x < dst_center_x ) ? src_right : src_left; const double dst_to_x = (( y_value < dst_top )||( y_value > dst_bottom )|| is_interaction ) ? dst_center_x : ( src_center_x < dst_center_x ) ? dst_left : dst_right; /* determine minimum arrow size for message/call to self */ const double good_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size ); /* define relation */ geometry_connector_t relationship_shape; if ( fabs( src_center_x - dst_center_x ) < 0.0001 ) { /* message/call to self */ geometry_connector_init_vertical ( &relationship_shape, src_center_x, src_from_y - (good_dist/2.0), dst_center_x, dst_to_y + (good_dist/2.0), src_center_x + good_dist /* the main connector shall be right to the start/end points */ ); } else { /* normal message/call */ geometry_connector_init_horizontal ( &relationship_shape, src_from_x, src_from_y, dst_to_x, dst_to_y, y_value ); } layout_relationship_set_shape( the_relationship, &relationship_shape ); geometry_connector_destroy( &relationship_shape ); } } TRACE_END(); } void pencil_relationship_layouter_layout_for_timing( pencil_relationship_layouter_t *this_ ) { TRACE_BEGIN(); pencil_relationship_layouter_private_make_all_visible( this_ ); /* get draw area */ const layout_diagram_t *const diagram_layout = pencil_layout_data_get_diagram_ptr( (*this_).layout_data ); const geometry_rectangle_t *const diagram_draw_area = layout_diagram_get_draw_area_const( diagram_layout ); /* layout the relationships */ const uint32_t count_relations = pencil_layout_data_get_relationship_count( (*this_).layout_data ); TRACE_INFO_INT( "count_relations:", count_relations ); for ( uint32_t index = 0; index < count_relations; index ++ ) { /* get the relationship to layout */ layout_relationship_t *const the_relationship = pencil_layout_data_get_relationship_ptr( (*this_).layout_data, index ); /* adjust visibility */ if ( ( NULL == layout_relationship_get_from_feature_ptr( the_relationship ) ) && ( NULL == layout_relationship_get_to_feature_ptr( the_relationship ) ) ) { /* this is a globally visible relation, not local/scenario-based */ pencil_layout_data_set_relationship_visibility( (*this_).layout_data, index, PENCIL_VISIBILITY_IMPLICIT ); } /* calculate layout */ { /* determine x-coordinate */ const data_relationship_t *const the_relationdata = layout_relationship_get_data_const( the_relationship ); const int32_t list_order = data_relationship_get_list_order ( the_relationdata ); const double x_value_rel = (list_order/((double)UINT32_MAX))+0.5; const double draw_left = geometry_rectangle_get_left(diagram_draw_area); const double draw_right = geometry_rectangle_get_right(diagram_draw_area); const double x_value = ( (draw_right - draw_left) * x_value_rel ) + draw_left; /* get source and destination rectangles */ const geometry_rectangle_t *const source_rect = layout_relationship_get_from_symbol_box_const( the_relationship ); const geometry_rectangle_t *const dest_rect = layout_relationship_get_to_symbol_box_const( the_relationship ); /* calculate coordinates */ const double src_left = geometry_rectangle_get_left(source_rect); /*const double src_center_x = geometry_rectangle_get_center_x(source_rect);*/ const double src_right = geometry_rectangle_get_right(source_rect); const double src_top = geometry_rectangle_get_top(source_rect); const double src_center_y = geometry_rectangle_get_center_y(source_rect); const double src_bottom = geometry_rectangle_get_bottom(source_rect); const double dst_left = geometry_rectangle_get_left(dest_rect); /*const double dst_center_x = geometry_rectangle_get_center_x(dest_rect);*/ const double dst_right = geometry_rectangle_get_right(dest_rect); const double dst_top = geometry_rectangle_get_top(dest_rect); const double dst_center_y = geometry_rectangle_get_center_y(dest_rect); const double dst_bottom = geometry_rectangle_get_bottom(dest_rect); /* is interaction relation */ const data_relationship_type_t rel_type = data_relationship_get_main_type( the_relationdata ); const bool is_interaction = ( rel_type == DATA_RELATIONSHIP_TYPE_UML_ASYNC_CALL ) || ( rel_type == DATA_RELATIONSHIP_TYPE_UML_SYNC_CALL ) || ( rel_type == DATA_RELATIONSHIP_TYPE_UML_RETURN_CALL ) || ( rel_type == DATA_RELATIONSHIP_TYPE_UML_CONTROL_FLOW ) || ( rel_type == DATA_RELATIONSHIP_TYPE_UML_OBJECT_FLOW ) || ( rel_type == DATA_RELATIONSHIP_TYPE_UML_ASYNC_CALL ); const double src_from_x = ( x_value < src_left ) ? src_left : ( x_value > src_right ) ? src_right : x_value; const double dst_to_x = ( x_value < dst_left ) ? dst_left : ( x_value > dst_right ) ? dst_right : x_value; const double src_from_y = (( x_value < src_left )||( x_value > src_right )|| is_interaction ) ? src_center_y : ( src_center_y < dst_center_y ) ? src_bottom : src_top; const double dst_to_y = (( x_value < dst_left )||( x_value > dst_right )|| is_interaction ) ? dst_center_y : ( src_center_y < dst_center_y ) ? dst_top : dst_bottom; /* determine minimum arrow size for self transition */ const double good_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size ); /* define relation */ geometry_connector_t relationship_shape; if ( fabs( src_center_y - dst_center_y ) < 0.0001 ) { /* transition to self */ geometry_connector_init_horizontal ( &relationship_shape, src_from_x - (good_dist/2.0), src_center_y, dst_to_x + (good_dist/2.0), dst_center_y, src_center_y - good_dist /* the main connector shall be above the start/end points */ ); } else { /* normal transition */ geometry_connector_init_vertical ( &relationship_shape, src_from_x, src_from_y, dst_to_x, dst_to_y, x_value ); } layout_relationship_set_shape( the_relationship, &relationship_shape ); geometry_connector_destroy( &relationship_shape ); } } TRACE_END(); } void pencil_relationship_layouter_layout_for_communication( pencil_relationship_layouter_t *this_ ) { TRACE_BEGIN(); pencil_relationship_layouter_private_make_all_visible( this_ ); /* hide some relationships */ const uint32_t count_relations = pencil_layout_data_get_relationship_count ( (*this_).layout_data ); for ( uint32_t index = 0; index < count_relations; index ++ ) { layout_relationship_t *const the_relationship = pencil_layout_data_get_relationship_ptr ( (*this_).layout_data, index ); /* adjust visibility */ if ( ( NULL == layout_relationship_get_from_feature_ptr ( the_relationship ) ) && ( NULL == layout_relationship_get_to_feature_ptr ( the_relationship ) ) ) { /* this is a globally visible relation, not local/scenario-based */ pencil_layout_data_set_relationship_visibility ( (*this_).layout_data, index, PENCIL_VISIBILITY_IMPLICIT ); } } /* layout the visible relationships */ pencil_relationship_layouter_private_do_layout ( this_ ); TRACE_END(); } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/pencil_relationship_painter.c000066400000000000000000000665351415120503000256350ustar00rootroot00000000000000/* File: pencil_relationship_painter.c; Copyright and License: see below */ #include "pencil_relationship_painter.h" #include "pencil_layout_data.h" #include "trace.h" #include "util/string/utf8string.h" #include #include #include #include void pencil_relationship_painter_init( pencil_relationship_painter_t *this_ ) { TRACE_BEGIN(); pencil_marker_init( &((*this_).marker) ); draw_relationship_label_init( &((*this_).draw_relationship_label) ); TRACE_END(); } void pencil_relationship_painter_destroy( pencil_relationship_painter_t *this_ ) { TRACE_BEGIN(); draw_relationship_label_destroy( &((*this_).draw_relationship_label) ); pencil_marker_destroy( &((*this_).marker) ); TRACE_END(); } void pencil_relationship_painter_draw ( pencil_relationship_painter_t *this_, const layout_relationship_t *layouted_relationship, bool mark_focused, bool mark_highlighted, bool mark_selected, const pencil_size_t *pencil_size, PangoLayout *layout, cairo_t *cr ) { TRACE_BEGIN(); assert( NULL != pencil_size ); assert( NULL != layouted_relationship ); assert( NULL != layout ); assert( NULL != cr ); const data_relationship_t *const the_relationship = layout_relationship_get_data_const( layouted_relationship ); const geometry_connector_t *const connector_shape = layout_relationship_get_shape_const( layouted_relationship ); if ( data_relationship_is_valid( the_relationship ) ) { TRACE_INFO_INT("drawing relationship id", data_relationship_get_row_id( the_relationship ) ); /* set the right line width */ const double std_line_width = pencil_size_get_standard_line_width( pencil_size ); cairo_set_line_width( cr, std_line_width ); /* set the right drawing color */ { GdkRGBA foreground_color; if ( mark_highlighted ) { foreground_color = pencil_size_get_highlight_color( pencil_size ); } else if (( PENCIL_VISIBILITY_GRAY_OUT == layout_relationship_get_visibility( layouted_relationship ) ) || ( PENCIL_VISIBILITY_IMPLICIT == layout_relationship_get_visibility( layouted_relationship ) )) { foreground_color = pencil_size_get_gray_out_color( pencil_size ); } else { foreground_color = pencil_size_get_standard_color( pencil_size ); } cairo_set_source_rgba( cr, foreground_color.red, foreground_color.green, foreground_color.blue, foreground_color.alpha ); } /* get points */ double p1x = geometry_connector_get_source_end_x ( connector_shape ); double p1y = geometry_connector_get_source_end_y ( connector_shape ); double p2x = geometry_connector_get_main_line_source_x ( connector_shape ); double p2y = geometry_connector_get_main_line_source_y ( connector_shape ); double p3x = geometry_connector_get_main_line_destination_x ( connector_shape ); double p3y = geometry_connector_get_main_line_destination_y ( connector_shape ); double p4x = geometry_connector_destination_end_x ( connector_shape ); double p4y = geometry_connector_get_destination_end_y ( connector_shape ); double center_x = (p2x+p3x)/2.0; double center_y = (p2y+p3y)/2.0; /* determine arrow direction */ int arrow_clock_direction; /* wall-clock direction assuming ascending y direction to top */ if ( fabs( p3x-p4x ) > 0.5 ) { arrow_clock_direction = ( p3x < p4x ) ? 3 : 9; } else { if ( fabs( p3y-p4y ) > 0.5 ) { arrow_clock_direction = ( p3y < p4y ) ? 0 : 6; } else { /* maybe the first segment is too short, take into account two segments */ if ( fabs( p2x-p4x ) > 0.5 ) { arrow_clock_direction = ( p2x < p4x ) ? 3 : 9; } else { if ( fabs( p2y-p4y ) > 0.5 ) { arrow_clock_direction = ( p2y < p4y ) ? 0 : 6; } else { /* maybe the first two segments are too short, take into account all segments */ if ( fabs( p1x-p4x ) > 0.5 ) { arrow_clock_direction = ( p1x < p4x ) ? 3 : 9; } else { if ( fabs( p1y-p4y ) > 0.5 ) { arrow_clock_direction = ( p1y < p4y ) ? 0 : 6; } else { /* connector has no length */ arrow_clock_direction = 0; } } } } } } /* determine feathers direction */ int feathers_clock_direction; /* wall-clock direction assuming ascending y direction to top */ if ( fabs( p2x-p1x ) > 0.5 ) { feathers_clock_direction = ( p2x < p1x ) ? 9 : 3; } else { if ( fabs( p2y-p1y ) > 0.5 ) { feathers_clock_direction = ( p2y < p1y ) ? 0 : 6; } else { /* maybe the first segment is too short, take into account two segments */ if ( fabs( p3x-p1x ) > 0.5 ) { feathers_clock_direction = ( p3x < p1x ) ? 9 : 3; } else { if ( fabs( p3y-p1y ) > 0.5 ) { feathers_clock_direction = ( p3y < p1y ) ? 0 : 6; } else { /* maybe the first two segments are too short, take into account all segments */ if ( fabs( p4x-p1x ) > 0.5 ) { feathers_clock_direction = ( p4x < p1x ) ? 9 : 3; } else { if ( fabs( p4y-p1y ) > 0.5 ) { feathers_clock_direction = ( p4y < p1y ) ? 0 : 6; } else { /* connector has no length */ feathers_clock_direction = 0; } } } } } } /* draw arrow */ switch ( data_relationship_get_main_type( the_relationship ) ) { case DATA_RELATIONSHIP_TYPE_UML_ASSOCIATION: case DATA_RELATIONSHIP_TYPE_UML_GENERALIZATION: case DATA_RELATIONSHIP_TYPE_UML_ASYNC_CALL: case DATA_RELATIONSHIP_TYPE_UML_SYNC_CALL: case DATA_RELATIONSHIP_TYPE_UML_CONTROL_FLOW: case DATA_RELATIONSHIP_TYPE_UML_OBJECT_FLOW: case DATA_RELATIONSHIP_TYPE_UML_EXTEND: /* t.b.d. */ case DATA_RELATIONSHIP_TYPE_UML_INCLUDE: /* t.b.d. */ case DATA_RELATIONSHIP_TYPE_UML_DEPLOY: case DATA_RELATIONSHIP_TYPE_UML_MANIFEST: /* t.b.d. */ case DATA_RELATIONSHIP_TYPE_UML_REALIZATION: case DATA_RELATIONSHIP_TYPE_UML_DEPENDENCY: case DATA_RELATIONSHIP_TYPE_UML_RETURN_CALL: case DATA_RELATIONSHIP_TYPE_UML_REFINE: case DATA_RELATIONSHIP_TYPE_UML_TRACE: { const double half_stroke_length = 0.5 * pencil_size_get_arrow_stroke_length( pencil_size ); const double part_stroke_length = pencil_size_get_arrow_stroke_087_length( pencil_size ); bool close_path; if (( data_relationship_get_main_type( the_relationship ) == DATA_RELATIONSHIP_TYPE_UML_GENERALIZATION ) || ( data_relationship_get_main_type( the_relationship ) == DATA_RELATIONSHIP_TYPE_UML_REALIZATION )) { close_path = true; } else { close_path = false; } switch ( arrow_clock_direction ) { case 0: /* direction: 12 o clock */ { cairo_move_to ( cr, p4x - half_stroke_length, p4y - part_stroke_length ); cairo_line_to ( cr, p4x, p4y ); cairo_line_to ( cr, p4x + half_stroke_length, p4y - part_stroke_length ); if ( close_path ) { cairo_line_to ( cr, p4x - half_stroke_length, p4y - part_stroke_length ); p4y = p4y - part_stroke_length; /* if p3 == p4, also move p3 */ if ( p3y > p4y ) { p3y = p4y; } } } break; case 3: { cairo_move_to ( cr, p4x - part_stroke_length, p4y - half_stroke_length ); cairo_line_to ( cr, p4x, p4y ); cairo_line_to ( cr, p4x - part_stroke_length, p4y + half_stroke_length ); if ( close_path ) { cairo_line_to ( cr, p4x - part_stroke_length, p4y - half_stroke_length ); p4x = p4x - part_stroke_length; /* if p3 == p4, also move p3 */ if ( p3x > p4x ) { p3x = p4x; } } } break; case 6: { cairo_move_to ( cr, p4x + half_stroke_length, p4y + part_stroke_length ); cairo_line_to ( cr, p4x, p4y ); cairo_line_to ( cr, p4x - half_stroke_length, p4y + part_stroke_length ); if ( close_path ) { cairo_line_to ( cr, p4x + half_stroke_length, p4y + part_stroke_length ); p4y = p4y + part_stroke_length; /* if p3 == p4, also move p3 */ if ( p3y < p4y ) { p3y = p4y; } } } break; case 9: { cairo_move_to ( cr, p4x + part_stroke_length, p4y + half_stroke_length ); cairo_line_to ( cr, p4x, p4y ); cairo_line_to ( cr, p4x + part_stroke_length, p4y - half_stroke_length ); if ( close_path ) { cairo_line_to ( cr, p4x + part_stroke_length, p4y + half_stroke_length ); p4x = p4x + part_stroke_length; /* if p3 == p4, also move p3 */ if ( p3x < p4x ) { p3x = p4x; } } } break; default: { TSLOG_ERROR("illegal case"); } break; } if (( data_relationship_get_main_type( the_relationship ) == DATA_RELATIONSHIP_TYPE_UML_SYNC_CALL ) || ( data_relationship_get_main_type( the_relationship ) == DATA_RELATIONSHIP_TYPE_UML_RETURN_CALL )) { cairo_fill (cr); } else { cairo_stroke (cr); } } break; case DATA_RELATIONSHIP_TYPE_UML_AGGREGATION: case DATA_RELATIONSHIP_TYPE_UML_COMPOSITION: case DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT: case DATA_RELATIONSHIP_TYPE_UML_COMMUNICATION_PATH: { /* no arrow tip */ } break; default: { TSLOG_ERROR("unknown data_relationship_type_t in pencil_relationship_painter_draw()"); /* no arrow tip */ } break; } /* draw feathers */ switch ( data_relationship_get_main_type( the_relationship ) ) { case DATA_RELATIONSHIP_TYPE_UML_AGGREGATION: case DATA_RELATIONSHIP_TYPE_UML_COMPOSITION: { /* rhomboid */ const double half_stroke_length = 0.5 * pencil_size_get_arrow_stroke_length( pencil_size ); const double part_stroke_length = pencil_size_get_arrow_stroke_087_length( pencil_size ); switch ( feathers_clock_direction ) { case 0: /* direction: 12 o clock */ { cairo_move_to ( cr, p1x, p1y ); cairo_line_to ( cr, p1x - half_stroke_length, p1y - part_stroke_length ); cairo_line_to ( cr, p1x, p1y - 2.0 * part_stroke_length ); cairo_line_to ( cr, p1x + half_stroke_length, p1y - part_stroke_length ); cairo_line_to ( cr, p1x, p1y ); p1y = p1y - 2.0 * part_stroke_length; /* if p2 == p1, also move p2 */ if ( p2y > p1y ) { p2y = p1y; } } break; case 3: { cairo_move_to ( cr, p1x, p1y ); cairo_line_to ( cr, p1x + part_stroke_length, p1y - half_stroke_length ); cairo_line_to ( cr, p1x + 2.0 * part_stroke_length, p1y ); cairo_line_to ( cr, p1x + part_stroke_length, p1y + half_stroke_length ); cairo_line_to ( cr, p1x, p1y ); p1x = p1x + 2.0 * part_stroke_length; /* if p2 == p1, also move p2 */ if ( p2x < p1x ) { p2x = p1x; } } break; case 6: { cairo_move_to ( cr, p1x, p1y ); cairo_line_to ( cr, p1x + half_stroke_length, p1y + part_stroke_length ); cairo_line_to ( cr, p1x, p1y + 2.0 * part_stroke_length ); cairo_line_to ( cr, p1x - half_stroke_length, p1y + part_stroke_length ); cairo_line_to ( cr, p1x, p1y ); p1y = p1y + 2.0 * part_stroke_length; /* if p2 == p1, also move p2 */ if ( p2y < p1y ) { p2y = p1y; } } break; case 9: { cairo_move_to ( cr, p1x, p1y ); cairo_line_to ( cr, p1x - part_stroke_length, p1y + half_stroke_length ); cairo_line_to ( cr, p1x - 2.0 * part_stroke_length, p1y ); cairo_line_to ( cr, p1x - part_stroke_length, p1y - half_stroke_length ); cairo_line_to ( cr, p1x, p1y ); p1x = p1x - 2.0 * part_stroke_length; /* if p2 == p1, also move p2 */ if ( p2x > p1x ) { p2x = p1x; } } break; default: { TSLOG_ERROR("illegal case"); } break; } if ( data_relationship_get_main_type( the_relationship ) == DATA_RELATIONSHIP_TYPE_UML_COMPOSITION ) { cairo_fill (cr); } else { cairo_stroke (cr); } } break; case DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT: { /* circle with plus */ /* const double stroke_length = pencil_size_get_arrow_stroke_length( pencil_size ); */ const double half_stroke_length = 0.5 * pencil_size_get_arrow_stroke_length( pencil_size ); switch ( feathers_clock_direction ) { case 0: /* direction: 12 o clock */ { cairo_new_sub_path (cr); /* to be called before arc */ cairo_arc ( cr, p1x, p1y - half_stroke_length, half_stroke_length, 0.0, 2.0*M_PI ); cairo_move_to ( cr, p1x - half_stroke_length, p1y - half_stroke_length ); cairo_line_to ( cr, p1x + half_stroke_length, p1y - half_stroke_length ); cairo_stroke (cr); } break; case 3: { cairo_new_sub_path (cr); cairo_arc ( cr, p1x + half_stroke_length, p1y, half_stroke_length, 0.0, 2.0*M_PI ); cairo_move_to ( cr, p1x + half_stroke_length, p1y - half_stroke_length ); cairo_line_to ( cr, p1x + half_stroke_length, p1y + half_stroke_length ); cairo_stroke (cr); } break; case 6: { cairo_new_sub_path (cr); cairo_arc ( cr, p1x, p1y + half_stroke_length, half_stroke_length, 0.0, 2.0*M_PI ); cairo_move_to ( cr, p1x - half_stroke_length, p1y + half_stroke_length ); cairo_line_to ( cr, p1x + half_stroke_length, p1y + half_stroke_length ); cairo_stroke (cr); } break; case 9: { cairo_new_sub_path (cr); cairo_arc ( cr, p1x - half_stroke_length, p1y, half_stroke_length, 0.0, 2.0*M_PI ); cairo_move_to ( cr, p1x - half_stroke_length, p1y - half_stroke_length ); cairo_line_to ( cr, p1x - half_stroke_length, p1y + half_stroke_length ); cairo_stroke (cr); } break; default: { TSLOG_ERROR("illegal case"); } break; } } break; case DATA_RELATIONSHIP_TYPE_UML_ASSOCIATION: case DATA_RELATIONSHIP_TYPE_UML_GENERALIZATION: case DATA_RELATIONSHIP_TYPE_UML_ASYNC_CALL: case DATA_RELATIONSHIP_TYPE_UML_SYNC_CALL: case DATA_RELATIONSHIP_TYPE_UML_COMMUNICATION_PATH: case DATA_RELATIONSHIP_TYPE_UML_CONTROL_FLOW: case DATA_RELATIONSHIP_TYPE_UML_OBJECT_FLOW: case DATA_RELATIONSHIP_TYPE_UML_EXTEND: /* t.b.d. */ case DATA_RELATIONSHIP_TYPE_UML_INCLUDE: /* t.b.d. */ case DATA_RELATIONSHIP_TYPE_UML_DEPLOY: case DATA_RELATIONSHIP_TYPE_UML_MANIFEST: /* t.b.d. */ case DATA_RELATIONSHIP_TYPE_UML_REALIZATION: case DATA_RELATIONSHIP_TYPE_UML_DEPENDENCY: case DATA_RELATIONSHIP_TYPE_UML_RETURN_CALL: case DATA_RELATIONSHIP_TYPE_UML_REFINE: case DATA_RELATIONSHIP_TYPE_UML_TRACE: { /* no rhomboid or other feathers */ } break; default: { TSLOG_ERROR("unknown data_relationship_type_t in pencil_relationship_painter_draw()"); /* no rhomboid or other feathers */ } break; } /* set the right line type: dashed/normal */ switch ( data_relationship_get_main_type( the_relationship ) ) { case DATA_RELATIONSHIP_TYPE_UML_ASSOCIATION: case DATA_RELATIONSHIP_TYPE_UML_AGGREGATION: case DATA_RELATIONSHIP_TYPE_UML_COMPOSITION: case DATA_RELATIONSHIP_TYPE_UML_GENERALIZATION: case DATA_RELATIONSHIP_TYPE_UML_ASYNC_CALL: case DATA_RELATIONSHIP_TYPE_UML_SYNC_CALL: case DATA_RELATIONSHIP_TYPE_UML_COMMUNICATION_PATH: case DATA_RELATIONSHIP_TYPE_UML_CONTROL_FLOW: case DATA_RELATIONSHIP_TYPE_UML_OBJECT_FLOW: case DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT: { /* no dashes */ cairo_set_dash ( cr, NULL, 0, 0.0 ); } break; case DATA_RELATIONSHIP_TYPE_UML_EXTEND: /* t.b.d. */ case DATA_RELATIONSHIP_TYPE_UML_INCLUDE: /* t.b.d. */ case DATA_RELATIONSHIP_TYPE_UML_DEPLOY: case DATA_RELATIONSHIP_TYPE_UML_MANIFEST: /* t.b.d. */ case DATA_RELATIONSHIP_TYPE_UML_REALIZATION: case DATA_RELATIONSHIP_TYPE_UML_DEPENDENCY: case DATA_RELATIONSHIP_TYPE_UML_RETURN_CALL: case DATA_RELATIONSHIP_TYPE_UML_REFINE: case DATA_RELATIONSHIP_TYPE_UML_TRACE: { double dashes[1]; dashes[0] = pencil_size_get_line_dash_length( pencil_size ); cairo_set_dash ( cr, dashes, 1, 0.0 ); } break; default: { TSLOG_ERROR("unknown data_relationship_type_t in pencil_relationship_painter_draw()"); double error_dashes[1]; error_dashes[0] = 0.2*pencil_size_get_line_dash_length( pencil_size ); cairo_set_dash ( cr, error_dashes, 1, 0.0 ); } break; } /* draw connector line */ { const double radius = 2.0 * pencil_size_get_arrow_stroke_length( pencil_size ); double dx; double dy; cairo_move_to ( cr, p1x, p1y ); dx = p2x - p1x; dy = p2y - p1y; if ( dx > +radius ) { dx = +radius; } if ( dx < -radius ) { dx = -radius; } if ( dy > +radius ) { dy = +radius; } if ( dy < -radius ) { dy = -radius; } cairo_line_to ( cr, p2x - dx, p2y - dy ); dx = center_x - p2x; dy = center_y - p2y; if ( dx > +radius ) { dx = +radius; } if ( dx < -radius ) { dx = -radius; } if ( dy > +radius ) { dy = +radius; } if ( dy < -radius ) { dy = -radius; } cairo_curve_to ( cr, p2x, p2y, p2x, p2y, p2x + dx, p2y + dy ); dx = p3x - center_x; dy = p3y - center_y; if ( dx > +radius ) { dx = +radius; } if ( dx < -radius ) { dx = -radius; } if ( dy > +radius ) { dy = +radius; } if ( dy < -radius ) { dy = -radius; } cairo_line_to ( cr, p3x - dx, p3y - dy ); dx = p4x - p3x; dy = p4y - p3y; if ( dx > +radius ) { dx = +radius; } if ( dx < -radius ) { dx = -radius; } if ( dy > +radius ) { dy = +radius; } if ( dy < -radius ) { dy = -radius; } cairo_curve_to ( cr, p3x, p3y, p3x, p3y, p3x + dx, p3y + dy ); cairo_line_to ( cr, p4x, p4y ); cairo_stroke (cr); } /* reset dashes */ cairo_set_dash ( cr, NULL, 0, 0.0 ); /* draw the label */ draw_relationship_label_draw_type_and_name ( &((*this_).draw_relationship_label), the_relationship, layout_relationship_get_label_box_const( layouted_relationship ), pencil_size, layout, cr ); #ifdef PENCIL_LAYOUT_DATA_DRAW_FOR_DEBUG /* draw the rectangles */ { const geometry_rectangle_t bounds = geometry_connector_get_bounding_rectangle( connector_shape ); const geometry_rectangle_t *const relation_label_box = layout_relationship_get_label_box_const( layouted_relationship ); cairo_set_source_rgba( cr, 0.5, 1.0, 0.6, 0.5 ); cairo_rectangle ( cr, geometry_rectangle_get_left ( &bounds ), geometry_rectangle_get_top ( &bounds ), geometry_rectangle_get_width ( &bounds ), geometry_rectangle_get_height ( &bounds ) ); cairo_rectangle ( cr, geometry_rectangle_get_left ( relation_label_box ), geometry_rectangle_get_top ( relation_label_box ), geometry_rectangle_get_width ( relation_label_box ), geometry_rectangle_get_height ( relation_label_box ) ); cairo_stroke (cr); } #endif /* draw markers */ if ( mark_selected ) { const geometry_rectangle_t bounds = geometry_connector_get_bounding_rectangle( connector_shape ); pencil_marker_mark_selected_rectangle( &((*this_).marker), bounds, cr ); } if ( mark_focused ) { const geometry_rectangle_t bounds = geometry_connector_get_bounding_rectangle( connector_shape ); pencil_marker_mark_focused_rectangle( &((*this_).marker), bounds, cr ); } } else { TSLOG_ERROR("invalid relationship in array!"); } TRACE_END(); } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/util/000077500000000000000000000000001415120503000206525ustar00rootroot00000000000000crystal-facet-uml-1.34.1/pencil/source/util/geometry/000077500000000000000000000000001415120503000225055ustar00rootroot00000000000000crystal-facet-uml-1.34.1/pencil/source/util/geometry/geometry_non_linear_scale.c000066400000000000000000000077461415120503000300750ustar00rootroot00000000000000/* File: geometry_non_linear_scale.c; Copyright and License: see below */ #define __STDC_LIMIT_MACROS #include "util/geometry/geometry_non_linear_scale.h" #include "trace.h" #include "tslog.h" #include #include #include void geometry_non_linear_scale_init ( geometry_non_linear_scale_t *this_, double lower_bound, double upper_bound ) { TRACE_BEGIN(); assert( lower_bound <= upper_bound ); (*this_).num_points = 2; (*this_).location[0] = lower_bound; (*this_).order[0] = INT32_MIN; (*this_).location[1] = upper_bound; (*this_).order[1] = INT32_MAX; TRACE_END(); } void geometry_non_linear_scale_trace ( const geometry_non_linear_scale_t *this_ ) { TRACE_BEGIN(); assert( (*this_).num_points <= GEOMETRY_NON_LINEAR_SCALE_MAX_POINTS ); TRACE_INFO( "geometry_non_linear_scale_t" ); TRACE_INFO_INT( "- num_points:", (*this_).num_points ); for ( uint32_t pos = 0; pos < (*this_).num_points; pos ++ ) { TRACE_INFO_INT_INT( "- location-%, order:", (int)((*this_).location[pos]*100.0), (*this_).order[pos] ); } TRACE_END(); } void geometry_non_linear_scale_add_order ( geometry_non_linear_scale_t *this_, int32_t order ) { TRACE_BEGIN(); assert( (*this_).num_points <= GEOMETRY_NON_LINEAR_SCALE_MAX_POINTS ); assert( (*this_).num_points >= 2 ); /* prevent division by zero */ /* check for duplicates and for possible insert position */ bool duplicate = false; uint32_t insert_pos = 0; for ( uint32_t pos = 0; pos < (*this_).num_points; pos ++ ) { if ( order > (*this_).order[pos] ) { insert_pos = pos+1; } else if ( order == (*this_).order[pos] ) { duplicate = true; TRACE_INFO_INT( "duplicate:", order ); } } /* insert if possible */ if ( ! duplicate ) { if ( (*this_).num_points < GEOMETRY_NON_LINEAR_SCALE_MAX_POINTS ) { double lower_bound; double upper_bound; lower_bound = (*this_).location[ 0 ]; upper_bound = (*this_).location[ (*this_).num_points - 1 ]; /* insert order value */ for ( uint32_t pos2 = (*this_).num_points; pos2 > insert_pos; pos2 -- ) { (*this_).order[ pos2 ] = (*this_).order[ pos2-1 ]; } (*this_).order[ insert_pos ] = order; (*this_).num_points ++; /* re-location in interval */ double interval_width; interval_width = ( upper_bound - lower_bound ); for ( uint32_t pos3 = 0; pos3 < (*this_).num_points; pos3 ++ ) { (*this_).location[ pos3 ] = lower_bound + ( (double) pos3 * interval_width ) / (double) ( (*this_).num_points - 1 ); } } else { TSLOG_WARNING( "geometry_non_linear_scale_t has not enough points." ); } } /* check for monotonic increase of order values and location values */ #ifndef NDEBUG assert( (*this_).num_points <= GEOMETRY_NON_LINEAR_SCALE_MAX_POINTS ); assert( (*this_).num_points >= 2 ); for ( uint32_t pos2 = 1; pos2 < (*this_).num_points; pos2 ++ ) { assert( (*this_).order[pos2-1] < (*this_).order[pos2] ); assert( (*this_).location[pos2-1]-0.000000001 < (*this_).location[pos2] ); /* equal locations are possible if lower_bound == upper_bound */ } #endif TRACE_END(); } /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/source/util/geometry/geometry_rectangle.c000066400000000000000000000430701415120503000265340ustar00rootroot00000000000000/* File: geometry_rectangle.c; Copyright and License: see below */ #include "util/geometry/geometry_rectangle.h" #include "trace.h" #include "tslog.h" #include #include int geometry_rectangle_init_by_difference ( geometry_rectangle_t *this_, const geometry_rectangle_t *rect_a, const geometry_rectangle_t *rect_b ) { TRACE_BEGIN(); assert( NULL != rect_a ); assert( NULL != rect_b ); int result = 0; const double a_left = geometry_rectangle_get_left( rect_a ); const double a_right = geometry_rectangle_get_right( rect_a ); const double a_top = geometry_rectangle_get_top( rect_a ); const double a_bottom = geometry_rectangle_get_bottom( rect_a ); const double b_left = geometry_rectangle_get_left( rect_b ); const double b_right = geometry_rectangle_get_right( rect_b ); const double b_top = geometry_rectangle_get_top( rect_b ); const double b_bottom = geometry_rectangle_get_bottom( rect_b ); if ( ( b_right <= a_left ) || ( b_bottom <= a_top ) || ( b_left >= a_right ) || ( b_top >= a_bottom ) ) { /* no intersection */ (*this_) = (*rect_a); } else { /* determine where to check for a suitable, maximum sub-rectangle */ const bool check_top = (( b_top > a_top )&&( b_top < a_bottom )); const bool check_bottom = (( b_bottom > a_top )&&( b_bottom < a_bottom )); const bool check_left = (( b_left > a_left )&&( b_left < a_right )); const bool check_right = (( b_right > a_left )&&( b_right < a_right )); bool keep_top_part = false; bool keep_bottom_part = false; bool keep_left_part = false; bool keep_right_part = false; if ( check_top ) { if ( check_bottom ) { if ( check_left ) { if ( check_right ) { TRACE_INFO( "to.bo.le.ri." ); /* 4 possible solutions */ const double area_top = geometry_rectangle_get_width( rect_a ) * ( b_top-a_top ); const double area_bottom = geometry_rectangle_get_width( rect_a ) * ( a_bottom-b_bottom ); const double area_left = ( b_left-a_left ) * geometry_rectangle_get_height( rect_a ); const double area_right = ( a_right-b_right ) * geometry_rectangle_get_height( rect_a ); if (area_top>area_bottom) { if (area_top>area_left) { if (area_top>area_right) { keep_top_part = true; } else /* area_right is bigger */ { keep_right_part = true; } } else /* area_left is bigger */ { if (area_left>area_right) { keep_left_part = true; } else /* area_right is bigger */ { keep_right_part = true; } } } else /* area_bottom is bigger */ { if (area_bottom>area_left) { if (area_bottom>area_right) { keep_bottom_part = true; } else /* area_right is bigger */ { keep_right_part = true; } } else /* area_left is bigger */ { if (area_left>area_right) { keep_left_part = true; } else /* area_right is bigger */ { keep_right_part = true; } } } } else /* ! check_right */ { TRACE_INFO( "to.bo.le." ); /* 3 possible solutions */ const double area_top = geometry_rectangle_get_width( rect_a ) * ( b_top-a_top ); const double area_bottom = geometry_rectangle_get_width( rect_a ) * ( a_bottom-b_bottom ); const double area_left = ( b_left-a_left ) * geometry_rectangle_get_height( rect_a ); if (area_top>area_bottom) { if (area_top>area_left) { keep_top_part = true; } else /* area_left is bigger */ { keep_left_part = true; } } else /* area_bottom is bigger */ { if (area_bottom>area_left) { keep_bottom_part = true; } else /* area_left is bigger */ { keep_left_part = true; } } } } else /* ! check_left */ { if ( check_right ) { TRACE_INFO( "to.bo.ri." ); /* 3 possible solutions */ const double area_top = geometry_rectangle_get_width( rect_a ) * ( b_top-a_top ); const double area_bottom = geometry_rectangle_get_width( rect_a ) * ( a_bottom-b_bottom ); const double area_right = ( a_right-b_right ) * geometry_rectangle_get_height( rect_a ); if (area_top>area_bottom) { if (area_top>area_right) { keep_top_part = true; } else /* area_right is bigger */ { keep_right_part = true; } } else /* area_bottom is bigger */ { if (area_bottom>area_right) { keep_bottom_part = true; } else /* area_right is bigger */ { keep_right_part = true; } } } else /* ! check_right */ { TRACE_INFO( "to.bo." ); /* 2 possible solutions */ if (( b_top-a_top )>( a_bottom-b_bottom )) { keep_top_part = true; } else { keep_bottom_part = true; } } } } else /* ! check_bottom */ { if ( check_left ) { if ( check_right ) { TRACE_INFO( "to.le.ri." ); /* 3 possible solutions */ const double area_top = geometry_rectangle_get_width( rect_a ) * ( b_top-a_top ); const double area_left = ( b_left-a_left ) * geometry_rectangle_get_height( rect_a ); const double area_right = ( a_right-b_right ) * geometry_rectangle_get_height( rect_a ); if (area_top>area_left) { if (area_top>area_right) { keep_top_part = true; } else /* area_right is bigger */ { keep_right_part = true; } } else /* area_left is bigger */ { if (area_left>area_right) { keep_left_part = true; } else /* area_right is bigger */ { keep_right_part = true; } } } else /* ! check_right */ { TRACE_INFO( "to.le." ); /* 2 possible solutions */ const double area_top = geometry_rectangle_get_width( rect_a ) * ( b_top-a_top ); const double area_left = ( b_left-a_left ) * geometry_rectangle_get_height( rect_a ); if (area_top>area_left) { keep_top_part = true; } else /* area_left is bigger */ { keep_left_part = true; } } } else /* ! check_left */ { if ( check_right ) { TRACE_INFO( "to.ri." ); /* 2 possible solutions */ const double area_top = geometry_rectangle_get_width( rect_a ) * ( b_top-a_top ); const double area_right = ( a_right-b_right ) * geometry_rectangle_get_height( rect_a ); if (area_top>area_right) { keep_top_part = true; } else /* area_right is bigger */ { keep_right_part = true; } } else /* ! check_right */ { TRACE_INFO( "to." ); /* 1 solution */ keep_top_part = true; } } } } else /* ! check_top */ { if ( check_bottom ) { if ( check_left ) { if ( check_right ) { TRACE_INFO( "bo.le.ri." ); /* 3 possible solutions */ const double area_bottom = geometry_rectangle_get_width( rect_a ) * ( a_bottom-b_bottom ); const double area_left = ( b_left-a_left ) * geometry_rectangle_get_height( rect_a ); const double area_right = ( a_right-b_right ) * geometry_rectangle_get_height( rect_a ); if (area_bottom>area_left) { if (area_bottom>area_right) { keep_bottom_part = true; } else /* area_right is bigger */ { keep_right_part = true; } } else /* area_left is bigger */ { if (area_left>area_right) { keep_left_part = true; } else /* area_right is bigger */ { keep_right_part = true; } } } else /* ! check_right */ { TRACE_INFO( "bo.le." ); /* 2 possible solutions */ const double area_bottom = geometry_rectangle_get_width( rect_a ) * ( a_bottom-b_bottom ); const double area_left = ( b_left-a_left ) * geometry_rectangle_get_height( rect_a ); if (area_bottom>area_left) { keep_bottom_part = true; } else /* area_left is bigger */ { keep_left_part = true; } } } else /* ! check_left */ { if ( check_right ) { TRACE_INFO( "bo.ri." ); /* 2 possible solutions */ const double area_bottom = geometry_rectangle_get_width( rect_a ) * ( a_bottom-b_bottom ); const double area_right = ( a_right-b_right ) * geometry_rectangle_get_height( rect_a ); if (area_bottom>area_right) { keep_bottom_part = true; } else /* area_right is bigger */ { keep_right_part = true; } } else /* ! check_right */ { TRACE_INFO( "bo." ); /* 1 solution */ keep_bottom_part = true; } } } else /* ! check_bottom */ { if ( check_left ) { if ( check_right ) { TRACE_INFO( "le.ri." ); /* 2 possible solutions */ if (( b_left-a_left )>( a_right-b_right )) { keep_left_part = true; } else { keep_right_part = true; } } else /* ! check_right */ { TRACE_INFO( "le." ); /* 1 solution */ keep_left_part = true; } } else /* ! check_left */ { if ( check_right ) { TRACE_INFO( "ri." ); /* 1 solution */ keep_right_part = true; } else /* ! check_right */ { TRACE_INFO( "0." ); /* rect_b contains rect_a, result is empty */ } } } } if ( keep_top_part ) { assert ( check_top ); TRACE_INFO( "-top-" ); geometry_rectangle_init ( this_, a_left, a_top, geometry_rectangle_get_width( rect_a ), b_top-a_top ); } else if ( keep_bottom_part ) { assert ( check_bottom ); TRACE_INFO( "-bottom-" ); geometry_rectangle_init ( this_, a_left, b_bottom, geometry_rectangle_get_width( rect_a ), a_bottom-b_bottom ); } else if ( keep_left_part ) { assert ( check_left ); TRACE_INFO( "-left-" ); geometry_rectangle_init ( this_, a_left, a_top, b_left-a_left, geometry_rectangle_get_height( rect_a ) ); } else if ( keep_right_part ) { assert ( check_right ); TRACE_INFO( "-right-" ); geometry_rectangle_init ( this_, b_right, a_top, a_right-b_right, geometry_rectangle_get_height( rect_a ) ); } else { TRACE_INFO( "-none-" ); geometry_rectangle_init ( this_, a_left, a_top, 0.0, 0.0 ); } } TRACE_END_ERR( result ); return result; } /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/pencil/test/000077500000000000000000000000001415120503000173545ustar00rootroot00000000000000crystal-facet-uml-1.34.1/pencil/test/integration/000077500000000000000000000000001415120503000216775ustar00rootroot00000000000000crystal-facet-uml-1.34.1/pencil/test/integration/pencil_diagram_maker_test.c000066400000000000000000000215311415120503000272210ustar00rootroot00000000000000/* File: pencil_diagram_maker_test.c; Copyright and License: see below */ #include "pencil_diagram_maker_test.h" #include "pencil_layouter.h" #include "pencil_diagram_maker.h" #include "test_data/test_data_setup.h" #include "trace.h" #include "test_assert.h" static void set_up(void); static void tear_down(void); static void layout_good_cases(void); static void layout_challenging_cases(void); #ifndef NDEBUG static void layout_edge_cases(void); #endif test_suite_t pencil_diagram_maker_test_get_list(void) { test_suite_t result; test_suite_init( &result, "pencil_diagram_maker_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "layout_good_cases", &layout_good_cases ); test_suite_add_test_case( &result, "layout_challenging_cases", &layout_challenging_cases ); #ifndef NDEBUG test_suite_add_test_case( &result, "layout_edge_cases", &layout_edge_cases ); #endif return result; } static data_visible_set_t data_set; static pencil_diagram_maker_t painter; static cairo_surface_t *surface; static cairo_t *cr; static geometry_rectangle_t diagram_bounds; #ifndef NDEBUG #define PENCIL_DIAGRAM_MAKER_TEST_EXPORT_SAMPLES #else #endif static void set_up(void) { data_visible_set_init( &data_set ); pencil_diagram_maker_init( &painter, &data_set ); geometry_rectangle_init( &diagram_bounds, 0.0, 0.0, 640.0, 480.0 ); surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, (uint32_t) geometry_rectangle_get_width( &diagram_bounds ), (uint32_t) geometry_rectangle_get_height( &diagram_bounds ) ); TEST_ENVIRONMENT_ASSERT( CAIRO_STATUS_SUCCESS == cairo_surface_status( surface ) ); cr = cairo_create (surface); TEST_ENVIRONMENT_ASSERT( CAIRO_STATUS_SUCCESS == cairo_status( cr ) ); } static void tear_down(void) { cairo_destroy (cr); cairo_surface_finish ( surface ); cairo_surface_destroy ( surface ); geometry_rectangle_destroy( &diagram_bounds ); pencil_diagram_maker_destroy( &painter ); data_visible_set_destroy( &data_set ); } static void draw_background() { /* draw paper */ cairo_set_source_rgba( cr, 1.0, 1.0, 1.0, 1.0 ); cairo_rectangle ( cr, geometry_rectangle_get_left( &diagram_bounds ), geometry_rectangle_get_top( &diagram_bounds ), geometry_rectangle_get_width( &diagram_bounds ), geometry_rectangle_get_height( &diagram_bounds ) ); cairo_fill (cr); } #ifdef PENCIL_DIAGRAM_MAKER_TEST_EXPORT_SAMPLES static void render_to_file( const test_data_setup_t *ts_case_setup, data_stat_t *render_stats ) { /* create filename */ char filename_buf[48]=""; utf8stringbuf_t filename = UTF8STRINGBUF(filename_buf); utf8stringbuf_append_str( filename, "test_pencil" ); const unsigned int variant = test_data_setup_get_variant( ts_case_setup ); switch ( test_data_setup_get_mode( ts_case_setup ) ) { default: case TEST_DATA_SETUP_MODE_GOOD_CASES: { utf8stringbuf_append_str( filename, "_g_" ); } break; case TEST_DATA_SETUP_MODE_CHALLENGING_CASES: { utf8stringbuf_append_str( filename, "_c_" ); } break; case TEST_DATA_SETUP_MODE_EDGE_CASES: { utf8stringbuf_append_str( filename, "_e_" ); } break; } utf8stringbuf_append_str( filename, "E=" ); utf8stringbuf_append_int( filename, data_stat_get_series_count( render_stats, DATA_STAT_SERIES_ERROR ) ); utf8stringbuf_append_str( filename, "-W=" ); utf8stringbuf_append_int( filename, data_stat_get_series_count( render_stats, DATA_STAT_SERIES_WARNING ) ); utf8stringbuf_append_str( filename, "-Ok=" ); utf8stringbuf_append_int( filename, data_stat_get_series_count( render_stats, DATA_STAT_SERIES_EXPORTED ) ); utf8stringbuf_append_str( filename, "_" ); utf8stringbuf_append_int( filename, variant ); utf8stringbuf_append_str( filename, ".png" ); /* finish surface */ const cairo_status_t png_result = cairo_surface_write_to_png ( surface, utf8stringbuf_get_string( filename ) ); TEST_ENVIRONMENT_ASSERT( CAIRO_STATUS_SUCCESS == png_result ); } #endif static void layout_good_cases(void) { test_data_setup_t ts_setup; test_data_setup_init( &ts_setup, TEST_DATA_SETUP_MODE_GOOD_CASES ); for ( ; test_data_setup_is_valid_variant( &ts_setup ); test_data_setup_next_variant( &ts_setup ) ) { /* setup */ test_data_setup_get_variant_data( &ts_setup, &data_set ); draw_background(); /* perform test: draw diagram */ data_id_t void_id; data_id_init_void( &void_id ); data_small_set_t void_set; data_small_set_init( &void_set ); data_stat_t layout_stats; data_stat_init( &layout_stats ); pencil_diagram_maker_define_grid( &painter, diagram_bounds ); pencil_diagram_maker_layout_elements( &painter, cr, &layout_stats ); pencil_diagram_maker_draw ( &painter, void_id, void_id, &void_set, cr ); /* check result */ /* TODO, manual check for now */ #ifdef PENCIL_DIAGRAM_MAKER_TEST_EXPORT_SAMPLES render_to_file( &ts_setup, &layout_stats ); #endif data_stat_destroy( &layout_stats ); } test_data_setup_destroy( &ts_setup ); } static void layout_challenging_cases(void) { test_data_setup_t ts_setup; test_data_setup_init( &ts_setup, TEST_DATA_SETUP_MODE_CHALLENGING_CASES ); for ( ; test_data_setup_is_valid_variant( &ts_setup ); test_data_setup_next_variant( &ts_setup ) ) { /* setup */ test_data_setup_get_variant_data( &ts_setup, &data_set ); draw_background(); /* perform test: draw diagram */ data_id_t void_id; data_id_init_void( &void_id ); data_small_set_t void_set; data_small_set_init( &void_set ); data_stat_t layout_stats; data_stat_init( &layout_stats ); pencil_diagram_maker_define_grid( &painter, diagram_bounds ); pencil_diagram_maker_layout_elements( &painter, cr, &layout_stats ); pencil_diagram_maker_draw ( &painter, void_id, void_id, &void_set, cr ); /* check result */ /* TODO, manual chack for now */ #ifdef PENCIL_DIAGRAM_MAKER_TEST_EXPORT_SAMPLES render_to_file( &ts_setup, &layout_stats ); #endif data_stat_destroy( &layout_stats ); } test_data_setup_destroy( &ts_setup ); } #ifndef NDEBUG static void layout_edge_cases(void) { test_data_setup_t ts_setup; test_data_setup_init( &ts_setup, TEST_DATA_SETUP_MODE_EDGE_CASES ); for ( ; test_data_setup_is_valid_variant( &ts_setup ); test_data_setup_next_variant( &ts_setup ) ) { /* setup */ test_data_setup_get_variant_data( &ts_setup, &data_set ); draw_background(); /* perform test: draw diagram */ data_id_t void_id; data_id_init_void( &void_id ); data_small_set_t void_set; data_small_set_init( &void_set ); data_stat_t layout_stats; data_stat_init( &layout_stats ); pencil_diagram_maker_define_grid( &painter, diagram_bounds ); pencil_diagram_maker_layout_elements( &painter, cr, &layout_stats ); pencil_diagram_maker_draw ( &painter, void_id, void_id, &void_set, cr ); /* check result */ /* TODO, manual chack for now */ #ifdef PENCIL_DIAGRAM_MAKER_TEST_EXPORT_SAMPLES render_to_file( &ts_setup, &layout_stats ); #endif data_stat_destroy( &layout_stats ); } test_data_setup_destroy( &ts_setup ); } #endif /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/test/integration/pencil_diagram_maker_test.h000066400000000000000000000016561415120503000272340ustar00rootroot00000000000000/* File: pencil_diagram_maker_test.h; Copyright and License: see below */ #ifndef PENCIL_DIAGRAM_MAKER_TEST_H #define PENCIL_DIAGRAM_MAKER_TEST_H /*! * \file * \brief MODULE TEST for pencil_diagram_maker */ #include "test_suite.h" test_suite_t pencil_diagram_maker_test_get_list(void); #endif /* PENCIL_DIAGRAM_MAKER_TEST_H */ /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/test/integration/pencil_layouter_test.c000066400000000000000000000237331415120503000263100ustar00rootroot00000000000000/* File: pencil_layouter_test.c; Copyright and License: see below */ #include "pencil_layouter_test.h" #include "pencil_layouter.h" #include "pencil_diagram_maker.h" #include "test_data/test_data_setup.h" #include "trace.h" #include "test_assert.h" #include static void set_up(void); static void tear_down(void); static void layout_good_cases(void); static void layout_challenging_cases(void); #ifndef NDEBUG static void layout_edge_cases(void); #endif /* STATISTICS OF VERSION: 1.28.0 test suite: pencil_layouter_test_get_list test case: layout_good_cases #Diag=432, total=1624 | ERR=0, W/C=10, W/F=181, W/R=125 test case: layout_challenging_cases #Diag=432, total=11793 | ERR=617, W/C=7833, W/F=9706, W/R=11167 STATISTICS OF VERSION: 1.28.0 - other fonts installed: [ 337s] test suite: pencil_layouter_test_get_list [ 337s] test case: layout_good_cases [ 337s] #Diag=432, total=1596 | ERR=28, W/C=10, W/F=174, W/R=139 [ 337s] test case: layout_challenging_cases [ 337s] #Diag=432, total=11205 | ERR=1205, W/C=8675, W/F=13081, W/R=15725 */ test_suite_t pencil_layouter_test_get_list(void) { test_suite_t result; test_suite_init( &result, "pencil_layouter_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "layout_good_cases", &layout_good_cases ); test_suite_add_test_case( &result, "layout_challenging_cases", &layout_challenging_cases ); #ifndef NDEBUG test_suite_add_test_case( &result, "layout_edge_cases", &layout_edge_cases ); #endif return result; } static data_visible_set_t data_set; static pencil_layouter_t layouter; static cairo_surface_t *surface; static cairo_t *cr; static geometry_rectangle_t diagram_bounds; static PangoLayout *font_layout; static void set_up(void) { data_visible_set_init( &data_set ); pencil_layouter_init( &layouter, &data_set ); geometry_rectangle_init( &diagram_bounds, 0.0, 0.0, 640.0, 480.0 ); surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, (uint32_t) geometry_rectangle_get_width( &diagram_bounds ), (uint32_t) geometry_rectangle_get_height( &diagram_bounds ) ); TEST_ENVIRONMENT_ASSERT( CAIRO_STATUS_SUCCESS == cairo_surface_status( surface ) ); cr = cairo_create (surface); TEST_ENVIRONMENT_ASSERT( CAIRO_STATUS_SUCCESS == cairo_status( cr ) ); font_layout = pango_cairo_create_layout (cr); } static void tear_down(void) { g_object_unref (font_layout); cairo_destroy (cr); cairo_surface_finish ( surface ); cairo_surface_destroy ( surface ); geometry_rectangle_destroy( &diagram_bounds ); pencil_layouter_destroy( &layouter ); data_visible_set_destroy( &data_set ); } static void layout_good_cases(void) { data_stat_t total_stats; data_stat_init( &total_stats ); test_data_setup_t ts_setup; test_data_setup_init( &ts_setup, TEST_DATA_SETUP_MODE_GOOD_CASES ); for ( ; test_data_setup_is_valid_variant( &ts_setup ); test_data_setup_next_variant( &ts_setup ) ) { /* setup */ test_data_setup_get_variant_data( &ts_setup, &data_set ); data_stat_t layout_stats; data_stat_init( &layout_stats ); /* perform test */ pencil_layouter_prepare ( &layouter ); pencil_layouter_define_grid ( &layouter, diagram_bounds ); pencil_layouter_layout_elements ( &layouter, font_layout, &layout_stats ); /* check result */ const pencil_layout_data_t *const layout_data = pencil_layouter_get_layout_data_const( &layouter ); TEST_ASSERT( NULL != layout_data ); /* const uint32_t class_cnt = pencil_layout_data_get_visible_classifier_count( layout_data ); TEST_ASSERT_EQUAL_INT( 0, class_cnt ); const uint32_t feat_cnt = pencil_layout_data_get_feature_count( layout_data ); TEST_ASSERT_EQUAL_INT( 0, feat_cnt ); const uint32_t rel_cnt = pencil_layout_data_get_relationship_count( layout_data ); TEST_ASSERT_EQUAL_INT( 0, rel_cnt ); */ /* const unsigned int variant = test_data_setup_get_variant( &ts_setup ); fprintf( stdout, " v=%i, #Diag=%" PRIuFAST32 ", total=%" PRIuFAST32 " | ERR=%" PRIuFAST32 ", W/C=%" PRIuFAST32 ", W/F=%" PRIuFAST32 ", W/R=%" PRIuFAST32 "\n", variant, data_stat_get_count( &layout_stats, DATA_TABLE_DIAGRAM, DATA_STAT_SERIES_EXPORTED ), data_stat_get_series_count( &layout_stats, DATA_STAT_SERIES_EXPORTED ), data_stat_get_series_count( &layout_stats, DATA_STAT_SERIES_ERROR ), data_stat_get_count( &layout_stats, DATA_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_WARNING ), data_stat_get_count( &layout_stats, DATA_TABLE_FEATURE, DATA_STAT_SERIES_WARNING ), data_stat_get_count( &layout_stats, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_WARNING ) ); */ data_stat_add( &total_stats, &layout_stats ); data_stat_destroy( &layout_stats ); } test_data_setup_destroy( &ts_setup ); fprintf( stdout, " #Diag=%" PRIuFAST32 ", total=%" PRIuFAST32 " | ERR=%" PRIuFAST32 ", W/C=%" PRIuFAST32 ", W/F=%" PRIuFAST32 ", W/R=%" PRIuFAST32 "\n", data_stat_get_count( &total_stats, DATA_TABLE_DIAGRAM, DATA_STAT_SERIES_EXPORTED ), data_stat_get_series_count( &total_stats, DATA_STAT_SERIES_EXPORTED ), data_stat_get_series_count( &total_stats, DATA_STAT_SERIES_ERROR ), data_stat_get_count( &total_stats, DATA_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_WARNING ), data_stat_get_count( &total_stats, DATA_TABLE_FEATURE, DATA_STAT_SERIES_WARNING ), data_stat_get_count( &total_stats, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_WARNING ) ); data_stat_destroy( &total_stats ); } static void layout_challenging_cases(void) { data_stat_t total_stats; data_stat_init( &total_stats ); test_data_setup_t ts_setup; test_data_setup_init( &ts_setup, TEST_DATA_SETUP_MODE_CHALLENGING_CASES ); for ( ; test_data_setup_is_valid_variant( &ts_setup ); test_data_setup_next_variant( &ts_setup ) ) { /* setup */ test_data_setup_get_variant_data( &ts_setup, &data_set ); data_stat_t layout_stats; data_stat_init( &layout_stats ); /* perform test */ pencil_layouter_prepare ( &layouter ); pencil_layouter_define_grid ( &layouter, diagram_bounds ); pencil_layouter_layout_elements ( &layouter, font_layout, &layout_stats ); /* check result */ const pencil_layout_data_t *const layout_data = pencil_layouter_get_layout_data_const( &layouter ); TEST_ASSERT( NULL != layout_data ); /* const uint32_t class_cnt = pencil_layout_data_get_visible_classifier_count( layout_data ); TEST_ASSERT_EQUAL_INT( 0, class_cnt ); const uint32_t feat_cnt = pencil_layout_data_get_feature_count( layout_data ); TEST_ASSERT_EQUAL_INT( 0, feat_cnt ); const uint32_t rel_cnt = pencil_layout_data_get_relationship_count( layout_data ); TEST_ASSERT_EQUAL_INT( 0, rel_cnt ); */ data_stat_add( &total_stats, &layout_stats ); data_stat_destroy( &layout_stats ); } test_data_setup_destroy( &ts_setup ); fprintf( stdout, " #Diag=%" PRIuFAST32 ", total=%" PRIuFAST32 " | ERR=%" PRIuFAST32 ", W/C=%" PRIuFAST32 ", W/F=%" PRIuFAST32 ", W/R=%" PRIuFAST32 "\n", data_stat_get_count( &total_stats, DATA_TABLE_DIAGRAM, DATA_STAT_SERIES_EXPORTED ), data_stat_get_series_count( &total_stats, DATA_STAT_SERIES_EXPORTED ), data_stat_get_series_count( &total_stats, DATA_STAT_SERIES_ERROR ), data_stat_get_count( &total_stats, DATA_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_WARNING ), data_stat_get_count( &total_stats, DATA_TABLE_FEATURE, DATA_STAT_SERIES_WARNING ), data_stat_get_count( &total_stats, DATA_TABLE_RELATIONSHIP, DATA_STAT_SERIES_WARNING ) ); data_stat_destroy( &total_stats ); } #ifndef NDEBUG static void layout_edge_cases(void) { test_data_setup_t ts_setup; test_data_setup_init( &ts_setup, TEST_DATA_SETUP_MODE_EDGE_CASES ); for ( ; test_data_setup_is_valid_variant( &ts_setup ); test_data_setup_next_variant( &ts_setup ) ) { /* setup */ test_data_setup_get_variant_data( &ts_setup, &data_set ); /* perform test */ pencil_layouter_prepare ( &layouter ); pencil_layouter_define_grid ( &layouter, diagram_bounds ); pencil_layouter_layout_elements ( &layouter, font_layout, NULL ); /* check result */ const pencil_layout_data_t *const layout_data = pencil_layouter_get_layout_data_const( &layouter ); TEST_ASSERT( NULL != layout_data ); /* const uint32_t class_cnt = pencil_layout_data_get_visible_classifier_count( layout_data ); TEST_ASSERT_EQUAL_INT( 0, class_cnt ); const uint32_t feat_cnt = pencil_layout_data_get_feature_count( layout_data ); TEST_ASSERT_EQUAL_INT( 0, feat_cnt ); const uint32_t rel_cnt = pencil_layout_data_get_relationship_count( layout_data ); TEST_ASSERT_EQUAL_INT( 0, rel_cnt ); */ } test_data_setup_destroy( &ts_setup ); } #endif /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/test/integration/pencil_layouter_test.h000066400000000000000000000016201415120503000263040ustar00rootroot00000000000000/* File: pencil_layouter_test.h; Copyright and License: see below */ #ifndef PENCIL_LAYOUTER_TEST_H #define PENCIL_LAYOUTER_TEST_H /*! * \file * \brief MODULE TEST for pencil_layouter */ #include "test_suite.h" test_suite_t pencil_layouter_test_get_list(void); #endif /* PENCIL_LAYOUTER_TEST_H */ /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/test/test_data/000077500000000000000000000000001415120503000213245ustar00rootroot00000000000000crystal-facet-uml-1.34.1/pencil/test/test_data/test_data_setup.h000066400000000000000000000130371415120503000246710ustar00rootroot00000000000000/* File: test_data_setup.h; Copyright and License: see below */ #ifndef TEST_DATA_SETUP_H #define TEST_DATA_SETUP_H /* public file for the doxygen documentation: */ /*! * \file * \brief Provides functions to setup test case input data */ #include "set/data_visible_set.h" /*! * \brief enumeration of all diagram types */ enum test_data_setup_mode_enum { TEST_DATA_SETUP_MODE_GOOD_CASES = 0, /*!< diagram data that should be drawn by pencil without overlaps or other problems */ TEST_DATA_SETUP_MODE_CHALLENGING_CASES = 1, /*!< diagram data that should be drawn by pencil, possibly with overlaps or other warnings */ TEST_DATA_SETUP_MODE_EDGE_CASES = 2, /*!< diagram data that should be drawn by pencil, possibly only partly or with rendering errors */ }; typedef enum test_data_setup_mode_enum test_data_setup_mode_t; /*! * \brief attributes of the test_data_setup_t */ struct test_data_setup_struct { unsigned int variant; /*!< current variant for which to produce test data */ test_data_setup_mode_t mode; /*!< kind of test data that shall be produced */ }; typedef struct test_data_setup_struct test_data_setup_t; /*! * \brief initializes the test_data_setup_t * * \param this_ pointer to own object attributes * \param mode the mode attribute */ static inline void test_data_setup_init( test_data_setup_t *this_, test_data_setup_mode_t mode ); /*! * \brief er-initializes the test_data_setup_t * * \param this_ pointer to own object attributes */ static inline void test_data_setup_reinit( test_data_setup_t *this_ ); /*! * \brief destroys the test_data_setup_t * * \param this_ pointer to own object attributes */ static inline void test_data_setup_destroy( test_data_setup_t *this_ ); /*! * \brief selects the next variant. In case there is no next variant, switches to invalid variant * * \param this_ pointer to own object attributes */ static inline void test_data_setup_next_variant( test_data_setup_t *this_ ); /*! * \brief checks if the current variant is a valid variant * * \param this_ pointer to own object attributes * \return true if there is a next variant */ static inline bool test_data_setup_is_valid_variant( const test_data_setup_t *this_ ); /*! * \brief gets the current variant * * \param this_ pointer to own object attributes * \return variant attribute */ static inline unsigned int test_data_setup_get_variant( const test_data_setup_t *this_ ); /*! * \brief gets the current mode * * \param this_ pointer to own object attributes * \return mode attribute */ static inline test_data_setup_mode_t test_data_setup_get_mode( const test_data_setup_t *this_ ); /*! * \brief initializes the data_visible_set_t according to the mode and the set variant * * \param this_ pointer to own object attributes * \param io_data_set pointer to the data_visible_set_t which shall be partily initialized */ static inline void test_data_setup_get_variant_data( const test_data_setup_t *this_, data_visible_set_t *io_data_set ); /*! * \brief initializes the diagram in the data_visible_set_t according to the set variant * * \param this_ pointer to own object attributes * \param io_data_set pointer to the data_visible_set_t which shall be partily initialized */ static inline void test_data_setup_private_set_diagram( const test_data_setup_t *this_, data_visible_set_t *io_data_set ); /*! * \brief adds visibla_classifiers to the data_visible_set_t according to the set variant * * \param this_ pointer to own object attributes * \param io_data_set pointer to the data_visible_set_t which shall be partily initialized */ static inline void test_data_setup_private_add_classifiers( const test_data_setup_t *this_, data_visible_set_t *io_data_set ); /*! * \brief adds lifelines to the data_visible_set_t, one per visible classifier * * \param this_ pointer to own object attributes * \param io_data_set pointer to the data_visible_set_t which contains visible classifiers and which shall be partily initialized */ static inline void test_data_setup_private_add_lifelines( const test_data_setup_t *this_, data_visible_set_t *io_data_set ); /*! * \brief adds features to the data_visible_set_t according to the set variant * * \param this_ pointer to own object attributes * \param io_data_set pointer to the data_visible_set_t which contains visible classifiers and which shall be partily initialized */ static inline void test_data_setup_private_add_features( const test_data_setup_t *this_, data_visible_set_t *io_data_set ); /*! * \brief adds relationships to the data_visible_set_t according to the set variant * * \param this_ pointer to own object attributes * \param io_data_set pointer to the data_visible_set_t which contains visible classifiers and which shall be partily initialized */ static inline void test_data_setup_private_add_relationships( const test_data_setup_t *this_, data_visible_set_t *io_data_set ); #include "test_data_setup.inl" #endif /* TEST_DATA_SETUP_H */ /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/test/test_data/test_data_setup.inl000066400000000000000000000750211415120503000252250ustar00rootroot00000000000000/* File: test_data_setup.inl; Copyright and License: see below */ #include "trace.h" #include "test_assert.h" #include #include /* number of same relationships in variant/variant-group size (the division-denominator): TEST_DATA_SETUP_REL_SAME_GROUP */ #define TEST_DATA_SETUP_REL_SAME_GROUP (1) /* number of relationship variants (the modulo-result): TEST_DATA_SETUP_REL_VARIANTS */ #define TEST_DATA_SETUP_REL_VARIANTS (6) /* number of same feature in variant/variant-group size (the division-denominator): TEST_DATA_SETUP_FEAT_SAME_GROUP */ #define TEST_DATA_SETUP_FEAT_SAME_GROUP ( TEST_DATA_SETUP_REL_VARIANTS ) /* number of feature variants (the modulo-result): TEST_DATA_SETUP_FEAT_VARIANTS */ #define TEST_DATA_SETUP_FEAT_VARIANTS (3) /* number of same classifier in variant/variant-group size (the division-denominator): TEST_DATA_SETUP_CLASS_SAME_GROUP */ #define TEST_DATA_SETUP_CLASS_SAME_GROUP ( TEST_DATA_SETUP_FEAT_SAME_GROUP * TEST_DATA_SETUP_FEAT_VARIANTS ) /* number of classifier variants (the modulo-result): TEST_DATA_SETUP_CLASS_VARIANTS */ #define TEST_DATA_SETUP_CLASS_VARIANTS (4) /* number of same diagram in variant/variant-group size (the division-denominator): TEST_DATA_SETUP_DIAG_SAME_GROUP */ #define TEST_DATA_SETUP_DIAG_SAME_GROUP ( TEST_DATA_SETUP_CLASS_SAME_GROUP * TEST_DATA_SETUP_CLASS_VARIANTS ) /* number of diagram variants (the modulo-result): TEST_DATA_SETUP_DIAG_VARIANTS */ #define TEST_DATA_SETUP_DIAG_VARIANTS (6) /* number of total variants */ #define TEST_DATA_SETUP_VARIANTS ( TEST_DATA_SETUP_DIAG_SAME_GROUP * TEST_DATA_SETUP_DIAG_VARIANTS ) /* spread range of a pseude random byte to full integer range */ #define SPREAD_RANGE(x) (memset(&x,(char)(x),sizeof(x))) static inline void test_data_setup_init( test_data_setup_t *this_, test_data_setup_mode_t mode ) { (*this_).variant = 0; (*this_).mode = mode; } static inline void test_data_setup_reinit( test_data_setup_t *this_ ) { (*this_).variant = 0; } static inline void test_data_setup_destroy( test_data_setup_t *this_ ) { } static inline void test_data_setup_next_variant( test_data_setup_t *this_ ) { assert( (*this_).variant <= TEST_DATA_SETUP_VARIANTS ); (*this_).variant++; } static inline bool test_data_setup_is_valid_variant( const test_data_setup_t *this_ ) { return ( (*this_).variant < TEST_DATA_SETUP_VARIANTS ); } static inline unsigned int test_data_setup_get_variant( const test_data_setup_t *this_ ) { return (*this_).variant; } static inline test_data_setup_mode_t test_data_setup_get_mode( const test_data_setup_t *this_ ) { return (*this_).mode; } static inline void test_data_setup_get_variant_data( const test_data_setup_t *this_, data_visible_set_t *io_data_set ) { data_visible_set_reinit( io_data_set ); test_data_setup_private_set_diagram( this_, io_data_set ); test_data_setup_private_add_classifiers( this_, io_data_set ); const data_diagram_type_t diag_type = data_diagram_get_diagram_type( data_visible_set_get_diagram_const( io_data_set ) ); if ( data_diagram_type_is_interaction( diag_type ) ) { test_data_setup_private_add_lifelines( this_, io_data_set ); } test_data_setup_private_add_features( this_, io_data_set ); test_data_setup_private_add_relationships( this_, io_data_set ); } static const char *const EMPTY_STR = ""; static const char *const NARROW_STR = "i"; static const char *const STANDARD_STR = "Hello World"; static const char *const LONG_NAME = u8"Input-Devices::360" u8"\u00B0" u8"SurroundView::Settings"; static const char *const WIDE_NAME = "WWWWWWWWWW" "WWWWWWWWWW" "WWWWWWWWWW" "WWWWWWWWWW" "WWWWWWW"; #define TEST_DATA_SETUP_NORMAL_TEXT "This software component shall implement the following interfaces:\n" static const char *const NORMAL_DESCRIPTION = TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT; static const char *const LONG_DESCRIPTION = TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT TEST_DATA_SETUP_NORMAL_TEXT; static inline void test_data_setup_private_set_diagram( const test_data_setup_t *this_, data_visible_set_t *io_data_set ) { data_diagram_type_t diagram_type; const uint_fast32_t pseudo_random = (*this_).variant; /* = this shall be variable/dynamic but not really random */ const uint_fast32_t diag_variant = ( (*this_).variant / TEST_DATA_SETUP_DIAG_SAME_GROUP ) % TEST_DATA_SETUP_DIAG_VARIANTS; switch ( diag_variant ) { default: case 0: { diagram_type = DATA_DIAGRAM_TYPE_LIST; } break; case 1: { diagram_type = DATA_DIAGRAM_TYPE_BOX_DIAGRAM; } break; case 2: { /* select any normal/std diagram type */ const data_diagram_type_t proposal_type = DATA_DIAGRAM_TYPE_ARRAY [ pseudo_random % DATA_DIAGRAM_TYPE_COUNT ]; const bool proposal_is_not_std = data_diagram_type_is_interaction( proposal_type ) || ( proposal_type == DATA_DIAGRAM_TYPE_LIST ) || ( proposal_type == DATA_DIAGRAM_TYPE_BOX_DIAGRAM ); diagram_type = (proposal_is_not_std) ? DATA_DIAGRAM_TYPE_UML_USE_CASE_DIAGRAM : proposal_type; } break; case 3: { diagram_type = DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM; } break; case 4: { diagram_type = DATA_DIAGRAM_TYPE_UML_TIMING_DIAGRAM; } break; case 5: { /* select a remaining interaction diagram type */ diagram_type = ((pseudo_random % 2)==0) ? DATA_DIAGRAM_TYPE_UML_COMMUNICATION_DIAGRAM : DATA_DIAGRAM_TYPE_INTERACTION_OVERVIEW_DIAGRAM; } break; } const char* diagram_name; const char* diagram_description; switch ( (*this_).mode ) { default: case TEST_DATA_SETUP_MODE_GOOD_CASES: { diagram_name = ((pseudo_random % 2)==0) ? NARROW_STR : STANDARD_STR; diagram_description = NORMAL_DESCRIPTION; } break; case TEST_DATA_SETUP_MODE_CHALLENGING_CASES: { diagram_name = ((pseudo_random % 2)==0) ? EMPTY_STR : LONG_NAME; diagram_description = NORMAL_DESCRIPTION; } break; case TEST_DATA_SETUP_MODE_EDGE_CASES: { diagram_name = WIDE_NAME; diagram_description = LONG_DESCRIPTION; } break; } const data_diagram_flag_t flag_emph = ((pseudo_random % 3)==0) ? DATA_DIAGRAM_FLAG_EMPHASIS : ((pseudo_random % 3)==1) ? DATA_DIAGRAM_FLAG_GRAY_OUT : DATA_DIAGRAM_FLAG_NONE; data_uuid_t diag_uuid; data_uuid_init_new( &diag_uuid ); data_diagram_t *diag = data_visible_set_get_diagram_ptr( io_data_set ); const data_error_t d_err = data_diagram_init( diag, (*this_).variant, /* diagram_id */ DATA_ROW_ID_VOID, /* parent_diagram_id */ diagram_type, diagram_name, diagram_description, (*this_).variant, /* list_order */ flag_emph, data_uuid_get_string( &diag_uuid ) ); TEST_ENVIRONMENT_ASSERT( DATA_ERROR_NONE == d_err ); data_uuid_destroy( &diag_uuid ); } static inline void test_data_setup_private_add_classifiers( const test_data_setup_t *this_, data_visible_set_t *io_data_set ) { const uint_fast32_t class_variant = ( (*this_).variant / TEST_DATA_SETUP_CLASS_SAME_GROUP ) % TEST_DATA_SETUP_CLASS_VARIANTS; uint_fast32_t count = 0; switch ( (*this_).mode ) { default: case TEST_DATA_SETUP_MODE_GOOD_CASES: { count = class_variant; } break; case TEST_DATA_SETUP_MODE_CHALLENGING_CASES: { count = (2*TEST_DATA_SETUP_CLASS_VARIANTS) + (4*class_variant); } break; case TEST_DATA_SETUP_MODE_EDGE_CASES: { count = (class_variant==0) ? (DATA_VISIBLE_SET_MAX_CLASSIFIERS) /* variants wit MAX classifiers */ : (DATA_VISIBLE_SET_MAX_CLASSIFIERS/4); /* variants wit MAX/4 classifiers */ } break; } for ( uint_fast32_t index = 0; index < count; index ++ ) { data_visible_classifier_t vis_classfy; data_visible_classifier_init_empty ( &vis_classfy ); data_classifier_t *classifier = data_visible_classifier_get_classifier_ptr ( &vis_classfy ); data_diagramelement_t *diagramelement = data_visible_classifier_get_diagramelement_ptr ( &vis_classfy ); const uint_fast32_t pseudo_random_1 = ((*this_).variant + index)*23; /* = this shall be variable/dynamic but not really random */ const uint_fast32_t pseudo_random_2 = ((*this_).variant + index + 8)*29; /* = this shall be variable/dynamic but not really random */ const data_classifier_type_t class_type = DATA_CLASSIFIER_TYPE_ARRAY [ pseudo_random_1 % DATA_CLASSIFIER_TYPE_COUNT ]; const char* stereotype = ""; const char* name = ""; const char* description = ""; int32_t x_order; int32_t y_order; int32_t list_order; switch ( class_variant ) { default: case 0: { /* all different */ x_order = pseudo_random_1; y_order = pseudo_random_2; list_order = pseudo_random_1; } break; case 1: { /* all zero */ x_order = 0; y_order = 0; list_order = 0; } break; case 2: { /* all 5x5 grid */ x_order = ((pseudo_random_1)%5)*1000; y_order = ((pseudo_random_2)%5)*1000; list_order = ((pseudo_random_1)%5)*1000; } break; case 3: { /* all diagnonal */ x_order = pseudo_random_1; y_order = pseudo_random_1; list_order = pseudo_random_1; } break; } switch ( (*this_).mode ) { default: case TEST_DATA_SETUP_MODE_GOOD_CASES: { stereotype = ((pseudo_random_1 % 2)==0) ? NARROW_STR : STANDARD_STR; name = ((pseudo_random_2 % 2)==0) ? NARROW_STR : STANDARD_STR; description = NORMAL_DESCRIPTION; } break; case TEST_DATA_SETUP_MODE_CHALLENGING_CASES: { stereotype = ((pseudo_random_1 % 2)==0) ? EMPTY_STR : LONG_NAME; name = ((pseudo_random_2 % 2)==0) ? EMPTY_STR : LONG_NAME; description = NORMAL_DESCRIPTION; } break; case TEST_DATA_SETUP_MODE_EDGE_CASES: { stereotype = ((pseudo_random_1 % 2)==0) ? EMPTY_STR : WIDE_NAME; name = ((pseudo_random_2 % 2)==0) ? STANDARD_STR : WIDE_NAME; description = ((pseudo_random_1 % 2)==0) ? NORMAL_DESCRIPTION : LONG_DESCRIPTION; } break; } data_uuid_t clsfr_uuid; data_uuid_init_new( &clsfr_uuid ); data_uuid_t diagele_uuid; data_uuid_init_new( &diagele_uuid ); const data_row_id_t classifier_id = ((pseudo_random_1 % 5)==0) ? (index+2) : (index+1); /* some classifiers exist twice */ const data_error_t d1_err = data_classifier_init( classifier, classifier_id, class_type, stereotype, name, description, x_order, y_order, list_order, data_uuid_get_string( &clsfr_uuid ) ); TEST_ENVIRONMENT_ASSERT_EQUAL_INT ( DATA_ERROR_NONE, d1_err&(~DATA_ERROR_STRING_BUFFER_EXCEEDED) ); const data_row_id_t diagram_id = data_diagram_get_row_id( data_visible_set_get_diagram_const( io_data_set ) ); const data_diagramelement_flag_t flag_inst = ((pseudo_random_1 % 3)==0) ? DATA_DIAGRAMELEMENT_FLAG_NAMED_INSTANCE : ((pseudo_random_1 % 3)==1) ? DATA_DIAGRAMELEMENT_FLAG_ANONYMOUS_INSTANCE : DATA_DIAGRAMELEMENT_FLAG_NONE; const data_diagramelement_flag_t flag_emph = ((pseudo_random_2 % 3)==0) ? DATA_DIAGRAMELEMENT_FLAG_EMPHASIS : ((pseudo_random_2 % 3)==1) ? DATA_DIAGRAMELEMENT_FLAG_GRAY_OUT : DATA_DIAGRAMELEMENT_FLAG_NONE; const data_error_t d2_err = data_diagramelement_init( diagramelement, index+1, /* = id */ diagram_id, classifier_id, flag_inst|flag_emph, index+10001, /* = focused_feature_id */ data_uuid_get_string( &diagele_uuid ) ); TEST_ENVIRONMENT_ASSERT ( d2_err == DATA_ERROR_NONE ); const data_error_t d3_err = data_visible_set_append_classifier( io_data_set, &vis_classfy ); TEST_ENVIRONMENT_ASSERT ( d3_err == DATA_ERROR_NONE ); data_visible_classifier_destroy ( &vis_classfy ); data_uuid_destroy( &clsfr_uuid ); data_uuid_destroy( &diagele_uuid ); } } static inline void test_data_setup_private_add_lifelines( const test_data_setup_t *this_, data_visible_set_t *io_data_set ) { const uint_fast32_t count = data_visible_set_get_visible_classifier_count( io_data_set ); for ( uint_fast32_t index = 0; index < count; index ++ ) { const data_visible_classifier_t *const visclas = data_visible_set_get_visible_classifier_const ( io_data_set, index ); const data_diagramelement_t *const diagele = data_visible_classifier_get_diagramelement_const ( visclas ); const data_feature_type_t feat_type = DATA_FEATURE_TYPE_LIFELINE; const char *const feature_key = ""; const char *const feature_value = ""; const char *const feature_description = ""; const int32_t list_order = 0; data_uuid_t feat_uuid; data_uuid_init_new( &feat_uuid ); data_feature_t feat; const data_error_t d1_err = data_feature_init( &feat, data_diagramelement_get_focused_feature_row_id( diagele ), /* = feature_id */ feat_type, data_diagramelement_get_classifier_row_id( diagele ), /* = classifier_id */ feature_key, feature_value, feature_description, list_order, data_uuid_get_string( &feat_uuid ) ); TEST_ENVIRONMENT_ASSERT_EQUAL_INT ( DATA_ERROR_NONE, d1_err ); const data_error_t d2_err = data_visible_set_append_feature( io_data_set, &feat ); TEST_ENVIRONMENT_ASSERT_EQUAL_INT ( DATA_ERROR_NONE, d2_err ); data_feature_destroy ( &feat ); data_uuid_destroy( &feat_uuid ); } } static inline void test_data_setup_private_add_features( const test_data_setup_t *this_, data_visible_set_t *io_data_set ) { const uint_fast32_t feat_variant = ( (*this_).variant / TEST_DATA_SETUP_FEAT_SAME_GROUP ) % TEST_DATA_SETUP_FEAT_VARIANTS; uint_fast32_t count = 0; switch ( (*this_).mode ) { default: case TEST_DATA_SETUP_MODE_GOOD_CASES: { count = feat_variant; } break; case TEST_DATA_SETUP_MODE_CHALLENGING_CASES: { count = (2*TEST_DATA_SETUP_FEAT_VARIANTS) + (4*feat_variant); } break; case TEST_DATA_SETUP_MODE_EDGE_CASES: { const uint_fast32_t lifeline_count = data_visible_set_get_feature_count( io_data_set ); count = (feat_variant==0) ? ((DATA_VISIBLE_SET_MAX_FEATURES - lifeline_count)) /* variants wit MAX features */ : ((DATA_VISIBLE_SET_MAX_FEATURES - lifeline_count)/4); /* variants wit MAX/4 features */ } break; } for ( uint_fast32_t index = 0; index < count; index ++ ) { const uint_fast32_t pseudo_random = ((*this_).variant + index)*7; /* = this shall be variable/dynamic but not really random */ const data_feature_type_t feat_type = DATA_FEATURE_TYPE_ARRAY [ pseudo_random % DATA_FEATURE_TYPE_COUNT ]; const char* feature_key = ""; const char* feature_value = ""; const char* feature_description = ""; int32_t list_order; switch ( feat_variant ) { default: case 0: { /* all random */ list_order = pseudo_random; SPREAD_RANGE(list_order); } break; case 1: { /* all extreme */ list_order = ((pseudo_random % 2)==0) ? INT32_MIN : INT32_MAX; } break; case 2: { /* all 5 grid */ list_order = (pseudo_random % 5)*65536; SPREAD_RANGE(list_order); } break; } switch ( (*this_).mode ) { default: case TEST_DATA_SETUP_MODE_GOOD_CASES: { feature_key = ((pseudo_random % 2)==0) ? NARROW_STR : STANDARD_STR; feature_description = NORMAL_DESCRIPTION; feature_value = ((pseudo_random % 2)==0) ? NARROW_STR : STANDARD_STR; } break; case TEST_DATA_SETUP_MODE_CHALLENGING_CASES: { feature_key = ((pseudo_random % 2)==0) ? EMPTY_STR : LONG_NAME; feature_description = NORMAL_DESCRIPTION; feature_value = ((pseudo_random % 2)==0) ? EMPTY_STR : LONG_NAME; } break; case TEST_DATA_SETUP_MODE_EDGE_CASES: { feature_key = ((pseudo_random % 2)==0) ? STANDARD_STR : WIDE_NAME; feature_description = LONG_DESCRIPTION; feature_value = ((pseudo_random % 2)==0) ? EMPTY_STR : WIDE_NAME; } break; } data_uuid_t feat_uuid; data_uuid_init_new( &feat_uuid ); data_feature_t feat; const data_error_t d1_err = data_feature_init( &feat, index+1, /* = feature_id */ feat_type, index+1, /* = classifier_id */ feature_key, feature_value, feature_description, list_order, data_uuid_get_string( &feat_uuid ) ); TEST_ENVIRONMENT_ASSERT_EQUAL_INT ( DATA_ERROR_NONE, d1_err&(~DATA_ERROR_STRING_BUFFER_EXCEEDED) ); const data_error_t d2_err = data_visible_set_append_feature( io_data_set, &feat ); TEST_ENVIRONMENT_ASSERT ( d2_err == DATA_ERROR_NONE ); data_feature_destroy ( &feat ); data_uuid_destroy ( &feat_uuid ); } } static inline void test_data_setup_private_add_relationships( const test_data_setup_t *this_, data_visible_set_t *io_data_set ) { const data_diagram_type_t diag_type = data_diagram_get_diagram_type( data_visible_set_get_diagram_const( io_data_set ) ); const uint_fast32_t rel_variant = ( (*this_).variant / TEST_DATA_SETUP_REL_SAME_GROUP ) % TEST_DATA_SETUP_REL_VARIANTS; uint_fast32_t count = 0; switch ( (*this_).mode ) { default: case TEST_DATA_SETUP_MODE_GOOD_CASES: { count = rel_variant; } break; case TEST_DATA_SETUP_MODE_CHALLENGING_CASES: { count = (2*TEST_DATA_SETUP_REL_VARIANTS) + (4*rel_variant); } break; case TEST_DATA_SETUP_MODE_EDGE_CASES: { count = (rel_variant==0) ? (DATA_VISIBLE_SET_MAX_RELATIONSHIPS) /* variants wit MAX relationships */ : (DATA_VISIBLE_SET_MAX_RELATIONSHIPS/4); /* variants wit MAX/4 relationships */ } break; } for ( uint_fast32_t index = 0; index < count; index ++ ) { const uint_fast32_t pseudo_random_1 = ((*this_).variant + index)*17; /* = this shall be variable/dynamic but not really random */ const uint_fast32_t pseudo_random_2 = ((*this_).variant + index + 8)*19; /* = this shall be variable/dynamic but not really random */ data_relationship_type_t rel_type = DATA_RELATIONSHIP_TYPE_ARRAY [ pseudo_random_1 % DATA_RELATIONSHIP_TYPE_COUNT ]; if ( data_diagram_type_is_interaction( diag_type ) ) { /* in interaction diagrams, most relationships shall be DATA_RELATIONSHIP_TYPE_UML_ASYNC_CALL */ if ((pseudo_random_2 % 4) != 0) { rel_type = DATA_RELATIONSHIP_TYPE_UML_ASYNC_CALL; } } else { /* in non-interaction diagrams, many relationships shall be DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT */ if ((pseudo_random_2 % 4) == 0) { rel_type = DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT; } } const char* relationship_name = ""; const char* relationship_description = ""; int32_t list_order; data_row_id_t from_classifier_row_id = DATA_ROW_ID_VOID; data_row_id_t to_classifier_row_id = DATA_ROW_ID_VOID; data_row_id_t from_feature_row_id = DATA_ROW_ID_VOID; data_row_id_t to_feature_row_id = DATA_ROW_ID_VOID; const uint_fast32_t c_count = data_visible_set_get_visible_classifier_count( io_data_set ); const uint_fast32_t f_count = data_visible_set_get_feature_count( io_data_set ); if (( c_count != 0 )&&( (pseudo_random_1 % 2) == 0 )) { const data_visible_classifier_t *const from_vis_clas = data_visible_set_get_visible_classifier_const( io_data_set, pseudo_random_1 % c_count ); const data_classifier_t *const from_classifier = data_visible_classifier_get_classifier_const( from_vis_clas ); from_classifier_row_id = data_classifier_get_row_id( from_classifier ); } else if ( f_count != 0 ) { const data_feature_t *const from_feature = data_visible_set_get_feature_const( io_data_set, pseudo_random_1 % f_count ); from_feature_row_id = data_feature_get_row_id( from_feature ); from_classifier_row_id = data_feature_get_classifier_row_id( from_feature ); } if (( c_count != 0 )&&( (pseudo_random_2 % 2) == 0 )) { const data_visible_classifier_t *const to_vis_clas = data_visible_set_get_visible_classifier_const( io_data_set, pseudo_random_2 % c_count ); const data_classifier_t *const to_classifier = data_visible_classifier_get_classifier_const( to_vis_clas ); to_classifier_row_id = data_classifier_get_row_id( to_classifier ); } else if ( f_count != 0 ) { const data_feature_t *const to_feature = data_visible_set_get_feature_const( io_data_set, pseudo_random_2 % f_count ); to_feature_row_id = data_feature_get_row_id( to_feature ); to_classifier_row_id = data_feature_get_classifier_row_id( to_feature ); } switch ( rel_variant ) { default: case 0: { /* all random */ list_order = pseudo_random_1; SPREAD_RANGE(list_order); } break; case 1: { /* all extreme */ list_order = ((pseudo_random_1 % 2)==0) ? INT32_MIN : INT32_MAX; } break; case 2: { /* all zero */ list_order = 0; } break; case 3: { /* all 19 grid */ list_order = (pseudo_random_1 % 19)*65536; SPREAD_RANGE(list_order); } break; case 4: { /* all 3 grid */ list_order = (pseudo_random_1 % 3)*65536; SPREAD_RANGE(list_order); } break; case 5: { /* all 5 grid */ list_order = (pseudo_random_1 % 5)*65536; SPREAD_RANGE(list_order); } break; } switch ( (*this_).mode ) { default: case TEST_DATA_SETUP_MODE_GOOD_CASES: { relationship_name = ((pseudo_random_2 % 2)==0) ? NARROW_STR : STANDARD_STR; relationship_description = NORMAL_DESCRIPTION; } break; case TEST_DATA_SETUP_MODE_CHALLENGING_CASES: { relationship_name = ((pseudo_random_2 % 2)==0) ? EMPTY_STR : LONG_NAME; relationship_description = NORMAL_DESCRIPTION; } break; case TEST_DATA_SETUP_MODE_EDGE_CASES: { relationship_name = ((pseudo_random_2 % 2)==0) ? STANDARD_STR : WIDE_NAME; relationship_description = LONG_DESCRIPTION; } break; } data_uuid_t rel_uuid; data_uuid_init_new( &rel_uuid ); data_relationship_t rel; const data_error_t d1_err = data_relationship_init( &rel, index+1, /* = relationship_id */ rel_type, from_classifier_row_id, to_classifier_row_id, relationship_name, relationship_description, list_order, from_feature_row_id, to_feature_row_id, data_uuid_get_string( &rel_uuid ) ); TEST_ENVIRONMENT_ASSERT_EQUAL_INT ( DATA_ERROR_NONE, d1_err&(~DATA_ERROR_STRING_BUFFER_EXCEEDED) ); const data_error_t d2_err = data_visible_set_append_relationship( io_data_set, &rel ); TEST_ENVIRONMENT_ASSERT ( d2_err == DATA_ERROR_NONE ); data_relationship_destroy ( &rel ); data_uuid_destroy ( &rel_uuid ); } } /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/test/unit/000077500000000000000000000000001415120503000203335ustar00rootroot00000000000000crystal-facet-uml-1.34.1/pencil/test/unit/draw_classifier_contour_test.c000066400000000000000000000106461415120503000264570ustar00rootroot00000000000000/* File: draw_classifier_contour_test.c; Copyright and License: see below */ #include "draw_classifier_contour_test.h" #include "draw/draw_classifier_contour.h" #include "data_classifier_type.h" #include "test_assert.h" static void set_up(void); static void tear_down(void); static void test_calc_inner_area_and_back(void); static void test_calc_inner_area_too_small(void); test_suite_t draw_classifier_contour_test_get_list(void) { test_suite_t result; test_suite_init( &result, "draw_classifier_contour_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "test_calc_inner_area_and_back", &test_calc_inner_area_and_back ); test_suite_add_test_case( &result, "test_calc_inner_area_too_small", &test_calc_inner_area_too_small ); return result; } static pencil_size_t pencil_size; static void set_up(void) { pencil_size_init( &pencil_size, 640.0, 480.0 ); } static void tear_down(void) { pencil_size_destroy( &pencil_size ); } static void test_calc_inner_area_and_back(void) { draw_classifier_contour_t contour_calculator; draw_classifier_contour_init( &contour_calculator ); const geometry_rectangle_t outer_bounds_before = { .left = 100.0, .top = 90.0, .width = 110.0, .height = 80.0 }; for ( unsigned int t_idx = 0; t_idx < DATA_CLASSIFIER_TYPE_COUNT; t_idx ++ ) { data_classifier_type_t classifier_type = DATA_CLASSIFIER_TYPE_ARRAY[ t_idx ]; /* printf(" type: %d\n", t_idx); */ const geometry_rectangle_t inner_area = draw_classifier_contour_calc_inner_area( &contour_calculator, classifier_type, &outer_bounds_before, &pencil_size ); TEST_ASSERT( geometry_rectangle_is_containing( &outer_bounds_before, &inner_area ) ); TEST_ASSERT( ! geometry_rectangle_is_empty( &inner_area ) ); const geometry_rectangle_t outer_bounds_after = draw_classifier_contour_calc_outer_bounds( &contour_calculator, classifier_type, &inner_area, &pencil_size ); TEST_ASSERT_EQUAL_DOUBLE( 100.0, geometry_rectangle_get_left( &outer_bounds_after ) ); TEST_ASSERT_EQUAL_DOUBLE( 90.0, geometry_rectangle_get_top( &outer_bounds_after ) ); TEST_ASSERT_EQUAL_DOUBLE( 110.0, geometry_rectangle_get_width( &outer_bounds_after ) ); TEST_ASSERT_EQUAL_DOUBLE( 80.0, geometry_rectangle_get_height( &outer_bounds_after ) ); } draw_classifier_contour_destroy( &contour_calculator ); } static void test_calc_inner_area_too_small(void) { draw_classifier_contour_t contour_calculator; draw_classifier_contour_init( &contour_calculator ); const double gap = pencil_size_get_standard_object_border( &pencil_size ); const geometry_rectangle_t outer_bounds = { .left = 0.0, .top = 0.0, .width = gap, .height = gap }; const data_classifier_type_t classifier_type = DATA_CLASSIFIER_TYPE_USE_CASE; const geometry_rectangle_t inner_area = draw_classifier_contour_calc_inner_area( &contour_calculator, classifier_type, &outer_bounds, &pencil_size ); TEST_ASSERT_EQUAL_DOUBLE( 0.0, geometry_rectangle_get_width( &inner_area ) ); TEST_ASSERT_EQUAL_DOUBLE( 0.0, geometry_rectangle_get_height( &inner_area ) ); draw_classifier_contour_destroy( &contour_calculator ); } /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/test/unit/draw_classifier_contour_test.h000066400000000000000000000016751415120503000264660ustar00rootroot00000000000000/* File: draw_classifier_contour_test.h; Copyright and License: see below */ #ifndef DRAW_CLASSIFIER_CONTOUR_TEST_H #define DRAW_CLASSIFIER_CONTOUR_TEST_H /*! * \file * \brief UNITTEST for draw_classifier_contour */ #include "test_suite.h" test_suite_t draw_classifier_contour_test_get_list(void); #endif /* DRAW_CLASSIFIER_CONTOUR_TEST_H */ /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/test/unit/geometry_connector_test.c000066400000000000000000000503671415120503000254560ustar00rootroot00000000000000/* File: geometry_connector_test.c; Copyright and License: see below */ #include "geometry_connector_test.h" #include "util/geometry/geometry_connector.h" #include "util/geometry/geometry_rectangle.h" #include "test_assert.h" static void set_up(void); static void tear_down(void); static void test_base_methods(void); static void test_bounding_rectangle(void); static void test_intersecting_rectangle_simple(void); static void test_intersecting_rectangle_corner(void); static void test_connector_intersects(void); static void test_calc_waypoint_good(void); static void test_calc_waypoint_zero(void); test_suite_t geometry_connector_test_get_list(void) { test_suite_t result; test_suite_init( &result, "geometry_connector_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "test_base_methods", &test_base_methods ); test_suite_add_test_case( &result, "test_bounding_rectangle", &test_bounding_rectangle ); test_suite_add_test_case( &result, "test_intersecting_rectangle_simple", &test_intersecting_rectangle_simple ); test_suite_add_test_case( &result, "test_intersecting_rectangle_corner", &test_intersecting_rectangle_corner ); test_suite_add_test_case( &result, "test_connector_intersects", &test_connector_intersects ); test_suite_add_test_case( &result, "test_calc_waypoint_good", &test_calc_waypoint_good ); test_suite_add_test_case( &result, "test_calc_waypoint_zero", &test_calc_waypoint_zero ); return result; } static void set_up(void) { } static void tear_down(void) { } static void test_base_methods(void) { geometry_connector_t my_connector; geometry_connector_init_empty( &my_connector ); /* init 3 segments line */ geometry_connector_reinit_vertical ( &my_connector, 10.0 /*source_end_x*/, 10.0 /*source_end_y*/, 30.0 /*destination_end_x*/, 30.0 /*destination_end_y*/, 20.0 /*main_line_x*/ ); TEST_ASSERT_EQUAL_DOUBLE( 40.0, geometry_connector_get_length( &my_connector ) ); TEST_ASSERT_EQUAL_INT( true, geometry_connector_is_close( &my_connector, 21.0, 9.0, 1.5 /* max_distance */ ) ); TEST_ASSERT_EQUAL_INT( false, geometry_connector_is_close( &my_connector, 21.0, 9.0, 0.5 /* max_distance */ ) ); /* init 1 segment line */ geometry_connector_reinit_vertical ( &my_connector, 10.0 /*source_end_x*/, 10.0 /*source_end_y*/, 10.0 /*destination_end_x*/, 30.0 /*destination_end_y*/, 10.0 /*main_line_x*/ ); TEST_ASSERT_EQUAL_DOUBLE( 20.0, geometry_connector_get_length( &my_connector ) ); TEST_ASSERT_EQUAL_INT( true, geometry_connector_is_close( &my_connector, 9.0, 20.0, 1.5 /* max_distance */ ) ); TEST_ASSERT_EQUAL_INT( false, geometry_connector_is_close( &my_connector, 10.0, 8.0, 1.5 /* max_distance */ ) ); geometry_connector_destroy ( &my_connector ); } static void test_bounding_rectangle(void) { geometry_connector_t my_connector; geometry_rectangle_t bounds; /* init 3 segments line, Z-Form */ geometry_connector_init_vertical ( &my_connector, 10.0 /*source_end_x*/, 10.0 /*source_end_y*/, 30.0 /*destination_end_x*/, 30.0 /*destination_end_y*/, 20.0 /*main_line_x*/ ); bounds = geometry_connector_get_bounding_rectangle ( &my_connector ); TEST_ASSERT_EQUAL_DOUBLE( 400.0, geometry_rectangle_get_area( &bounds ) ); geometry_rectangle_destroy ( &bounds ); /* init 3 segments line, U-Form */ geometry_connector_reinit_horizontal ( &my_connector, 10.0 /*source_end_x*/, 30.0 /*source_end_y*/, 30.0 /*destination_end_x*/, 30.0 /*destination_end_y*/, 10.0 /*main_line_y*/ ); bounds = geometry_connector_get_bounding_rectangle ( &my_connector ); TEST_ASSERT_EQUAL_DOUBLE( 400.0, geometry_rectangle_get_area( &bounds ) ); geometry_rectangle_destroy ( &bounds ); /* init 1 segment line */ geometry_connector_reinit_vertical ( &my_connector, 10.0 /*source_end_x*/, 10.0 /*source_end_y*/, 10.0 /*destination_end_x*/, 30.0 /*destination_end_y*/, 10.0 /*main_line_x*/ ); bounds = geometry_connector_get_bounding_rectangle ( &my_connector ); TEST_ASSERT_EQUAL_DOUBLE( 0.0, geometry_rectangle_get_area( &bounds ) ); geometry_rectangle_destroy ( &bounds ); geometry_connector_destroy ( &my_connector ); } static void test_intersecting_rectangle_simple(void) { geometry_connector_t my_connector; geometry_rectangle_t overlap; bool intersects; /* init 3 segments line, Z-Form */ geometry_connector_init_vertical ( &my_connector, 10.0 /*source_end_x*/, 10.0 /*source_end_y*/, 30.0 /*destination_end_x*/, 30.0 /*destination_end_y*/, 20.0 /*main_line_x*/ ); geometry_rectangle_init( &overlap, 19.0, 19.0, 5.0 /*W*/, 5.0 /*H*/ ); intersects = geometry_connector_is_intersecting_rectangle( &my_connector, &overlap ); TEST_ASSERT_EQUAL_INT( true, intersects ); geometry_rectangle_destroy ( &overlap ); /* init 3 segments line, U-Form */ geometry_connector_reinit_horizontal ( &my_connector, 10.0 /*source_end_x*/, 30.0 /*source_end_y*/, 30.0 /*destination_end_x*/, 30.0 /*destination_end_y*/, 10.0 /*main_line_y*/ ); geometry_rectangle_init( &overlap, 11.0, 11.0, 18.0 /*W*/, 25.0 /*H*/ ); intersects = geometry_connector_is_intersecting_rectangle( &my_connector, &overlap ); TEST_ASSERT_EQUAL_INT( false, intersects ); geometry_rectangle_destroy ( &overlap ); /* init 1 segment line */ geometry_connector_reinit_vertical ( &my_connector, 10.0 /*source_end_x*/, 10.0 /*source_end_y*/, 10.0 /*destination_end_x*/, 30.0 /*destination_end_y*/, 10.0 /*main_line_x*/ ); geometry_rectangle_init( &overlap, 9.0, 11.0, 10.0 /*W*/, 10.0 /*H*/ ); intersects = geometry_connector_is_intersecting_rectangle( &my_connector, &overlap ); TEST_ASSERT_EQUAL_INT( true, intersects ); geometry_rectangle_destroy ( &overlap ); geometry_connector_destroy ( &my_connector ); } static void test_intersecting_rectangle_corner(void) { geometry_connector_t my_connector; geometry_rectangle_t touching; bool intersects; /* init 3 segments line, Z-Form */ geometry_connector_init_vertical ( &my_connector, 10.0 /*source_end_x*/, 10.0 /*source_end_y*/, 30.0 /*destination_end_x*/, 30.0 /*destination_end_y*/, 20.0 /*main_line_x*/ ); /* touch source end */ geometry_rectangle_init( &touching, 9.0, 9.0, 1.0 /*W*/, 2.0 /*H*/ ); intersects = geometry_connector_is_intersecting_rectangle( &my_connector, &touching ); TEST_ASSERT_EQUAL_INT( false, intersects ); /* touch source end by 0-width */ geometry_rectangle_init( &touching, 10.0, 9.0, 0.0 /*W*/, 2.0 /*H*/ ); intersects = geometry_connector_is_intersecting_rectangle( &my_connector, &touching ); TEST_ASSERT_EQUAL_INT( false, intersects ); /* touch destination end */ geometry_rectangle_reinit( &touching, 30.0, 29.0, 1.0 /*W*/, 2.0 /*H*/ ); intersects = geometry_connector_is_intersecting_rectangle( &my_connector, &touching ); TEST_ASSERT_EQUAL_INT( false, intersects ); /* touch main line */ geometry_rectangle_reinit( &touching, 20.0, 9.0, 1.0 /*W*/, 21.0 /*H*/ ); intersects = geometry_connector_is_intersecting_rectangle( &my_connector, &touching ); TEST_ASSERT_EQUAL_INT( false, intersects ); /* init 1 segment line */ geometry_connector_reinit_vertical ( &my_connector, 10.0 /*source_end_x*/, 10.0 /*source_end_y*/, 10.0 /*destination_end_x*/, 30.0 /*destination_end_y*/, 10.0 /*main_line_x*/ ); /* touch source end */ geometry_rectangle_reinit( &touching, 9.0, 9.0, 2.0 /*W*/, 1.0 /*H*/ ); intersects = geometry_connector_is_intersecting_rectangle( &my_connector, &touching ); TEST_ASSERT_EQUAL_INT( false, intersects ); /* touch destination end */ geometry_rectangle_reinit( &touching, 9.0, 30.0, 2.0 /*W*/, 1.0 /*H*/ ); intersects = geometry_connector_is_intersecting_rectangle( &my_connector, &touching ); TEST_ASSERT_EQUAL_INT( false, intersects ); /* touch destination end by 0-height */ geometry_rectangle_reinit( &touching, 9.0, 30.0, 2.0 /*W*/, 0.0 /*H*/ ); intersects = geometry_connector_is_intersecting_rectangle( &my_connector, &touching ); TEST_ASSERT_EQUAL_INT( false, intersects ); geometry_rectangle_destroy ( &touching ); geometry_connector_destroy ( &my_connector ); } static void test_connector_intersects(void) { geometry_connector_t my_connector_1; geometry_connector_t my_connector_2; uint32_t intersect_count; /* double empty */ geometry_connector_init_empty( &my_connector_1 ); geometry_connector_init_empty( &my_connector_2 ); intersect_count = geometry_connector_count_connector_intersects ( &my_connector_1, &my_connector_2 ); TEST_ASSERT_EQUAL_INT( 9, intersect_count ); geometry_connector_destroy ( &my_connector_1 ); geometry_connector_destroy ( &my_connector_2 ); /* completely separated */ geometry_connector_init_vertical ( &my_connector_1, 10.0 /*source_end_x*/, 10.0 /*source_end_y*/, 10.0 /*destination_end_x*/, 30.0 /*destination_end_y*/, 20.0 /*main_line_x*/ ); geometry_connector_init_vertical ( &my_connector_2, 40.0 /*source_end_x*/, 10.0 /*source_end_y*/, 40.0 /*destination_end_x*/, 30.0 /*destination_end_y*/, 50.0 /*main_line_x*/ ); intersect_count = geometry_connector_count_connector_intersects ( &my_connector_1, &my_connector_2 ); TEST_ASSERT_EQUAL_INT( 0, intersect_count ); geometry_connector_destroy ( &my_connector_1 ); geometry_connector_destroy ( &my_connector_2 ); /* close but not overlapping */ geometry_connector_init_horizontal ( &my_connector_1, 10.0 /*source_end_x*/, 30.0 /*source_end_y*/, 30.0 /*destination_end_x*/, 30.0 /*destination_end_y*/, 10.0 /*main_line_y*/ ); geometry_connector_init_horizontal ( &my_connector_2, 15.0 /*source_end_x*/, 30.0 /*source_end_y*/, 25.0 /*destination_end_x*/, 30.0 /*destination_end_y*/, 11.0 /*main_line_y*/ ); intersect_count = geometry_connector_count_connector_intersects ( &my_connector_1, &my_connector_2 ); TEST_ASSERT_EQUAL_INT( 0, intersect_count ); geometry_connector_destroy ( &my_connector_1 ); geometry_connector_destroy ( &my_connector_2 ); /* 2x touching but not overlapping */ geometry_connector_init_horizontal ( &my_connector_1, 10.0 /*source_end_x*/, 10.0 /*source_end_y*/, 30.0 /*destination_end_x*/, 10.0 /*destination_end_y*/, 20.0 /*main_line_y*/ ); geometry_connector_init_horizontal ( &my_connector_2, 15.0 /*source_end_x*/, 20.0 /*source_end_y*/, 25.0 /*destination_end_x*/, 20.0 /*destination_end_y*/, 10.0 /*main_line_y*/ ); intersect_count = geometry_connector_count_connector_intersects ( &my_connector_1, &my_connector_2 ); TEST_ASSERT_EQUAL_INT( 2, intersect_count ); geometry_connector_destroy ( &my_connector_1 ); geometry_connector_destroy ( &my_connector_2 ); /* 2 segments identical, 1 empty */ geometry_connector_init_horizontal ( &my_connector_1, 10.0 /*source_end_x*/, 10.0 /*source_end_y*/, 30.0 /*destination_end_x*/, 20.0 /*destination_end_y*/, 20.0 /*main_line_y*/ ); geometry_connector_replace ( &my_connector_2, &my_connector_1 ); intersect_count = geometry_connector_count_connector_intersects ( &my_connector_1, &my_connector_2 ); TEST_ASSERT_EQUAL_INT( 7, intersect_count ); geometry_connector_destroy ( &my_connector_1 ); geometry_connector_destroy ( &my_connector_2 ); /* three real intersects */ geometry_connector_init_horizontal ( &my_connector_1, 10.0 /*source_end_x*/, 10.0 /*source_end_y*/, 30.0 /*destination_end_x*/, 12.0 /*destination_end_y*/, 20.0 /*main_line_y*/ ); geometry_connector_init_vertical ( &my_connector_2, 5.0 /*source_end_x*/, 11.0 /*source_end_y*/, 5.0 /*destination_end_x*/, 19.0 /*destination_end_y*/, 40.0 /*main_line_x*/ ); intersect_count = geometry_connector_count_connector_intersects ( &my_connector_1, &my_connector_2 ); TEST_ASSERT_EQUAL_INT( 3, intersect_count ); geometry_connector_destroy ( &my_connector_1 ); geometry_connector_destroy ( &my_connector_2 ); } static void test_calc_waypoint_good(void) { geometry_connector_t my_connector_1; geometry_connector_init_vertical ( &my_connector_1, 10.0 /*source_end_x*/, 10.0 /*source_end_y*/, 10.0 /*destination_end_x*/, 30.0 /*destination_end_y*/, 20.0 /*main_line_x*/ ); geometry_point_t pos_before = geometry_connector_calculate_waypoint( &my_connector_1, -0.1 ); TEST_ASSERT_EQUAL_DOUBLE( 10.0, geometry_point_get_x( &pos_before ) ); TEST_ASSERT_EQUAL_DOUBLE( 10.0, geometry_point_get_y( &pos_before ) ); geometry_point_t pos_first = geometry_connector_calculate_waypoint( &my_connector_1, 1.0 ); TEST_ASSERT_EQUAL_DOUBLE( 11.0, geometry_point_get_x( &pos_first ) ); TEST_ASSERT_EQUAL_DOUBLE( 10.0, geometry_point_get_y( &pos_first ) ); geometry_point_t pos_main = geometry_connector_calculate_waypoint( &my_connector_1, 29.0 ); TEST_ASSERT_EQUAL_DOUBLE( 20.0, geometry_point_get_x( &pos_main ) ); TEST_ASSERT_EQUAL_DOUBLE( 29.0, geometry_point_get_y( &pos_main ) ); geometry_point_t pos_third = geometry_connector_calculate_waypoint( &my_connector_1, 39.0 ); TEST_ASSERT_EQUAL_DOUBLE( 11.0, geometry_point_get_x( &pos_third ) ); TEST_ASSERT_EQUAL_DOUBLE( 30.0, geometry_point_get_y( &pos_third ) ); geometry_point_t pos_after = geometry_connector_calculate_waypoint( &my_connector_1, 40.1 ); TEST_ASSERT_EQUAL_DOUBLE( 10.0, geometry_point_get_x( &pos_after ) ); TEST_ASSERT_EQUAL_DOUBLE( 30.0, geometry_point_get_y( &pos_after ) ); } static void test_calc_waypoint_zero(void) { geometry_connector_t my_connector_2; /* main line length = 0 */ geometry_connector_t my_connector_3; /* srd+dest end line length = 0 */ geometry_connector_init_horizontal ( &my_connector_2, 10.0 /*source_end_x*/, 10.0 /*source_end_y*/, 10.0 /*destination_end_x*/, 10.0 /*destination_end_y*/, 20.0 /*main_line_y*/ ); geometry_connector_init_horizontal ( &my_connector_3, 10.0 /*source_end_x*/, 10.0 /*source_end_y*/, 20.0 /*destination_end_x*/, 10.0 /*destination_end_y*/, 10.0 /*main_line_y*/ ); geometry_point_t pos3_source = geometry_connector_calculate_waypoint( &my_connector_3, 0.0 ); TEST_ASSERT_EQUAL_DOUBLE( 10.0, geometry_point_get_x( &pos3_source ) ); TEST_ASSERT_EQUAL_DOUBLE( 10.0, geometry_point_get_y( &pos3_source ) ); geometry_point_t pos2_main = geometry_connector_calculate_waypoint( &my_connector_2, 10.0 ); TEST_ASSERT_EQUAL_DOUBLE( 10.0, geometry_point_get_x( &pos2_main ) ); TEST_ASSERT_EQUAL_DOUBLE( 20.0, geometry_point_get_y( &pos2_main ) ); geometry_point_t pos3_dest = geometry_connector_calculate_waypoint( &my_connector_3, 10.0 ); TEST_ASSERT_EQUAL_DOUBLE( 20.0, geometry_point_get_x( &pos3_dest ) ); TEST_ASSERT_EQUAL_DOUBLE( 10.0, geometry_point_get_y( &pos3_dest ) ); } /* * Copyright 2017-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/test/unit/geometry_connector_test.h000066400000000000000000000016371415120503000254570ustar00rootroot00000000000000/* File: geometry_connector_test.h; Copyright and License: see below */ #ifndef GEOMETRY_CONNECTOR_TEST_H #define GEOMETRY_CONNECTOR_TEST_H /*! * \file * \brief UNITTEST for geometry_connector */ #include "test_suite.h" test_suite_t geometry_connector_test_get_list(void); #endif /* GEOMETRY_CONNECTOR_TEST_H */ /* * Copyright 2017-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/test/unit/geometry_non_linear_scale_test.c000066400000000000000000000047641415120503000267570ustar00rootroot00000000000000/* File: geometry_non_linear_scale_test.c; Copyright and License: see below */ #include "geometry_non_linear_scale_test.h" #include "util/geometry/geometry_non_linear_scale.h" #include "test_assert.h" static void set_up(void); static void tear_down(void); static void test_scale_conversion(void); test_suite_t geometry_non_linear_scale_test_get_list(void) { test_suite_t result; test_suite_init( &result, "geometry_non_linear_scale_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "test_scale_conversion", &test_scale_conversion ); return result; } static void set_up(void) { } static void tear_down(void) { } static void test_scale_conversion(void) { geometry_non_linear_scale_t my_scale; double location; int32_t order; /* init and trace */ geometry_non_linear_scale_init ( &my_scale, -3.14, 3.14 ); geometry_non_linear_scale_add_order( &my_scale, -100 ); geometry_non_linear_scale_add_order( &my_scale, 200 ); geometry_non_linear_scale_add_order( &my_scale, 200 ); geometry_non_linear_scale_trace ( &my_scale ); /* test get_location */ location = geometry_non_linear_scale_get_location( &my_scale, +200 ); TEST_ASSERT( ( +1.0 < location ) && ( location < +1.1 ) ); location = geometry_non_linear_scale_get_location( &my_scale, +100 ); TEST_ASSERT( ( +0.3 < location ) && ( location < +0.4 ) ); /* test get_order with snap */ order = geometry_non_linear_scale_get_order ( &my_scale, -3.1, 0.1 ); TEST_ASSERT_EQUAL_INT( INT32_MIN, order ); /* test get_order without snap */ order = geometry_non_linear_scale_get_order ( &my_scale, -3.1, 0.01 ); TEST_ASSERT( ( INT32_MIN < order ) && ( order < -1000000000 ) ); order = geometry_non_linear_scale_get_order ( &my_scale, -1.0, 0.01 ); TEST_ASSERT( ( -100 < order ) && ( order < -80 ) ); geometry_non_linear_scale_destroy ( &my_scale ); } /* * Copyright 2016-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/test/unit/geometry_non_linear_scale_test.h000066400000000000000000000017111415120503000267510ustar00rootroot00000000000000/* File: geometry_non_linear_scale_test.h; Copyright and License: see below */ #ifndef GEOMETRY_NON_LINEAR_SCALE_TEST_H #define GEOMETRY_NON_LINEAR_SCALE_TEST_H /*! * \file * \brief UNITTEST for geometry_non_linear_scale */ #include "test_suite.h" test_suite_t geometry_non_linear_scale_test_get_list(void); #endif /* GEOMETRY_NON_LINEAR_SCALE_TEST_H */ /* * Copyright 2016-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/test/unit/geometry_rectangle_test.c000066400000000000000000000425511415120503000254240ustar00rootroot00000000000000/* File: geometry_rectangle_test.c; Copyright and License: see below */ #include "geometry_rectangle_test.h" #include "util/geometry/geometry_rectangle.h" #include "test_assert.h" static void set_up(void); static void tear_down(void); static void test_contain(void); static void test_intersect(void); static void test_bounds(void); static void test_difference_basic(void); static void test_difference_4_candidates(void); static void test_difference_3_candidates(void); static void test_difference_2_corner_candidates(void); static void test_difference_2_stripe_candidates(void); static void test_difference_1_candidate(void); static void test_expand_4d(void); test_suite_t geometry_rectangle_test_get_list(void) { test_suite_t result; test_suite_init( &result, "geometry_rectangle_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "test_contain", &test_contain ); test_suite_add_test_case( &result, "test_intersect", &test_intersect ); test_suite_add_test_case( &result, "test_bounds", &test_bounds ); test_suite_add_test_case( &result, "test_difference_basic", &test_difference_basic ); test_suite_add_test_case( &result, "test_difference_4_candidates", &test_difference_4_candidates ); test_suite_add_test_case( &result, "test_difference_3_candidates", &test_difference_3_candidates ); test_suite_add_test_case( &result, "test_difference_2_corner_candidates", &test_difference_2_corner_candidates ); test_suite_add_test_case( &result, "test_difference_2_stripe_candidates", &test_difference_2_stripe_candidates ); test_suite_add_test_case( &result, "test_difference_1_candidate", &test_difference_1_candidate ); test_suite_add_test_case( &result, "test_expand_4d", &test_expand_4d ); return result; } static void set_up(void) { } static void tear_down(void) { } static void test_contain(void) { geometry_rectangle_t rect_a; geometry_rectangle_t rect_b; bool contains; /* no contain */ geometry_rectangle_init ( &rect_a, 10.0, 10.0, 10.0 /*width*/, 10.0 /*height*/ ); geometry_rectangle_init ( &rect_b, 11.0, 11.0, 11.0 /*width*/, 11.0 /*height*/ ); contains = geometry_rectangle_is_containing( &rect_a, &rect_b ); TEST_ASSERT_EQUAL_INT( false, contains ); contains = geometry_rectangle_is_containing( &rect_b, &rect_a ); TEST_ASSERT_EQUAL_INT( false, contains ); /* clean up */ geometry_rectangle_destroy ( &rect_a ); geometry_rectangle_destroy ( &rect_b ); /* contain */ geometry_rectangle_init ( &rect_a, 10.0, 10.0, 10.0 /*width*/, 10.0 /*height*/ ); geometry_rectangle_init ( &rect_b, 10.0, 11.0, 9.0 /*width*/, 9.0 /*height*/ ); contains = geometry_rectangle_is_containing( &rect_a, &rect_b ); TEST_ASSERT_EQUAL_INT( true, contains ); contains = geometry_rectangle_is_containing( &rect_b, &rect_a ); TEST_ASSERT_EQUAL_INT( false, contains ); contains = geometry_rectangle_contains( &rect_a, 9.0, 9.0 ); TEST_ASSERT_EQUAL_INT( false, contains ); contains = geometry_rectangle_contains( &rect_a, 19.0, 19.0 ); TEST_ASSERT_EQUAL_INT( true, contains ); /* clean up */ geometry_rectangle_destroy ( &rect_a ); geometry_rectangle_destroy ( &rect_b ); } static void test_intersect(void) { geometry_rectangle_t rect_a; geometry_rectangle_t rect_b; geometry_rectangle_t intersect_rect; int err; bool intersects; /* no intersect */ geometry_rectangle_init ( &rect_a, 10.0, 10.0, 10.0 /*width*/, 10.0 /*height*/ ); geometry_rectangle_init ( &rect_b, 10.0, 21.0, 10.0 /*width*/, 10.0 /*height*/ ); err = geometry_rectangle_init_by_intersect( &intersect_rect, &rect_a, &rect_b ); TEST_ASSERT_EQUAL_INT( -1, err ); TEST_ASSERT_EQUAL_DOUBLE( 0.0, geometry_rectangle_get_area( &intersect_rect ) ); intersects = geometry_rectangle_is_intersecting( &rect_a, &rect_b ); TEST_ASSERT_EQUAL_INT( false, intersects ); /* clean up */ geometry_rectangle_destroy ( &rect_a ); geometry_rectangle_destroy ( &rect_b ); geometry_rectangle_destroy ( &intersect_rect ); /* touch */ geometry_rectangle_init ( &rect_a, 10.0, 10.0, 10.0 /*width*/, 10.0 /*height*/ ); geometry_rectangle_init ( &rect_b, 20.0, 10.0, 10.0 /*width*/, 10.0 /*height*/ ); err = geometry_rectangle_init_by_intersect( &intersect_rect, &rect_a, &rect_b ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_DOUBLE( 0.0, geometry_rectangle_get_area( &intersect_rect ) ); intersects = geometry_rectangle_is_intersecting( &rect_a, &rect_b ); TEST_ASSERT_EQUAL_INT( false, intersects ); intersects = geometry_rectangle_is_contiguous( &rect_a, &rect_b ); TEST_ASSERT_EQUAL_INT( true, intersects ); /* clean up */ geometry_rectangle_destroy ( &rect_a ); geometry_rectangle_destroy ( &rect_b ); geometry_rectangle_destroy ( &intersect_rect ); /* part intersect */ geometry_rectangle_init ( &rect_a, 10.0, 10.0, 10.0 /*width*/, 10.0 /*height*/ ); geometry_rectangle_init ( &rect_b, 15.0, 15.0, 10.0 /*width*/, 10.0 /*height*/ ); err = geometry_rectangle_init_by_intersect( &intersect_rect, &rect_a, &rect_b ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_DOUBLE( 25.0, geometry_rectangle_get_area( &intersect_rect ) ); intersects = geometry_rectangle_is_intersecting( &rect_a, &rect_b ); TEST_ASSERT_EQUAL_INT( true, intersects ); /* clean up */ geometry_rectangle_destroy ( &rect_a ); geometry_rectangle_destroy ( &rect_b ); geometry_rectangle_destroy ( &intersect_rect ); /* full contained */ geometry_rectangle_init ( &rect_a, 10.0, 10.0, 20.0 /*width*/, 20.0 /*height*/ ); geometry_rectangle_init ( &rect_b, 15.0, 15.0, 10.0 /*width*/, 10.0 /*height*/ ); err = geometry_rectangle_init_by_intersect( &intersect_rect, &rect_a, &rect_b ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_DOUBLE( 100.0, geometry_rectangle_get_area( &intersect_rect ) ); intersects = geometry_rectangle_is_intersecting( &rect_a, &rect_b ); TEST_ASSERT_EQUAL_INT( true, intersects ); /* clean up */ geometry_rectangle_destroy ( &rect_a ); geometry_rectangle_destroy ( &rect_b ); geometry_rectangle_destroy ( &intersect_rect ); } static void test_bounds(void) { geometry_rectangle_t rect_a; geometry_rectangle_t rect_b; geometry_rectangle_t bounds_rect; int err; /* part intersect */ geometry_rectangle_init ( &rect_a, 10.0, 10.0, 10.0 /*width*/, 10.0 /*height*/ ); geometry_rectangle_init ( &rect_b, 18.0, 12.0, 10.0 /*width*/, 10.0 /*height*/ ); err = geometry_rectangle_init_by_bounds( &bounds_rect, &rect_a, &rect_b ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_DOUBLE( 10.0, geometry_rectangle_get_left( &bounds_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 28.0, geometry_rectangle_get_right( &bounds_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 10.0, geometry_rectangle_get_top( &bounds_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 22.0, geometry_rectangle_get_bottom( &bounds_rect ) ); /* clean up */ geometry_rectangle_destroy ( &rect_a ); geometry_rectangle_destroy ( &rect_b ); geometry_rectangle_destroy ( &bounds_rect ); } static void test_difference_basic(void) { geometry_rectangle_t rect_a; geometry_rectangle_t rect_b; geometry_rectangle_t diff_rect; /* no intersect */ { geometry_rectangle_init ( &rect_a, 9.0, 10.0, 1.0 /*width*/, 90.0 /*height*/ ); geometry_rectangle_init ( &rect_b, 11.0, 20.0, 10.0 /*width*/, 10.0 /*height*/ ); geometry_rectangle_init_by_difference( &diff_rect, &rect_a, &rect_b ); TEST_ASSERT_EQUAL_DOUBLE( 9.0, geometry_rectangle_get_left( &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 10.0, geometry_rectangle_get_top( &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 1.0, geometry_rectangle_get_width( &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 90.0, geometry_rectangle_get_height( &diff_rect ) ); /* clean up */ geometry_rectangle_destroy ( &rect_a ); geometry_rectangle_destroy ( &rect_b ); geometry_rectangle_destroy ( &diff_rect ); } /* part intersect */ { geometry_rectangle_init ( &rect_a, 9.0, 10.0, 1.0 /*width*/, 90.0 /*height*/ ); geometry_rectangle_init ( &rect_b, 8.0, 11.0, 1.5 /*width*/, 1.0 /*height*/ ); geometry_rectangle_init_by_difference( &diff_rect, &rect_a, &rect_b ); TEST_ASSERT_EQUAL_DOUBLE( 9.0, geometry_rectangle_get_left( &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 12.0, geometry_rectangle_get_top( &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 1.0, geometry_rectangle_get_width( &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 88.0, geometry_rectangle_get_height( &diff_rect ) ); /* clean up */ geometry_rectangle_destroy ( &rect_a ); geometry_rectangle_destroy ( &rect_b ); geometry_rectangle_destroy ( &diff_rect ); } /* full contained */ { geometry_rectangle_init ( &rect_a, 9.0, 10.0, 1.0 /*width*/, 90.0 /*height*/ ); geometry_rectangle_init ( &rect_b, 8.0, 9.0, 3.0 /*width*/, 92.0 /*height*/ ); geometry_rectangle_init_by_difference( &diff_rect, &rect_a, &rect_b ); TEST_ASSERT_EQUAL_DOUBLE( 9.0, geometry_rectangle_get_left( &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 10.0, geometry_rectangle_get_top( &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 0.0, geometry_rectangle_get_width( &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 0.0, geometry_rectangle_get_height( &diff_rect ) ); /* clean up */ geometry_rectangle_destroy ( &rect_a ); geometry_rectangle_destroy ( &rect_b ); geometry_rectangle_destroy ( &diff_rect ); } } static void test_difference_4_candidates(void) { geometry_rectangle_t rect_a; geometry_rectangle_t rect_b; geometry_rectangle_t diff_rect; /* no intersect */ double in_x[4] = { 1.0, 2.0, 3.0, 2.0 }; double in_y[4] = { 2.0, 3.0, 2.0, 1.0 }; for ( int case_idx = 0; case_idx < 4; case_idx ++ ) { geometry_rectangle_init ( &rect_a, 0.0, 0.0, 5.0 /*width*/, 5.0 /*height*/ ); geometry_rectangle_init ( &rect_b, in_x[case_idx], in_y[case_idx], 1.0 /*width*/, 1.0 /*height*/ ); geometry_rectangle_init_by_difference( &diff_rect, &rect_a, &rect_b ); //geometry_rectangle_trace( &rect_a ); //geometry_rectangle_trace( &rect_b ); //geometry_rectangle_trace( &diff_rect ); TEST_ASSERT( geometry_rectangle_is_containing( &rect_a, &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 0.0, geometry_rectangle_get_intersect_area( &rect_b, &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 15.0, geometry_rectangle_get_area( &diff_rect ) ); geometry_rectangle_destroy ( &rect_a ); geometry_rectangle_destroy ( &rect_b ); geometry_rectangle_destroy ( &diff_rect ); } } static void test_difference_3_candidates(void) { geometry_rectangle_t rect_a; geometry_rectangle_t rect_b; geometry_rectangle_t diff_rect; /* from left from bottom from right from top */ double in_x[12] = { 0.0, 0.0, 0.0, 2.0, 4.5, 7.0, 2.0, 7.0, 2.0, 2.0, 4.5, 7.0 }; double in_y[12] = { 2.0, 4.5, 7.0, 2.0, 7.0, 2.0, 2.0, 4.5, 7.0, 0.0, 0.0, 0.0 }; double in_w[12] = { 8.0, 3.0, 8.0, 1.0, 1.0, 1.0, 8.0, 3.0, 8.0, 1.0, 1.0, 1.0 }; double in_h[12] = { 1.0, 1.0, 1.0, 8.0, 3.0, 8.0, 1.0, 1.0, 1.0, 8.0, 3.0, 8.0 }; for ( int case_idx = 0; case_idx < 12; case_idx ++ ) { geometry_rectangle_init ( &rect_a, 1.0, 1.0, 8.0 /*width*/, 8.0 /*height*/ ); geometry_rectangle_init ( &rect_b, in_x[case_idx], in_y[case_idx], in_w[case_idx], in_h[case_idx] ); geometry_rectangle_init_by_difference( &diff_rect, &rect_a, &rect_b ); TEST_ASSERT( geometry_rectangle_is_containing( &rect_a, &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 0.0, geometry_rectangle_get_intersect_area( &rect_b, &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 48.0, geometry_rectangle_get_area( &diff_rect ) ); geometry_rectangle_destroy ( &rect_a ); geometry_rectangle_destroy ( &rect_b ); geometry_rectangle_destroy ( &diff_rect ); } } /* 0 1 2 3 4 5 6 7 8 9 10 */ /* 0 . . . . . . . . . . */ /* 1 . . . . . . . . . . */ /* 2 . . . . . . . . . . */ /* 3 . . . _ _ _ _ . . . */ /* 4 . . . _ _ _ _ . . . */ /* 5 . . . _ _ _ _ . . . */ /* 6 . . . _ _ _ _ . . . */ /* 7 . . . . . . . . . . */ /* 8 . . . . . . . . . . */ /* 9 . . . . . . . . . . */ /* 10 */ static void test_difference_2_corner_candidates(void) { geometry_rectangle_t rect_a; geometry_rectangle_t rect_b; geometry_rectangle_t diff_rect; /* le.to. ri.to. ri.bo. le.bo. */ double in_x[8] = { 2.0, 1.0, 5.0, 6.0, 6.0, 5.0, 6.0, 1.0 }; double in_y[8] = { 1.0, 2.0, 1.0, 2.0, 5.0, 6.0, 2.0, 5.0 }; for ( int case_idx = 0; case_idx < 8; case_idx ++ ) { geometry_rectangle_init ( &rect_a, 3.0, 3.0, 4.0 /*width*/, 4.0 /*height*/ ); geometry_rectangle_init ( &rect_b, in_x[case_idx], in_y[case_idx], 3.0, 3.0 ); geometry_rectangle_init_by_difference( &diff_rect, &rect_a, &rect_b ); TEST_ASSERT( geometry_rectangle_is_containing( &rect_a, &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 0.0, geometry_rectangle_get_intersect_area( &rect_b, &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 12.0, geometry_rectangle_get_area( &diff_rect ) ); geometry_rectangle_destroy ( &rect_a ); geometry_rectangle_destroy ( &rect_b ); geometry_rectangle_destroy ( &diff_rect ); } } static void test_difference_2_stripe_candidates(void) { geometry_rectangle_t rect_a; geometry_rectangle_t rect_b; geometry_rectangle_t diff_rect; /* vertical horizontal */ double in_x[4] = { 4.0, 5.0, 1.0, 1.0 }; double in_y[4] = { 1.0, 1.0, 4.0, 5.0 }; double in_w[4] = { 1.0, 1.0, 8.0, 8.0 }; double in_h[4] = { 8.0, 8.0, 1.0, 1.0 }; for ( int case_idx = 0; case_idx < 4; case_idx ++ ) { geometry_rectangle_init ( &rect_a, 3.0, 3.0, 4.0 /*width*/, 4.0 /*height*/ ); geometry_rectangle_init ( &rect_b, in_x[case_idx], in_y[case_idx], in_w[case_idx], in_h[case_idx] ); geometry_rectangle_init_by_difference( &diff_rect, &rect_a, &rect_b ); TEST_ASSERT( geometry_rectangle_is_containing( &rect_a, &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 0.0, geometry_rectangle_get_intersect_area( &rect_b, &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 8.0, geometry_rectangle_get_area( &diff_rect ) ); geometry_rectangle_destroy ( &rect_a ); geometry_rectangle_destroy ( &rect_b ); geometry_rectangle_destroy ( &diff_rect ); } } static void test_difference_1_candidate(void) { geometry_rectangle_t rect_a; geometry_rectangle_t rect_b; geometry_rectangle_t diff_rect; double in_x[4] = { 1.0, 3.0, 5.0, 3.0 }; double in_y[4] = { 3.0, 5.0, 3.0, 1.0 }; for ( int case_idx = 0; case_idx < 4; case_idx ++ ) { geometry_rectangle_init ( &rect_a, 4.0, 4.0, 2.0 /*width*/, 2.0 /*height*/ ); geometry_rectangle_init ( &rect_b, in_x[case_idx], in_y[case_idx], 4.0 /*width*/, 4.0 /*height*/ ); geometry_rectangle_init_by_difference( &diff_rect, &rect_a, &rect_b ); TEST_ASSERT( geometry_rectangle_is_containing( &rect_a, &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 0.0, geometry_rectangle_get_intersect_area( &rect_b, &diff_rect ) ); TEST_ASSERT_EQUAL_DOUBLE( 2.0, geometry_rectangle_get_area( &diff_rect ) ); geometry_rectangle_destroy ( &rect_a ); geometry_rectangle_destroy ( &rect_b ); geometry_rectangle_destroy ( &diff_rect ); } } static void test_expand_4d(void) { geometry_rectangle_t rect_a; /* good case */ geometry_rectangle_init ( &rect_a, 4.0, 4.0, 2.0 /*width*/, 2.0 /*height*/ ); geometry_rectangle_expand_4dir ( &rect_a, 1.0, 2.0 ); TEST_ASSERT_EQUAL_DOUBLE( 3.0, geometry_rectangle_get_left( &rect_a ) ); TEST_ASSERT_EQUAL_DOUBLE( 2.0, geometry_rectangle_get_top( &rect_a ) ); TEST_ASSERT_EQUAL_DOUBLE( 4.0, geometry_rectangle_get_width( &rect_a ) ); TEST_ASSERT_EQUAL_DOUBLE( 6.0, geometry_rectangle_get_height( &rect_a ) ); geometry_rectangle_destroy ( &rect_a ); /* negative-size case */ geometry_rectangle_init ( &rect_a, 4.0, 4.0, 2.0 /*width*/, 2.0 /*height*/ ); geometry_rectangle_expand_4dir ( &rect_a, -3.0, -4.0 ); TEST_ASSERT_EQUAL_DOUBLE( 5.0, geometry_rectangle_get_left( &rect_a ) ); TEST_ASSERT_EQUAL_DOUBLE( 5.0, geometry_rectangle_get_top( &rect_a ) ); TEST_ASSERT_EQUAL_DOUBLE( 0.0, geometry_rectangle_get_width( &rect_a ) ); TEST_ASSERT_EQUAL_DOUBLE( 0.0, geometry_rectangle_get_height( &rect_a ) ); geometry_rectangle_destroy ( &rect_a ); } /* * Copyright 2017-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/test/unit/geometry_rectangle_test.h000066400000000000000000000016371415120503000254310ustar00rootroot00000000000000/* File: geometry_rectangle_test.h; Copyright and License: see below */ #ifndef GEOMETRY_RECTANGLE_TEST_H #define GEOMETRY_RECTANGLE_TEST_H /*! * \file * \brief UNITTEST for geometry_rectangle */ #include "test_suite.h" test_suite_t geometry_rectangle_test_get_list(void); #endif /* GEOMETRY_RECTANGLE_TEST_H */ /* * Copyright 2017-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/test/unit/pencil_classifier_composer_test.c000066400000000000000000000314441415120503000271310ustar00rootroot00000000000000/* File: pencil_classifier_composer_test.c; Copyright and License: see below */ #include "pencil_classifier_composer_test.h" #include "pencil_classifier_composer.h" #include "test_assert.h" static void set_up(void); static void tear_down(void); static void test_expand_space(void); static void test_set_envelope_box(void); static void test_set_envelope_box_too_small(void); test_suite_t pencil_classifier_composer_test_get_list(void) { test_suite_t result; test_suite_init( &result, "pencil_classifier_composer_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "test_expand_space", &test_expand_space ); test_suite_add_test_case( &result, "test_set_envelope_box", &test_set_envelope_box ); test_suite_add_test_case( &result, "test_set_envelope_box_too_small", &test_set_envelope_box_too_small ); return result; } static cairo_surface_t *surface; static cairo_t *cr; static geometry_rectangle_t diagram_bounds; static PangoLayout *font_layout; static layout_visible_classifier_t layout_vis_classifier; static data_visible_classifier_t data_vis_classifier; static pencil_size_t pencil_size; static draw_classifier_icon_t draw_classifier_icon; static void set_up(void) { /* init a pango font layout */ { geometry_rectangle_init( &diagram_bounds, 0.0, 0.0, 640.0, 480.0 ); surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, (uint32_t) geometry_rectangle_get_width( &diagram_bounds ), (uint32_t) geometry_rectangle_get_height( &diagram_bounds ) ); TEST_ENVIRONMENT_ASSERT( CAIRO_STATUS_SUCCESS == cairo_surface_status( surface ) ); cr = cairo_create (surface); TEST_ENVIRONMENT_ASSERT( CAIRO_STATUS_SUCCESS == cairo_status( cr ) ); font_layout = pango_cairo_create_layout (cr); } pencil_size_init( &pencil_size, geometry_rectangle_get_width( &diagram_bounds ), geometry_rectangle_get_height( &diagram_bounds ) ); draw_classifier_icon_init( &draw_classifier_icon ); /* init a layout visible classifier */ { data_classifier_t data_classifier; data_diagramelement_t data_diagele; const data_error_t err1 = data_diagramelement_init( &data_diagele, 17, /* id */ 32, /* diagram_id */ 99, /* classifier_id */ DATA_DIAGRAMELEMENT_FLAG_NAMED_INSTANCE, DATA_ROW_ID_VOID, "1ded6d32-cdea-43d8-931c-9459065f8944" ); TEST_ENVIRONMENT_ASSERT_EQUAL_INT( DATA_ERROR_NONE, err1 ); const data_error_t err2 = data_classifier_init( &data_classifier, 99, /* id */ DATA_CLASSIFIER_TYPE_CLASS, /* main_type */ "stereotype", "classifier name", "classifier\ndescription", 10000, /* x_order */ 11000, /* y_order */ 12000, /* list_order */ "94ad5563-3040-4f27-8e8b-d51ffc5ad4c8" ); TEST_ENVIRONMENT_ASSERT_EQUAL_INT( DATA_ERROR_NONE, err2 ); data_visible_classifier_init( &data_vis_classifier, &data_classifier, &data_diagele ); layout_visible_classifier_init( &layout_vis_classifier, &data_vis_classifier ); data_diagramelement_destroy( &data_diagele ); data_classifier_destroy( &data_classifier ); } } static void tear_down(void) { /* destroy the layout visible classifier */ { layout_visible_classifier_destroy( &layout_vis_classifier ); data_visible_classifier_destroy( &data_vis_classifier ); } draw_classifier_icon_destroy( &draw_classifier_icon ); pencil_size_destroy( &pencil_size ); /* destroy the pango font layout */ { g_object_unref (font_layout); cairo_destroy (cr); cairo_surface_finish ( surface ); cairo_surface_destroy ( surface ); geometry_rectangle_destroy( &diagram_bounds ); } } static void test_expand_space(void) { pencil_classifier_composer_t classifier_composer; pencil_classifier_composer_init( &classifier_composer ); const geometry_rectangle_t space = { .left = 100.0, .top = 90.0, .width = 420.0, .height = 104.0 }; for ( unsigned int t_idx = 0; t_idx < DATA_CLASSIFIER_TYPE_COUNT; t_idx ++ ) { data_classifier_type_t classifier_type = DATA_CLASSIFIER_TYPE_ARRAY[ t_idx ]; data_classifier_set_main_type( data_visible_classifier_get_classifier_ptr( &data_vis_classifier ), classifier_type ); /* printf(" type: %d, %d\n", t_idx, classifier_type); */ for ( unsigned int show_children = 0; show_children <= 1; show_children ++ ) { /* run composing method */ const int err = pencil_classifier_composer_expand_space( &classifier_composer, &space, (show_children != 0), &pencil_size, font_layout, &layout_vis_classifier ); TEST_ASSERT_EQUAL_INT( 0, err ); /* check that all layouted rectangles are outside space */ const geometry_rectangle_t *const symbol = layout_visible_classifier_get_symbol_box_const( &layout_vis_classifier ); if ( draw_classifier_icon_is_fix_sized_symbol( &draw_classifier_icon, classifier_type ) ) { /* no intesects if fix-size-symbol */ TEST_ASSERT_EQUAL_DOUBLE( 0.0, geometry_rectangle_get_intersect_area( &space, symbol ) ); } TEST_ASSERT( ! geometry_rectangle_is_empty( symbol ) ); const geometry_rectangle_t *const label = layout_visible_classifier_get_label_box_const( &layout_vis_classifier ); TEST_ASSERT_EQUAL_DOUBLE( 0.0, geometry_rectangle_get_intersect_area( &space, label ) ); TEST_ASSERT( ! geometry_rectangle_is_empty( label ) ); const geometry_rectangle_t *const space = layout_visible_classifier_get_space_const( &layout_vis_classifier ); TEST_ASSERT_EQUAL_DOUBLE( 100.0, geometry_rectangle_get_left( space ) ); TEST_ASSERT_EQUAL_DOUBLE( 90.0, geometry_rectangle_get_top( space ) ); TEST_ASSERT_EQUAL_DOUBLE( 420.0, geometry_rectangle_get_width( space ) ); TEST_ASSERT_EQUAL_DOUBLE( 104.0, geometry_rectangle_get_height( space ) ); } } pencil_classifier_composer_destroy( &classifier_composer ); } static void test_set_envelope_box(void) { pencil_classifier_composer_t classifier_composer; pencil_classifier_composer_init( &classifier_composer ); const geometry_rectangle_t envelope = { .left = 50.0, .top = 40.0, .width = 460.0, .height = 180.0 }; for ( unsigned int t_idx = 0; t_idx < DATA_CLASSIFIER_TYPE_COUNT; t_idx ++ ) { data_classifier_type_t classifier_type = DATA_CLASSIFIER_TYPE_ARRAY[ t_idx ]; data_classifier_set_main_type( data_visible_classifier_get_classifier_ptr( &data_vis_classifier ), classifier_type ); /* printf(" type: %d, %d\n", t_idx, classifier_type); */ for ( unsigned int show_children = 0; show_children <= 1; show_children ++ ) { /* run composing method */ const int err = pencil_classifier_composer_set_envelope_box( &classifier_composer, &envelope, (show_children != 0), &pencil_size, font_layout, &layout_vis_classifier ); TEST_ASSERT_EQUAL_INT( 0, err ); /* check that all layouted rectangles are within envelope */ const geometry_rectangle_t *const symbol = layout_visible_classifier_get_symbol_box_const( &layout_vis_classifier ); TEST_ASSERT( geometry_rectangle_is_containing( &envelope, symbol ) ); TEST_ASSERT( ! geometry_rectangle_is_empty( symbol ) ); const geometry_rectangle_t *const label = layout_visible_classifier_get_label_box_const( &layout_vis_classifier ); TEST_ASSERT( geometry_rectangle_is_containing( &envelope, label ) ); TEST_ASSERT( ! geometry_rectangle_is_empty( label ) ); const geometry_rectangle_t *const space = layout_visible_classifier_get_space_const( &layout_vis_classifier ); TEST_ASSERT( geometry_rectangle_is_containing( &envelope, space ) ); TEST_ASSERT( ! geometry_rectangle_is_empty( space ) ); } } pencil_classifier_composer_destroy( &classifier_composer ); } static void test_set_envelope_box_too_small(void) { pencil_classifier_composer_t classifier_composer; pencil_classifier_composer_init( &classifier_composer ); const geometry_rectangle_t small_envelope = { .left = 150.0, .top = 140.0, .width = 15.0, .height = 10.0 }; for ( unsigned int t_idx = 0; t_idx < DATA_CLASSIFIER_TYPE_COUNT; t_idx ++ ) { data_classifier_type_t classifier_type = DATA_CLASSIFIER_TYPE_ARRAY[ t_idx ]; data_classifier_set_main_type( data_visible_classifier_get_classifier_ptr( &data_vis_classifier ), classifier_type ); /* printf(" type: %d, %d\n", t_idx, classifier_type); */ for ( unsigned int show_children = 0; show_children <= 1; show_children ++ ) { /* run composing method */ const int err = pencil_classifier_composer_set_envelope_box( &classifier_composer, &small_envelope, (show_children != 0), &pencil_size, font_layout, &layout_vis_classifier ); TEST_ASSERT_EQUAL_INT( 1, err ); /* check that actual_envelope rectangle is bigger and is within small_envelope */ const geometry_rectangle_t actual_envelope = layout_visible_classifier_get_envelope_box( &layout_vis_classifier ); geometry_rectangle_trace( &small_envelope ); geometry_rectangle_trace( &actual_envelope ); TEST_ASSERT( geometry_rectangle_is_containing( &actual_envelope, &small_envelope ) ); TEST_ASSERT( ! geometry_rectangle_is_containing( &small_envelope, &actual_envelope ) ); /* check that label and space are withing symbol (unless fix-sized-symbol) */ if ( ! draw_classifier_icon_is_fix_sized_symbol( &draw_classifier_icon, classifier_type ) ) { const geometry_rectangle_t *const symbol = layout_visible_classifier_get_symbol_box_const( &layout_vis_classifier ); const geometry_rectangle_t *const label = layout_visible_classifier_get_label_box_const( &layout_vis_classifier ); const geometry_rectangle_t *const space = layout_visible_classifier_get_space_const( &layout_vis_classifier ); TEST_ASSERT( geometry_rectangle_is_containing( symbol, label ) ); TEST_ASSERT( geometry_rectangle_is_containing( symbol, space ) ); } } } pencil_classifier_composer_destroy( &classifier_composer ); } /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/test/unit/pencil_classifier_composer_test.h000066400000000000000000000017171415120503000271360ustar00rootroot00000000000000/* File: pencil_classifier_composer_test.h; Copyright and License: see below */ #ifndef PENCIL_CLASSIFIER_COMPOSER_TEST_H #define PENCIL_CLASSIFIER_COMPOSER_TEST_H /*! * \file * \brief UNITTEST for pencil_classifier_composer */ #include "test_suite.h" test_suite_t pencil_classifier_composer_test_get_list(void); #endif /* PENCIL_CLASSIFIER_COMPOSER_TEST_H */ /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/test/unit/pencil_layout_data_test.c000066400000000000000000000314661415120503000254100ustar00rootroot00000000000000/* File: pencil_layout_data_test.c; Copyright and License: see below */ #include "pencil_layout_data_test.h" #include "pencil_layout_data.h" #include "set/data_visible_set.h" #include "test_assert.h" static void set_up(void); static void tear_down(void); static void test_empty_model(void); static void test_normal_model(void); static void test_too_big_model(void); static void test_inconsistent_model(void); static data_visible_set_t* init_empty_input_data(); static data_visible_set_t* init_fake_input_data( uint_fast32_t classifiers, uint_fast32_t features, uint_fast32_t relationships ); test_suite_t pencil_layout_data_test_get_list(void) { test_suite_t result; test_suite_init( &result, "pencil_layout_data_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "test_empty_model", &test_empty_model ); test_suite_add_test_case( &result, "test_normal_model", &test_normal_model ); test_suite_add_test_case( &result, "test_too_big_model", &test_too_big_model ); test_suite_add_test_case( &result, "test_inconsistent_model", &test_inconsistent_model ); return result; } static void set_up(void) { } static void tear_down(void) { } static data_visible_set_t* init_empty_input_data() { static data_visible_set_t empty_input_data; data_visible_set_init( &empty_input_data ); data_visible_set_private_update_containment_cache ( &empty_input_data ); TEST_ENVIRONMENT_ASSERT ( ! data_visible_set_is_valid ( &empty_input_data ) ); return &empty_input_data; } static data_visible_set_t* init_fake_input_data( uint_fast32_t classifiers, uint_fast32_t features, uint_fast32_t relationships ) { data_error_t data_err; static data_visible_set_t fake_input_data; data_visible_set_init( &fake_input_data ); /* initialize the fake_input_data.diagram */ { data_err = data_diagram_init( &(fake_input_data.diagram), 3, /* diagram_id */ DATA_ROW_ID_VOID, /* parent_diagram_id */ DATA_DIAGRAM_TYPE_UML_CLASS_DIAGRAM, /* diagram_type */ "diagram_name", "diagram_description", 32000, /* list_order */ DATA_DIAGRAM_FLAG_NONE, "bfe86725-1507-4789-ac92-82f1090a1984" ); TEST_ENVIRONMENT_ASSERT( data_err == DATA_ERROR_NONE ); } /* initialize the fake_input_data.visible_classifiers */ fake_input_data.visible_classifier_count = classifiers; for ( uint_fast32_t c_idx = 0; c_idx < classifiers; c_idx ++ ) { data_visible_classifier_t *current = &(fake_input_data.visible_classifiers[c_idx]); data_visible_classifier_init_empty ( current ); data_classifier_t *classifier = data_visible_classifier_get_classifier_ptr ( current ); data_diagramelement_t *diagele = data_visible_classifier_get_diagramelement_ptr ( current ); data_err = data_classifier_init( classifier, c_idx/2, /* id */ DATA_CLASSIFIER_TYPE_CLASS, /* main_type */ "stereotype", "name", "description", 1000*c_idx, /* x_order */ -300*c_idx, /* y_order */ 4000*c_idx, /* list_order */ "19e0f597-9b9d-4e27-b69d-fc648370ae46" ); TEST_ENVIRONMENT_ASSERT( data_err == DATA_ERROR_NONE ); data_err = data_diagramelement_init( diagele, c_idx, /* id */ 3, /* diagram_id */ c_idx/2, /* classifier_id */ DATA_DIAGRAMELEMENT_FLAG_ANONYMOUS_INSTANCE | DATA_DIAGRAMELEMENT_FLAG_EMPHASIS, /* display_flags */ DATA_ROW_ID_VOID, /* focused_feature_id */ "bcb8a819-90c7-49ad-b21d-feccfd5bcf96" ); TEST_ENVIRONMENT_ASSERT( data_err == DATA_ERROR_NONE ); TEST_ENVIRONMENT_ASSERT( data_visible_classifier_is_valid( current ) ); } const uint_fast32_t classifier_mod = ((classifiers/2)==0) ? 1 : (classifiers/2); /* initialize the fake_input_data.features */ fake_input_data.feature_count = features; for ( uint_fast32_t f_idx = 0; f_idx < features; f_idx ++ ) { data_feature_t *current = &(fake_input_data.features[f_idx]); data_err = data_feature_init( current, f_idx, /* feature_id */ DATA_FEATURE_TYPE_OPERATION, /* feature_main_type */ f_idx % classifier_mod, /* classifier_id */ "feature_key", "feature_value", "feature_description", 6000*f_idx, /* list_order */ "17c18bbd-c1d3-438d-bd85-5ec2704f8511" ); TEST_ENVIRONMENT_ASSERT( data_err == DATA_ERROR_NONE ); TEST_ENVIRONMENT_ASSERT( data_feature_is_valid( current ) ); } /* initialize the fake_input_data.relationships */ fake_input_data.relationship_count = relationships; for ( uint_fast32_t r_idx = 0; r_idx < relationships; r_idx ++ ) { data_relationship_t *current = &(fake_input_data.relationships[r_idx]); data_err = data_relationship_init( current, r_idx, /* relationship_id */ DATA_RELATIONSHIP_TYPE_UML_ASSOCIATION, /* relationship_main_type */ r_idx % classifier_mod, /* from_classifier_id */ (r_idx*r_idx) % classifier_mod, /* to_classifier_id */ "relationship_name", "relationship_description", 1500*r_idx, /* list_order */ DATA_ROW_ID_VOID, /* from_feature_id */ DATA_ROW_ID_VOID, /* to_feature_id */ "a0feb041-647e-422f-a4ff-2e6647c08f77" ); TEST_ENVIRONMENT_ASSERT( data_err == DATA_ERROR_NONE ); TEST_ENVIRONMENT_ASSERT( data_relationship_is_valid( current ) ); } data_visible_set_private_update_containment_cache ( &fake_input_data ); TEST_ENVIRONMENT_ASSERT ( data_visible_set_is_valid ( &fake_input_data ) ); return &fake_input_data; } static const int DUPLICATE_PARENT_CLASSIFIER=2; static const int DUPLICATE_FROM_CLASSIFIER=2; static const int DUPLICATE_TO_CLASSIFIER=2; static void test_empty_model(void) { data_visible_set_t* empty_input_data; empty_input_data = init_empty_input_data(); static pencil_layout_data_t testee; pencil_layout_data_init( &testee, empty_input_data ); TEST_ASSERT( NULL != pencil_layout_data_get_diagram_ptr ( &testee ) ) TEST_ASSERT_EQUAL_INT( 0, pencil_layout_data_get_visible_classifier_count ( &testee ) ); TEST_ASSERT_EQUAL_INT( 0, pencil_layout_data_get_feature_count ( &testee ) ); TEST_ASSERT_EQUAL_INT( 0, pencil_layout_data_get_relationship_count ( &testee ) ); TEST_ASSERT ( ! pencil_layout_data_is_valid( &testee ) ); data_visible_set_t *fake_input_data; fake_input_data = init_fake_input_data(0,10,10); pencil_layout_data_reinit( &testee, fake_input_data ); TEST_ASSERT( NULL != pencil_layout_data_get_diagram_ptr ( &testee ) ); TEST_ASSERT_EQUAL_INT( 0, pencil_layout_data_get_visible_classifier_count ( &testee ) ); TEST_ASSERT_EQUAL_INT( 0, pencil_layout_data_get_feature_count ( &testee ) ); TEST_ASSERT_EQUAL_INT( 0, pencil_layout_data_get_relationship_count ( &testee ) ); TEST_ASSERT ( pencil_layout_data_is_valid( &testee ) ); pencil_layout_data_destroy( &testee ); } static void test_normal_model(void) { data_visible_set_t *fake_input_data; fake_input_data = init_fake_input_data(15,30,20); /* make the 0-th relation a from-feature-to-feature relation: */ data_relationship_t *linked_rel = data_visible_set_get_relationship_ptr ( fake_input_data, 0 /*index*/ ); data_relationship_set_from_feature_row_id ( linked_rel, 0 /* not DATA_ROW_ID_VOID */ ); data_relationship_set_to_feature_row_id ( linked_rel, 0 /* not DATA_ROW_ID_VOID */ ); static pencil_layout_data_t testee; pencil_layout_data_init( &testee, fake_input_data ); TEST_ASSERT( NULL != pencil_layout_data_get_diagram_ptr ( &testee ) ); TEST_ASSERT_EQUAL_INT( 15, pencil_layout_data_get_visible_classifier_count ( &testee ) ); TEST_ASSERT_EQUAL_INT( 30*DUPLICATE_PARENT_CLASSIFIER, pencil_layout_data_get_feature_count ( &testee ) ); TEST_ASSERT_EQUAL_INT( 20*DUPLICATE_FROM_CLASSIFIER*DUPLICATE_TO_CLASSIFIER, pencil_layout_data_get_relationship_count ( &testee ) ); TEST_ASSERT ( pencil_layout_data_is_valid( &testee ) ); pencil_layout_data_destroy( &testee ); } static void test_too_big_model(void) { data_visible_set_t *fake_input_data; fake_input_data = init_fake_input_data( DATA_VISIBLE_SET_MAX_CLASSIFIERS, DATA_VISIBLE_SET_MAX_FEATURES, DATA_VISIBLE_SET_MAX_RELATIONSHIPS ); static pencil_layout_data_t testee; pencil_layout_data_init( &testee, fake_input_data ); TEST_ASSERT( NULL != pencil_layout_data_get_diagram_ptr ( &testee ) ); TEST_ASSERT_EQUAL_INT( DATA_VISIBLE_SET_MAX_CLASSIFIERS, pencil_layout_data_get_visible_classifier_count ( &testee ) ); TEST_ASSERT_EQUAL_INT( PENCIL_LAYOUT_DATA_MAX_FEATURES, pencil_layout_data_get_feature_count ( &testee ) ); TEST_ASSERT_EQUAL_INT( PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS, pencil_layout_data_get_relationship_count ( &testee ) ); TEST_ASSERT ( pencil_layout_data_is_valid( &testee ) ); pencil_layout_data_destroy( &testee ); } static void test_inconsistent_model(void) { data_visible_set_t *fake_input_data; fake_input_data = init_fake_input_data(5,5,5); /* make some wrong ids and links */ data_feature_t *illegal_feat1 = data_visible_set_get_feature_ptr ( fake_input_data, 4 /*index*/ ); data_feature_set_classifier_row_id ( illegal_feat1, 12000 /*non-existing classifier_id*/ ); data_relationship_t *illegal_rel1 = data_visible_set_get_relationship_ptr ( fake_input_data, 0 /*index*/ ); data_relationship_set_from_feature_row_id ( illegal_rel1, 1 /* feature id 1 does not belong to from classifier */ ); data_relationship_set_to_feature_row_id ( illegal_rel1, 0 /* not DATA_ROW_ID_VOID */ ); data_relationship_t *illegal_rel2 = data_visible_set_get_relationship_ptr ( fake_input_data, 1 /*index*/ ); data_relationship_set_from_classifier_row_id ( illegal_rel2, 12000 /*non-existing classifier_id*/ ); data_relationship_t *illegal_rel3 = data_visible_set_get_relationship_ptr ( fake_input_data, 2 /*index*/ ); data_relationship_set_to_classifier_row_id ( illegal_rel3, 12000 /*non-existing classifier_id*/ ); static pencil_layout_data_t testee; pencil_layout_data_init( &testee, fake_input_data ); TEST_ASSERT( NULL != pencil_layout_data_get_diagram_ptr ( &testee ) ); TEST_ASSERT_EQUAL_INT( 5, pencil_layout_data_get_visible_classifier_count ( &testee ) ); TEST_ASSERT_EQUAL_INT( (5-1)*DUPLICATE_PARENT_CLASSIFIER, pencil_layout_data_get_feature_count ( &testee ) ); TEST_ASSERT_EQUAL_INT( (5-3)*DUPLICATE_FROM_CLASSIFIER*DUPLICATE_TO_CLASSIFIER, pencil_layout_data_get_relationship_count ( &testee ) ); TEST_ASSERT ( pencil_layout_data_is_valid( &testee ) ); pencil_layout_data_destroy( &testee ); } /* * Copyright 2019-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/pencil/test/unit/pencil_layout_data_test.h000066400000000000000000000016371415120503000254120ustar00rootroot00000000000000/* File: pencil_layout_data_test.h; Copyright and License: see below */ #ifndef PENCIL_LAYOUT_DATA_TEST_H #define PENCIL_LAYOUT_DATA_TEST_H /*! * \file * \brief UNITTEST for pencil_layout_data */ #include "test_suite.h" test_suite_t pencil_layout_data_test_get_list(void); #endif /* PENCIL_LAYOUT_DATA_TEST_H */ /* * Copyright 2019-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/readme.markdown000066400000000000000000000037661415120503000201400ustar00rootroot00000000000000 ![ScreenShot](user_doc/doc/1_introduction_banner.png) crystal-facet-uml ============= crystal-facet-uml creates sysml/uml diagrams to document system and software architecture. Like a crystal shows different facets of the same thing, this application shows different views of the same system. ![ScreenShot](user_doc/doc/screenshot_1.png) As software architect, you create a set of diagrams describing use-cases, requirements, structural views, behavioral and deployment views. crystal-facet-uml keeps element names and element hierarchies consistent. It exports diagrams in svg, pdf, ps and png formats to be used in text processing systems like docbook, html, latex. crystal-facet-uml exports the model to xmi format. This tool runs on your local linux PC and is based on glib, gdk, gtk, cairo, pango, sqlite. ![ScreenShot](user_doc/doc/screenshot_2.png) ![ScreenShot](user_doc/doc/screenshot_3.png) How to use this program is described in the [User Manual](user_doc/crystal-facet-uml_documentation.pdf) . Install crystal-facet-uml ----------- This section describes how to install a binary package. Debian/Ubuntu/Raspbian: > sudo apt install crystal-facet-uml or > sudo dpkg -i crystal-facet-uml_1.x.0-1_amd64.deb openSuSE: > sudo zypper addrepo https://download.opensuse.org/repositories/devel:/tools/openSUSE_Leap_15.3 devel_tools_15.3 > sudo zypper install crystal-facet-uml or > sudo zypper install crystal-facet-uml-1.x.0-1.1.x86_64.rpm Windows/wine: > unzip crystal-facet-uml_1.x.0-1_win32.zip How to build from source ----------- Building from source is described in [./build](build) . About ----------- > Version: see META_VERSION_STR in main/include/meta/meta_version.inl > > Author+Copyright: 2016-2021 Andreas Warnke > > License: Apache 2.0 License crystal-facet-uml-1.34.1/test_fw/000077500000000000000000000000001415120503000165765ustar00rootroot00000000000000crystal-facet-uml-1.34.1/test_fw/include/000077500000000000000000000000001415120503000202215ustar00rootroot00000000000000crystal-facet-uml-1.34.1/test_fw/include/test_assert.h000066400000000000000000000100251415120503000227300ustar00rootroot00000000000000/* File: test_assert.h; Copyright and License: see below */ #ifndef TEST_ASSERT_H #define TEST_ASSERT_H /* public file for the doxygen documentation: */ /*! * \file * \brief provides assert functions for test cases */ #include #include #include #define TEST_FAIL()\ {fprintf(stderr,"TEST FAILED at %s:%d\n",__FILE__,__LINE__);exit(-1);} #define TEST_ASSERT(COND)\ if (!(COND)) \ {fprintf(stderr,"TEST FAILED (!(%s)) at %s:%d\n",#COND,__FILE__,__LINE__);exit(-1);} #define TEST_ASSERT_EQUAL_INT(EXPECTED,ACTUAL)\ {const long long exp = (EXPECTED); const long long act = (ACTUAL); if (exp!=act) \ {fprintf(stderr,"TEST FAILED ((%s)==%lld!=%lld==(%s)) at %s:%d\n",\ #EXPECTED,exp,act,#ACTUAL,__FILE__,__LINE__);exit(-1);} \ } #define TEST_ASSERT_EQUAL_PTR(EXPECTED,ACTUAL)\ {const void *exp = (EXPECTED); const void *act = (ACTUAL); if (exp!=act) \ {fprintf(stderr,"TEST FAILED ((%s)==%p!=%p==(%s)) at %s:%d\n",\ #EXPECTED,exp,act,#ACTUAL,__FILE__,__LINE__);exit(-1);} \ } #define TEST_ASSERT_EQUAL_STRING(EXPECTED,ACTUAL)\ {const char *exp = (EXPECTED); const char *act = (ACTUAL);\ if ((exp==NULL)||(act==NULL)||(0!=strcmp(exp,act))) \ {fprintf(stderr,"TEST FAILED ((%s)==%s!=%s==(%s)) at %s:%d\n",\ #EXPECTED,exp,act,#ACTUAL,__FILE__,__LINE__);exit(-1);} \ } /* EPSILON(x) = 2.2204460493 e−016 */ /* double precision of mantissa: 2.22e-16 - adding factor 100 to compensate rounding errors of previous calculations */ #define TEST_DOUBLE_EPSILON 2.22e-14 /* TINIEST((x) = 4.9406564584 e−324 */ /* double tiniest: 4.94e-324 - adding factor 100 to compensate rounding errors of previous calculations - relevant if EXPECTED==0.0 */ #define TEST_DOUBLE_TINIEST 4.94e-322 #define TEST_ASSERT_EQUAL_DOUBLE(EXPECTED,ACTUAL)\ {const double exp = (EXPECTED); const double act = (ACTUAL);\ if ( fabs(exp-act) > ((fabs(exp)*TEST_DOUBLE_EPSILON)+TEST_DOUBLE_TINIEST) ) \ {fprintf(stderr,"TEST FAILED ((%s)==%f!=%f==(%s)) at %s:%d\n",\ #EXPECTED,exp,act,#ACTUAL,__FILE__,__LINE__);exit(-1);} \ } /* EPSILON(x) = 1.192092896 e-07 */ /* float precision of mantissa: 1.19e-7 - adding factor 100 to compensate rounding errors of previous calculations */ #define TEST_FLOAT_EPSILON 1.19e-5 /* TINIEST((x) = 1.401298464 e−45 */ /* float tiniest: 1.40e-45 - adding factor 100 to compensate rounding errors of previous calculations - relevant if EXPECTED==0.0 */ #define TEST_FLOAT_TINIEST 1.40e-43 #define TEST_ASSERT_EQUAL_FLOAT(EXPECTED,ACTUAL)\ {const float exp = (EXPECTED); const float act = (ACTUAL);\ if ( fabs(exp-act) > ((fabs(exp)*TEST_FLOAT_EPSILON)+TEST_FLOAT_TINIEST) ) \ {fprintf(stderr,"TEST FAILED ((%s)==%f!=%f==(%s)) at %s:%d\n",\ #EXPECTED,exp,act,#ACTUAL,__FILE__,__LINE__);exit(-1);} \ } /* Assertion to throw if test environment is wrong (not if test case failed). */ /* In contrast to assert.h, this always terminates test execution, even in NDEBUG mode. */ #define TEST_ENVIRONMENT_ASSERT(COND)\ if (!(COND)) \ {fprintf(stderr,"TEST ENVIRONMENT ERROR (!(%s)) at %s:%d\n",#COND,__FILE__,__LINE__);exit(-1);} /* Assertion to throw if test environment is wrong (not if test case failed). */ /* In contrast to assert.h, this always terminates test execution, even in NDEBUG mode. */ #define TEST_ENVIRONMENT_ASSERT_EQUAL_INT(EXPECTED,ACTUAL)\ {const long long exp = (EXPECTED); const long long act = (ACTUAL); if (exp!=act) \ {fprintf(stderr,"TEST ENVIRONMENT ERROR ((%s)==%lld!=%lld==(%s)) at %s:%d\n",\ #EXPECTED,exp,act,#ACTUAL,__FILE__,__LINE__);exit(-1);} \ } #endif /* TEST_ASSERT_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/test_fw/include/test_result.h000066400000000000000000000040551415120503000227530ustar00rootroot00000000000000/* File: test_result.h; Copyright and License: see below */ #ifndef TEST_RESULT_H #define TEST_RESULT_H /* public file for the doxygen documentation: */ /*! * \file * \brief Provides result struct for unit tests. */ #include /*! * \brief attributes of a test result */ struct test_result_struct { unsigned int total; /*!< total number of executed test cases */ unsigned int failed; /*!< failed number of executed test cases */ }; typedef struct test_result_struct test_result_t; /*! * \brief initializes the test_result_t * * \param this_ pointer to own object attributes */ static inline void test_result_init( test_result_t *this_ ); /*! * \brief destroys the test_result_t * * \param this_ pointer to own object attributes */ static inline void test_result_destroy( test_result_t *this_ ); /*! * \brief add test result * * \param this_ pointer to own object attributes * \param success true if the test case succeeded, false if it failed. */ static inline void test_result_add_test_case_result( test_result_t *this_, bool success ); /*! * \brief returns the number of total test cases * * \param this_ pointer to own object attributes */ static inline unsigned int test_result_get_total( test_result_t *this_ ); /*! * \brief returns the number of failed test cases * * \param this_ pointer to own object attributes */ static inline unsigned int test_result_get_failed( test_result_t *this_ ); #include "test_result.inl" #endif /* TEST_RESULT_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/test_fw/include/test_result.inl000066400000000000000000000022641415120503000233060ustar00rootroot00000000000000/* File: test_result.inl; Copyright and License: see below */ static inline void test_result_init( test_result_t *this_ ) { (*this_).total = 0; (*this_).failed = 0; } static inline void test_result_destroy( test_result_t *this_ ) { } static inline void test_result_add_test_case_result( test_result_t *this_, bool success ) { (*this_).total ++; if ( ! success ) { (*this_).failed ++; } } static inline unsigned int test_result_get_total( test_result_t *this_ ) { return (*this_).total; } static inline unsigned int test_result_get_failed( test_result_t *this_ ) { return (*this_).failed; } /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/test_fw/include/test_runner.h000066400000000000000000000036711415120503000227510ustar00rootroot00000000000000/* File: test_runner.h; Copyright and License: see below */ #ifndef TEST_RUNNER_H #define TEST_RUNNER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Executes a set of unit test suites - in line with the xunit architecture. * see https://en.wikipedia.org/wiki/XUnit */ #include #include #include "test_result.h" #include "test_suite.h" /*! * \brief attributes of a test runner */ struct test_runner_struct { test_result_t result; /*!< test result statistics */ }; typedef struct test_runner_struct test_runner_t; /*! * \brief initializes the test_runner_t * * \param this_ pointer to own object attributes */ static inline void test_runner_init( test_runner_t *this_ ); /*! * \brief destroys the test_runner_t * * \param this_ pointer to own object attributes */ static inline void test_runner_destroy( test_runner_t *this_ ); /*! * \brief test runner - runs a test suite * * \param this_ pointer to own object attributes * \param test_suite test suite to run */ static inline void test_runner_run_suite( test_runner_t *this_, test_suite_t test_suite ); /*! * \brief get test runner result * * \param this_ pointer to own object attributes * \param test_suite test suite to run */ static inline test_result_t test_get_result( test_runner_t *this_ ); #include "test_runner.inl" #endif /* TEST_RUNNER_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/test_fw/include/test_runner.inl000066400000000000000000000040211415120503000232720ustar00rootroot00000000000000/* File: test_runner.inl; Copyright and License: see below */ #include "tslog.h" #include static inline void test_runner_init( test_runner_t *this_ ) { test_result_init( &((*this_).result) ); } static inline void test_runner_destroy( test_runner_t *this_ ) { test_result_destroy( &((*this_).result) ); } static inline void test_runner_run_suite( test_runner_t *this_, test_suite_t test_suite ) { test_result_t suite_local_result; test_result_init( &suite_local_result ); fprintf( stdout, "test suite: %s\n", test_suite_get_name( &test_suite ) ); unsigned int count = test_suite_get_test_case_count( &test_suite ); for ( unsigned int idx = 0; idx < count; idx ++ ) { fprintf( stdout, " test case: %s\n", test_suite_get_test_case_name( &test_suite, idx ) ); fflush( stdout ); /* help to localize errors in case of sudden termination */ bool success; success = test_suite_run_test_case( &test_suite, idx ); test_result_add_test_case_result( &((*this_).result), success ); test_result_add_test_case_result( &suite_local_result, success ); } fprintf( stdout, "test result: total %d, failed: %d\n", test_result_get_total( &suite_local_result ), test_result_get_failed( &suite_local_result ) ); test_result_destroy( &suite_local_result ); } static inline test_result_t test_get_result( test_runner_t *this_ ) { return (*this_).result; } /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/test_fw/include/test_suite.h000066400000000000000000000075341415120503000225730ustar00rootroot00000000000000/* File: test_suite.h; Copyright and License: see below */ #ifndef TEST_SUITE_H #define TEST_SUITE_H /* public file for the doxygen documentation: */ /*! * \file * \brief Provides a set of unit test functions - in line with the xunit architecture. * see https://en.wikipedia.org/wiki/XUnit */ #include /*! * \brief constants of simple test suite */ enum test_suite_max_enum { TEST_SUITE_MAX_TEST_CASES = 48, /*!< maximum number test cases per test suite */ }; /*! * \brief attributes of a test suite: fixture-setup, fixture-tear-down, set of test cases */ struct test_suite_struct { const char *name; void (*setup) (void); /*!< pointer to setup function of test fixture */ void (*teardown) (void); /*!< pointer to teardown function of test fixture */ unsigned int test_case_count; /*!< number of test cases */ const char *(test_case_name[TEST_SUITE_MAX_TEST_CASES]); /*!< array of test case names */ void (*(test_case[TEST_SUITE_MAX_TEST_CASES])) (void); /*!< array of pointers to test case functions */ }; typedef struct test_suite_struct test_suite_t; /*! * \brief initializes the test_suite_t * * \param name name of test suite * \param setup function pointer to setup function * \param teardown function pointer to teardown function * \param this_ pointer to own object attributes */ static inline void test_suite_init( test_suite_t *this_, const char *name, void (*setup) (void), void (*teardown) (void) ); /*! * \brief destroys the test_suite_t * * \param this_ pointer to own object attributes */ static inline void test_suite_destroy( test_suite_t *this_ ); /*! * \brief adds a test case to the test_suite_t * * \param this_ pointer to own object attributes * \param name name of test case * \param test_case function pointer to test_case function */ static inline void test_suite_add_test_case( test_suite_t *this_, const char *name, void (*test_case) (void) ); /*! * \brief adds a test case to the test_suite_t * * \param this_ pointer to own object attributes * \return number of test cases */ static inline unsigned int test_suite_get_test_case_count( test_suite_t *this_ ); /*! * \brief executes a test case * * \param this_ pointer to own object attributes * \param index index of the test case, value between 0 and (test_case_count-1) * \return true in case of success */ static inline bool test_suite_run_test_case( test_suite_t *this_, unsigned int index ); /*! * \brief gets the name of the test_suite_t * * \param this_ pointer to own object attributes * \return name of test suite */ static inline const char* test_suite_get_name( test_suite_t *this_ ); /*! * \brief gets the name of a test case in the test_suite_t * * \param this_ pointer to own object attributes * \param index index of the test case, value between 0 and (test_case_count-1) * \return name of test case */ static inline const char* test_suite_get_test_case_name( test_suite_t *this_, unsigned int index ); #include "test_suite.inl" #endif /* TEST_SUITE_H */ /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/test_fw/include/test_suite.inl000066400000000000000000000054331415120503000231220ustar00rootroot00000000000000/* File: test_suite.inl; Copyright and License: see below */ #include "test_assert.h" #include "tslog.h" static inline void test_suite_init( test_suite_t *this_, const char *name, void (*setup) (void), void (*teardown) (void) ) { TEST_ENVIRONMENT_ASSERT( NULL != name ); TEST_ENVIRONMENT_ASSERT( NULL != setup ); TEST_ENVIRONMENT_ASSERT( NULL != teardown ); (*this_).name = name; (*this_).setup = setup; (*this_).teardown = teardown; (*this_).test_case_count = 0; } static inline void test_suite_destroy( test_suite_t *this_ ) { (*this_).name = NULL; (*this_).setup = NULL; (*this_).teardown = NULL; (*this_).test_case_count = 0; } static inline void test_suite_add_test_case( test_suite_t *this_, const char *name, void (*test_case) (void) ) { TEST_ENVIRONMENT_ASSERT( (*this_).test_case_count < TEST_SUITE_MAX_TEST_CASES ); TEST_ENVIRONMENT_ASSERT( NULL != test_case ); (*this_).test_case_name[(*this_).test_case_count] = name; (*this_).test_case[(*this_).test_case_count] = test_case; (*this_).test_case_count ++; } static inline unsigned int test_suite_get_test_case_count( test_suite_t *this_ ) { TEST_ENVIRONMENT_ASSERT( (*this_).test_case_count <= TEST_SUITE_MAX_TEST_CASES ); return (*this_).test_case_count; } static inline bool test_suite_run_test_case( test_suite_t *this_, unsigned int index ) { TEST_ENVIRONMENT_ASSERT( (*this_).test_case_count <= TEST_SUITE_MAX_TEST_CASES ); TEST_ENVIRONMENT_ASSERT( index < (*this_).test_case_count ); bool success = true; (*((*this_).setup))(); (*((*this_).test_case[index]))(); (*((*this_).teardown))(); return success; } static inline const char* test_suite_get_name( test_suite_t *this_ ) { return (*this_).name; } static inline const char* test_suite_get_test_case_name( test_suite_t *this_, unsigned int index ) { TEST_ENVIRONMENT_ASSERT( (*this_).test_case_count <= TEST_SUITE_MAX_TEST_CASES ); TEST_ENVIRONMENT_ASSERT( index < (*this_).test_case_count ); return (*this_).test_case_name[index]; } /* Copyright 2019-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/todo.txt000066400000000000000000000071041415120503000166330ustar00rootroot00000000000000ideas for future versions: @gui [ ] performance optimization: redraw only when shown(=visible) items have changed; do not redraw 3 times when changing 3 attributes simultaneously. (especially at undo/redo) do not redraw twice, once for deactivating a tool and again for activating another [ ] a "saveAs" or export-as-cfu1 command should allow to copy the current db [ ] show a progress bar while exporting diagrams (especially for png mode) [ ] scrolling through search list missing if result list is too long @gui+ctrl [ ] When undoing/redoing things, switch to a diagram where you see the changes [ ] When pasting a new diagram, switch to the new diagram in nav view to see the changes @pencil [ ] improve layouting of relationships. Maybe "longest first + shortest best" is not the best strategy? instead look more for distances to other lines [ ] Support Diagram-Types: Profile [ ] exception+error flows to leave an interruptable area (activity diagrams) [ ] activity bars on lifelines missing [ ] feature compartments in use-cases look ugly [?] more relationship types needed: undirected ---- and one-way x--> and no x--x dependency (non-navigateable ends) [?] more relationship types needed: undirected ---- and one-way x--> and no x--x association [?] sequence diagrams need if/loop-boxes [?] activity diagrams need swimlanes/partitions @io [ ] export formats: enhance xmi standard compliance [ ] import XMI format [ ] xmi export is not spec-compliant for uml:Port, provided and required Interfaces [ ] xmi export: improve error message if exported file exists and is read-only [ ] uuid is lost at cut+paste, a new uuid is assigned. @data [?] some diagrams exist for completeness only - but do not contain important information. These shall be greyed out. --> add a "display_flags" field to "diagrams" [ ] performance optimization: possibly the feature and relationship filter on a visible_set is slow? [?] diagrams need some kind of category/classification/stereotype like idea-for-future, rejected-alternative, ... --> add a "stereotype" field to "diagrams" [ ] some way to compare two database files / and/or to merge - maybe there are already solutions for sqlite3 and git: a) store an sqlite3 dump to git, not the binary Note that a cfu1 database file contains many ids and foreign-keys and ordering-hints, this is not mergeable by humans see e.g "sqlite3 mouse_droid.cfu1 .dump" b) setup git hooks and use a custom merge/diff tool for binary db documentation needed maybe rowid should be replaced by GUID to make this easier maybe a database schema file is needed c) define an own simple, sorted, line-based text format for version-control-system storage [ ] links unclear: interactionuse(diag-reference)-to-fragment(diag); part-to-component, object-to-class [ ] links unclear: provided/required-interface(feature)-to-interface(classifier) [?] features can have stereotypes, see UML spec 2.5.1 chapter 11.4.5 (maybe use existing value-type?) @ctrl [ ] delete features immediately when they become invisible in all diagrams (note: the search+xmi+json export find them) [ ] delete relationships immediately when they become invisible in all diagrams (note: the search+xmi+json export find them) @universal+utf8stringbuf [ ] combine the static string allocation with dynamic additional buffers for unexpectedly-long strings [ ] combine the static array allocation with dynamic additional buffers for arrays of unpredictable lengths @main @ts_log/trace/test_fw crystal-facet-uml-1.34.1/trace/000077500000000000000000000000001415120503000162215ustar00rootroot00000000000000crystal-facet-uml-1.34.1/trace/include/000077500000000000000000000000001415120503000176445ustar00rootroot00000000000000crystal-facet-uml-1.34.1/trace/include/trace.h000066400000000000000000000155351415120503000211240ustar00rootroot00000000000000/* File: trace.h; Copyright and License: see below */ #ifndef TRACE_H #define TRACE_H /* public file for the doxygen documentation: */ /*! * \file * \brief Prints traces to a byte stream */ #include #include #define TRACE_OUT_STREAM stdout #define TRACE_INDENT_MOD (32u) #define TRACE_INDENT_MAX (31u) #define TRACE_INDENT_STEP (2u) #define TRACE_NULLTERM_SIZE (1u) extern __thread unsigned int trace_indent_depth; extern const char trace_indent_pattern_begin[ TRACE_INDENT_STEP * TRACE_INDENT_MAX + TRACE_NULLTERM_SIZE ]; extern const char trace_indent_pattern_end[ TRACE_INDENT_STEP * TRACE_INDENT_MAX + TRACE_NULLTERM_SIZE ]; extern const char trace_indent_pattern_info[ TRACE_INDENT_STEP * TRACE_INDENT_MAX + TRACE_NULLTERM_SIZE ]; #define TRACE_INDENT_BEGIN \ (&(trace_indent_pattern_begin[((TRACE_INDENT_MAX-trace_indent_depth)%TRACE_INDENT_MOD)*TRACE_INDENT_STEP])) #define TRACE_INDENT_END \ (&(trace_indent_pattern_end[((TRACE_INDENT_MAX-trace_indent_depth)%TRACE_INDENT_MOD)*TRACE_INDENT_STEP])) #define TRACE_INDENT_INFO \ (&(trace_indent_pattern_info[((TRACE_INDENT_MAX-trace_indent_depth)%TRACE_INDENT_MOD)*TRACE_INDENT_STEP])) #ifndef NDEBUG /* SWITCH */ /*! * \brief a condition to determine if tracing is active */ #define TRACE_ACTIVE (true) /*! * \brief traces a string */ #define TRACE_INFO(x) { const char *string_test = (x); fprintf(TRACE_OUT_STREAM,"%s%s\n",TRACE_INDENT_INFO,string_test); } /*! * \brief traces a string and an integer */ #define TRACE_INFO_INT(x,i) { const char *string_test = (x); const int int_test = (i); fprintf(TRACE_OUT_STREAM,"%s%s %i\n",TRACE_INDENT_INFO,string_test,int_test); } /*! * \brief traces a string and two integers */ #define TRACE_INFO_INT_INT(x,i,j) { const char *string_test = (x); const int int_test = (i); const int int_test2 = (j); fprintf(TRACE_OUT_STREAM,"%s%s %i, %i\n",TRACE_INDENT_INFO,string_test,int_test,int_test2); } /*! * \brief traces a string and a hexadecimal integer */ #define TRACE_INFO_HEX(x,i) { const char *string_test = (x); const unsigned int int_test = (i); fprintf(TRACE_OUT_STREAM,"%s%s 0x%x\n",TRACE_INDENT_INFO,string_test,int_test); } /*! * \brief traces a string and a pointer */ #define TRACE_INFO_PTR(x,p) { const char *string_test = (x); const void *ptr_test = (p); fprintf(TRACE_OUT_STREAM,"%s%s @:%p\n",TRACE_INDENT_INFO,string_test,ptr_test); } /*! * \brief traces a string and and an information string */ #define TRACE_INFO_STR(x,s) { const char *string_test = (x); const char *string2_test = (s); fprintf(TRACE_OUT_STREAM,"%s%s %s\n",TRACE_INDENT_INFO,string_test,string2_test); } /*! * \brief traces a string and a double */ #define TRACE_INFO_FLT(x,r) { const char *string_test = (x); const double real_test = (r); fprintf(TRACE_OUT_STREAM,"%s%s %f\n",TRACE_INDENT_INFO,string_test,real_test); } /*! * \brief traces a function start * * Note: For every TRACE_BEGIN, one TRACE_END shall be called to create a nicely indented trace output */ #define TRACE_BEGIN() const unsigned int trace_symmetry_test=trace_indent_depth; { fprintf(TRACE_OUT_STREAM,"%s%s [begin]\n",TRACE_INDENT_BEGIN,__func__); trace_indent_depth++; } /*! * \brief traces a function return */ #define TRACE_END() { trace_indent_depth--; fprintf(TRACE_OUT_STREAM,"%s%s [end]\n",TRACE_INDENT_END,__func__); (void)trace_symmetry_test; } /*! * \brief traces a function return and an error code if the error does not equal 0 */ #define TRACE_END_ERR(e) { const int int_test = (e); if ( int_test==0 ) {TRACE_END();} else { trace_indent_depth--; fprintf(TRACE_OUT_STREAM,"%s%s [end] ERR=0x%x\n",TRACE_INDENT_END,__func__,int_test); } (void)trace_symmetry_test; } /*! * \brief ensures to flush all data. * * Call this macro before fork() or when you expect a process crash (e.g. SIGSEGV). */ #define TRACE_FLUSH() { fflush(TRACE_OUT_STREAM); } /*! * \brief traces a timestamp */ #ifdef _WIN32 #define TRACE_TIMESTAMP() { const clock_t now = clock(); fprintf(TRACE_OUT_STREAM,"%s[%i+%i/CLOCKS_PER_SEC]\n",TRACE_INDENT_INFO,(int)(now/CLOCKS_PER_SEC),(int)(now%CLOCKS_PER_SEC)); } #else #define TRACE_TIMESTAMP() { struct timespec tp; const int err = clock_gettime(CLOCK_MONOTONIC,&tp); fprintf(TRACE_OUT_STREAM,"%s[%i.%06i %s]\n",TRACE_INDENT_INFO,(int)(tp.tv_sec),(int)(tp.tv_nsec/1000),(err!=0)?"?":"sec"); } #endif #else /* SWITCH */ #ifdef __GNUC__ #define ATTR_UNUSED __attribute__((unused)) #else #define ATTR_UNUSED #endif /*! * \brief a condition to determine if tracing is active */ #define TRACE_ACTIVE (false) /*! * \brief traces a string */ #define TRACE_INFO(x) { const char *string_test ATTR_UNUSED = (x); } /*! * \brief traces a string and an integer */ #define TRACE_INFO_INT(x,i) { const char *string_test ATTR_UNUSED = (x); const int int_test ATTR_UNUSED = (i); } /*! * \brief traces a string and two integers */ #define TRACE_INFO_INT_INT(x,i,j) { const char *string_test ATTR_UNUSED = (x); const int int_test ATTR_UNUSED = (i); const int int_test2 ATTR_UNUSED = (j); } /*! * \brief traces a string and a hexadecimal integer */ #define TRACE_INFO_HEX(x,i) { const char *string_test ATTR_UNUSED = (x); const int int_test ATTR_UNUSED = (i); } /*! * \brief traces a string and a pointer */ #define TRACE_INFO_PTR(x,p) { const char *string_test ATTR_UNUSED = (x); const void *ptr_test ATTR_UNUSED = (p); } /*! * \brief traces a string and and an information string */ #define TRACE_INFO_STR(x,s) { const char *string_test ATTR_UNUSED = (x); const char *string2_test ATTR_UNUSED = (s); } /*! * \brief traces a string and a double */ #define TRACE_INFO_FLT(x,r) { const char *string_test ATTR_UNUSED = (x); const double real_test ATTR_UNUSED = (r); } /*! * \brief traces a function start * * Note: For every TRACE_BEGIN, one TRACE_END shall be called to create a nicely indented trace output */ #define TRACE_BEGIN() {} /*! * \brief traces a function return */ #define TRACE_END() {} /*! * \brief traces a function return and an error code if the error does not equal 0 */ #define TRACE_END_ERR(e) { const int int_test ATTR_UNUSED = (e); } /*! * \brief ensures to flush all data. * * Call this macro before fork() or when you expect a process crash (e.g. SIGSEGV). */ #define TRACE_FLUSH() {} /*! * \brief traces a timestamp */ #define TRACE_TIMESTAMP() {} #endif /* SWITCH */ #endif /* TRACE_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/trace/source/000077500000000000000000000000001415120503000175215ustar00rootroot00000000000000crystal-facet-uml-1.34.1/trace/source/trace.c000066400000000000000000000023371415120503000207700ustar00rootroot00000000000000/* File: trace.c; Copyright and License: see below */ #include "trace.h" #include #include __thread unsigned int trace_indent_depth = 0; const char trace_indent_pattern_begin[ TRACE_INDENT_STEP * TRACE_INDENT_MAX + TRACE_NULLTERM_SIZE ] = "| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | + \0"; const char trace_indent_pattern_end[ TRACE_INDENT_STEP * TRACE_INDENT_MAX + TRACE_NULLTERM_SIZE ] = "| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | \' \0"; const char trace_indent_pattern_info[ TRACE_INDENT_STEP * TRACE_INDENT_MAX +TRACE_NULLTERM_SIZE ] = "| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | \0"; /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/tslog/000077500000000000000000000000001415120503000162535ustar00rootroot00000000000000crystal-facet-uml-1.34.1/tslog/include/000077500000000000000000000000001415120503000176765ustar00rootroot00000000000000crystal-facet-uml-1.34.1/tslog/include/tslog.h000066400000000000000000000263361415120503000212110ustar00rootroot00000000000000/* File: tslog.h; Copyright and License: see below */ #ifndef TSLOG_H #define TSLOG_H /* public file for the doxygen documentation: */ /*! * \file * \brief Prints error and event logs to a byte stream * * In contrast to syslog and printf, these macros are typesafe. * * An error is a condition that leads to an observalbe malfunction. * E.g. removing the device on which the database is stored. * * A warning is issued when a condition may possibly lead to a malfunction. * E.g. Opening a read-only database file. * * An anomaly is a non-standard condition that is expected to not cause a malfunction. * This should be logged to easier analyze issues. E.g. paste an empty clipboard. * * An event is a signal that is send to or received from external software parts. */ #include #include #ifdef __linux__ #include #endif // __linux__ #ifndef NDEBUG #include #include #endif // NDEBUG /*define TSLOG_OUT_STREAM stderr -- stdout is better because traces and logs are merged to the same stream in the right order */ #define TSLOG_OUT_STREAM stdout #ifndef NDEBUG /* SWITCH RELEASE/DEBUG */ #define TSLOG_RED "\033[37;1;41m" #define TSLOG_YELLOW "\033[30;43m" #define TSLOG_CYAN "\033[30;46m" #define TSLOG_INVERSE "\033[7m" #define TSLOG_NORM "\033[0m" #define TSLOG_PREFIX_ERR TSLOG_RED "\nERR " TSLOG_NORM ": " #define TSLOG_PREFIX_WARN TSLOG_YELLOW "\nWARN" TSLOG_NORM ": " #define TSLOG_PREFIX_ANOM TSLOG_CYAN "\nANOM" TSLOG_NORM ": " #define TSLOG_PREFIX_EVT TSLOG_INVERSE "\nEVT " TSLOG_NORM ": " /*! * \brief starts to log */ #define TSLOG_INIT(program_id) {} /*! * \brief stops logging */ #define TSLOG_DESTROY() {} /*! * \brief logs an error string */ #define TSLOG_ERROR(x) { const char *string_test = (x); fprintf(TSLOG_OUT_STREAM, TSLOG_PREFIX_ERR "%s\n", string_test); fflush(TSLOG_OUT_STREAM); } /*! * \brief logs an error string and an integer */ #define TSLOG_ERROR_INT(x,i) { const char *string_test = (x); const int int_test = (i); fprintf(TSLOG_OUT_STREAM, TSLOG_PREFIX_ERR "%s %i\n", string_test, int_test); fflush(TSLOG_OUT_STREAM); } /*! * \brief logs an error string and a hexadecimal integer */ #define TSLOG_ERROR_HEX(x,i) { const char *string_test = (x); const unsigned int int_test = (i); fprintf(TSLOG_OUT_STREAM, TSLOG_PREFIX_ERR "%s 0x%x\n", string_test, int_test); fflush(TSLOG_OUT_STREAM); } /*! * \brief logs an error string and an information string */ #define TSLOG_ERROR_STR(x,s) { const char *string_test = (x); const char *string2_test = (s); fprintf(TSLOG_OUT_STREAM, TSLOG_PREFIX_ERR "%s %s\n", string_test, string2_test); fflush(TSLOG_OUT_STREAM); } /*! * \brief logs a warning string */ #define TSLOG_WARNING(x) { const char *string_test = (x); fprintf(TSLOG_OUT_STREAM, TSLOG_PREFIX_WARN "%s\n" TSLOG_NORM, string_test); fflush(TSLOG_OUT_STREAM); } /*! * \brief logs a warning string and an integer */ #define TSLOG_WARNING_INT(x,i) { const char *string_test = (x); const int int_test = (i); fprintf(TSLOG_OUT_STREAM, TSLOG_PREFIX_WARN "%s %i\n" TSLOG_NORM, string_test, int_test); fflush(TSLOG_OUT_STREAM); } /*! * \brief logs a warning string and a hexadecimal integer */ #define TSLOG_WARNING_HEX(x,i) { const char *string_test = (x); const unsigned int int_test = (i); fprintf(TSLOG_OUT_STREAM, TSLOG_PREFIX_WARN "%s 0x%x\n" TSLOG_NORM, string_test, int_test); fflush(TSLOG_OUT_STREAM); } /*! * \brief logs a warning string and an information string */ #define TSLOG_WARNING_STR(x,s) { const char *string_test = (x); const char *string2_test = (s); fprintf(TSLOG_OUT_STREAM, TSLOG_PREFIX_WARN "%s %s\n" TSLOG_NORM, string_test, string2_test); fflush(TSLOG_OUT_STREAM); } /*! * \brief logs an anomaly string */ #define TSLOG_ANOMALY(x) { const char *string_test = (x); fprintf(TSLOG_OUT_STREAM, TSLOG_PREFIX_ANOM "%s\n", string_test); } /*! * \brief logs an anomaly string and an integer */ #define TSLOG_ANOMALY_INT(x,i) { const char *string_test = (x); const int int_test = (i); fprintf(TSLOG_OUT_STREAM, TSLOG_PREFIX_ANOM "%s %i\n", string_test, int_test); } /*! * \brief logs an anomaly string and a hexadecimal integer */ #define TSLOG_ANOMALY_HEX(x,i) { const char *string_test = (x); const unsigned int int_test = (i); fprintf(TSLOG_OUT_STREAM, TSLOG_PREFIX_ANOM "%s 0x%x\n", string_test, int_test); } /*! * \brief logs an anomaly string and an information string */ #define TSLOG_ANOMALY_STR(x,s) { const char *string_test = (x); const char *string2_test = (s); fprintf(TSLOG_OUT_STREAM, TSLOG_PREFIX_ANOM "%s %s\n", string_test, string2_test); } /*! * \brief logs an event string */ #define TSLOG_EVENT(x) { const char *string_test = (x); fprintf(TSLOG_OUT_STREAM, TSLOG_PREFIX_EVT "%s\n",string_test); } /*! * \brief logs an event string and an integer */ #define TSLOG_EVENT_INT(x,i) { const char *string_test = (x); const int int_test = (i); fprintf(TSLOG_OUT_STREAM, TSLOG_PREFIX_EVT "%s %i\n", string_test, int_test); } /*! * \brief logs an event string and a hexadecimal integer */ #define TSLOG_EVENT_HEX(x,i) { const char *string_test = (x); const unsigned int int_test = (i); fprintf(TSLOG_OUT_STREAM, TSLOG_PREFIX_EVT "%s 0x%x\n", string_test, int_test); } /*! * \brief logs an event string and an information string */ #define TSLOG_EVENT_STR(x,s) { const char *string_test = (x); const char *string2_test = (s); fprintf(TSLOG_OUT_STREAM, TSLOG_PREFIX_EVT "%s %s\n", string_test, string2_test); } #else /* SWITCH RELEASE/DEBUG */ #ifdef __linux__ /* SWITCH RELEASE SYSLOG */ /*! * \brief starts to log */ #define TSLOG_INIT(program_id) { const char *string_test = (program_id); openlog( /* ident: */ string_test, /* options: */ 0, /* facility: */ LOG_USER ); } /*! * \brief stops logging */ #define TSLOG_DESTROY() { closelog(); } /*! * \brief logs an error string */ #define TSLOG_ERROR(x) { const char *string_test = (x); syslog(LOG_ERR,"ERR : %s",string_test); } /*! * \brief logs an error string and an integer */ #define TSLOG_ERROR_INT(x,i) { const char *string_test = (x); const int int_test = (i); syslog(LOG_ERR,"ERR : %s %i",string_test,int_test); } /*! * \brief logs an error string and a hexadecimal integer */ #define TSLOG_ERROR_HEX(x,i) { const char *string_test = (x); const unsigned int int_test = (i); syslog(LOG_ERR,"ERR : %s 0x%x",string_test,int_test); } /*! * \brief logs an error string and an information string */ #define TSLOG_ERROR_STR(x,s) { const char *string_test = (x); const char *string2_test = (s); syslog(LOG_ERR,"ERR : %s %s",string_test,string2_test); } /*! * \brief logs a warning string */ #define TSLOG_WARNING(x) { const char *string_test = (x); syslog(LOG_WARNING,"WARN: %s",string_test); } /*! * \brief logs a warning string and an integer */ #define TSLOG_WARNING_INT(x,i) { const char *string_test = (x); const int int_test = (i); syslog(LOG_WARNING,"WARN: %s %i",string_test,int_test); } /*! * \brief logs a warning string and a hexadecimal integer */ #define TSLOG_WARNING_HEX(x,i) { const char *string_test = (x); const unsigned int int_test = (i); syslog(LOG_WARNING,"WARN: %s 0x%x",string_test,int_test); } /*! * \brief logs a warning string and an information string */ #define TSLOG_WARNING_STR(x,s) { const char *string_test = (x); const char *string2_test = (s); syslog(LOG_WARNING,"WARN: %s %s",string_test,string2_test); } /*! * \brief logs an anomaly string */ #define TSLOG_ANOMALY(x) { const char *string_test = (x); syslog(LOG_INFO,"ANOM: %s",string_test); } /*! * \brief logs an anomaly string and an integer */ #define TSLOG_ANOMALY_INT(x,i) { const char *string_test = (x); const int int_test = (i); syslog(LOG_INFO,"ANOM: %s %i",string_test,int_test); } /*! * \brief logs an anomaly string and a hexadecimal integer */ #define TSLOG_ANOMALY_HEX(x,i) { const char *string_test = (x); const unsigned int int_test = (i); syslog(LOG_INFO,"ANOM: %s 0x%x",string_test,int_test); } /*! * \brief logs an anomaly string and an information string */ #define TSLOG_ANOMALY_STR(x,s) { const char *string_test = (x); const char *string2_test = (s); syslog(LOG_INFO,"ANOM: %s %s",string_test,string2_test); } /*! * \brief logs an event string */ #define TSLOG_EVENT(x) { const char *string_test __attribute__((unused)) = (x); /*syslog(LOG_INFO,"EVT : %s",string_test);*/ } /*! * \brief logs an event string and an integer */ #define TSLOG_EVENT_INT(x,i) { const char *string_test __attribute__((unused)) = (x); const int int_test __attribute__((unused)) = (i); /*syslog(LOG_INFO,"EVT : %s %i",string_test,int_test);*/ } /*! * \brief logs an event string and a hexadecimal integer */ #define TSLOG_EVENT_HEX(x,i) { const char *string_test __attribute__((unused)) = (x); const unsigned int int_test __attribute__((unused)) = (i); /*syslog(LOG_INFO,"EVT : %s 0x%x",string_test,int_test);*/ } /*! * \brief logs an event string and an information string */ #define TSLOG_EVENT_STR(x,s) { const char *string_test __attribute__((unused)) = (x); const char *string2_test __attribute__((unused)) = (s); /*syslog(LOG_INFO,"EVT : %s %s",string_test,string2_test);*/ } #else /* SWITCH RELEASE SYSLOG */ /*! * \brief starts to log */ #define TSLOG_INIT(program_id) {} /*! * \brief stops logging */ #define TSLOG_DESTROY() {} /*! * \brief logs an error string */ #define TSLOG_ERROR(x) {} /*! * \brief logs an error string and an integer */ #define TSLOG_ERROR_INT(x,i) {} /*! * \brief logs an error string and a hexadecimal integer */ #define TSLOG_ERROR_HEX(x,i) {} /*! * \brief logs an error string and an information string */ #define TSLOG_ERROR_STR(x,s) {} /*! * \brief logs a warning string */ #define TSLOG_WARNING(x) {} /*! * \brief logs a warning string and an integer */ #define TSLOG_WARNING_INT(x,i) {} /*! * \brief logs a warning string and a hexadecimal integer */ #define TSLOG_WARNING_HEX(x,i) {} /*! * \brief logs a warning string and an information string */ #define TSLOG_WARNING_STR(x,s) {} /*! * \brief logs an anomaly string */ #define TSLOG_ANOMALY(x) {} /*! * \brief logs an anomaly string and an integer */ #define TSLOG_ANOMALY_INT(x,i) {} /*! * \brief logs an anomaly string and a hexadecimal integer */ #define TSLOG_ANOMALY_HEX(x,i) {} /*! * \brief logs an anomaly string and an information string */ #define TSLOG_ANOMALY_STR(x,s) {} /*! * \brief logs an event string */ #define TSLOG_EVENT(x) {} /*! * \brief logs an event string and an integer */ #define TSLOG_EVENT_INT(x,i) {} /*! * \brief logs an event string and a hexadecimal integer */ #define TSLOG_EVENT_HEX(x,i) {} /*! * \brief logs an event string and an information string */ #define TSLOG_EVENT_STR(x,s) {} #endif /* SWITCH RELEASE SYSLOG */ #endif /* SWITCH RELEASE/DEBUG */ #endif /* TSLOG_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/000077500000000000000000000000001415120503000171335ustar00rootroot00000000000000crystal-facet-uml-1.34.1/universal/include/000077500000000000000000000000001415120503000205565ustar00rootroot00000000000000crystal-facet-uml-1.34.1/universal/include/arena/000077500000000000000000000000001415120503000216445ustar00rootroot00000000000000crystal-facet-uml-1.34.1/universal/include/arena/universal_arena_list.h000066400000000000000000000054611415120503000262340ustar00rootroot00000000000000/* File: universal_arena_list.h; Copyright and License: see below */ #ifndef UNIVERSAL_ARENA_LIST_H #define UNIVERSAL_ARENA_LIST_H /* public file for the doxygen documentation: */ /*! * \file * \brief implements a single linked list for use in a memory region. */ #include "arena/universal_arena_list_element.h" #include "arena/universal_memory_arena.h" /*! * \brief attributes of the universal_arena_list */ struct universal_arena_list_struct { universal_arena_list_element_t *begin; /*!< first element of the single-linked list or NULL if empty */ universal_memory_arena_t *allocator; /*!< allocator where append allocates memory from */ }; typedef struct universal_arena_list_struct universal_arena_list_t; /*! * \brief initializes the universal_arena_list_t * * \param this_ pointer to own object attributes * \param allocator allocator where universal_arena_list_append allocates memory from */ static inline void universal_arena_list_init ( universal_arena_list_t *this_, universal_memory_arena_t *allocator ); /*! * \brief destroys the universal_arena_list_t * * \param this_ pointer to own object attributes */ static inline void universal_arena_list_destroy ( universal_arena_list_t *this_ ); /*! * \brief appends a pointer to an element to the universal_arena_list_t * * \param this_ pointer to own object attributes * \param element pointer to the element to be appended. Only a valid object can be added, NULL is not allowed. * \return -1 if allocator is out of memory, 0 on success */ static inline int universal_arena_list_append ( universal_arena_list_t *this_, void* element ); /*! * \brief gets the begin of universal_arena_list_t * * \param this_ pointer to own object attributes * \return pointer to the first element or NULL if empty */ static inline universal_arena_list_element_t* universal_arena_list_get_begin ( universal_arena_list_t *this_ ); /*! * \brief gets NULL; for usage in an iterator-like way "for it=begin, it!=end, it=it.next" * * \param this_ pointer to own object attributes * \return always NULL */ static inline universal_arena_list_element_t* universal_arena_list_get_end ( universal_arena_list_t *this_ ); #include "arena/universal_arena_list.inl" #endif /* UNIVERSAL_ARENA_LIST_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/arena/universal_arena_list.inl000066400000000000000000000053141415120503000265640ustar00rootroot00000000000000/* File: universal_arena_list.inl; Copyright and License: see below */ #include #include static inline void universal_arena_list_init( universal_arena_list_t *this_, universal_memory_arena_t *allocator ) { assert( allocator != NULL ); (*this_).begin = NULL; (*this_).allocator = allocator; } static inline void universal_arena_list_destroy( universal_arena_list_t *this_ ) { assert( (*this_).allocator != NULL ); (*this_).allocator = NULL; (*this_).begin = NULL; } static inline int universal_arena_list_append( universal_arena_list_t *this_, void* element ) { assert( (*this_).allocator != NULL ); int err = 0; universal_arena_list_element_t *new_ele; err = universal_memory_arena_get_block( (*this_).allocator, sizeof(universal_arena_list_element_t), (void**)&new_ele ); if ( err == 0 ) { universal_arena_list_element_init( new_ele, element, NULL ); if ( (*this_).begin == NULL ) { (*this_).begin = new_ele; } else { universal_arena_list_element_t *find_last = (*this_).begin; bool finished = false; for ( uint_fast32_t cnt = 0; ( cnt < 1000000000 )&&( ! finished ); cnt ++ ) { if ( universal_arena_list_element_get_next( find_last ) == NULL ) { universal_arena_list_element_set_next( find_last, new_ele ); finished = true; } else { find_last = universal_arena_list_element_get_next( find_last ); } } if ( ! finished ) { TSLOG_WARNING("max loop count exceeded in universal_arena_list_append, list too long"); err = -1; } } } return err; } static inline universal_arena_list_element_t* universal_arena_list_get_begin( universal_arena_list_t *this_ ) { return (*this_).begin; } static inline universal_arena_list_element_t* universal_arena_list_get_end( universal_arena_list_t *this_ ) { return NULL; } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/arena/universal_arena_list_element.h000066400000000000000000000057011415120503000277420ustar00rootroot00000000000000/* File: universal_arena_list_element.h; Copyright and License: see below */ #ifndef UNIVERSAL_ARENA_LIST_ELEMENT_H #define UNIVERSAL_ARENA_LIST_ELEMENT_H /* public file for the doxygen documentation: */ /*! * \file * \brief is an element of a single-linked list. */ /*! * \brief attributes of the universal_arena_list_element */ struct universal_arena_list_element_struct { void* data; /*!< pointer to the data of the element */ struct universal_arena_list_element_struct* next; /*!< next element in list or NULL */ }; typedef struct universal_arena_list_element_struct universal_arena_list_element_t; /*! * \brief initializes the universal_arena_list_element_t * * \param this_ pointer to own object attributes * \param data pointer to the data of the element * \param next next element in list or NULL */ static inline void universal_arena_list_element_init ( universal_arena_list_element_t *this_, void* data, universal_arena_list_element_t* next ); /*! * \brief destroys the universal_arena_list_element_t * * \param this_ pointer to own object attributes */ static inline void universal_arena_list_element_destroy ( universal_arena_list_element_t *this_ ); /*! * \brief gets the data of universal_arena_list_element_t * * \param this_ pointer to own object attributes * \return pointer to data */ static inline void* universal_arena_list_element_get_data ( universal_arena_list_element_t *this_ ); /*! * \brief gets the next element after this universal_arena_list_element_t * * \param this_ pointer to own object attributes * \return pointer to next */ static inline universal_arena_list_element_t* universal_arena_list_element_get_next ( universal_arena_list_element_t *this_ ); /*! * \brief sets the next element after this universal_arena_list_element_t * * \param this_ pointer to own object attributes * \param next next element in list or NULL */ static inline void universal_arena_list_element_set_next ( universal_arena_list_element_t *this_, universal_arena_list_element_t *next ); #include "arena/universal_arena_list_element.inl" #endif /* UNIVERSAL_ARENA_LIST_ELEMENT_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/arena/universal_arena_list_element.inl000066400000000000000000000033201415120503000302700ustar00rootroot00000000000000/* File: universal_arena_list_element.inl; Copyright and License: see below */ #include static inline void universal_arena_list_element_init( universal_arena_list_element_t *this_, void* data, universal_arena_list_element_t* next ) { assert( data != NULL ); (*this_).data = data; (*this_).next = next; } static inline void universal_arena_list_element_destroy( universal_arena_list_element_t *this_ ) { assert( (*this_).data != NULL ); (*this_).data = NULL; (*this_).next = NULL; } static inline void* universal_arena_list_element_get_data( universal_arena_list_element_t *this_ ) { assert( (*this_).data != NULL ); return (*this_).data; } static inline universal_arena_list_element_t* universal_arena_list_element_get_next( universal_arena_list_element_t *this_ ) { return (*this_).next; } static inline void universal_arena_list_element_set_next( universal_arena_list_element_t *this_, universal_arena_list_element_t *next ) { (*this_).next = next; } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/arena/universal_memory_arena.h000066400000000000000000000055731415120503000265750ustar00rootroot00000000000000/* File: universal_memory_arena.h; Copyright and License: see below */ #ifndef UNIVERSAL_MEMORY_ARENA_H #define UNIVERSAL_MEMORY_ARENA_H /* public file for the doxygen documentation: */ /*! * \file * \brief implements a memory region from which memory blocks can be allocated dynamically. * * The memory region itself may be statically allocated. * These functions are not multi-thread safe. */ /*! * \brief attributes of the universal_memory_arena */ struct universal_memory_arena_struct { char* mem_buf_start; /*!< memory buffer start */ size_t mem_buf_size; /*!< memory buffer size */ size_t mem_buf_used; /*!< part of the memory buffer that is already in use */ }; typedef struct universal_memory_arena_struct universal_memory_arena_t; /*! * \brief initializes the universal_memory_arena_t * * \param this_ pointer to own object attributes * \param mem_buf_start address of memory buffer * \param mem_buf_size size of the memory buffer */ static inline void universal_memory_arena_init ( universal_memory_arena_t *this_, void* mem_buf_start, size_t mem_buf_size ); /*! * \brief destroys the universal_memory_arena_t * * \param this_ pointer to own object attributes */ static inline void universal_memory_arena_destroy ( universal_memory_arena_t *this_ ); /*! * \brief resets the memory buffer, all memory is treated as unused * * \param this_ pointer to own object attributes */ static inline void universal_memory_arena_reset ( universal_memory_arena_t *this_ ); /*! * \brief fetches a memory block from a memory region * * \param this_ pointer to own object attributes * \param block_size size of the buffer to allocate * \param out_block start address of the allocated block, NULL if none available * \return 0 in case of success, -1 if there is not sufficient memory available */ static inline int universal_memory_arena_get_block ( universal_memory_arena_t *this_, size_t block_size, void **out_block ); #include "arena/universal_memory_arena.inl" #endif /* UNIVERSAL_MEMORY_ARENA_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/arena/universal_memory_arena.inl000066400000000000000000000047171415120503000271270ustar00rootroot00000000000000/* File: universal_memory_arena.inl; Copyright and License: see below */ #include static inline void universal_memory_arena_init ( universal_memory_arena_t *this_, void* mem_buf_start, size_t mem_buf_size ) { assert( mem_buf_start != NULL ); (*this_).mem_buf_start = mem_buf_start; (*this_).mem_buf_size = mem_buf_size; (*this_).mem_buf_used = 0; } static inline void universal_memory_arena_destroy ( universal_memory_arena_t *this_ ) { assert( (*this_).mem_buf_start != NULL ); (*this_).mem_buf_start = NULL; } static inline void universal_memory_arena_reset ( universal_memory_arena_t *this_ ) { (*this_).mem_buf_used = 0; } static inline int universal_memory_arena_get_block ( universal_memory_arena_t *this_, size_t block_size, void **out_block ) { assert( out_block != NULL ); int err = 0; static const unsigned int align = sizeof(int); static const unsigned int align_mask = ~(-align); /* assuming a complement of 2 presentation */ /* -1 = 11111111, -2 = 11111110, -4 = 11111100, -8 = 11111000 */ char *const free_start = (*this_).mem_buf_start + (*this_).mem_buf_used; const unsigned int free_misalign = ((unsigned int)free_start) & align_mask; unsigned int padding = (free_misalign==0) ? 0 : (align-free_misalign); char *const block_start = (*this_).mem_buf_start + (*this_).mem_buf_used + padding; char *const next_start = block_start + block_size; if (( (*this_).mem_buf_start + (*this_).mem_buf_size )<( next_start )) { err = -1; *out_block = NULL; } else { err = 0; *out_block = block_start; (*this_).mem_buf_used = next_start - (*this_).mem_buf_start; } return err; } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/stream/000077500000000000000000000000001415120503000220515ustar00rootroot00000000000000crystal-facet-uml-1.34.1/universal/include/stream/universal_buffer_input_stream.h000066400000000000000000000107621415120503000303630ustar00rootroot00000000000000/* File: universal_buffer_input_stream.h; Copyright and License: see below */ #ifndef UNIVERSAL_BUFFER_INPUT_STREAM_H #define UNIVERSAL_BUFFER_INPUT_STREAM_H /* public file for the doxygen documentation: */ /*! * \file * \brief implements an universal_input_stream and buffers data in a fixed-sized memory buffer */ #include "stream/universal_input_stream.h" /*! * \brief attributes of the universal_buffer_input_stream */ struct universal_buffer_input_stream_struct { universal_input_stream_t input_stream; /*!< instance of implemented interface \c universal_input_stream_t */ void* mem_buf_start; /*!< input memory buffer start */ size_t mem_buf_size; /*!< input memory buffer size */ size_t mem_buf_fill; /*!< input memory buffer: amount of valid, read bytes */ size_t mem_buf_pos; /*!< read position in the input memory buffer */ universal_input_stream_t *source; /*!< pointer to stream source, an external \c universal_input_stream_t */ size_t stream_pos_of_buf; /*!< buffer position in the total stream; read position is (stream_pos_of_buf+mem_buf_pos) */ }; typedef struct universal_buffer_input_stream_struct universal_buffer_input_stream_t; /*! * \brief initializes the universal_buffer_input_stream_t * * \param this_ pointer to own object attributes * \param mem_buf_start address of memory buffer * \param mem_buf_size size of the memory buffer * \param source stream source where to read bytes from when buffer empty */ void universal_buffer_input_stream_init ( universal_buffer_input_stream_t *this_, void* mem_buf_start, size_t mem_buf_size, universal_input_stream_t *source ); /*! * \brief destroys the universal_buffer_input_stream_t * * \param this_ pointer to own object attributes */ void universal_buffer_input_stream_destroy ( universal_buffer_input_stream_t *this_ ); /*! * \brief resets the buffer to empty * * \param this_ pointer to own object attributes */ void universal_buffer_input_stream_reset ( universal_buffer_input_stream_t *this_ ); /*! * \brief reads a buffer from a memory region * * \param this_ pointer to own object attributes * \param out_buffer buffer to write read bytes * \param max_size length of the buffer to write * \param out_length number of bytes read * \return 0 in case of success, -1 if there are no further bytes to read */ int universal_buffer_input_stream_read ( universal_buffer_input_stream_t *this_, void *out_buffer, size_t max_size, size_t *out_length ); /*! * \brief fetches 1 byte from the input buffer without moving the read position. * * \param this_ pointer to own object attributes * \return next byte or '\0' if end of stream */ static inline char universal_buffer_input_stream_peek_next ( universal_buffer_input_stream_t *this_ ); /*! * \brief reads 1 byte from the input buffer, * * \param this_ pointer to own object attributes * \return next byte or '\0' if end of stream */ static inline char universal_buffer_input_stream_read_next ( universal_buffer_input_stream_t *this_ ); /*! * \brief returns the current read position * * \param this_ pointer to own object attributes * \return read position */ static inline size_t universal_buffer_input_stream_read_pos ( universal_buffer_input_stream_t *this_ ); /*! * \brief gets the input stream interface of this universal_buffer_input_stream_t * * \param this_ pointer to own object attributes * \return the abstract base class of this_ */ universal_input_stream_t* universal_buffer_input_stream_get_input_stream( universal_buffer_input_stream_t *this_ ); #include "universal_buffer_input_stream.inl" #endif /* UNIVERSAL_BUFFER_INPUT_STREAM_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/stream/universal_buffer_input_stream.inl000066400000000000000000000055721415120503000307210ustar00rootroot00000000000000/* File: universal_buffer_input_stream.inl; Copyright and License: see below */ #include static inline char universal_buffer_input_stream_peek_next( universal_buffer_input_stream_t *this_ ) { assert( (*this_).mem_buf_start != NULL ); assert( (*this_).mem_buf_fill >= (*this_).mem_buf_pos ); assert( (*this_).mem_buf_size >= (*this_).mem_buf_fill ); char result = '\0'; const size_t buf_available1 = (*this_).mem_buf_fill - (*this_).mem_buf_pos; if ( buf_available1 == 0 ) { /* try to fill buffer */ (*this_).stream_pos_of_buf += (*this_).mem_buf_fill; (*this_).mem_buf_pos = 0; (*this_).mem_buf_fill = 0; const int err = universal_input_stream_read( (*this_).source, (*this_).mem_buf_start, (*this_).mem_buf_size, &((*this_).mem_buf_fill) ); if (( 0 == err )&&( (*this_).mem_buf_fill > 0 )) { result = (*( (char(*)[]) (*this_).mem_buf_start ))[0]; } } else { result = (*( (char(*)[]) (*this_).mem_buf_start ))[(*this_).mem_buf_pos]; } return result; } static inline char universal_buffer_input_stream_read_next( universal_buffer_input_stream_t *this_ ) { assert( (*this_).mem_buf_start != NULL ); assert( (*this_).mem_buf_fill >= (*this_).mem_buf_pos ); assert( (*this_).mem_buf_size >= (*this_).mem_buf_fill ); char result = '\0'; const size_t buf_available1 = (*this_).mem_buf_fill - (*this_).mem_buf_pos; if ( buf_available1 == 0 ) { /* try to fill buffer */ (*this_).stream_pos_of_buf += (*this_).mem_buf_fill; (*this_).mem_buf_pos = 0; (*this_).mem_buf_fill = 0; const int err = universal_input_stream_read( (*this_).source, (*this_).mem_buf_start, (*this_).mem_buf_size, &((*this_).mem_buf_fill) ); if (( 0 == err )&&( (*this_).mem_buf_fill > 0 )) { result = (*( (char(*)[]) (*this_).mem_buf_start ))[0]; (*this_).mem_buf_pos = 1; } } else { result = (*( (char(*)[]) (*this_).mem_buf_start ))[(*this_).mem_buf_pos]; (*this_).mem_buf_pos ++; } return result; } static inline size_t universal_buffer_input_stream_read_pos ( universal_buffer_input_stream_t *this_ ) { return (*this_).stream_pos_of_buf + (*this_).mem_buf_pos; } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/stream/universal_buffer_output_stream.h000066400000000000000000000066461415120503000305720ustar00rootroot00000000000000/* File: universal_buffer_output_stream.h; Copyright and License: see below */ #ifndef UNIVERSAL_BUFFER_INPUT_STREAM_H #define UNIVERSAL_BUFFER_INPUT_STREAM_H /* public file for the doxygen documentation: */ /*! * \file * \brief implements an universal_output_stream and buffers data in a fixed-sized memory buffer */ #include "stream/universal_output_stream.h" /*! * \brief attributes of the universal_buffer_output_stream */ struct universal_buffer_output_stream_struct { universal_output_stream_t output_stream; /*!< instance of implemented interface \c universal_output_stream_t */ void* mem_buf_start; /*!< output memory buffer start */ size_t mem_buf_size; /*!< output memory buffer size */ size_t mem_buf_filled; /*!< number of bytes written to the output memory buffer */ universal_output_stream_t *sink; /*!< pointer to stream sink, an external \c universal_output_stream_t */ }; typedef struct universal_buffer_output_stream_struct universal_buffer_output_stream_t; /*! * \brief initializes the universal_buffer_output_stream_t * * \param this_ pointer to own object attributes * \param mem_buf_start address of memory buffer * \param mem_buf_size size of the memory buffer * \param sink stream sink where to forward bytes to at flush and at full buffer */ void universal_buffer_output_stream_init( universal_buffer_output_stream_t *this_, void* mem_buf_start, size_t mem_buf_size, universal_output_stream_t *sink ); /*! * \brief destroys the universal_buffer_output_stream_t * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int universal_buffer_output_stream_destroy( universal_buffer_output_stream_t *this_ ); /*! * \brief writes a buffer (e.g. a stringview) to a memory output stream * * \param this_ pointer to own object attributes * \param start buffer to write, not 0-terminated * \param length length of the buffer to write * \return 0 in case of success, -1 otherwise */ int universal_buffer_output_stream_write ( universal_buffer_output_stream_t *this_, const void *start, size_t length ); /*! * \brief flushes buffers * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int universal_buffer_output_stream_flush( universal_buffer_output_stream_t *this_ ); /*! * \brief gets the output stream interface of this universal_buffer_output_stream_t * * \param this_ pointer to own object attributes * \return the abstract base class of this_ */ universal_output_stream_t* universal_buffer_output_stream_get_output_stream( universal_buffer_output_stream_t *this_ ); #include "universal_buffer_output_stream.inl" #endif /* UNIVERSAL_BUFFER_INPUT_STREAM_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/stream/universal_buffer_output_stream.inl000066400000000000000000000012361415120503000311130ustar00rootroot00000000000000/* File: universal_buffer_output_stream.inl; Copyright and License: see below */ #include /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/stream/universal_escaping_output_stream.h000066400000000000000000000103521415120503000310770ustar00rootroot00000000000000/* File: universal_escaping_output_stream.h; Copyright and License: see below */ #ifndef UNIVERSAL_ESCAPING_OUTPUT_STREAM_H #define UNIVERSAL_ESCAPING_OUTPUT_STREAM_H /* public file for the doxygen documentation: */ /*! * \file * \brief implements an universal_output_stream_if that replaces a set of predefined * character sequences by other character sequences and forwards the output * to an other output stream. * * This class can be used to e.g escape a couple of characters by escape sequences * or to indent lines after every newline character. * This class does not search for sequences that are split between multiple write calls. */ #include "stream/universal_output_stream.h" /*! * \brief attributes of the universal_escaping_output_stream */ struct universal_escaping_output_stream_struct { universal_output_stream_t output_stream; /*!< instance of implemented interface \c universal_output_stream_t */ const char *const ((*patterns_and_replacements)[][2]); /*!< array of 0-terminated pattern and replacement strings, NULL terminated. */ universal_output_stream_t *sink; /*!< pointer to data stream sink */ }; typedef struct universal_escaping_output_stream_struct universal_escaping_output_stream_t; /*! * \brief initializes the universal_escaping_output_stream_t * * \param this_ pointer to own object attributes * \param patterns_and_replacements pointer to 2-dim array, NULL-terminated, * each arrray-entry is a pointer to a 0-terminated string. * \param sink pointer to data stream sink */ void universal_escaping_output_stream_init( universal_escaping_output_stream_t *this_, const char *const ((*patterns_and_replacements)[][2]), universal_output_stream_t *sink ); /*! * \brief destroys the universal_escaping_output_stream_t but not the underlying sink * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int universal_escaping_output_stream_destroy( universal_escaping_output_stream_t *this_ ); /*! * \brief changes the patterns_and_replacements attribute * * \param this_ pointer to own object attributes * \param patterns_and_replacements pointer to 2-dim array, NULL-terminated, * each arrray-entry is a pointer to a 0-terminated string. */ void universal_escaping_output_stream_change_rules( universal_escaping_output_stream_t *this_, const char *const ((*patterns_and_replacements)[][2]) ); /*! * \brief writes a buffer (e.g. a stringview) to the data sink, replacing patterns by replacements * * \param this_ pointer to own object attributes * \param start buffer to write, not 0-terminated * \param length length of the buffer to write * \return 0 in case of success, -1 otherwise */ int universal_escaping_output_stream_write ( universal_escaping_output_stream_t *this_, const void *start, size_t length ); /*! * \brief flushes buffers including the ones of the underlying sink * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int universal_escaping_output_stream_flush( universal_escaping_output_stream_t *this_ ); /*! * \brief gets the output stream interface of this universal_escaping_output_stream_t * * \param this_ pointer to own object attributes * \return the abstract base class of this_ */ universal_output_stream_t* universal_escaping_output_stream_get_output_stream( universal_escaping_output_stream_t *this_ ); #endif /* UNIVERSAL_ESCAPING_OUTPUT_STREAM_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/stream/universal_file_input_stream.h000066400000000000000000000062701415120503000300300ustar00rootroot00000000000000/* File: universal_file_input_stream.h; Copyright and License: see below */ #ifndef UNIVERSAL_FILE_INPUT_STREAM_H #define UNIVERSAL_FILE_INPUT_STREAM_H /* public file for the doxygen documentation: */ /*! * \file * \brief implements an universal_input_stream_if and forwards data from a FILE */ #include "stream/universal_input_stream.h" #include /*! * \brief attributes of the universal_file_input_stream */ struct universal_file_input_stream_struct { universal_input_stream_t input_stream; /*!< instance of implemented interface \c universal_input_stream_t */ FILE *input; /*!< input file */ }; typedef struct universal_file_input_stream_struct universal_file_input_stream_t; /*! * \brief initializes the universal_file_input_stream_t * * \param this_ pointer to own object attributes */ void universal_file_input_stream_init( universal_file_input_stream_t *this_ ); /*! * \brief destroys the universal_file_input_stream_t * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int universal_file_input_stream_destroy( universal_file_input_stream_t *this_ ); /*! * \brief resets the read position to 0 * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int universal_file_input_stream_reset ( universal_file_input_stream_t *this_ ); /*! * \brief opens a file * * \param this_ pointer to own object attributes * \param path file path identifying the file to open for reading * \return 0 in case of success, -1 otherwise */ int universal_file_input_stream_open ( universal_file_input_stream_t *this_, const char *path ); /*! * \brief reads a buffer from a file * * \param this_ pointer to own object attributes * \param out_buffer buffer to write read bytes * \param max_size length of the buffer to write * \param out_length number of bytes read * \return 0 in case of success, -1 otherwise */ int universal_file_input_stream_read ( universal_file_input_stream_t *this_, void *out_buffer, size_t max_size, size_t *out_length ); /*! * \brief closes the universal_file_input_stream_t * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int universal_file_input_stream_close( universal_file_input_stream_t *this_ ); /*! * \brief gets the input stream interface of this universal_file_input_stream_t * * \param this_ pointer to own object attributes * \return the abstract base class of this_ */ universal_input_stream_t* universal_file_input_stream_get_input_stream( universal_file_input_stream_t *this_ ); #endif /* UNIVERSAL_FILE_INPUT_STREAM_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/stream/universal_file_output_stream.h000066400000000000000000000062371415120503000302340ustar00rootroot00000000000000/* File: universal_file_output_stream.h; Copyright and License: see below */ #ifndef UNIVERSAL_FILE_OUTPUT_STREAM_H #define UNIVERSAL_FILE_OUTPUT_STREAM_H /* public file for the doxygen documentation: */ /*! * \file * \brief implements an universal_output_stream_if and forwards data to a FILE */ #include "stream/universal_output_stream.h" #include /*! * \brief attributes of the universal_file_output_stream */ struct universal_file_output_stream_struct { universal_output_stream_t output_stream; /*!< instance of implemented interface \c universal_output_stream_t */ FILE *output; /*!< output file */ }; typedef struct universal_file_output_stream_struct universal_file_output_stream_t; /*! * \brief initializes the universal_file_output_stream_t * * \param this_ pointer to own object attributes */ void universal_file_output_stream_init( universal_file_output_stream_t *this_ ); /*! * \brief destroys the universal_file_output_stream_t * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int universal_file_output_stream_destroy( universal_file_output_stream_t *this_ ); /*! * \brief opens a file * * \param this_ pointer to own object attributes * \param path file path identifying the file to open for writing * \return 0 in case of success, -1 otherwise */ int universal_file_output_stream_open ( universal_file_output_stream_t *this_, const char *path ); /*! * \brief writes a buffer (e.g. a stringview) to a file * * \param this_ pointer to own object attributes * \param start buffer to write, not 0-terminated * \param length length of the buffer to write * \return 0 in case of success, -1 otherwise */ int universal_file_output_stream_write ( universal_file_output_stream_t *this_, const void *start, size_t length ); /*! * \brief flushes buffers * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int universal_file_output_stream_flush( universal_file_output_stream_t *this_ ); /*! * \brief closes the universal_file_output_stream_t * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int universal_file_output_stream_close( universal_file_output_stream_t *this_ ); /*! * \brief gets the output stream interface of this universal_file_output_stream_t * * \param this_ pointer to own object attributes * \return the abstract base class of this_ */ universal_output_stream_t* universal_file_output_stream_get_output_stream( universal_file_output_stream_t *this_ ); #endif /* UNIVERSAL_FILE_OUTPUT_STREAM_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/stream/universal_input_stream.h000066400000000000000000000065501415120503000270320ustar00rootroot00000000000000/* File: universal_input_stream.h; Copyright and License: see below */ #ifndef UNIVERSAL_INPUT_STREAM_H #define UNIVERSAL_INPUT_STREAM_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines a pair of a) a pointer to a concrete instance of an interface * and b) a pointer to objectdata that implements the interface. */ #include "stream/universal_input_stream_if.h" /*! * \brief object (vmt+data) of a universal_input_stream_t. * */ struct universal_input_stream_struct { const universal_input_stream_if_t* interface; /*!< set of interface functions to write to a stream, kind of VMT */ universal_input_stream_impl_t* objectdata; /*!< object that implements writing to a stream, used in interface functions as this_ parameter */ }; typedef struct universal_input_stream_struct universal_input_stream_t; /*! * \brief initializes the universal_input_stream_t * * \param this_ pointer to own object attributes * \param interface set of interface functions to write to a stream * \param objectdata object that implements writing to a stream */ static inline void universal_input_stream_private_init( universal_input_stream_t *this_, const universal_input_stream_if_t *interface, universal_input_stream_impl_t* objectdata ); /*! * \brief destroys the universal_input_stream_t. * * This function does NOT call \c destroy on the \c interface. * * \param this_ pointer to own object attributes * \return returns 0 if success, -1 in case of error */ static inline int universal_input_stream_private_destroy( universal_input_stream_t *this_ ); /*! * \brief gets the set of interface functions * * \param this_ pointer to own object attributes * \return the set of interface functions */ static inline const universal_input_stream_if_t* universal_input_stream_get_interface ( universal_input_stream_t *this_ ); /*! * \brief gets the object that implements writing to a stream * * \param this_ pointer to own object attributes * \return the object data that implements the interface */ static inline universal_input_stream_impl_t* universal_input_stream_get_objectdata ( universal_input_stream_t *this_ ); /*! * \brief calls \c read on the \c interface * * \param this_ pointer to own object attributes * \param out_buffer buffer to write read bytes * \param max_size length of the buffer to write * \param out_length number of bytes read * \return 0 in case of success, -1 otherwise */ static inline int universal_input_stream_read ( universal_input_stream_t *this_, void *out_buffer, size_t max_size, size_t *out_length ); #include "universal_input_stream.inl" #endif /* UNIVERSAL_INPUT_STREAM_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/stream/universal_input_stream.inl000066400000000000000000000041401415120503000273560ustar00rootroot00000000000000/* File: universal_input_stream.inl; Copyright and License: see below */ #include static inline void universal_input_stream_private_init( universal_input_stream_t *this_, const universal_input_stream_if_t *interface, universal_input_stream_impl_t* objectdata ) { assert( interface != NULL ); assert( objectdata != NULL ); (*this_).interface = interface; (*this_).objectdata = objectdata; } static inline int universal_input_stream_private_destroy( universal_input_stream_t *this_ ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); (*this_).interface = NULL; (*this_).objectdata = NULL; return 0; } static inline const universal_input_stream_if_t* universal_input_stream_get_interface ( universal_input_stream_t *this_ ) { assert( (*this_).interface != NULL ); return (*this_).interface; } static inline universal_input_stream_impl_t* universal_input_stream_get_objectdata ( universal_input_stream_t *this_ ) { assert( (*this_).objectdata != NULL ); return (*this_).objectdata; } static inline int universal_input_stream_read ( universal_input_stream_t* this_, void *out_buffer, size_t max_size, size_t *out_length ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).read != NULL ); return (*( (*((*this_).interface)).read )) ( (*this_).objectdata, out_buffer, max_size, out_length ); } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/stream/universal_input_stream_if.h000066400000000000000000000037311415120503000275060ustar00rootroot00000000000000/* File: universal_input_stream_if.h; Copyright and License: see below */ #ifndef UNIVERSAL_INPUT_STREAM_IF_H #define UNIVERSAL_INPUT_STREAM_IF_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines a set of function pointers that allow to implement an input stream. * * This is an interface only - to be used in a pipes-and-filters architecture * where pipes and filters do not know their predecessor or successor. * * A user of this interface needs a) a pointer to a concrete instance of this interface * and b) a pointer to an object that implements the interface (this_). */ #include #include #include /* universal_input_stream_impl_t allows to distinguisth general void pointers from pointers to implementation objects */ typedef void universal_input_stream_impl_t; /*! * \brief function pointers of a universal_input_stream_if_t. * * This is similar to a vmt and used here to access an implementation of this interface * * Lifecycle functions like init and destroy are not part of the interface. */ struct universal_input_stream_if_struct { /*! a function to read bytes from an input stream into a buffer */ int (*read)(universal_input_stream_impl_t *this_, void *out_buffer, size_t max_size, size_t *out_length ); }; typedef struct universal_input_stream_if_struct universal_input_stream_if_t; #endif /* UNIVERSAL_INPUT_STREAM_IF_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/stream/universal_memory_input_stream.h000066400000000000000000000073731415120503000304260ustar00rootroot00000000000000/* File: universal_memory_input_stream.h; Copyright and License: see below */ #ifndef UNIVERSAL_MEMORY_INPUT_STREAM_H #define UNIVERSAL_MEMORY_INPUT_STREAM_H /* public file for the doxygen documentation: */ /*! * \file * \brief reads data from a fixed-sized memory buffer and implements an universal_input_stream */ #include "stream/universal_input_stream.h" /*! * \brief attributes of the universal_memory_input_stream */ struct universal_memory_input_stream_struct { universal_input_stream_t input_stream; /*!< instance of implemented interface \c universal_input_stream_t */ const void* mem_buf_start; /*!< input memory buffer start */ size_t mem_buf_size; /*!< input memory buffer size */ size_t mem_buf_pos; /*!< read position in the input memory buffer */ }; typedef struct universal_memory_input_stream_struct universal_memory_input_stream_t; /*! * \brief initializes the universal_memory_input_stream_t * * \param this_ pointer to own object attributes * \param mem_buf_start address of memory buffer * \param mem_buf_size size of the memory buffer */ void universal_memory_input_stream_init ( universal_memory_input_stream_t *this_, const void* mem_buf_start, size_t mem_buf_size ); /*! * \brief re-initializes the universal_memory_input_stream_t * * \param this_ pointer to own object attributes * \param mem_buf_start address of memory buffer * \param mem_buf_size size of the memory buffer */ void universal_memory_input_stream_reinit ( universal_memory_input_stream_t *this_, const void* mem_buf_start, size_t mem_buf_size ); /*! * \brief destroys the universal_memory_input_stream_t * * \param this_ pointer to own object attributes */ void universal_memory_input_stream_destroy ( universal_memory_input_stream_t *this_ ); /*! * \brief resets the read position to 0 * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int universal_memory_input_stream_reset ( universal_memory_input_stream_t *this_ ); /*! * \brief reads a buffer from a memory region * * \param this_ pointer to own object attributes * \param out_buffer buffer to write read bytes * \param max_size length of the buffer to write * \param out_length number of bytes read * \return 0 in case of success, -1 if there are no further bytes to read */ int universal_memory_input_stream_read ( universal_memory_input_stream_t *this_, void *out_buffer, size_t max_size, size_t *out_length ); /*! * \brief gets the input stream interface of this universal_memory_input_stream_t * * \param this_ pointer to own object attributes * \return the abstract base class of this_ */ universal_input_stream_t* universal_memory_input_stream_get_input_stream( universal_memory_input_stream_t *this_ ); #endif /* UNIVERSAL_MEMORY_INPUT_STREAM_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/stream/universal_memory_output_stream.h000066400000000000000000000074151415120503000306240ustar00rootroot00000000000000/* File: universal_memory_output_stream.h; Copyright and License: see below */ #ifndef UNIVERSAL_MEMORY_OUTPUT_STREAM_H #define UNIVERSAL_MEMORY_OUTPUT_STREAM_H /* public file for the doxygen documentation: */ /*! * \file * \brief implements an universal_output_stream and forwards data to a fixed-sized memory buffer */ #include "stream/universal_output_stream.h" /*! * \brief attributes of the universal_memory_output_stream */ struct universal_memory_output_stream_struct { universal_output_stream_t output_stream; /*!< instance of implemented interface \c universal_output_stream_t */ void* mem_buf_start; /*!< output memory buffer start */ size_t mem_buf_size; /*!< output memory buffer size */ size_t mem_buf_filled; /*!< number of bytes written to the output memory buffer */ }; typedef struct universal_memory_output_stream_struct universal_memory_output_stream_t; /*! * \brief initializes the universal_memory_output_stream_t * * \param this_ pointer to own object attributes * \param mem_buf_start address of memory buffer * \param mem_buf_size size of the memory buffer */ void universal_memory_output_stream_init( universal_memory_output_stream_t *this_, void* mem_buf_start, size_t mem_buf_size ); /*! * \brief destroys the universal_memory_output_stream_t * * \param this_ pointer to own object attributes */ void universal_memory_output_stream_destroy( universal_memory_output_stream_t *this_ ); /*! * \brief resets write position to 0 of this memory output stream, * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int universal_memory_output_stream_reset ( universal_memory_output_stream_t *this_ ); /*! * \brief writes a buffer (e.g. a stringview) to a memory output stream * * \param this_ pointer to own object attributes * \param start buffer to write, not 0-terminated * \param length length of the buffer to write * \return 0 in case of success, -1 otherwise */ int universal_memory_output_stream_write ( universal_memory_output_stream_t *this_, const void *start, size_t length ); /*! * \brief flushes buffers * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int universal_memory_output_stream_flush( universal_memory_output_stream_t *this_ ); /*! * \brief writes a terminating zero to a memory output stream * * If the memory buffer is full, the last byte is overwritten by zero * to ensure that even in this error case, the buffer is null-terminated. * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 if last byte gets overwritten or buffer of size 0 */ int universal_memory_output_stream_write_0term ( universal_memory_output_stream_t *this_ ); /*! * \brief gets the output stream interface of this universal_memory_output_stream_t * * \param this_ pointer to own object attributes * \return the abstract base class of this_ */ universal_output_stream_t* universal_memory_output_stream_get_output_stream( universal_memory_output_stream_t *this_ ); #endif /* UNIVERSAL_MEMORY_OUTPUT_STREAM_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/stream/universal_output_stream.h000066400000000000000000000070771415120503000272400ustar00rootroot00000000000000/* File: universal_output_stream.h; Copyright and License: see below */ #ifndef UNIVERSAL_OUTPUT_STREAM_H #define UNIVERSAL_OUTPUT_STREAM_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines a pair of a) a pointer to a concrete instance of an interface * and b) a pointer to objectdata that implements the interface. */ #include "stream/universal_output_stream_if.h" /*! * \brief object (vmt+data) of a universal_output_stream_t. * */ struct universal_output_stream_struct { const universal_output_stream_if_t* interface; /*!< set of interface functions to write to a stream, kind of VMT */ universal_output_stream_impl_t* objectdata; /*!< object that implements writing to a stream, used in interface functions as this_ parameter */ }; typedef struct universal_output_stream_struct universal_output_stream_t; /*! * \brief initializes the universal_output_stream_t * * \param this_ pointer to own object attributes * \param interface set of interface functions to write to a stream * \param objectdata object that implements writing to a stream */ static inline void universal_output_stream_private_init( universal_output_stream_t *this_, const universal_output_stream_if_t *interface, universal_output_stream_impl_t* objectdata ); /*! * \brief destroys the universal_output_stream_t. * * This function does NOT call \c destroy on the \c interface. * * \param this_ pointer to own object attributes * \return returns 0 if success, -1 in case of error */ static inline int universal_output_stream_private_destroy( universal_output_stream_t *this_ ); /*! * \brief gets the set of interface functions * * \param this_ pointer to own object attributes * \return the set of interface functions */ static inline const universal_output_stream_if_t* universal_output_stream_get_interface ( universal_output_stream_t *this_ ); /*! * \brief gets the object that implements writing to a stream * * \param this_ pointer to own object attributes * \return the object data that implements the interface */ static inline universal_output_stream_impl_t* universal_output_stream_get_objectdata ( universal_output_stream_t *this_ ); /*! * \brief calls \c write on the \c interface * * \param this_ pointer to own object attributes * \param start start address from where to write * \param length length in bytes to write * \return returns 0 if success, -1 in case of error */ static inline int universal_output_stream_write (universal_output_stream_t* this_, const void *start, size_t length); /*! * \brief calls \c flush on the \c interface * * \param this_ pointer to own object attributes * \return returns 0 if success, -1 in case of error */ static inline int universal_output_stream_flush (universal_output_stream_t* this_); #include "universal_output_stream.inl" #endif /* UNIVERSAL_OUTPUT_STREAM_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/stream/universal_output_stream.inl000066400000000000000000000047511415120503000275670ustar00rootroot00000000000000/* File: universal_output_stream.inl; Copyright and License: see below */ #include static inline void universal_output_stream_private_init( universal_output_stream_t *this_, const universal_output_stream_if_t *interface, universal_output_stream_impl_t* objectdata ) { assert( interface != NULL ); assert( objectdata != NULL ); (*this_).interface = interface; (*this_).objectdata = objectdata; } static inline int universal_output_stream_private_destroy( universal_output_stream_t *this_ ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); /*int result = (*( (*((*this_).interface)).destroy )) ( (*this_).objectdata );*/ (*this_).interface = NULL; (*this_).objectdata = NULL; /*return result;*/ return 0; } static inline const universal_output_stream_if_t* universal_output_stream_get_interface ( universal_output_stream_t *this_ ) { assert( (*this_).interface != NULL ); return (*this_).interface; } static inline universal_output_stream_impl_t* universal_output_stream_get_objectdata ( universal_output_stream_t *this_ ) { assert( (*this_).objectdata != NULL ); return (*this_).objectdata; } static inline int universal_output_stream_write ( universal_output_stream_t* this_, const void *start, size_t length ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).write != NULL ); return (*( (*((*this_).interface)).write )) ( (*this_).objectdata, start, length ); } static inline int universal_output_stream_flush ( universal_output_stream_t* this_ ) { assert( (*this_).interface != NULL ); assert( (*this_).objectdata != NULL ); assert( (*((*this_).interface)).flush != NULL ); return (*( (*((*this_).interface)).flush )) ( (*this_).objectdata ); } /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/stream/universal_output_stream_if.h000066400000000000000000000044461415120503000277130ustar00rootroot00000000000000/* File: universal_output_stream_if.h; Copyright and License: see below */ #ifndef UNIVERSAL_OUTPUT_STREAM_IF_H #define UNIVERSAL_OUTPUT_STREAM_IF_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines a set of function pointers that allow to implement an output stream. * * This is an interface only - to be used in a pipes-and-filters architecture * where pipes and filters do not know their predecessor or successor. * * A user of this interface needs a) a pointer to a concrete instance of this interface * and b) a pointer to an object that implements the interface (this_). */ #include #include #include /* universal_output_stream_impl_t allows to distinguisth general void pointers from pointers to implementation objects */ typedef void universal_output_stream_impl_t; /*! * \brief function pointers of a universal_output_stream_if_t. * * This is similar to a vmt and used here to access an implementation of this interface * * Lifecycle functions like init and destroy are not part of the interface. */ struct universal_output_stream_if_struct { int (*write)(universal_output_stream_impl_t* this_, const void *start, size_t length); /*!< a function to write data to an output stream; */ /*!< returns 0 if success, -1 in case of error */ int (*flush)(universal_output_stream_impl_t* this_); /*!< a function to flush data to an output stream; */ /*!< returns 0 if success, -1 in case of error */ }; typedef struct universal_output_stream_if_struct universal_output_stream_if_t; #endif /* UNIVERSAL_OUTPUT_STREAM_IF_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/stream/universal_stream_output_stream.h000066400000000000000000000053171415120503000306060ustar00rootroot00000000000000/* File: universal_stream_output_stream.h; Copyright and License: see below */ #ifndef UNIVERSAL_STREAM_OUTPUT_STREAM_H #define UNIVERSAL_STREAM_OUTPUT_STREAM_H /* public file for the doxygen documentation: */ /*! * \file * \brief implements an universal_output_stream_if and forwards data to a FILE */ #include "stream/universal_output_stream.h" #include /*! * \brief attributes of the universal_stream_output_stream */ struct universal_stream_output_stream_struct { universal_output_stream_t output_stream; /*!< instance of implemented interface \c universal_output_stream_t */ FILE *output; /*!< output file */ }; typedef struct universal_stream_output_stream_struct universal_stream_output_stream_t; /*! * \brief initializes the universal_stream_output_stream_t * * \param this_ pointer to own object attributes * \param out_stream out stream to wrap, e.g. stdout or stderr */ void universal_stream_output_stream_init( universal_stream_output_stream_t *this_, FILE* out_stream ); /*! * \brief destroys the universal_stream_output_stream_t * * \param this_ pointer to own object attributes */ void universal_stream_output_stream_destroy( universal_stream_output_stream_t *this_ ); /*! * \brief writes a buffer (e.g. a stringview) to a file * * \param this_ pointer to own object attributes * \param start buffer to write, not 0-terminated * \param length length of the buffer to write * \return 0 in case of success, -1 otherwise */ int universal_stream_output_stream_write ( universal_stream_output_stream_t *this_, const void *start, size_t length ); /*! * \brief flushes buffers * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ int universal_stream_output_stream_flush( universal_stream_output_stream_t *this_ ); /*! * \brief gets the output stream interface of this universal_stream_output_stream_t * * \param this_ pointer to own object attributes * \return the abstract base class of this_ */ universal_output_stream_t* universal_stream_output_stream_get_output_stream( universal_stream_output_stream_t *this_ ); #endif /* UNIVERSAL_STREAM_OUTPUT_STREAM_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/universal_array_index_sorter.h000066400000000000000000000065211415120503000267260ustar00rootroot00000000000000/* File: universal_array_index_sorter.h; Copyright and License: see below */ #ifndef UNIVERSAL_ARRAY_INDEX_SORTER_H #define UNIVERSAL_ARRAY_INDEX_SORTER_H /* public file for the doxygen documentation: */ /*! * \file * \brief Sorts array indexes by a sorting criteria (weight) ascending */ #include #include /*! * \brief constants for maximum values of universal_array_index_sorter_t */ enum universal_array_index_sorter_max_enum { UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE = 2048, /*!< maximum number of indices to sort */ }; /*! * \brief attributes of the universal_array_index_sorter_t */ struct universal_array_index_sorter_struct { uint32_t entries_count; /*!< number of all contained array indices */ uint32_t entries[UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE]; /*!< all contained array indices */ int64_t weights[UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE]; /*!< weights of entries */ }; typedef struct universal_array_index_sorter_struct universal_array_index_sorter_t; /*! * \brief initializes the universal_array_index_sorter_t * * \param this_ pointer to own object attributes */ static inline void universal_array_index_sorter_init( universal_array_index_sorter_t *this_ ); /*! * \brief re-initializes the universal_array_index_sorter_t * * \param this_ pointer to own object attributes */ static inline void universal_array_index_sorter_reinit( universal_array_index_sorter_t *this_ ); /*! * \brief destroys the universal_array_index_sorter_t * * \param this_ pointer to own object attributes */ static inline void universal_array_index_sorter_destroy( universal_array_index_sorter_t *this_ ); /*! * \brief adds an entry to the index-list * * \param this_ pointer to own object attributes * \param array_index index of data within an external, unknown array * \param weight weight of the array-entry by which to sort * \return -1 in case the list is full, 0 in case of success */ static inline int universal_array_index_sorter_insert( universal_array_index_sorter_t *this_, uint32_t array_index, int64_t weight ); /*! * \brief gets the current list length * * \param this_ pointer to own object attributes * \return number of entries in the sorted index array */ static inline uint32_t universal_array_index_sorter_get_count( const universal_array_index_sorter_t *this_ ); /*! * \brief adds an entry to the index-list * * \param this_ pointer to own object attributes * \param sort_index index of the sorted index-array * \return array index in the external, unsorted data array */ static inline uint32_t universal_array_index_sorter_get_array_index( const universal_array_index_sorter_t *this_, uint32_t sort_index ); #include "universal_array_index_sorter.inl" #endif /* UNIVERSAL_ARRAY_INDEX_SORTER_H */ /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/universal_array_index_sorter.inl000066400000000000000000000053751415120503000272670ustar00rootroot00000000000000/* File: universal_array_index_sorter.inl; Copyright and License: see below */ #include "tslog.h" #include static inline void universal_array_index_sorter_init( universal_array_index_sorter_t *this_ ) { (*this_).entries_count = 0; } static inline void universal_array_index_sorter_reinit( universal_array_index_sorter_t *this_ ) { (*this_).entries_count = 0; } static inline void universal_array_index_sorter_destroy( universal_array_index_sorter_t *this_ ) { } static inline int universal_array_index_sorter_insert( universal_array_index_sorter_t *this_, uint32_t array_index, int64_t weight ) { assert( (*this_).entries_count <= UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE ); int result; if ( (*this_).entries_count < UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE ) { bool already_inserted = false; for ( uint32_t sorted_index = (*this_).entries_count; (sorted_index > 0) && ( ! already_inserted ); sorted_index -- ) { if ( weight < (*this_).weights[sorted_index-1] ) { /* shift */ (*this_).entries[sorted_index] = (*this_).entries[sorted_index-1]; (*this_).weights[sorted_index] = (*this_).weights[sorted_index-1]; } else { /* insert */ (*this_).entries[sorted_index] = array_index; (*this_).weights[sorted_index] = weight; already_inserted = true; } } if ( ! already_inserted ) { (*this_).entries[0] = array_index; (*this_).weights[0] = weight; } (*this_).entries_count ++; result = 0; } else { result = -1; } return result; } static inline uint32_t universal_array_index_sorter_get_count( const universal_array_index_sorter_t *this_ ) { return (*this_).entries_count; } static inline uint32_t universal_array_index_sorter_get_array_index( const universal_array_index_sorter_t *this_, uint32_t sort_index ) { assert( (*this_).entries_count <= UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE ); assert( sort_index <= (*this_).entries_count ); return (*this_).entries[sort_index]; } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/universal_array_list.h000066400000000000000000000141061415120503000251720ustar00rootroot00000000000000/* File: universal_array_list.h; Copyright and License: see below */ #ifndef UNIVERSAL_ARRAY_LIST_H #define UNIVERSAL_ARRAY_LIST_H /* public file for the doxygen documentation: */ /*! * \file * \brief Defines basic list functions. * * This is an abstract type, to be used by specialized types like data_search_result_list_t. */ #include #include #include /*! * \brief attributes of a universal_array_list_t * */ struct universal_array_list_struct { /* usage-relevant */ unsigned int length; void *elements; /* internal */ unsigned int max_elements; size_t element_size; ptrdiff_t step_size; /*!< bytes from one array element to the next */ /* callbacks to elements */ void (*copy_ctor)(void* to_instance, const void* from_instance); /* the copy constructor of an element, needed to add */ bool (*equal)(const void* instance_1, const void* instance_2); /* the compare operator, needed for get_index_of */ void (*dtor)(void* instance); /* the destructor of an element, needed to remove and clear */ }; typedef struct universal_array_list_struct universal_array_list_t; /*! * \brief initializes the universal_array_list_t struct * * \param this_ pointer to own object attributes * \param max_elements maximum number of elements that fit into the array * \param elements pointer to array of elements * \param element_size size in bytes of a single element (the base type, without padding for alignment) * \param step_size number of bytes from one array antry to the next (this may be equal to element_size or bigger in case of padding) * \param copy_ctor a function that copies an element, NULL if memcpy shall be used. * \param equal a compare function, NULL if memcmp shall be used. * \param dtor a function that destroys an element, NULL if no cleanup necessary. */ static inline void universal_array_list_init ( universal_array_list_t *this_, unsigned int max_elements, void *elements, size_t element_size, ptrdiff_t step_size, void (*copy_ctor)(void* to_instance, const void* from_instance), bool (*equal)(const void* instance_1, const void* instance_2), void (*dtor)(void* instance) ); /*! * \brief destroys the universal_array_list_t struct and all contained elements * * \param this_ pointer to own object attributes */ static inline void universal_array_list_destroy ( universal_array_list_t *this_ ); /*! * \brief prints the universal_array_list_t struct to the trace output * * \param this_ pointer to own object attributes */ static inline void universal_array_list_trace ( const universal_array_list_t *this_ ); /*! * \brief checks if universal_array_list_t is empty * * \param this_ pointer to own object attributes */ static inline bool universal_array_list_is_empty ( const universal_array_list_t *this_ ); /*! * \brief appends an element to universal_array_list_t * * \param this_ pointer to own object attributes * \param element element to be added. Only a valid object can be added, NULL is not allowed. * \return -1 if list is full, 0 on success */ static inline int universal_array_list_append ( universal_array_list_t *this_, const void* element ); /*! * \brief appends all elements of that to universal_array_list_t * * \param this_ pointer to own object attributes * \param that list of elements to be added. * \return -1 if list is full, 0 on success */ static inline int universal_array_list_append_all ( universal_array_list_t *this_, const universal_array_list_t *that ); /*! * \brief returns an element * * \param this_ pointer to own object attributes * \param index index to be returned. 0 \<= index \< universal_array_list_get_length(this_) * \return pointer to the element, NULL if index is invalid */ static inline void *universal_array_list_get_ptr ( universal_array_list_t *this_, unsigned int index ); /*! * \brief returns a const element * * \param this_ pointer to own object attributes * \param index index to be returned. 0 \<= index \< universal_array_list_get_length(this_) * \return pointer to the element, NULL if index is invalid */ static inline void const *universal_array_list_get_const ( const universal_array_list_t *this_, unsigned int index ); /*! * \brief returns the index of the given element * * \param this_ pointer to own object attributes * \param element element to be searched. Only a valid object can be searched, NULL is not allowed. * \return index of the element, -1 if element is not in the list */ static inline int universal_array_list_get_index_of ( const universal_array_list_t *this_, const void* element ); /*! * \brief clears the universal_array_list_t and all contained elements * * \param this_ pointer to own object attributes */ static inline void universal_array_list_clear ( universal_array_list_t *this_ ); /*! * \brief returns the size of the set * * \param this_ pointer to own object attributes * \return number of object-ids in the set, the number is less or equal to universal_array_list_MAX_SET_SIZE */ static inline unsigned int universal_array_list_get_length ( const universal_array_list_t *this_ ); #include "universal_array_list.inl" #endif /* UNIVERSAL_ARRAY_LIST_H */ /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/universal_array_list.inl000066400000000000000000000150301415120503000255220ustar00rootroot00000000000000/* File: universal_array_list.inl; Copyright and License: see below */ #include "trace.h" #include "tslog.h" #include #include static inline void universal_array_list_init ( universal_array_list_t *this_, unsigned int max_elements, void *elements, size_t element_size, ptrdiff_t step_size, void (*copy_ctor)(void* to_instance, const void* from_instance), bool (*equal)(const void* instance_1, const void* instance_2), void (*dtor)(void* instance) ) { TRACE_INFO_INT( "- max_elements:", max_elements ); TRACE_INFO_INT( "- element_size:", element_size ); TRACE_INFO_INT( "- step_size:", step_size ); assert( element_size <= step_size ); assert( (element_size+sizeof(int)) > step_size ); /* something is wrong if there is more padding than an int */ assert( elements != NULL ); assert( max_elements != 0 ); /* a list of size 0 could be valid - but most likely this function is called with wrong arguments */ (*this_).length = 0; (*this_).elements = elements; (*this_).max_elements = max_elements; (*this_).element_size = element_size; (*this_).step_size = step_size; (*this_).copy_ctor = copy_ctor; (*this_).equal = equal; (*this_).dtor = dtor; } static inline void universal_array_list_destroy ( universal_array_list_t *this_ ) { assert( (*this_).length <= (*this_).max_elements ); assert( (*this_).elements != NULL ); universal_array_list_clear( this_ ); } static inline void universal_array_list_trace ( const universal_array_list_t *this_ ) { assert( (*this_).length <= (*this_).max_elements ); assert( (*this_).elements != NULL ); TRACE_INFO( "universal_array_list_t" ); TRACE_INFO_INT( "- length:", (*this_).length ); TRACE_INFO_INT( "- max_elements:", (*this_).max_elements ); TRACE_INFO_INT( "- element_size:", (*this_).element_size ); TRACE_INFO_STR( "- copy_ctor:", ((*this_).copy_ctor == NULL)?"NULL":"exists" ); TRACE_INFO_STR( "- dtor:", ((*this_).dtor == NULL)?"NULL":"exists" ); } static inline bool universal_array_list_is_empty ( const universal_array_list_t *this_ ) { return ( 0 == (*this_).length ); } static inline int universal_array_list_append ( universal_array_list_t *this_, const void* element ) { assert( (*this_).length <= (*this_).max_elements ); assert( (*this_).elements != NULL ); int err_result; if ( (*this_).length < (*this_).max_elements ) { unsigned int index = (*this_).length; (*this_).length ++; void *pos = universal_array_list_get_ptr( this_, index ); if ( (*this_).copy_ctor != NULL ) { (*this_).copy_ctor( pos, element ); } else { memcpy( pos, element, (*this_).element_size ); } err_result = 0; } else { err_result = -1; } return err_result; } static inline int universal_array_list_append_all ( universal_array_list_t *this_, const universal_array_list_t *that ) { assert( that != NULL ); int err_result = 0; const unsigned int len = universal_array_list_get_length(that); for ( unsigned int idx = 0; (idx < len)&&(err_result == 0); idx ++ ) { err_result = universal_array_list_append( this_, universal_array_list_get_const( that, idx ) ); } return err_result; } static inline void *universal_array_list_get_ptr ( universal_array_list_t *this_, unsigned int index ) { assert( (*this_).length <= (*this_).max_elements ); assert( (*this_).elements != NULL ); void *result; if ( index < (*this_).length ) { result = ((char*)(*this_).elements) + ((*this_).step_size * index); } else { result = NULL; } return result; } static inline void const *universal_array_list_get_const ( const universal_array_list_t *this_, unsigned int index ) { assert( (*this_).length <= (*this_).max_elements ); assert( (*this_).elements != NULL ); void const *result; if ( index < (*this_).length ) { result = ((const char*)(*this_).elements) + ((*this_).step_size * index); } else { result = NULL; } return result; } static inline int universal_array_list_get_index_of ( const universal_array_list_t *this_, const void* element ) { assert( (*this_).length <= (*this_).max_elements ); assert( (*this_).elements != NULL ); assert( element != NULL ); int result = -1; if ( (*this_).equal != NULL ) { for ( unsigned int index = 0; ( index < (*this_).length )&&( result == -1 ); index ++ ) { const void *current = universal_array_list_get_const( this_, index ); if ( (*this_).equal( current, element ) ) { result = index; } } } else { for ( unsigned int index = 0; ( index < (*this_).length )&&( result == -1 ); index ++ ) { const void *current = universal_array_list_get_const( this_, index ); if ( 0 == memcmp( current, element, (*this_).element_size ) ) { result = index; } } } return result; } static inline void universal_array_list_clear ( universal_array_list_t *this_ ) { assert( (*this_).length <= (*this_).max_elements ); assert( (*this_).elements != NULL ); if ( (*this_).dtor != NULL ) { for ( unsigned int index = 0; index < (*this_).length; index ++ ) { void *current = universal_array_list_get_ptr( this_, index ); (*this_).dtor( current ); } } (*this_).length = 0; } static inline unsigned int universal_array_list_get_length ( const universal_array_list_t *this_ ) { return (*this_).length; } /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/universal_bool_list.h000066400000000000000000000073271415120503000250160ustar00rootroot00000000000000/* File: universal_bool_list.h; Copyright and License: see below */ #ifndef UNIVERSAL_BOOL_LIST_H #define UNIVERSAL_BOOL_LIST_H /* public file for the doxygen documentation: */ /*! * \file * \brief Stores a list of up to 32 booleans */ #include #include /*! * \brief attributes of a bool list */ struct universal_bool_list_struct { uint32_t list; }; typedef struct universal_bool_list_struct universal_bool_list_t; /*! * \brief initializes the universal_bool_list_t struct * * \param this_ pointer to own object attributes * \param first first value of the pair * \param second second value of the pair */ static inline void universal_bool_list_init_pair ( universal_bool_list_t *this_, bool first, bool second ); /*! * \brief re-initializes the universal_bool_list_t struct * * \param this_ pointer to own object attributes * \param first first value of the pair * \param second second value of the pair */ static inline void universal_bool_list_reinit_pair ( universal_bool_list_t *this_, bool first, bool second ); /*! * \brief copies original to this uninitialized universal_bool_list_t struct * * \param this_ pointer to own object attributes * \param original pointer to object attributes that shall be copied */ static inline void universal_bool_list_copy ( universal_bool_list_t *this_, const universal_bool_list_t *original ); /*! * \brief replaces the already initialized universal_bool_list_t struct by other data * * \param this_ pointer to own object attributes * \param original pointer to object attributes that shall be copied */ static inline void universal_bool_list_replace ( universal_bool_list_t *this_, const universal_bool_list_t *original ); /*! * \brief initializes the universal_bool_list_t struct to empty * * \param this_ pointer to own object attributes */ static inline void universal_bool_list_init_empty ( universal_bool_list_t *this_ ); /*! * \brief re-initializes the universal_bool_list_t struct empty * * \param this_ pointer to own object attributes */ static inline void universal_bool_list_reinit_empty ( universal_bool_list_t *this_ ); /* Note: Till now, only constructors for pairs are provided. Extend as needed. */ /*! * \brief destroys the universal_bool_list_t struct * * \param this_ pointer to own object attributes */ static inline void universal_bool_list_destroy ( universal_bool_list_t *this_ ); /*! * \brief gets the first value of universal_bool_list_t * * \param this_ pointer to own object attributes * \return first value of the pair */ static inline bool universal_bool_list_get_first ( const universal_bool_list_t *this_ ); /*! * \brief gets the second value of universal_bool_list_t * * \param this_ pointer to own object attributes * \return second value of the pair */ static inline bool universal_bool_list_get_second ( const universal_bool_list_t *this_ ); /*! * \brief prints the universal_bool_list_t struct to the trace output * * \param this_ pointer to own object attributes */ static inline void universal_bool_list_trace ( const universal_bool_list_t *this_ ); #include "universal_bool_list.inl" #endif /* UNIVERSAL_BOOL_LIST_H */ /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/universal_bool_list.inl000066400000000000000000000040411415120503000253370ustar00rootroot00000000000000/* File: universal_bool_list.inl; Copyright and License: see below */ #include "trace.h" static inline void universal_bool_list_init_pair ( universal_bool_list_t *this_, bool first, bool second ) { (*this_).list = (first ? 0x1 : 0x0) | (second ? 0x2 : 0x0); } static inline void universal_bool_list_reinit_pair ( universal_bool_list_t *this_, bool first, bool second ) { (*this_).list = (first ? 0x1 : 0x0) | (second ? 0x2 : 0x0); } static inline void universal_bool_list_copy ( universal_bool_list_t *this_, const universal_bool_list_t *original ) { (*this_) = (*original); } static inline void universal_bool_list_replace ( universal_bool_list_t *this_, const universal_bool_list_t *original ) { (*this_) = (*original); } static inline void universal_bool_list_init_empty ( universal_bool_list_t *this_ ) { (*this_).list = 0; } static inline void universal_bool_list_reinit_empty ( universal_bool_list_t *this_ ) { (*this_).list = 0; } static inline void universal_bool_list_destroy ( universal_bool_list_t *this_ ) { } static inline bool universal_bool_list_get_first ( const universal_bool_list_t *this_ ) { return ( 0x1 == ( (*this_).list & 0x1 )); } static inline bool universal_bool_list_get_second ( const universal_bool_list_t *this_ ) { return ( 0x2 == ( (*this_).list & 0x2 )); } static inline void universal_bool_list_trace ( const universal_bool_list_t *this_ ) { TRACE_INFO( "universal_bool_list_t" ); TRACE_INFO_HEX( "- list:", (*this_).list ); } /* Copyright 2017-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/universal_int.h000066400000000000000000000026301415120503000236120ustar00rootroot00000000000000/* File: universal_int.h; Copyright and License: see below */ #ifndef UNIVERSAL_INT_H #define UNIVERSAL_INT_H /* public file for the doxygen documentation: */ /*! * \file * \brief provides basic integer functions like min and max */ #include /*! * \brief determines the minimum of two signed 32 bit integers * * \param this_ first signed integer * \param that second signed integer * \return minimum of two signed integer */ static inline int32_t universal_int_min_i32 ( int32_t this_, int32_t that ); /*! * \brief determines the maximum of two signed 32 bit integers * * \param this_ first signed integer * \param that second signed integer * \return maximum of two signed integer */ static inline int32_t universal_int_max_i32 ( int32_t this_, int32_t that ); #include "universal_int.inl" #endif /* UNIVERSAL_INT_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/universal_int.inl000066400000000000000000000015621415120503000241500ustar00rootroot00000000000000/* File: universal_int.inl; Copyright and License: see below */ static inline int32_t universal_int_min_i32 ( int32_t this_, int32_t that ) { return ( this_ < that ) ? this_ : that; } static inline int32_t universal_int_max_i32 ( int32_t this_, int32_t that ) { return ( this_ > that ) ? this_ : that; } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/universal_int32_pair.h000066400000000000000000000072741415120503000250030ustar00rootroot00000000000000/* File: universal_int32_pair.h; Copyright and License: see below */ #ifndef UNIVERSAL_INT32_PAIR_H #define UNIVERSAL_INT32_PAIR_H /* public file for the doxygen documentation: */ /*! * \file * \brief Stores a pair of int32_t */ #include /*! * \brief attributes of an int pair */ struct universal_int32_pair_struct { int32_t first; int32_t second; }; typedef struct universal_int32_pair_struct universal_int32_pair_t; /*! * \brief initializes the universal_int32_pair_t struct * * \param this_ pointer to own object attributes * \param first first value of the pair * \param second second value of the pair */ static inline void universal_int32_pair_init ( universal_int32_pair_t *this_, int32_t first, int32_t second ); /*! * \brief re-initializes the universal_int32_pair_t struct * * \param this_ pointer to own object attributes * \param first first value of the pair * \param second second value of the pair */ static inline void universal_int32_pair_reinit ( universal_int32_pair_t *this_, int32_t first, int32_t second ); /*! * \brief copies original to this uninitialized universal_int32_pair_t struct * * \param this_ pointer to own object attributes * \param original pointer to object attributes that shall be copied */ static inline void universal_int32_pair_copy ( universal_int32_pair_t *this_, const universal_int32_pair_t *original ); /*! * \brief replaces the already initialized universal_int32_pair_t struct by other data * * \param this_ pointer to own object attributes * \param original pointer to object attributes that shall be copied */ static inline void universal_int32_pair_replace ( universal_int32_pair_t *this_, const universal_int32_pair_t *original ); /*! * \brief initializes the universal_int32_pair_t struct to a pair of 0,0 * * \param this_ pointer to own object attributes */ static inline void universal_int32_pair_init_empty ( universal_int32_pair_t *this_ ); /*! * \brief re-initializes the universal_int32_pair_t struct to a pair of 0,0 * * \param this_ pointer to own object attributes */ static inline void universal_int32_pair_reinit_empty ( universal_int32_pair_t *this_ ); /*! * \brief destroys the universal_int32_pair_t struct * * \param this_ pointer to own object attributes */ static inline void universal_int32_pair_destroy ( universal_int32_pair_t *this_ ); /*! * \brief gets the first value of universal_int32_pair_t * * \param this_ pointer to own object attributes * \return first value of the pair */ static inline int32_t universal_int32_pair_get_first ( const universal_int32_pair_t *this_ ); /*! * \brief gets the second value of universal_int32_pair_t * * \param this_ pointer to own object attributes * \return second value of the pair */ static inline int32_t universal_int32_pair_get_second ( const universal_int32_pair_t *this_ ); /*! * \brief prints the universal_int32_pair_t struct to the trace output * * \param this_ pointer to own object attributes */ static inline void universal_int32_pair_trace ( const universal_int32_pair_t *this_ ); #include "universal_int32_pair.inl" #endif /* UNIVERSAL_INT32_PAIR_H */ /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/universal_int32_pair.inl000066400000000000000000000041731415120503000253310ustar00rootroot00000000000000/* File: universal_int32_pair.inl; Copyright and License: see below */ #include "trace.h" static inline void universal_int32_pair_init ( universal_int32_pair_t *this_, int32_t first, int32_t second ) { (*this_).first = first; (*this_).second = second; } static inline void universal_int32_pair_reinit ( universal_int32_pair_t *this_, int32_t first, int32_t second ) { (*this_).first = first; (*this_).second = second; } static inline void universal_int32_pair_copy ( universal_int32_pair_t *this_, const universal_int32_pair_t *original ) { (*this_) = (*original); } static inline void universal_int32_pair_replace ( universal_int32_pair_t *this_, const universal_int32_pair_t *original ) { (*this_) = (*original); } static inline void universal_int32_pair_init_empty ( universal_int32_pair_t *this_ ) { (*this_).first = 0; (*this_).second = 0; } static inline void universal_int32_pair_reinit_empty ( universal_int32_pair_t *this_ ) { (*this_).first = 0; (*this_).second = 0; } static inline void universal_int32_pair_destroy ( universal_int32_pair_t *this_ ) { } static inline int32_t universal_int32_pair_get_first ( const universal_int32_pair_t *this_ ) { return (*this_).first; } static inline int32_t universal_int32_pair_get_second ( const universal_int32_pair_t *this_ ) { return (*this_).second; } static inline void universal_int32_pair_trace ( const universal_int32_pair_t *this_ ) { TRACE_INFO( "universal_int32_pair_t" ); TRACE_INFO_INT( "- first:", (*this_).first ); TRACE_INFO_INT( "- second:", (*this_).second ); } /* Copyright 2016-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/universal_simple_random.h000066400000000000000000000043711415120503000256550ustar00rootroot00000000000000/* File: universal_simple_random.h; Copyright and License: see below */ #ifndef UNIVERSAL_SIMPLE_RANDOM_H #define UNIVERSAL_SIMPLE_RANDOM_H /* public file for the doxygen documentation: */ /*! * \file * \brief wrapper on the stdlib rand/random function; sets the initial seed. * * These functions produce pseudo-random numbers that are not suitable * for security/cryptographic use cases. */ #include /*! * \brief attributes of a universal_simple_random_t * */ struct universal_simple_random_struct { int dummy; }; typedef struct universal_simple_random_struct universal_simple_random_t; /*! * \brief initializes the universal_simple_random_t struct, based on the clock as seed value * * Note: You may call this often, the underlying random generator is just initialized once. * * \param this_ pointer to own object attributes */ static inline void universal_simple_random_init ( universal_simple_random_t *this_ ); /*! * \brief destroys the universal_simple_random_t struct * * \param this_ pointer to own object attributes */ static inline void universal_simple_random_destroy ( universal_simple_random_t *this_ ); /*! * \brief calculates a pseudo-random integer covering the full range of uint16_t * * \param this_ pointer to own object attributes */ static inline uint16_t universal_simple_random_get_uint16 ( universal_simple_random_t *this_ ); /*! * \brief calculates a pseudo-random integer covering the full range of uint32_t * * \param this_ pointer to own object attributes */ static inline uint32_t universal_simple_random_get_uint32 ( universal_simple_random_t *this_ ); #include "universal_simple_random.inl" #endif /* UNIVERSAL_SIMPLE_RANDOM_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/universal_simple_random.inl000066400000000000000000000056001415120503000262040ustar00rootroot00000000000000/* File: universal_simple_random.inl; Copyright and License: see below */ #include "tslog.h" #include #include #include #include extern bool universal_simple_random_initialized; static inline void universal_simple_random_init ( universal_simple_random_t *this_ ) { if ( ! universal_simple_random_initialized ) { clock_t now = clock(); /* integer represents clocks, to be divided by CLOCKS_PER_SEC */ #ifdef _WIN32 srand( now ); #else /* POSIX.1-2001 */ srandom( now ); #endif universal_simple_random_initialized = true; } (*this_).dummy=0; } static inline void universal_simple_random_destroy ( universal_simple_random_t *this_ ) { } static inline uint16_t universal_simple_random_get_uint16 ( universal_simple_random_t *this_ ) { uint16_t result; #ifdef _WIN32 if ( RAND_MAX >= (uint16_t)(-1) ) { result = rand(); } else { result = (((uint_fast16_t)rand()) << 8) ^ rand(); } #else /* POSIX.1-2001 */ if ( RAND_MAX >= (uint16_t)(-1) ) { result = random(); } else { result = (((uint_fast16_t)random()) << 8) ^ random(); } #endif /* Note: random() is possibly not available on win32?, preprocessor-if could distinguish __linux__ and _WIN32 */ return result; } static inline uint32_t universal_simple_random_get_uint32 ( universal_simple_random_t *this_ ) { uint32_t result; #ifdef _WIN32 if ( RAND_MAX >= (uint32_t)(-1) ) { result = rand(); } else if ( RAND_MAX >= (uint16_t)(-1) ) { result = (((uint_fast32_t)rand()) << 16) ^ rand(); } else { result = (((uint_fast32_t)rand()) << 24) ^ (((uint_fast32_t)rand()) << 16) ^ (((uint_fast32_t)rand()) << 8) ^ rand(); } #else /* POSIX.1-2001 */ if ( RAND_MAX >= (uint32_t)(-1) ) { result = random(); } else if ( RAND_MAX >= (uint16_t)(-1) ) { result = (((uint_fast32_t)random()) << 16) ^ random(); } else { result = (((uint_fast32_t)random()) << 24) ^ (((uint_fast32_t)random()) << 16) ^ (((uint_fast32_t)random()) << 8) ^ random(); } #endif /* Note: random() is possibly not available on win32?, preprocessor-if could distinguish __linux__ and _WIN32 */ return result; } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/universal_utf8_writer.h000066400000000000000000000050071415120503000253030ustar00rootroot00000000000000/* File: universal_utf8_writer.h; Copyright and License: see below */ #ifndef UNIVERSAL_UTF8_WRITER_H #define UNIVERSAL_UTF8_WRITER_H /* public file for the doxygen documentation: */ /*! * \file * \brief implements a utf8 writer and forwards the output to a universal_output_stream */ #include "stream/universal_output_stream.h" #include /*! * \brief attributes of the universal_utf8_writer */ struct universal_utf8_writer_struct { universal_output_stream_t *output_stream; /*!< pointer to external \c universal_output_stream_t */ }; typedef struct universal_utf8_writer_struct universal_utf8_writer_t; /*! * \brief initializes the universal_utf8_writer_t * * \param this_ pointer to own object attributes * \param out_stream output stream */ static inline void universal_utf8_writer_init ( universal_utf8_writer_t *this_, universal_output_stream_t* out_stream ); /*! * \brief destroys the universal_utf8_writer_t * * \param this_ pointer to own object attributes */ static inline void universal_utf8_writer_destroy ( universal_utf8_writer_t *this_ ); /*! * \brief writes a utf8 string to a stream * * \param this_ pointer to own object attributes * \param utf8_string 0-terminated string to write * \return 0 in case of success, -1 otherwise */ static inline int universal_utf8_writer_write_str ( universal_utf8_writer_t *this_, const void *utf8_string ); /*! * \brief writes an integer to a stream * * \param this_ pointer to own object attributes * \param number number to write * \return 0 in case of success, -1 otherwise */ static inline int universal_utf8_writer_write_int ( universal_utf8_writer_t *this_, const int64_t number ); /*! * \brief flushes buffers * * \param this_ pointer to own object attributes * \return 0 in case of success, -1 otherwise */ static inline int universal_utf8_writer_flush ( universal_utf8_writer_t *this_ ); #include "universal_utf8_writer.inl" #endif /* UNIVERSAL_UTF8_WRITER_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/include/universal_utf8_writer.inl000066400000000000000000000040661415120503000256420ustar00rootroot00000000000000/* File: universal_utf8_writer.c; Copyright and License: see below */ #include "trace.h" #include #include #include static inline void universal_utf8_writer_init ( universal_utf8_writer_t *this_, universal_output_stream_t* out_stream ) { assert( out_stream != NULL ); (*this_).output_stream = out_stream; } static inline void universal_utf8_writer_destroy ( universal_utf8_writer_t *this_ ) { (*this_).output_stream = NULL; } static inline int universal_utf8_writer_write_str ( universal_utf8_writer_t *this_, const void *utf8_string ) { assert( (*this_).output_stream != NULL ); assert( utf8_string != NULL ); const size_t length = strlen(utf8_string); const int err = universal_output_stream_write( (*this_).output_stream, utf8_string, length ); return err; } static inline int universal_utf8_writer_write_int ( universal_utf8_writer_t *this_, const int64_t number ) { char number_str[21]; /* this is sufficient for signed 64 bit integers: -9223372036854775806 */ /* Note: snprintf is not available on every OS */ sprintf( number_str, "%" PRIi64, number ); const size_t length = strlen(number_str); const int err = universal_output_stream_write( (*this_).output_stream, number_str, length ); return err; } static inline int universal_utf8_writer_flush ( universal_utf8_writer_t *this_ ) { assert( (*this_).output_stream != NULL ); const int err = universal_output_stream_flush( (*this_).output_stream ); return err; } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/source/000077500000000000000000000000001415120503000204335ustar00rootroot00000000000000crystal-facet-uml-1.34.1/universal/source/stream/000077500000000000000000000000001415120503000217265ustar00rootroot00000000000000crystal-facet-uml-1.34.1/universal/source/stream/universal_buffer_input_stream.c000066400000000000000000000114561415120503000302340ustar00rootroot00000000000000/* File: universal_buffer_input_stream.c; Copyright and License: see below */ #include "stream/universal_buffer_input_stream.h" #include "stream/universal_input_stream_if.h" #include "trace.h" #include "tslog.h" #include #include /* the vmt implementing the interface */ static const universal_input_stream_if_t universal_buffer_input_stream_private_if = { .read = (int (*)(universal_input_stream_impl_t*, void*, size_t, size_t*)) &universal_buffer_input_stream_read }; void universal_buffer_input_stream_init( universal_buffer_input_stream_t *this_, void* mem_buf_start, size_t mem_buf_size, universal_input_stream_t *source ) { TRACE_BEGIN(); assert( mem_buf_start != NULL ); assert( source != NULL ); (*this_).source = source; (*this_).mem_buf_start = mem_buf_start; (*this_).mem_buf_size = mem_buf_size; (*this_).mem_buf_fill = 0; (*this_).mem_buf_pos = 0; universal_input_stream_private_init( &((*this_).input_stream), &universal_buffer_input_stream_private_if, this_ ); (*this_).stream_pos_of_buf = 0; TRACE_END(); } void universal_buffer_input_stream_destroy( universal_buffer_input_stream_t *this_ ) { TRACE_BEGIN(); assert( (*this_).mem_buf_start != NULL ); assert( (*this_).source != NULL ); (*this_).mem_buf_start = NULL; (*this_).mem_buf_size = 0; (*this_).mem_buf_fill = 0; (*this_).mem_buf_pos = 0; universal_input_stream_private_destroy( &((*this_).input_stream) ); (*this_).stream_pos_of_buf = 0; (*this_).source = NULL; TRACE_END(); } void universal_buffer_input_stream_reset ( universal_buffer_input_stream_t *this_ ) { TRACE_BEGIN(); assert( (*this_).mem_buf_start != NULL ); assert( (*this_).source != NULL ); (*this_).mem_buf_pos = 0; (*this_).mem_buf_fill = 0; (*this_).stream_pos_of_buf = 0; TRACE_END(); } int universal_buffer_input_stream_read ( universal_buffer_input_stream_t *this_, void *out_buffer, size_t max_size, size_t *out_length ) { /*TRACE_BEGIN();*/ assert( out_buffer != NULL ); assert( max_size != 0 ); assert( out_length != NULL ); assert( (*this_).mem_buf_start != NULL ); assert( (*this_).source != NULL ); int err = 0; const size_t buf_available1 = (*this_).mem_buf_fill - (*this_).mem_buf_pos; char *const buf_first_read = &( (*( (char(*)[])(*this_).mem_buf_start ))[(*this_).mem_buf_pos] ); if ( max_size <= buf_available1 ) { /* read all from buffer */ memcpy( out_buffer, buf_first_read, max_size ); (*this_).mem_buf_pos += max_size; *out_length = max_size; } else { /* read from buffer till buffer is empty */ memcpy( out_buffer, buf_first_read, buf_available1 ); (*this_).stream_pos_of_buf += (*this_).mem_buf_fill; (*this_).mem_buf_pos = 0; (*this_).mem_buf_fill = 0; const size_t remaining_len = max_size - buf_available1; void *const remaining_start = &( (*( (char(*)[])out_buffer ))[buf_available1] ); if ( remaining_len < (*this_).mem_buf_size ) { err |= universal_input_stream_read( (*this_).source, (*this_).mem_buf_start, (*this_).mem_buf_size, &((*this_).mem_buf_fill) ); const size_t buf_available2 = ( (*this_).mem_buf_fill < remaining_len )?( (*this_).mem_buf_fill ):( remaining_len ); memcpy( remaining_start, (*this_).mem_buf_start, buf_available2 ); (*this_).mem_buf_pos = buf_available2; *out_length = buf_available1 + buf_available2; } else { size_t remaining_actual = 0; err |= universal_input_stream_read( (*this_).source, remaining_start, remaining_len, &remaining_actual ); *out_length = buf_available1 + remaining_actual; (*this_).stream_pos_of_buf += remaining_actual; } } /*TRACE_END_ERR(err);*/ return err; } universal_input_stream_t* universal_buffer_input_stream_get_input_stream( universal_buffer_input_stream_t *this_ ) { TRACE_BEGIN(); universal_input_stream_t* result = &((*this_).input_stream); TRACE_END(); return result; } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/source/stream/universal_buffer_output_stream.c000066400000000000000000000105351415120503000304320ustar00rootroot00000000000000/* File: universal_buffer_output_stream.c; Copyright and License: see below */ #include "stream/universal_buffer_output_stream.h" #include "stream/universal_output_stream_if.h" #include "trace.h" #include "tslog.h" #include #include /* the vmt implementing the interface */ static const universal_output_stream_if_t universal_buffer_output_stream_private_if = { .write = (int (*)(universal_output_stream_impl_t*, const void*, size_t)) &universal_buffer_output_stream_write, .flush = (int (*)(universal_output_stream_impl_t*)) &universal_buffer_output_stream_flush }; void universal_buffer_output_stream_init( universal_buffer_output_stream_t *this_, void* mem_buf_start, size_t mem_buf_size, universal_output_stream_t *sink ) { TRACE_BEGIN(); assert( mem_buf_start != NULL ); assert( sink != NULL ); (*this_).sink = sink; (*this_).mem_buf_start = mem_buf_start; (*this_).mem_buf_size = mem_buf_size; (*this_).mem_buf_filled = 0; universal_output_stream_private_init( &((*this_).output_stream), &universal_buffer_output_stream_private_if, this_ ); TRACE_END(); } int universal_buffer_output_stream_destroy( universal_buffer_output_stream_t *this_ ) { TRACE_BEGIN(); assert( (*this_).mem_buf_start != NULL ); assert( (*this_).sink != NULL ); int err = 0; err = universal_buffer_output_stream_flush( this_ ); (*this_).mem_buf_start = NULL; (*this_).mem_buf_size = 0; (*this_).mem_buf_filled = 0; universal_output_stream_private_destroy( &((*this_).output_stream) ); (*this_).sink = NULL; TRACE_END_ERR(err); return err; } int universal_buffer_output_stream_write ( universal_buffer_output_stream_t *this_, const void *start, size_t length ) { /*TRACE_BEGIN();*/ assert( start != NULL ); assert( (*this_).mem_buf_start != NULL ); assert( (*this_).sink != NULL ); int err = 0; const size_t space_left = (*this_).mem_buf_size - (*this_).mem_buf_filled; char *const buf_first_free = &( (*( (char(*)[])(*this_).mem_buf_start ))[(*this_).mem_buf_filled] ); if ( length <= space_left ) { /* append all to buffer */ memcpy( buf_first_free, start, length ); (*this_).mem_buf_filled += length; } else { /* append to buffer till buffer is full */ memcpy( buf_first_free, start, space_left ); (*this_).mem_buf_filled += space_left; const size_t remaining_len = length - space_left; const void *remaining_start = &( (*( (char(*)[])start ))[space_left] ); err |= universal_buffer_output_stream_flush( this_ ); if ( remaining_len <= (*this_).mem_buf_size ) { memcpy( (*this_).mem_buf_start , remaining_start, remaining_len ); (*this_).mem_buf_filled = remaining_len; } else { err |= universal_output_stream_write( (*this_).sink, remaining_start, remaining_len ); } } /*TRACE_END_ERR(err);*/ return err; } int universal_buffer_output_stream_flush( universal_buffer_output_stream_t *this_ ) { TRACE_BEGIN(); assert( (*this_).mem_buf_start != NULL ); assert( (*this_).sink != NULL ); int err = 0; if ( (*this_).mem_buf_filled > 0 ) { err |= universal_output_stream_write( (*this_).sink, (*this_).mem_buf_start, (*this_).mem_buf_filled ); } (*this_).mem_buf_filled = 0; TRACE_END_ERR(err); return err; } universal_output_stream_t* universal_buffer_output_stream_get_output_stream( universal_buffer_output_stream_t *this_ ) { TRACE_BEGIN(); universal_output_stream_t* result = &((*this_).output_stream); TRACE_END(); return result; } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/source/stream/universal_escaping_output_stream.c000066400000000000000000000146661415120503000307630ustar00rootroot00000000000000/* File: universal_escaping_output_stream.c; Copyright and License: see below */ #include "stream/universal_escaping_output_stream.h" #include "stream/universal_output_stream_if.h" #include "trace.h" #include "tslog.h" #include #include /* the vmt implementing the interface */ static const universal_output_stream_if_t universal_escaping_output_stream_private_if = { .write = (int (*)(universal_output_stream_impl_t*, const void*, size_t)) &universal_escaping_output_stream_write, .flush = (int (*)(universal_output_stream_impl_t*)) &universal_escaping_output_stream_flush }; void universal_escaping_output_stream_init ( universal_escaping_output_stream_t *this_, const char *const ((*patterns_and_replacements)[][2]), universal_output_stream_t *sink ) { TRACE_BEGIN(); assert( patterns_and_replacements != NULL ); assert( sink != NULL ); (*this_).patterns_and_replacements = patterns_and_replacements; (*this_).sink = sink; universal_output_stream_private_init( &((*this_).output_stream), &universal_escaping_output_stream_private_if, this_ ); TRACE_END(); } int universal_escaping_output_stream_destroy( universal_escaping_output_stream_t *this_ ) { TRACE_BEGIN(); int err = 0; (*this_).patterns_and_replacements = NULL; (*this_).sink = NULL; universal_output_stream_private_destroy( &((*this_).output_stream) ); TRACE_END_ERR(err); return err; } void universal_escaping_output_stream_change_rules( universal_escaping_output_stream_t *this_, const char *const ((*patterns_and_replacements)[][2]) ) { TRACE_BEGIN(); assert( patterns_and_replacements != NULL ); (*this_).patterns_and_replacements = patterns_and_replacements; TRACE_END(); } int universal_escaping_output_stream_write ( universal_escaping_output_stream_t *this_, const void *start, size_t length ) { /*TRACE_BEGIN();*/ assert( start != NULL ); assert( (*this_).patterns_and_replacements != NULL ); assert( (*this_).sink != NULL ); int err = 0; const char (*char_buf)[] = (void*)start; /* count and analyze input patterns */ unsigned int pattern_count = 0; char head_common_bits = '\x00'; /* optimization, improves xml export by 5% */ char head_common_pattern = '\x00'; /* optimization, improves xml export by 5% */ for ( unsigned int pattern_idx = 0; (*((*this_).patterns_and_replacements))[pattern_idx][0] != NULL; pattern_idx++ ) { pattern_count++; if ( pattern_idx == 0 ) { head_common_bits = '\xff'; head_common_pattern = *((*((*this_).patterns_and_replacements))[pattern_idx][0]); } else { const char unequal_bits = head_common_pattern ^ *((*((*this_).patterns_and_replacements))[pattern_idx][0]); head_common_bits = head_common_bits & ( ~ unequal_bits ); } }; head_common_pattern &= head_common_bits; /* search and replace patterns */ size_t bytes_already_written = 0; for ( size_t index = 0; index < length; index ++ ) { /* check if a pattern matches */ int matching_pattern_idx = -1; const char chr_at_idx = (*char_buf)[index]; if (( chr_at_idx & head_common_bits ) == head_common_pattern ) { for ( unsigned int pattern_idx = 0; ( pattern_idx < pattern_count )&&( matching_pattern_idx == -1 ); pattern_idx++ ) { const char * pattern = (*((*this_).patterns_and_replacements))[pattern_idx][0]; const unsigned int pattern_len = strlen( pattern ); if (( index + pattern_len <= length )&&( pattern_len > 0 )) { if ( 0 == memcmp( &((*char_buf)[index]), pattern, pattern_len ) ) { matching_pattern_idx = pattern_idx; /*fprintf(stderr,"found pattern %d at pos %zd\n",matching_pattern_idx,index);*/ } } } } /* replace pattern */ if ( matching_pattern_idx != -1 ) { /* write previously processed bytes */ err |= universal_output_stream_write( (*this_).sink, &((*char_buf)[bytes_already_written]), index-bytes_already_written ); bytes_already_written = index; /* write pattern */ const char * pattern = (*((*this_).patterns_and_replacements))[matching_pattern_idx][0]; const unsigned int pattern_len = strlen( pattern ); const char * replacement = (*((*this_).patterns_and_replacements))[matching_pattern_idx][1]; unsigned int replace_len = 0; if ( replacement != NULL ) { replace_len = strlen(replacement); } err |= universal_output_stream_write( (*this_).sink, replacement, replace_len ); bytes_already_written += pattern_len; /* forward index */ index = index + pattern_len - 1; } if ( (index+1)==length ) /* is last? */ { err |= universal_output_stream_write( (*this_).sink, &((*char_buf)[bytes_already_written]), length-bytes_already_written ); bytes_already_written = length; } } /*TRACE_END_ERR(err);*/ return err; } int universal_escaping_output_stream_flush( universal_escaping_output_stream_t *this_ ) { TRACE_BEGIN(); assert( (*this_).sink != NULL ); const int err = universal_output_stream_flush( (*this_).sink ); TRACE_END_ERR(err); return err; } universal_output_stream_t* universal_escaping_output_stream_get_output_stream( universal_escaping_output_stream_t *this_ ) { TRACE_BEGIN(); universal_output_stream_t* result = &((*this_).output_stream); TRACE_END(); return result; } /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/source/stream/universal_file_input_stream.c000066400000000000000000000071011415120503000276720ustar00rootroot00000000000000/* File: universal_file_input_stream.c; Copyright and License: see below */ #include "stream/universal_file_input_stream.h" #include "stream/universal_input_stream_if.h" #include "trace.h" #include "tslog.h" #include #include /* the vmt implementing the interface */ static const universal_input_stream_if_t universal_file_input_stream_private_if = { .read = (int (*)(universal_input_stream_impl_t*, void*, size_t, size_t*)) &universal_file_input_stream_read }; void universal_file_input_stream_init ( universal_file_input_stream_t *this_ ) { TRACE_BEGIN(); (*this_).input = NULL; universal_input_stream_private_init( &((*this_).input_stream), &universal_file_input_stream_private_if, this_ ); TRACE_END(); } int universal_file_input_stream_destroy( universal_file_input_stream_t *this_ ) { TRACE_BEGIN(); int err = 0; if ( (*this_).input != NULL ) { err = universal_file_input_stream_close( this_ ); } (*this_).input = NULL; universal_input_stream_private_destroy( &((*this_).input_stream) ); TRACE_END_ERR(err); return err; } int universal_file_input_stream_reset ( universal_file_input_stream_t *this_ ) { TRACE_BEGIN(); assert( (*this_).input != NULL ); int err = 0; err = fseek( (*this_).input, 0, SEEK_SET ); if ( err != 0 ) { TSLOG_ERROR("error at resetting the read-cursor in a file."); err = -1; } TRACE_END_ERR(err); return err; } int universal_file_input_stream_open ( universal_file_input_stream_t *this_, const char *path ) { TRACE_BEGIN(); assert( (*this_).input == NULL ); assert( path != NULL ); int err = 0; (*this_).input = fopen( path, "r" ); if ( NULL == (*this_).input ) { TSLOG_ERROR("error at opening file for reading."); err = -1; } TRACE_END_ERR(err); return err; } int universal_file_input_stream_read ( universal_file_input_stream_t *this_, void *out_buffer, size_t max_size, size_t *out_length ) { /*TRACE_BEGIN();*/ assert( (*this_).input != NULL ); int err = 0; size_t read_bytes = fread( out_buffer, 1, max_size, (*this_).input ); if ( read_bytes != 0 ) { *out_length = read_bytes; } else { err = -1; /* finished, no more bytes to read or other error */ *out_length = 0; } /*TRACE_END_ERR(err);*/ return err; } int universal_file_input_stream_close( universal_file_input_stream_t *this_ ) { TRACE_BEGIN(); assert( (*this_).input != NULL ); int err = 0; int close_err; close_err = fclose( (*this_).input ); if ( 0 != close_err ) { TSLOG_ERROR_INT("error at closing file:",close_err); err = -1; } (*this_).input = NULL; TRACE_END_ERR(err); return err; } universal_input_stream_t* universal_file_input_stream_get_input_stream( universal_file_input_stream_t *this_ ) { TRACE_BEGIN(); universal_input_stream_t* result = &((*this_).input_stream); TRACE_END(); return result; } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/source/stream/universal_file_output_stream.c000066400000000000000000000075541415120503000301070ustar00rootroot00000000000000/* File: universal_file_output_stream.c; Copyright and License: see below */ #include "stream/universal_file_output_stream.h" #include "stream/universal_output_stream_if.h" #include "trace.h" #include "tslog.h" #include #include /* the vmt implementing the interface */ static const universal_output_stream_if_t universal_file_output_stream_private_if = { .write = (int (*)(universal_output_stream_impl_t*, const void*, size_t)) &universal_file_output_stream_write, .flush = (int (*)(universal_output_stream_impl_t*)) &universal_file_output_stream_flush }; void universal_file_output_stream_init ( universal_file_output_stream_t *this_ ) { TRACE_BEGIN(); (*this_).output = NULL; universal_output_stream_private_init( &((*this_).output_stream), &universal_file_output_stream_private_if, this_ ); TRACE_END(); } int universal_file_output_stream_destroy( universal_file_output_stream_t *this_ ) { TRACE_BEGIN(); int err = 0; if ( (*this_).output != NULL ) { err = universal_file_output_stream_close( this_ ); } (*this_).output = NULL; universal_output_stream_private_destroy( &((*this_).output_stream) ); TRACE_END_ERR(err); return err; } int universal_file_output_stream_open ( universal_file_output_stream_t *this_, const char *path ) { TRACE_BEGIN(); assert( (*this_).output == NULL ); assert( path != NULL ); int err = 0; (*this_).output = fopen( path, "w" ); if ( NULL == (*this_).output ) { TSLOG_ERROR("error at opening file for writing."); err = -1; } TRACE_END_ERR(err); return err; } int universal_file_output_stream_write ( universal_file_output_stream_t *this_, const void *start, size_t length ) { /*TRACE_BEGIN();*/ assert( (*this_).output != NULL ); int err = 0; size_t written = 0; while (( written < length )&&( err == 0 )) { ssize_t out_count; out_count = fwrite( ((const char*)start)+written, 1, length-written, (*this_).output ); if ( out_count < 0 ) { TSLOG_ERROR_INT( "not all bytes could be written. missing:", length-written ); err = -1; } else { written += out_count; } } /*TRACE_END_ERR(err);*/ return err; } int universal_file_output_stream_flush( universal_file_output_stream_t *this_ ) { TRACE_BEGIN(); assert( (*this_).output != NULL ); int err = 0; int flush_err; flush_err = fflush( (*this_).output ); if ( 0 != flush_err ) { TSLOG_ERROR_INT("error at flushing file:",flush_err); err = -1; } TRACE_END_ERR(err); return err; } int universal_file_output_stream_close( universal_file_output_stream_t *this_ ) { TRACE_BEGIN(); assert( (*this_).output != NULL ); int err = 0; int close_err; close_err = fclose( (*this_).output ); if ( 0 != close_err ) { TSLOG_ERROR_INT("error at closing file:",close_err); err = -1; } (*this_).output = NULL; TRACE_END_ERR(err); return err; } universal_output_stream_t* universal_file_output_stream_get_output_stream( universal_file_output_stream_t *this_ ) { TRACE_BEGIN(); universal_output_stream_t* result = &((*this_).output_stream); TRACE_END(); return result; } /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/source/stream/universal_memory_input_stream.c000066400000000000000000000072501415120503000302700ustar00rootroot00000000000000/* File: universal_memory_input_stream.c; Copyright and License: see below */ #include "stream/universal_memory_input_stream.h" #include "stream/universal_input_stream_if.h" #include "trace.h" #include "tslog.h" #include #include /* the vmt implementing the interface */ static const universal_input_stream_if_t universal_memory_input_stream_private_if = { .read = (int (*)(universal_input_stream_impl_t*, void*, size_t, size_t*)) &universal_memory_input_stream_read }; void universal_memory_input_stream_init ( universal_memory_input_stream_t *this_, const void* mem_buf_start, size_t mem_buf_size ) { TRACE_BEGIN(); assert( mem_buf_start != NULL ); (*this_).mem_buf_start = mem_buf_start; (*this_).mem_buf_size = mem_buf_size; (*this_).mem_buf_pos = 0; universal_input_stream_private_init( &((*this_).input_stream), &universal_memory_input_stream_private_if, this_ ); TRACE_END(); } void universal_memory_input_stream_reinit ( universal_memory_input_stream_t *this_, const void* mem_buf_start, size_t mem_buf_size ) { TRACE_BEGIN(); universal_memory_input_stream_destroy( this_ ); universal_memory_input_stream_init( this_, mem_buf_start, mem_buf_size ); TRACE_END(); } void universal_memory_input_stream_destroy( universal_memory_input_stream_t *this_ ) { TRACE_BEGIN(); (*this_).mem_buf_start = NULL; (*this_).mem_buf_size = 0; (*this_).mem_buf_pos = 0; universal_input_stream_private_destroy( &((*this_).input_stream) ); TRACE_END(); } int universal_memory_input_stream_reset ( universal_memory_input_stream_t *this_ ) { TRACE_BEGIN(); assert( (*this_).mem_buf_start != NULL ); const int err = 0; (*this_).mem_buf_pos = 0; TRACE_END_ERR(err); return err; } int universal_memory_input_stream_read ( universal_memory_input_stream_t *this_, void *out_buffer, size_t max_size, size_t *out_length ) { /*TRACE_BEGIN();*/ assert( out_buffer != NULL ); assert( max_size != 0 ); assert( out_length != NULL ); assert( (*this_).mem_buf_start != NULL ); int err = 0; const size_t stream_bytes_left = ( (*this_).mem_buf_size - (*this_).mem_buf_pos ); if ( stream_bytes_left != 0 ) { const size_t bytes_to_copy = (max_size <= stream_bytes_left) ? max_size : stream_bytes_left; char *const buf_first_read = &( (*( (char(*)[])(*this_).mem_buf_start ))[(*this_).mem_buf_pos] ); memcpy( out_buffer, buf_first_read, bytes_to_copy ); (*this_).mem_buf_pos += bytes_to_copy; *out_length = bytes_to_copy; } else { err = -1; /* finished, no more bytes to read */ *out_length = 0; } /*TRACE_END_ERR(err);*/ return err; } universal_input_stream_t* universal_memory_input_stream_get_input_stream( universal_memory_input_stream_t *this_ ) { TRACE_BEGIN(); universal_input_stream_t* result = &((*this_).input_stream); TRACE_END(); return result; } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/source/stream/universal_memory_output_stream.c000066400000000000000000000105511415120503000304670ustar00rootroot00000000000000/* File: universal_memory_output_stream.c; Copyright and License: see below */ #include "stream/universal_memory_output_stream.h" #include "stream/universal_output_stream_if.h" #include "trace.h" #include "tslog.h" #include #include /* the vmt implementing the interface */ static const universal_output_stream_if_t universal_memory_output_stream_private_if = { .write = (int (*)(universal_output_stream_impl_t*, const void*, size_t)) &universal_memory_output_stream_write, .flush = (int (*)(universal_output_stream_impl_t*)) &universal_memory_output_stream_flush }; void universal_memory_output_stream_init ( universal_memory_output_stream_t *this_, void* mem_buf_start, size_t mem_buf_size ) { TRACE_BEGIN(); assert( mem_buf_start != NULL ); (*this_).mem_buf_start = mem_buf_start; (*this_).mem_buf_size = mem_buf_size; (*this_).mem_buf_filled = 0; universal_output_stream_private_init( &((*this_).output_stream), &universal_memory_output_stream_private_if, this_ ); TRACE_END(); } void universal_memory_output_stream_destroy( universal_memory_output_stream_t *this_ ) { TRACE_BEGIN(); (*this_).mem_buf_start = NULL; (*this_).mem_buf_size = 0; (*this_).mem_buf_filled = 0; universal_output_stream_private_destroy( &((*this_).output_stream) ); TRACE_END(); } int universal_memory_output_stream_reset ( universal_memory_output_stream_t *this_ ) { TRACE_BEGIN(); assert( (*this_).mem_buf_start != NULL ); const int err = 0; (*this_).mem_buf_filled = 0; TRACE_END_ERR(err); return err; } int universal_memory_output_stream_write ( universal_memory_output_stream_t *this_, const void *start, size_t length ) { /*TRACE_BEGIN();*/ assert( start != NULL ); assert( (*this_).mem_buf_start != NULL ); int err = 0; const size_t space_left = ( (*this_).mem_buf_size - (*this_).mem_buf_filled ); char *const buf_first_free = &( (*( (char(*)[])(*this_).mem_buf_start ))[(*this_).mem_buf_filled] ); if ( length <= space_left ) { memcpy( buf_first_free, start, length ); (*this_).mem_buf_filled += length; } else { memcpy( buf_first_free, start, space_left ); (*this_).mem_buf_filled += space_left; TSLOG_WARNING_INT( "not all bytes could be written. missing:", length-space_left ); err = -1; } /*TRACE_END_ERR(err);*/ return err; } int universal_memory_output_stream_flush( universal_memory_output_stream_t *this_ ) { TRACE_BEGIN(); assert( (*this_).mem_buf_start != NULL ); const int err = 0; TRACE_END_ERR(err); return err; } int universal_memory_output_stream_write_0term ( universal_memory_output_stream_t *this_ ) { TRACE_BEGIN(); assert( (*this_).mem_buf_start != NULL ); int err = 0; if ( (*this_).mem_buf_size == 0 ) { TSLOG_ERROR( "buffer size is 0; buffer is not terminated by zero." ); err = -1; } else if ( (*this_).mem_buf_size == (*this_).mem_buf_filled ) { char *const last_char = &( (*( (char(*)[])(*this_).mem_buf_start ))[(*this_).mem_buf_size - 1] ); *last_char = '\0'; TSLOG_WARNING( "last byte overwritten by terminating zero" ); err = -1; } else { char *const term_char = &( (*( (char(*)[])(*this_).mem_buf_start ))[(*this_).mem_buf_filled] ); *term_char = '\0'; (*this_).mem_buf_filled += sizeof(char); } TRACE_END_ERR(err); return err; } universal_output_stream_t* universal_memory_output_stream_get_output_stream( universal_memory_output_stream_t *this_ ) { TRACE_BEGIN(); universal_output_stream_t* result = &((*this_).output_stream); TRACE_END(); return result; } /* Copyright 2020-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/source/stream/universal_stream_output_stream.c000066400000000000000000000057751415120503000304660ustar00rootroot00000000000000/* File: universal_stream_output_stream.c; Copyright and License: see below */ #include "stream/universal_stream_output_stream.h" #include "stream/universal_output_stream_if.h" #include "trace.h" #include "tslog.h" #include #include /* the vmt implementing the interface */ static const universal_output_stream_if_t universal_stream_output_stream_private_if = { .write = (int (*)(universal_output_stream_impl_t*, const void*, size_t)) &universal_stream_output_stream_write, .flush = (int (*)(universal_output_stream_impl_t*)) &universal_stream_output_stream_flush }; void universal_stream_output_stream_init( universal_stream_output_stream_t *this_, FILE* out_stream ) { TRACE_BEGIN(); assert( out_stream != NULL ); (*this_).output = out_stream; universal_output_stream_private_init( &((*this_).output_stream), &universal_stream_output_stream_private_if, this_ ); TRACE_END(); } void universal_stream_output_stream_destroy( universal_stream_output_stream_t *this_ ) { TRACE_BEGIN(); (*this_).output = NULL; universal_output_stream_private_destroy( &((*this_).output_stream) ); TRACE_END(); } int universal_stream_output_stream_write ( universal_stream_output_stream_t *this_, const void *start, size_t length ) { /*TRACE_BEGIN();*/ assert( (*this_).output != NULL ); int err = 0; size_t written = 0; while (( written < length )&&( err == 0 )) { ssize_t out_count; out_count = fwrite( ((const char*)start)+written, 1, length-written, (*this_).output ); if ( out_count < 0 ) { TSLOG_ERROR_INT( "not all bytes could be written. missing:", length-written ); err = -1; } else { written += out_count; } } /*TRACE_END_ERR(err);*/ return err; } int universal_stream_output_stream_flush( universal_stream_output_stream_t *this_ ) { TRACE_BEGIN(); assert( (*this_).output != NULL ); int err = 0; int flush_err; flush_err = fflush( (*this_).output ); if ( 0 != flush_err ) { TSLOG_ERROR_INT("error at flushing file:",flush_err); err = -1; } TRACE_END_ERR(err); return err; } universal_output_stream_t* universal_stream_output_stream_get_output_stream( universal_stream_output_stream_t *this_ ) { TRACE_BEGIN(); universal_output_stream_t* result = &((*this_).output_stream); TRACE_END(); return result; } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/source/universal_simple_random.c000066400000000000000000000013311415120503000255160ustar00rootroot00000000000000/* File: universal_simple_random.c; Copyright and License: see below */ #include "universal_simple_random.h" bool universal_simple_random_initialized = false; /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/universal/test/000077500000000000000000000000001415120503000201125ustar00rootroot00000000000000crystal-facet-uml-1.34.1/universal/test/unit/000077500000000000000000000000001415120503000210715ustar00rootroot00000000000000crystal-facet-uml-1.34.1/universal/test/unit/universal_arena_list_test.c000066400000000000000000000062011415120503000265040ustar00rootroot00000000000000/* File: universal_arena_list_test.c; Copyright and License: see below */ #include "universal_arena_list_test.h" #if 0 #include "arena/universal_arena_list.h" #include "arena/universal_arena_list_element.h" #include "arena/universal_memory_arena.h" #endif #include "test_assert.h" #include #include static void set_up(void); static void tear_down(void); static void test_append(void); test_suite_t universal_arena_list_test_get_list(void) { test_suite_t result; test_suite_init( &result, "universal_arena_list_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "test_append", &test_append ); return result; } static void set_up(void) {} static void tear_down(void) {} static void test_append(void) {} #if 0 static char one_and_half_element[ sizeof(universal_arena_list_element_t) + 2*sizeof(double) + sizeof(int) ]; universal_memory_arena_t small_arena; static void set_up(void) { universal_memory_arena_init( &small_arena, &one_and_half_element, sizeof(one_and_half_element) ); } static void tear_down(void) { universal_memory_arena_destroy( &small_arena ); } static void test_append(void) { universal_arena_list_t test_me; universal_arena_list_init( &test_me, &small_arena ); /* check empty iterator */ universal_arena_list_element_t *it1 = universal_arena_list_get_begin( &test_me ); TEST_ASSERT( NULL == it1 ); /* get memory from arena */ double *ele_1; int err1 = universal_memory_arena_get_block( &small_arena, sizeof(double), (void**)&ele_1 ); TEST_ASSERT_EQUAL_INT( 0, err1 ); *ele_1 = 34.5; /* append by getting memory from arena */ int err2 = universal_arena_list_append( &test_me, ele_1 ); TEST_ASSERT_EQUAL_INT( 0, err2 ); /* get memory from arena */ double *ele_2; int err3 = universal_memory_arena_get_block( &small_arena, sizeof(double), (void**)&ele_2 ); TEST_ASSERT_EQUAL_INT( 0, err3 ); *ele_1 = 17.25; /* fail to append by getting memory from arena */ int err4 = universal_arena_list_append( &test_me, ele_2 ); TEST_ASSERT_EQUAL_INT( -1, err4 ); /* check non-empty iterator */ universal_arena_list_element_t *it2 = universal_arena_list_get_begin( &test_me ); TEST_ASSERT( NULL != it2 ); TEST_ASSERT( ele_1 == universal_arena_list_element_get_data( it2 ) ); /* check iterate */ it2 = universal_arena_list_element_get_next( it2 ); TEST_ASSERT( NULL == it2 ); TEST_ASSERT( NULL == universal_arena_list_get_end( &test_me ) ); universal_arena_list_destroy( &test_me ); } #endif /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/universal/test/unit/universal_arena_list_test.h000066400000000000000000000016531415120503000265170ustar00rootroot00000000000000/* File: universal_arena_list_test.h; Copyright and License: see below */ #ifndef UNIVERSAL_ARENA_LIST_TEST_H #define UNIVERSAL_ARENA_LIST_TEST_H /*! * \file * \brief UNITTEST for universal_arena_list */ #include "test_suite.h" test_suite_t universal_arena_list_test_get_list(void); #endif /* UNIVERSAL_ARENA_LIST_TEST_H */ /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/universal/test/unit/universal_array_index_sorter_test.c000066400000000000000000000070151415120503000302720ustar00rootroot00000000000000/* File: universal_array_index_sorter_test.c; Copyright and License: see below */ #include "universal_array_index_sorter.h" #include "universal_array_index_sorter_test.h" #include "test_assert.h" #include #include static void set_up(void); static void tear_down(void); static void test_insert_and_retrieve(void); test_suite_t universal_array_index_sorter_test_get_list(void) { test_suite_t result; test_suite_init( &result, "universal_array_index_sorter_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "test_insert_and_retrieve", &test_insert_and_retrieve ); return result; } static void set_up(void) { } static void tear_down(void) { } static void test_insert_and_retrieve(void) { int err; uint32_t count; uint32_t unsorted_index; universal_array_index_sorter_t testee; /* init */ universal_array_index_sorter_init( &testee ); count = universal_array_index_sorter_get_count( &testee ); TEST_ASSERT_EQUAL_INT( 0, count ); /* insert first */ err = universal_array_index_sorter_insert( &testee, 17001, -17 ); TEST_ASSERT_EQUAL_INT( 0, err ); count = universal_array_index_sorter_get_count( &testee ); TEST_ASSERT_EQUAL_INT( 1, count ); unsorted_index = universal_array_index_sorter_get_array_index( &testee, 0 /* = sort_index */ ); TEST_ASSERT_EQUAL_INT( 17001, unsorted_index ); /* insert second in front */ err = universal_array_index_sorter_insert( &testee, 23000, -19 ); TEST_ASSERT_EQUAL_INT( 0, err ); count = universal_array_index_sorter_get_count( &testee ); TEST_ASSERT_EQUAL_INT( 2, count ); unsorted_index = universal_array_index_sorter_get_array_index( &testee, 0 /* = sort_index */ ); TEST_ASSERT_EQUAL_INT( 23000, unsorted_index ); /* insert third at end */ err = universal_array_index_sorter_insert( &testee, 45022, 11 ); TEST_ASSERT_EQUAL_INT( 0, err ); count = universal_array_index_sorter_get_count( &testee ); TEST_ASSERT_EQUAL_INT( 3, count ); /* insert fourth in middle */ err = universal_array_index_sorter_insert( &testee, 99900, -18 ); TEST_ASSERT_EQUAL_INT( 0, err ); count = universal_array_index_sorter_get_count( &testee ); TEST_ASSERT_EQUAL_INT( 4, count ); /* check full list */ unsorted_index = universal_array_index_sorter_get_array_index( &testee, 0 /* = sort_index */ ); TEST_ASSERT_EQUAL_INT( 23000, unsorted_index ); unsorted_index = universal_array_index_sorter_get_array_index( &testee, 1 /* = sort_index */ ); TEST_ASSERT_EQUAL_INT( 99900, unsorted_index ); unsorted_index = universal_array_index_sorter_get_array_index( &testee, 2 /* = sort_index */ ); TEST_ASSERT_EQUAL_INT( 17001, unsorted_index ); unsorted_index = universal_array_index_sorter_get_array_index( &testee, 3 /* = sort_index */ ); TEST_ASSERT_EQUAL_INT( 45022, unsorted_index ); /* done */ universal_array_index_sorter_destroy( &testee ); } /* * Copyright 2017-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/universal/test/unit/universal_array_index_sorter_test.h000066400000000000000000000017331415120503000303000ustar00rootroot00000000000000/* File: universal_array_index_sorter_test.h; Copyright and License: see below */ #ifndef UNIVERSAL_ARRAY_INDEX_SORTER_TEST_H #define UNIVERSAL_ARRAY_INDEX_SORTER_TEST_H /*! * \file * \brief UNITTEST for universal_array_index_sorter */ #include "test_suite.h" test_suite_t universal_array_index_sorter_test_get_list(void); #endif /* UNIVERSAL_ARRAY_INDEX_SORTER_TEST_H */ /* * Copyright 2017-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/universal/test/unit/universal_array_list_test.c000066400000000000000000000210731415120503000265400ustar00rootroot00000000000000/* File: universal_array_list_test.c; Copyright and License: see below */ #include "universal_array_list.h" #include "universal_array_list_test.h" #include "test_assert.h" #include #include static void set_up(void); static void tear_down(void); static void test_insert_and_retrieve(void); static void test_max_size(void); static void test_element_lifecycle(void); unsigned int ctor_calls; /* count constructor callbacks */ unsigned int dtor_calls; /* count destructor callbacks */ unsigned int eq_calls; /* count equal callbacks */ test_suite_t universal_array_list_test_get_list(void) { test_suite_t result; test_suite_init( &result, "universal_array_list_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "test_insert_and_retrieve", &test_insert_and_retrieve ); test_suite_add_test_case( &result, "test_max_size", &test_max_size ); test_suite_add_test_case( &result, "test_element_lifecycle", &test_element_lifecycle ); return result; } static void set_up(void) { ctor_calls = 0; dtor_calls = 0; eq_calls = 0; } static void tear_down(void) { } static void test_insert_and_retrieve(void) { int err; char (string_buf[5])[7]; universal_array_list_t testee; /* init */ universal_array_list_init ( &testee, 5 /*max_elements*/, &(string_buf[0]), sizeof(char[7]), ((char*)(&(string_buf[1])))-((char*)(&(string_buf[0]))), NULL /*copy_ctor*/, NULL /*equal*/, NULL /*dtor*/ ); TEST_ASSERT_EQUAL_INT( true, universal_array_list_is_empty( &testee ) ); TEST_ASSERT_EQUAL_INT( 0, universal_array_list_get_length( &testee ) ); /* insert first */ err = universal_array_list_append ( &testee, "123456" ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 1, universal_array_list_get_length( &testee ) ); /* insert second */ err = universal_array_list_append ( &testee, "abcdef" ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 2, universal_array_list_get_length( &testee ) ); TEST_ASSERT_EQUAL_INT( false, universal_array_list_is_empty( &testee ) ); /* read element */ TEST_ASSERT_EQUAL_PTR( NULL, universal_array_list_get_const( &testee, 2 ) ); TEST_ASSERT_EQUAL_PTR( NULL, universal_array_list_get_ptr( &testee, 2 ) ); TEST_ASSERT_EQUAL_INT( 0, memcmp( "abcdef", universal_array_list_get_const( &testee, 1 ), sizeof(char[7]) ) ); TEST_ASSERT_EQUAL_INT( 0, memcmp( "abcdef", universal_array_list_get_ptr( &testee, 1 ), sizeof(char[7]) ) ); TEST_ASSERT_EQUAL_INT( 0, memcmp( "123456", universal_array_list_get_const( &testee, 0 ), sizeof(char[7]) ) ); TEST_ASSERT_EQUAL_INT( 0, memcmp( "123456", universal_array_list_get_ptr( &testee, 0 ), sizeof(char[7]) ) ); /* search element */ TEST_ASSERT_EQUAL_INT( 1, universal_array_list_get_index_of ( &testee, "abcdef" ) ); /* clear */ universal_array_list_clear( &testee ); TEST_ASSERT_EQUAL_INT( true, universal_array_list_is_empty( &testee ) ); TEST_ASSERT_EQUAL_INT( 0, universal_array_list_get_length( &testee ) ); TEST_ASSERT_EQUAL_PTR( NULL, universal_array_list_get_const( &testee, 0 ) ); TEST_ASSERT_EQUAL_PTR( NULL, universal_array_list_get_ptr( &testee, 0 ) ); /* search element */ TEST_ASSERT_EQUAL_INT( -1, universal_array_list_get_index_of ( &testee, "abcdef" ) ); /* done */ universal_array_list_destroy( &testee ); TEST_ASSERT_EQUAL_INT( 0, ctor_calls ); TEST_ASSERT_EQUAL_INT( 0, dtor_calls ); } static void test_max_size(void) { int err; uint64_t buf[5]; universal_array_list_t testee; /* init */ universal_array_list_init ( &testee, 5 /*max_elements*/, &buf, sizeof(uint64_t), ((char*)(&(buf[1])))-((char*)(&(buf[0]))), NULL /*copy_ctor*/, NULL /*equal*/, NULL /*dtor*/ ); TEST_ASSERT_EQUAL_INT( 0, universal_array_list_get_length( &testee ) ); /* insert first element */ const uint64_t ele1 = 0x8000cccc10004444; err = universal_array_list_append ( &testee, &ele1 ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 1, universal_array_list_get_length( &testee ) ); /* insert second element */ const uint64_t ele2 = 0xcccc100044440000; err = universal_array_list_append ( &testee, &ele2 ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 2, universal_array_list_get_length( &testee ) ); /* insert self, first time */ err = universal_array_list_append_all ( &testee, &testee ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 4, universal_array_list_get_length( &testee ) ); /* insert self, second time */ err = universal_array_list_append_all ( &testee, &testee ); TEST_ASSERT_EQUAL_INT( -1, err ); TEST_ASSERT_EQUAL_INT( 5, universal_array_list_get_length( &testee ) ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &ele1, universal_array_list_get_const( &testee, 4 ), sizeof(uint64_t) ) ); /* insert third element */ const uint64_t ele3 = 0x1000444400005b5b; err = universal_array_list_append ( &testee, &ele3 ); TEST_ASSERT_EQUAL_INT( -1, err ); TEST_ASSERT_EQUAL_INT( 5, universal_array_list_get_length( &testee ) ); } void copy_ctor (double* to_instance, const double* from_instance) { *to_instance = *from_instance; ctor_calls++; } void dtor (double* instance) { *instance = 0.0; dtor_calls++; } bool equal (const double* instance_1, const double* instance_2) { eq_calls++; return ( *instance_1 == *instance_2 ); } static void test_element_lifecycle(void) { int err; double buf[4]; universal_array_list_t testee; /* init */ universal_array_list_init ( &testee, 4 /*max_elements*/, &buf, sizeof(double), ((char*)(&(buf[1])))-((char*)(&(buf[0]))), (void (*)(void*, const void*))copy_ctor, (bool (*)(const void*, const void*))equal, (void (*)(void*))dtor ); TEST_ASSERT_EQUAL_INT( 0, ctor_calls ); TEST_ASSERT_EQUAL_INT( 0, dtor_calls ); /* insert first */ const double ele1 = 17.125; err = universal_array_list_append ( &testee, &ele1 ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 1, ctor_calls ); TEST_ASSERT_EQUAL_INT( 0, eq_calls ); TEST_ASSERT_EQUAL_INT( 0, dtor_calls ); /* clear */ universal_array_list_clear( &testee ); TEST_ASSERT_EQUAL_INT( 1, ctor_calls ); TEST_ASSERT_EQUAL_INT( 0, eq_calls ); TEST_ASSERT_EQUAL_INT( 1, dtor_calls ); /* insert first again */ err = universal_array_list_append ( &testee, &ele1 ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 2, ctor_calls ); TEST_ASSERT_EQUAL_INT( 0, eq_calls ); TEST_ASSERT_EQUAL_INT( 1, dtor_calls ); /* insert self, first time */ err = universal_array_list_append_all ( &testee, &testee ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 3, ctor_calls ); TEST_ASSERT_EQUAL_INT( 0, eq_calls ); TEST_ASSERT_EQUAL_INT( 1, dtor_calls ); /* search element */ int idx = universal_array_list_get_index_of ( &testee, &ele1 ); TEST_ASSERT_EQUAL_INT( 0, idx ); TEST_ASSERT_EQUAL_INT( 3, ctor_calls ); TEST_ASSERT_EQUAL_INT( 1, eq_calls ); TEST_ASSERT_EQUAL_INT( 1, dtor_calls ); /* done */ universal_array_list_destroy( &testee ); TEST_ASSERT_EQUAL_INT( 3, ctor_calls ); TEST_ASSERT_EQUAL_INT( 1, eq_calls ); TEST_ASSERT_EQUAL_INT( 3, dtor_calls ); } /* * Copyright 2020-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/universal/test/unit/universal_array_list_test.h000066400000000000000000000016531415120503000265470ustar00rootroot00000000000000/* File: universal_array_list_test.h; Copyright and License: see below */ #ifndef UNIVERSAL_ARRAY_LIST_TEST_H #define UNIVERSAL_ARRAY_LIST_TEST_H /*! * \file * \brief UNITTEST for universal_array_list */ #include "test_suite.h" test_suite_t universal_array_list_test_get_list(void); #endif /* UNIVERSAL_ARRAY_LIST_TEST_H */ /* * Copyright 2020-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/universal/test/unit/universal_buffer_input_stream_test.c000066400000000000000000000127641415120503000304410ustar00rootroot00000000000000/* File: universal_buffer_input_stream_test.c; Copyright and License: see below */ #include "universal_buffer_input_stream_test.h" #include "stream/universal_buffer_input_stream.h" #include "stream/universal_memory_input_stream.h" #include "test_assert.h" #include #include static void set_up(void); static void tear_down(void); static void test_read_chunks(void); static void test_read_all(void); static void test_peek(void); static char my_in_buffer[10]; static universal_memory_input_stream_t my_mem_in_stream; static char my_buffer[6]; static universal_buffer_input_stream_t my_buf_in_stream; test_suite_t universal_buffer_input_stream_test_get_list(void) { test_suite_t result; test_suite_init( &result, "universal_buffer_input_stream_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "test_read_chunks", &test_read_chunks ); test_suite_add_test_case( &result, "test_read_all", &test_read_all ); test_suite_add_test_case( &result, "test_peek", &test_peek ); return result; } static void set_up(void) { memcpy( &my_in_buffer, "123456789", sizeof(my_in_buffer) ); universal_memory_input_stream_init( &my_mem_in_stream, &my_in_buffer, sizeof(my_in_buffer) ); universal_input_stream_t *my_mem_in_stream_ptr = universal_memory_input_stream_get_input_stream( &my_mem_in_stream ); universal_buffer_input_stream_init( &my_buf_in_stream, &my_buffer, sizeof(my_buffer), my_mem_in_stream_ptr ); } static void tear_down(void) { universal_buffer_input_stream_destroy( &my_buf_in_stream ); universal_memory_input_stream_destroy( &my_mem_in_stream ); } static void test_read_chunks(void) { int err; /* get universal_input_stream_t */ universal_input_stream_t *my_in_stream; my_in_stream = universal_buffer_input_stream_get_input_stream( &my_buf_in_stream ); TEST_ASSERT( my_in_stream != NULL ); /* get universal_input_stream_if_t */ const universal_input_stream_if_t *my_in_if = universal_input_stream_get_interface ( my_in_stream ); TEST_ASSERT( my_in_if != NULL ); /* get objectdata */ void *my_obj_data = universal_input_stream_get_objectdata ( my_in_stream ); TEST_ASSERT_EQUAL_PTR( &my_buf_in_stream, my_obj_data ); /* read first 5 */ size_t len; char buf5[5]; err = universal_input_stream_read ( my_in_stream, &buf5, sizeof(buf5), &len ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( sizeof(buf5), len ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &buf5, "12345", sizeof(buf5) ) ); /* read last 5 */ err = universal_input_stream_read ( my_in_stream, &buf5, sizeof(buf5), &len ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( sizeof(buf5), len ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &buf5, "6789", sizeof(buf5) ) ); /* read after end */ err = universal_input_stream_read ( my_in_stream, &buf5, sizeof(buf5), &len ); TEST_ASSERT_EQUAL_INT( -1, err ); TEST_ASSERT_EQUAL_INT( 0, len ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &buf5, "6789", sizeof(buf5)-1 ) ); } static void test_read_all(void) { int err; /* get universal_input_stream_t */ universal_input_stream_t *my_in_stream; my_in_stream = universal_buffer_input_stream_get_input_stream( &my_buf_in_stream ); TEST_ASSERT( my_in_stream != NULL ); /* read first 12 */ size_t len; char buf12[12]; err = universal_input_stream_read ( my_in_stream, &buf12, sizeof(buf12), &len ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( sizeof(my_in_buffer), len ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &buf12, "123456789", sizeof(my_in_buffer) ) ); /* reset */ err = universal_memory_input_stream_reset ( &my_mem_in_stream ); universal_buffer_input_stream_reset ( &my_buf_in_stream ); TEST_ASSERT_EQUAL_INT( 0, err ); /* read first 12 */ err = universal_input_stream_read ( my_in_stream, &buf12, sizeof(buf12), &len ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( sizeof(my_in_buffer), len ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &buf12, "123456789", sizeof(my_in_buffer) ) ); /* read after end */ err = universal_input_stream_read ( my_in_stream, &buf12, sizeof(buf12), &len ); TEST_ASSERT_EQUAL_INT( -1, err ); TEST_ASSERT_EQUAL_INT( 0, len ); } static void test_peek(void) { /* peek and read the 10 bytes */ for ( int idx = 0; idx < sizeof(my_in_buffer); idx ++ ) { char nxt = universal_buffer_input_stream_peek_next( &my_buf_in_stream ); TEST_ASSERT_EQUAL_INT( my_in_buffer[idx], nxt ); char cur = universal_buffer_input_stream_read_next( &my_buf_in_stream ); TEST_ASSERT_EQUAL_INT( my_in_buffer[idx], cur ); } /* peek+read after end */ char last1 = universal_buffer_input_stream_peek_next( &my_buf_in_stream ); TEST_ASSERT_EQUAL_INT( '\0', last1 ); char last2 = universal_buffer_input_stream_read_next( &my_buf_in_stream ); TEST_ASSERT_EQUAL_INT( '\0', last2 ); } /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/universal/test/unit/universal_buffer_input_stream_test.h000066400000000000000000000017411415120503000304370ustar00rootroot00000000000000/* File: universal_buffer_input_stream_test.h; Copyright and License: see below */ #ifndef UNIVERSAL_BUFFER_INPUT_STREAM_TEST_H #define UNIVERSAL_BUFFER_INPUT_STREAM_TEST_H /*! * \file * \brief UNITTEST for universal_buffer_input_stream */ #include "test_suite.h" test_suite_t universal_buffer_input_stream_test_get_list(void); #endif /* UNIVERSAL_BUFFER_INPUT_STREAM_TEST_H */ /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/universal/test/unit/universal_buffer_output_stream_test.c000066400000000000000000000120321415120503000306260ustar00rootroot00000000000000/* File: universal_buffer_output_stream_test.c; Copyright and License: see below */ #include "universal_buffer_output_stream_test.h" #include "stream/universal_buffer_output_stream.h" #include "stream/universal_memory_output_stream.h" #include "test_assert.h" #include #include static void set_up(void); static void tear_down(void); static void test_append_regular(void); static void test_append_border_cases(void); static char my_out_buffer[10]; static universal_memory_output_stream_t my_mem_out_stream; static char my_buffer[6]; static universal_buffer_output_stream_t my_buf_out_stream; test_suite_t universal_buffer_output_stream_test_get_list(void) { test_suite_t result; test_suite_init( &result, "universal_buffer_output_stream_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "test_append_regular", &test_append_regular ); test_suite_add_test_case( &result, "test_append_border_cases", &test_append_border_cases ); return result; } static void set_up(void) { memset( &my_out_buffer, '\0', sizeof(my_out_buffer) ); universal_memory_output_stream_init( &my_mem_out_stream, &my_out_buffer, sizeof(my_out_buffer) ); universal_output_stream_t *my_mem_out_stream_ptr = universal_memory_output_stream_get_output_stream( &my_mem_out_stream ); universal_buffer_output_stream_init( &my_buf_out_stream, &my_buffer, sizeof(my_buffer), my_mem_out_stream_ptr ); } static void tear_down(void) { universal_buffer_output_stream_destroy( &my_buf_out_stream ); universal_memory_output_stream_destroy( &my_mem_out_stream ); } static void test_append_regular(void) { int err; /* get universal_output_stream_t */ universal_output_stream_t *my_out_stream; my_out_stream = universal_buffer_output_stream_get_output_stream( &my_buf_out_stream ); TEST_ASSERT( my_out_stream != NULL ); /* get universal_output_stream_if_t */ const universal_output_stream_if_t *my_out_if = universal_output_stream_get_interface ( my_out_stream ); TEST_ASSERT( my_out_if != NULL ); /* get objectdata */ void *my_obj_data = universal_output_stream_get_objectdata ( my_out_stream ); TEST_ASSERT_EQUAL_PTR( &my_buf_out_stream, my_obj_data ); /* write */ const char test_1[] = "Hello"; err = universal_output_stream_write ( my_out_stream, test_1, sizeof(test_1) ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( '\0', my_out_buffer[0] ); /* flush */ err = universal_output_stream_flush (my_out_stream); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 0, strcmp( &(my_out_buffer[0]), test_1 ) ); /* reset */ err = universal_memory_output_stream_reset( &my_mem_out_stream ); TEST_ASSERT_EQUAL_INT( 0, err ); /* write */ const char test_2[] = "Hel"; err = universal_output_stream_write ( my_out_stream, test_2, strlen(test_2) ); TEST_ASSERT_EQUAL_INT( 0, err ); /* write */ const char test_3[] = "lo!"; err = universal_output_stream_write ( my_out_stream, test_3, sizeof(test_3) ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 0, strcmp( &(my_out_buffer[0]), "Hello!" ) ); } static void test_append_border_cases(void) { int err; /* get universal_output_stream_t */ universal_output_stream_t *my_out_stream; my_out_stream = universal_buffer_output_stream_get_output_stream( &my_buf_out_stream ); TEST_ASSERT( my_out_stream != NULL ); /* write */ const char test_1[] = "1234567"; err = universal_output_stream_write ( my_out_stream, test_1, strlen(test_1) ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &(my_out_buffer[0]), &test_1, sizeof(my_buffer) ) ); /* write */ const char test_2[] = "890abc"; err = universal_output_stream_write ( my_out_stream, test_2, strlen(test_2) ); TEST_ASSERT_EQUAL_INT( -1, err ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &(my_out_buffer[0]), "1234567890", sizeof(my_out_buffer) ) ); /* write */ const char test_3[] = "lo!!!"; err = universal_output_stream_write ( my_out_stream, test_3, sizeof(test_3) ); TEST_ASSERT_EQUAL_INT( -1, err ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &(my_out_buffer[0]), "1234567890", sizeof(my_out_buffer) ) ); /* write */ const char test_4[] = ""; err = universal_output_stream_write ( my_out_stream, test_4, 0 ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &(my_out_buffer[0]), "1234567890", sizeof(my_out_buffer) ) ); } /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/universal/test/unit/universal_buffer_output_stream_test.h000066400000000000000000000017471415120503000306460ustar00rootroot00000000000000/* File: universal_buffer_output_stream_test.h; Copyright and License: see below */ #ifndef UNIVERSAL_BUFFER_OUTPUT_STREAM_TEST_H #define UNIVERSAL_BUFFER_OUTPUT_STREAM_TEST_H /*! * \file * \brief UNITTEST for universal_buffer_output_stream */ #include "test_suite.h" test_suite_t universal_buffer_output_stream_test_get_list(void); #endif /* UNIVERSAL_BUFFER_OUTPUT_STREAM_TEST_H */ /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/universal/test/unit/universal_escaping_output_stream_test.c000066400000000000000000000113371415120503000311550ustar00rootroot00000000000000/* File: universal_escaping_output_stream_test.c; Copyright and License: see below */ #include "universal_escaping_output_stream_test.h" #include "stream/universal_escaping_output_stream.h" #include "stream/universal_memory_output_stream.h" #include "test_assert.h" #include #include static void set_up(void); static void tear_down(void); static void test_write_regular(void); static void test_write_border_cases(void); static char my_out_buffer[16]; static universal_memory_output_stream_t my_mem_out_stream; static universal_escaping_output_stream_t my_esc_out_stream; const char *const ((my_patterns_and_replacements)[][2]) = {{"&","&"},{"--","- - "},{"\n"," \n"},{NULL,NULL}}; test_suite_t universal_escaping_output_stream_test_get_list(void) { test_suite_t result; test_suite_init( &result, "universal_escaping_output_stream_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "test_write_regular", &test_write_regular ); test_suite_add_test_case( &result, "test_write_border_cases", &test_write_border_cases ); return result; } static void set_up(void) { memset( &my_out_buffer, '\0', sizeof(my_out_buffer) ); universal_memory_output_stream_init( &my_mem_out_stream, &my_out_buffer, sizeof(my_out_buffer) ); universal_escaping_output_stream_init( &my_esc_out_stream, &my_patterns_and_replacements, universal_memory_output_stream_get_output_stream( &my_mem_out_stream ) ); } static void tear_down(void) { int err; err = universal_escaping_output_stream_destroy( &my_esc_out_stream ); universal_memory_output_stream_destroy( &my_mem_out_stream ); TEST_ENVIRONMENT_ASSERT( err == 0 ); } static void test_write_regular(void) { int err; /* get universal_output_stream_t */ universal_output_stream_t *my_out_stream; my_out_stream = universal_escaping_output_stream_get_output_stream( &my_esc_out_stream ); TEST_ASSERT( my_out_stream != NULL ); /* write */ const char test_1[] = "&"; err = universal_output_stream_write ( my_out_stream, test_1, strlen(test_1) ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 0, strcmp( &(my_out_buffer[0]), "&" ) ); /* flush */ err = universal_output_stream_flush (my_out_stream); TEST_ASSERT_EQUAL_INT( 0, err ); /* write */ const char test_2[] = "---4\n"; err = universal_output_stream_write ( my_out_stream, test_2, strlen(test_2) ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 0, strcmp( &(my_out_buffer[0]), "&- - -4 \n" ) ); /* write */ const char test_3[] = ""; err = universal_output_stream_write ( my_out_stream, test_3, strlen(test_3) ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 0, strcmp( &(my_out_buffer[0]), "&- - -4 \n" ) ); } static void test_write_border_cases(void) { int err; /* get universal_output_stream_t */ universal_output_stream_t *my_out_stream; my_out_stream = universal_escaping_output_stream_get_output_stream( &my_esc_out_stream ); TEST_ASSERT( my_out_stream != NULL ); /* write */ const char test_1[] = "0123456789abcdef"; err = universal_output_stream_write ( my_out_stream, test_1, sizeof(test_1) ); TEST_ASSERT_EQUAL_INT( -1, err ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &(my_out_buffer[0]), test_1, sizeof(my_out_buffer) ) ); /* reset underlying memory output stream */ err = universal_memory_output_stream_reset( &my_mem_out_stream ); TEST_ASSERT_EQUAL_INT( 0, err ); /* write */ const char test_2[] = "&&-----"; err = universal_output_stream_write ( my_out_stream, test_2, strlen(test_2) ); TEST_ASSERT_EQUAL_INT( -1, err ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &(my_out_buffer[0]), "&&- - - ", sizeof(my_out_buffer) ) ); /* write */ const char test_3[] = "\n"; err = universal_output_stream_write ( my_out_stream, test_3, sizeof(test_3) ); TEST_ASSERT_EQUAL_INT( -1, err ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &(my_out_buffer[0]), "&&- - - ", sizeof(my_out_buffer) ) ); } /* * Copyright 2020-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/universal/test/unit/universal_escaping_output_stream_test.h000066400000000000000000000017631415120503000311640ustar00rootroot00000000000000/* File: universal_escaping_output_stream_test.h; Copyright and License: see below */ #ifndef UNIVERSAL_ESCAPING_OUTPUT_STREAM_TEST_H #define UNIVERSAL_ESCAPING_OUTPUT_STREAM_TEST_H /*! * \file * \brief UNITTEST for universal_escaping_output_stream */ #include "test_suite.h" test_suite_t universal_escaping_output_stream_test_get_list(void); #endif /* UNIVERSAL_ESCAPING_OUTPUT_STREAM_TEST_H */ /* * Copyright 2020-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/universal/test/unit/universal_memory_arena_test.c000066400000000000000000000050411415120503000270420ustar00rootroot00000000000000/* File: universal_memory_arena_test.c; Copyright and License: see below */ #include "universal_memory_arena_test.h" #if 0 #include "arena/universal_memory_arena.h" #endif #include "test_assert.h" #include #include #include static void set_up(void); static void tear_down(void); static void test_alloc_blocks(void); test_suite_t universal_memory_arena_test_get_list(void) { test_suite_t result; test_suite_init( &result, "universal_memory_arena_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "test_alloc_blocks", &test_alloc_blocks ); return result; } static void set_up(void) { } static void tear_down(void) { } static void test_alloc_blocks(void) { #if 0 char thirty_three[33]; universal_memory_arena_t test_me; universal_memory_arena_init( &test_me, &(thirty_three[1]), sizeof(thirty_three)-1 ); void *block_1; int err; err = universal_memory_arena_get_block( &test_me, 1, &block_1 ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT( NULL != block_1 ); TEST_ASSERT_EQUAL_INT( 0, ((unsigned int)block_1) % sizeof(int) ); void *block_2; err = universal_memory_arena_get_block( &test_me, 1, &block_2 ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT( NULL != block_2 ); TEST_ASSERT_EQUAL_INT( 0, ((unsigned int)block_1) % sizeof(int) ); TEST_ASSERT_EQUAL_INT( sizeof(int), ((unsigned int)block_2)-((unsigned int)block_1) ); universal_memory_arena_reset( &test_me ); void *block_3; err = universal_memory_arena_get_block( &test_me, 33-sizeof(int), &block_3 ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT( NULL != block_3 ); TEST_ASSERT_EQUAL_INT( 0, ((unsigned int)block_3) % sizeof(int) ); void *block_4; err = universal_memory_arena_get_block( &test_me, sizeof(int), &block_4 ); TEST_ASSERT_EQUAL_INT( -1, err ); TEST_ASSERT( NULL == block_4 ); universal_memory_arena_destroy( &test_me ); #endif } /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/universal/test/unit/universal_memory_arena_test.h000066400000000000000000000016671415120503000270610ustar00rootroot00000000000000/* File: universal_memory_arena_test.h; Copyright and License: see below */ #ifndef UNIVERSAL_MEMORY_ARENA_TEST_H #define UNIVERSAL_MEMORY_ARENA_TEST_H /*! * \file * \brief UNITTEST for universal_memory_arena */ #include "test_suite.h" test_suite_t universal_memory_arena_test_get_list(void); #endif /* UNIVERSAL_MEMORY_ARENA_TEST_H */ /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/universal/test/unit/universal_memory_input_stream_test.c000066400000000000000000000103601415120503000304660ustar00rootroot00000000000000/* File: universal_memory_input_stream_test.c; Copyright and License: see below */ #include "universal_memory_input_stream_test.h" #include "stream/universal_memory_input_stream.h" #include "test_assert.h" #include #include static void set_up(void); static void tear_down(void); static void test_read_chunks(void); static void test_read_all(void); static char my_in_buffer[10]; static universal_memory_input_stream_t my_mem_in_stream; test_suite_t universal_memory_input_stream_test_get_list(void) { test_suite_t result; test_suite_init( &result, "universal_memory_input_stream_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "test_read_chunks", &test_read_chunks ); test_suite_add_test_case( &result, "test_read_all", &test_read_all ); return result; } static void set_up(void) { memcpy( &my_in_buffer, "123456789", sizeof(my_in_buffer) ); universal_memory_input_stream_init( &my_mem_in_stream, &my_in_buffer, sizeof(my_in_buffer) ); } static void tear_down(void) { universal_memory_input_stream_destroy( &my_mem_in_stream ); } static void test_read_chunks(void) { int err; /* get universal_input_stream_t */ universal_input_stream_t *my_in_stream; my_in_stream = universal_memory_input_stream_get_input_stream( &my_mem_in_stream ); TEST_ASSERT( my_in_stream != NULL ); /* get universal_input_stream_if_t */ const universal_input_stream_if_t *my_in_if = universal_input_stream_get_interface ( my_in_stream ); TEST_ASSERT( my_in_if != NULL ); /* get objectdata */ void *my_obj_data = universal_input_stream_get_objectdata ( my_in_stream ); TEST_ASSERT_EQUAL_PTR( &my_mem_in_stream, my_obj_data ); /* read first 5 */ size_t len; char buf5[5]; err = universal_input_stream_read ( my_in_stream, &buf5, sizeof(buf5), &len ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( sizeof(buf5), len ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &buf5, "12345", sizeof(buf5) ) ); /* read last 5 */ err = universal_input_stream_read ( my_in_stream, &buf5, sizeof(buf5), &len ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( sizeof(buf5), len ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &buf5, "6789", sizeof(buf5) ) ); /* read after end */ err = universal_input_stream_read ( my_in_stream, &buf5, sizeof(buf5), &len ); TEST_ASSERT_EQUAL_INT( -1, err ); TEST_ASSERT_EQUAL_INT( 0, len ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &buf5, "6789", sizeof(buf5) ) ); } static void test_read_all(void) { int err; /* get universal_input_stream_t */ universal_input_stream_t *my_in_stream; my_in_stream = universal_memory_input_stream_get_input_stream( &my_mem_in_stream ); TEST_ASSERT( my_in_stream != NULL ); /* read first 12 */ size_t len; char buf12[12]; err = universal_input_stream_read ( my_in_stream, &buf12, sizeof(buf12), &len ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( sizeof(my_in_buffer), len ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &buf12, "123456789", sizeof(my_in_buffer) ) ); /* reset */ err = universal_memory_input_stream_reset ( &my_mem_in_stream ); TEST_ASSERT_EQUAL_INT( 0, err ); /* read first 12 */ err = universal_input_stream_read ( my_in_stream, &buf12, sizeof(buf12), &len ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( sizeof(my_in_buffer), len ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &buf12, "123456789", sizeof(my_in_buffer) ) ); /* read after end */ err = universal_input_stream_read ( my_in_stream, &buf12, sizeof(buf12), &len ); TEST_ASSERT_EQUAL_INT( -1, err ); TEST_ASSERT_EQUAL_INT( 0, len ); } /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/universal/test/unit/universal_memory_input_stream_test.h000066400000000000000000000017411415120503000304760ustar00rootroot00000000000000/* File: universal_memory_input_stream_test.h; Copyright and License: see below */ #ifndef UNIVERSAL_MEMORY_INPUT_STREAM_TEST_H #define UNIVERSAL_MEMORY_INPUT_STREAM_TEST_H /*! * \file * \brief UNITTEST for universal_memory_input_stream */ #include "test_suite.h" test_suite_t universal_memory_input_stream_test_get_list(void); #endif /* UNIVERSAL_MEMORY_INPUT_STREAM_TEST_H */ /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/universal/test/unit/universal_memory_output_stream_test.c000066400000000000000000000135151415120503000306740ustar00rootroot00000000000000/* File: universal_memory_output_stream_test.c; Copyright and License: see below */ #include "universal_memory_output_stream_test.h" #include "stream/universal_memory_output_stream.h" #include "test_assert.h" #include #include static void set_up(void); static void tear_down(void); static void test_insert_regular(void); static void test_insert_border_cases(void); static void test_null_termination(void); static char my_out_buffer[10]; static universal_memory_output_stream_t my_mem_out_stream; test_suite_t universal_memory_output_stream_test_get_list(void) { test_suite_t result; test_suite_init( &result, "universal_memory_output_stream_test_get_list", &set_up, &tear_down ); test_suite_add_test_case( &result, "test_insert_regular", &test_insert_regular ); test_suite_add_test_case( &result, "test_insert_border_cases", &test_insert_border_cases ); test_suite_add_test_case( &result, "test_null_termination", &test_null_termination ); return result; } static void set_up(void) { memset( &my_out_buffer, '\0', sizeof(my_out_buffer) ); universal_memory_output_stream_init( &my_mem_out_stream, &my_out_buffer, sizeof(my_out_buffer) ); } static void tear_down(void) { universal_memory_output_stream_destroy( &my_mem_out_stream ); } static void test_insert_regular(void) { int err; /* get universal_output_stream_t */ universal_output_stream_t *my_out_stream; my_out_stream = universal_memory_output_stream_get_output_stream( &my_mem_out_stream ); TEST_ASSERT( my_out_stream != NULL ); /* get universal_output_stream_if_t */ const universal_output_stream_if_t *my_out_if = universal_output_stream_get_interface ( my_out_stream ); TEST_ASSERT( my_out_if != NULL ); /* get objectdata */ void *my_obj_data = universal_output_stream_get_objectdata ( my_out_stream ); TEST_ASSERT_EQUAL_PTR( &my_mem_out_stream, my_obj_data ); /* write */ const char test_1[] = "Hello"; err = universal_output_stream_write ( my_out_stream, test_1, sizeof(test_1) ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 0, strcmp( &(my_out_buffer[0]), test_1 ) ); /* flush */ err = universal_output_stream_flush (my_out_stream); TEST_ASSERT_EQUAL_INT( 0, err ); /* reset */ err = universal_memory_output_stream_reset( &my_mem_out_stream ); TEST_ASSERT_EQUAL_INT( 0, err ); /* write */ const char test_2[] = "Hel"; err = universal_output_stream_write ( my_out_stream, test_2, strlen(test_2) ); TEST_ASSERT_EQUAL_INT( 0, err ); /* write */ const char test_3[] = "lo!"; err = universal_output_stream_write ( my_out_stream, test_3, sizeof(test_3) ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 0, strcmp( &(my_out_buffer[0]), "Hello!" ) ); } static void test_insert_border_cases(void) { int err; /* get universal_output_stream_t */ universal_output_stream_t *my_out_stream; my_out_stream = universal_memory_output_stream_get_output_stream( &my_mem_out_stream ); TEST_ASSERT( my_out_stream != NULL ); /* reset */ err = universal_memory_output_stream_reset( &my_mem_out_stream ); TEST_ASSERT_EQUAL_INT( 0, err ); /* write */ const char test_1[] = "123456"; err = universal_output_stream_write ( my_out_stream, test_1, strlen(test_1) ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 0, strcmp( &(my_out_buffer[0]), test_1 ) ); /* write */ const char test_2[] = "7890abc"; err = universal_output_stream_write ( my_out_stream, test_2, strlen(test_2) ); TEST_ASSERT_EQUAL_INT( -1, err ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &(my_out_buffer[0]), "1234567890", sizeof(my_out_buffer) ) ); /* write */ const char test_3[] = "lo!"; err = universal_output_stream_write ( my_out_stream, test_3, sizeof(test_3) ); TEST_ASSERT_EQUAL_INT( -1, err ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &(my_out_buffer[0]), "1234567890", sizeof(my_out_buffer) ) ); /* write */ const char test_4[] = ""; err = universal_output_stream_write ( my_out_stream, test_4, 0 ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &(my_out_buffer[0]), "1234567890", sizeof(my_out_buffer) ) ); } static void test_null_termination(void) { int err; /* write */ const char test_1[] = "123456"; err = universal_memory_output_stream_write ( &my_mem_out_stream, test_1, strlen(test_1) ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 0, strcmp( &(my_out_buffer[0]), test_1 ) ); /* write null term*/ err = universal_memory_output_stream_write_0term( &my_mem_out_stream ); TEST_ASSERT_EQUAL_INT( 0, err ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &(my_out_buffer[0]), test_1, sizeof(test_1) ) ); /* write */ const char test_2[] = "7890abc"; err = universal_memory_output_stream_write ( &my_mem_out_stream, test_2, strlen(test_2) ); TEST_ASSERT_EQUAL_INT( -1, err ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &(my_out_buffer[0]), "123456" "\0" "789", sizeof(my_out_buffer) ) ); /* write null term*/ err = universal_memory_output_stream_write_0term( &my_mem_out_stream ); TEST_ASSERT_EQUAL_INT( -1, err ); TEST_ASSERT_EQUAL_INT( 0, memcmp( &(my_out_buffer[0]), "123456" "\0" "78" "\0", sizeof(my_out_buffer) ) ); } /* * Copyright 2020-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/universal/test/unit/universal_memory_output_stream_test.h000066400000000000000000000017471415120503000307050ustar00rootroot00000000000000/* File: universal_memory_output_stream_test.h; Copyright and License: see below */ #ifndef UNIVERSAL_MEMORY_OUTPUT_STREAM_TEST_H #define UNIVERSAL_MEMORY_OUTPUT_STREAM_TEST_H /*! * \file * \brief UNITTEST for universal_memory_output_stream */ #include "test_suite.h" test_suite_t universal_memory_output_stream_test_get_list(void); #endif /* UNIVERSAL_MEMORY_OUTPUT_STREAM_TEST_H */ /* * Copyright 2020-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/user_doc/000077500000000000000000000000001415120503000167265ustar00rootroot00000000000000crystal-facet-uml-1.34.1/user_doc/crystal-facet-uml.1.gz000066400000000000000000000040321415120503000227620ustar00rootroot00000000000000ĉacrystal-facet-uml.1Yko_10е7ζAPVc~A7 Cqr!ŕ,:h5<8qp\OK;7Kxڊy(\Մ~mz"#eoQ{?xn_#/z#0Ѣ 3蚍26Y66юL{N fmVu^ iE{vi5g:ˠJ˧bf k \M Lﱁ&_Ѹ?;:fw yѭop=U&LLtq wu2;v4/M`:iOY;'K-2>WoH+D̋ԱX;'t""i$,YPIml}* (;`N,Y*b2nR16XW3nxp;fHx.{/1#$mfpӠ˸$ JrY e EV+TFޒ69vɩȄrL K&ͅP'-(m=3n."{Q\,p+"&3\Wqiѻۻtyςq!1;.9c_FS_EPѱLoЖfz~,x?’ a32Y9N?.5\H-/No 虌| x HsLAmF{8b?xT,9hqqp2) Dѓ&`k_xxvMi$pDq& (\\&*_6Y΁W)`V/TaR": Ums s`4W Lt@Lˉ@qUKjxFP 4ǵ=(Wr.VNIR.hi dW12>t1U0߲tnqUdzUfX] C*T9WL&D[Y""H|:eYFYYsc 3bxHLDE}CbzbJ[Em^x?!6U.m=lӘ.U+_⑌aXt8l/id !,9R.}: (mxG 9,s;w+M-vo x:m)p8AVQPںzf_EnA[QeVq(^D7ʶLŤ NZva|y7> stream xڅα0ᝧc;[JmGMĹqh#  wÕYY9C[ c%:Z[Y#7Љ61PG˚rȟ!/B %Q( txJôCU,}BWh?:h7F endstream endobj 13 0 obj << /Length 978 /Filter /FlateDecode >> stream xřMo@{Yvf@Pi!1UE"Ŀg{M1┨}XBz9QFNԟuE-|O>'ͯ﷋T8=,hUqu~szSNnhUJ]HA[qz5:P ~.DގT;O:[g+Cf0Mm zdնV^@R+YM\+dh6)*Ҩh6ߤJ$׃}Z%B;IFbbv`twJMBA mYi}Pm4z,_)Ҍj3If '3`0 FC)5x4s:em9֪HWL\1f0Ҕ Ț4. & kiC,F*-Ja$I͘9xiϏ^o\!C4聕臓U?nq556k~&DQW MO_vͪϠoBwnd0r5\#K`!I=oHҩ0mU#ea0rY$uwNH mi]W`xˠ" WS\ݜ/)|h⦹_J"[9aR*1Ö `$gab0YR#K`3 $#9Eg kTZ3kpQ:psa tޜ]r:~n(*7 ;SҲa@%Meq3x/Y'ji/? /qptm&n#9r-~5ߟMl1g )-YS}!wΣG@2-t-XUg@#H^` r]2y FVH2YQSD9G9()A$E9vpfӜٳϯuWFe7FObQ endstream endobj 59 0 obj << /Length 1023 /Filter /FlateDecode >> stream xMsF|=8qKF"23T%dvY~Ͼ ";_xg)HcBOH*4GcDbnUTVf~ (*nL$LYa.S)̔ꚢ4^-< W d8v[D1zl!I f\x?{!T#ʰT["4B_Y[dpB1q{+ BJ񯲪hk}bړSb&v_r(4RkopS)D> ʳ !JukGpfNL/jQ3skn1/KIC@i0?U;SO= k!P"+"g=^nv["5ʑ¿BlDa؈.- TB`2vLX}ky=9OL慱I/"3`1K_E'G=}4:^DtJ#'Ny*;GDRש7RZygjkgʾ<4M.W-3v?&ۃW>"яeĜv6ާeDλ(ܠ@GuˎCSE>mun h$1ڴF#1+ȓx 6c?,qҘ endstream endobj 126 0 obj << /Length 1096 /Filter /FlateDecode >> stream xKw6)XO8~49IN,,0#蔇+ N}%83Ц[+Ñt^` \'I#, 8mj L}4n|4M`u(UZ6Au$#뺒M!@Cbq 5!M8,C0$9X.~[?Gˆ f(Lh?6  g} 3^VGUCt_(p M@/*C|羡 @q2 Ƈ!VRӣ1//x;@Yk|W5X`1M^_7*,](1¿ĖȯJYnvgʓXJU:%.H܀!g\W&I\=ԙL7*->?^^ފT|CAi_nEvW\Luy،V0Vh$ 6o-a&cfb1y'ꭼլc#J'ZagG7weMȢ-_7JK\fݡi"0tW1+Vkw{2ݩ4&i:6j¿NbOՑRB׈l'jPF+r\ZWU]ne>zP%g;s:GYE0?Hb$DL\˴,וwWsbrqEV6ߨf#UN[,5bjUjtB&dcDi>7Ӟ=)a/] endstream endobj 165 0 obj << /Length 656 /Filter /FlateDecode >> stream xڝTMO0Wc;>j@ qٰ;l`*eS y_51!/4͘t#` p!яut]cfBn)0<5( D,tv3I0DaC>D4ƈaaWSX8|o0 r-ԊBMq#mj߷+i'ܦ x&h$I\kBq]񩽹 5Y~̙ejrhm.ڼyM+e8l6p۪E?a hj5}f,4n\m7k .&T ]^?|?>9*GJ?)z-BMJ`A $>%؂/ r@H hkxk/9 KPq) G fX@;q|uK[S;__xiuZV+DlW=&EnDqkCZ.$vp:y vjsiw%Uv}ׄ|Od%Ҝ endstream endobj 160 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///1_introduction_banner.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 168 0 R /BBox [0 0 945 315] /Group 167 0 R /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 9071 /Filter /FlateDecode >> stream xKm+j`*_E Y8Y}^sZ]Tk}=KY߅vN=k MFyU4V~5V1k3_]8g Ο(4xֿHif 3z|:{>hQ4b~67R"c"azHI?Ë пex68i{"2>E[M!iDmaW{OQ>nnUӴYYfQL^bΪs({YIk= -GU+of9Ǿ([c ۳ [ h2o&]\-zD~Xiysv+S߃Ri4[KZdqGhV+mޡgtͭ (;AկۭGէa 6Kz4NֿmwZPn}t"Ͽ~2yݺe"2ZSkYGn4_u AVNجlmQɱY6s(Q"j և%ѥ[`jn"X-ViS+a8q Y{x5H'6-/gyM`v,~9uI<_Cd\ 'NHLg| ڳ1\enꯟ 4~%n2$`-ߦO@|r5~2Xm{:bn[ m1فxB.tKd8 >qQaW$Jk VӉgbhF[6HIȗ|z'C?v1&bc{8ݚ #.gWd@=COsmaRwp䕍I/f9FQjhl@E֡h`|dlSwIS/tTBo;,(}ZF(l1PFRF)hlEh-+;Nݼ[zH%Iz27;Kԁ1Mhe:5 Дn/T\lIgfpbfa%ŭsqޘ}]$|n 4 VKL# ܧZ!z 'QjNn-R[6]3W{ʆNI8_EUW6eBhVG{hՓi5t{ep=|yr;u›hd%- }h =vLq\F7@i^!)(Ŧ1.\{!MC6@!v]憁5 8M {~3'_ uNs=fpǮn/*۟|%UlV"I+J@J;{$WPj.T|]f1g^ɭz44DKUVהcjbqzuhsʼn Ŝ5{>: Rs$\1j m6HjynjI7pHȠ[}ѵB e5+&Ed栍̤7 N=H1UfiX~Xݵ+@L]N NHiJ ?[EۦAn_ZI3ȂeD2cIFD4%7[/>p/b7{b Ŋ$,tBʌ p&K*X? eKUnKGSIɾXI3\dd4KƷnhNT[ -eђZ}$q#v/*vFWj#كZnO+V6sGۊJC EƧKx\< tVj;t|\$h?QbM2 ϨFW[h۲̀-vWȣ7@ \OmdgK3[HBflKf"W;Ie}՛A[׾|f>N-T9svl/d t:ޖEWsc9 ɼ,%*Ͷn,1ipfݬѐq&NХ.JYO8fZno|ż Z5w)VkY<?%ʬ3:cQņL!H`3syUv~tb`8CL2b>U.՛{,/LዜhZfw$#KDZHSf lx•dm?8*dw?#Ť\"=04ceSל¤#p1(1 c>n1P XFt=w8%V dxi=<>3Z@c oh\om5ê`s_~)w /L>Ld#X6ڃD8wat؄*!SȈ"ۑ人 @ֈiL " |DP,a W]P@ W6҅6]3IƯ0wX88U$vBx!*QC:JG O-*X?8a!ﶠ1dR>~ֵRBM&U"IBHګA^aJ ms ҙA԰YLo<( o YG;c&w1> UmېyX`7icg惔6M_#Pa=y6[j0&f{lpBח-GWu_¿H09TΣg@܋D0D 6`綎y=aSMGw% ug)˷Xa-pPm[cYcҶ!R=dmEr) |m ~1D΂-{Gb {LӢ? w|qݧ &l <1gT0 oS'pߝ~ v/'.^ vPIĒ|"?u КrJܤ?~@6z\~!j[p Z' }j Ph=F1xL"U>Mr)q$]`$P˂<^MNKDX-釅]$#r`LV2 qx7v=^z< ,u;zRy [V+v.52Kx2ݠfI׏ְ 4$&[V_M6H(LjøkX,fZ۱VꞾQ+.+F{kf|U\uSKZ1A3]Yfy✝ؕ푺fMZmϗqT^?qșVƹ] %ӜzYD"+p//23AwDvYqN+!P '~rbի G.ɯaK5+Ic:+j#L@,jD Y}sCW춏u>"\%V1w-?; #;Wwl)=B1N1NӡSlo &9%;SmR+:0Gfɓ.#fsbҴX8JX9 l0vqjGL{F?ydٞћ fRz8mR,YpdeK "fqB(? efE rk)d(th*u8-$EN. S0 sXQ_ p :%(ݯ28|6W:R! kAIzvOO u;L"[n!XRwkRXuF*_>+KDhcS[HW)M "\d69'483,7ck$@+lUs?:)Q%V6]V0pqg\!H ]KkZL=z?#&"\0NhDj7HޜI*Q0r2 >jxfEծВ@lRٍ`Z9*=P%D͉u;1AKh`} 9TgS5ΑsC</ևm?by\3y9ܝGm&c얓?3dQ2RXSo0B9OG5F&!sDE^XwБKxHN?8td7@+[ t}S?(D3=$$P#uA,/VO1T3S a} o丰s-^cTr߼|mQ6hF?X3z2]vkwn@~c]#&Ku``As LZ fgqfIA1w ggb숃 #oI[x6aa]XW X $g@ȘPbnc'^Rj."'`f2ӱρ#8׉dP"%uUl@Bnر6#s7,& "rݴوPNC˸baJ7xN){(B8wq`vCںdþ9(,.Zc= Sed}LbK)1 < A:oU {^1P:jŰ邱\C&;m/wR3; }H.AV9o ^mXHNEsc2|rHXɓ$)̆Dt!h}}#ʖ&U@d,Jen:rD9׽:p 1NbE Nc`@(IծK $~4#dJ,X.Œɢɷ_G5c (3N KCxbt. oᠨFIO<՞/=,+xrU\:ZON%16ĝ=G0Of!/&6JwtNQW(|쑁P)0X|O7Y|]zOv@ukmFtFMY5{3h 7dik置Fj.LEy;I4u4Inޕ>Gմ|D+ҧI=H4Mp\ʅ~ыe;SCr\Tm FܵU:]bD<;zt*Ņ"4o. tz:+f.XfzFʖy=M.dm/ j#^Q99yȔ~OF(я'uZG-;9%}(i8zl;uH k+M3&8 ry8 /R2 3 =X# (@#‘G|8~(gZG</NP49n/w#M;oZԷk_L H'@sܯg m Fbk6!u'-9oG @O+7? C? ٖ endstream endobj 161 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/crystal_facet_uml.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 169 0 R /BBox [0 0 24 24] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 611 /Filter /FlateDecode >> stream xuTKn1v|HH,K&- Ou{y }zƮ.Վ gz)j\?/*WmKdPMlI7%5ZkRuԄıGlLpEd&'|~+r @虔Y9d7%0EVRO'>myAЍ H8`\.kRџm=( MJ^ڲ֖"J_+vmk3mK:=gtNB!ML D4 0θ~DfsF7Sأ@"Š]2S0} voxA:gNvZ6FÒ;Fcdk#1R F.<ۉd4\Fi& >'s(Rf3 *c<ݶęu #)BKBɿ#~wڇ<)2=9mY 'M VO-mHµQ\)'xByt  :C9+>b#@LO< u4VM3lkܖ?K endstream endobj 162 0 obj << /Type /XObject /Subtype /Image /Width 1120 /Height 630 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 147042 /Filter/FlateDecode /DecodeParms<> >> stream xy:g}{}:{ @ @  l@ @ @ @ @:+T*0,($)#K@ iA "2L# ( 86&ՆN@ p.v~H&YGX, H$F/@ h AJ~Mvf^ @ HJkA07 KR`@ @ G}UP:qnāj}trss~VWWUQQ5r,sޖht7I/R kJJIȨ،1jVpzbL&3)99^|^~~yyyEE zzzlF}Y("]&J}rss+*PVPv?~8Q`A ȿ ŋ`c9(૪҂󅄄`CA y@&Sn߹MiikMLLXXԤ/0(CxŚ9cFZ.g(:];n$ݻwO<֭CyˇD3c+|hdh>yA(--̼s7V˖,[S[(:<ʐݷbbtbaaGii۷obc?L:5 7%]gld4ͭ{7G޶5PGGNȟh`m:}͌ob͵byn%%%%%%YYYщ\!HIK,511133#HuysssFFӧO?|pĉíK: wUqn\:~~}|~6P"_ AU>HGRضƍ32>x HHHȹs*++i魁b5:<<Օ/[zu׽\tF0) W]nݛׯD'p:Jm c|T޹}:B>~[yy˖e˖uZ >>cO2ht!SYFJJի+W<~쨓 9nشiӊ+y]W^]t큣mmk Np-[,))34w7v% LY[a-Tj ӧOߺy㷬ʞq+Vb˗/?q؄ s?ydŅ>b00` ST g4Ot͢h ~􇜜\m \~=2򔄄Dpv]]o-;G«1J-X3p5$^zzF"cÕ{t)3&k֭[v*..= /^bEn?h+X+MӦyՏ+5HP$a4}L&ŋן<Ў{ȑ#{Ԅ,+ٳ&...&F7)h֖W~T$++{aìUTUyRgYXX_ML p <}};vw<[WW=<v(\W&e Q6wm{ѣ+ 32}, Eg۽o$%tŋ6mzu\\\nݼaffoЛ7c~!ϟ}>ϗHMMM]uoXTTOr~y܎RD{dn9g<))/-_.++c``ӧ8</!!xJFF$Hmhh~sc_Pe;QnM7K"v(UZ]lE!Mr ϝd0ucőzEDDL6)MMӧO;VPPť?짞djZ&kxU?|0>>W;{GR(IDך5k\ $WRnns;>yyyo޼yǢƆFJC#00imm=xv]vS~Z)✹wWKOO744yf,N9ϯ41A"*aR>mlloN$ {)^ѣ-ZYE% ab"x###''ŋX2֭޷[xa;; *m y׶ؠAmTU}N)I@I&..qg֭[ۿi y~XNN%Kܾǁf..!""o߾74h4Zyyy7ݔw[7o1>]dYP.CQ}g 8p d:HLLOft:5֯_IImm8K#Ƿ:#,7*u'| H v!j5a30T haA0X5N_ݶ9W[@F\4P"/?|b---4fXp8Cx5 Cx΁`? gL;gJNRzy3A$xۃz,[JUF*reבl][ڽHM8t4 `D#t<ڥgϞy*dff666""Yq @]-򱢶ԙӻu܏:s={Bz#b]xw޲yKJ >>cmmm'OrwwTB܎g `aaŴjjiNˠqh߉d6UTTێ<el&/$K`V|?? ]C#@GJJ9`Ç، ߹Ag|"/2oߜ9nF> Ep8$J]}K33s_?#BRL&B<Af ` AQ` EEE簝`]MثljõTFHO'//{f짺chZҥK-Zuꔼq'&&6jԨh鵮=Y/tuu;.7.iB(( Dɦkce:jl\5 I~BM|||2u\J-IHHbr_ U~ RXSYá ɵE:l}*5DLLA?;qr999@ڱeo@o9{bn! -z6P򢰩kkb[w63B}j:mBBB|'Ɵ.{,)i-@" <ןM;M6uIII< <[iii3g***2031s&vNVlQy 6ܼySMMm׮]7ź'x ;侻{?~8㵕j XX~&Й4UidW< v/>d)/Rܖxƍ}O"\43>l>W,_.,,xgN=(**2pF6~{{{HO&uZA "E #8412V\p^YS}?IL2:̀T[[;a71^Ѧz$ok+j^+6 A7?_DDxV*$VW`'Oܻ-!!!=k޽&J T\Md@ %MMM***__n6푬ח,^8""(ki0> tq4lpo~𮸸8..ӧOC]pMZ̊KJxq&b-:( $!6ĄX" y,77]Oo Z9Ғ{>>Ga3Zѻq0~z)#x<^><1sfMM}H$rs332o(*҇.vK{[\\便Fha0BD^ؒtxѣ{6b%gN6P=1e}{zbC}U_2Eq;ϑq8@2yvl4(cFW0hN+$q1')/D`ϟ?3fLKK6)9r锔LOOWVGhHQQQZOz wrLHHHHHʲ"k0<~E[=? y%sd8kp\vrl%`A?LVBE;R\˩8K[fjKFG%ԩ3?KO bz457+*vA7a,^`ZBƎ"ςUUU ۷3gN8ۻpݺu޽4dD}ыI i-߾hii;v,''CW(U"H" ,Xyyy-d2Q i9‚Ar $|VTTf}TVVvߕ~mY@4߃4,>vyI/H$H~OOx ;;{BBĦb 8#!VI "EEn< ߿KJJfk9Ȉ8PV$I "l|SNWuV T1 oow![ _|PA6$o4c 1i^}\ GD% {2u%XRRRll GΝ;ٳ~LLL,3#]} A~jյk׈D"SR+//SYYPYYDP(?JK;^@ \x\AZ4sN@$+!$H30gCr"EQѯCLUǶD^b -ƥX2sν}6YmQ 0+]]c#DbCCݻ.]ӧa9"~RĄ^~ˏ?~!CCC%EޕAu<.%%Eofkȣ^ bB3Ąn%%H$lۼe˗/ C wkߥٵsgݻ>_inj*..QSU32ϳ(e $q ̬BA=#mm^L;u4"Ee0@g2 Й{$Ra̒юfϝK|ճWMMȼJ|nje)2\f5쓗:fVneevڗ/_` ǺLX;Dؒx꿁TY$~`uuWh4UPNNСZH5m:Qcy}4*ZKtDp q哊=07mҖ=x{ĉc: kρXlt!P^~*`YYY ***킨sޕ6Y EZqK-i>aömۖ9k֬޼Pwuyn!`THzޠ$æomuu3f*V#݋SBB^{?L&ŴfP8DCCCihh---\R ) `!p3mX0h`Dr4aoE![C(bƪԋ{Eo%K[ +qZAYxKKKO?,pqafVV tbh333{iuu5gܾw1U$ 붬LdHyF)D޽{ghCA 6N,R12 -GvskΠmWPyu `r7ONL9<?卍,s } z)7n?R^E8`mm{475t;; 6̟?1==6f]`qw*|8|>򥍍ڵk###333~ݱG^^u]]ݖo@Ht&Iq?d.^pϟ??iҤr`"[1 ,ܹk+\MU,@Ά)b!H1i@M< _\Y ft`(`x̋ݘHL2"?_ӓo>O=:]A"r~p3Kta`%*}F=FK^pB <,{/jI)2 0eʔ߽{f.:+qS  Hp!555ÇξsBN滵Wv5H0X+ý?~@T02|ʵ6bf3x?,l[rrr'>NE9}zE>>3f̼yO.[rĈtc(8vwR+jjj7g&D]]*"jYlr>$W2 jf|+3şgP{y Jh+<ȓ)Uƻ 6t1L8 qP t,rBA*ˤeu] *,/m $:|B+rPGFNy8Й#˩333/&''% ;%h999< 6DC=##CMM͛{֭e˖͟?ܹE6ozc}iP} 3gΜ>}ZAAam+)\OWݻwGxJKOMwDY/5lJMMY0-))oiAh7&Y[>{bIikjjf/Yl@UC2fT~mo־c}Õ>hss9sjkkG~M2etz+""i:.+K|f sTO8A2y qGWss3Nt Ɍ61|GA+1#t( ǁ ;0Kh9$)x9*`qQ$Y<?rVň㴵99 eeeNNNm}||?.''SUU}xXN֏Ka5Tʶ-Ie1Qf^^!4 .q"' "Gs󎠧?g-t =zrti}2E 񢣷b}e][Hv|\.re4a„r< ߿~cQW^}GiDDD[?~<ږw}v;o-䄄ccc}}o'߶J0$$DMMĤ6>>siΝ;x׳':߹sSF [W2XYZV?}{=|'L{n+h[/\ñXǏ1}+pL דٵ?,5ý]G>`P?>zn*OxR>17-4LJe;X;\(Mpp@WFw퐘d,a457s7<oaa߽{won&'>{O"% Fdl@ga?1e{6ߤ52L&꺻#R(|y:U ګ8PQQ)$,qEQF1/n}…#x{޻w/8h{?\ѣǦ&Y ,+뚨)D1M!rA5p|WTT()+!NVBJJ}Q>stYYyL_>?tТ rssC-*LtuuLLLtut111&]. *2ٞW`k*"ʠcBOҊ%zMꪥuvLVUU쾘 Dp8/pᠨ5: PTƶ.X+fff7Îz4%ti79Bj08 ;y1@"[C_r%pͮdk  !$ . POFɠ*% FZgCCh//.MݰQpEJe: \_W/u333kk됐]vuUʕ+w޵>t/ĉbbb KLMCBBv_zY TU^:88wp+b[ ,^33Ç޽;88<|lyw=%jڻuǴiӺr9{0qľ7nH+$$D\'M:ٳvܵmVA_@RBcc)/~?TXXxmRDg"2[&=wfzL(iEEEXlEeNGLGs>1&&:|x sM?}'%%yFEʱ'JJJjkMϧgI/gQFEeM&H$RRRyjhhhS(n>JJJjjj:vэ`ٔ2@'Q?rF %.`0''}뫥 |6Ꮑd``޺VWWy& M XNL\L\\\JBrň]+-,,q0ےnllߠknnԏJNwoײ߻wO]Cѭ. 6_eckhhؕիW/^m۶Yfu_˗/w#n s,,,z͛NEk׌ҩC`YPY^)R:ȓ'"]ͻj1331+kN9}mڸa~>\d1wN\| gϞ}3g ΥK{αaؑiL ?#wJqк̵'W FLL`v4q8\e:߽}P(-:{܎rws]~}Uvv;vˮ5}I}Ѣcǎ=yɔ+6k  QP@巧 .^^^cƌ‚GG}ur|.k %Juq[B#z͹YF̯.ґ~\Ul'"rJ땔@c [^n]222.....l~IOtIZZٳ;*DcӮ=z$--njbl^vue&l6[CCםRXXu:j9痐`bbs=!;T"H~!CL:YEY9|YauL AJr]ZqƱcǒ+Չݕi1ŦLr*ꔶV?@*u`yyǏ4mmxP/eeϓ7mW_ vlH^<֘/++g0B,[YU'RttyyyVVև ?2L RYY3c={[X/YX\\xih{`֝ygZHšC,Xxɲ=GEW;tX*0:G6=+%`=dرGBEAN7~YqLu iS:tyŗ{_~nnm1k׮h Zׯ_Oz?)Y##Ǐ9rӳk׮yxxܾ}{ر$toPv{;;> 3T{Ǐ?yO#11{%# p;)0#(@ٵk׉'bno~ ##'NLtZ enZlA۷9?n8fG&4hœQ$hjn;1qx|>Hxv{: LnBkDAr.]_SS7kş$$${ uěvcǎ3gFDDhkk :`(|򈈈v_]D|%2rR Lb&._qO9·CYoĮ4  $'Ors.7os;F@@U_'..NV nF_BQ|7mRUUƝ=gǏ{gwzzz```-d2Ϟ=N?`nGF~+Vnٲ ߻g9OzlihPY[è7_8,6JR_~]jUii䤾8nܸػwNJKKۼys0XΖ]qs B( "` _Gecc3իײ{AUWWlLJJ zXwwv8իWl٢>ߺׇDZ;u{ݶ}y[n VNI[-CS԰S֭['%%u' xcXp7ӧO/\`ݺ딚 ϟ?ߺuk۸y0*nmڴISsHxX?lX &z#r coߓG =Z5;qqM\*c#edfjNҲ] =R#l7o޼{vK ?|Jeϟ%n&QdF -&R tWoQ8BIcاd c;-/'fl2Cş,oq칵 ҂Hׇ0O b>|GD}}}ss3GGG,Sv$,,LP6lX?{"޶}wƍ377oҺ*##ɓ'ׯ_WVV -oH\ >~"' V$.g.QثQUZaUs$ێG=+o{Ѻr ?:.((c.%%%wMNN~$&& HSS A_fԤIz/ݫYRrҋOUU$0mllVWS9Vq/I`x60̤{y+((9;O5j@^Eߏ?77D"a؆-- NN':oMh @k_|]%`{9C{%LNy*߃Ǩw3P؝EL6oUM9 ? Q30u˔) cN@؏(F҇ @ zC0sقDa/@ h AIY&ٗ+~LSA @0DQ,ZI(l6N DH"p@ 'pd 75UWQi3 `, @ @@ @ N.v@  $@ @ t .ClKdd$l 2J9_v »@ 7,Y'@@ 2p+I`AK#g$@ @ @ @ @@ @ 4@ Tjw4 d֬Y}*((|捴4ihhpqqTSS@`0~򥾾AJJ ߿GP^^bddχJx BR%%% ܥP(&** [ @ 4 ~8OUTT@ 477ԴTVV 0 UU՚iiiWEEE(6ӛljADDwctJ@:IOOc# EQO_~ZZZ s8 өV233I$#bbb`;@ q 6 A?.'!K ޮ3f N@ 20 v@ (@ @~W @  OF-'+=¼me RP>m8zKLd2O;)N03ݰzwK9\A@ @  FO=ww }=u7G;{}}e+=y%x)ݟ"ɛ9IRdԙii;"VTT.]EQW @ ȟjkhkkkjncg s`% }5u ? I{)("J'\ XeV G}Z**B|yԂE}ssι{2/stu^ys =d55&: ?H$:}v71Aھrrv}jcccggWSS#~ >Śqpp5kw}wu,"`III[^#ǯ#MG_~8?nONד'-=d ]Feݻ} QԌK)鲲l6{ueXXFxUUUnڴiرcA?СC5 4to=<@_!T[[CV:DbQq."''_SS$gg猌 !?&M4yѢE񡡡 \. O< /P>& 5fP(liiųDbsKKY]I&'N8>!<|E4o+1cFYYӧOYYYT*l:>a„חY[l/bŊl2<<|ʔ)ƍ>}zHH~m888ɉNWzxx٥q8PLL̔)Srrr,YBcbbzm,:>wׯ P[_?DO!D$Z[Z,6# UTTzM!G[o)\QQajj;vZ ε 2<==}ȑt2,^k֬ٳgO{{{BBӧ{=M6qPuu?!|}}"""fsrr B,+222883̰0GGদh@`jj /OQSSS^^'JYY<}|҄ 6MC՛q** MC.)*(l? \2uyREEEgf̘qȑWWWu8mmCIII!ƌvĉОϜ?}t˖-&,7 r|| BhرIIIQQQ}Y,Ωb<110**H$" aÆ)))AW P r˾_^Q1ktø7n.=y떭lYztxǜϊN={ǎ^\.x\.ju#!**E%%Q1 of3E4k֬Yfb%%%:^TT4c VP&VZZڗILLLNNh|>?%%ܹsxI@ߖB{J ArD"AYYً/F [[[}}ccT* S^ÉSgD=MRf@̡XoC olocsVm]7saey-Fez^UEqaḄ66h~}B3g  ӧORPP % "szFm޼!TZZz…hjj?H$zxx̝;۷)Jw-r"BXҢ 4Xo466UTTx<' 08-ZsabcǍ΅C !ĉ544$(yVVիjUUUnnnXmm7o ,˗ZZZ 6l?sii ڵk?x9''gѢE}58`aawTQQ+]]]xM !mt~bƌг (JdddwV ;wn{{#GTŋɓ''&&zyyGEEHPYY1uT"B֭;wfss365kkƃ޼y-{ܱcp^=\܊+V^$?0o޼Ç# _|I"\\\oݺER,XP^^M@"~w*/cEEE///waa!@5jTzz:3\A\A#_,E(O[޹@ =A$W$>=X\GGQDq #|XWjjO͛>y3uK7&&fʔ) vvvrl6a۶mc?4B[w.Z  h4Pի~鯿:{l; :}a{ 3g޺uΝ;YYYg̙蕴t'&tyUHֆض֭[/{{^wtwwJ>l>訤t%)==]KKz:sy| ǃrzJJJ!>=ܲex+V૸0H,++ÃNϝ;Y{a#.]JRRR gffb̛7ƍCz%q.}||t ֯__VV&[\\aggg:~ر.+퓒$d{Īӧc7K^qqqppN mll gϞ_{.1%%%|Z,w0ǹ^LLz`²߅5NLܑj$@!///|[GG`&&&&FEEa#z .]]a.yf333… /^x,@JHH011J/XC\ⴵ:M6f77'N"u+|x-g6}Xt3mjiO>S&#V.Krs|uu5y'~/B+)++#-ݾk7 n>_B[7*`fY c OܹsH$=sL``#G?}"K,w{^^D|.AN^^$O uwuT(3~[* -7 E hkkSPPEEE "5Ww444'644sO'GTMMMwٳgݺuaaawaNfggw˗_vm񊊊]VH$=<<Νe=ʹϟ?fffjjj1cp100hllx<O(b @۰.wϊ757z Ṷ{~3m*-1bDؚ`iHgӈ1{ŲJEE{]UUH/_`aaTTTz}ϓ@ ߸qO)))yuk8B177ϫ*??}BXYY]rfwW n<̙3+++>4cƌ.P(/+߿H666ϟ?y󦅅|u䘙My`MMML&|9z}U+֝;vvg`̘/(RU]SU] @?y!7mjjAݻ UUUccX!Cٳ'>>>%%EWWf׮]G~HHHX~^PPЉ'zbùg0$:(( ?㣣\Y:W2zM6ٳL&w.#--r…S0o'OLLLd0,KEEeȑ#@LNN!Mmw-K"EJJꧤD >XbMP.v|&]gt>󥩫sss_h.]]]kB7oZZZv>sذa}o^ffe'744_bl6'NN>, yyySN˟MhhhKH H$ׅB!DߩTj]]׎;TjSSwaa!@5jTzz:B֭[Xւ ;::o&sqq)//#HxbwI###\}Cx<2%%%yNP((D"@D!ǃ x<H*!vO݁Mu<zOBQVUW+H>>>۷o0aBԽ{K.0{Νu! ?XLLLFFƵkԒ?~mxy[.:2QDVwQMw< HwmP_[pLGY)|x܎We 5ā (ΨTjFFxJzz 5C« !:FH46Hdmm_RRҹxbI& ^sww?y$z BtgBq]]]ڵkƍ[lYir3f(++{"YYYT*QXqqqppNϗݰa3Nwww?vxnYY٪URRR3gٳgݻb111SL_t)N7))I52<<|ʔ)ƍ>}zHH͆bG""##-,,6ng 2<==}ȑt;|}}"""]>}|r==͛b|_awwwOO7nDEEt,zuqq&>vϓ}Y,־}BBB ]&i&.^WWx}e<  q@k?{ԩS}}}%\]][[[ݻ3f\d2!D$ &//oԩx 2n8l@ WUU_///:tRЫW}T*a}q=4D"9r$%%B`6PWD"Ѷmێ?;lذtzzzzQQь3$r[[[|~JJʹsD@MbBFwGBp%`0ϟ =zlss_GG^Xb2=111QQQ4^j|Rkkٳ+++=]3g ӧwxxx̝;GJJږ` b ?@6oތ*--p455]\\ 7 CBCCccc{B'N\`DByr\ÉD"dee} Æ [~=Bv|D  5̈ܰaC֭xbNNNff&`0XڵkY,ҥK痢ٳ׶{{_~f_pҥKv5'555;;;''g׮]|>^jc׮]fffӦM{Aϻkjhh>y򤽽@Oqx>O<`0X,ȑ#w\.W[[{֬Y}6""b޽r߾}'`hhxjdddW_K C~'ŋx&00ѣGG166nhhwzϻ$%%ݸqѣGD"QUU_^^Й|& .]]]7o޴TQQdZZ{}ׯ_wttvttPԞGꨆG999W#^ o1@XjcY|>_AA!++ [}:| ˗CǑ}'ŋVVVǏd2mmmǎ[\\mPT-~3|o BPXTTe$ wuZGGC 2dʕGA:u|ҤI؊޺ukQQQGGGjj*}͙3'66!rUUUsrrCCC/^X^^yfooo숶k֬9qDNN'O~ܹww(999x]'`cƌsNKK]eeP(x<߀NB,Ydׯǖsy .1L"BBB,Y vZe˖9sdee PNNNGGGzz:V۝;w(N|||IIIhhoQQ~еkzyyݹs޾}&px {jsuurL&6lؽ{wqqիW[> ֲe |K.Ŷ;VQQm۶ŋ>~ʕ%%%B+`ggӞ$iӦ]z>++d2&&&׮]!N>}ݺIddd"H4vX!kkkg@<==8ٳ˗w9lذb 榦[EEg h,իwﮨ BjjjXJz >>sذax5|ƍ7n8))~iʕG B+Bm6l(//7771cƥK̙SUU:,}ժUÇ7o^wU)))D^'zΝ پ}DcbK+\.BqwwoX]]]-ZtܹSyϗ@ K"VvhyyK.iiiijj/Ͽ~IIѣGtuu߿d,7!!A^^_ cȐ!_F»w?!֮]^wΜ9s/^4iBh6loo#L&~߾}X]xqٲe0BH]]ڵk˖-ۻw}W\\rMMM*..NHHp8ZZZ|Ͳe BFedddddܹ366mƍúQF455566&%%=zACC믿V-JvnTVVV:tdbK?رR+22EEE4m ,wʊ]jU=|={NJJ |z=ii 6?@( @IH 7:;;Yl6UpXLQQQDD\ZZrrȑ#BO>]|^HHF{Mqq1BhҥK)))XXm,+22288ĄJ\JJJ^^PWWEYYرcϟ? i&.^WWv9Xeeeڷo_HHkע t:RXXcpppSSStt@ 055+''۷/_qqqba[x… drbb"~amɓ'ceB!KaRR#?3rI<ٹdeWv*1b޽{KKKy~H$:::aߞ<==;_莔uYP~@ L2LgϞ|rUU>W̫W𠥇6{2H$#Gl[[%z,*EG==*H$z%K/IgSٳdGśgw/ }8Hm۶ǏvonnM|>?%%ܹsx"6 Bb ByzPΝ;deeuuuզ G-++ї6bbbh4gbK% ,liir' ON_pae\ ֝?>rbG|^礲RIIIVVAUUKD***l6BRTP(\@DЁ@ԋյΞ=ѣ{]yxx̝;\))~Դs`Faa4Fm޼!TZZz…hjjױ)JKKxbKK?Á{_!njq޴3;i$;;˗/*++߹sgƌϟokkkmm566.))~֮%eee ~~~ЍtMZZL&s8**ttt޼yC$D""HUSS͛7Ё|9GPyyB ::: ˵rgvcP[D"#fdee5uذaׯP(r, @@իWKJJJCC ޱqz__;w>}t&&&~-źwͮuVuuoVV6ݿ*@ kA"FQUU%++{%EII [nCH$Rxx7|Cl[oܹO>EY!vZ??Kzyyijj"\3gFMPLLLzms=𰷷_Əyҥ^h|DDԩS Dbff&ϷcVXzy544l߾]ZZ]ecc>|6]VSS###3dȐ$|~uuSN9::VVVBHIIYYY5Ǫ|MZ#~K-Nj"MG LMME"bkk+<7y f^*3|'O&&&2 - 255MNNrڳf²ݏ=Ңk{"""+,--ݜMMMM544<{luu5D222_JK<صkW||#G455{ 󥧧7m42M >c| ,j2../񼽽e˖}骪?ݰoQOdZU>+Vt{MKKK^KA߷gc:ѣGNNNȫW~>YjճgɌUUU[l}ӧrXG%>yٷI /> -iii9p>~3@ꗋQ$|06+2v)|Ҹ2K#*ʊ >uYƿ0޽{'NxE[[ȑ#̙y.]t)99JﹹO0mgϞd++ ###жm۰PBؽgΜAOѢ/^|QKKKٳgzҤG544hhh|N111;w-..vss۸q#B8...//嚚uH$/;֌(#9H$d[;;QFN2e F(y5kٳ=!!֭:t(K. H$Bnn. JKKs1L"4...ǎ{yRRlbbrBEEEFFFrrriii#G I{ j qGqPHHHCCCLLLLL F9s&>s\\CBcƌqss;qDhhBHCCCGG+///O$d._\(yxxlYYY&iff&++rpppppv1bĢEJJJD.jkk`0eddBcǎLJJ]mmmkk+J(˗===YYYk˖y}$qRRRrrr\.t깫2+LW@.ʒ$E:~꿗=/>¥K)ΜHnEK}}{8OTgG n - XUgx(@̃'xh4ڑ#G>|xƍK.,[.^BZZZVVVyyy}oÇ\nYYYkk%K t:ɜ={6V={UUUl6K| IIIY[[x<&9|,:BDGGǴ4x  Օ_zE B|KK DRRRjllR|>bX,eD" --nooGihh?\JJ 6eee>_SSfd2BiiirXI>/\.Lp8I$BgdjjJpWC%eammnice%%,k?㰬 u]`@@BZD]]cÿ5f4>3H$K[F":Bz1)1nÇG577ǻ|P]&© \.Çϟ?711QUUd2ZZZ *qѣG677utJJJ⿎s@(k`0lذڇ >bl#%%U__OP^zennc,K$t9PTZl?T__ʹTWW`jj3X[[5OgϰRRR&&&EEEC-))?|X8p/^<5zBHUEeUT\""F .%%5z;w6p5HRSS::k i?a&%%3fzԔH$K|*L_+++> gkkI&njX`}aaabc<<<Ν /PmmmGG@xH$RRR PH ttt^~gX,P___{bK#޼y}5DKb`b1,..P(jjjLH( EWob?]L@Kwϒ\.7hҍpy\׬^OYb<W >ݵ{{J {Ʀfѣ7 Ҕ8Ыob8}6_gײMufiiC45Euw,PGcF^.NϜym?u^}Cc;k4-6errYYA=)|rrFwG3 wm#H#F )2w1fx/*s*B177Zz5&wssX +++x fAwrrrT*!$8WVVV'EPlllN,*f8~kOѤ@,+qhm@=]J&Ma>="1.($$ ݺs}xݾ{oiQ.^ZΤw!|*xw?1;;?p8xB۷'Mtz@]]}cHP!|H}>v`G3PS#Iz0 3OewY>>>NqFzz͛ &`ګV yfFFիTŋ;=s̓'OD[['Op8ʕ{{_~f_p@g֭xbNNNff&`00H`X0"cEbx;{.0@fSȺ͛6>+]?ν{]kimtJ eeeMo[w+||fNj<̈JvW#a M-w̖8X;[>BPsKKƲ溻0PW_௪yFDY[ ,Gξ? ?J]]iS>y]snY>.@OzTMMM/_͛Ν%Wr FbbbDDD (NNNGmii@/dffMSM}-<@BEDDݻW XZZ۷׷3>|ɓ' 6{ȑ0`sP__ڊmST ܌md]]AS\8/.nm7^~#|W9g2׋X_ `x%뜎 Wm.>@}cXx|~fcwZU5C>mjkܺ7Ӧ\Cw%D">׶@ x^T4āBٹŋ͛XmgϗzЪFEE۷;a,Y UCћ22> (RL&t%{cWExKHăf 3' ZͦP(ͮnoo1_mddH~s7w&MjfV}Cy?&$jiҾ=D(\'B鲤 )Q6hG4l:L&Op:ЏFYF;z(sngOH&kUGyHmSd-M6BHMM-ߜg>().EbX^Y]ca߳gGG]=C!am%ПR8y򤃃<_&52ꬬa%D"ӿp8;Àx$5BOgR|!O4-\OIN#6}[*F]Mu]HJnXp|†@06fodBLt  ǧZK0;xL&ww7o+8lN\0OjEqGX} س-kWسo uӦJIz>~?#PUu L0r۷O0snjj޽{ߵDruu?A(77ɓ'K.wOPbbb+PXXx2lhh0w\| W@HKKC?| ֦&"/uttD"QEEJ{{P({ T*]:::|>6Rgش***}?'''kWJ.^@رĸaa%C֮<āBCH_~{_`ѝO%%72%l*BixGl[MM-fO"|&޼60<=,?xm\%Eys>3``$f$#Ν;͛}vlQm4;^^^@H]fq\Xby<^yy7odreeѣB؏EEEx.J}WH$kkkcXoH CԳ7g͘Opt VWWvڸq-[VZZ]1`nnf[ZM{R\\D}||geeyxxsfee[ڲe fŊ!!!vRRK111SLYd NGphlϟt777n Ο??{TWW.]Ֆe߿?99bL>!TYY>eʔqM>=$$fw3gٳgݻb堝=<'NP(<==>>>t:}„ ׯ/++hӧ Gq.(bji7,/_"^zU]]-[MMMkkkcc#UŋMMMohhE־x񢢢V$FMM ϯr;ﰦ$HZW (Um.XFqn T[! "CHIަ!yxx=='95^ ﮹A$cӧϟ? QcccAAH$jjjOѣG lll|%Hlooϟ?lmm(C^^JtÇ>Y,~kk+,F&\.N%ri4vNŃ-)uЈ^[3I$RddQ֬Y$X}}2|W^^khhnjj (**Znݔ)SBCC[ZZa֛p"##WZ5b>k~z ?~|ݺu {`^[p8ѡ111Ǐ_tP(|pT\rrrAQQ`D"/^K±,qGa2Jupp A\\1o=#!K>gb1LAT.~gӊW޹gVVVppڵkL".xyy͙3UTT4w\|;HtttΆ϶.Y™ 2Y[[3e2P(qc555555|4445* ^CCTQI$҈#RRR:::lmmşg/644Kuu5 )ۅ ⏫QFZiUO8?_tzIIֶ*..5;;ְV !>\.L&s\uuuP(//.h4&ӆD")))Y%%%]͠hI@tJ4+nO7kt7TWWxB @M HKK r8::~:3/Q>RKSRK]LkkQH;B >ny}e~H ðM6߿?>>o[jkk>|ѣӦMkkkǏK Bܜf|="5 @ BQQQgd\ח$H$XW*111 [|N\\ɓ'---Y,:s+4MQQ^\KMM\xɓp-8n4(5Ϝ9# ad2Y« W >Ikq{BkkWp{S^KK@WWWWW`:ǿy+W;ܬbhhh``aXwk]|>ҎO E` R[[ٳSSS0&&&Ћ_|;ydwLP0 Ev{{}2OO])o5 uÆ ӧO޽[KKY؅ <==d@l#666njkkD1cwgD W)M|ǂIA2ħ FozBFs7޽#Z!@  LR+VXvmvvyllln߾bŊ~ ¨Q~7???{qMMСCa_|MRUU7"7WOSk 'kW\yĉJ  0'G8jҷ;>>>׮]۾}֭[~ M)((HblB``+Μ9v丸8fjj/Tپ}{bbիVZu CFDD$&&fff0}XFoimɮl6[SSرcYYY/_$H111cǎ^1<<<**W(3&::׷s` ȑ#ǏonnP(C9sb%''H$kkk&>}0mmSiY@ M!}# P(xWErrtq1cƨZ2;;mu677߿o_߿*++d@|2<~z# }&7G133KHHVE > %@ HAB @  8p9%_:@ |MTTQjkk,Y(uM6/\|KޝHCw|>jjjjjjbX, @]B6m"HAzOx{{޽;))I$u=vؒ%K*++͛e˖`vՁ 6 )Hlnnkmm:;;l6jkkp8B ݻw1 BS@|L ;wժU#FPTT!%Ѽ!B}4(777<<|QQQÇ 6l/?b 99L&[YY1LCCC{…={3 OOOOOO[__wޢ6zh˖- G ƅ `;[npqqYfMeeeZZ555'LH`iiif.bܹ{wR{hQwRvv6w1h zzz[nuwwد\Q(DSS_M1@$D5jTPPК5kVVV=պymll"""\nRR#G':::44 777&&F__kA~ƍ]]]K. Ν̄RDFFW/ЂT__쬪Z[[o߾4r$ ._&@  ut;v+**1 zu`իWÃŋݼy)HĀV fffd2ٳgPhooёQ>!!a{&ѣGddd|>Æ fff//g?^ <~xƍP4H$J 5[[[<[YY9r޼yO<122.gOb(++Kt'C0@ |>ŋ򺺺# %%%EEExQgg'G?_~ɓ4]@W׮];eʔ>~ 𴵵2T*%==D1bDJJJGG-'䬭SAVVŋj RObHP0@ #<oŊcǎ%zPĒ?8o߾ m۶f͚{ωo@p8;;;WWWcccw5a6mڿ||<h4%%jD" D JTbܤccccbb wO}H<6N<liib:;;V!FwH0ӣ0Js\@o\.0---|_f% |ƧJAAA{߀(**jjjR5D[[ٳSSSųlmmoܸfnCD"I{n---gg>}OOO///xZRR&? @|qdr{{;UWW 򝝝#>MBBB"h߾}/ڵf'%% yZv- Z ѣ Eܥ8@;uĉΝ;׿F$]3nܸOx<4\:{G 7n$_G-YÇC Oiii?^a"% ~ΝkffvÇh4ss(....999<O"ĉՖrrr׮]|7^`2hOAKS rfl߾h~Aj-"~h.!UQQ~K2Đ]O!Nxbffĉªnܸf7:L$\N ׻^xW~waد:l0%k׮~o^x<_~zz:RǛ8@ EAB -ѣWYf{KU(ʄ O`}}իWG ximmmDDݻ'LMMw*++_|yǎ-Oyyyjjj'OԼzzmm̙39NIIӧݛ]]M8ĉT*uNz ć@ 5/^trr쬮~ʕ+=yѣGϟollHaNNN]]ɓ'E"QAA+W6cccoݺeiiyׯ_߼yΝ;}999Bɓl8*%%MMM/^<}4L~䉏OkkkjjjCCí[^|a4Ipy>z}޼yx[V^wqq)**Yt_xekk+ x?| ҁ~k@w:ߞ9sF^^~C^^СC666IIIhDY!Ctvv&''4q֭ΰbAAAffÆ \]]qP(jrƙˍ7-Z4qD:9ðׯh4HaoXXBsrrfΜdɒ+WHUVh.]p…$+11,HAAaȑO>3gg .Yd͓&MZϞ=koo0553gΧ-00BÇ߹sUII? _-Z-6@ oFMM3gZ[[^|Iӡbƌ~իO5k?^PP%!ڄBkײ1 c0VܴiԎ͛?ƦzxxH8`YzիhGR)VTTO񔔔V1cH$P(!!!_|ŦM`nUUZ*88X(Bx.tI#[b{!Μ9|r 6m4gΜk׮}бcǖ,YRYY9o޼-[hWwfoEȷ@)aaaӧOroCL$ҡ%B*85k،7n߾}{pٳg{yyFGG^_"G>F23ZNNpC"HMMMnjm6 Du)G@|n|0' [n ݼyC ><11HK[pJ111'O.^X @ :::7oR!a{.a-7L6{ӧo۶ SA 䒙|"4/DW&@ 3hРŋGEE >s8ccc\;III<O[[{֬Y/Yɥd2ʊd;bcc/\?WUUyyy/:HHH(..&&&L&HDiiionnԜ0aB`` F(22rϞ= XWW/c8@&7l؀kGq秽Y$;w ѓCjzwͧ;,ZH(krmr 겯fAGc}).~'|K 7|~'BnI$RddQ֬YXXXꫯ DǏ/]TOO/44`TTT7o._&""&%%9rֶk׮M6 6~PPPA}}} ÕMMM]__쬪Z[[o߾4É 500͍?~<hݺuVjmmݵkP(411:?VVV2\:$YtP(x/^˻}vLL j)~ " ={ֶFM]i ґY;zBMCs@533#Ϟ=p+7n̙3{ mmmvw^ho=zKFFZz`ُ?NNNvqqSUUMLL{{{t[YY9r޼yO<122{~6l033xyy={6''*H111Dߓoޮ#czrO(++h4"(޾I9r$ܽ{`p[Mkѝ/OwjSRRrww#wW^^kii.ZZZf| @єpϧrOHmI 3f̸~u@|;@ 8|pԧtƒ 7_o޼%N# 544F  mmmgϮOMMUWWQREEeƌ%%%&&&rrr0 t:H$655'655A-T[lGSSssssww.\%%%}2Bi@l6NZƍl6[6 evibbRVVvQ| gܹ_~%K>ٓ NT܉ D ),,Fw׎H8eeeuuu bee/láP(B444ܹsZXnn.~3h  bccsm]r x>D"_~֬YRsttt\7rrr&MXbߢEϟU[[[^^}3L&rSRRT޲Bbb"Á^\~z.$$]KKb=~|JݩS&Nwܹ}ٲe͛7oa244tΝ͛1cN[[[aaa~~]2dGZZZR(#FȞÇߺu+11QYYd޾};<<ݛBxoSȖ-[lق&!?mrMOsvF@ w$ƈr˗/?~իWaȐ! ,&&&鉉v%''H$kkk&; RTTTtttEEjHH+266>p@rrr\\QSS355iYxxxTTP(3fLttoncc}Ĕ-- Ps533;|Ç[[[i4yTTte0ydWWT6yPVVh"+++L޾}]֭[׽)tk!E h5߇ܾsǭϝ<e?QSŗ!>he^ee%?ݯ$33XNNÇ޲ ?~Xj7Bv#qqqpi{^EEEQQ_Zbx< p6JԬSVV&?STTڵk###{jA^^^MM ȑ#fff c ׆ot(D >b;3@ vyy6M&2VH$r8TWW؈aF-~XW|#YNJ}oreӡ߇0MML|>?!5?]'.].O!o߼ ]QĻ@ P__]577,˗<˗?jlldX mmmqg Bn3 D"arrr^x@x4C}I$}}s(cf\'s3eX1&6UFJϟ'š2"Ň 8p}v>r@~ATUU_z A 16cW(++cF MMͶ6/<<ߊa?V <11W.\EruuŽ~Epct"T?/?B.`0 ]?;[xYqӎ?*-[4Fw•7f}3 )HA憇/^8**j0KC$''d+++&)u;ƍ<,[NܹsΝGą $z ܳgOyy9:LÑ*l|֭...k֬LKK~ss ^j#b>obbd2ǎ TWW ￯^a9΁ @ }]mmG!%KF9@#{L&Or QRgZ܎)d\_c--+<0s3S@X $D5jTPPК5kCn޼|r.{ȑ>FG,]T(;w.33H k/':::44 777&&F__1p8V1b:;;۷,--F}}} ÕӡSTT~z''իWx<ĉá0555)@ tttttt< >S& [;9!uSӨQ {v×K.8HCgT^6R^#OVAgϞX1nܸ3gB !!a{{^G⒑i4Hk/|>Æ fff//gHUd '1|~XX-F9o޼'OIm$..NUU511ONKK$%%1gddDkFFʕ+NRTT݂@ llF:TD"M _iDI"s䲔]"K'++kڴiV) #%%ȑ#˗/755t钿}PRR2uT#Uqq[/PTA&c8=!''gmm-"><|ggC =***rrr£DGGǻw0 {4 >~/¦Ξ=;}"P=@|Шw_zսسgϞ>}kUUUVVVVUUH{GzzCZ0 ۴i H8d2]]]H$p444*++ߢ`mmm+#FEEEbR\\ɓ'---Y,_gggO ǏBFc|>_µɓ'̙sҥ9s[@ \.W c#vuuUWWC*Ԭ466vttdBR;;; P(dXwEUU 6WY"t:&H BH$UNE?o'vyo$0~O~`m0̘1ĄH$655hjji)t:Wtz{ySćciiZ.\%%%2 wnnns)xx@ssk-77e˖=|ɓU(((455)))x< 0lĈOrHq{ǫf/jJ#no*@ >j#4 p={& NP`ņ;wtb/_ dKKKUU‚Bdy^zEpd!U| P(666o^bEwҥK~~~0ɓ'ϟ?_egee5|𸸸͛7;@ 5 Nvtt Ikk+ s-<"H$*ZSS<-- W;:USS_֊WAڑ'5a6VW<.W$JHnjxOY\(t! j4ite,H$if͒䤣roܸ3i$===?d2\.7%%Jtogԩojj*GZZZR(#F{/"{8`vvvN8qv^^޹s to$$$]KKb=~|rw}b444$EFF*++O:6Nka.D__*E9|* j:Wou<%''/ n[ˡGP `T? $G+W^|^"C X`̵KNN'HL&SCFDD$&&fffp@rrr\\QSS355Wl۶-))iʕzzzL&3##Cb_~9sL@ &"aۑg^@/Xفarحfc0L|c@#-ݣR EEEhN>s^~8o<<̙3?Ӊ' >lB|Aee<ρǏ[ޔPSCCC 9\6 jjjﮋ#G%$$H]쯩. DhjG&ϑPTT1c}ً/'Na#@AX,6-:v@|`mG DzY,uTT<::b"b //oI;PD G@DFA:p!> eΝ=/hx3I$K;~u(|m_s|vɒ%7o4iRcǎEEEc"8hР1c 2/߿ի P(7{…\VZuݜ _}M< `Ld8lܸQF-[dXy{{޽tҥR=[`D>x ++K;555C}Hv9s+W]$fΜ@ CCC@PUUe``GzEyjj^dKQnyfeeA訢r9 zީW7қ,2?k"UŋGEE >@ 7n:x ^`ٲet:H,???11NWW_3D9&s۳O[5WS\QD@ރ*Tyb)HYYYk׮2ex֭[1 {ѣGSRRNʗ=|p…CQFTJGkhhӶ fgg߽{wEEERW@|֗,+ᆆ_D7GUlmlP_ 7iz) XD"QN<K$ u͔WU?w t4Ͽzɓ.:;;O>3X" c'6[ӏ@A0lӦMwl_L6-55uf|MMMDSq$$Jv/cikkD#dqձcZXXo?w\``)ԩSkkkǏB!mnkkݻWVV6buu1cikk777ؠ @  eܻMDB99Ҳe=zÄ"~INn~2_OJWIQT_s/ʧφsX -CBaՕ獂W_34z}y.Iتtwuk^Ii?詅>̹fL{ehs9Ι= =ڊbZӧϜ<_SO8~|X R[[ٳSSS{U0tB􄲲2BaZZ=,L؂XӉDbSSxbSSh4\cccOhuر7Cu`7ŋK.͝8qFD777www~yyyZZZd2y)@ ψ-DÇGdn\ޯXP 031yQ[ wxwvuӖĴ!"x׼իttt>W"t RUU%0jԨJXRSW0P$joo;>pgysG[+)QMu66 3*+\-f]mS }ߋZmm-1e}{;%EK1^4l+'e0&SeLrʑa߇5CKO.~bq;w~}wz})((Wg;vFFFe:thDDDbbbffɓ'{f퉉)))ZZZ ,蟂dccm۶+W1̌ KdE;;pdmmd2o~'&&ڵ<_F,--ߋ2ܽӧM&c18; :ҕ+W$@|v`oR`nEǥeS& h4 K ^H PT%^.P(a Hr$yy*'MHwS&c"Lv/n@MG\[2eС6EBH$turYbyشBG9fh hV6[@G{DRRPacbJZDnfifϖޮVB#pWg ($-:QdkGprr_ǾxTcԩS̙3Gj-ݾ}W_}W_ӧOMֿHHhooooo/CcٵKJn -,,qF$1008Æ cA@ ga},Ix<ޔxʍ[uu3O6X8gs% 0-,Bc 0k1V=s݇)TtЫ<do  "G={jdZq )d9y WFF2u~wXTeWA4b/`$`~#MĨ%Q(V.#4˲l{w,EA3gw9{μ3oL<6s[CF(Hihx(HHrzpY7Ur<|6$I@ O_p87U/s;gU"g39/|~qIiaQ ا_~B=i *J5u"N͝q䷒֣Q'lƍCù8OI 9,>Rijip87:ŊrCʽe \Jq77豢⒖ Cw9ߚ;k&߳oqiYcN5fOy(btmގC"}c?rW-Y܇~&>JzeDbCCÁh4mxxF@ ,z<  E2lܗy5*)- 5JO*r >˖X&8?yCS+˓Q"Bz,w bw7o:уvڔ)[wS$?5gFCN$])=&-re~׊S8m,Lm\p&8:؃HmㆣQwKgϜd?tF|WA';^kjl~+K30%Adk -EϟoxW&ɦFF>C]%ĉH}bcc'O7Ґ111 _k׮-..s};9 (**277 |.S(I ŋ-,,?.w|G[H~-ӧY[Y oR_?[L!S sGK"SH$ E]]@!It"B$|n57ڟ>h<E2 jB )T6)>bJBQhx>><<|&:::g%K+W!O>{Ǐ?j{nݚ,6=k֬3fݻ@ @~ m}(˗Փ6%UH vty|nˆ8HY艝 JEE&6b29Aj}ĒX.HfwHVdžwbRuHH_oHITFF3u[,H$nhNFMgf?sRr3h*vއ...j#{ΝZZZ?}tgg֭[/ c$UUUCCÏX77G=ykXA4j@ HH={ٳ}+DJ]LB푁Qaz}n~+1M--Nc+  k+--;5ԅ#$[[/Yd۶mSRR|Ξ=$Yp… ?vco߾-& %&&W&@K'9FSSQCwuťe>`wq)_µ45/\6wVU 5UJ (*S&Ox rHII0aªU**,--lv{{; wo֬Ym6ȑ#fzʕ+'N.:t̙3,n޼y>} > W^]`EmݺeĉW~&Hٳg?{ ͝7o ˗/۷vvvO>w6@ ?4^TUd;{*mܾ챒h*3XNԃ\y`K@lkP _C̷DUl6NKK ;-=rweaa ['N/06_p:f̘ٳg'''_v X knnVSSC$22REEĉ 8::z{{>}:""Bjdd9';;_(zxxűlmaa!/@ O̮]!)/C8@?\|yÆ ;v:u*6h"93R@:˙L&;8GVUUUUUkll H}}^t)aNNN ezرoTUUܹS2Z9o\.͛7L&sŊ yyy'N^`! xP(1P() D{={6** X߯r…K.YZZΙ3GlOD"W3v` +/a=H$A@nL&h@ Bܹsn߾H&gΜ)ǜ\n~~~IIڸq㲳utt @ ȧJs:X4E 䳆AU d2,XPWWw)&b7a„%K9rŅJd1-rO@(xb9hii988ܹs?%%Yv<9dee)55U[[D";TUU1L {EcciZcCF@8B郆 HAAAQQQAvL*iӦ;v$$$xyyꦧ JGGGBd2w,6d;;M6m׮][kkkrp666/^BPVVVT*9DQQH$D"HrI$Fp88N(***8N3L*{@d2d2&t:`hMMP(@dpdlq8ܰaäs"(+KgpE%6dH!Xmu5oh# ڴiG>̙3cbb|||"""qK.Y[[dSSb~~~~~~/nkk+**Bdƍ%:u*Nx񢚚ĉ}XXǰN @ gD}}*FԴа\ 5b"N蔗#YAAD$Y,+lffV\\MMM 5$wU,A #ꠝAZ~},pM6ݼy#44ĉqqqzzz~~~W^3 :u]SS3))?5jTlllLLLdd$x|ָP(3f̸qƜ9sd,/38hdaaAsz<@ eee>`0X,xwމD"lyB!L!UUUGQQá$G$^ho߾Kt%5E%H c}[CS 4C]@ C /k{zz9 }}}Ԩl:::㱶p ".>}&@Ēr### /EvhLP{ *57M]V%L3t/^8~ԫ= " D*@># Kɓ''OUmmmMOO/))GJ*IFĤp8D2+R+L+@ųgϮ_~>}bBCCA"s\WWWgll,F뀃H@4ܻwG*]vΰ\X.,W;yd###@ d˖-SLٱcЯjIII||={AB۷|>$1I3>LI˅rspիW۷oʔ)Wg*6z9sL6m@DO>}Ǐ.O+WJuּd1l6{֬Y3fػwgd7L>?8Od!!EUUUAraWR1'AS>|pqqm;wjiixGر_CVVV|||wۣGǎ[__tvvՑH$`ROAAA(JF \vL& L& EAA/?~ A"D"L&JJJ>|(Ν+VթϷ~; *j<A ?|8DVVVVVVCr83f0X Z~/"sfffaaMiiQHHNOHH8s *0_u޽ UPPXhX/^ظq]hhhgggttŋuuuBBBПYVV/YdŊΝ;ׯ_=gϞh Xn۶mȑ)))'Noߎ=&3nnn)))K,!III"Hy(5133c0YYY.ʢP(l!7ܼyB8pӧJJJ ?vttĆᄒ555+J Çꊉprrڿ3@Œɓ'ڵk…W^Bh )?Xqx<8G$Jp8T/\ x}C:;;h4IVTThB@\PB,,,H$ReehLJTQQ9qXwqtt>}tDD*o߾}̘1,X(&&]L@?~c@رcϝ;.\xܹ-[h4A]FfϞ Ҳ_@={vrrk#,,Xa.k. A<==oݺ{b}^BY`ƾe5o<<<{,%%mIMM}ⅽJ7Ͽs@B}… s郬_YY9~!kr7˗7lذcǎSʎ F xK)>899%$$`E &\rv;(RMnn.7ߜ/U^6---@1Zwޖ( D㻋/ _zOsL(c2 lxaa!Oeee:CC秦Jj63Yl^FMNev|!|>޽{$ۛl;;;ȼ<3AL N:%AǏdsss<=<</^,#ka0x< Ԅ9<<<֬YWZ[[MR+Oܹ,tU5111QQQ*))"Sjj6D;v,|A 5 U&.)H"gʕ]NڰϢjhmmpA#`#ə DNXSp8n  [ZZlllP(8cժ*0!H}-ϩTECCCvdK0tuuDxVVVHːUdPYYy[Ep"ӧpPZZJ$ϟ?}T*f,..۠ HAAAQQQrZrJffxvlڴIFJJ Hrr12liin:P/_qlll###sssF H.nۮ]~1{ yEee%N @QH@ bN<)krF$$(cNSSemll@VT*NK깸d<] 11qذayFr>>I&L{'Op[[[/'  i^ dff1ܼM__@ ;~ѽi=ޑ,BQSS333 6mS8jԨؘHjnnUSPP?x`YY͛zJ?~|dddLLLHHH  >}zXX[Xa,\ԩS횚b~ϲ3fܸqcΜ92z 8hdaa4a#x ,,|5k(555'''""B( °0WAP/FXITUUݼy HHp|>BH$p`( A섵c5l.۫cK`b4h8BRFBWW߼y#wI'Oj#w;WH/Muuuuu}EEFGGǍ7Ə?vج/_QWWG bccq8ܜ9sV())ioooooՕݻw\.BcX|~ZZW_}bi4Z]]0>|0### ɖ,Yȑ#8 #չs$}}}}}}ѯTwwQ^Lڼy͛!n~3f A K憍ッ{ݻw޽&:CCC}|F>JKKQF---gQ}}}KKKyyyqq1+ԋ7͛7#44v2d=Z)@l6ĄD"G /_@ <g8p$eeeips`鹺^vfL<Acy FYAA|{ggݻwjy=ZQQS/p!x<˗g͚EP]wJ⽛[yy_|iiilٲ|555t o/^[tiv !%wޝ8qjC gѵkװ~Ϣh@lٲ{"z1s 7 *2Ptttc 8g#Smmm%okkk6MMM) t=x^jll|Yccȑ#׬Y"VrrrrrT^IyK$B!0)5Ç뜜OcO6߿ﭬ# `]AAaĉB>|m1Eѝ1 ~ܸqC,T?P@3o2(>._k&aAdWF׋]zkkkhH Xg="CFI3b Rwi[ϟ?dwMև ݻgii 999IMm1OGϞ=KKK;p@ !zR(~?555 T[AJJJRRR444FᒓdrsssoRCuuu+Æ άbcc'OlddXs|^`w{5}#r-I{;WV N5777???9H5?hoAooÇK޵#GeXYYYAAAn?t$UUUCCÏQgo@ OwsP=)O0oEkjj[hvvveԴ}˃JӌD"N:N苢΀Or:.6AO vK,ٶm۾}^pqq_ЛoYjTQg…Rm@ lPruu"@zk̺55I`QhhhZ*<<ibccI$Ү]DvA#GUVV#gddH$@T鰮رcL&x駟tEGGr8Z AݻwWUU?ؚ5k ơC:t%修O.Um ;zhiiֲe˖-[f][[v+W#GHg&zIw.?~<77嚙'h?CTTTUU ݕ$6"4mԩb!NYYF577 mmmGYY,`q\*E$|q0 ˅rrhN$¬֯_MĬ,&DX,VXX֭[MMMڋ/6nhgg{Euǎ\.7((HCCÇϟ?݅o۶MKK ۷oŁQTm9xmFa``|dggO6m;1~Ek"CJKK}}}BBBtzBBB@@3gA&믿ݻ޽{ -.9s@ 2P(L&xVRpSSgXD"VYY<=455aBt˅rfC$Ds􎎎94V㺺ǎ'cǎuww?w\PP/**ڽ{7z |.AG2SUIIIQQc/"ٖ]vYXX y֭d DGG&&&-1)~E=DFDFF8q\rtt>}tDDo-X(&&]$GP! Lf"DBP$F!8\7o=-@ ._aÆ;vL:UTkԏ._}"B$MMMO >~wKKKؓD{={lTT:VTTFPVVھc2BP̻zEE|ȑ3gDDDhiiy{{{{{wbB1' \.WGwf@zHFMdtqqqXwk3NcE)++#(ՠ؈9\@ 2H.nrssͱ!G HL&suuuN?]~O 755a\A--]v!RQQqƍÇkkkϘ1Cj3@xԲd@ ttt0"%%%]ܬ(5~뱋d]9ŋkJOw؈\xQQQ@0"+@p)((#**JҺ=z~jA|>z_LhLKK[nHR__Kwww[lrJEE'XMrr5k$-ꦧnTUUJ&^XfYZZ޿};-M.ڽuLٴi c)))_50"/_nnn"'s΅ׯ_'&&z;v!@ _D$ϟ/m::l0&믿vڵk/^yI*|rABBB̙c``SSS|Cwlڴoʕ>>>555̙3cbb|||"""錌\Kddw߭[.((ݽydtQ͛7-^X[[A7 'N`XݣG&9b#" @3gCH$ڿ?8oe 8vC!H~i}.]… .\hmmUTT }T!~3-8pD" Yj@@Pz Jw3 alo6~xsh4WWW38,tVRd,lH$`bwd23Ϩo$)$$Dv?'=%3ɩf L&t( }~Ćh4[[pyA !X QHKKroܸx^M QTg,\. !11ښ@ +++uttLf}}bNNꫯkWXXҢlee5ZB<~i>"jjjJJJNZZZƣFemsGE >|XL  >aWW߫˫$ƍrnoos#J500VX' \pVZ%jnnrիW$ TSSz}M2EF~ƍ^^^|9r$)))%%EӧO={V*((Xre8YI|||xx8z=zΜ9ӦM뿅"l/'\rz;`euuuP@j_EPg̘v3gϟ+++O6-,,,'''""ɓ'>|;wnFFFkk+@WWWONNnkkx֭[fxBUUfWTTp8'OTWW?{_C>#^xQXXbcc3FBa^^޳g>|t*JPD"hkkkkk+++KNN666_UUL&##zooo55%KDEE=}Txy{{>|_ꮮ4.i&IwI*z#fee4PY;wjiixGر_3K@>*333]]]s"_!;|*sڵoeeeԄ׷ %㏩W^|ZMMMvv?9T7nx(Ν;2" Hbg Ǔdyag+W?***N^YY)L2nܸ|riDL[rrrgxAMLLtuuD"Qkk+b*--;vܹs6 22ή?xnʊRRRΝ;gaa1k,555OOϊFSSٳgkhh'y9///mmmRrr2Jnx}}ZK& ߿ɒ%۶m۷ogzzzGGǤI>}3''r/\:=tslmmG >{yy]r%44422r<44{GQZZ~_I&ѐ!֭[G`ooOPܹA"˝e===Q%jWWok<==srr3b.G=H$-mы/z!)){ Nj塾fff%}}}W>3F>>|D|Gә3gƎ;c I+;wQUU>}EwN,q8zq~~~cc?4>$МĆ?|TGGACCC[[ۻwVTTΜ9[vqqqMMMׯ.] x<bh4 P(Re  UVc޾}[IIi޽nnnX ߿?**KEGGr8Z M͛ׯ_khh,[lٲe U ;tХKPIZKK ,*++;~xnn.533 R ݻΟ?]f d4JF=q 6Y\]]ݱcDzL&zO?h41bdcc>AcŽ=ZZZld2YSSsԩb) CR ѣ߼y\.D׭[ ^lٿ/pli[l![n6lMLL>Jg ]^>%Ĵj\tAl֫j̙E>|x K@lGQUU7xq8> ܥ]]].\p8wST'''KKˋ/^~ eaEHΏYXX̜97o߿ ȨQx|?uvv?}Fxŋ׭['흝׮]+--_pBP+ ;"fee~u.,KaXaaa[n555mۦU]]]VVp8۷o_p#"" &N@ }v\\ FFF!!!t:=!!! ̙32 UH6Jvr윙YXXhccӷH.<yƍBCC;;;}}}/^eXܶmȑ#SRR#ҥK Hi@eW~A.f:;;t:t-Zwwuu d29++kiii@II S~zVTT}iݺu} ʕ+L\ZZjkk,X`iiQ;rȹsbu@FF1bGwG˗...>| Ba]]Z@\Spmm+V---)))EEEՒ䡱Jف)cccÒ1c`{… ޽322zm^^^ll,,$ IJJ ᏛݻwSSS`](=z(*޶mۤI}رc:;;A:B+ckkJӧOy:f`(;::6o,~nbE'''aK.Q#ؓicƌyaKKeiilll>|_ ]6lرcԩSDkkkAƏ-Vk LFp8I}}}uxK.ENNN ڇa6Jv# A9D"ɓl6^ӊ._]jѱRbZ`Do2ܹs?ݣG%:XLMMMrr2rwwWVVp坝Փ&Mz䉃&X2Ƀ<(B@ 1&A 18}tT"E'j-((A#F@ad2v^ He"k%H. ( ;qP~Ik.޹sk6cYTTjCAA̬W.@{E"۷oQW3њ/_Ç D"޽{Ϟ=gyfŊL&L:5>>۷]eee\bB}C60L>5"c}1`+)t@5ȑ#111gΜXd2B!0ah4܅6:>f *C ^9pӧO]]]QsdAAA,~׮]{eXyyy/^444ܸqӧ|~AVXe˖9s455͚5맟~bX٨3l A`8@C ѣ{ Ht:H&U@ jjj91%FWWW]]ݛ7o444t:Lnii HF'됵k$>|xMoY` 0Ɍ~ӖBwH(jhhVg1::K޽{k֬A'ȃNrr2@խNLLGBauu54j`0Z[[d2,XPWWw)1XoFܹsΝ -"@v {xxH5Bd=!7)ty1L677---PQQqƍÇkkkϘ1`0xN#ss󆆆Lggg333555`WIId2666|>ɓ/,QF={믿͐P(|1l>cƌު7D$ϟc}TFu'!ۜUTT*++[[[)ʨQf444lviiϏ?NPH$҂ jkkHD"188x?~ֶe1E/999yڴiʕ+}||kjjJKKQrbddr/]dmmM&MMM7o77.T23gDEE455EDDxNvRɩb?~ay2BBB5<Īvŋwvv[Xew"E@D"ԨAbǧ(Q!"=FXb &v(U˲}{w߲KQϽs93ܽΜss), bwVEEEׯ_ľ귁AxxxbbرcJӧI 石'GG>}8::j(" Q.ݻѣGݺud|>_GGN8q/~iUUsbGAhl RSSY,y93|;v6 8p 11qǎʪ~gffv%#G$%% آцUuy֭'N OIIyG nñ?y7otclll}ɽzOJJ龾/報 a mhVӒȃz4@vbF. H͛#F3f1c C^ $G@ٳ ) " C^3,++h m:vxKBBBCu.ԍOڼԢ¯`ڴil6~BӶ5557ٗ@NO2%==ƍL&̌b* X߾}[\\+labb2vX{{t׮]^F9rH|_d7oN4jG\.1o߾uqqiܹs>}ɓf3##x@ ())ÇWq~4;Ԧleˈ* oٲ8 T*uڵ*Z6SÇkImZ'3iҤI&3[CHf7f?@$Bw@I#RRR|0V\"y10bĈ!0Ě!%7o58os5v0""t%߽{tȐ!T*U&~К]\\N6Bٳg322矷o>}ӧR~~~h-2&rtt 9uzRB:::*={ 5++4G >t4#2ѯ_?ynK)ٓ'On޼ikkCfb 95IX3nr?766l !}ǹVWW+={bF'ʊDi|b~\6yO %6|,[###ZLQ;r6lX*zzz)}q#G'bCΝ;v}¥w7o(]0`Ŋqd$͛7cǎ 6ݻf֭a,AjUA"ҧ a'(.B( No]]SQ̙qA5'##رc?  ={vk)ɇyqzzӧOg͚ռjܹs/_ՙt5$$ tT|\.uVjjرcꫠ ¥Xyy9ᅌhƌqqq4ipDFP3۷K&&&!섊3`K. h]qkYYYb8//*8Iw w֭={˕yyyDΘ@1?LAnc^$PhhΝ;_x1w܆h?Ν;===.\hddsɴD[>NOO矛 ]p믿Y`.))sIhSOgr訸Z !MD./dddwa BTɿ ,,,""K.ڨI?˲;wM2M"ұcLj5CKKG"t:^>>FLMM/+iqܹ8#mjjzڵ>}̞=;//H?rN_f yevԩ/^믿pONp޼y8//oڵcƌ۷oPPжmp$''0!w8p@ 5áT .\6@ RY #CYre@@@߾}$. 6Çf۷qN8A\M\3g۷/v'Js޽9swРA˗/'.]vذa}5jTddP(ht셌음*t{*aX,oXfZ`hGiƍ_={ BGGGbqr+W??t:Casp<'@ #\~_똘OOψUV(t L```RRC&00аYYY/XX馦gΜy ӉS2ݺuߏ;6l0sssϟ?;wmddyaaaNN̙ 8pk׮}H{{k׮v ;yg7ALL̊+q 82ג%KnZ__7?~Gt]zD"255{nZ#f}f=> j GSEIrLxx8BhĈ)sPt$˗/Buuuuuu 8.N߿|:u\ Nr\.ͦR(^|9n{YEJYUUgnn޳g1c۩wp<ܓ#a&&&K{ MNN$ɺuBSLx+Wnb [{챲ڽ{7"޽q>%ɞ?~z ''˄˕ ɓ-Zz!CBQ6d'O^|իz?~}._"J/^8j(ۗ}޽ƍgϖH$ JҌ/DR p"ֶLnh4___]H$Ϟ=1cacmii㓙휝' we,'֊D"zl(HLX,cۃ۷oW(&mݻwn::: .tLITnذСC 7fXjKJJJekjOIIYhŪ MIcc 7nTWWh/^Cne2ى'N:E$)^"?r즁AC'D ĄhbbB؃%%%8p 66<44444f@j#LfMMMΝBT*U T @ H$jk0oզ]6`͵5 ڭY~}+=]h  *--ݿ?!DPݻȮBiii!b*?_tiSLϞ=kN0a޼yO&FGG1SNT*2@===# |CS|>YYYw$(((PтϻwbƍР~' EDD,0c 77cǎx<Ν;:wu'N؄Wm&˽o>^ uUw&A^㓒tŋocoo7otGG=z e4rǢynnn|>ĤnÆ ;vP(jtttTl}|ӧO?~|ҥYf}v?VV4kG={7o_JKK B( {}x֭ aaa"A>Rk׮]vܺu !?3 KXjnooje˖-[FN!͆eUݻڸRl6[Uo}addm6鵍SXXxq6NR`ԨQxǵݏ_UZZbŊ$WW˗/Ӊ=%77WR>}[bOUKHOO{s׏-.m \\\`P 4(Mo߾=33[n^y #޽{ӓ P(._޻w~ؐ߾}Ϗ C fgg7OA~JaP#Gѱ ~Y?yHJOqtt矛PK:`[R ydL#du޽ƶ}KO>MRCBB ERR;# 5ƣG ӆNڝ;wӲ2##fwdvڕ8h Ν#T(˗/i|* B(44tΝ/^;wdk֬177qFrrr}}+%###C&Cnڴn̙~⑕Jeeeի{cǎR4)(H@@OO/TWWc!DP{䚄Wmm-'Rz衫Kccc})m󨩩pq~|ڴiΝ#` T*uСiLL9aK,BhԩO޺uk||;cr@ƍYYY<O__ѢEǏ[˥Rc a޼y!\ތ ׵Ovuu֭[<|>Ĉ-鯡ʻ$5^v-::z۶m#P(Q(&ݻwgdd|AoiF… 7o7o^XXE򒓓=zTUUeff֯_ :x'[LL̮]'OL򑖖XRRbcc3f'''gϞ=m0D999{Dcǎ={6q5??۶mO<155%ߘVX%T&Lpƍ3g,Z[;nddԫW/r ۷oܹSYYs޷ WIIX,3332d>"BΝ;8\&?~{uuu*~,,,Z熆ؐ/**laC,IOOψUV)--rիWK$(SSӊwJR<ڳgڵk, 444,..>x`VVVrr2A l߾=22ڵk:u۷/B(##c͚5 XbEMM͎;r stt?s… 8>|ܹ慅999DYHr7noLm<7k❒i*g|||T:cǎqƙR4--{ݣJ2;;{„ Br,K(rPȘ1cBo8rʕ+ cȑٳg=zDyͬYT"CDMxbr\.kaa*M6L(:::/_$'D"P( ݻpL&{ JER*}ٳgoߎ!A}||\]]NۥK(H֭[rN2ŋW\FRR}ll,~MԩSSC_&&&!zڵk9x  h>|Hܘ&wJm ;㔔LbL&ٳ'nƦ>33MWW`P(BV( " :RUUUE֊D"zD`0$ B4 ukxhs>zѣNNNÆ 4iH$n rxDk1tPM&xRP*Moofgg('O\hի BN6mqP(]t7hn❒i* jÎS(Ν;?899 flT*RښRWW󫫫y}&M7x`rguByyyϟ߹sE`` nݺlٲ5k|"d.]4y)SgϞi5.`0T)y}T"xyy1L###xDXKY(&&&66h4J?~Et:]݉x8t Xr$ѣGtLN]vرZpuu=z  Ciiitt#:uDR_-eEEEEmݺEӫWg8멩wp޼y ,8pI6n𑧙e˖O8¢KϚ5kڴiQQQ8F5B k,m>4vX2RFjXV.S( ;m6Æ ;*PѤ p¥K^p;q&I۟>^ xM377$&&رC"XYY};FhdB~-BHWW-&&& xt`J8HL&w9 ڵ+ܤ?qDCCçO *jdd4l0xAm䙬,XOOOwK3T!ǫmjmFo:4R{.j-ifdd6K:3_xAXѣG~*T5999R b4lL֊.Ǐwww߳gګq;whR'X0A'B+z$lA[  37VS K $;;XXXT* ?~\PP JsrrB"(// qV9ҿp&իW V"x<:^SS#˱eyyy]]ammRH$:::W,֒ ]]]33-//o,^}}}II F333k\AmwB[[ۊ b 5TX__,jkkL&BB̌`{} >++^&Q7o8::|\ zaLcϙ3gƍ j,ϳgώ?ê*{{O8&'':t͛0@F,;;;?}H(r\{ h*++ܰ윝+]]] p "J\NR)6 nnnF/p<\>/b16NJL&TQcLMMjjj kbX$hJ:sJrT*x<@>Н;wݻWP4?Ϛ5++++$$dƍV駟V\ c|Z?T*B100dk <Ha08~aaamm-V<&YXX(5UVVWUU|kbΎL(3DDboo/qA!N;uDP-^ɱF B P(X,ׯbqeeD"Q[K.؟@K>__M6M4)22rƍ88ѣG7o&Ȏ3f….\hSH$+8d^AUN!8F300  J8WsssS\\A|Ja`0LLL0 U &//+ɐW{KRXADx !kh8!1 !LMM]={m۶>`0 pBCCVu޽/^,^0p*--ݽ{wFFфXz^^^rrGpBwҥM6%$$7gϞ+W˥ORn׋ }=KlQD&˗/BuuuB6B8Syٳjٽ{q>|8**J&=|83>h,!ԿcWWשSǰZO@ppÇ/_={b >| ׮!dldйS61ko),,rwu%6&Ih&ɓ'-Zz!C JJP8p@իd5ٳg3f 'YZZdff"t}B?X:֝Nڲ&&?$uJ s3Bh{.r !t̹̜AGP:תkjV.]lii2xЀ?n~YP`kcr^5Ѻ -7d@AjJrÆ JHH T6 lL&s˗/T O<|tXssPlXz|||JJʢEX,VmmmxxX,&*700h-; %%%$$ƍ!!!0AGGgw1B/_V~:hſ͎ KK$_oٺgŋB77622|#C٪r>U[[fU;iXVGGtU N獵oѵk';ۥ  [~ƃM_3?Yya1W,373;po8O:::f&&::t (H-߿3P(~~~ Jz{{#p8*ZYYIN4_ssu!Ο?sN /]4y)SϞ=Ӧ;&L7oޓ'ORRR4x2ЁY̷?8c)%N Zν{14`H+gN"gڸI$c?k3BhxP_LcGϟwPX,>q:e_BB֎13\¹Ϝ+*.vZah./lvBBY;̘1C"lٲE.ᑖFd.++{.8 0]TD"4m GɽQQطv6+׬;wl<<_~]T*Gb/~&!T\Z&H\󥵱?>E#K!E%JXsڵ+lzzzL&S(:gN]vرjz{{/_|ΝFJ nwh/^xĉd2g̘*--1bDNTe2YϞ=KP(z:{---_e&Lr?3XiãJtռШT.SV*;Ֆ EsG ?8Nvz$\.W*[,0'@Aj"""÷Ƙ2eJnݎ?~ԩ*ѹs1cL0^z'%%EGGt__ŋc?xɓo޼鎎=zjB۶m ۷o ӦSC3f !wiv'}~ K7o:AqE֬i~6Vzzz޹;vrAkk\"+˝_QKԖ}US[x4q,cgkT*yGw/\.bb0Lfe˖Ʈ޽{?ꫯOGoݺA/[lٲej ޺u ! TqssS mwwwWWƮo7_?GG{?8r"Cmmmy>w^X/2hN~؛dia+'7WPzw562߷ﶝjQÿ|zhWmY㺺3. Wƃܜ<߭.fWUVUMÇذnC}|44mgCGGS˗EEEBcV(NtX.uy Bd{vA͙9]oMMgL!;vύX,\89wq>vHò"K:xh=|{#2O?L 6t"׳r\-{mnٛ  @ǀB^… 333uyfsssH+B"3c7|7Ο@CQ 1hGԨ$JRic 0绤utnK"74{V(z# @;Vr9UDLvWu9Qcw| @Vzꥥ!6m2=tܿn="'(HG*jF¯NMAzwލ>|KYnkaS5֪f С$p1>!:v&@{vgw/@Aj1nnnnnn~֬Y0|tL&  !Э[`h 9/vr|۶m: &J  %a8P ; *Cٳgs\|\UUellRrFJ$Q]]mhhHP)qS]}233FgoΝ%:V+XLb!XP>E\)l2( e=bs6l0ӦMC 6MNwrr"#FP[UQQg>ɴot\š맒Ҙpڣ>` IKd#-XM6_yy9yݸL'XP#J$1QgF3fԢo"4Tn6uT(*oNm*U%ڭDCTnm_UmMf`@Av-F('R>߮%CX,VxO3m^n] ( \& Fhrm$JR===|/DLP(tuuutt}vɔ)S(B K۷ioS!b1Bkv ƄD4K^ҭ['O~Ai<[{\AH$UUU)u9+hG5o(**b0^dbdWVVJz@rBaee%LPRimm-B111dL& CCCqe1cƴF5t`,Yfw>*,cϫ ݻw۷gΜBd07I;Q#֮Yx ]vmL>ԩBHWWܜnaaR)H ok:T*G04 Bb @Rk׮ma-j{/[슊?+Pϟd2BỸ}qۼ+ЎJ &-/aپZP__O Enp q _ ҉۵k>r势~.]֬YR\&]$<}͛vJHHXbٳ8bŊ˗l[> 0qDDBZUU5~9s;wYf͕+WΟ?_ ubbbnnnTTTXXXvv6ugddPԜҥKMv֭~i!믿۷/77ש_Vy BXnϜ9o/00P&a_~Wr-+++wwwB–.]*Jׯ_"""rJkkk˷lB }i(GGǸ۷ocGv_~>|D"իׯro6''իǏд++`aÆ 3f OB#GJ۷oYYӧOnjӰfIjEQP[X,|||BSNrfbO Sn ]n؊63 )H=zPkRIB|>h4:t<C8*Y#F;>qY,@ 'vuȐ!cƌ :t(j~~\.YEEo߾]QQ+ YVOO5_efffMꋊrss ~Gq8={><((hȑW^իWZZ?quggk׮%$$h;G!;;[TKR" #88… }x1cRh#phƦA}}fG3r{he-g~SynGcxghhXQQSYYɓǏz([bRWWi>Aħ<q~DB$r@'C.^:JJR(rP(<hdW*ʠ7nH$kkkD뗗tYf:uJOO/ gffn޼ƍ\.dvvvyyyuuuSN=x𠯯oEEň#>|XRRN|Çk)rUtttd<ٳgUrklPegoUZXC@ `)rah4 www|LBL6M姍\J%0q_6V-Bh 4Æ 322?MLL\.wƌ?v옽}|||jkk3a„ׯ?x2s83gj. 3g/;fkkqF[[[q8W111!kkk''o6..Nˆ~Dz2Ә}ʕ+:u4p[PՋFM8qѢEFF*M/66!o߾w 4??_KFmbر .駟,,,~CAcr<(Mc @{?>|?|h/=|x$ICB\N!uuubqåߣI&臘&%%%**㹺>}Z%|ryr֬Y]tQ5&&wttt``aÈKwet:W Ve2/_L\ / ;1cر8}gC񇳳Ib-ZVVVQQQ* BhԩwꫯJӱsqww={6ҪA/3gΓ'O~& _CZdI~Rw ©Ai{o ^FFA#Drm ֪JxlB޼y/!௤AAAj:99؞b``@D A5GlvÇ@;@A1 }}}ԴB*~:BP(;wvtt$Rӻw^ZZZWW~M___B/18:a WctMooo&Y^^NөT*~z{{?ydىD"&يG;GUvʩ;p@ŋYYY.++[v/ MF__i }YZZ ŧŋ7otoVTTߡqt gg޽{~0> 277x<^yyׯ_?Ν;V?pfVSSAi;###իWRѣGC}ĉSRR:w{tuu]БټyԩSmmm,X0o< MJ* d|wÆ  [%,)Vg۶m1& ~zrp=cS(v!GlC~~~{I޽߿rp8ZRId2L&D B,KRS\O%H$"vhbq8*fi4p8FFF\.à2e}h킾}{յ53a Hj"D\KkD׫kIh0&bOD4&&cFD4P@HQ`0 ~sNch ~묽9kjLhhٳgM/-2D"UWWk 'J$%ZKEEŢES` /(*bQT*Jd.BA4NL.d2Z-JM1Ơ]?~+#†z׮]yi'77pH?ŋ/2 EN6\|rdd$ſGFFO8****//MIIIprrz Fo߾@6={Z æO~ r~8j(&)}lmm5RRܲe= Ǘ-[)GFF~QQQoFejΝ;lmm̙Hy]-ZrJ|wϞ= ,0"vddS⬬^- .%%ĉ033Owm;v=yD"wwv?믿?{ 3` EDVVVăL&|u{4dbaLh .y< ( sssC?bx(>NccsrjL&hNC7/ZN}֭[Zh4˱c\jժ(???CR]vڵa7o|,kk={ް4)) ߽rѣGvܹpZz՟`ŕ! ukYx;#w0 Z~1 [n뫷- ?_|&6T͟IL"͛Ϟ={oݺ5,,lFl31}o0`hU@T*U.2Ɔw MJNg坝L&rd!@ :,楥STDwPC r Ş/퍍ħ舉!HqqqK;whlll\\\g?rYlmmmmmQ_x~HHH8ydcc#n߾>pL&ۻw͛7njaؒ%Kt+ڰaXbEzz_eeFFFqq17.H:3zh þǏkݧzȑ[oDO:TYY_憄`v)OOϋ/X僃u}W şѣxCbK>cdl`VSS-z:6Rȑ#+**pPavx??SN)lJg0D "ʪRPH$:!JCBBRŒH$=#2`7J%HQ4_fkkKRU*56F{饗 E|||L)/DDDxyy/6# RI4 EiidD2v؁C@*//?+xxxhMիWO6MǦǏ?~XL0ȫF"DDD9s&77VUU2ښr;;; ÌԮRp0X[b2"JVƏ_VVL/oGgkLL̅ Lfqq^ğ{Cm Rݝmɓ-Z4gΜo}+Kg0~i0`0j(|mQ o#a":i W7tb]T__occP(r9!!!BpN"nO@@qshM/'1 3ez/9hUd2]]$Iss3HC rڵ쌌 ƞ?^o1&immhl6,d~D $%%%$$"ڵk]Cra95ٯu *˫V_BPy &LPPPwڵqF /^v={?>11ш&ETcv3/VU/:K/Z $5&yrH$#Hr`d2 B&R)谰RhIP`fffvJZ677 CVt:WըRoooooo4jhh0aBaa!MLL믝(L&1öD@bBܹsH@0eʔ)S544bI [lfX.\XbroooRYPP`(@s~~~{{{ZZb1ovGk[Də:u[t:^WWgdZcԨQj:77([Έ؎+F6-*++ `:/{ݷo_rrilllzX,z- a8X,Ft-U((ZFǿ`GqsET>wVP%BPtG_}1HNNnkk{^aHSL!|" ʚ1c[X,c__#G_FmذaӦM/RaaZrrr={;99eggO60bĈΣGW^-**z7)6]SSK$ ]vyxxneeo'%%effzyy>fXXX]]=,[,11133mǎnnnzCP.\k6-D"!չ>}Rת5 A kXRXbƍ)))dž C u'۷RkRCO_-20D"T*__߰@gg琐dI(V( –f.с BN/<^Ө}ٳ%%%/_KJJΝ;wy<@nn.omkk#M'5VhC>ܹ1c?4}7޽{7;;}ۺukJJJrrŋ>| gddL8/К+߻wmϟ??c |w^|Џ̬߸q#o.]dCǣHDuDll׍qqqs D^dɒ;wF6-n͚5nnnF#ժsrrt:vˈH$Ϟ={ƍv}!7ӧ~FZd # Z+׭[ BF uJR*ZXX-0]`+<0 \GIFH$&!jTo# b0+V$^5PZZG~'O8;;#DFϟ:;;[[[_~jRIQx~pt[677c]YY) ÷lrر;wh4&VVVtfb~W,StNdddRRҪU*CBB"!!رckkk aXCCv` sD"Y[[KRFѠAA]6U)<f͚eaaPf)..nmmEi1g/LcxqbFÉB7ߘP FLS6332ihÌjL_wkoozҁ~ܹs'55Ec0F $0oSKP rFi yѢE0`RR!G*n=n߾=vX::kkkc$իuuuݎ}p\333[8h֚1|IALSSSc$`0Ak y.uUd2Y 辗`9%H0 MA흜]g$;VZZL233y< Ejjj{{{rr2 ۠V322}DWWWGGD" 5jT^^L&koohllDa+**<==1 khhϷ( hBĸkZH $Nݠϴ\.u;u'@21Bff&w#i& CCCQu-Zh  +Df0 7nq ןM&AD0`ؒ{kמ={͑#GzGƌp`!}5D]]L&S6 _A|߫Ѓg@annnzt?Kn߾_bRR[[+H^~劊)S G۷(P!??_߿U uEYXX?0ԉ:uΝ;(_q~?c޽2?|uxxΝ;ǎkTbnBԁ_iȮ]^:nJ냁MOKR3Yay}]])aiad2#D"@bp^Rv*0W4  y_r`"mxڵ_|V^aXrrrqq_ܹ GyE$s6 я3Hmmmd2B(JZD^;qͽxaz}hstrDl2̞(??l…J233ڵk'N0)00pp:A`9q*))h4!!!aaammmFTRRJGH[[>iVXXىh4hąw@gii)Lnmm})^C$ ]C.]t>;;L&KIIprrzO?4**"""-Zhʕ{Y`aӧO?p~S⬬ Z޹s9sjkkTܹ322r„ /͛r{!yJJʉ'8`ff'`vHyf-?~|ٲe4MVǏhD_YZZꕇÞj ʈ'NBr~8j(&)v߾}l6{HC:׫C,]tٲeEtdM3w0MH`|> Wtz =Zz@*//rѣ[[[+KKKCBBBCCFYQQQXX C]n߾{+V}'{0 {۷Sowa agϞ0?ρN񒓓^􂴂cCC 888)JWWWvqwwBSXf )((ϯ c\rѣ555'O^p\._xodee7nݺ7|h 555++'qqqJP׿몪qoyyyuuu1#?UV[NPx_r%9<j!7lٲ{oZŌF;vjӦMVMݻw9sӅ/Fv\ #$$$\x ."Z2")}wδ477t:O嶴8::lC؉b2|ƍ/x<7f\TT4zhB~WWׄ Lfii)J2kkkh|qռy{ކbu;:tm&h:8pl6; wIMM]`x...nnn"a۶m/BNg<ɓh}~x뭷ƌaا~zСW_}UP111͏=B㏗/_%ɗ_~SNyzz^xqܹz@aK|MO>o7l؀~b֯_{^H Q.Ϛ5VGݻw_~yٳgwhw3.*"99ۿŋᇤ 6+VHOO믿d2޽{o޼ZdI:Ő03gT(wޝ4iR{{{^^^VV1" mnSmyqiikFjkkQ43Ht޽H|,(P `*8rHLVQQT*5Ju4TWWn߾L&㉏,,,EEEQQQ_|1~x#G888455yxxlٲ%00ǝ%pU+Fh4bxH?VFNǃda^pCĤ$8Jf„ 0nB,dD"`_5&&… zN0 |JV㑇,--Ǐ_VVeEUh >_LO%:ziӦi[ZZ eŋ/{c̙sرDEcDժL&Ġ".{̙\.[UU~jjj$Vhuޭ0s̹p¤I.^8uTKKK#-# ^;=H:K.R4**.--7NƎ[XX^Lj:,,L뵈Isszu.A"Hx|#Q ð[`k9!ɽn(MKKÇ߿R7xӳ$55cD48&//bxYxڵksyݑޏt*JVi4ިͦ|w{!ڵk ,=<ݎaXGGÉP(NJLL4zGU}`$??tmλ&!!aƍ{Bo `AZ` X¿Z ޾1''͠I]]WGGGMM!Ы?))ãNKR.{A G~t D8::R/?o@@@?Mn5kh4z4T?fX.\Xbvttlii)ɲf̘akk{-eooO,F]]]ޜ9sBBBL۷Kȣ욚tĉ틌0믿+1c[5fDTĎ;|}}9" _'Otvv=z7޸zjQQћoaٳ);;{ڴi,ː׬YT*#hs_>&&0EF7\.'VVVF:n7R` @7#+++lmm}嗍0wEFx AuqC[]мːdRIR?3bO3_H$n= v ֭[Lfrrr]]݈#6msɒ%D?Lp7Ι3GT+.]z.Y?5jTBBG}tܹM6 ~Iˇ-66|RϪ E@@ѣG}>XreIIӧ۷rʠ WW+V~Dy(֘qQ1 >}ƍi4޽{mG͘1/vډ'*peHZi&!!!>>oE|>_ohin"zof2rno0s$/,`W_=n:EJ(Dx7 >|jDcE(dn766j|9)RGJJJBBBwرgr⊊O"Lf[[#jT*JEƒZ(`T*hBVrGGGooo6-ɄB!ND(b@ 077d2d a1`V/HJeIp>>  EyѢE $0@ `Py+VXYYv{{ 333tҒFr&H( F#A(d5$NFJ0 e·{X0`aee?qܹH;; ?~\PL0iٿۓ'Oll6L&CX񬬬b1RH$ BPjkkLPaÝ;wf͚URR2wO㊕}T?XWWGPFZRRBƍXRd2\JЀnkeeaXAAz9ZR@ :u*~!j]"{X0`aثaX[[[KK+NO`&D":URRxxxCUN 8p|M|{ܸq9RapB-,,:;;q"N'N0,44TԸq2A CX0`p$S?0tB033JZ^Lmmm<oh}96diy ]FPZ K ?G cUb@!W jhh0aBaa!MLLWjmm  N'---LCͲ.qر#ƍCQ cNNNxx%h4mmm$ p8* Лð66ЀB!\"@` A\nOy<DBH$7S/*j۶m$i;v H[n} K}}}{{)jkkkjjF]__999d2AAAJrӦM|>֎׮]KKK駪*///+4vRP5H` G/,//e";;{׮]3l1c|`%(J+$$]'JU(mi 'H(,$&7o*`kk;k, ͛7o^aaahh(L֊f% $J5qeq@ H᝝%%%b))J%BhMMMfffB޽{xyDe2ٸqX,V%~KK Q T*i4&gИRKr RRipps{^{.9@FnxDZ0D߿ߍMARUTT?Fþqӛ tIlll {ߍ;;af\RPP|~lCj777%7|WW2P---NNNxHVn{{=3 ,D~~n|jrpܗ^z C1I$RkkcS(bzY|$wQ 5 Օx[tlPAĀ3 ʕ+fܹW\A싋I$@ 8qbuuܹs/_FTl6V(Ν;7++̚5̜9\ `@9NVV֚5kBBB@` h!x6ڵkI$Ҙ1c1 ;}tmmCZRRHPK/vmoo{۫fΜG0gΜ1$%4󫯾 hĀBM@gO@@@@@ڞ3g 0h{̙hwܸqD⭖.]Jdĉij!!!M0B"==8쎎Zljlٲdǎxt~f„ ݚ%AAA})((pttw^cc9>J0544ߝ8q"z[n#O>ӦM믿&L=y]r9AZr L f=rHF/.0Lhla CRyzzzxx2777KKK.m2gɩEuuuϾJ ++FbD1uԯɉB,XܹsL&cɒ%Ν377}oܸ!NrO>XвB\]]+++˵`2W~.'iݹsGiii\\\QQڵkj0lȑmCb0et뺺xZd2*RnPx~AxffҥK###VZ5M&*^c #HPzޕuE3111SNݹsg%M뗆  *<<`1 BV߻wֈ2>~(:Л!0*ZQQà SvvvjL&QFtyhHDD,@k)ZQP&,, ':xh;) D)\`زe (/A FJyΝzk۶mׯ_j*0ELOO_|yttttt5kLvر-[dff._/P999h Mk?y ~}k P˗/GH$RnnnMMMMMͣG8Ϙs?xҥKΝqF~~~VV֥KP177'Ol޼_~}6E9w^Q[[D&._?oHHhܹs<@gΜ0ƍ.]:{lVVVIIIvv3gP^[hb c  F˵vZ͛7,,,"""n߾`JJ{Յ_|922bn޼xa}ᇣFb2NOEFF:u*..ի 0Re///{{իW ###'NheeZsN???[[9sbte˖e>sPE3^ O?j'N8pO>1r9B|O[V/*U*7ob_uu5aӧO?po߾@6={l-1 xbPPU\\Ǐأ.d!v 6IIIuuux242qwwwvv~@qrrz:$G\1 ֭[u;[l6۔˗/ .™3g/_~رYfs8Вյdɒpܙ3g?>44RH$&B!?2 <,^vÇ{xxܹs…4m͚5B@*.[l˖-x߿EpkYoa4رcW\YjUTTbݺu߿?za7o~zVV={F.|pĈ{ͭ[~O=ɓ'<OoaCbDDD|o}ٲe&J"䠏R`TUUj?%%%)) E Hsss#""Яɓ'gΜxI&766j `smwy7x\+X-Kln53c C;}ud27oOEx2{ >.d!$n / Z7@ 9t##^FQUUpq\r$Iwhͭ ծJ"HH$SRJDFV"HcSTB<1H$H`\P(PpFVVVHHɓ/rcƌxb@@'ObFHdgg' .\ؿ hn]̰X,&)?~h 9bǯ^zڴi*L9s&77VUUAUMMJ3f 2BLUUUj_gii"sΝ;wΜ9.\4iŋNjccȐ`Ԣ zwy[V/*5H!9bnn>iҤ2#ib2z.H0pZ(їu++&M| (?,---W`4îeLbBKѨjAb5ȅCkܹsx^LP"""LMG42w{|NFC7nɓ'Q؀A… M f@x6xm PZ[[k4< ڵk ,=8"(**jIII~~~ jVr\RT*E^H|oTRj5ўF!Є7ݻ7++ m"CR&kɬP(?,a(r0F2777T]PC` `dZVz 15hY"M F2Jd2닑HŎ>hV^ nbb"wp\.GC܃oEkii!.Hc0 >G< }ۛb]paŊgL2eʔ1 oooOKKCFFLJD"c*v{!1}^^VQFܗ^z 0Ry}~W^y뭷Pp'NȐ`bBѣְ)2w"RYPP`Sh4ݛ={MBe꺮`  %77H-qqqLȼ 6Y&<|\nȫQT|>_ߩVF&UTTfꊯi |>ӳˋ8R2ښd2YFʆJ...peFꫯΟ?Op8fp83g,//Gηt:deeY9E]6hr] |Æ 6mx饗 juTTʚ1c[X,Fy7xիEEEof XYYIII^^^\c__#GBfh4e˖%&&fffر `hs_>&&u0T!pbwwӧO777[ZZr9!n5lf-[fa1 srr={;99eggO6MK/2"">ST333[cEE]PC_ $_lmm{Ytl%2e `rr!% QkTi%]TWW2޵\.7##ȑ#uuuVZr;w'njSYYr-,,LJf{Xozj6&b8p.]6kĉgCBBL'(((C ZZZò!֭[Lfrrr]]݈#6mϝ;i&@O?!k\oaV{ݶmG}g<[avСh˗nF.>}ƍќ|rʒӧO>|xƍsQ*ʥKn%4$Zf͚?cԨQ 'Nrְ)9x zX*ugu222֮];qDB5?P(d=S(VVV#FU;-ᑁD OOPzd@/\ ~\,w1L~^S}ԒT*!D=bbB jjjZ[[$_~ijjruuп cff&JDž[qk׮a]YY) ÷lقf 4 +++ ^^v}PZt_򁃆bBE#VVV.cX {utB\>xobmhJ%*R߿oěG"ru3Vl/Ƃuduk׮%K{. $;j|gA!h. t:0ooZ1xԐJL@```pppEPTcǎ5RmCCC8k]T*ccc+**/_~Ǐ;88|KAZZ;v488ͼeffVWWx+ .455ݻ͛|/LP]/ꊋ\nggOGGɓoܸ!]\\ryee@ 8qbuuܹs\T* G9LPl}t+J GAV2e}he !A^^^E,&Lw $g }ZȁbtttWq@յhјNbo"T^^>IuFC{"!GR\CדHI&i9sbu֞~)y#H6m0044-yھ}; ?f… 3fgPzbA&1+q"˩T))d\K $X@_vQ" b@\.7F3f t:Pv?#"EFF=ۆ0 {nTT1^)hħ 1y* _@(T*Ó/ <]VVRߥP(b<@珑Dx@3]YDcGȻi;a„#G&Fp1sSC#~n:p'ϒ7nXZZjʪMLLBB,X󞞞]]](@`$=њ@F֖Jݭ1'Ѣ'((O|Ȇa'W\yQoT*---uOs0 o"Ŏ>'0 dz0"۵d2Y"d{d "E wL:uΝ޵kWjj*vww^~Vk޽{wȑ6lXx)N:f͚_!5͞={N8뛚?f!:tH+*immF"hD"{zz|r촵ƌ󁁁GRa۶mz!?7cΞ=mDFF(sW^9r$1/JI&SN XYY^sZs{!wuk H$Qjc䒧V@L$>>Gv/Rjjj.^8{͛7o߾mmm4iҲeӯ_l2>:srr"w 駟.]G0`hޞfJJJZZZ?;*}ܖrS/ jB&İAE " ("]~ .i )$-<̝9s{Ow޶~O?hѢ슊 B~uTƒׯATZFH4oՐBcƌSf޽sΕH$Ǐr^_jUdddii'|e˖uݽ{7**jݺu.[7+{Eу4.\bVP( ^vգF****++q'V'LPPP񢢢rrrv`عjB;K.\D9~ګWܤ$жmVX{$wryXX؅ tBzWz뭷K.mgy~/P( Qƌx$CX/r]'mJ;v-fCnqx/40ڵkS(//S3,j>T*`^FGGc;jbbbZA]D)0TR| 8z_\\|r̙3[nuVLL?!vG}sκ_>**jҤIf7~:IҜ7",K@@/6lXVVٳB6vfѩ_5.QPPSG?^ZP;f7b̙3g0F8!!!jժF``uK:fߺu+<<]X,*8rjo8FKbC򆶍B7nի*++oܸ122rٲeeee\.wѢE'Nطoϟ7oСCo߾3uT<~|a ]x1,,r18v.J}5z+e"*++<r… Gѿok׮)= ͛7'$$;vlڴix SNm۶-,,{jj;s!՚`m۶!fΜjW4y ]&3(H4#>>>RymmSJ2s+pï]vEr]mv}Ν[lA۷5ünݺ]o̙3'Ol6[՚L!C;w֭[ؙʕ+7o\ddx_YY?!stSOn݊ d~Vuҥ:urb:t($$DTN0d2IRɔzȑN:edd;v$IfZѣ]&FAπwUL߻wÇ?x˼JhSԖX,CӦM˗oذk׮k֬t6cڵ+**ÇX,N_|yIIILḺcƍG9i$\ùcï^rח:ԩS'&)=rm>}y睥K?^*b-K\E~~>>:eʔu]|R&N>ï:???<<!4gΜ>;v쨪,Yꫯ |xY&=]xVq2ѵ_1vׯw-66+!64**!sR/u[/4++rKNNNNNt xcRut;zR/\Aށl 0xत_}Ȑ!mB@ tݳTX,۷۷nj3rcǎ>>K,9rի/_ ƪUB*j͛aaa.BӥgggϘ1#661-SHrJ˧@AVfԨQ=\O4@qXpX,JäRIOWDkAg< wwNdxґA|>!d`dpxځN:#a6]СC}`=NPTBz;WVV֧OFcǎӧӝmb^|EyNLFϠA 4o޼ݻWVVSbbbvK{9^zT_rAlzQFy{ߧj7eff_3go߾!C79c4q^}?!4wܹs>iB\'8xI׮]BLS$&f0{ƪݻ6lذj*HVf۽9>l9]3i`[wcpnuVL& RR+Vh0}z4nM/q*P.vjkqxc$Ko6k,άxַ=x2FQs\XLVDP8p^?P(tx7faӧOoRҥKR)ֈbA/^rJPxxxtt׬Y|lzn?|ȑ#+Wܾ};|7l2{wypժUl6Lx[%Mf͚|g/RV?^zĉ7nܘ8qxGFF>sׯ_X%{7ybZzˠٳ"b gϞ3gN^w=l0χ*++g~㐐}-Zhʔ)uuu'OrСC遂^xb@0k֬򰰰c x]8Hݹ}ԩX,V*(I<\6m0-8]ݍ 9I^B Z,n |\.r5$v=x5g&>pmjjjf3IHH@L&6mX4 `"cw!W\̀|>ׯw>eʔ)tK.]ԛ>)N8}{|w=z8}"""\T ڼyPrvwY<>Ç?zo3L=*Phjkke27-N׷oH$tPq;TwlF{>jTݐjn˖-aaa֭{nTTԺuccc`.1j݌dj2,44GPx߭Z :|>d2?"f3b0 OXOtF@EKP# L&MIIB8ڡϏd,S2:X,cfsp8 .IL&ml2j _4k_}޽v|$Ibk e48IśL$pKaa5LS 0XrݻI"H._~b}GmK CvKҸ\L&sR[[.$ mh)ɼyfsg6}iI$h x L_d tŊ~ 0_N$ `ٍ i-\nIIjŕw_Tq)۷oflٲ h7@;+\) & hns;8 ml6X:(BΝRǏeuZntͶ v= h-ܽB7nܰX,l6;((HP$i4FbݻwqqjeX*J%%%D"7oތsvCҩS'(HЌ0L8& h>n߾:a x<C$ܝM!TJ853 ԉ/O?h"Ih4| ζ(Hd<~j=m޽{]tr|ŋj5Nذa% =l6ʐEW|}}ۈ^PPCrEohΙ -fPt^dh4 BHVp8Vdx(H=B+8S)}D!)8`ɡ=v'$f ]A$i4JDB*V}ybwv:w [tФ"|&{QCCCo޼IK_2jZ$aۍFcHHH]]@  7[zz:  o9U*l` 6%H9tka I^$!^Fۂ Cxm$I7 @+hܹϩ .4 Ȑ6+&,>=H0 A @e֭ 8&$P@A $P@A sذa^66&}vf_hQˌaHM~閹&1{lD֭&L#1 x#MVm~[$}geee%''ʐ-sM>l;ܾ}ӧo޼d2\2xZ@Ah,\it#Ò԰0mphiҖ/_.zuEym߾}ڵ?;Ϝ9~ذak׮GMKK ݺu[`]5͋ y7z=OUFUVV<$vebccG]VVm6-M:bŊl]IƏlЙ3gE$/xO駟~gϞ!Dr9|bڮ]{ %t>*Ͷp.]~]9b̝;7&&F ڵ˥La$VرcT*]lYnnnYYŇ>SFSt7FFF:G)qƭ^://h4ү̙3Zj2&OpB裏 v|yDrH-:qľ}|yzm664-_v;D8p`Μ9uy999SN%b/f7nD]x1,,,11y<[ld;vwn̞={իW֭۰aüoӡC,XpԩX³d͛7'$$;vlڴi鱱 0ߚ &MݻwppkjjJJJ<6mZjjUUU%33?999--ޣ bǎ֭H$;w^dɁBfyʕ۶mݻT*0a@ 00Ѹf͚[&''GGGڵK.>|aTXVt}ثW//s=ݎBbo߾o3fLcnrȑǎKOO?yM O8sqlJr<|>I%vbZ,N`XX,}bw07RJR x}n!qʤC<~Z;Sx^JbABF2tt:]zzzvv3bcc-w0?@A&חr2޽{wfsUUfcXΝ;3fϞ=山EEEs</##갶dzj; Bk07p8  ѣ%%%|>_~<~8ǫr!..ݺuF 6R|f  @TN0d޽{7""F${QRRR^^n5MK"x<^gӱT*&%Iǧ# ѓ2hРA͛7{Ѯ] ƒN2ެk׮6_۷7C.]zB6իgn[B(++/_GU"W@G(򦒌qGtt4p_oWH r'|B- 6Bwpw&o @yW<řsssT***ZTE#JJ FSFZzd,+ĉsrrxSv۵O#F1b}or`tyݏ?ޘ% Ł^x @Gy<^~~###{ׯQF}]HHٳg " SN'O>}7|#J.]*J=;͜9fmٲn!brssg͚/:~>BH,4h+WDGGG/_sxLq`V¡J۶mkdp;^3fotnݺz$,,LV/҉'nܸ >Iu7 wh| 3nŹqNeۮ%ٖۑZH ̙3ϝ;3~۷^R̟?_ݻtŋYϟ_}o=`ڳgϞ={ BCڸq;zh6|#Gx\.OHHh[L0a/vكǯON-V^yxZjԩSLqvRxwlذaΜ9YYY\.^^a$+W?{ :t歷ޚ:ujQQݻun$Ia6ٺukk]zx. `۬`o߾9i!I211s+O`8XBzׯ߂ F `AF/SاOҧOK.>|…={`$ D"'^r%,,L*C=@℄Lf0|CF3 ޽۴>Q D"˿B(%%!TVV&fQwܾ}ȑ# o \~I B'm.\~z@hϟYJ@\IZ>>?C^$IeeD"1x,T`0`]vO;r\$xPhZz}\\͛7guuRtw4""ϯ.kjjlΚ5r'p> +Bm|JOvlJ^p8̊UAiii<[V)AAj( .1tx h$F`0?!Vo8jfBHO?͚5륗^裏Lsϭ^ҥKK,o]vҥ/rmA>/^t >o׿p͛7/\pر}ܭ[;o޼Ȑ7xPomҖ-[&}٫WY&))oر2ӗ/_.zuE@K.=gذak׮u'Wc 0xۡNLv\țC-LAA Y,990r'L@wܧOf5t,mOF#P(ƍz꼼Jш/Zĉ:t۷l+v؁i4jSNl>|ƍB/^ 9o7oޜpرiӦfϞzիWw !4sLV믿Lɓ'/\ZcmͩSm=55w9tj[`m<~ر?\*.[,77O? ĝlq8)ٸqcdd$?斝%Pr\_1S?l6ۥt:Ao.XԩSs w6IM89fS(dR65=ՁP=9FIoI%wA%&&*J&R(W7Vo߾c:kPMŕ+W9Y={dffRq@SUUeX2332Fq͚5.]¿ v튊:|.ÇX,N_|yIIILḺcƍ)S[b>x(mǎUUUx,YW_mPo'D~_3gG}T&Mݻ7Bh6l())IJJW3m4 %72qIaνuuÆ .\ѣBh͚5[l !9=᥻D"qNFA5v^ гT*___lbBs]Yg`P(A$d2I?0]Bdyy٬|W6m*//ӦM:u*>t]m6>34駟 Ϟ?rcǎULo]pQ{_:$*WE;wJR455RJr~8ݎ;ON//[XXXVV&FgXHBaDD!t9b9|6|7 MCrr2,&}gáx1w7#djdKtϞ :.MaF rϚ5O=Լ`eSSS^TUeZqqwuQQPe1:ZXXDF-lzzQQBϯRRI$Պ-~t !6b*=\XX>#"" _YYY>}4MFFU_O$333E"V@e4/;38ˈ`OF=H%'WcIM{K};wrzr=*=점;;yRA;@Ap>䰟Vq;.OO-l5r`uuu>&ԧ(FDFe0$Iz׋7m7a„@Fp\L&KNN~׮]}|| EPPQ( ry``x,b֭[[yֳvTFWa$\] e2I_BZm[$G(왘6<&&r>իF.eNp v#I bDeþLxTݻLwh4ZzG/ KEP~_X5Zm/yyyy!Dˍ;]捻@!D"l%IZJ*2$SNk5 [=z4%cc6we-PpVH<7`0 AAA]28V㑑+<^v{p03i2^r\T*#f3Am*tF#ŢgP(Xo1L&l6=TwDYTF[zV m*nqqqnn.˥2;P[[+ɚor<--㕗GEE97xb@{E $IGx&X#wKF___\jf˶a@@BC%H֭\.Z?rǀD"LfZt:]II jAAAgh4&H$X,K;psT*ոq ۷jumm?_ZZj|||fϞ|ػwܹs%_{5x \`+6$B8ŢTqm:.vX뫪zRG)Jտ+fZؿ1$$ahh(p8Β h4b`xtږYdIbb#\Yv-)^GNVLFNL]-X>|D$e0 @c1$I Bߔf(M ͆Wz TIY r5$-K6"lgE"ɤRT*z6 / ؓ 鳩J2we ^o(gKFӭ[7(u….]HRʫ~C8tҘ9C[j]No@KQMq߱pDRd2U*TJK@@/ FK>>V !!!8!S5QL_tUUUUԚ//%IW/,,1Lt3Bhoknܸi077ðyqQ%+ @ ž={{ر?dAohZ-&&BڈI$GBB!~5L^^^^^BsXO;vlgy!ԥKAyyydd$uuu8 Zv?.&搌$ILAz$Dit^z9d-V9ӽ^g ы*A;3gիW{nIm $?oZ94%ppʏ7_~ v (HX rrrٓPQQT*?/~wAYև[L&d2DGGO>xD}rss=*VK^'fcXJR 0LF#H `pB>}Add$r [+**l?;w :BP_~]*+V$xx(шH`pl6[hhhMMd 6LDa@hg2?~ܥKP!K~1LRjCCCJ%rJR"h4j  [WW};uT[[۩S'f2d2Nh4:.((a6V% u L,JA;~)Sܹ^p85.ιx;,(g_8i7@G jqРA{juuuxáq͡:O!FA߉7*V[nB` !.#~Ǔ'OꈈBaٺw1Νu]̶sV'͢ÓXrv9DmQ6+,sWbc\.홾X)ޒ&?R>>.ӚWUUy84!t32'₳p!C fsmmD"(xQ>~-.!JU* ruP@A)(9꒓^h[]vMDDĽ{c.DZ/ÀG픢[SLEm[3g!x"oP@$H"  eI"1ۋewK"i*R䰹~lƪԎYO S$xqwKs;=߿MLLl>=5.'9AL&`'j;zJ zV*W mTH@kA=fZhƕi22 iP?3 f$?!7E(@EcWeXq/|u^S$xzMaaL&#I~~~Bd2SBGƁ=z$ɑ#G={?OBB1bTYY%%%8H婨hp@`ϺCĤ j VS#I$sz,A*RKL&S^aaa8}_pp0V[@AR*.\HKKxT 6к0>!c&Yüϵ0cp M١3\dÔ ZCapWN Pq 4huGͷ|}vN\ud=MukzFsFsfL&&f- ñvX,@ʂtP:nCW\n)stAX]]-J-۷9D=8ۢ{Ν;W"?0F\\ܴW>ٰq y`JzR_fcE.|ٞK ߝZSS ht [SSc49NTTZl6`rfD"FCUCjܹs!T*LJJ;wVT$IGDDt:О={𲲲`Je4+**|}}lvmmm.]Ouuu.]jkkF[\3T$… _}O>!׿_Q/ab #R.7{{Ȑ!۹sɓaJAٳgpp0}D:~{'" rt+T>z)L_}UppMriӦNsfPw?RrȨ7BtvEVt:O? @q}ڵk.67~=|2o9Ƭ.K0 "<<(H Pmm-^X,De4Ij#8á~HdAAATh;f{99G7?S ގw}6LX`A߾}ccc/_>zhÆ:Ê ~X>}Sj-[VX1raÆ AA!Ν;gZccc,KΝq"}1̬~ ۹s端G%$$2d޽CT* ng\.{|RUU%M&5efQ]]d2`hó`tT>CX~Ʉ=2bkAsUR9eʔk׾kݻwׯ_lll``>'\ƍˇ 2uoFTҽaJO/TmDv }1gΜ9s$ ر Olx#88f;Px]Xb.+HUYY (-[;!^~Pv  ޽oѣGN޽{7o^`$͛7B))) `QveeeiiiPaGG$ͦ2Rm`0t:\E X,?v!Ԧ1̰0qk-3ϸK h `-hL6BaFFFFF7'9rk׮) @䧟~rʝ;w^|}5 $$$it(")( 6lg9;vAwYNCE_AT^)s@B}>wa33,}{}aAA!JUVVuuuG$1LǕdddlvYYFԬx3UPPPRRzÑC555 !:%y***8󡼼|dHI&m۶mnnn&i&??ݻQQQϞ=l} H0gΜs璯333-,,h4ZffiϞ=!>F]]]x"9[BSSY]E"kv0o )6[^WWqk\.fz 0%t:~5BHd溚љ0 GYYbыdee)F |/|A׷yf{{{ BBBȓ=zѣZ֭{Epp0 H!Kh6[eee!r (~OXL|RIצjoo߮*pGG/}8,®Bѫ锔Zq"t-fhh(|,!ONܹԴq~QZZڝ;wRSS /z`H|;6>}˛@.r:B⮵koԁN+prrʚ>}ӧL$YYYSSӕ+WVVV455:u ķ1$ 3fHLLP(l6{ϟHMM޽{~~СCsssLf^^B ={ "2$UWWȇuߟ\ Ȩ4JMMZII DBg1cBU|(y xdH"==!j*kkk׎;|8BNkjjc!p9?? ! ]@kG)**fdd$$$_N4YYY>|acc#l3%%b #'֭a\jMMM<^G8b >VyL{3gL6 !DP<<<<<CVV""b3QW 8cFrqvhQaL556@0!AQiT þvkx|ă8|ש2QHLL|N5q8L$HEIEq]T A,,y9Eg9j*} j*d)*)=HJ5tF%1r$&g`BR)z !  pq r!D.BRT*F$tEѨT0AtJR(  ȑȏVHZǯ RgT^^~+ɷ޾*a0TF]KyQƻ766@-G"S#G.@JB0]RXXثWt7|azյ7 ]3hkaG:C:'m:}y!ѱG3f]~ ry{vdz>kqp߹w|_t澴R;T||f;xr0t9G1A,V_tmCcdd[TXFM\<<>y;6A;+6m151v'b.Z0 yORn͌m]$HBqqI^\A! m;Eѱ7CF`cg9h2-wؗSMM HG<8yΐF-m(}}ajZQw2񣂮̈́޻o.Y:cR<`7nO6cs$.)%ePbrባܘ OVX\hdhlY.YZVfm5 rY?svZZiYztW16KHY}Ӻ'.bve_Z6zeAnx>WJJ#!#ᮭ[tuZmhY'ledN?ݲa]C, NҟW5_\~liiY޽.Y]_OB#`Zn!ye8Ҍ.k6O4`lnkQy62AjgFn2gX4[@ EG)--;vP|̡GBuu#Wut֍?p*M-oL 8BpQScs!BRs9y¼%KBѱGSomٰ>>J >~瞽ΣeؽJز).wcbBt:f/ [pt[ ZE]MMMUV;ز/&B|ɢϜof-G>|?6m?|BliԻp'ܺ4jDCSyaQ#e֮9IB#FEYgffjv$(x Erϟv̬.nŸ.K(\[WgհeeeM nA{ FF䩆6kaaqiw]IJX.2e~}TUSs_%\HOWgͪ;wfbjbd2f.{+.131ZҎ:ڻ1.NcLMUUTf奣]_oGv# ++6[qNT-,taF;(Mawz0SQQ7;+. Z-vmOrB/_bgۮfWx'OXֳQ5HG[;rR }S\#G"{6p8˗l Gk=Ej Ҍ.0Į#ZIޢ]hֿ{9xǛB̙ [޲0a3fK~۱l&eᢢb f}S 465! --g ?m4B-ƌjur6[bTyߢW 035%˳X}z.(,t:!$+h6~ffvMpj?il$_$%doMMͫ%!jH"9f,dr8ZWNpvNZ҆ c2/ oV6YM<^3S m2Eё0L/e ki(Yn0@'N,|,*,>Oŕ׵0+WƎ *9*w̬ˉWWDuOmz?tupeF2e<0 S[e 'o3qq*ݧ?yc(}i9w㰡&ﮯf&2bAqm# AүKh3z{͙}3۬YutAtqH  &>olki( i .0lг[PW@AwEu]rr2+a[V4+{M+:źvw,ryn)+/VAQщSgΛ=jPC}㧹FzzAd=W8rLLND.JuuuBt R{7MOrkjB͵`fSV"Aˈ}Nŵ)Nr 0>ٳy lo+ng`47'9O5"y$hii1/L-ammSQQgXB c1~foܸE9Cf*=]87!RWo`0|<D!r>}$!T[Ww)jYyySSìlխ[7auqpV_^{sJl;iձ8Ç)((9;mپin^eUՎ={54ԛ]'~?AEeeccɹ9;mٱINNUUuvyN iHCMM?{j_B[wEE߲feZg\ BRG=j ͊미2~%8;i.H;[ܼq>lF m߼u-(hsl! $e\xQؖOmFhupƽRce-WzBvg~"yNtԙ6!fOܱkh? P]]ݍ'^ktjSp= \q==!Yfѓ>z]t:!8t@HYƨ[m5էܳOBaZdE_`BH_5 "JA1qS|nݾmc3P\_޾+}e FL\V',4\\!DRZm\hq5*ǣGf%WZP!L=sZr@+VO+*.KFFFB#m_MMM-7[Q C7i(tcBo4'Wy0@nvsZ>Æ'kfEEŸɞ(`|`~fah`m0i.מ]&b$ޫ" : Z ~gzڲ Ɨm+5 C $H޾.&i2\`x\pIrr)P4! S9bAۥzeyeXSH_YZ AJ˰䍍?:l6BI8iSlo{ǝ8I&LtEJ̀{:Z J\h|fy666~mzxm''F? @{,vm$pLB!_epCǥɈ7f}dMunԞZ{hʕ,{z)1bہG)--;vP|̡GB>ޘ@p6ḣ&\\.c,YZ__=z;mˆ1TJHX?s^gk:/mǤ;דg[;B@ٶiñh&)Zu555Uf]WXNeaKNq˶чgۦ QWZ[.PeaN2}Fwvls1ں呫Ǻ^:wvƟF8 H3r[E`:]8ϟ]<ޞZ˪3jXhF`[ظ$%G, V2iblvy*J)׹\/V.]bldfUDuM흻A3gsq151f2RʥKLL|aiEЅH(,sbdh8' n-o3SSUYAxyhkwכ鑝!T^^+**Z@{%vIWWܯ'OƚyCA$~x_[߄Bt,)c؇Y>4<>=~!]oUQQ1AO AcSڲŘQ##VXf]ja޷k LM,V޽ A2ڻo`8̌\N) $%doMMͫ%\)Vl[meeePKilDX[Zzbg7~ ++{1x=.㔚ȏ م a:?}s*?9=~d3!K^A }2-aeLqiT*Sq1 #Bybe '88ci s8M3w6t҄"׬dRH\ PJ&{wm̺xuEjk[7_\b<=]jBTE{uӵkMRX,J摡o ;źv[EE'NY8oFOs z>=0,7/D@uuuBُVԄ̛k=RͦP-:RH\ beǕcuNYy9 ?@p6kw ^JO88び <OF@ y~=˳w^{V?z':63b07g-w>ͫڱg45?lllvy997g-;v>ɩ;~RX}뮨}EPXHMM?{.,T[Ww)jYyySSìlխ[fx<.!y+B|K_XwybM5ϮU?9SWNDfOeصmi)[M{yާ~=4z{NA/ 4z@!AFWTk~p.ršEGDbf;hP-VćYS||G9\յ#-w`ɊH8W}=wz+,d?nPL\X66? !h4ѣBIhAuuu7n:it߼~,!ڝrɞdaO_?Е IPUEF2ݢp! 7o:oܬ({a$F*SUWQȐu1mly@ncUTT_d%ɇNJpt]Z|=]mȎ ;UPTTTTl=`Lԩ@Nǝ8I&Lt1@g| endstream endobj 173 0 obj << /Length 1385 /Filter /FlateDecode >> stream xڭXo8_P>^oOj۬tRw0S۴76 iUQ0f2x8jv)b'4JU$汳 Uܹ j ,s/JdEGq#$\}Q'}i-1UEe^GXf!Nw 8q :8%|"Ϝ^:IQºv;΂_G~x=,wƭPkBDKԔzq [9Q8sELS\aR2?3i\3`gUz{ ? ~݅RU< 1G 7Y%j0 ?"mG%`&eLleJQr4F,/^ !z~{sm'noRL'i?ĖS vҲ*QyI5e2L =ōyѵ_rZ%ik(Q> L(bm`z0ǎ;O#nQa)60\XsZMel iGA*=I \1]e{!ցŖ1a;ĀUj"xfؤɉ"Xb>dg[Ӆ<]cn97x WHcZ& o`~hťI[Í$zy>zgUyHqs=vdbF1:(耞WΥ3d'+ϒV/06OfkS*ä|Vj '5 `ƶ#Xb o;r6%g$(6Np\n 3̭g:b<E ,! n+*ss)]Ct 3{=RH0?2ρ}#?ܠi]:ʔP앾jM_Ԗ 7c4x{7) `,G}7e%{澵3@`O84ĪI6}ϰn` c@k [\ܿ<[#-/GTľf3 endstream endobj 180 0 obj << /Length 612 /Filter /FlateDecode >> stream xڝTM0+|$`jw*UMO\0C dI(ROc7C} >leI,MDQ*R)6?è\Q\4 ]~0Xwm<_'8KqF8<7SqYN'H ~BK g\7 {F2C9 A f*!llTysE8)|!ُaI30!U=Vf8=֊2õ<nzp=p}U+׭RW5\L9ΦɟazUۓ}j\-M1扸[azgFE)[;oVs𽹧1)ge(vqՍ{%(&\NI1ͦo endstream endobj 176 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///2_feature_gallery_export/D0003_Classifiers.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 184 0 R /BBox [0 0 800 600] /Group 175 0 R /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 185 0 R/f-0-1 186 0 R/f-1-0 187 0 R/f-2-1 188 0 R/f-2-0 189 0 R/f-1-1 190 0 R>> >> /Length 2614 /Filter /FlateDecode >> stream xZYoG~_я} @d b7V PhV!HE~U}̈P2e$kji J~Ђn_'J0ЌʄKq%~ҋ?1?J*rJ ,bvU/*=;&yCݾ9oAAƛljV D_ ?/-]l+˕΋K+,?E'Ӌ`wQZ?=6tB1[*JR4897B h4-Xu\#4q U1TCc̎ h3t `et!hC%ht䆰h_b(_EJN1= gۮ3/2 #Sv'Lj,=Ar;GǙO Լ;< u{r.DzӪ𐎇4Hwk^Lj:d>EvoGJ*FZcJnmmV0ܑ!UH(HnimoHvYrcLo)Q)~n6u]ҳe꿠#Go(֥5/a1L:ZZ4ZhɮSྯ[k=yzi{nh>>򸎁X~dn.֨{ۣ f'V-)p'C;;-Of5ٳ` }&} )K2u1!;jUPy]uѓPZw2T5#ޑ*E`QtROfn%UzsM'w`C|6]8kM}!2$T[L5'*p@-X! `HW4}P5KpxmIϾG׍bˌoցۚ*` |U[Ӡc'(:&5ĸ=iK_K7-ݝ@2vNO:4sJUClqnXiӿ,!ncL'Qo n>e<PjRx[.α-XX ݇(4ꁾ #;:pSvRP0٣h44 »' |gLqΞ-poK01KxмCn2"43e1:rښ!2×nn,yy27 |\Ojjk̆Ւ?+96t@9Hb0ʑ4بK?YiHh)/W&\䓕3^r}*+ ǜ Ib'H: ޱsϤr$\O|D6;bdNtV`*i%뉂r t*Imȣa3Io endstream endobj 2 0 obj << /Type /ObjStm /N 100 /First 851 /Length 2715 /Filter /FlateDecode >> stream xڵ[ms6_oL&L_wkk9|PlM^*yd,A,LLճv%H(UA**Vye\dZ.fEubbR)҄"cp|YYtInmG9+H! Bm@W]9N,.ΠKRങY9@6zȥ~MtvҌ~+@Hg0Fϗ@DT%nUݦWgz^Jث7]AŇhT'm1LRHȷ4 Qy_rwTP[ST8r(ڢ-RlbW")HqE+R\W")HE/R|_")H"WƘL>l7'|]YӼN_Dq0:cG0 "̏.qbX(0(I0[hq?[ @NmdAn(v(̚- :`l8K%&_#F)uĎi X tc. fdX I8F5q)n(~x(.iKCPh@˔5}3!4u77詑D@Cԍ|eDYXxwf ˀRGuSO<#)5gy՚oc)tVbC3D-$&>TPj5wC 2`7 e3c:{_ o e3hZ5u̮Uy{:ϣnՃ m<HL6>k<`njU<ۯz?x>z4&G>c*cUc&rI9V9k]/ˌE)4%xF˺U Xn, e%Ъ;G#ԝ wS9g $Pk:Ԫ5#Def2LPF(0;O6C Ձr7j`lB}))tClZeeٛ®e,c~+[Sl7*ɁZ҈DpA_[EU~CzuuQmmZ=:-+Q<\\~7V?ggzǀ~\=:Kci9{b?y|S'⇓lyy!ξLjѫcc$rdvσqFz^*+aM( N_9Kgj#Ns8D/pE-Ñ@Ȼ[c=Ļ7P m8vK_e!ܬ(9l{붂 |=W~ttzzhaY=[͋O5Y}Q\v0<[/.6$?g{|\\_Vcy[E^yۤ-1Tc]o^j&5f_j+7ˌ!z W̕sG^̑wW(`^;-y-)Dvϱ|`>É=M/d: 1>/O_#&0l{aqwC_k$W聆=!)ldmGbzY= ǽYZ*bTI vjf.暶^kB,/U"2OzWǘ\| Goȫ'- qo f:T endstream endobj 192 0 obj << /Length 205 0 R /Filter /FlateDecode >> stream x]SN0+|C4NmJ.=pMDM{;HZO&֦z=Ҹ-OaO3s{:Iǰ\?R:0{yyZE<ĩ[^s<|܃ڟ]VGݳ_t%ū],*eL5")iOR]]ou7 [E){6(ZSu] ;hh3oX@0{ִд(/V| r;1Ǡ> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> stream x]n0EYtâ5=N YxT"028;Ͻ6âϸ .נFLN%IoE}p]DB7-px2ˈ`0LәK?8 ]m{0#d|Mܟm#bp0 6;h:o2Z=*J<.mtD.Ȋ54u8.Q&yGX1+⚹&/k+ə4$zCuU\wKn͙5eG<װsbJ=pfMϨ茒Y7꬗I=(Arϒz[_s5ӤAq ݝ58t|i'W[h endstream endobj 198 0 obj << /Length 211 0 R /Filter /FlateDecode >> stream x]j >]NC&?3Ӂ(MiM*4*,5^IG>Zyޝzg84 JDq, n=N k>8{IdoNSz׽n'Ni@{OY4[tcU|SKH-է00Zd],CRHE"*#W*I.D7+QIHF4N%ߵzq{ĖX oly(Yc7WW  endstream endobj 200 0 obj << /Length 213 0 R /Filter /FlateDecode >> stream x]=n {N1XFM"?`ƸRy2P ?83@q[ @ҁ 6Ub52BkE\3pzvq'rNn eP/׽f~.؟kO]/H6:\ȆfZ@r1,tWJznq\@SRmŝn endstream endobj 203 0 obj << /Length 215 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> stream xX{\Ts.P.,YȲ \HB((*"&P]LKfS3F/DL3)[oBn9s^cD!$G#ASlD B$a%F]+0!S#Z7x3=cqԩO FH̩yY(GH c$ ؇{T؅8$C;ꃐQU"V iq9*c]®*n&IbX wx<1$!ь.;o~00ʐ)L7:FVC¸[*BUXjNv|-+piOb3^@[Vn-yM3g B2:Pb' _(BZCLLF)T 3xijoM`HXIQ{quЫ)1.9_'[*F9ʎq~s/NsoFNAL dK1zyHs|s?ё”ĢS7tίI |_+YVU]><564§Yٚi1$=mL8ܘTN^X662r,#L!cQ͛G =P 2!JF+ u2d0pvܯS4 ) K1Og1z8/-P&l27 trz ddZc.PֿhquC蛤\43M!a&fG&C2{3g&N;>=~=6M$ozƻR[ ښZ;w~} \0A?KoQ8dP8YWRQC6(v_ĥ9YKq]ӆ/ QՍ}/im,Sk&Fwd_M7 z!y+*D ;phm' rX%-[:Zp5!4 tAyHۀSSpbP!ixXhfd}9+;3F/c3N}5q-66L./ x@oLΈ 0ݞQz]( ն/N-lBIL^.΢N~F/;XGl.Iqd]nK'jS r$>\'g4:'œ p?e`Xw<8=9wn^0c[f00ndogiD˲%)CGֺHc1n_bpJr JAnu8 \o2H}ݱai]tQ9|{nUkS+m ,POh+fv ϥQ;Pf8Գ8u"$ )!d>W9թo=-{!Ǭgg\Idxmޜlb|tsb90MD*&DSK-A RHܥüFJw[Z/f?DoMvɼbДhi5!LNєw) ­; 4/b |.G^3)F ӏ!J·})rō+gjĐ5sl r|œ&,MnZq>=bmwDϤ b' IY%&ЙRLy?Xu/;}˷oOfϟourf@WXssy4:ҀQ;0 F$ ٛe?jc>snʋN/(p`bo^!=XU6K+Z;0lWBۗӭ |ʲ `26\ȼ};ئ\c*z?]E^daFpXbHXk]7< p8=6TOǮ]6y⻏xsG5A|7䊨&vg tIc+:mLr`ߴgOC{WGfrzwer'qN![6(W*^<*\: YN93xĥoq=.,(:/kX PQ~mLkkw8q%E2$V(&_ֻhH drVp'3KBR?=]-͘V&$rRoRw:J5Aeb@+ *' Aj]iۍVۊbd(5?, Ú'5Ϝ9@New_}RQ1=XXyǍ\;YxCRd Ǽcr_W?Y␼ڜ{Ƥie/[46J/-+e#DCgR1 q;ETz{7Au3jkE̎/蘓d)72_|aNfҋ.,jϞͯ=3'iӖe,sl67AD]An(5M>\g֌ONfZg-+Z+p:r5W6 ys`;˛ڹI=_(lXG˂/ޮtLJvv5őPVˁ]h\,FV69^3A?TvYp]#uHkZיq2J}?H ##ペ+?A+IO(7  3ƲCʤس$/!SRmok[Ufl^!>Pd,Sj^ubz6}jUQ+^WüY*%㢢Y#&Lxgv; #L/7"ԅSq^I5i7?)]#x=ހ7_5c○Fy/䖇@R/0 /pq}_@ xtӃ;TЁj!C>+G` *؟^nu>CCHa!t:4px3ÅuܽgBV+ȝCU]Op(M@3;*P"CGh VT&|)}h1wr'ku I>'F HG>@.`/Y1 wUE (楳=Z +]rǯ9Bf82t?T t&> stream xWWT{Qf`fÐ;CC=)>PdTSMAL[eV/+}-͊PZ YgIEi0wgs{o/ x`0*0c59y77V_Ǫq/DTӘ'/7RׄSXSP P[0x.fC*&Sq@E  40&I15k[!(#0+(+,KV)}FVe,]r.@jFqQ{b:=҇8"9~1MhG?vX0+秫/T k@ӝZa^2pH 4[TG`9.v96JVlܜ6ľ4|}mKSg<;{OdhNγ./]<őuuf:9;w-&cY&@=Tvme{*z01+xk/]9oSb?#E5vs]Qd:2Bt\D#ZSϗx7f^3uGwu_ =cϼ3]Lo@b"T5yQEox'IhJ|} 임w[']-3fm^&]Y;-8v ksk;yo-uIIoٝ1WI]K8ޗjcKGtٓOHl& yLXtGzfQj46=rcKHO_S ۻ+UU~R4SiG;nW3Q wx"@,/x?u`4r1elmI|M}67զ=ANeEQ`tn_9WcM1zzq|%3V5bݗE$tr1v:y2_$k*Ғe_3yfkn)LzAvQrK"ooT9Eoڬ˗eq !LmM(S4DGJn¯a{(wx*熇}131gwm1x&|ŲrfվQqm bA0YO$"\bQJDKՖʃz>tL09l> stream xTkx>%?B @&Vl)4 T.A .Hj!zQ1Bb) ZZ`p'=?>3{Μ<RDH+9S[f sȸg梅?5fϛˢ9DZ0=wiVdT*:WDI !\O+lT1o{  N[9\59|IYi/Bpj󲵉 B1Czdke]V zaR+G!ѳGMZIWiݗ>^`/ΔW$Ә,kyqrTE\-Qԣaxo`p 7+x>Ԩ2ч黋>s%1Ymi&E#]Q3DMY$o hZz@U52!_YXV4&Pa}iQ~cdN6fFfYfVئ;dר75TMqCq,0tmhTO۩FrJZnӄyUQH䕶KvJ'aiꐺZD\zP#$*|U;T"!d/ft"Swt9jۚm~{:kHԎ{1oZ9ʨ^|7BjwcYYf!+{iRQ\lHM#U-Jqm*'Yr^'Hy2s)%\:@Ƒ-ŃF%²h`fES'3+7j1k.l}kI> ]o+X/2]je|89 Ս1>/1q&qT>)1 eK3~)'~/^\eZt3cz_ 0`:7|Ə##! ~Ʈ&iɇ$bx}|xf[?mn|7F1ii-Nʼn͛R 65x4xT"d<q'CGF~6h lhя06OZaY맣>|zCNʬkzkX- VMPw+ꕌ6cc9#sY81a|+7KKXĢDWjFRn˙] X;`$zЍ f  LQz@XtQ62< jV*a:;Rf4 endstream endobj 217 0 obj << /Length 222 0 R /Filter /FlateDecode /Length1 420 >> stream xc`d```cp``bPHϩLP@JFnI C-_s''?@~M(`Pc[|Vf @;9x9YSQ F'LnZwS߸5<*11-"& IYMMM̌ԔDELmW?/]5W'}fnSܾEe\cb Rx~  pC<}$NǾW8\N ${?A~Ȃ#sC ^} Y endstream endobj 219 0 obj << /Length 223 0 R /Filter /FlateDecode /Length1 4188 >> stream xV{xTյΞ yLLfBHȐ5L!! I M`"E^K@1@ ֦0VUz^{Sja]gs9gڿksg`6w ƌqX:Ѳ ȀdvxU7M}6HWCGUIYtʦ'-$ܱpn4גܹ{RuagI\z_k׌ 83Q5=P *N2P٥HtAvCS"CAT1fac(e^ON'%fu${=gX,9pGLaց/_HQRin~gፉ[u 5[ꛜyUݎHS4'gL3e;2g'S6,$lMImy2T۴aOL\-(qnGaz /KdnVMkR~`#Fϙ,+8sʒST*E׸]cs+'@wDxqVcm=+M9lo.-50ۄ!n|mɊ8xȒ܆ʾ_ ONyRڅE(kJC7+ ? F"Gch$UmʕF=WOGqqvSݯw>IG?~MUQ8cڤXWM3|>O Fq1D(`K$§/+ wQ[ٹȎhҞWQ@b:  Z{XytzÕfML[p%r}^Win.OWM8{C󜘔`j S.z@LM*W *S#jR2\T܋G X؛;!1[^EN51C͢kO>8[CX| [QHd{\B|??C^92i ۈeW 7 ÖLL*;ٜ=nq.z^dhǘE;O!NvMXf5K: G]||q5w.b]95yDi#F" q7c!{٠Q-K[2ְgس̍ #OQFS?!}| D}k*/vh*\ڀhԴvfj_bf`- 2CHK&f p OU'nWSKg+^HIDjEI̹=۵Y۵yPnMxE ߒXw6&&Z(g^-tKSMFĘkDw"ΘI~{>juEFP"CƬȐTET/UKؽJ[3$‡Æݬ_&Nv'u;=luR{kzAoBERjTu)Tj]@5o(Knl`uMIRD[ 1_ḰUr$A%0;?K|^ş$Ņ >#ħaH|dŇA^ {';d~Nzqv26MmޕxGmH  ڃ7%^lk)W%NJ"/$^xQ f%BNıű8^=C]yH<ij?3~Ԅ;~>d8dS0~"A',x\GM15~ A<"Gbďoo=؛=n !`AkIN~'}E WwQw`}$-v}m۬{Hq[(R[l&b3~ ^bDM^qDo/&8ZbJNJX)qGø=ea,X"XbI,0׊UIH̓K̕#]0nl%n+fɩbK̠gԢÆvh1IJaD4M4KL0Uz$4јѠaJ&KGAI\uaԞ&HLPmJTOU5DO@D8U W eq\CYJ3M$Nx$JP\'PBQ=. > stream xc`d```cp``bPHϩLe;P$d&06/e``2sf@JFnIGC%_s''@&c M(`Pc;|Vf @;9x9YSQ F'LnZwS߸5<*11-& Ih8"Pi.u?t^Y}髌cN39ŻRe7>bR++m2Hr0@8^(Ha`cY5Pq`baHar7b3/10] endstream endobj 229 0 obj << /Length 247 /Filter /FlateDecode >> stream xڝOk0 :&(ױn2J!i nh2d-Iz$x~!`BƦicuI}Y)CE7?>]\O<y'=qQ:ۜ/rU'!@. (lMb#l :x $Tlsë^u_od%:V`Ȣ> >>/Font << /f-0-0 233 0 R/f-0-1 234 0 R/f-1-0 235 0 R>> >> /Length 2309 /Filter /FlateDecode >> stream xYMocO,~pd !k݌E%Û$@=Hٚ5Xf4|],VE6g57o'z~qb|U=K|~^2k7/f7{|U'r$O>{zEy 2d;_OOQWe93n؜Q^>nL䯰rrz귋ӧﶟ>_/i~zuyuu!?=j3|g懟^썼1fvpi7g,p>cgñev6w3\T!%Y"g@!=Ggf2h;6370/o|h |boW~^,?YES F|Y=hoǣyGC4z<53HGÿ_>o^w<ۣntsW@QMu#/mUL"$PLR)Xi㔊vh&B #N)]ec2'J4ҖQ vCY/JŻ_>[F VzaRRɌ]ۃap >ao 2v*Dɶ 8l~ҚfoSypA!k]Ӷ<[I!V;)oL*{ dBQͥ2w]MJSlg%\pſ"W B`DpB Hr8(uY h6)5NCP(aW[EʬAhm@wj A3D#\Bhwi#A9NM0VLYI5DT J "惑jK/ZCt2G8j-Tx MZW;X+L4ΉiȠfWјܴqCÒ@#͎ٹ sXλ,HEh Ey/]|B'G, 1tKa\\sۥ*zf T+F-Z%UѴDRF{eM$+` !!qkLwC@8A'3 Mboטm;\ YP|KZ$b(h`l.hE: |hddjwB8 wyM|4Q,z6(uYS7^4?exuLe|xyN>Un9}$la|% c5߃4ڌvUs>0l.wr"Ёf(h~n9OCu\;Q)o핏+L0(I+.; WEJ"hV@#Q!vyO|qWHY` Cu382Xd..#;.kl,f0`r(#B KX'~=Q}m HǨ';.N;ip AdW6!Aj4McaS--Y BTA&@VE 1Z=|=h64} _la "Nm\Y-rX}\ [%Eꎑ~|ꡘBWb5Ui9ud%z5e`~ou0_d͙/Ro6 endstream endobj 237 0 obj << /Length 243 0 R /Filter /FlateDecode >> stream x]n0 yC@V U !=㪓vhQNd\u?xp2xuȴzvlgPq-+'UU:e =Nނ0}I5ySu:i=ٽk;Nbvt>۞ی:NZAUIW}Rݿ3)zU@4F@|>ј9J\Dgid /Mǵ"S `` HZg a~~d{ .wR9o}^2V-xid~(y$.ħ>җ?Ux`!*%;?x<\j endstream endobj 239 0 obj << /Length 245 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> stream x]n E|tq#YtEaHjߗaTF ٹx5ƍu:\>:V\[fѳ,}`YX#n[I/<0y4.uhiz3q/gY {c{eTZ4~TFwy[c:N+kLF}MykuC'' +Ԃ@OA51%2k:Ƴuĩ####<=.Ǥڊ+Vm$&CYTO?˼^+/u !*=#upG~J/jB endstream endobj 242 0 obj << /Length 248 0 R /Filter /FlateDecode /Length1 3824 >> stream xW\TUff6Bffd2$` MG Q`a fhʖ!5R4tKAs?vϙs|9!)Ԭ싶rYȼtsD1Bn RJ{!ps0~YK V} #0.7P\qEVJA6a|~Ci1ruA< w% 93*FNڷbqwcn0+$D{11I $!:;AT~7z 'oVQK /A381Þkݽ᮳{&O{ި=]? :*o3J JpXavE"$Zk 7~MpAT^ފ}HQR2m›;0qKRZg=TF"z}q L.!W5eCD<l͠7Ztz4N^JoR%cP*=j+[~%'Pv}#6y x|ucSUx^]Tr琻5S<X""͞5ۡ&$;b*#!#ɠ)*ѸPHUF nٟ۬vT&6p|0?~y虘Q=.^ 4ۄ."G #9EMxfpAۙ\]K?rgsWCO'5(1+a8/1 6t^\QΫE˳s  <^oƆnz131%xr7ߐM"l㸫`NNFq kK݄]ˎbϮtp-7Arl AFtp~ ̅Fz?H O<P; qB/x@-3BGg¼?BAz( w=ĮQ*L5UG(g `K¸hU(Cc.J,!Jc4JDf Ē)r-KЪwTβVېUt?4ku:c05^4-plS`VP!"c5lo` Mc5jtT(|Y B{WNZh.Y_Z8WʊYYx}KggKݙ;:g ei/ϚW6/Xn!`l 7ّvh rK)%kn՜5Z5sNi%Y{ʼn{moas3-Ź"VXAc\P1B_A0g0Gt׬_>yVœvZ#ҁկZ.~Xf@TiPh=UR6?r*$,{/9xٮߘؒW/+19^s׿j?(-ܛi;uLԩBE΋^VS{w'W|}sffMyd(??/qVN.QHtY&"FCz[7uk,"S\Ǔ +m>UU A\\VE7Jk8>2XpQuW걔wE^v:hFJoR댰qɝ#|l}s!?Q<ɽQS|ws4 Nev۩/צǾw O Z?rԿkgh2:g[y0^b[ցE/t2*gn 2ۦ&lWU"H׏Ž^eq?[ Sjx5om$egS-Hwe81܂lcB #1 F&ldKvGl+'SE1nCMN$=Kfyh%rq .+pi"~Z@?*!awY8-#r; :V Woȯ ~)wo| `'%x@˨׮e?㇀ V88 4Nj`s=*ް:-i̤_Cv{lpgs.B7p|f φ=3G;LJB*8Q \[h4ALA3ԢjJ΄6hL#y7H"4 XR<{Œ" "fb%(Ğ ÷dwFd d)6kOg @I M]@"$fxs 0>] s7]̘ |3 " endstream endobj 246 0 obj << /Length 250 0 R /Filter /FlateDecode /Length1 3176 >> stream xVST?߹"e%Q\0b"+ (N1ƌQ8vHGSB4hVE$ZQUQݻ?ͽw.BDJ .W qi!./i eR&$H!'8S4ÙL4w_(V?JCU2^^ۈ!bg2#!4b,os 3.~[.)zk0lGPrBPF">ߠǯ0ʺu-+IVdǬZO獬֒ +vlMOϷ&J6e㪕}I)eŶbCH-GXlo+rQ?NL&ah6EjGt7Yߦjk}$4I3~ch;gڷOO2ye-kvY=U9e4 ylؽ#G­{=vH^ pJ0*}, Pl=H#:@fG'/oe}9_0c=p~^k(-Y>4S*Ld}ի aK#=|U:Qx|ܕCӹ_bG9(8 Clp#C~LWgN֮ZT2#Y%kh"8X %.o`>; r"9: Tdmv0|)w::8jx]\RD⟩hѤX$cչ9ʤ'O=2SLH s_?>oc9c&7XKͬ&8@-BD)<4n+X. tj[;9,ھ04iAUќWt融NW,l0D}T |h")+=@n=74ȬMO¨meO{ xB;"8uPhHW^9}lt {e[aӼMR_T1޿)xh\W (l]+eΆP֝s$!1%!krϏ)w&q]A~N .nĜ r8pkKeM~5atcbQ5ʽP*\vXCc56]#!#;i"br70̇,(_o7<{$X:ܟ+vB=>{O;> xt vgC 甫-9FzIqsCxѐQEޭES]}%3,MMK ф_ ipʹt6;%|%Y#V2K!|'&5$!1F-d~"H 淓H ;PEye$"l䋑kKC"!pDڄ}!!T|>Dz F}Uj1zHD*^"7I}V_6e endstream endobj 249 0 obj << /Length 251 0 R /Filter /FlateDecode /Length1 420 >> stream xc`d```cp``bPHϩLP@JFnI C-_s''?@~M(`Pc[|Vf @;9x9YSQ F'LnZwS߸5<*11-"& IYMMM̌ԔDELmW?/]5W'}fnSܾEe\cb Rx~  pC<}$NǾW8\N ${?A~Ȃ#sC ^} Y endstream endobj 225 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///2_feature_gallery_export/D0004_Relationships.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 252 0 R /BBox [0 0 800 600] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 253 0 R/f-1-0 254 0 R/f-1-1 255 0 R>> >> /Length 2483 /Filter /FlateDecode >> stream xZKoϯa[~ X!6oĈR2%N|կ̒K %J= JpBaIF>7}ъ +v&eu3Ig|4⃧~,Oao.:i VZWo\c5$p\Y5wob+ unCu~ffsoe|OIO~k6_z6?[[s{]")˞IHL .Pw\{V?bH0o+1[I&c6-[J?en?[+(PjndyIȢ";BAsL"SLޟ0)7f7!DW"y\xM$uқRNi' Rj%A!0^!S>')Wr@"<*8 *ݍ'UCpv'}h#5RHJ`r~/*VFt X_a#*; TX& ZR'UMqSR=D2<銍)Ge,.QKFrl*oFDn-_o}jK*۱q4;湥{F3H1$Jeگr n9@w0L1%: E9YdGrE1 g@NKq,b`j/$4_p{eR.pǺFA%Zɚ>ܭM;ǽQ U3dpP戃,(*g,yr;ʑ8iDXHCMRiGD2B}M`|QL*7Gj8ٖH~hgQ)[QLH͕sP,W ,DlQ*j[%a"|ͱCW|-&U$e毒En&<͜RY*TaA#LB#GIW 22S3C3 9uTQtdhKJC(iM>6K_X;A{'Z/=X=T,ZBNsI {"Jq)%⡕0M0$:.Қqt>N02v# W wW1,x*Ǧ$KoҊnsw ):ߑ c8ROTKV/Q`DF$7FvNyƶ*&D2Pn'#\0f|OIo~irun'KrܔЧࡏ΄)YJߠ[ W;k'hrIg-w1δq^r4 3G՛^֭d}irc*ًoF鱿Qa}-Mt+]vz*+*>ʒN 10V7z(F^xtbfPr|DĘHXLNiӮru;$,*ICV*Ϩ*DzlznV$Q?0xP endstream endobj 257 0 obj << /Length 263 0 R /Filter /FlateDecode >> stream x]Sn0 +t ;+`^r6 Ktj 9W]`ƣ!9vfeG4T\Kd;if4V m~VnkZFb͏dAgΛm~oO5ݷ~g?Rc }[v$!r fh۽io8{8PUi Iq=*QxWף/_O`f$3g[x ;OIq=ЃG,I,'=^K]B_$}^;Cs Cxp8x~Ixzs?*a̜4'jCe-d?-^KK;&5g*Q endstream endobj 259 0 obj << /Length 265 0 R /Filter /FlateDecode >> stream x]n E|,E V%RnCuRv2LJ];8ϽW(l\F\k4g^T5ѬYIQa[VzfѶP|e|[Gip '+Kv/: ަq)O:+>-.A_PeA\'k┳3:V$-4$6̆b7iG#ijԉk9 #Gr\qܐ=ĬoH__R!VG9fGQtH{qj{q (55Y [\cLm&:5z0/?# endstream endobj 261 0 obj << /Length 267 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> stream xX_W739lH+E녥H-V@AA D(>PuֻjZqǪ녥Vī Z+%(0~Scw|HbGJ'd%nDBhlrZ}%|ǧL#K J.k!.jNIUxK>H@q_O QJr=^{$JGq"]1*NN I(@=;XP%[h' N-.4Gq6YML тVWjxZae)Р.:VJI R [IBɍ@q3_ܗd.&Qm I4!> ^GL&b phnnƀ`)&k+k5$aYyR+}a&[>Jc ]נ g3 ҌH:kkZQOm3JZLFdN4J24j7wu"a9wǏInr8*X>8d7=tyQv_XY'%Id*&R-NEr76;ϙwd}Rqvl WmM_S@k-†I*?lX-Y>xw&^S O45A_4&QXF˒EKb u܃=M+3b+W<)V~:;nR 4!Eì3O~z:+XʛWѣ2F#7gp^| y[&..xwX;n|sn,*a#=}>*XXV^dѳh[d}1,|Qߏ66ft:+ڢ bٲ!p{6?"ųYMHVuJ 5^wH?pZ0jg;PۄB(>![)>Odb_1^IfPhD@$\q֝K=":0MWΤ OͅiۖX1DܼY X꽂rvI񱥖 #^ea/jW*G_>G3g=[˙{C%6:nDžW*c6b,x&Z L,EssM?n,`硼S53bĩY{Fӿ˪)>7wo vZ(uPom\ʵ cdrk4p"2enXe-[&^ʘƾ*_Hϒe.cM0p>!¾83ݸ߰6cHmܨx^ܞ5n mOO=eFlj$G}z ^n\={/^EP*|Gsz:$x]$4rG-Ozm~:%)jk W7g.|;&"PNDup#bQV4zv'Sk19hhk15p٧֊t#0Nfg6ycV[Y:Kl.M(X aDY@qz0TOd5osxsK9Y|7 d}Kz?" q,?(ٜJ>PoPpvl'n4͌cR5/f۰VDY΍UPȣ @wfk}<4k_~sη8ԉs:f\ϫGN,p`buQ`3|#ڔF@ȩPj;",b,MR_!uX U\+x;Y*X){#Wi$= Lf6x&@̂bZN ^~^f]ZzW~ѐ-U4x*铣-e.>\!Ij>NM/=- g<^GFxK,t/yH0B2Ʉ=2s# !e#E!OMێD}Eh$:zVM9Ff䗐hEE1 i4a !a?)~wӳXs #@6!aVGA {(V!Rvb>Gev@wKHج{=Kq:tDyNHvEF5 >P_Ĥn endstream endobj 264 0 obj << /Length 269 0 R /Filter /FlateDecode /Length1 3156 >> stream xWyPWPf`z@C8"s@(1D0PԀgQ$hn-b#FU)_$U[mO}t}{!@ђ(BIy;w =!tv²WʀU{}l}Ihlg畔.,䰝킅lvIDA$!6ld½-h'&>X r` IAU@ZWc}BmwTG4BR9$⧓s8% dvf, F&:&a>2/(뀴glqZa _,; SAxGP͚4cNF"YB4 nsXv>D/* O_Qk]^)kz$?dY"CRWmts)i81519z"n0rYB,*&I6d*dcN׍?_H-};__ߙ0,hvO՛$*1$q/%[~n,սKMQ lIH<1*9fO1z  b!!0_QT9Jv]-`xTN8@:;?'ҹKz+"ݎ2_aU(c 6Z$#GbY ɟ9͜)ˑ|D{Q߅ZM[VWhǪi1B=q ;’;n,Hr}ǚ֧[kkkgKvF 6Ð{g;0&V􋪁 5`k*Ccf%=WU-pe$,F{`(]ݺW~ dK͙vnjoZf4#gL7v.bGc F$Já$H!Xp&* VsQGIv]~&OAwe[jWQFLHNF97DW HZ>u6X#}t o{ﲣ̕VXh0\c-0Yɖ N_ٝUUۋJ~T5sKIHv>ZZBmu|2ON7 S-v5 *)'lm͞= =2G l/(ߟ>+>}9Z8{]?DX7^.lUkJ2e|U[ǁ$R ĚY -M5nሕ);5#$6΃X9$#Gpɏ3r#}pK,d(S}*E^OY%N94ϥ{w9ۗ͘[&ܱ0@oD]:_D.d;V~gqɱ<5..%%..uStjjTl(_'ބ>g }0+Y@ZC#Jf\] Ǘĸ U_.w~p7BԞ?^ DeԿ5!?T%1?r)M#.o4gl'N߹-mCu}G1 7 znI[dKI8>3I m'P Тr2DǗr+I>m"u$Z/WՠVC4"{dy?{hhdhH짛txh! y/ 19v\1~kKЏC?@]uyjOB \ٷ endstream endobj 270 0 obj << /Length 271 0 R /Filter /FlateDecode /Length1 424 >> stream xc`d```cp``bPHϩLe;P$d&06/e``2sf@JFnIGC%_s''@&c M(`Pc;|Vf @;9x9YSQ F'LnZwS߸5<*11-& Ih8"Pi.u?t^Y}髌cN39ŻRe7>bR++m2Hr0@8^(Ha`cY5Pq`baHar7b3/10] endstream endobj 276 0 obj << /Length 389 /Filter /FlateDecode >> stream xڝRMO0 W9IuE| ehWi1$$8qg=#<9KqZ+*+@[o54e>Uj0rYou5(ot+)]x)%FS·/&#X_B.R%̧ !! ! @X!ɐr_=#8nuj'd0j#z- |H8xT5׵ƷOtYSjiM M`S>02f]|*Q79+nd^6;WcY};'B* u"4Uvc|v]^MflQc/g8 ë{޹6?Sɘ?KfN%;$FR/Ҙ\ endstream endobj 226 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///2_feature_gallery_export/D0006_Classifier_instances.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 279 0 R /BBox [0 0 800 600] /Group 278 0 R /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 280 0 R/f-0-1 281 0 R/f-1-0 282 0 R>> >> /Length 2182 /Filter /FlateDecode >> stream xYmow@P;nAZldܸ̐I'9I!i9K O WPJ_u鴠7L7:TpLP_ZzcPRN+ V=i4kziV^uG+R{?7ʸlXL0:;z8>G9x9]ǗKN89OzZ8lN'YaHWB@ (Í0ʐZ233)hNUDtFh#Mֹ~'/pg+P | ە 2(-~Ooq5f~i +i,'h#] \\=-6!gS=jdv|=ﰌo`? _2Q)zQ7ǐDRG)ʁ| KgHh>FN[cQYm>;m;d y-제V:,-,UB@EE٬2b{bB8;(0P<@T4qpSqlqJL٬J7spF?1@B䕠vzi=މŐ]CC^5/]\_HtJ b EjҖtγfLQO3^Kҕޢ$ggC=:ZiGz`Ј{AtwH0!shJ!3gM,oM!I;s8g+1wzB@E2|iRB{M]`ڱ8Ȯa~-C‚`Vekx?Rq^7E}i6T@TaG?g g a]wױ*h;rhlʲ)Bf̬ùAX϶fƻm-4@&T âض5up1h)6 gU@jجSKݽ(Ā>=`,!'=ʘm{P mZ-A-ϏVy [/n}=+l4!J~Kfa&+\2 V dRmH Л2c$DPH$.)2I%Hg K3ѐ⍝oI"9 3# _Vd1nWT]A&ǚ01gm< pr}^zw|#1kB{&LNv9RprdH[L(I嵨8klaFP"*/.h])eQ`Yv# : *y:͊&4JW`" endstream endobj 284 0 obj << /Length 290 0 R /Filter /FlateDecode >> stream x]Sn0+xLdH&` H.>$-X9bIN=H #rY^g\nf!e^Mi.v S}}wnעL˦<.EӘWlfSi>?/GR~YT~o[g5e^pҲ߷U;FA/kklMUM3B9WqI7m,ZP48 w jB<vKMV!iOOБS㡑!4_/Ç0 0 0 #rzxyF`>ďQ׳G9-`,bO$0CF %n8;[f`"s?xK K Ks,HxpP73 hC |v1uPӬwn]V_b endstream endobj 286 0 obj << /Length 292 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> stream x]Rn CV,UŇ>ԴZ1]6JeR>,lJ?`/ɂ# igmYvܿj9y=$Ѫ%nj 6 a謱-b2Ƃ=a5 y77CXPT¬פˌ`i(sCyL͸7瞞0{5yc^g=9'W?ߏ1P6s~,4xn/)c˳)n1Α\=M endstream endobj 289 0 obj << /Length 295 0 R /Filter /FlateDecode /Length1 4972 >> stream xX[GA^2/H ÀL\(> "E$BP@/!\qYUqY.M`5_Fytz@|nw:9 !9IH_q;bS_"DV'{R oŋGw#{)piR{9gPL1s)ÄEoE9hjݑF C24 ٣Z0a' nL0J *{Ä\ c<ƾω䈱$!. iݑN.:^!hJ__E;3jTV;;gmWq6~'*^ڙN7ke`<:^k^ tq4FHtz` ~EhԹk9`&?슋[1f!}/i^@qlQ4 փ^/SңjU;8;kԒ1ggYVq ,qGw~? _sFzm/Y_[W69!<8u̶m[;fJ4m5dǢ꒖#3`b"&̘1۾:$͍ك䆐2B ~JF+=drQz>]xDSwmwGҺ\%ng^!$4OS HNGx.K"דy/E|ѕ7fC ˅/*,=Uo9i0sb`@+t'z-=eF§ K6r_8jfg?u'ߓ2ٯ=r29aF8IN2+<::|VOnl\ {{L Ǐ?аRԻW1Yޯv?`V9oS;j'-/ _2jTuYpP]E"8s"n|gzs 'rO6A9lG52@ھF{;[c!.O w vjwPIgп ]}Ҟ<[$ve SX^ރ7K,ks?=.vp ~wbícnۧNI:AGp 9#P@8O-$%V>/wo{f)宊ߪW_&,3ʚ_oл3^yYMo8VU^x<3Â+`!ۊVL@w `ae@S)>wqkthܸCI l#*!_ F/Yg$H8ʗ66[ Xg xřH"|p۸='23%/ςIW/#_ofbΕ_a% kzHB6늞?~j^i4 y8obn,Է`afQ7zqZf6R|e߶4F7;x!>guF^iJrvMOoጯpYo,']٫֭E*=v\ieW3AFؗ~=YC{1θMki7v;m^vמ轇⩢uqNRhɥ"ƽ{-i^4&8%aJݤТ:x>N@8`p/*# "dQi޶! v=¶Gn"Lx"@EcMYKKf˵k`8Pp]AjWVx@Y:@|*CWWsU'RMPykW緿ݝ}j9\Ia T3Y.e*dB!UeXW<'ɵCU؀˒-)\Ip`ޔ~ndhb ~NO.f|7ħ/x Vj$C7-Vw[KGL,NM!ٰ< /=N4S͖VkM/G!xxmʲ\)=}6T?%#GО^@_q{BLT4VMei(wqy?kU*--J5an6ѱ#ttw;YLFQKZ%!A?@Jf 3'(hlwpK $ík&*z= jy- = ZwYSjˊ]^e= e^;+%.=j?:nϵӘU ;v 1jduE:]@xU#+ x 6(W ڴŦӇ _0ͽ u5yxSC[[j_#_~z_2ji1s>Ž}rRn{Kx%WҖYZHv5,9O/q"b+^PASrrӓXM'$4JzBkk%B20hkϑIBe8|K/_z/`RZΒۅ+,k^'gĐq}ul>70%EiYG?9ԗ1PJtJL}2^IwLq|U`GH:i Slbޒ9J8KU*@3p^.Jqkhs?j8@/n;qNQƿE/u`S8ؤBb+FjRI˻R|RI8Wu/N>@pXˍVIP{?^Y8v⃣Igl=aջ!n- 8BUr,RsF~`Efd. ?"chh`B;R$<0\0 3Q]`ٓޝ BFoaa$A[*nH*6]Aq-r#~h1فKa_R5s 8`Yx & ;G`}D P }9# ]H,9BS@!;貃5. `=> stream xW}XTUs>a23@úÀ|,(jf( !b, fcYh6hEf>})>P!x;cb=}sw~\@h`0nAaүOmK羪/>{-);ӻEBnvek~O3Ԯ-(Z }9 ˖BbuR3i&b l4ڍFx/Z6m :kJTf2r{<%FQ>do)e,Zy_rݶ'z1]ۛgOrދDyv܌hMI5]hsQDk',nO`vމyQL՛yӴa*H{f$;02fnj B1x|Ijyjjzϻ6X\t[q7o?o=G>2j  @r ŢK/^ϣuaE…+rX'^S/oC'vZSFFt&! McK]&;k<;>oL.; yWڳٔu 7](CKu6XlA-n<*b/ɫ+CUS2> _\K5<4 zxy>Ф8hBcܰxbE,f]BrqN*]gZݤa>Xϓqv|g!JQ tAnFkƏfqxnx cT#Q)J3{Y^ѯ7xLhe~9o 0O>x$MU~Tc3 *F|8rF]-Al(Dl<ʅ׎|%cgep_?Diy5o9I/ZܜD~njJcz^9HW<+>]5X)1x5_wNǝ:wchp#".JIBIgMiIۏ ?^'^^^U>4>' Ϳ3v|@3UUd*399##99sclfflLfK[l:#)*Ye&Nۂ;wVR{W8Wz?Cq zFG;Ljfi.e7P?HO}Xn!y)f!,Db ~{3bVf]F?TV1Ɔq&][-}%Ժ#"{cJC(y^2g`OC jP(nxUl/ Q\=0[L0B% ib.EHBk!um] E4X/1F0mi- ~r?:5,r> stream xc`d```cp``bPHϩLP@JFnI C-_s''?@~M(`Pc[|Vf @;9x9YSQ F'LnZwS߸5<*11-"& IYMMM̌ԔDELmW?/]5W'}fnSܾEe\cb Rx~  pC<}$NǾW8\N ${?A~Ȃ#sC ^} Y endstream endobj 272 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///2_feature_gallery_export/D0007_Examples.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 299 0 R /BBox [0 0 800 600] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 300 0 R/f-1-0 301 0 R>> >> /Length 1706 /Filter /FlateDecode >> stream xXMo7q ~i|@!Pԅ䦲Ӧ(Kr. AΘ>< W B+%VF >S%>^6<"~n-βB -K|m޽J*Jpb֛2 f.m%E/qR[ xImsrP P˳]sN[n;Oi7݂lοrj1ܭІx^@L(A+( ZQ*swƵCwxVsVACW琟KS"BZObfRKٞ\Gى{,R64h0؄ O{Ӿ]jC\=-m5([E_&Q&Hh@9̸@/b77I ӛQQW (`U@k6#hEQMH+3"nLě(c )8pRʆCѦܑ|[G );Rjlr2F*$IK[M$y8XL*&*νLɪKNSU3i2L2 V2yg$'t ;N^рĢ&(Z KNL^u&0<~ N|:'ϧ˕xt>;ScxYճAHttg7vlǷ0M3aW;fD-Y$7^Z7V&#R\ E@lMEz i2jil(UMQMTw.6#xUSv44ǰ!(N6))8U2xKeG &2w$Em xWGT87GSWy:[Qv7x5;60b1nk=s4含w(hDD~4p t1 E\ \Q8炯، mauAQv=${#Jrwj3gFCyQIpܛ6y+zQ9AU58XX.2bw"E4-o [=,R031S qASpTN Gk75QP =#Q5~9B5NLDV/K^g~)t!ְTnkȫ8AƘ5Srj2R0f\eDŹYCA/֨-1d֤cXcCe ^'4cM&50'f,p#4uoDi LiSLCF_UirT57(,BTFhғ&& }wТjoQ\k/<Z%9[ ,1[XjwЁw'I2qPbR7wMu̢T}=l@ hR0[0w!hC;^؅->{e1'0(ӲEňċ:BA4\ BnG L66n62~G9@2|{uwpoǂ;3 ѯ5%~@X{_GV蘪AƝ;Lѻh;1R"O;ޥ]빏=]yyWv]{9ƍRZ?_ȯI endstream endobj 303 0 obj << /Length 307 0 R /Filter /FlateDecode >> stream x]n0 yC,B E! /NNKUfaҎ\k(> stream x]RMo0 W*( I+EHSwF=U'~yy{ "5Z3^/v.S۱ Hɧu^pl}? cHW<0㉩5/P}*҅nD(ru~XmJS|[9tc/(LY6`ݿj)~wQKҲLAZe0Uq ֏ b^eb"̼&^IH=dH)fzGXSg S1d/E})R.{As:&{OM~$בT~kW2N~,}cZg~Hy)PV~ݯ endstream endobj 306 0 obj << /Length 310 0 R /Filter /FlateDecode /Length1 3844 >> stream xW}XTU?{gTJRflu,bu15$%#P>Q H \ʏm%aY5WS  iuKJsPc*}hُgsV*5k8ЋJ[q?GGʛv.ZJDqKr4A4z?L| c^uA@B 1*wwjLy=9o[g{ӛ၏uc+)!]bҀOKv[^ 2B0x2Evu:^%aKVz\t`=GlY Ofl\uxMޔ_D\T¡sBr𘓳8^>Zh ~Sj{x1i{z#&k'_^VVr[j+/4Q]hħO Je\a\jQP-._# Ih$! QFv~KxFKa-ehGz;Rڢ𜋳1?gɰ8Ք'ol,;A/ ~zQ ΎC6Hj`\}KǺ$??%&e-Zue{G}XZlQuu.oHy\7 %0J!  29(c:`hbFF؄LmظG󊮆;]ꮴNZݤ56Hq:,p{: "/@-L0 GFbr~ s"`!SaP`t^ s}6cf~ Zշp:2{E] pCOu8rR12nA?wv<}ώH)e7RݐF  tgۂΡ>==O M~I?.GY$'pL")$"!Ξ.3^K6Hq /囹z {k8C[apA`o+ck|xhqдangB;,js`;s/8fSP*2OT_k]+5; l|ed <ΎZ`s7ƕt~Gm8^Xkݪ7].b^G^iCok8!O<$q1>>3KJlXnSFooK7O_uQ6ZMGnؓ:#*A} dVxhb5c&ˋ`7+l/ב,]XEow\a9OwJ $^3'4 2DQȍdhkM|6(yx|;}<ˠC` B`?%4.X*6&Mpޱ%4񰟶0^uz(]OvJ=e'iׅw[vIALbA|ȭ5 XBl9me]^^zM,lM> "zn=E)a/ p@+F0rF (4L+!VS`wpL`}nГk;\Bꗟ9å7ć>Q:kSr_w^o6-~o9qa-S1V 1M>t_ȥ^ѮCn.;'S#:,K%/0BB_?w@.~|Q""mC-M%[EH^3Cmd \g"73 $Nf'd[mާNLHoX-ϕWڏiPݡkw]_N:;COvo^~}ȁUF y69|unYЙ$#Yl֭!xj< rX[?ՠt~,~9JBY 2^~4ŨN0ϼP/1dI"a~4Őw,cf<F/Zaߙ4R@C/9cXP'e rKᤝZ.swot ;| endstream endobj 308 0 obj << /Length 311 0 R /Filter /FlateDecode /Length1 3264 >> stream xW{PTs]X%.YdPc`P*jQE A|Qktj vL8&>4M58#ՂbMQĸ{%1}zv{}܂k5Z7,|iޕ_D%mX$ljg\rzCq򂒲uh|%9kkt#h\VSV14 @!Ձz_&^ң`F'k!C`(n1KuOfJkC,[Ζ+%lMn@ztiC3b, M?v`pfT9h]<0Tu3b 9O%]%7`sQ7ۤ:$Ο 'ޭ%3 v[Ƙfj PhX-6Dm\w̜y+A~+rFvo!wd Υ2V1wz֙r;R GWRUlRR#ؼGƈVkA4sVZ^Z{Fx{8@UI!{iI_=yCn\P2mQtl.?p.k~/nQKE!ĎGF&5(y^Xĸ\wwcv/M;֎/ډn}QkX@5C=zۊJ>W (&T>թ`{~L% 5# lS Ī%,=* LÃ,*?zs[mOZ>3廩L+mcǏ&ϫyC[*Jard}RAP!RyE$| t~bO0^fX5",c8ߌΣP\?k?~8CJ||8 T2 Y"PJ;^jۺ2;PQkZG(o4n+ AP ]1w7*׍pCWNt|TrHQCS9nм9nYrv,/eNL2QAijE/_I.$*%F⨞(R $0UɠA#{oea.  KW3O_|'$/YT^# J{&aRqb=[_0g"oUtlBnU/r߉?~8~]W'J/ l=z٘efv=>&ݐl\}kW5k_Pw6L N)R"h95J0+ΆTb! q $I/v4wiHu $[!T[/J UPHULx/^kXD%60Z'K3ӻH2"Ux<%ީAC 4Sӗ}P/:apx7xc,4 endstream endobj 316 0 obj << /Length 248 /Filter /FlateDecode >> stream xڝOk0 :&+ucVzI;qCo?'k vN{' CՓ E\)l16<ݏRjCE7?>]\O<y'^z7l9_T?d(NBe Z@vGsV&0P}b#z}UбC }Xkg̓PC@ H7H2ϟ|i/ endstream endobj 273 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///2_feature_gallery_export/D0008_Activities.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 319 0 R /BBox [0 0 800 600] /Group 318 0 R /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 320 0 R/f-1-0 321 0 R/f-1-1 322 0 R/f-0-1 323 0 R>> >> /Length 2790 /Filter /FlateDecode >> stream xZKϯ#yQ"tH7*IYY{ΐKR U[S]]]z{7A~_SI$U3TzA?woՠV_̮~OAvI^Pov[XM{qwnޮYXڬ[=ot\s}c귵ߦ->oGmo} R2wlb[Qu &F-[=oV38?ulWCr6zeV}ZR2.?Q7BΦ9|9^-ڜd{zgxگ5}nx?~z˻N)^^~GE/&΋8;訓7䕗J)uZ lZTg]}Z#{`u"c"ϸ< TgdG,j!9 lF(egʺh!;P P*[.Ygi7 ٬mj͹2!ESr&2$Şf%Ƀ#y@AE8Xrmh6y]kaTO(MĨp=5&zcԘؔT'QE,[iĩtuIec6Jg#B0dO1oNjKCtXݖѺ6G c]{ (V).0 2pA00DǢCY莣6MT%1R kVZ4e&"ypllFe7m5!1_.9!kvgyFvo%֠\G4_3;`'ktuLvZYa'\ӏ/c9@!!H4Np$V.NQ*Q"Nu;NYʹ*#N-)8ѸFE7-ۍBnnWʗSqlH st#;$`Ձy. 2o%s`x#0#C8#`SAMq0\MI85˱ҺlCD`-XAT6.:b0mm掳1Zk]B#fHH'g4[ y՟Y>T RbF4Zp40J$lG҆:aTN~a`ҠIQijv cFB `Boa[| UФE]TNt Eg/CC֊.G=kF 9@.T Lڟ(k/12/ cp %pB=Ze,Ep-- lHdDewYŬwd*{j}\U.S-m\vԝF_x 4C TR>{p[eiees|7gkrG~r]u]\c'=_n.h{p&-s.^cѣa.רV닊< hUxShҦ0< ?ըMn g4kEaزqqvᜤ|f(nJv{D߯> stream x]RMo0 W*(*!p؇ 1Qb //<7~\eg*ѻ|dыC!hۍvRp-+LfQU2H7{rsBJEq:L~`\Եt0t/]x&uۧ?@t?%;;XBg!vZVP ߛ*8wEU4!*CT$ğ?!?"ϱb{=j8<NG|I||#a!=/1*XS fo )(p_ R\KQ- z< =`MA}jƺ}&ƘOGsljQ f endstream endobj 327 0 obj << /Length 335 0 R /Filter /FlateDecode >> stream x]Rn CG4eJ/>;}Y6J.Ź{[ygʭ&2_>yV8N!"%۲y;G\ָݓGx`-__C Kֶ܀Mv/Cx&ENw&ݻuۧ?\QKz6ACXS-omxV2Z=D֨Ce njSHXֈI#QEuq IcIcQC|E||M|> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> stream xW}XTU?{g`@cfBfms,b11DDCP> D` F0EpZײL3wWE]5-12TR4-(STbzvg; ;ޏgFIӈ L\&#D2Ko((ovg.IMǯmAhX ΄2'3gemK>̯|T#41U9\ y?̽`5 I3rE dk΄rN N'-`܇.K:5 Es%$OK9'a7bHqp4lF(5!"Ts!8&}E3?s#$A CC]ML%\/744hw|iJ[\%eƅU>B¹N$ Gpp( rtrwHs[ |+CR#{I$fkE2(TS grr)&6.vzdt[X30Ad/kI0!'vu_У JuZTc뙡o'eЖnR)Ǐ_==w-0W]H,4|~p|avtAjFKzj\iwW痯E,^oTU4ԆRS@DMR+yy 댁ZL)1?sNLBB̜L-ظw˒ֺ{j]ִӦHk]ޠ[obYp4~`Tb\kٝmZ:&kҤ;8LBD^ 3p~ NgN)aF1 _|AOmBpFJ1\4JB7=e3ZI?*osQâMY`;& \$b8ij)Œ΋,{< 3:I`op'U~36жK#b4@qguZ!2hh_YJor^d.7r,'i{UK+Wwei.DR\bϙ+*ˬV'!j*~vVC @NgF-LN^-f(CQn:uR(զ{u`Q ¿HQ>#cx&Vbq|g޻}:GŅBlE:g?Y!v邐Q"lYZjäևPs.Vl}.}患حk_; IX%8gRb*_;`JOku ]p+' /!9vߝ4}ҁ~H,gbDr}S#reV ~04H >@֑vDd& \J-ɳ6^=1b{՜T~b]ܽ,ig2]>Ӛb)-1w Z 32F&\P[[v^' dh"Tl:&D#Ɋ}lkwU/2G!L3Y%-B㾄"'  h,ؐ;ʫ3S~kOӖYė+[19"^wGºƝD)b.+pMHi=vh,뿉e΍uZJx=~]O[sXU{ljBo)l->N~0x-ÝB {̓e9ۿꢷ2翺rV3wՅr4Rqrhcj5>c2UkFFXS}=Lr$7A_@:C/68z0 $ek-E+e<|#  ed-jS&!$hH` ,)݄h ֎)|_E!m.淤XμGlY mLUxkʫx>.*>$<+s᧑׉``y!i~{da<*2cyCxV!z\{ UmnLؒVӁxgqρ =U~A]P^?/TSx p'KU䒘_Ȥ󞬩s&9D܅mb]:Je ۺS $f*Gƌ#N3܍q~6*b)Fbue'[]/lQ?8%[znWykfUE:oKY&Uh^z eWĒ DTF|-x%%-[mޭюp NV{%?4U pk7#G*.~ !2ΐN(#ZqRC2F|( =$.n\P[НxlL]Gݲ SҹHhWD\<(jR(-A5 mbQH&{rh)$D1|]0\Q-@ N4]bĂ@D8&f7@Ke`J*Xxޅn"HWX|2>)sSC`y:~ѠX`}%Ag endstream endobj 201 0 obj << /Type /ObjStm /N 100 /First 908 /Length 2499 /Filter /FlateDecode >> stream xZYSI~_Qo T111 ȋ10<Ȣ4 jBj6?_VKXG[v($eבYWq&`B)+,=f ;`mK& [VD@4`4EH c("%̒)q4""Y(+-KZb> #3aJ ILs)R֚kF:L[Vm" fP-\bZ+c$΀(>h0XfD8j<+_ukK4wTz0 @bY@[b$R9s2ԂvK2IbxmLzmw[ p wCZ  ho!.:(@MAF@O%X\a#7 E (0E HPh8Oz-i#$I sdH8b  ZA!̅n$6 k@~ l1Hsɯ&ӧUwvTOyRntSaխ?ޝs}vvwTߵu}ê봝Iviif]3>[MQ[o#DN!:I|>lܣx_6[wOlbE&7]_%odV&Âz޸k57w)[D>39hTwi63]yzkB}rpOw?~:/Ff[nsDy= w}?[n/ҺocDik} ryfE az~QaP> Z0:(611Jd/b3ERZ@62LJ4 f$(e39e4Gy?˾{?_=<]?c=l\%,T͎vpc=YpEX,U5uV DkV5ܰ*P"5{Ձjiffd&bp_LJRMٱӫD_ۚapH土Qڎx׊Vz`XU\pwr*>N9)L/Nxͫ&1q.S?}ޚ3%j^֏F\EB$ 00"0U V5 !פ_j"^tUUG|/H%rb-zT O)#jkV3d{utB^}zA;C7{=|#aQޙ9o&w߷nJ+*]'EX,պOKdw0!VIy3I04w㯃糈8糔 UY%Y%VgX|O80_/M+_*_vïYʅvs ]X &¬_(9CaqBj8w%߼P2|RI?FZ`)Yog(=krԴu/`(0ɿ ?%V endstream endobj 334 0 obj << /Length 341 0 R /Filter /FlateDecode /Length1 3228 >> stream xW{PTs^޲˲KbrHc#}BP@B `% *- jvLkfl&UɌ&> (T]IG=~ _îp/ج%yJf/\ڱ{l4XHP /,\Z,ķ[tI\EC"QA8 5A dР3 Tv Ce`5<[a9JR ׳r% ΋Sa8ulHnsƘMaL0*EXvla3j i~]phMه#_b^Q-77~]BFnza$/$cmb2ih|d*:v)n}}OI ^_w?5[ٜ{9>ʂ V6,զ["%|p7FsIdo8$FXiBFVhg\iaoŜS\_9nH+bȊ&M j7DUŚ" d6 ϴQ>vls> _PTHO1 R55j)4^mC~- *+,\f!-=ފ.DSu&<1uHRshneh1<v/9֕䆖q])XByqia DBlAMfRaD*$5v<.zt>I39Eָ G7铱ٵ47s(C{bdc뎉"~"^K2w:-9N)qf{ͤ'KƦ 05Tԝ-BA1fwvٕ%cvig]ܲptcGGk02,P":p,&3+o͘[3Y3xl6aAE'ŒǐzQzwL]˻wDׯ7N9%/ו4vpĊ ְxk', 2|/%V](4ԷY;"Ҳ2/H"kxV'U`'v4lPEWՖcݪ> )"̨=A#q)JIR mS8.3VYqgb(]>^KBLOpœ~ʠ=q} fϾ>>ӪF$COBr^:}໨3ՍX4+zx LY9 vh)ws{F р_wlg vwn乘]_ݨQ%_\OՔj0 cA@_&~Iܶ%6^#6=߾'T>T-'>(S ˂Q|P43V>GSG6ET>fIB'd[Ci2zIRPh 7r>h z *ثB?-÷6ѥƆžP׊> stream xc`d```cp``bPHϩLe;P$d&06/e``2sf@JFnIGC%_s''@&c M(`Pc;|Vf @;9x9YSQ F'LnZwS߸5<*11-& Ih8"Pi.u?t^Y}髌cN39ŻRe7>bR++m2Hr0@8^(Ha`cY5Pq`baHar7b3/10] endstream endobj 344 0 obj << /Length 346 0 R /Filter /FlateDecode /Length1 420 >> stream xc`d```cp``bPHϩLP@JFnI C-_s''?@~M(`Pc[|Vf @;9x9YSQ F'LnZwS߸5<*11-"& IYMMM̌ԔDELmW?/]5W'}fnSܾEe\cb Rx~  pC<}$NǾW8\N ${?A~Ȃ#sC ^} Y endstream endobj 312 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///2_feature_gallery_export/D0012_System_States.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 347 0 R /BBox [0 0 800 600] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 348 0 R/f-1-0 349 0 R/f-0-1 350 0 R>> >> /Length 2324 /Filter /FlateDecode >> stream xYKoϯaG~ X6!! (XJ )C |U34egQ{o FݍzV(w5#_G|9ғVWrKūV]U``ds0!;d[^]^CŸqqv#>{vuљ+˷..m-fy*xP&) vpx^SRi首V[edSroU~wxֻvfgF|5\'uyu#v_}\=&q1bB46Lr:N!fJ,]Cϻջ8LSp h\bS3uYr1h/<`b6ʳmx4Ʉ䠬ScѕXvvX´kwd)!OY[[wq.lFGA͎Q^]ZS? 8Tx?^]|zAW?pߟk>W_?y=(*~VWi_FC\RRHA\xS9Y9Kt$IoCʿǁeBn$`Pb6wԡ0=j b2u1&ܚ ~} bA O8a]>,A"0h>ɣ]K[?"3ŗ4K,'2O$~uh=w'ۦ@ӈ I0K$i0Z:'-:Q%oL_RL]{}LomW ȶtP"0MBٮv[v T.S6^J.h,O pPmm&ҾMXQ~Gr^+EM{I=WvOcWyxz+}!yAU;M m88;{؊9ö5<ۭϴu^es-MS㑩sݎ6[1 : ;cY#ihϰцN9oXu6 ZEZmP'$4$Kcsg% @xy8/-\=n:`NC?8bM ܌?niwn#~s"_/t*{)at6|To^>"qRkdjs>yޞ3Ur9KS4Esɬ"̠jK bn"s+7Y4xnDxq;戫-t/m4YmVuni( _n1-\E,'pݖ@(L/* GY%j}}L$Tr#t\d!)<˳GTǏ)gmꂶ]=tp߆5 endstream endobj 352 0 obj << /Length 358 0 R /Filter /FlateDecode >> stream x]Rn0+|JRE/Pi? 74Rq"}w=J=NƞYyyYiu?Đ<^'qjU0T<^<.R4ģ^|iYjՁz{iD>0_,yHW{H~ tZOGRMYnu[E1;3kHI5kW˒jc\wkv180ʌ0mm'<[xZ41S3O#F&7wN0f12A6#ٌE'G/+x#Zu᎓;fdٹ#^KS'H^μCN$Mz endstream endobj 354 0 obj << /Length 360 0 R /Filter /FlateDecode >> stream x]n0 y CEZ !M݅hlF=㪓vb Nsܸq=̦ـ| Tz[ŷ:۲ԸaVU5l{s `1s+NVЪ@{k7!$Qo,uۓsY\%3[\|g0tҺjjeZ$`Z@|>1)s)\202dT39ι_E̋o}?r^J*&>t)P!q.9Y_@rs };t3Oxtx ~/yg endstream endobj 356 0 obj << /Length 362 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> stream xW_TUsA@dfDdf`6Wd$VS$$⑨X +&0Q1rMs}ڮX5{` (W3Ic=AO~9{}Jx(N}:MU8:2({Yɛkཐ 9e̞[+8߀YoLMh/N+Ȇq$Gq p]+0t>#*AE8IG5NvzrG#h, N]@L%Q0$`3@k6 փ7f)([Vx ',,YJ|BR0^gwYsckyket+ܨAo 0{JF=3gSb[@mR8Lhd,%kB' Fsp)?lP!f|my )$$W~KcRcDw+UO 1?=jŁ1eݝzl4W/`65d܁ͅ}yg=D7GA^f;ZW(uf nMgW&guEj$PJ4#; _#i|e:e@Qp *$U8p iWuS?x*dk#/gpwxKIщϋ鑂q.0zxN"ڔƳ|`0dvDK $W;{'uS?NIyiFOnŸ'؝q<9eZ2T5 8O⹠A!fDBB+Τ34fLMLش|\0aKaל[ 2a.2K:9VCR%)4dX 3kTDD$څQQ#Pt!ƥwc0μY.ߢ䅸!Шw߷ȴ4(s҂$̦O!@UUGg"OUU$ÝCnPZYNF.,׭O#ҺNxRFƕd'#Y]ve֦S']l2}*v"\u6D}at; xU2xsIH^Ės8B7)&`[eKo$ҟ]WS[MMky E^4LW5yd+uY$Yk lj* 4i-(.jkNǧ)qoW:-7)ρ')BZG!\!P'3_BFg\mTe雇<]T:I?,yϤ)=28PK{[]fg_1DCԦ}ڝ`Ť g֥X{A+R藗1%2t:LvgB*µt'ԲCZdYO/'HpNb{3J. A=/y1̈́Sͮ7.ʙ_E}f};476 =xTCjAavqDZo(+[KtDgCŃ=@NJ]Һa6N$"ScQS:.|"&Enc?y_P2%n jf[4Fzv ʬYӃ:oHB^)yZG:5Vv]P5zʙ.߹->3oRɠ) 8lٵ[-$)&NٻG>3 ?:E& ?Y2R<%zu9d$Qzn^9p^ Z1uk~2or]^OU)-dn{kl_;u#w0 _kiUQv/r؞U,-+cG6 ߗy@ch]g-߼uX[TAF76V&jguŽ C? 븮\;ܟq饢7o)ӄN^%/QH!)+SBoC.}čU2Pi>|'Y.m7cɊ_Aշ%y Oƻ$p6fԤOgIJx/= #IY"3cj-}֗,pYG_3@υ_$*"W5oFc9xSט::oWQ݅v.=pQr^15>.uoS+2g<܁̷ 㜻58!3FB#k9vWf-]u{I"+90Iim|ND;muďѷr}CbA?Z;Mߴ13}|2^|{;u_v~B[}R <>wܠzȋ$H5mF@_G7Xϭ5<߿F֐d~6~swޥ?ܱ w~T\[,Z$A )Y<)})R}_.T|[YkJ?Nwr.'9"ut*b"y2a,U#]+?0kW^8}u $A]/ +a&v[86ĠEBS`}*bs:@O7BtW8hf :`$vp((QCo,K 8QSXq=~PXc'G}FkY#8Ieu̒8̩P[# endstream endobj 359 0 obj << /Length 364 0 R /Filter /FlateDecode /Length1 2772 >> stream xVSTι.O.wwD4`qaa! ՕBWaP!>PSN'(h혎mc L`:#m$5aR*ޅh:&Aoι{Ao)u<ݿrdgAZ墭nٓx 8[wCG} 9%-n砞W.Yԣ@ !1jB(G4pFR3H E96#=X-쒎|)_çԴZʧ6y @ OcT*:HՀNo:5I%rOX88b86V$.'q~qX_1 ѱd6j6^ԡKssd!v6(d&gg''eguǻ䵩_ 9͢gq Î!ƀ9NoZc9L#2lw'_z =pR/JwV*eX7Č=Mvuؼ4c:/Ŧ~Zތ~:8X!7ΆVg/%_-˧/$7澋,\f}1Ao~`W^L=-L B O фdq8}MH蓾,s}!#J[2=-aT=ū`G[8*qfbjmZ3~/f~b8}Ļ|=iV6~3_59(bDBFb w }}en]#X$.f;ĽB33P;3A>7D&dqq6{>:RøATi;hퟱi+9g\\a_~Gn8P{ЍvأmVm! Ԇ*&/I4YUq_lxWlG+.o󪶤-ߴh?_+?zI׌ws##3)kxc`dz/Ut051"a~ wU?#]SW!2[TpjVΎ?ܛ >|:Pj`RGE/= wxZS|~҂Smkn_o )B<>ÎR<%(gka!Q( (-DD|;'| endstream endobj 365 0 obj << /Length 366 0 R /Filter /FlateDecode /Length1 420 >> stream xc`d```cp``bPHϩLP@JFnI C-_s''?@~M(`Pc[|Vf @;9x9YSQ F'LnZwS߸5<*11-"& IYMMM̌ԔDELmW?/]5W'}fnSܾEe\cb Rx~  pC<}$NǾW8\N ${?A~Ȃ#sC ^} Y endstream endobj 371 0 obj << /Length 247 /Filter /FlateDecode >> stream xڝ?k@ [KlBc'IP{v $qz#xgPEC`B}c .Y{8LYCY7?>]x>xwI)'Z8IxY@kmTAfk Y0h^Fz#s贀! }RXYt>/5+H.EUxCSWo7i[ endstream endobj 313 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///2_feature_gallery_export/D0013_Communication_Diagram.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 374 0 R /BBox [0 0 800 600] /Group 373 0 R /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 375 0 R/f-1-0 376 0 R>> >> /Length 1329 /Filter /FlateDecode >> stream xWKo7qy(6ֺ9䶱TE{!ڵ%B; g53\{Kk ePld^>\zt+WJkgċ'듎-Q&muL_V3ףX[ miTY@=䨲w"RdH)W) "H'.x.܄U} st8SfTJ/4&@ rġ7S⾂GT2y?P9e~M(jm(ow"81F &+"e-FV %in\TKuA%J#)(VHU&76;&[R5j} )3I<%d Ria^z/J[p3pkc92M%θN~Aj y6:%a|'E c+䔎X4G~\lx,U\4ч;ڕ DW_ښ%wu`6!;!V p* z6#4qPpƌif@[qQt)vCoP-'Bȥ齃1\Z tG831+UA:4 v]:IY'He7*\%,"٭h?s)_0=nh8hV[&n؂ H-2U+ $4|M6i}8dC遗ӢͲy#n؍{bD28^  ߆vΐAn_- naPAIM9{EQ :>ɝAMnǕCϩJ:w*э:ȟD5'fFEJ8.eKהe"?I793}dCpy̙ABNi>?99X3~d~ZKUF endstream endobj 378 0 obj << /Length 382 0 R /Filter /FlateDecode >> stream x]Rn0 !cRtlN 48C.H6xX8̺xO?Ь!D<鎎CTJϷvRN؏it9])=(u!kw@p:Qu[gvzmO\>׉tW@x$ՔV7}Uÿ3SwTS%>cp`3yBo7c x%5jkU1|-yw¯wp7fěMF1ǁ2:&렗^\y-^&<xдi=Yߜ7N| w!BٵnKJy!>& ;;T; endstream endobj 380 0 obj << /Length 384 0 R /Filter /FlateDecode >> stream x]Mo0 >v hi.HL4B?;:iƍ+$a6-0\k0=^FѬ6SUBv[V7JkH>hqY'; y .:jnT5X݄D񾱴>۞dGAZ2wC.t֠V쿵,I?.(4M)(]=F@|>62B\jrL8іQ+%{sYIbFad~؏U^ y))P߳Sp?a¦ endstream endobj 381 0 obj << /Length 385 0 R /Filter /FlateDecode /Length1 3900 >> stream xW{@Te?wA<.X*23ZÀL&() a(Ĭ01rݬUs}V>GccϽ3ds8| 'Bhμ }uu^hz^9ɫrsK1||q?oAٚC.|1'Wxݼ"Hb@ !T0Ơ@943\zDH(!D+m#c}®$&mRT.xx2)f _`Q%z9<ޫc&sOx#Vo޼}ž'Rb%Xg:Yn$1O9p@`2N{%BD<?OvO]U+J;ՊWXv`M蟈NՊkϜ*6aFZcҘ#~NJguJc P4p ιO;بxS Iq,%}4OXm ZCd h%(<ᴪwyO>`!)nќgO j\lbMcѧo;彽|ݾvi>(ԇfwHQsQW@( 5 tHPV.d "5vk֓']}>cU|gO':=(8z37']xM>ᇣzKcʖ6.\KU3!fŒRo%KjZ&Xq'kU!`+4˭Vtz{c؟hq++dQ4寒B[326OIIOOںXf}X6ڴk~sΖѣ4eZcPz@ǂ *}g4n~Kgi<<6'Nr78s`7ѣ,1|n.a~"4c;$*DWF&?Dh{Kʶ$_%d"m ;Y܆:a/vi Ȁ`΁I |$k\BpŋGdݨd1$v k/]̮"±SX]9|xi > ;=Ւky|oZ#;Dl@2x B FFC@uTMGI[Yjq~yPG*ءm_e&mXw%ۂ>n̈́`τ_u̪qq qqmщSʹOC>Q;\JWRZQ4(%8h3s=W cM6-iL ^I}c14\;s( vN%^A-.h]wMP=Wٻܓc{v ZZڤ~U-QԸEi"=T@hq&bOha翸9;m[{CU JzZIJ0Jѳ` _*=UVbV.9omz܀_^PP-e'o ;V'|N=ᎁ| &c=Qx >\G^]:O> 0 jO${j ?ŵpEd*Z%K*薕|"F8yNT bH9]TJIb*]oC|ca WЃNg# + 4`Gz`[NԝYᥪ'469Hz }M5b=8QJ6ԁ}]8w9f>˟>_5G$ jEcSmLNJ!#kjX4YR݊QD@.3bv" M>IJ!҄W}ǐӥ/F7oN-`vc ,o pU0nxW#OlRF@jim  n7}$d}Grc-Rwݟ&|A.2PiZ(k(^o}<> stream xV{PTs]`AمES܅,a|İ,.(B7ctTƂVmLƷcSADms2SE[N dB߽Zm'ߞ;ߜ{^B`0`;:STR]e?ͨ~Omc %Si0R;tYUіJmIق~D҂*S;dH/M  "f$4f6dw0J=$3^橵rhDUy,܆P F҆ *"E+R(6??ҏ5-8Ba,R;K|:ˑp]$Uq9cY-8íl$vܷ-gtvy݇ՅipĨ?ͦZ~=.;=屶wu/'{\LȽ`!2R%9=T63:kcKvp_5VEϹޛ\7v=csXy |Wa!d=jk1X,jhC]qRN]$ʸN[ v$:b:5- N>lY`n8V !࡮֝_WgDn(۟/GFS t^Kx^qfQ]5r+ull<bns[cg4xWvBر #C""d1\<ޚ4Bذ簉VI@|=vɖ*T{o`-RZsH 3|) YYY4Ah'|'|m4S@*ggTšX^QhbBmQ¼YMu _jwe<N`|Aƻ]$_\%DV/iyɡ3&xѺzy>7đꖕ᪟OpћdLyȧW [-d:cJ46<GAͨǬ{Dkl\S|Gy^G;ۻsj*i BjQ?,8Ny17m隱#>,fKbso;h.OHPHP nQ^n 9/jIsd_F_[~k_OݴEKج7E啋:RGO>OO]ɓ"ynEĄג3EdD" >+AӏO>3激櫬YM33|'>t}ƨh}hH4߃FCq k.YgQNLwZ;E zǏ7ZN9UO球u|t!J/8+\cy@̓#خXOK)Vm}"#E+?q^o:> }ޗ#޴xw6Cz ubMQ3Vv)zJD!Q9.,D3q|^)Aֽ3]XAH wٞytY'гm{8^/]\J^_W`(cJq?-U-47X}FJ GCsct8Q\˧W4[ogLWӺ=vimxL]톏ΦS=P$\ X,na7bc{~7ļht  NvYвC k3}f~nQiSU㟆^2l7Ppe߮ȱ`p];ՕʣSmh% #DɺAgmڧ|RK//P>R dG: R>xd-0b׋:HCA $rkHh~_3M$}# z$+5AB\~ӿ)(IhDEI&iof=*x|`[ѕ endstream endobj 367 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///2_feature_gallery_export/D0020_Sequence.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 387 0 R /BBox [0 0 800 600] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 388 0 R/f-1-0 389 0 R>> >> /Length 1469 /Filter /FlateDecode >> stream xXn7+x> N@6 F H>>Fr,ٱWl͌A0Zji\_/$/7w$=l>煡o%)/||+->1;Q±Ϗ9e'^s‚7Kqp+ _Нi/}+W+^{7ddHrBJHb U[j-321Z-\wگ~^; )OlX P WVC.AC_:t2ՑB9H&lN)$Eݫݻ_޾(!@%"\w•. 0Ӯs)cV'Rr*OWBG{k\@l7u!z}.{㻛to 4-oy^ |ɲEPTQ3nOQH_[qCdTϖĉGNl^r2JX=zš!<;/Bqv*P6LΒ%w*̰d˕|S$Y/1 ~ L[-.(= ëL4|l݌2(D\+A[彟1F-GD9@+Ő#Ъ<*1.SAƶE G 8e0 MyiL-gs AC\&bdYͬ*CptX(])`ȁSbiP>kp oq ȟ( R>I5F]-PAdQ-ґaE \ piOʜpaӥRPK&MyeUsŷL^ρ1G:c #CIh7;& 1XZ5(SQȹనI'~2!.+g+#/Bo9 2'ǰ QH{]z TncSM@=XiiҺ{hGk 4֣sf/SM`irgj+P4>0C<*,FPvoxm0#O~hF8YţaBh3k]bNUzvOEm[,LXu:42[/{rGZN2A+/TεUr}]vpE먌dm~\(&% wQhyv!Ǒ^0rK8,ϱ endstream endobj 391 0 obj << /Length 395 0 R /Filter /FlateDecode >> stream x]Rn0+|HV^8~@bohƉL8zz ;N! ,䎴~>yDGĦ~p-?΢Hx$G:> stream x]n0 Ew}tJ0 8eAv}I1H6{Ώ+dq6=Fo#.%Gh(4.+Nwj>hrY6Ov>-Z?Krն`Q!B^dS|^Bƅl0?jƹVJ,'gyNA5ujuʗ/wub s!\^5{NEYc\G02˺׭Lb ĢX_9q)\2k~-~:Q1]vKԒR/ { s`W~H$ endstream endobj 394 0 obj << /Length 398 0 R /Filter /FlateDecode /Length1 3940 >> stream xW[TU?{gpeTfDVր P@&GA,(4J׬ͅEV}@PW M%&S>a{v /{98#h&"/5gqEsBo?_EHKiՐ9wLxUv,3sV*#߁dg0>7srQ8Ahl{!!Lj$h rBU1rNN#'`܃]}ة0t$OrNC.'$0;be_N - Zo})5ZZtspwWVsscgh?xv.\Rmjo9?TCjk~u7f?=c}{A_'vRH$5]UT |Z"UZf0ß?jV(tmL3V.>?uy F _CH\Z"h2g5rDWG  kE]YƖIWZ,wWGgzzex5kb>;o]Q6;_7<[2wX#rEH kr|tkqd5je| v>o _f䅑~1eX!%}ONRn)Ȝv̂Ut$vӭaP=gc@a ;voĝx5~f565sNcꤷ">idUw Jy$Uc`BOҫnkv ZpWnzF+6}hO~N\YkE_/;XUz6?֘W|\d ,r0GO%GW$?$X9~lؙy(xeU6usʇ\`w 7?VL}B~}}q3N>Lʫc:/3G(*U pZ3qq*mctN|'^A7-qQ w3Z-*K*銫ʗWm)/'={׭蔥X0o[e% U! S*+߬.M+[ %EB (9'\]`髷W@d,LtHHzBCciOf%G1 Ib\>TA14$ki>ğI+'F󟢜{`vdp5XP0Ƴtz7kJácsB/$?yDH {Ώ2M,wzo_-K- ⪼7V+Jw,cz<b|WLou˜Y9LլI{cTF^ -aF],(]`+B{ر,d&ǟ%ɟ8O_C9?"k# e 7?ܛ5-aʊ$oT'G^׫-'' #qZ״R?C~g$=FH0M躝K}r7cQ!/؄*H^~^FOU_~+`>o_xtx G;;*^N 8Mɡ+t=8!W߾܁'R!KsB L@XԀL]O_o?iO76zn}Bw$iϻd9P6NMrrPKJÔ4)Nwd"]\3'3m+;9Y 7> stream xVST?}h+KhaQ` H qE@mAQ$)LaTԤd a01 jv&df 3c4)uD .=$_s߻{~sH 7Ww| tu=9/hQƥoX| K T-g]KH/*xHTkwbLOzH~.u! '+4&,((aԣaڎ!W5nP-T #U Y!ΩaS)`lFb›_=pAK]]98dJkcc+h6,Kc;qf۬Sb6" 6ݩ0;ǯ}]vCU獻^pqWf;|飶#/r߫Kr>lk}M>|CElhA逸0I_VC@q_E;jvhs[EFO(̞؍q$/W, s^JZ֘A5"XhOng[OA嶹9YpTbҾ-fN K "D[N#(Q`Qv[l2*.IB3Wnhx畗#LU.96bc7E a9sRd<t;)N b *,LzxNJ?i3p>`slR|b(1:lᢎe='.~y3r[M-XZ&'| a0"+dHaCM͚K!̈m)<8b6V7%6,] æ1bƁOwvyA_A}WZSL"J9rs~9Gh0t|NT 3A]~[laaaLæaB* tLiI#a]%" 5 {qH^7^[(A֡>ɫuG (~v=z^Qn[&X,hMLc ~ykc2׽Ƈ?;;f6ߤo5l=yaکo]zCOzzxye1_Ư$,<=-;K_̇04h|p)QE155u3mdcP~Fy40[\4m|3VVo˦'Ѡ.Vݔj{HN^gm}uR)I<طY ZWlNFKheNTOKV-(|kzo<*~󻬼?_p)_Y2]}unK45Hi`WOoS;IL6ss_ӧ\<z%c0W/i%G%aL4*T ; EňFoM\,.3󼌎Apٕf?ϣR.qqٞDRyj纺uf! ,$Pf>SX{,c({¨:5'0>?ݐQl?}\BdzJ$?xNbHӢz=XoΏlZtw|{SQ/\FjkEύ 54(ޟP +{]G ?i"xSqajfTlT/@jF1hL|% $Eȉ @%{$!rI$t'eTOaV+t/]OZCRK3"fubZ1{4/ endstream endobj 404 0 obj << /Length 379 /Filter /FlateDecode >> stream xڝRN0+W"*8.+I!"iiT{;Qy> >>/Font << /f-0-0 408 0 R/f-1-0 409 0 R>> >> /Length 1855 /Filter /FlateDecode >> stream xYn7}c78]0yl 9Ud3H0"YUdFim Qk3E7Փs^GֵN]B}{ҳVW?zFWgwхx" 8uv5.LAaR̍-|wq\b]: SV1eş0E e6nO 7w:Dv::D,8,(UG(p`H%l:\C;"*OEixJC5;TRXQ`VdJ[x9o9yc\L(O&*D6 ]>b8zhAyƖnhjWUZ84MbVbvQp00-d4JPoǂ(:DѲipkGC(V}XL-Ĝ.b'QuDB+\IZ-&ۤ^T 5.2} OGu- f10<@d=v誥6J#y802(>?d-q[k)(I-6Rjۄ6y3a쎹u;9m4;I qy7$Yvk~yhq[/E5\oqu=f$IVm`<81tEĝ &ﻌ-h $oNU%F5';^bG4W5S[eN"K)ϙkժ9=Vr^ƈ19=ƣi5)N@MWCDcC`꒱=[t,lN%k]htZjN͉h)|~}C9PN.xƤcJE= dWrݳ쿟nOmDYz:l (+*hF5nzD0ԜqL+4;Oڡ䇧'QFՠ-NѾ~uQׇ9 'KQ "8P #51}i@e4 ]x4`1+*$爘mŁJr*K8s+ =ԝptYoc+tiJu9)ۊfS9}`R]j[&5Ҫ[Ռ[u{o ux r ls # endstream endobj 411 0 obj << /Length 415 0 R /Filter /FlateDecode >> stream x]SN0+|Jj'6HQ%xDN䦇=ޝH;jS=m7i\tEc);ڏIcX.;yC?BM&u(%cvt[Ǵ7_O[P<ЁҢk^HC{@&q9_y&mdB0E:}ܧ=׺5)u]չe)8GL=/qcm7k0^Z/Z d͂ߊ 2v}n@΁B Ixzch ~ޣy{cl^lj^yIjZ[A}Yx0.#³|pʹ OژO*y~Cuu endstream endobj 413 0 obj << /Length 417 0 R /Filter /FlateDecode >> stream x]n0 Ew}tJ0  eAv}E1H6.0W0| aċu(A[F&EmYqꝙEB'5l{1Xwy`4\ :hb_儐}]}Ls|nLシf tmw t\YqhԷ hD<&C䊹"~b~̓!z { y7s4%x ~`~ k_#k$OŞxü!ͼN\ď̏yjNCu*>cEgx1Хn|[Cu:?{J/ȡl endstream endobj 414 0 obj << /Length 418 0 R /Filter /FlateDecode /Length1 4676 >> stream xXCTU?{gW \a@&KY+ELP@bBB Pfٮ&=02BL+H=w?w{#h<"((5gvnWF#Ba 0!73N/[G6 ˄E?3gUa|۲_JH5BE0ϙmE80EJC!#@Ƞ*+8cqV[k7P#H$ N,&$0_<ZVS|O[[|jI$B !L`%*22&6aƘ1@?&ZY?`'c&q^G2njwo<%G¶mo<- ΛʧE'9-N ͱ ]dU L=Ql=NKxwm6Wl`7i"s@WbiF# P`a`!$hs4x Wލ^|IcWFK3ϹKc.7|xִe>gLS̸a%Ϙ0_!5'^gdrC½d2 [ 7O/^oKH\((sJlBB̠Cqmnt RFKm[X[i 3hy(CHxI 6q.ٻiٖe\xǎe헐}('OiuЄ5Z##\2Щ0o-``nRIE Ҫ `!JHo8Ara._F/i%߃hkdr1i,.abRy+7NN+[SXI:>cl!4E5EG$0Q`ώ0;6 C@瓓 :6} Gڜ@QeOY6= X楳#AqTJm VaX^ܼw?x6% Iob4xW O)  a2 JM~v* =H/Xhs yׯ-V2|ur 8FW^h4~v ?B%q?'$h%adV G;vF$ի-/ G1y)"^< =o{5;,2̂?mi7ܑsanqE kg;b *F&(p1L⧛,ZT `-LḎl`|*. +>|jkܬ ,+O6:vo;AeS0+q&%-( 9 D[o̫c[q¦bȚ%3˼٣F,Kz^cז)OzNh-W+bPF$_i/ls!*]/b1z;[WқKr Qj.e'u4oj ٔL0lDQlp Җ޼Sz@A+7|ș@YPd5F `t*e!L~~6cF/WF⌢ȐI{^4qܸ'~gy^cz7 ߖ[PCL7BvhSʲZ62h-}^qOEp-lX z :PG<EhJ銫~ml)/';~s?[cRb}T7*˛[jƥƆ{^]3Y +00/!V֨s}m~V!kWӖ"%>$4MY;7#'z _'#qUu_&< ]fx 񬌸G^ޖ9 ks|!y94B*Pݗ$Tc]z?t\ 7}d.,ws/d}P[1`{pe2$6tVH(BS`T{; GMIs9}I|EՋA3N0Q]3hj;9!/A W=sOb/^179;2b=ǟGvzrԿ[/;Xd AiEݼz`ס Xq.P[ ߆K*c-=+cZa7ڈ㨭4{#o8Mx!]ED sU҃$UN;^v\qmL'o}X`Yb2z(Y<, Һ Ay'Ne\#=wê8:Vi%}6qv^#W,RJ]!DJX-V*Ik&p\LPu 4^5,MجY"U ؀, W9` AWa06&݆c3ϊ{lM[@(<et~ эb:O=;r?cbXQ;"pȰ @Ūko\Tʱ9~i\+bGMt*'h:ug4L"'FQKIH;"L7 llƯB|A&mZA<0[U=~aхZ~9~-;IXvAWR؅:88ݷʝeX?\| 34é.? t A|i?`x2b%~,oy+7ЃNsDhI,'}A+Ϧ#YG*wQYdGE Kv1|9P`Bk*4h:V-DtxN20w!GSfD~!Z)|407灜Rb Wr4\E~ hP2N7a^f>}R΃5|@1 #t` x`|,"ApyNJ(hl |>C|!Υ><I}$o?.ge 6j@ endstream endobj 416 0 obj << /Length 419 0 R /Filter /FlateDecode /Length1 2892 >> stream xVSTι.ݵ%Nlb. 0BWZdS䕤(@4c4jDiiЩAMLfFkK[gQQݻkNг^ `P[sek8WTn=W4ᘽlG 2ǜe89bRY řb;˰_z _Uyj $DM~< 16 zGO* %:Ukc#|ar)EJ= J- 0m%Î,%¬$h%hm6/^JwqO5bB FH? 'Ձ@qF[Ӆ/W 67t\Jjak c- >qie8dzL >(0&." 2oxy9rL'Wgoיqټ82 q)tR9|6ql Iq`14;.軃$ݿw%e+-k\壱R?IfR?"nB1 լ1*`N@_d3Pb?VAw(e2*o/_fdwn-3"|5;7Nr ,cAt9ďdd  T EbZp} F7{*91?.fbs*bpY@cyJjj\Tc4v&jmh>³eɜZIb}TTKCD;  dM $2JH4SPcc^x欼Xϣs_ %VzLk򴴶m}13sm_?ΜN✇6GmBBQA"vd qnqЇ$b¢c~}&'QyܩP~.܄(ǩUddB, xfx4ԅE;*,dءòsژzHL_`ELyw;G+9HYF,$scv?Đ5bbLƐA-ݳ+׿:`QF!2ř,n:ӵsFėRwZwx2Jc y  8^=a OQ E~ŢzK&j ]z zn7o]u%_]("*s*Z7Ԯ3ohsב~i$r(׷HxAM7tE)USBt)C zH)*X}~ɍɌk_TX9~1xcq b|9,qn#u{3XO+Q(Yjѣ2]Ӆ""Ԫ"KDd)*אnAgʢ^?m VO5ӑ'r' r>"ҹ e!=\̛ZSkPLj }*Y\-gevIWCy&<[VC~S ''pE-6A8n۬kꢟ*[O[m p9jLxG ܻq4i YGX7gx.t\ a$=h珆>}xTYiz.r]5[+:ؿq{"sl|NhqX#^@`=iòydDo\RC&C.&.fcHP9hk zVţQ|PxfĤ܃k' Q5&y/l9Ø<82[p[G0or DlT> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 421 0 R/f-1-0 422 0 R>> >> /Length 1555 /Filter /FlateDecode >> stream xXKo7q 74E@AFEA,9)$'qEoH.w%ŵkÐ3!P$/XO <'JxETeZl2C~$?7oJu+aHRɲ#+ut|=Ihv:u'Z((toWÂR B{maHŰ_E.KЍ+ zx|=_N*W-1 hMJϰS1~DZ:ci ƱVgP?Yzl9hmٟ^eXݼٮ4;oxOIWio$Ii4vnо<] Zǎ7$a #Xe q#6&42uEY;dFǑ!'^ae4紓n^^B%Ωpǀr =b`y@x&q&┫"5 $Wꃩ?EחO/ģG՗rוxYo6JiX<~,<{=c}$N{1,b ', -ƁwNkiBsdN7-m5u&wCCiJJ82(iG:Cy6dÛ끸=edv6r()1JDlppk䃒uJ@h,f M귯jVWQTlҤ8iIM>=L3gV gZ]PhU}Wg+O- V⽍ܔt/Y)ϹrRT!{>ǣb ?J.Y~1ݴo86ŧկݿW endstream endobj 424 0 obj << /Length 428 0 R /Filter /FlateDecode >> stream x]Rn0+|LJR^8~KTe!]oJ=c0uvj[?m2{`]uD rEQJ7vP] ֏0Ffn*wOnAH) N,w_7F{k?̒x:\e;>d dk-ޟA> stream x]Rn0+|Loo*!*pCM^HXzQ*;ٱݸ=343^F'RQUzi"ͧmYqꝝE#n.kg|R- NVm{0R7q\}lS|neGҳ.(> stream xW_W?LJ}P  AIJH}}!H#Q"b-k]KQVZJUEWtuѨH|T\$E{89P(Qڰ}tc]ŝob>m33‘\|ηpmIyUq  g `  ?: {^`IC9T !YPBډZ&~mc=BmW`T1U,|MLfL *lvk9;{OJ5E"؋2ұqvG>=ʗݼ=1`A2H}zH 0 7UI֠ 4EFEM0/TWyȧ"W|Nߩ#JN%C{Oq~(f?"ZmH|+!fjz9ɳ'_][2}0֘eWBzCB y`7܍gcGҩudV|?3*4I鼮xޞ4,FrY%b0oЯKqrn71{ 5QF^5Dyl Ca6 վC?HzMۼ`Qlz)9nw52sk%tUT5}W;]7GϢUXėQjdd0ʬL mBO}Wѱd!sFMNWȨ muKB]7ځT 硯2GI'm∋P0yD\ye_CIRiQ%@!}~7{H|/{x6{X(/sP&yuFb!D[uLvxvvS$MYǙ(*Py0ճ$Iė߉vl=Ǿ`d!I# -c'3F(1˵> B Ĥplly6"}q'4ǯ}.ުϝ> o>UW;hi,'zxBrB(yh4w䤬?qr=1ϴ6i#KvNSCg6ͩ5tm b'$1B0'Up}{޸3%6giҬA&.+*XFbڇd|: y+屧Jup-COBq-\R˷߲'NີYL-}@#g.@ YZZ+[ݽSB-+c_DZY9Nxg,I$\*9!D'z&^la?EE"t ߵ/,(qnё$<ŮrMe|e^/PX9L*:7A$|%r60EҝKG)_i|usK{YWW> G QCMAj6y"3mՎW2J:p ./`|ɮ޷.e3ZgLݦ!WO7z#y%y[*<ڃ3r >>? Q|nĩ-^uYVI6dȶl `G1&y'$y¤x""' [4wǭas#d qmOvo[A.c?yyYYGG5#rg 㽏qxIV1mmi^O{xH%Ty>R'UZmTG~? ȢvdzHA"Hj9ds H=|)$v,YHq.XlW#"9x!/D~-Rm2R~%FlR+TCx/,"Htg`6W{ E¾} -C@3#md:"}26R7 <* endstream endobj 429 0 obj << /Length 432 0 R /Filter /FlateDecode /Length1 3352 >> stream xWyTT 303Ak`U,P AQdQ5 ۉTkq_z4-Z hꩈ[5`RrS"Fx͘`?_;w}~wy@P27-^*Х9_wV<8g >Y%럹*HP2 8.M+ɇp8pev@n/`NF9#IC(!p(Q / i*\JZ"Tcit/?"YH< G{sqN,AZZnex"79&&Y$bb;ͼM /._+H\pl2.j(ډҽb@ӑX{`֑̥gႤ=詜R0QjGTzŻl& ^_gK,m;<ye8lbyLPheUd1bj6E:Y kx\]foQEơ+]]_-:̓ȅ55k't'K m$[3@l­tҼfI D!:`yk`==ՓI{Yo+wm(HfDuxY1@.bdF͢5:t*W3!b5oI>mMul=7=2V7NչT^mh`@UKx@}ڏ-Ѩp7E/z!Se01D7Y?ݙ3!1\^7!<3YƉ> t5ƁY #т _M0U3e}eH=ۤ~+U0~D1M z L!x6@ѯ*+]l}:tPv[͚Mٳ5R>H1Mo Qř/g4#*ĽV= LyB(oɺ\<[]Gթ$wLaM}(uʶҭ2Pc/qvVU ws(&cQIFZguZdL&nWns-)w>'gd_̊ 6SkyhG5Μ:0։0%zk4+]tfw5#5rv)%݋c֓eWRtmRdniidmR"ηNCNbA='| =})6$Aተ̎V ONGr@4wyo68[?&_ܺ/.djwgmJ}\~dʁ<'+B¾:_@hJY2zI͌crRP1{F>b~}gYlѻ5! 9ӫ;UV u[va\rROmN3J>V\!Jʄ^ ^^Alͤ'cYk,A"w7+t簲~$kG3gg;KDI>q!{~:f/˸OZ_171U5o~>S! ++_IK*}}24[_o3pSYZ{'K{qjp95SoB2X(@= vo y9P̏>ŰeKT ?Xxx2!wA4 ")ᔍ7AEꖅ%3݋ n2v$h< a}MA:sjN# s90+\oq9#u_ȁ" endstream endobj 437 0 obj << /Length 248 /Filter /FlateDecode >> stream xڝOk0 :&+ucVzI;qCo?'k vN{' CՓ E\)l16<ݏRjCE7?>]\O<y'^z7B9_T?d(NBe Z@vGsV&0P}b#z}UбC }Xkg̓P$eq9_)=|QIo8d8 |O>}ie endstream endobj 401 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///2_feature_gallery_export/D0014_Deployment_Diagram.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 441 0 R /BBox [0 0 800 600] /Group 439 0 R /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 442 0 R/f-1-0 443 0 R/f-1-1 444 0 R>> >> /Length 1429 /Filter /FlateDecode >> stream xXKo7q p $NP @C Kn )qIQkk%X{(81of8 +%VF ^ןUp (BK_!;WV⵰Q: >_4II%# 4d]sRM}ۮ7mhcڿmwUnLV.#ˮ^w].Ur1n ; ,?F,ب O%3Mֹ,εWPڟVP|Bԭm߳(1g^IL^{Qno/)AG&gR㶞~9:i]{IU$HY)sN$e's(a FTb]޸]߫_A:=a(Igt t2`1P[̔_]vn@kcF&:U1o8{e]}fQB<qټ|}ٰRapNM>d$(Hhe"+<Y\FƒBIH c{-XU9Ӿo9 e;=tCJuYJNY_e%.?pPl>zO m/a,)'HO ZE\) bK!?2CDF\u_+ endstream endobj 446 0 obj << /Length 452 0 R /Filter /FlateDecode >> stream x]Rn0+|R}8 ^R':nì8Ϻ|/ѱ8Un};*p=|ڇ~TMyU/ZosQ/vP4ìKj}{iĺާa.OyXBIn|ZDZ GVMYnu[#wUZ%iYE51㴨Ɩ%@ރE|+52 lxkxkp'd$Kr.!$IIГ-V+I4; 5@k`LR3K6cxx x#Alfݺ"mσĘF!a>8+?^ endstream endobj 448 0 obj << /Length 454 0 R /Filter /FlateDecode >> stream x]n E|t4T/P~; }(0 W@v;Vyaр5r\Q~{ -9OIy8g9#Q8CE k jk2{zk 34 1kRC&7=k 9.~ endstream endobj 450 0 obj << /Length 456 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> stream xW{X?C]X4m*.ƈT  EMbUcXGC"&lK̮|?wg̝{ ` *Ylgd/)چm|YPRH gliappA&NB9Tӑ4zB@(!KI)=1B&2٭ϓ4Ն|3jy4?Pi=A6L!^fhz,6kvݻ3}>c|G_ڣ;@k@'O- P( z0=juަ0W8F#;q=IV|^4"5{B򡩥F an[09ήZce|0 p} a4TBP`joV5e_]awbfƒp%}d ft-mUW@zw ?0@mBګjAMAmvۺj\e^[d,;qK&B5h]n,[@yPh3FtjDWd7es|[A:=4UQGhD,5 (F= hĊ&oP_mYK'FL[0)!gBw8b[B- [rWN_{Y@OQhx*FzK%a=r<:\p:[ W,{@8ɉvyB$8"hV&ZJ4 f.h߾O?+=VL_GX>q[ԯ8{|Ep2D=ZC#)6֨(I 3DEA9& trh/7.4>TlCsrԛ[Oz9třOq!SjYg+Q87wD40G #f"v2TFYޝݹSƮ.Zڅ6qLay3(m1zRʒ|ީ}@K^/W7M'{P'#ű4K+Nup~c{FXeGIb;|Ty0 =DQ?q؝FUwxߢĬR֕=Eىs2_]<;{YxRcѡࠝǚe 9HEKVZdbl$j[밌)̑K`O;GN5^Dht uw.^2|]Rv!~^dx<öK({„\I9ꍘ@4}{7*`Ťq8z[g}jJi7N#܊v?uYetQE94{YM6&,˓1b>*?mxDMrmkv]~{[r+q uo~f'&&y>1vP#:^󢌧 7lIƟZNhtz蟟4o}7v#ҴaRPчG=3͓z  a&_VUuX<(gP7lς~5ҳnï*XŌχ P&d$z*t\(Cw_?!lF@RҎA(Qڤ=C"ytg _pC PLDَ,8KLw(guA^\[:L܏(io+31Rə endstream endobj 453 0 obj << /Length 458 0 R /Filter /FlateDecode /Length1 3264 >> stream xW{T;3kY%I jBX-b!+AC=5FAkEFHbh=GA.6Qk`=m꿝9wg^, X`0< FlF^~Y X pݜ> $PGIs %#œl (I |³R-` 0B(Ӥ&Ʉ>֠nAxx [}4YZ`jT 4vR5e:HgaZDbRDbZsrbӥ6c|+k )JG-OvhA;q']2 61Q` gȲ6@buŻdfH@ >f͞]66ބ^DyC#GH= X)AB f{>F7??'yZzLP12O3iMJ5a~7awXQ\\ʥZ~M,|xS)^ D 1(Nu,+V׃6Cv8@W6_CWSCgBq#{6e :/<@/^>E,YK P3O-@s9"!8,ocW:JVlo1Zj В`vV&Ȳ55$OΝ_ y,W6f7,'گL7P:\ ^ؘ9ֵsܟ>aN|*o>q'_lo~rqG>+ kR 6Nc|#$"v6Ң#))ӵ.KK76-/M8-YKP %-iDyGlˎ<~!yt W 3-%]uC6syU=\Ɂ "! B+Sg>~,X;1poab1h t!fF.vTf,7 #n8T%z;؇jU'ZgOzE>ADZO$g5N5Ha)?6EkswW SttىZ)>{|1z~m~vޠE(銓j;; 6V%%AD/[)blNs<83`hh1tn6Cf D 2T[Z 5m^'SrѦNYzg̒1/6~b %[k}7WPyM9m-h_BF$z(:V@7Nl,tn5+QQި݊[)Ez4>?|!ٸ[p+nn-e!~pT)KSeFbBk 1H+SnV. "h*f{/"3CG?mڳŕý%472}9}݇{;-4*ŵ *ާxnCIb99 Yz "'Г  !R@An^?9E-Z-H\&SۤS*?HߡvPլjW @c\3PĤ3v C:n¦́ؿ" endstream endobj 459 0 obj << /Length 460 0 R /Filter /FlateDecode /Length1 424 >> stream xc`d```cp``bPHϩLe;P$d&06/e``2sf@JFnIGC%_s''@&c M(`Pc;|Vf @;9x9YSQ F'LnZwS߸5<*11-& Ih8"Pi.u?t^Y}髌cN39ŻRe7>bR++m2Hr0@8^(Ha`cY5Pq`baHar7b3/10] endstream endobj 433 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///2_feature_gallery_export/D0015_Component_Diagram.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 461 0 R /BBox [0 0 800 600] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 462 0 R/f-1-0 463 0 R>> >> /Length 2456 /Filter /FlateDecode >> stream xZYo~_x1yl0g,If^|E6==Zydu}ãXwF+%N }+.^+C#*nMOBK'~=~ݽ|%TMAXD^UIiD΂/3Ɋ}wqQnݐ`u~(OÆaaC/ |3 8o.U;OFf;IgPQc|J2Bc,Lc7`dz bu~v&gxY|%mÛӫ>9Z׳Cy'{4& %b=ng :Rt0*2 mmwT SxaD k<何5$tmZf %(du7H`;H S$mH&뀲bfe#B6s!hpT`v;[3! 7&bЪϦnvq};88qs}ԥ"Mؚ)TJ*%Mʟ%T=\uwQd"RT4.\ϲ~`#T?3_/޿I::S 8+QWTS %w0t72\rHs !8)Yhd]NZ:utR.i C>fk}z qiNO@6l^9D6غk*8!Rw2YΖ V84&PoYIQQk95rmʄnҔ\ 'ճ}efeƵ 7 e\őwqyfs@=X}r|TsGߐ'y4m4oX]|ݞ? 8I[SY7,ٰ6ٹx;+ `7̀t` J'p``6AC4Aۮ*qf0 8eS4 ÃJVQ·]Ik "j|ֹ`B<~`X)*PiiCMӨ͕ JX3`$W8 lPZ'NRx,ZyȧBҍggı8Ԉ >y`5P EGw߲$`MpXGy>&e.4KZ Qb#xvSk`(-xf4-Ҷ"%>i BM&dd.Q<::J ֣Pŕ0a5`?.J DDJ`)IM&f[$N܃%B ҴHc %h#Ba ].2Q|"嘜UjUWKt%(pr,H _0pRT+"93WgтV>p0GWl%,jl)fWs \4fEmFT*NV $?Nod^ #oG,LVSFoa3>G d +w5ؖ0QV}5\N*+a[%@%M%HDoF|Xmnt!͖tzB 9`*iW_t%I~>ʏU|/DB?K(9H?RoPRI0= &%^ݑӐ5|):wv?OaʨU%/R5PҨɕ-BpH+g6o虋5dt4AH!]YIf.\Vu1n2-<;`2@ctj\#JBюo'I}E&` Xϸck%8m^TD'OD *6 찶Ɏv\s}Tꡂ@T 5咊e 99-hcΪtEY&bP!h/ 糤+d߇e*DǔF֕䲀`4Rtk\I:e3#݌Vꖫ cK\r [&߃z bRENШm!q~ᴠ9Fo[R~lp5$ |+S/ڐu n~!s we~Vw <*.it.$KSf6b)]kT9;Y<8H]Q2poƧd3ΐ+s)-)8J-_z=u_(/zx] щr]67s|_\jCGZ=Q>E$\D,~GrIL\X! [HZJMtn9fz?0Kl endstream endobj 465 0 obj << /Length 469 0 R /Filter /FlateDecode >> stream x]SAn0<@H (ҋI}D5%/c$@6Ghv^?qt+-(\kG9Qfݟʿ?E~˖n{XF$IO7]^밾 gU9xynاmݔ#%e!Du4eޏҺ΋껩dCƮ.8/Xjl =S #;b> H ]LF+z j7`0)q?!+OnQ{-2yێ=$߀wxG˻ ]g֛ 1ߏyה!/3隣||TD endstream endobj 467 0 obj << /Length 471 0 R /Filter /FlateDecode >> stream x]Mo0 9v@4 !M݅>n?C! WCObΰI7ya]р2yQNf 2,>s"Vfxnq' ['әSk?0d.NZph2aco|#)>Ld k _@yֹNΪKFg(Z41V0_qB.PSFn 1diG^qwď̏a&}5$ƀ}N bͬyfK֗ɬϯh~}5U#G7oȇ>MaVɟ545+/*}CWcǦEܾ8}#9]_~*~Az endstream endobj 468 0 obj << /Length 472 0 R /Filter /FlateDecode /Length1 4308 >> stream xX[W?LS !`"!IJ*Q("5 +Vu]UuZ/,U),B*VKlՐIP;3޹;(aPN˝5?t#@7΅gz{r{-8NҦ :wjQEs\?8P3AwJrQ *iI:=#n$V)"n-cB5^(1E\ 8ux"1lۄ3h@en>:^h< GNDMmXi_>ڷ}i~ Bb"Xkͬ>%.jcB?5^x&1'.m?Ovefsr3#ٙ{6VMեKUWfE1CJNe 7zK58OVzи^-ʂڴ^ ߙeF3,Y\yT!o_ք#hz(1y8zY*Co?'*Ce]Њ}9\r5|z{^sN)]|,)m61]k4UȨO1)PI.zJg4ѩdFЂq[o?qbhh`wޥۊODɞ PrFkgP>AT@rZog B5[ξa_r-mYR Rtd$D#aܠAHu&y6ΆB?>ЮWX`wO~G4}9eaʔ?_T& u=G>aHWG0 !_J& ; M/F8\ EƠO؁U#wgy4`?;2åYTT8O췖y?aZ刡K6chx~|} 1D n/*ӄ?GQ+N KCo*~c{H#^^g]?U^r vskP<ojJ*Zv31/if v+[ղfi@ :v%_]tA_xuA]('%Y)9%~wgL+͞panڵCwejl<+8O?7}ZQx%gҜYf3e*wr [mrVU#15hp&ʋ'x݌fl4H$vOl$!kKKX*.L2܌aJo-IxuXLMb*-Xyq=G2鐕kN!Bˊ i&¾nPlen oJgX:]U7*U?SASW>Cz8vJNcKp;K&*E-eAa1`4`sC m6Z!;w<;nr_,Vo9Kg翻LwcNY|Veɪ'b>1I&xaxq r7|JY HȢ !X|5ʫ:c o*/cֺ|+Sqi ⅎ|tttlltȸȱchr }O 8 A'yL%Ed!Ogۭȓ/DfǺ# fl"Yrםnv1cEF45pA٬^~k7nwq4:aEౖKh \+U&=$3φ-}/ݰgH\ K?9.^v3"K)s⮢Owxd;_ H"!̗"@1 gDF Q7H/AR狡HJqލHH#x0|E߀/`ܯõ+!VDCCqHTԂPuzNT$| =DM⑊YH)J|Vr+# wgHOR6tQHx sٍ<\+r^Az"BF{>[@PQ endstream endobj 470 0 obj << /Length 473 0 R /Filter /FlateDecode /Length1 3508 >> stream xWWTw{ˇ%F]\bIJ`5 *9 "Qb1jhƨ15nR{ Qc=ȇ5s7[1itݝf;`01?7kť >`-)Y8V#i r~b@kǨCŹEߧV7Wf O/H`0B0d30 M %fzm'2@5&^{wZ2 L7vb-e К~fMzCy"okZڜ*I/!3wv*.ԃHgኖUT5jU-,VWt2|#xʒ۫ͯt;{*p/w~&ύr_>^ؼ]N=Rɮ~:2]*sZ&ձ).v~,%yc#?la1hJNP:bp`;kxKX帲GkOw' ,$&@ E ;xܡ0Zw&m?zs[Z>ڽZ삪QUc'vF?" <ZqE}<>WC6yPU0a6t ?׻cgdY 9*^*^'.Y'Ab} haT-'xooo}AiɂYڎd;ހqjձcUjEmo\ 1HN<ɝ4Ky2>-mϺ8q>Za3crx]ä˪#69'x삡#k$3d;" -\Xݧ5,CJzc^ۤe ~l'AK\VP7jm!)3ťq},PH66y0m1xt&ImV ~6)wkn|yK{:xC&Fׅ/w.(aae֙✾s/`C8(J)hrJzw|M5o.߬\UT¬ڿ~?F;_ɫ-Xeyx&9l. (S@ڮXdyZW#1xvݭGs @1yBOt|#a<?IhFU޼qz %X~rZC2R8X(3qk`~,fnNTX=~i)j8_Og_LK;:UM}__~TQ jU:.ބb!k=¦W=O|XQ&[/u_|>y'V>Co/ҕ$]e6Z x&o5uwԋ$뉦qG"a;^^EX}?L|Ms^ݔ}|6z.?BkғgJNNߒ0>=t 2FЋŸU ~f #e{1 }foH{\Ɲ wgoߧ>܌??LnQ(DI>Jꥯ /j VEI2 }ׇ; wfwϾ{W8̿tE{p:ѐR7~K![rTm0 #RX*! \vY)|LeTvS~3ddEy# C> stream xڝRN0+x}E,qz"ĉXHp͛!;ǝ hÍ`3UR_7fAYBcRw:l3rSVpK6C^fe4v'F@DhjP @ÈlAr!Ma ڙL hxf@ĸZwo wRaGNnϘt;JqcOG2>NH*.\p5x&UJn^Ղtrc~0ȝ]AWGSw?>znmTr&/+D\[|sw{vӜIJ PGQoh endstream endobj 434 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///2_feature_gallery_export/D0016_Package_Diagram.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 481 0 R /BBox [0 0 800 600] /Group 480 0 R /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 482 0 R/f-1-0 483 0 R/f-1-1 484 0 R>> >> /Length 1224 /Filter /FlateDecode >> stream xWn7}߯px\ j%' {%V*"̜U3Sz(?[qr#<6 LJ'w;M@\Ha}9oIF;,_HEd4J4 f/^w_;CsnE7Ӫ}qx`Ml]woz-0i-qG}w%TiO84d҉@8BPsh0t7e~mȵjUjv>#+ACyr֊~[V51Jkm8tQ 6e`-|Et)Ґ2u{&#jc>6C* d00UH$Â*y[|:+#xlk5Q'ɏMed#Na:NZn85vItD8D FxC>sYGc*.wr8='/?_拿r\ 3y⼉KwNvc7w;Ւ=^kS/@+/K2 ml}8FeD޲Tf#ܣWSI`_@95hiSvٿ4}.zf><ʺdaCa>T34f/ηQ=Eb{8Dқ:d7VC:UČh%:d#b9x!W!QZKY㿿;6fN ۜuLKsQn4ˈGuGvd"VwAߧ2`|[zƽ\ 5;g2 UTkBj\G2kwM}<;g~>%yZ! 9'dЇ/Py-sUE(#eVFQdZmH:eF 2mp<OK=aidLL;}|EMG}I>D*?ǿ{KcRCdUɳ 2 VČ ҁ*ȴCuYg ?/cX$~> stream xZ[O~_oh*Z`&lr Y<8f|6W=c r[./.;i񂙱^9(k6ҳ{!5=oi4N%ڹ]tltK_NZ5ۭjꯒK\\_cł= ̉ ^R!+__|O;դ|R@דYG@*f뎕J~Hw߅%;ǧ.XLg!֨b\p>R;#S}b<)bm`p,hf@k/ڗ&8*Z!Wg#Gb"dHL-/|^+^.BdP206YQv$xcG#`܆ !J!*!g_I!dۘ[O{4D:m*4l45g羊Xb[ƹHhת몄/] UkfYz:Xx=ź?wnPxOO#| Uߢf5'=ƆʾaTyv( wz~x9{H6 gQMzǀEW*!G54xR>?=v3S;r,0pJP@giilOzqD`Jqע8|J  :31PrV>Tk8+mYY1]brC7LشbmUq~%Wϵ\)26%%FNĤ cbE4p9,<+cg>:*rHix^Ęl(LmR`Vy(ehZ6jU̮..*`vĀPr"SzhI5^`"b:5[A{G_ϗ /]FTe- "70s^a~6f 8K350Rf ɀN&n(;|Xi9><]2!Ѥ1Zoeu.>8$qF& SfjäE!Ômi.@ ~>SO`ToBL oHƸ !D>b,T6ZKZW./W>ĄvࣃP"!븧8Q|M̆mgdS(gl7jBEZ-GEDHDT\ Zb%`T,-yagQe!Z0Dl[0zs7| 8X|o]-zwY[݌i-"iXnj|&ȺOJ[6BG6O\hS %go%5P2K-Q+\d)қ%\hc., G'K|~%9@D3%PT~inlEJ_`q.NNo1x8yw_Ğb WGNV־OZzkL͏ ƅA-l6VҼ-5)^'ѕšq@Qi쩵A>d:t2[;6 endstream endobj 487 0 obj << /Length 493 0 R /Filter /FlateDecode >> stream x]n0 yCV !M݅hlF=㪓v|IsU'a6-z `Px:dڎfLW ۲ԸaVU\ְݓ{|PZ-X ׹T{'tNU]kٽtP'xXmOeͣ -;sTUֺZ\J|wAUG)UA{ឹ.GL|2Hs͉"S_j k@A }D_>sO>A!Y~x)J}F'>8v*~4 endstream endobj 489 0 obj << /Length 495 0 R /Filter /FlateDecode >> stream x]n0 y Ca4F! /NNK GՀ+tepƋuPjF/(eũwfm g\\ְYg| O?8[!]M{8!dIu\붏#-YGatmw tZQlu X1 Z%!H\2ĬVVRp#3F.ؿ %ik5:rU8_q\s}C{s=7sڒ2 ɇjh|C0FJKBJ$͈c>= $ endstream endobj 491 0 obj << /Length 497 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> stream xW WT>{g0 q 00Bk<yeP:m0jJZKV5` S*(*di%2*pgԬ4?w^%yPuVpB}BMʲg)>{,źyid6Bܽ."+,e- V,gX9,gxHG$D"#Z"L<!FN5 T hvWF >` 2D ><QkFEMzO}Ƽ [SRfeu=h<1JJ.g#æԭwxy3'}QWǴgj~q :~ _j23QKb*r<9ىϭɊuxF,_9#6f%BcTA cs8~ ? G9U)HTc5x6St4 `A5= l_^iV=+o}7pu9nHsXQJ`v>`bSmyU>S/؅o<άXꓲ 3ը%*7ѩ0\a3 M}sgQ81sFli59 EΕviŗkHB11܀:ȘH[=e+z; N#pN0bdI|&dS=)JpS争pIUrJWet* ӷ,bO7s|šhsoh)XؤK->i<~0 }E?ҍ?puk!3WRGRP@긥^x9 g,?%2,j;٥5)/ޟq<xk]GF~lHv,L}!g mYω5zLNtI?Ԏrt gIY9qx a4ޫw+7PcYەwX {}Xp_ X!|4`3 4aip`Q;펃g{@s3y[m`Ona_6\rP7&o9ܵj0~u*.>x!*,\M<'+s3k0)LY#t%ծn;N b$ 2g q@oie] 9tA|v?MtgW'uq~#RmK %׿}p 8w1?/ӭoQ74Rkr^=e#oo%ϱjs^,/o)ohii(>R{XnuH!Zی6|ruT@ŃtoBJI i`ekZ6Dk9; R߮?}ߎ_=N)?^ߙ%*ܻ/@"]fB+m*|뷛(4'|2Ѣ$p4VxWѣz%+ꆒ;ת endstream endobj 494 0 obj << /Length 499 0 R /Filter /FlateDecode /Length1 3008 >> stream xVS?{ K4>{g/PD  j\ $6;t5U:A|錂j=0?;9zHss(3//;%VЊjZE9^t\4wԯ~TA\3_~AQIn@E9K!c @x]jt `7F&Q2 5)!P0I fH+,[V%VdlR$S2ʂ,ɂf&S^;X{U l8%|/N'^# hCpcBMplq9۵?aP@g~mõ4;'r7 yRaZӆ/X@XM:LouMp.ϥ{z AfSjIxvjlI33''df~,zT}BMZqeh03D6բ# <ƕާOz>e g6JV6ѷCbKNWYyBՙAR_#`$l֩:9I?;j1>U T믡|fOx_Mʃ|syْ4[[头9[t$w[6x~rtcTW2dd[$ |FSed%0 mt~^<*X!ۂQrђ@ Aœ9@S !ZUU.ZTBMtRTуhZw:S͉.CH:Ē~֐Sd#q%*caWy[cwtv 'G*TnHy=+~6]|_kJtKբ]1xb(=}{mYik}SYfᶪKQre`25hXRبEۢ({H1a&٢lNYP^Y~ vvco-,/x?[]☽5KpՏNHx-i^yn[ F<+yiBp}pjQD̈́FN/;m6ѺGwxC%=xS#)m. :G4Ժs;3Č3[?~GQs&(zcDy;wFNsMnKݼuj@f)Gs滋gb*TJ]._q/G1kx0#b5 :>lq΄[9?ٰ=W'OV7P[ΤVy4BV#M. w -Ǜoo/&~BEj_SC%'Ey֔R*kT禹dzuZ͍&$E}DQ6j~Ž5]qS.[癸]Y UmO߇WχqwnCsx /[TVaeҞƂ^yE^0QGt`L{m&jxQ`>KKO}78 ӆVGO+WBh?_/D'{wTW< [+傟X%l8V,D10 z(; Y )!HL%iT6 6J-A*mj[urdImG`teMD6nB%tPE5x5:KKv::rjZz֬ 2[mb endstream endobj 500 0 obj << /Length 501 0 R /Filter /FlateDecode /Length1 424 >> stream xc`d```cp``bPHϩLe;P$d&06/e``2sf@JFnIGC%_s''@&c M(`Pc;|Vf @;9x9YSQ F'LnZwS߸5<*11-& Ih8"Pi.u?t^Y}髌cN39ŻRe7>bR++m2Hr0@8^(Ha`cY5Pq`baHar7b3/10] endstream endobj 474 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///2_feature_gallery_export/D0017_Class_Diagram.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 502 0 R /BBox [0 0 800 600] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 503 0 R/f-1-0 504 0 R>> >> /Length 1125 /Filter /FlateDecode >> stream xWKo7qY@ g.KӢhfAW]H*7)"ߐ\IJBrfypoAxEkzc %͍zA8m +u]'E&@pNYc@V~x`۾ ~΁Bⷤ DÁSzaJ-f7A/-BeNFi\w7˝NرD'j4r(YsVP,M8aIjzQ[cU 伟[vA~ac >3\4R:R5_b d}>_?:Pu!xF[ĮU^w]h\ K.lKRN",ms^sSMd!T2 - RdYZ+.y"V۵'əb|u>~sY{OoAVjtkrVyDXٗ`~CHi{zZ4u;zj}P 9a~<,lTk Tُ R))frGXY:jIV-rM՜Õ jP03Ҕw{d[(ćR{խm֨5Wu@E `2ASo"&gS<nZ *61BE ۉ#$C]_T9ϠW56Ih9mfgUa "-I ӽN?{ RV:U@<{,h;]z065gJ6<W4 #cJq;$)q ?zӯ;q‘ =l \J6c+\ endstream endobj 506 0 obj << /Length 510 0 R /Filter /FlateDecode >> stream x]RN0+|Jj6HQ%x8DN䦇=ƓnqE7e{Z0T4K$ajetVfհy9-taR]7<-墯ӵZ7/%QA_}k%[YV^#^A?F$Cχ,?- ;c\ W]WQcݟY\ xP endstream endobj 508 0 obj << /Length 512 0 R /Filter /FlateDecode >> stream x]j0 ~ Cǒ >XHm5,qC~U:ϒB281N\kP'<['Uʷ'/ qYP|Rpaݳ^N xug}GvWpF} {4#Y4m$oY%朚.3:\MĆ$;{#>u>}/>7u FgdTd endstream endobj 509 0 obj << /Length 513 0 R /Filter /FlateDecode /Length1 4420 >> stream xXyXTfA LC" F+2 Au APP0LQHKԘJC wFk nQ\z\K}oüswι!)IʜZт B$6%#]FŒٗΞ ^c2BZ; H|װ2hve;I3nE) _e4dnH@7DD [d2[a Ü'`܎喝ؾpO-$oY 8%#ќC8^NnHwb_.V.Qr?wWAjGXV::o=['_A87H _RH÷L#Ë gP\_ˇZ/Dytz?Q_묒)]TzJr$n9ɭu S:n{bf|ޏ yEѯ-n~V>]{Cbi2ziAGcժtvqvV)Ect΀i.xHusb[1q~sV""q6acuI1eekڊ#&\|ggtr=u 8~HسSB%-_O_ ma=^&L0(v ibHD&i&NrFh"FS*z=lAK 2+ xzrF _77o~?ͮ2P6xp%/ܙ:l\Esq` \bY }`r;NA@hK^?E%S? !bI|W>6u#Ӱuppq5C#'UZ_Ip6iN]GCgo?hN}#MiNJBzAKDh % XFyk+)8 j5zED `gRR֟I99zmavAy IFؖ0R2{9^{=L'5׀}~j"lyms#G5N_ T\ěRLo10/ pwq_8+vޝZ.5_:6pSo*vñqDoXb]ݭ}bda/Thg/=9d@;/76Fql ZX!2(Tu7wy\oR*wO>@,1FW9NMsj9A+sl>|ҠI^ J1UJq҉"Bs-^antқgs,![|g6>khQhŠp.?f`~@w^C54;23{ɜno/\lhjjȯ3ٳGw#g Kf5P4ZqybG<vC̩,3#HJsFE^L;';~n☢.('Ěɋ+RL&ѥ kEǠG\Nxd|DsMяk3%|Ђ{[-cXq=PiYD9?+c$(( }ݝkVҟfN2sV5RQ=BK\2\".}yYFJ«5zU/S+WyZ^a'u QO=zS ^i<ҕ CJԙ = y[R<K]ew)\Nkˉ*tŗЫ6~ģ/eIkI#OepPQҚHKMUUq.AޮRʲu+RNk8DЀca#F5*lnyU h{⪔C6_XpBj>?8G<>ٙY\IaoYlOd%c>J7+}T7xuSޟs 'm3iƻ/^$,rv=u䝁'^z5Η$=q^噋;Pw3WgdæY-s+iޣ~ DC~ւGC@ OQH,Da`{;ǎ$M ?bD:l$0|z'*!ۋmRzO>)׷1N+@t -Qz\Vpn3@tr“?X刽i=;o9Їi؍ް3lb"*\#,$r{G*XvOjvDh$+5ؠ7u.\ :kѢ[m|:pzZ_\#L ҩglqѮ;wNӲ"Dx4=~[A஌UgΔV]v@lg5TA\-{|&rъAZA oݞXurk.R"Ea^ZN\!<W >F5x+8؊1+QsʒIaa၁G<  DP~:uq rB~|#q"0t :Zzo':'`\{<-w79X@/ïH@dy dـRddm/74gÚo>wdXEW% x8!zF>~?ݞyx/-mXƳ|u jp_sJ JQ{TG8M\Bk/C42IF(72]]C| #?E@;]Ȇ4Hy("@T-|x !藂APJRÎ Rk@$K Nǃ$~J@.Z)KAM-la-V"ddg]06` UHN @=Dԇi9{ endstream endobj 511 0 obj << /Length 514 0 R /Filter /FlateDecode /Length1 2116 >> stream xUkLW>.EfImUfR" L!T>]_[WAJ@-T[HFӈ/mИ lL)>?|4 U[۔fٵ&GLΜ{=yݳ`t`Իp~*,^?{b,QKk%E^=BZR-}E2!*w~l9ֵfRnUI$GUm[2:>]~۝v_SU)~tJ ݦ"Q֠1h:Y{ۗo]V翱?I{ YsnBg%Һ1\ơT[qEJwܽ;w07y3 0 }pR|˲گv9sՂ66QLXfʓQZ)̚9J?*olWVr"Skw%/f'F$\.'8#AKn2%I|砬D{bӶ#ks}&jۄ_bG0UPW͢j}嚟eM3$Vxء%Խ?Y8gƧ홠azlwX Rb\G"T/v[ 5?9eg1F马,202->`rrm55|,Bc_+](lik"un ׯހv*5v jT^U,$\^9ˣC?gyH&ң͊Mˁ:E fZ8.E/Vf.-E'DFmڜj|\CIo q?)tsiJBؿ/d I 2! R(刧?=|3ymӜx.D[*?{Oȗ͵!7JyFsS#|4(B ; a]k`q1rP{rh&q1&.!M|>$n0$>F/~ye O\| endstream endobj 519 0 obj << /Length 249 /Filter /FlateDecode >> stream xڝOk0 :&;žucVzI;qCo?%k vN{g CiQE=8|4PG5A`[篏$,v?KK^86p,wi=x6h(p܌"b_> >>/Font << /f-0-0 523 0 R/f-1-0 524 0 R/f-0-1 525 0 R>> >> /Length 1259 /Filter /FlateDecode >> stream xWMo7qyM @hbܠPe)M+ىc-rWd9C!hR{E#4>#GZLͧ\-nxE݂뙘 -$o9'1Z ONx|/}9nSn?+㜷 (/H4ϛv&GdO2r}{ͳ]JK~y#G&d2 ,f:q1YFӝ 18CHRun/z6ֹB0cݾ33T5ek|+e.nZE/xԓBșѻl(C>ף5Z `ݎ$%>}xLl(}\Cqbzs;Yg܈l>ך8:/_7' [L4Sw3iD5\ >p֨TM.rɤ3Qv¡H*d4=deŋ3/67>8x*O&%1 r9i}Iaٿ`7 0|!XzK2ȫ,q\V$띑}dd9U(4;>id Apcfp]~ Y- qQEPl0*0X uJMT&0PP){ u8E(;В#"Jn+ͻk,%JO¡FmD%*8(œgaY%CO&Xn;PA (u"mι}|֡hAa-wMEo0q^aiޠyjԆd*G};A:FyB(JwJޖz# E%™+݂}hw] RhT `enDp)\@;*5ܔUJk8ݍEfw>")??4GuU=8{ٰ~Ӄ4ЋpUXEI^U?YTP^U-AcN8G≨OY}3\BJQf#樠zIT +vxb[Jv!K.WȏI$N?JSE;.=%,8\I]/G^4DR|0mrM#wG 0gx7K }W 'MEm* endstream endobj 527 0 obj << /Length 533 0 R /Filter /FlateDecode >> stream x]Rn0+|LI$ J/Pi?KTeȁRxf^guʳ0V>X[0{ nGwo&Yݶ0nR<6{sOs at>wDu7`5 0pڿ xq<"T-,^]> stream x]n0~ Cďi$J/}1ȐC޾^OJ=,;3yCq{V9ZK${:^t]ooi,(>^έ&425\M==)eџpDx:_e.{hv/ڝIfIm]>mu|^gez/0-sg)tDla/ȻTI?.*ckC4JX/P/".q> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> stream xW}XTUϹ23\t>`ȶV`f@'K،0# @ YǏP5ȴ5pd]ˏXD%E3*֠\}4{{  §rg}/`{Elg1$#Gc[p C h !ѣB "Zi' v.i͒ł_@0uJY4 ݆H0Ƥ1bJMD8lNv5Hahs_4F:!8[h],lMA*ם1 m*6[0Xbh Jm\yCnm|-qYze ksiI0mqKNLgV-foRpRX!(Dm6OB l2D:jޓAlŠ*x{H%{It5q7j P>zy;h1CQ٦hh8j7O/Xr,tiFG7.R-qPL0#$ 3&$%M@0Јx26Υ{10q%,S#oN침ݕIceR8owqZPoʅL<0?pRc//w^WxyO&ɳg%D̽6L~:Psu2}r^bWμE>bfH Arq XyaHtD@oWl_CΟfߐ2rwru~m-rg?EƸ\s/S!Kݕm#3N'Bq,r~mJIH@,E} OxkYit[4{]gf}_7O?½-!FB%W6+(€' !@՞/":\snAÙ&)vC|wyiZE8xϑ]~"vvM]$0x&o@9ū+^;>P^fط!Z"4פ>SGw%O?t"'}tu}*^>e3$QƐTŗLA1p;9ʧ01RvȤGfs6`s9Zɕ[*XwzdB05m{}?=ބtnq?".L^֢EBZ(Nahoh7Vs_}.?/Ȕ"$ ܟ/L3 pobc8ǒ%u^S4Egb|G 8x{*ǽ^Me2,zX#r5NՈϜX)fE- ALJBXKsy$ #U,]K*up@t ѳ7z{7K\dYd<1oFR"IHf}ޮ`Čwí$`{_v!NI-wL_l@p;Q:r~.-hÌwS ~܅_a4MGߤO.";zqaI?-~ݥ-N[?;J& Y |pHvKUA?d~@pӓV/} x#Lu0_c\P-qNCۉV}Dіeq`&| `=/GKó+3ޑ͉\ N!U"ۊ<;G 8FЉwfpTx=P[Ѱ<ú<Ƕ?bo@k"_H?ט* endstream endobj 534 0 obj << /Length 539 0 R /Filter /FlateDecode /Length1 3920 >> stream xWWT>az3CaSBJ@E(W-mٲ|n"CQ+7+ޔ*0~hZ3k}ۿ9!jM(?QȖB=J+\dOJ닅ND.|f_4z΃Ul}g!<7st%$@"'!}B ሊxoGU+j=)ZA NzHj .@96$zLvl)[<4BʦL_@f'J ZC0{:˗URtYh[>K;K,En `4QrdckªG* ?`9hm"AO՜ä2F%d? seY6mjz}K;qj!)`9c|ƾȤq~B~W t;A. D.=/+^(F -Yf o,9wG>d,EC&5j|8~.а܂E|.]b{i@!uIO^~dh ]\b!AL!YTԽu[Ps%d D^1h4y)b\y;G9x*j,,/ݸ\vmj}""؁CYNߵÓ :Vfx u[U*bӚmZ fa麠4snq߾c~iT c;dI1@#`R˞`p ieݠLnQ\XGֽîP}<4Փn$f C ш8R6" x隔lqS.;ܖ* :8KNA*1܏a q7n*Έ\#\lC0b~?l*+7R^ago} A>>X^Zh?eﺿ091~mm̞~1!i.^TWcݥNT|Kw*vNj|6=;qM $G.]3cvRdpj mYm.Ʃxa"'r:HESwEet45#|FGb1#mێ8+.`*~+*f&;ehњنB/E# kw}C2?|0I)YKVN_8tt5܀Чh-B5{K୒E;EA)u.ce/JOHHnafLZZLtZ7Pnlqh%ugL>r+\)/50ͯ?I { 0DV߿Pw+?N/{{1Np(<G׋f:wZ.]: ?(Y[|B(w8ND>]Y4@X́Zv8c'5vAO- kًas@%@T3װHǷdnY.? L!=COOeMmܑ3,N>ffqC_@8}y9U)Z6~NP*5l̠p+)h`XqV1u@3ͲTwl?bDrh*s*\>@C:p#7)II'g'4wߍI&\9rvȱ9ƬB5vsvjl,Zp&?49ڲ*vL `+[Ae=tDZ7|,v NLJ AeX\8h:,ZU[R -D-\^uxێ1ȹjlg*rK)}g<`8ʾb3N't kg7y3,m!Om.>1}YV֠=w9z^ew\(|d}=rZZ2;TZDy_=aUc`$=ڟ/cA 1d[LTDjohNE]G\NJ AMMؓ顟pkKT0߱_3U7:k41l߸hh ;+;F"Gl: f)èG-GbI-,~s08yil5U3S'vlZt)2s}{ +Z]b}_o2nmFbbzzbb1;joS샱j/*{]񁑁͢ ;"3!/s w a3l60~Q|;y.\O{;uXi+7bpЛ&he-{ bu/FaFkGy_/٫Z3ourC}[ΰ~-xZOާ.d_4W=Шq? 0+Hr#H1‘KcI L{)$O ST l߅yă&$&Ej Y|)Vc~)ϢH=Y =TRD"0:=4Ժhхzא <] L\]DNu85Bكp`T:X{~VqD@ٞ9Qν^+ogbͥ endstream endobj 540 0 obj << /Length 541 0 R /Filter /FlateDecode /Length1 420 >> stream xc`d```cp``bPHϩLP@JFnI C-_s''?@~M(`Pc[|Vf @;9x9YSQ F'LnZwS߸5<*11-"& IYMMM̌ԔDELmW?/]5W'}fnSܾEe\cb Rx~  pC<}$NǾW8\N ${?A~Ȃ#sC ^} Y endstream endobj 515 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///2_feature_gallery_export/D0019_Block_Diagram.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 542 0 R /BBox [0 0 800 600] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 543 0 R/f-1-0 544 0 R>> >> /Length 2333 /Filter /FlateDecode >> stream xYmowQ; hmhc_ pO'qeiZrݕN',ɝy8/H(lRb{hِ%~hxFTeN\g_^t' W_ %jHW'$+~u ۾lJ9߿d3Kt2<ިRW}ѦK33PYmMԾB{C{达rT. ^PP()=|!27Gv(X;q4voYA DR_+38vj}ϋ=un/w{ͩC㵈Azr VheRwڵ|vZ0~ǟv3mExJɄm2Q.씓Ngɓ6ZOF{ :) IA1mc3<{Ca@"E;`r'@FI8hy2D &6R!z;f Pb{9!¥.1 ?1F 5` Sy|>4IN%lL$ƿvn UP9v$A拾h/#˞CA !a, Qhsq(;d`>KsƀuNk-kπkU51AS#Ƿ-~##7ﶷ/wϯwJiBx!^~v|J (s57[B!z alw>E6{|o)'}\v؃4tz\;<N-2*-8<-AtaTt/8ƄV6SUk5""k?&Jit$0Ox1ZR=g Ugn+3ñx3hHhR)f:iX I;>AX+Og$ YZ@`I;.pJΉ$RJOl29腤zNmr8S@j^%fp0?,z8yikDbdeΝEuJQBqAbk~j}dPnsh:;ciJ{9 сd*QGW~ӑQb&mqLU&ShNB+#s66`68b;(pa4̰K(W}g7: t4>ǧZƃ_ON^G[L)kX3N95yia4i; zΌ".~;y$6t`SX}/+Eۉb^1)EVlP7qX)'A*j7w^tA-%VAUBg:4蘚* )J0HkdXۋ>R cWM7L3P 3O+[Wz hs~U, 1'smb^ĬX7-1_P:f+~Z?e ְM+cA&$/5 t>T 3e_x<0yo`tA8TkpIk3$M 4>ȎfH27+8̈́v%cRiCpM9YǂIuɾeq>&W y(%q9#{h Y;Ľh18=|ЛLXߙNI[X@CD^%0slMlKRNbuژz pPG:$O ˑd6CdT.Z;l&G&JiD00 W5#Y; "e#{-blk>AlzKr{tz_=ߔؼqqz@ endstream endobj 546 0 obj << /Length 550 0 R /Filter /FlateDecode >> stream x]SAn0 Cm:HQrCn&H@0_+J{j._yL3.Q73NszYqPi]m4l__=(Sv|ǥh[SJ-sXz/14Ny92t맞uLU&޺;)s!i=߷UMw4,A/k7hmUM;BߞҏGՉZUi)f8- #%=qp]ey" xGbIXXWrx@ 4-9˺u---Z|G#9`c3um7ozbZĒ1s%vtS_?TA/B}7o}99 8BN? 8|Fݡw77O=]ػwp ϸGy ׄaqWg{Ƙ:_<Ϙi;.+ɬD endstream endobj 548 0 obj << /Length 552 0 R /Filter /FlateDecode >> stream x]Rn0+|LH$T}:A*2wRxܾn\ef*Le rDK3=^$(euvu-O\ְݳxR=cyUiv'I[Qyy\g\ ,zwQi#kkˏ,Aԅ4 겈bX#҈1 dH21 V쩢q8gϜ< EgmIZe`@\ONZ ˁsʩ8"q1{YYU8GI_1{[ endstream endobj 549 0 obj << /Length 553 0 R /Filter /FlateDecode /Length1 5332 >> stream xX_N4MZT4VZ-.D!lTP!labqudȶ6Yn-ך<)~;}ޟ3#D|򴔛{w@5!3˜93}ax#u3%OC"' 2nk7+]+\W?0[ Weh[P8$C ꊐ^w" r̩q9'naz6%RwX1V]Z]IKbڄxvAB؍ת@^&spwr}`!Ht`~76pbNdXLީTE.G}Ys~MCP`b\+Nj2 Qd[?@[C" i5Hrsg@,;5=NYe %o(Tx=רj%؄P5 82VCB1 ʝzpKGp1~Y_CnMYdg]RcH/7b5Ɯ!j>4U)t VH:Xc2W;!7\Z LMx?fV9{PDWGiڀVw.!gʠ`0 jtd6&VaQZ›76z1 A>z*CŜgz8^]ܮK2uY͏ˏ-㳺/}G_؈ 3&ιx8.$?0.hInw0 @it~Fw;ί0QnLȴAk3&?p|S8 ci^.qJ!M8`zAp9dhEa;v0 ;`0AG}|WvVT/ rDOޔ u,Xed YݤKnspЈi%_7u)옏fY0oJ]>vbxPr*#*f؟пB{ 6zXeQ  -g͚☨1bÌ2fmi+ӿyEڵrz~o"~Go(6*봔e^Hz "/(=N&'pjwJm`=}MpF{ApΞ^npe%ikXSM_`Yu R?4%5H4ɸ+nhͣG\ʎpUV{/ "n +ضtqv#Zk{59Gƞ B;n , '\cZ?59k>8hNWwW'/S>$ 8qf^Wi|Ab$HD[ځn1e@ݷ |Loļ!Vk]C6'JaXrqp*\{t iC!>a^i׾"bSrs^Kͱɭg϶΍5S>;읛4gѢl,X3UUg% 32īs-y0ЧTyˎz$mlڌVLj~CO#n^v=G[V=>»O?BG}GT;OoNiBi%&Hw+Eo[Ss Ӗ7|A}[eq)iR<@pbJrJ 62q Wc.'d[bj>j`5 `QצAS~WcJZMXoV;yj p?2U<7ㇳ$g!sǡC?Ϳ3ed!@_wN[ZG!ҷ9Rc@R' Uh;ýR{$u _}5nѓ[5q3.(wC`_9ZI$K'j\dD(k³_Nl)#u0r*%>k8>K=CupP@!RGtHAs-䣗~#g{y%~dbPK+a6D!ï|*lM70rJi?њn.MUt#Mf_փMfj/d,,AX΂Ga>oՒ$@Q’ qggzJL])fp&EhPt8 F?Ȋ:pk3OUfsn[n-۞6;i7˖9CEїGJe;f2=\q?6J>뚓oMe2)( eHʦOCc6WIvp:taU 15´Tn+z ֩cL[Z ;4anOpdgILQMnA_W*dZ=Εi6t\KPٮǴ u7=M9+hIB_⎍GޛeۈP21?[1u䗏@YP̹x#BF3A*FkL`#HhĄPr4~,wm8.&/7nRdwj@~l+i)Ucմk/>%ӄny~H⧣_{t]OG5qt@a i;3D\-5@f#kD'fElޏy*>u?}#wv C6%xQ#a4wos: _Iur;O[syKm;kGKƘ4#=thxСB""BB>.CēBp ZGxp!)!u:ooj tNA-ϕ< ovl<>e몀Wgw̔Qf^C-pcst|iYσb29·qVsH WΨOԏ h֏MHuSQ}QAkIl8Z~3D\P>E@}S$ݷd~""{,/PfB @" @@Ár!AZk> e"4# G{kh45 >w荢Fl m!{<@MB?|*"P^]{nmb9E5S,2X/ wX! ؋:Npi>i@ ggX ]` xFuaq@]A̮)@EwH tru<1!u endstream endobj 551 0 obj << /Length 554 0 R /Filter /FlateDecode /Length1 3308 >> stream xWST?OaewEG 첈FXh+DD%ȇQ?EIFS5~V;ET`ˆ댂 QSqJQb?w羻ws~ "%)n/_ 1-L_YTzjҔT,|.ڏ=D./vzyVf-I(~) '*@-A x7:&Nҡ`TV/Axc} _%$9I.ܽ{,_NbI#+$ @0$oxG&h6'}o3 hp8g0Ɛ`'Z4nf&ۛ.|DݚutWǭŐ[A]Λ; 3J (8/,rHCJH8o@)KgE$,Al UghqPBdc{~ڭ[[[Rs9J_g7 ^1+j66d- IS@ҍIfdxފxB!5Oր|}y.ʈw(lM)u Z-(~ҍiS-K .-\ 8_h' h(;sPR[¸\H_`41p"a;,Rɢ^TyN.sa,%oS:zN-:a._*xFH~}_GyEN&a8!=/zßXaMJG;ofG&$DF$$A WƐ40}f[&d1]tFaxpA&#oFmJ]2c^sl ?n\|m¸S;;yҊ/ϝ㡉9#u#jR~;{ zB7D6ҝfgSy܉%99%ɜq^pMNufU F 6)U<)6> /|? -ĜβS1ЍYP0mUɪ3U^M1 WV+ y0Xb@,3Z FlMTLiֈ?46b۷5?=47U;Iwg Y7,2B#y&fcGB(u 8Ag݃CQƒH`d tCEmE`m;š'.6މiM]m%yYXaWkOkN]4jZLk:iV eO0+ΝhF|?ҕC|x2O>Iҙ<-Xf>DkoG bxo;.#_b*gb\Ѫ#<(h rR%8/GnX/wCڡ+^Mj9e7f0cœFE_Jņ%|RD{_YjqOǓ Rvse !u&31fΛ1w2{?ސh=~=40몦J?֓/t#>Q@/ T7KJ5oV14m|s.xdOzI= kun+9yIdmmR0R؛^,,2Ert?S%?Rq#DBQb,Cď Fاn+J)'0QR4O F&R?*U۩NBZfNEF ѷUU;*Hkg|4w5Up6-4  endstream endobj 566 0 obj << /Length 804 /Filter /FlateDecode >> stream xڵV]o0}Wal >NT-کr hS4MдS{|}0+܋>c)I| h <\3 % +ք#\ BB_bN1U.9?3xd/ ^L0f&fizXA?2c ֻ@I#HTݻKkڎ8p@Q gYlo=JabӖ`Q8O:öh3˛RQf5!**!\HnetuQC $ SjvacgJ`xv]@곺af+6 (1 9`N&+jŦ7u 4u2rGQ̂}udNFײyaj \b1}= kj})驟t- 6;&\5 2*J}oBtg4R}jUmmĶLvx4 Bf :t5HIΣˈ[rSl%Y=u -ןf#meccNX.Qryz=3e lufLc;{!>Gݕ˜֢Hl۝1;v tiSk)T>uUUs+J5WxvCXzV@)w͂9SwO^4AVJ6(Uwσ!.g'&}9oy280]#DViNrU?4/Uv3AC@bm U2LMh,R2M(woZ) endstream endobj 516 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///2_feature_gallery_export/D0022_Parametric_Diagram.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 571 0 R /BBox [0 0 800 600] /Group 568 0 R /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 572 0 R/f-1-0 573 0 R/f-1-1 574 0 R>> >> /Length 1330 /Filter /FlateDecode >> stream xWn7}߯A4gx/\S 4A*BSŹErXm%gᙋHh|&:'Z\}FUa=")'>c߿oVZH_Vagӎqj"k^dt՝,&zatѽ_IP4m[wp?BNdӿ+*ei_ɰYfqAfgp+A)et)X{c4o h j, b!kwa'Zۿɮc '6.ss-O,eۉ*xoӷw=ڕe[ Hx4N)8 CIXՑu6{ٜo/%SR?_I|AU\GɺϲyֆѮo$XxrZf/[q/Z{է3qv&=?`S5/B:V앢#/D iﰏKU>eupH 0q@`=-S #V b R_n_ uI;,2&Fv[+/. V%xxZT1@[KڦI.4Z!ҫ Pd󨘫)5~n%6 }<Z}@0H$eql#Rl+Ũ?  ]UbC0Zn$!I=sFlsxS94h7+]R@K0L 2 H*ƚ1Em6GNAn3*8Trw:nܙf?fqerW9ﲏ*[mu'#0jU!\ dʫ:lĠ&ޝ#(¾ f^tu5VS endstream endobj 576 0 obj << /Length 582 0 R /Filter /FlateDecode >> stream x]Rn0+|LHJ/91!}(zƳxyEga^0z<]eqjSh7*ɇyj}z䦞:{ z;:\OՎhͯ݉u{庎i̺Hd'繳:dyah{*j*y 7 ǠS$Cx'DSBS LqBKˤ7 M-B]Bo$hhJ-.aYHjQ \ ,$Rm@CcDS f7ivɿg'> stream x]RMo0 W*(J]8Cc8Q/{/N>n\!{p;:pA# x8`FV鯧ދ,mYqjR}e <- qzr4`F޿BqQ&PEp BUe1D~0#// aJJJҖGH>},ad%cI5\CMyyMy>J2_<0/G&5^+$ao/HOLpۖ&:5:ϔ= Ǖa endstream endobj 580 0 obj << /Length 586 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> stream xW[Te?{S.؊00h+0 d*agn(H*%kci߂@hbce{͞}/{3w~wF̹ &n M_i]&w,Ҩ  ><';wAqDon7_̜p9_1~5wVq$Qq Y`Ѐ;xAΨsI:"I=l Wvv*^ƙ"([i,ܼ}hA3lX ^5=@:Hc6t]WΑ7JKߠoꩃ>0v)#}~ ۓi ;*߇zG`AEZ3M[\U0%d-SD[{wiJpMDhIuQڵo?cގÎ9:r؞[mފg$lR<> i(_w׋6Վ߁hp[*6Djz9ׂ73ߓd/I|{T{kip琯`>`4y-MBI>{ܻi$j9,}*Ď"'wvk)jWĝǪZ6?B\\ff˳*:y}ډs<ڔ=S8FUV,M*"q!F.% goj/dzcb5Ϗ#,6[sroh6>7q.xMl2=js?(j0p{=~WC9> _D8ƍ P"Y-#-nG6Zzf\:qM;yA;Bc@]H~J~\!&)0K4U2Œ   &t2]UK۞=mU"/Q$$&ATKHKyK8l2ѣ;b!>-uYζ"8Zr/1.?_PgL>Z:"7y*܈w䴭6tlJ۽MlĥmX4Ag7{ f)C DBkz|7{"-ط<^Dldhyu(na?؉5}X1`J0m's&% g@/Ÿdb$FjV:/7rNͱ~S/ŘQIj ^R_+Ϧydn|mI%jM '/ _e_m&ҺdA>X̚VQx1.JQ mCpQ6 q|'[0ȑCMc%a1qGw=N-N0\ߓ'^MfC5Aѣcn>}cPQ#ږkSOXЄvH8 ­*KM^4r &VFmDlU1+PI# 5UM!l~k5Fn{ 9Asz{1 g^k&~TTUテĨ{u}x8)yTxHʹ%6(6f3ޔ_?bQ?K5*VC%~Mo]Έ pL!!C^9;T'B 8~׃LC^w,~wF?#nj[3w+} {y ѻ„JȒa83` z{$l1 HKJ9( A6DID)B)EHX%BxK0b)QG%Z~:*l7grAE)@م,bh-HqkQRW} 6G֌> stream xVWTw{첼ŏhxjԲ,bB QEUPQ $!zbQњkD4#Shm,9A<zb9iOΜyͼ{@`0|ޒelo]`iiF1Mjɚkh,&g-YQw@ggXr멿lIF2q懁n%A/0@äz1M ݬVݍ hha*;S',]MW%?C,@d*$͌64[[x@^[p֙[ّ:ѥsi%6Q'N #t:q8vUV3"B,򠨘XͪC,2>jxdԏxS-z'9Ӓh=nxbU/N0Sx̬H5$Q]@ /g~;t8/yz_]ƫ߫0E2'k @`v*>R AeZeAQ+Gɏ1jkzʍu7z#:i<9*JN.s\c2$ʮ/$/5 #VFtj˙Ff-3@i"a!/z6›40r_ +g~ϫ2t8fl a6KK0t[2U>SQLaמ;qړӽ ^8d+qO&zy؇^B^zH]L SCЮ]ؓ7Wı8rnK{U]ǿfwx9;N3d״ȉM:r! ͩePe+*V%M̧ׄ յ!ͽwHᄐ'*> stream xc`d```cp``bPHϩLe;P$d&06/e``2sf@JFnIGC%_s''@&c M(`Pc;|Vf @;9x9YSQ F'LnZwS߸5<*11-& Ih8"Pi.u?t^Y}髌cN39ŻRe7>bR++m2Hr0@8^(Ha`cY5Pq`baHar7b3/10] endstream endobj 597 0 obj << /Length 614 /Filter /FlateDecode >> stream xڝTMs0+t $&4v2u'aʇr $at+zoV'gr e(qHC 0f(ZehN&IK_O9Y,{^x Y*E: w #n9D" AQZ9g@ڻGXY!NS*Dߜ skb!đ`=b>LaL/d`.>WFe{ 7 Ib#Uki(¡0Za1'<nӔ_ˤ#Z@[pDX5,c0Mr4GsjBҳ{wc0H?y"ckK{%.8\19J,%O燂rEFOsB\NGRk{ǢE5c%(-ߴڦC[,6uQށs. (Լ>*rwC)H$pD5RJ1(K$+@D*mTl}52Oeզ)=w=i1Ck vxzqvS%|㫬ʛE}ifu 좰_xsF/,q 5FLW/] r~ endstream endobj 563 0 obj << /Type /XObject /Subtype /Image /Width 1120 /Height 630 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 87378 /Filter/FlateDecode /DecodeParms<> >> stream xu\SlCTJ1@0b+vab &H(e R" ^~GN{9 FE"@$H 4E@=jMuEi1N@UPHJz ߷l*J$ px\6%NiŠ!DR""beG! CD","JR5p^ AT15j& Wy n@gaߨKDdip^ /:WG.cf߯I/R]]}/_VTT $%% 䤨 " JJJpWVV8jH>>k#6؜⒒R uXZHExo8rН]b~74OF<.%pF MMMM U5پbbbPP֎AT;SRRhuu766655<N P/pLx-GJ3CB;}u۶{Giff%++}Ǐ}`?REEgϞ'%%ݽ͛CnXЯ_vʇIb⿴KYYQ2v Bo߾{Nffhǹ3d-'32mK p,KHHMvK SoHٖh$c*{n~ä`T Ο̌BO<É;iXVg R1cΚc9&{m.\\`%K[٘F?~|׮]c6m(''yBѶnvy-^ת=~ݻG;:nٲY^^$|}}}/_^Zt:}Kdrƥ{ 0{?MjGԕ%,.;gB9zT;;jI`x<޲+ i㬿!!qtuU}6vQQaa @0 ҫW';wnȑ|Yf]xQ щv~BHt#bGv͚5kMx_e)\h'?>󄉞fff=zhvQTTDR說M6ݹs+Q_~u`dd{={q/~`nݺ~ag$Hee勖}"Ћ/2þ ~|WXw`%j%&TYYŠ JJJn8ׂI$D"8NoזEeeezzzUUIjX=&9s'5615''+,pիW'%'EFDb}g SSSMX۷E dɒ7;й{ZbҰ˗yJTTw?':}L<5lq~(}}}ԛ7qk׭믿G}`h0qҥrrrW\YhѱG[^ޫW^pa;vr功cGG-㧬̝;/ ~a^^ύaK+m-VlTڴiSHp6AǏϙ;/GA-ݞ8|RBT!55zOѕM FZZڇ/|ޣGM76k'Ol޴QOOKrB{Ξ5`o[E'e>V]NjI1y[߾}k<͛۶mӓ~=a[pan.7z5'zV3x'SD"e|yr# .:y`ʼnˍ >k׮0]Ht̙Ȩpر.mڧTj54ڷ\;qKؙ\011oPVVF3bĈFjk(B"¨=~"Ϟ:=~o:99ݼq\PE7|3g6Xgg7 *A*++<50pOGYy݀op/7)Y/iMr…UW.9Rn)1AÆ=~o-jԡN_8`?E.M|ۭ/<9ùsns{דxRRRG;֊$?1~Ljv$-JkY?nɉ>zș19ԸԪiΪjn>ƽg?O0AZZzNNNשּׁ;w޻w]_t gl7t]ˆ?~XDDD~^F~sBBaÆ KJL$Erf~ k󰇇ɓ'g͚iԸ{xXYZZxzy<H .pY|eGi) +CT qRc+ҿ~O,|||?}@%[oAԬkV}6Qbz҃s4}dlhi://^秨`hhӧp!!!eeeEEEҪZٶK[熤BHA3t$At/ֽzW9YEBx`LgOXaZsuu 8qbU:::NJMM1bsW.=/)/K{|<]w&8+22y_ wvv>rF;V):-JtW@@3f4~ykiUDI\ZRBZJZF°`kk^z5ի|#K0lBBэ7dLg&!ET1,@D %\ ?ƍEEE:*UC;wnk}&d墨 Ms-[߿y.Zt͎ڵlll̙C9;;Λ??Zj7_IeE$) Y PU/--ݴg׆ N:3r9MrHHH ݾ}gW``wb0l '//*"6 /5捛! *zK[tS6σ! ۿر666 :eqRRR?}255c2Ó?nggg !󯪬|*֠dJedo ,,le1˧:B1Y<ڕ;Np8Ls("ivxy''qW뮮]Vh6F:;0LI>.Wph?#ƿ+w?X/ۑ/ h'_H"* @$&%`֔Gl߻pYƦ:#9 l6Q^[^AKߥ||(wBi]6ק :bOkHFJqx^?[b IG\⇌WC/ɚԾw'"gM|r۷=zt]~ڨ`f5 Хx߿,["~hӧ~̼'A+V9sYLP[ێIIIfUHF\,OMPBlM^qCRmaMMM'ձ-%ȳOOW4HJJ*((~fР]y{6akK6olcg'a6ҪcId),9 '-=21Y̡Ç8vFHK8^TT_'H231A '0B-I9;ef.yRD}Z2ɱ0B<,TQqR뗴t*JUD჌L$$1|Pq6---fz t^i`~\!r{$p}P!ojelj!999 FFFPC RC%%%LVQkBkZA0cEK;qգi- -hhc"##[ڬ`p\xw=Bhnnn !daaea%k 4TWWoiv qqfwF$?X5P[Q22/^077p8!"ta!C~ƹ;ש3'|뛚:}R E+)ˑB<~I$dk*o;X!˗Ht:ͦhT< %!BEAFH!6 %]XB,ھ6싛KGHj|锔xM Tq߬g`s+))AU٦eڄ[+Q[uoS .\(wr޽F eQ%aXݡOMwQGŠC 4eʼ#ܚϜ9kݺ!đbUy芥+v?o޼6|l~ޖgz!BÃVGow`/_ji<O_tb_nڦ?P(EEeeeCMLuttCJJrZMLvh߷W^{G4qx$@6BWDB8n?+&`qR!Cl jdG!sssGGիWoJwFoB{쉌o>YUo?SFFfF ;;}~VWWUV\c" ~Į!~N.d6EJJE=_=~bۡ i˺o"}?<-퇹i̱39!;aC#mC#BCCDb}fVOiUyv߷󫪪\ƺ.]DLLۢsJH(GN^! `]lʪv?&& p 5hPݿ\SL6431Df5ܘ}$V\y MMm۶5 "݁=78߿9 Q))G81$F1QfhsTe[JBƍy\%V o˖ڍq~s'$o}آXKϛ7Sw/uv";7q:wz =y;)Ȁ-P $$qQt&Ozhga*]P7΀T^^>i>JZ'oˋʙ#Lϓ:04ťy_BBٳg»6]+=L+WtW`'Nص.۷oag]4"`XUCEq[3cRSSƣ톽OIhI; WTU㛯>13mdDr6TTZR>o>|l0-u"3#$f\Lyk}MB&Lt)<tיs?}8sؙ{R}L'<2+mcwa|&H$2<~855?ݳggZRbl{Z!ÏDO=}e%سgφ VWWptÇ:uŋ:uGvv{!$%%?Z1dkk>d2b hN;Ax$Z0 =NA"xKO&歽FQ/YXzlc:Hd!m2^O;'}ABO y4vJ][!8#CTMmJk-FA8?owB#F),,)Sƌ啕|rYYwމF U:go tuu=۷}^P ݁4[bl6'Z3!bH\p$" x+UTTRb͚5sJ٢;Zd̄?% cǏEEF̞=GLL67/W[[r%AVF&;+[EE۶n13p{755ypEnO tRrrB Z{}JKKhr9ޣU@Uj(Ӛ>cOO3f̰ñegQ|ˍ8\|ATXo/%''GEE> ƼwyÖ yI e 6n<N:#?87Iߑ#d4{ S!k+0{֟ vtҚ~=/393cMxiiiyyI^#`f>IRM!f̞6C|fٲe'OLJJѣoأHtzzzu_,i5,0L#??_sPKr5a$/ )ޑ)GGǷqEEEVǻ3̔l6[0kkk[waXKCMv$oĘK͕nS"%T 7B>6:q Vrcuʴacp֯NO}PsQ+?/vP.(VRRKgw'qb<gs΍;λ%@##n LII)-l%elMՇ_!Bi5%4AROII)b|t+>iaO6*/./CS!zHUqH@c4wB*l=2,t>z)-7| ~r}$**V.o^hf8.7^o#GwOϟo4ցZ|AA陞>a„Ǐ5ݻ\.!t)̱'QB60ClߡxNNN>>>ӧO0dVVV;DʰBK{+Oԣ%Jyk_^6?B$ Rzz{G6sc%ֶS18SΛ5y7n"6O<믿,-- ddd$D$ލHK8n:/AzunJZTik%` Y z <#: ܭztzϷ̏o\=}2:nD0P~ ft0%*0|FQzpwoi?See}IIIll,蝑#G޽{ԨQGutSW!r>֖5WxIII%t`{ &: 12"`H餱m72ߚ'w$HL6\BTAONtӇSG$%%999$+#3KKKÒ\?gʞs7l뗘I"͜9͛{믿|}}g̘>}\451"??ӧNRVV={OÊZZ޽:thUzo2aj-ށ(mP\\z/AX=YYYKƸ1;70ED"f#ʦ͟dH'{ivnР*qv ~p0=RL$bJ֕cmB {,:<*mf8z?>>O<).. ov߰w8;0+ ME99liqJ}Z׫ ;+¼3JeO(bqKJMJKL?٫tGbSΙ$7 xyyymm---m۶rkWèeee]`2!..kVVV-l"߻]w[޾}[WW'##aXX4HwHZnU`XYYݸq#-U=JJJttz.يiNJC':uNʊj5Kks jU"h0zСÇ 7Ik׮_fMK^ZCC#00{+ELgcPY֯_sM۲o7)8"$/|qnayUlb'&*F#NOL'^KGTTQHD$KArHD,Dg:6q?²2B ->ӻo2Q7ۧnhh̙3[ʕ+ܷoĉz؈ikcTTT ϝ;7cƌV67n\p,%!F޽{ΝMO;ꋍ4nh{ѣGHN*AJ&Mv?E0j8[8[\tl/ mۡ%vUU?~*$$daaQ߽{7|xZjӧ/^\p~Ȑ\& lT0Ⳳg ?έS H$"{\7@4T*UOO ðKb$T"tߠ**=BEEbM8>dAvK;~Р^^ii۷oϟ 6wR X:..N灩nEoӫq Aq+z8jVJMMqFFOf>x𠩩YlNF=FSQbb" v']ѝ#.~le'm6@wVcg 'H;6l,?HB7aAOE1ťk^ii)G8\I|| !ufO/oOOFh7YZZjdd\͛:>d^ޓDB8rŊ͛6v0y}]=w#F8qde3ul'1d2YDTDLVPP齧?Da߿/'Lݻw7 vR`W_$Q5"a]]X[؜]iMCgfTk'JW$Hn^qNAAٹ=]NnnC f*2Pttt&LhbF1 da:ozTG|pWEBk!I +JJJ>c2}RSS{,v! È͔̊M& YlVJ!H,.))4099CffTTTЁYYY,6J+..ׯ1;w4\?<''ڵk1ϞveVTTtJnԿǎ:;;>|ã᪫W߾}{ĈLM6 6Ǐxqv}<'MiÆ 2TP8z0h999Yh΅۸9AD`4\ucǎ9~p6GD% {{SNH$.{28dD4@!Գg 'B TS[6 Hg2>AR { r,Ǐ>_t)##O>SL)((ȼmB}-[L2%((O>=z۷/JKKq/(((.XF =},9;'  w(sz :#;%H'd2}\KN˽1!ڍЋ8N4i5]YӦOOQޙ镐P 3gΐH'N4#ڷo߁hȑawNvڶ6lGkI]K-^x1XE+"9t:/_.\+Cx,hs:8ɀœ}|>|8x͐W^+**q6 :X[2I =ݯ)YSS]SXXfq?r!2\RR.v4ک644444D[K~HOO!CAUUGvbڅΑ#Grrr233 ZsB_ $D240~ɸqn &c͢ӟhjT5F̝+B:̌Mjkk>F8:~x}6xHZS]QZBgx\^@ DEe!; 4H$h6f(O<+/@k|)  tq)"s@A$ AH50H2P$B7(_( AH$ A_ ~#7n]]]4r4IU H©>^볣F<f7vCSkjk[_UM[W1?ED8;9򳣆 As ZZ[\RڳgBew'잩qu55 ;3cs<$oZS[+-%ZWSS#&.VBꚚVV/p8"\\2Y,*r^G͜6@-P("""ͮ%5cx<VV/yGA?¢'8VVRrq8*H 4{ c! 1 STo};w]F&NQ^^Wg_]rH alv`46T\LU_{:٩ ~SgIi B g@<̻hZZy_=L$EED,m-M*{'$=ybɢZY:{"1εkRS p\W̏GO;KMM3f v v/22"avN.6znUY99Ad~P5gҐAji3#`A^(+;{#?~RTT8rB$H?@$Ҋp(V8;;C!$H|4 qqq(FQ((#FT*Hq ݻMLLFv!C@Qb (dذaPR^IkDFF^ o++++--EԼ~yMK;hť0L򼼼7o1fTWWz)))qqq^'H:݀0 0Lwx&-RHo$B)p (R""zE(Eѫp,^P){ll7 ! &̜=sygΜz&Nh^^^Õɹs+SZZZtzFFư0577[ZZ"}}},Ǜ0а0;;J53/pbbrgCuRs̙<]]]ׯa )Jf8D"|VM_xuꔓᥚ>]~ڵkvvv|Bرc&L8uTUUջ#w}wҥɓ'ϛ7}ժU7o,]D"۷t+[ϴ+VHzf̘q]\޽VkjjB7oތ= dgg+J6m8Q.x<?BJ/K^@`h4V9=Rzz7D577tiӦggg봶/ Bٵ}'O 4Ǟ^rKWub 6͘;o-%~kg΍}=OV;hO) |7ܽة0W_%HB0!!|`_|~GGGPh"GGǧzF^:''Gӕ$&&9rbϞ=ϟr_r !.ZAOzƏO.+J 'r8kZR}}=˥R|>!$-,,B`@ܡBk )PCCäIi=c>gGzLh"~̪qMm17-=c664'hjn9zk<'>kii='O|QSSs-B@;CF}}W^yt…'/%~;;;%>lNP(1 ßį!ӧ_zDGG߸qEGG{xx\rL&㗩`0x6;;࿃PrD"{.a,!d2mllܹC"ڪhjkkuCCCjjV8q"ZGA\s)aW,[X0w΅/,ttO3{+Bh^b2HzfS"2߯\<{n~ᶭ/"v v'L5@¹;vlŋ-rij@mmm\K>X M޺u9rg͚5DGG>>~)B(00Gb~X[[ K=<zѣG!: k뵫V~)[P(?_όԴrԫ?teK}y*ϯLǼ<BÖN|{_O>>&&,X4ΟD=믿.M^OHHxwz-( ?@rwwwrr2+VXn# =s F]]] Bk$0vP( BRi4Je|>!NC`)FfX4FX!`K$*ATǻBF [;45&F[DBKk0dof2AAAT*c>(P(ڬV*' ( LF(|0233#""lmm!:Ś0aԩS% 9Bt .nVpjmmdЕ0\.յNFC34j5ł8`juGGcNRC9b1LT E$0twwl(1.!!uNRݺuիyyyØ7q8\3`8i4:0ƹrj5eʔY͛7---FjPA0N#׍,{{{5YmffU0 T* d2c`t: @2eeeUUUZFM8ʕ+SNںpP||qt:c0!FFG&wttljjRvvvR444ҚiӦ%$$xyyYZZ1KPb@*_KKFaXx~YYYd2O"Ԩj6n8<+˳d;3RLJJ R* !RRRR@L>@BQ((K*VTTDFF2LJhONP srrBBBB,+::ðR<}KKKxx8~FRO4>P(RSSt>-,,Bdeey{{.a+M2dݻw 撯o{{;t{LSAA5qNH#]{cD"zD"t 8;;a 5\.oooR4ͭ0=~`zBvvvɆL&d 庸ΏD"?vvvL&!$D"X,xxxrH$J0eʔz hcff[VV! >lt:D")JRy&F7nܸrzKKKpdCTtf#ƿL&?Ɗ BA"j&uJ$66@"d ~P(666 z\^QQaoo?-h4$ 1% 3 xH$///LP(͡LXpʕo VZtR|Vٲe Zr |xHQ([[[Extk׮]~!ܜaeee޽{ׯ_jĠ Pbb+W޽O,1nܸV[[s ¤I_~bA133?~|RRҭ[*** G\g{qW^-,,}񲴴x$M,o[n]]]ŋ/^zꩧ޽R~W<}rr2>(BΎj!/\299yԩgիǏ6mO?=_}UYYĉ'MTSSs{N/vڵ~v1Rlll3.]$˹\n\\̙3B!xry[[dKp,Xgw|=(.yyy+ KK{L&ᇙnnn;w0죏>'K!!!k֬y /=ӧOGd2<ƍׯ_zfff= rbZGGz|TӧO4n۶mժUYfƾCv;I$^ݍjBaXgjrR41t:aa0 8OOhoo{ bΝ{иcǎ]~ڵkG}jnf~^P}w)))mmmeee<*@h4MMM;y`X0z|W'|>ޞntknnJ@ T*Tk-ŲI\\͛7O} DGfff!!!SLdcPggO?$ xSO=UYYIۏmll4_SSSSSso|򉅅׬Y\]]GzYݻŋgφ..;;oܸqPjhhζ 2C޾}[RM4 +`h4靝|>m#V\i:#Ů>447;;;6}"OOO3aj:"" }h4ZhhhfffZZZDD<[h ܹc ܽcvkjj*))7 ␐H$?ɼwPzewt:]nn^555J0oo899S(D0dkk;a„|++RiEEE``9>FCBB***ܠ@ ]yy^F!>f\ނ 4ѽnnnuuueeeFѮ{48p,d1L77GGGx,!h4F~9H 11ФILWj[Ô)SF>@P]\\f[[[#""5UUU^^^P!dûpkk몪*J|||x<D"q\'''GGGP}}}ff&Bh֬Y bC޽{E g555]]]!sssWWWkkk B[[ۊYfdgg#Onff5ڊxmcc3i$PHbqQQb?46$ֶ8 Úsop9`5ͽ{l=ˆrwWsЃVmoo988y>I$>NqgggrrZB#޽ZQQ}r]]]666T*UՊbsss[$)J'~7 ;;p NhooX,+++d2Baaao7Q>~~[`04FtIIIz<00xf`ڴiaԩS̊+* DjV;CjĽ06~n| j=tԔ6tB@ ̬H&u:hG-,,h4FJ:B:ƍڊaXggH$WRVuuu-//oooOVT*ojjOA oeT*RI\eDx# r)#M" \PfCT{NDDg0 2nl2FE1sr\&T*oܸD...C..G X\z~ x6x2mtFG0%jFXvl#ϧa'◕p{2"J&]lllZZZ@`]Jîm1\Z |1 Dd29;;[Ϡ2L b/cXd2YPaP(S06X 2mڴꎎ\..v͜=f.xs4m_`Y]QF Ӊj*JBK 4 L68e2D"x x?=>'H9P($HUUUQT'j5yb% YT/!닟rÔ7 E7djc0LH3lB{ y\a?2 XNj?򪪪r, Jjjj¿E~9p)n5 *..Ɵ(((PTD[[[GGǦ&BP( g *@?`i4D"z`XYYM8qWsF}#66.]\.7..31͝3g(VE:HŹ:;;ss ɓcVMMMqqYL"111]]]g}pT+& .T*o@$0\zpP&j ?\vḹn|nDwJB$`2r_ʎ]AT 䙳_Q_._>ߟ~.v+cfDHB賷Haeoxm8{Tgx>;f1_yqHaHnXF$}vxvn^1fbʬQE@F\@8Nw?!$;1~JJ0NP|IPed&HOz^auuxd~ !ׯYnjZ}q#AQGEFak7lZdo_-(,`?B'/^?yWutJ^{yu/P(oޅg2>k7l;{V܍N;^9q"B~߅?e3>֭;NΎ؉ojim\z} ¿}wB[o#ExA};{`hyO<9ZZVf8̟͛l?[!ɡZZZO}__DO?'bB[d) z _ykYox~[L&.~e[-,,[lbr 1wúusNpa2KR;?n[;%Ҕwz|QVWHE#Ⳟ^R$zyfw=~raXVvNpP( MHNF;wRgFEV,[$ ̝39pE zm_=#ɳcf̎\z퍷vmužM0l?Gj `07WW|:+ZiS&ߺrNpP g_o~rUYUѪ=݉b/^ui9:çK$$I}C` M!vwr1 ;y81~)jN0xJ3c'lܐPd&O @EOgMM7cݭ\qKԴO.ttw^b/a"zP#ƚA VaXn?p K0naٹy:d„=!^QY9u 1]%'>wv'W} [HLJL5uE%ŝ,E"75XLD:--$P(}?n&V457_?O3X.+ :bc_j ~V~)\'fӢqGǁ> E!6=bϏF䩤[_<խ莞>\eŗ~SӅh_ڶk7146nrH_x?|Fj݆ #}|/%898lٸķ'I'O"f-}j{=oy{5,Eعs(j[:[jjnh)66.]\.7..n̙F9s@0XqqqƖ\B1yd#ƬYfDncbb8΂ Ls9|}CòU^g~ 䂅 dۍ}8jޠX{♛/}jh"z.vc ӧE-70&5x?l=$aaX{ksg{F6}--Ĕ_|!TaE=<.4:B ZZC0[JDZ_/l!ZU]Q*nm.vìS &Fg8u[!@YYYz@FVCtɡ$<#B! Z1ð .|III:NP"##7nOH$((#]п7o4++kΜ9]v*Jx/x0,!!oyW%oY uvvR'N8wM61Grro 9kooeϟ`aT*s–,Yzj& ;a?ceΝ;~z[[ۧ~:,,͍㙙YXX |%uuuw>sLllC&L0\ً6ZH$2L*޻w~8|M^y8ri&(..^ٻw] //fjZTVXXx۷8p_~aٰ @s|7JJJZjΝ;y*u({iwwG}~gg_uܹcjgxxgB//'|ǁvn:8(..޶mdɒW:88@ 9*ɓ׬Ye˖͟?@4=dk{{S]\\,--RiUUDզom!N7~x[[f_+1ðR<==|>*DpB bҤIoFll}xVVVllR

 ;g˒Hދ777j澾\F O;;;Jecc)Sۋ{OH$j:44T&8eeeDNKKST ch[[[r!ի_{5@0kAM<0z^x!//oz ~}r[t˗ucG䏱 |>$aggg-c^'ATaXFFFzzziii?UF;::B!BH(bjh4*2ǰ fL25p8>DGP 4-;;;--p<޵0~xH #x%466wFxxg^b#j U JܹK `̙ H 7o‚6l=QT8hllp8?NOO7LP(z;'',{Drssûh=~H$,2 yU@RTjyyyiicooo^_WWG:1;tM8q=&fgg+ar4xJу!RzF477tiӦuwwgddDDD455 OX[[gffz{{[YY ZZZLP 4‚BTkʪDh=~khh TCH$첳om~]Ҙ@Ο?!:}tLTj>XV~IWWWkkrggg ;ϯDb|SBuGǐJbM"dgg &M233Z)(cf 9*tr{\z<܈|$ZSa UKbPTFc2oIƐg/>h=zfgg>Kz~|>Ν;$ IdbmmАj'Nrwwv]ooo:V}rڄN[o-tGG;wz///b}˭ZGgD6BiE :;; ) L6|qUx 6 .LJJZlYYYY?Ο?xvvv`@@@`aaѣ熋K?SH$RPPPk#IBI&JmC-8::x ~rR)z<!f[ث@(FDDXc333iL /?yOO͛7 _ƻ kh4&t ٴjJWe *B@i[nݺukIIIVVVcc#B. #>6afT1F$pH+F}H݉!KH)aPz`\KE a 0 `$ ~s<>(hŋ;v(--Mǣ u@@LhTq0l:|>DbrF 3Q0-jFC0R5HTtTSQZB^;pÿJbf1K`i%nm)ҨPZ DV j&  6tH$ q6>>>**J(2 ;;3g&&&"Ξ=K"H$Rss3B'HR$i'O)𹽧`vر@f'MW_y G9991)Sdff!@t:<7nD}ǁ"FYXX̘1=2uȑt;;>(IӧO\`+'hg3f%11Q.N6 @2%bx NNN7n\rrrAABhƌįmmmee^OIIA͜9s_K/mٲ%++R oذaǎi>B_m)UUUGE-^~ ,rmfkk/E޽koo~رݻw*gϞ%HKK#9qℕX,H$]]]'OV*ϟ'(g._\ՒH;w^ϣ]zI()JPCCa &,_!DR+===tU1Όf$LJdN6a¦J\FnAb/ܹS\\wѣyyy B'|rbbD"AEFFhA}qϷ Ʒh4Cvo>^1cڵkLud2Yqoooo333eBU"XTڙ,tm˜;vm߆Jڻ?yH2 (;\rr֭۷osd2aGrAAA׮]Ccccccckjj={Vtg"(Jpp0<ʅ n~~~C6Fnbxw}\200P&$o=jt:]ddiUM "3ٙB`T* @01LpXlqB1zO8q ?O|>?000==sT*522ȑ#]]]?+BH*9y˖-G矝z}}}=BW_%r;zh@@@kkX, :qG}d&88ĉQ԰k׮!d{ɒ%?eMMMjjjkk {sν{s< !ӪZEhg[FG`? ~fFGܾCI)fFM?_ʋ6;sm;Cꋓ'9P(<v>g\tI.sܸj:rsss̙3:J?,,,55u7oބ}:{{ϴk3...11ٳF\B?ytZ! mp8 ,3ͅ22vFRs\H҅K\.wM{rBz~٪˗.9#z¿]y/Ft5R}oBe(AӧM|떿O;ADdOM]]MM-a7nkZR eHcQ]nܸcU%`bfL?rĖSbeLbvqHߝ;w7(4~@3А>zkbKN|/*~v${[xsiL;EP5F+6=bϏq}~K;z4bc_ +-+1o/OGiW^ H-&:jۮ`߸!G}A֬b0~" V/[|s1$)$(p;#J:pbxhxGJ2ꙿz=x d(G,!)980A$aXo,7,F" @x #)Ga H  taXL֪T(z]|q{S]{S1B%Pz~arWuuܨ[;D" d99t:C$޺}7&zz9f2_ڼ 3rZs?bDzlfn~ ϭ%V;9$c}ΞSZZOL }ү]7^ysz4Z}3)qftdd2L!2f3z^/aOIY0 #Cbꎗ\u2|"c&ug%!e2E \n^C@R_ By t:ݍ+Jb0pv.~S}.]U+^|eЧ/އL&e|w&| ekk)[;w]1=;Cew+!^])lۺ !ܦ##oUVU9ۿu7o7N3$X굫VIk(S?? D9^hhTzm ӵ 0L %`L|/X:yV?Vqtp{@"==aF۩iQӦ}\Br#3,,۷nUlk+/k4jZM"d 'f^ǟ}J}gŲCD&&D;w3Od~rꛓiYd~zw< L&Kx6_}i4줣 ϭ_~Ms7>U+4(v#ajId@R)dV;q S1LOQ*9ќˎETjz\VnlB&tB ambqeeU= r 0uJ%EE>+;'wsT.|];lw)RRS4<1ّɤmڰ^QP? FOV];=j9oHd6L>4͏2Q$ 0j:!)%$(HT*[wRUj BYR;;9: ôZM$R[wRBRLBB&Oq]Н{!Y,&BZոN09o0Qcz=B򪭭u:|=2d*=F%M_1 ϭ_z@F $ =1ŎJ괺,hTS޹{O.{iar?vhJj!1b0ѠOBam]muu"_3aO{mb tω=/pD#__dRa6Am⊪̬;ӳs0p8{ r}}B:xS𔆙'ejeK*BhjrP3HF! >33d'S()S%%͚|F"#">h]}CwwwTRс?!9sơ#_DL 5=%HQGb2499#C;w';:*AF+ZvʵWՃN9 11"!+ /#LP,4iؠoPz{LH,))7ΞNHVXlaY`^ қ `Gkk5ĨXnذwQUz+KYw( ,_|-93?bUQqkO/:et[w~ڎB6m}GPV^nkcE"ў/¾Çĉ>yRDߚ@Q/0rؽp8$"IH҂@Hk)))i|~d2YKKs޼yvc%aΚ`!A5U16ϧ*|L&#D lvH(TV/D"qm~yƦŴ wot!d4ڀL&{w`FVP$ڵ/w$ H$B][බV@0lѻ 6ɑH$"DB?B<8$Zğ;H$0m>#As3 :\ vuqRX/[/;l:X-lii$ P`0G)ttt̜.ᱱ8uP(QFYYYyxxxyyt 0DR/WpwW#pGHyf @ QԩS{IIѣ]\\tȴFcccnnיL >UVu Ç\.RUUDP]C Pd2+**^|yI ~;;;09eoOS>ɛ`Ο?w߉D-[X @ rʆ ~Ǐϙ3 JKK:tʕI&o~~~jjj`|f͚o-haRlTKs!C89P[[;s̽{~Gu4eʔ .绹~g {{7oĬYpBMMmձ/^HIIy1c$A3Q$)P7RzzkMMMFFƱcǠ$cc?}֭[s̩?rʬe˖peƌk֬Yx/0 CFBI&ݸqCUU4̝;7>>~z7z̿{nڴ 1"~@;;?D"ܹlDQ >^Z"8Rss qƅL8qƍW\W~QgϞSN:i|g`햖 A[[itVj7lPGΝ;n:|%`q =UUU˗/On lٲeÆ Vju@ uZ#5}ŋuuuw͍@ xyyIHwCw(g=ѣZZZO2<'ѣGђ0t@ILd2@l{L++Fϝ;ހW_]pɓ~-3y //?z*BeٳgO?D" b//۷[[[ "GQVW1 BH $:}Hك6X7D}JR|[zq3D---8 ,+66Ν;s1g"/^`0 Ɯ9sB n$ ZjBD"%%%%%%} R[T y敗;VR__ر 9H` Z i\޶;~xCCr+++MMM3fرɉHMMmnn޿c"""pFM8w: 6w>177#O"ĿUUU=ں#,-- |<:: '{7|SRRڊ^܌uaa!SPP󪮮 :::P9ijxGn{{{WWWcǎaW\wˬZ 99M_%\ ̟?_{kߐ}Ư^D")++OUU4\ 9rd.@ ޿OR544Bʯ_>||||nnnTTTTTTVV۷qOٳYYY=B=}422d"<=={ ;$!ľ>v@odd4o<`=?{Nxm\\\O0uu+VDGGsQF͝;8Orr2BS?BH[[޾ٳѣG?777qƁRSS]vstR޽gϞǏd2W\I&m-, eݺu}Lvvv xO>=~?o߾%Λ6mOU.]tÆ >,)))))GI$۷g͚uÇwѣΝsvvqsswƍǏ?s J)d {Q03f̒%KTTT^4>bzwykk-!)<}oٲJ^re{%Fq8I&M>ǏwYBw;x!D {GV@XVoeCh4mpcqu]|YQQQ__?$$f.a2x MkkXS(':tO?h@|6D];555:~ѣG l6v"q2115ko:P433{ 3g쐀J:99/^444i^+ϙ3œ&M2djhh.dGts`0Db-H}ot <ie&(H?AP⋄+o߂@3 eǎK.ݻw]ϟ`aaq/^ܹ7jrȥKjիWk<o޼yj)))  ={{P(trr,B4|;H >.<7jhhx5&  egHԔ9̩%\.ɩPnn jkkmmm{>nVSScggחuA@@@gQ^^~&2rCUUU .8̪Cb00ݠ;$000ϱ0y0rbrr 1c4551 {{{|'%%Iؘffffpd!".D!BmmmLA;;?|>fnfSRRD@ z:uc(uuuϞ=^ϊ?SYYG2H$JHHPPPKPDPSSѹuVuu؞y #<<\B8 j߈HT*-88xuՖ8㥧O4JDF6]YYQWWa۷'NlߏIJJp8=u*0xyy577O21D['EEE),,~{:%$$455M>+0YbP(zh``` D"cvvvx 䥟zzzU"ZZZ!---O1xkCCBzzH$7nF mʒXPPxb1SSSggׯ@xa@ PUU'Et '''ׯ_?T@x<&:v[VP+`!V\yo߾}Pnf+((tXYY]|>͘1c:x<,n:`orx+nnn6m!.ۣyǎsss/eƍvo2B9++b_S֩ҥK'Og uxܜ嶶v8$É ;YjPyO>-))h pI{nݺuG(t6g(drjwy<P|:D饦JS '|'N:zCuBtwwlMO[#G}'X!`S(~u$rʾ\ҾK]J.ER/ٽ{ov၏^ u -,, MMMū544BG0cǎş544qhqEE[\Ν a4ad~r 6:z:%''_x1((h]E%r8u@ I N?{]\\VZ5+((tXL͛.=;88nƨQ ^FR;UUU bll/ _;-[ _+.]hѢD1Z< lmm{:UUU-Zwٲe@a?{@ K,9tІ LLLN:Y訪vA;,n3f̘1c$Tظl "㊓'O^|N 7µk<<<-Z<::iiiuV_ҷN͋/VSSzj\$:TXX8k֬ .HWVt+򀍍4|]Ξ=믿@iӦ?~CSQQɌa *-@|}֭[} V=lϟ={˗?~qF0 &&&M8Ν;`D"ݻw'MD7OСCw޽{?,v?illrޫWV\kG5 l@+-߱cǑ#G׭[wڵ7opܑ6477'%%9sٳg/_NJJjEEQFM>/^(++ i^xqkkk///==A c#***o޼>b!TP,suB:::޷oPd>̼zǏGNUU#i`H  qZ`cc3[nفeH͛7o񊊊 FSS4@133322gP0ĉ'N`2yyyUUUl62RzzzVVVصfH$c 9x<^ddd~~>3666 >jjj&L;G$Fee5k mBիcǎUTT|M~~Mh4 䝃?~ʕ` rǎ򋡡!XT `*ΑTUUeee]reXje˖ ϟ3gV qbZ(MQ=t + h¬D(G]$4rΝG@`$///%%%%%%?ĭYxx )S|p۶my^ d2JW;PhhqUU˝2e HήA[[[***;vrDtu+KKJJ޽{Ӧ`d3l2%%%x(Ìr8wAy5?~|~ ¬Y*** Fjjj_vF544#}H)BHO"00]Z$!"I,3x;^.4}tHc(+++{xxPׯ_a3III::: 8𜡡aNN6eeeFFF`gJ۷p?\36o,B?nmm]b U7Vԗ/qvvf0I4Ui$ِD[o`QƆX͙3D"!Ǝ究v}}=Nonnnii>c _3fLw!W 3EI(W˄ &DEEbH$ ...h?uDw7ao <@ E BN+))4PٙVJ-]!^ rss|P(5BEEe…D"144֭[MMM_[__ڵX2wf舳۷o###|N733RTTTQQi/x\]]322JKK)a}}qAA9x7 F՝Vjgq~uuu4i$.ǏIrpXP"@23$O?)}dVVV[CTTTݻf B"긃!vf2EEEӦMи~qqqw{ѣ322222ttttttTTT+PjjjBD"999͘1CEEE  F:2\,X]]{ ‘#G999!H^|k $%K|||sss+GAV=\8۷oʴd@V$=\QQL A4Я}GcǎUSSC9994664|4O6mڴibaNT*UII O+ LcHL0\EEEggg}}}gA Ν ȜƑr zެC% )򚚚|}}񟮮111)))ѣ{H0(++xG&8CP c4(fEEEEEE#)))cǎYZZ&''{zz¯0$,(((((ěh@IzDErw F" yyy|>lу[Η 0ѱcccccc $Y444d0zzz`L#dnn奮Ķ60 $PT'''@0 Xb#MMMwww$10ÙzPncccbbfǏx_=`K+F$x">>BhjjĒDŋHajEGG3f@ |>{]d0}1Fͥw?ydOOOEEE\𤤤/_FFFN>}<""",, !D"zZL؃5t:=55522/_u޽eb 3gbu"nnn&&&[9::DDDzG  /deeu>D"&O/IHH|˗/3f۷oAtZZZòX!H$Rdd$ϟ5k$!P(LJJJNN/J$?]hll,..ՕKtuu)J B4:::;;^|cXpǹsX `;wO4snHTZZ3l2Y~eBB@ @,[ !}ΝG߿#9;;Atuu;E;V/133|0--`[NSSs d2B!DRPP`bEE~R666xI$zJMMd;G(JNC T@#9sB"h 䗤sN4IBϟ'%%M0A&ZZZ{bA=eʔGKJJZZZJK.555˗]v`B=>|XVJ@ \v-,, sKHH(--k׮~0YcKu^#8$$'sssNNN@*((5jF3557<"C?oo޼144TSS%%>#\^R___\\ҋ촵WZ˺:'jjj BUŅ},,,\\\bbb,,,h4Zhhls!Y,VRRR~~ǔ)S[:j| `Ш{I|||{Ⅶ+zr}˗/]GiP 111mmmxbXYYYXX~:,,,>>[P3|>_ !4{ǏST `gA$UUU?h(wwT{{ϕ}PAEEEDw I&;p)ƍݵQQQ.ikk_tiݺu޼yYBBvݻo&Hnnn!!!o޼1cLP(K. >F@[$C,X?x 99yܹWHBaLL H7o^@)hkk/M=\.fw y>^---?~]C]O/lhhKzzz=zUTTz8Nddd||}b<<<Dׯ_kii?.ҧ'HW^]zHFssYL!88XCCK{vvvhh #M|o߾ӧڵrHLmmmiii!!!߻w={vf_ijj:qĩSu9993o߿ˋ{ټyƏرf!"lٲ丸~d]\\ovqq),, x XXL]~zRAA|$Iy \vX؋KAaaayyxq @zjFF i#H صkǯY&&&`%%%;;;;;իW]p_O>|r0T ڹs'H<~'|BR&C]]]]])S|EEE:u˗;a„ }+}^˗//++wRVV GH$ mPAAFD")g<"H ҿKR;M--]l900h-[2-- ҥXڱc|+Vddd|s}~/oaɘ1c^{7N8޽{ +++9rG(ʖ-[LLL:ʠ ???+++i˵^iiieeeC?`X****Eqqq$NKYׅfxn޼9{ :O??Xvr.]zܹ;w;v 122rƌ>>>;h4YWW)^)޽{7gϞ u` x?㯾kHI@@; 0{ tvvkTk ֬YcjjڗW:" h:WWתW^b,kܸqӦM={6B0Д-Zh…}XGL4ҥK}?}Iw\x<u4 Ǐu8:믿S5w+ 233Bqlllƌ3+ٳ{׶h 0ٳG[[?6u͍@ xyy @^K.ݻwmz1Z?ٹsÇ.\8<߃? <()):t̙3H0q…osK`8!PhhOdd$B(((G'F Px%2++ |D$00̌B‚@ ,Z Wٳ***SN}4t钅J70[rDΝsrrRRRRVVvuuӾ#YGGǟ~ !$p6m߻;l e+goذE~߾}Ϟ=i/Z'@F<򪯯_`ADDɼyFE7N bPKzmtxS8ett\nttʕ+?KrrƍE"Nj9s&d2]\\ϟ6o޼t; vڵaÆ7778??˗/#d{TEUUF@ܿ? H$pm߾}֭iii:::8ٗ_~pD|@ݶmۅ L&Jw)gΜ޵N***P wH$B!!!" S<<}xN#sss<D&tScgg׎;|+t\^Ћ/LLLƌcoofB퐘'+ҥK6...@ʵijj$@фA];,B+W$d2yժU!@,l/?uwJ.[ѷo;\z5DRVVh%33flnn9///dz7ʯ_>||||nnnTTTTTTVV۷qOٳYYY=B=}422d"<==z5x`A^nP(㏩T뛛q(kvtXwGEъ{d K/.]糝O}ll!>lEŗS(! S3 B TWW5jp6Xivhii XxX#GS۷o?sL\\ˋH$ @7v(/sAG:wBzzz"ZHMMurr>^joo^XX,D&L@ D"cp---RakhY,Vaa ijj) pމOPP?;\\\8X1)= |ѝHFllիW/Ffx<^wuJJJRUUՅ 5(R!,,,55((((p6Xiv"---ǍgffF"^z8SrrrccYd2B{qt̙3cbb\\\ZZZ eR@%%%777##b͛x<Ν;̙sUܱHmN>}iݻwٓ&M{PTTp8n~wW癢89k -Leغuk``MMMB!sN}YGGǚzgg .8q_%ҥK7lؠSRRPSS#u֐|駟FGG>|XrǏ[[[8q:zQhh(vG`lvyyyII O]zD"}~~~FFF\.r .\駟***{n[syŁDbwa]xIkk+F ~ cɞ?+ܠssm۶}]v_K.=yd'6ɓ}Keff @/Ϸ| v7޽{FFF_~d2L&~dyyy|>ʕ~~~"]}zʔ)ޒS䀀"OOυ oo޼?}MJJJfgg߻w ,^W^jnnOt]|o/utΝccI&u^Z)JKK={`0-[&+9 ;X SUUuܹ'OdeeuDbC  ׯ߿_(޽{TTT骪ZZZ^^^_|񅏏N$$$? Þհ?\$}'#A OݗVKX,֑#G drQQQ`` >&:n:wwɓ'{01:PH$+v7>>>""bd2ŋXP___..C; ِGmܸ_ u@n^re۶m;vprrڼyѣG >^m455D"a+L!_ֆ?= B066ӧ3f̐U@/vq!77SN:rL0!::o߶JLL4޽{PG\A&7nܘ~3ft% MMMGjjjvG {:pKy;s۷:{y7((ʕ+x4p8JJJdegOm0̿1ď?xҥ?5hhѢϗH$BoyX){#nJOɖafy;\(I$@K,sww?ai! %!!A x{{Ǘ-L, ,+ HO> kG ]:[[[!eyf0Qhkk0QUUmhhD=ʷAUU﹓d)'|LPɓLҥ|]\\p  @d@^^A?VVV52444)1惒nMMLÀ*MMM Sh41"hbb"/SYY)}---Rzܒ2w ^,}y;4EEE\v asL!_%%%/J:ӔH ޝEu?waa}WPbhiZ5Iڬ,511mLŘ͘XԴ1V4.}w;: 000q3?6gzΝ; "KPV5<<Ud&M∈ЗЇGEDD@ z\ndd䍯}鵵}ٳuuuIIIv6l?C{㧣}֛/_enj7njjjffڻB骫G˩٩V !V588׷aHDSjKJJ!&I(/! >ǩS<==CCCq_ett{ff&Not***p8 $&&Wf8:>}zܹh_lqE뮻Fk]"(111+++))i8mmm|rllę((([ڌFcuuu]]]LL̨$H;kj FN ҢE>쳖R9{BDJqqqÜl6奤D"e;;;{{{f͚ޮVd2zNsBbbb._l4%\hQA`ҢݪT.{=bo{SpwǏ:t-8&HmΫVZbEMM͔)S.:  :ܹSTޤ~&GyDс===oҵKHbŊ/b׮]s`miiٿGG?Aa3fP쯟`_[^@l6;H`ݺuoO>IRooo/\]]#""Z[[h%++q@?+1}xJՊb@0D 7L⿗_~9..n8h_oc˖-1NlGZ[[nka'J`3|믿T*]fkllūV?_zyf577ߤU$H0 X]}ُ?zwrz{{z:d}>xr@n>o6%TccckEKJeNNNLL0x7|?8~yɐXl\.7߼׭[wfeee8f\^{5 =r5k֜8q"'''''d2ժM&@ >}.g$H0l}%|G}tѢEt؜!+WWW1 r%CCCJeEEEPP\."h4wwwBH%,,qKٹ~6%A9]wݕ;wv֝`!:,g N?/z[N(.^orJSSSgg'!D*KE=#AIw5Wz衳gϮ\… }RL뛗88 &//r D"Qz:"J/=}z jZh4ڵ +On3cƌ+V>|]Ktjnnnmm5uuu ?:Zj͚5+WDS 66666z$H0 !d۶m%%%-:xJUYYP(R)=QHLLμ}: ]1tIQQ@ מ7O>{쨼5 :Ryٳg?;w|}}@<蔛lٲ c36'Xf:x욇GRR111׬ٳg>}~e',ArӦM90!ߏ ȹ^fw߽bŊ2ɀzzz~8z8ٳgggg[,~>BL0W\Yb}kc{r7o?cbb~~8-- .PUUU{ݾ}{OO/vZtX?33s֭o׮]r@`X~]v޽;11رcC\GJ@0, .ڳgG}4{lww3gFDDxyyM¡Xmooɩ/r*0 6<[ly֯_q֦V/\v޽b 4% A}gժUV!fm~<.n~̟ΆJKeF0B* ȽG^|O*(,tFqJL>o;GvOC}"=ۧ jȏn|\,!C.2c9z#"<==?߱}W FfX&H}执~v£'NTTTN zQɴcO2Ms<ԓb²잯>t::;ccc^|3{Yi+uw?p߄~1$(苿рzzz9{jk[ !yǡ!ч|cvttj_xvK٧2{gc !6l o  A|֊%w߿>߽xJ$wn/M?y]_<%`ԽW^ZO}\T*ZV`[zEݩծ]:iZˋ0Z, gY6j\:#$o?y凣~ɒ v{Og;;;w{g+g-KIiiQq !C.O5k7{z2:k0 ۀzzz`ggGU_筸x9] Ddo~my{+fL>Ī|uq$x.vf|Ͻ V%pʔ~̜Occcv|'R7MO߱v>pBIހ }tl?7)t@ `@x `]\t  A@ $$HH  A@ $$HH  A@ $$HH  AlIIIbT *77Oa~~~EE* x{3g6448>|8>>g90;SO%KQ9Hƫ+Wmذ^b2֭[L:y7|M{|P__~zTJ w>s -z-T af3!l6oܸQR9^p$HҥK-ZsBzzzx 6T* o1[l!lݺ`0ڵ i{[[[O:n췁eY4~iBӧ.\j@4EEE=SH$mlqf Bٿ?* i&>_l˲Hooo4-[ A ]rɓJR͛X@$H㒷wkkkBBq1MAᇻw.)) feeֶEGGZgquuű  &N'J'/`6x≿Ɏ= Ytҿw}>zy$ M4F'ܳg /~zwwwBH{{{qqqCC!/::z̙3g|饗6o޼z3gرC(P:  wEEEG`Yv߾}|IffjOr̙z˗o޼yѢE˗/p0 !tLCPL=}'Ϟ=Q^^r>>B kj u:ݫaÆ9sTVVs=f8Kkoo_lYYYYFFK/? Gt>oB@I}}<~/h4~'+W0/-))ٱcGDDΝ;m6-|Ynfկ~6j4f,˾{8&g{WK!t A`0ї/_>x޽{GUVuvv_~T+**V^699ӄO?ݻsrrwYYY{JO?_|#`BzW!III=PKK B$:y7/]2}=?' WWM6Ν;wܹs!d#[L/~QYY`BJLL0̆ 6l0YVuɒ%$Iff&!|z0.\hnn;qD||<H_vرqFd7$H ūtXoE"H$D.s8buu}VZuܹ>Ylŋhq'==}ͨa~O>7x^x 8%K޽_>~ڵ;wD$pV=>y衇jC=3̜9̙3;FFF?~|޽ǎJt_x\.!`bXbKKKM&:&A,/~e˖Oڰa]-˗SSSSVBVkppoUUUKK 0 "ҧe^%˵ZmII MHBaJJ !`0$''šW7nsѓJE%Bg̘AK***BBB NV0'NJ\$lcEAAAOOÉ Nrn۶ɓsΝء4Hƽp\wuuuI$ah6RRRfgggoooSSӬYjuBBBVk2RRRSRRd2 r =!\|h4K^rrr]]DR8p;2 Cgާ!RtF!2a "zq?VlWo3oP(r>tBqf=bYe쬬ύJ%^0\.$xzzvvvBb:Bo5559^^p8cvD3gNeeZ #0m4릺zΜ9[AݒVtϟ/((X,N 0.c^=Ri{{...hb wƱ^>5""UBC@\f}4`ؾ}O|pV`Tn'j:pi}z_xiii!ѻ 6-88X.?a:H$ST*/\`X"##'Rj-K#kÆ 6mZ`Abb={゙ko߾?O6m:;;KJJ\.q|F9[&g+l6ŋŎ8q;QCǀ̈́@a.]:ѣwmhh(((Xxioo> իלWTUU* ٣"G{8Ͷlٲfgg\|Y7mڴoֱ;8jG9[ c5AmmZ^p;vlݮwu`QS؍cIIINJwp#O^TTm6>裢iӦ榦ݻw;c2 "J333_Zvڵk\DQTaaaسg:: L2СC7o~Wms?w[nmkk۸qK/0 t t A\ƍ{_3<B_aTYYY\\uoܸ:B$ YwyJG}u3gΜ:uRfΜ9wn m pkqܹsΝ;U Dv0 0 g0LFF$Y^xat  Au;) U*O>M/i_Bo0L`` kҥ ЮvSO,?yڴib%99/}hsnٲeʔ)"h֬Y999#G}aJeX蔯 0RT;l߾=44u5kX,OiBΝ;]\\\\\f͚u>  ÓO>www#*!Ȍਞ1n׮]}бeO{=Bjk\z5c Ͳt,h{QiwvXL6mw=c @ceDe;jB^{5eя b%~~~^x~Bp8*{OOώ\_tb{̾".+Ji_: /@H$qqqR?Oaf޼y'V>(^TrDB[RR25?VUU'??… D46GD N=hI$>B_pdCǖ!>Cn$%%%%%׌-c=@MM͑#G=zͲQ0NMDVND"X,nnn22/9sF%K,Y7K!s=Vl6/^466qBa}}=˲ϟ7Fs!y,fgg)ϝ;x2D7nH?mii)))h4e樮UeZ_cن:wiXziӐ M$csTOԘlxҥK,߿-׌<֭fl 2EEExseHBN9uTNNNWWO?pN:u)zq̙>|>}J(!p8<oժU+EVV}cƤЋ#gy}WTBhIssŋm6!瞣khk6֯_Oڵ֪`^TTD}\˽ދ2{TOԘllL777-Ì<Ï-7Ϥ0ҥK~juffffffaa!=? 8@~ӧOkZBȜ9s|u^>$П>L&o<;LRSSӒGyqvz8P@s9)S8DaV@ BD%='jLp1`: c 3 twwoڴ￯Zv-!ܹsӌ ò,HO>gΜ#G_\:ٱcKf̘AKfZKz.dߘBK䫯.\.w͚5{?׬[c۶mb9z{{ok{zz˱ڏ?NKh @zgg|=i_c5# MM{zz[=n RUU!$22g?ҥK/~ 3;eYz1)ޑ @:u*h4#lFC !shܹ_|&''ux ->>},DIHHXlYBBǻۆSo/^<{l:g&9'jLpa| ,ݻ>|e,A3HxipwwX=s̏?P(V^'_YO9 !^^^۶m۷oOLLlmmh4ӧO϶l8MRRg}Ʋ,KMM=r?m-x}kzwvڕjjBHKKCs\9![nfΜYVVvV{]w=٘?JgΜQ(* \Q=QcF{|OLJcПWz Emm Z[[[=nfҥ~p!^/H=ji ?Fjj Ν{ZG}3WWW۟+[NѣAAAζa>(7 b8ZZpqǎ[`Aww]w5y` YgggBDB_W2 !/΄nmsr H&u8q"##cYSO=Ө[bq*O&&&w}wE:Isr H&ܚ@sXg1 3^_kł, $H#A_g8 `lb9RLrz:c[k]qqqrZV"jkk Q(:BIrTՄ[UU0LBBH$")jEEEaDPh6O8!J !t "|jq/d2 Ι F %33s޼y7Ѭ $#rp+ BT*f9///!!!%%%--M$655ғ%"(%%%55URUUUEdT1118s)L=Xy<.FB_0e4<==Ѭi$|||lO teʆ>kQ*,0r{zzҷ/ Ο?_PPñZ׵/,655:gU3 Ѐ`|ŨvTĨ& { RRڪj !%++q@m4̽`\};iii{>6-88X.?a:̔H$Sj6<<<;;;KJJ\.IHH/b uF $G2,888//O" ?@U1*<<.ŋ111MÏQ6ҥK"hԩhPpҥKСCz^"=ztNW\)//OMM@C¨h4UUUt('QTTdZZܹsSL?Xx^p9`b(esss[[[;`nWW׻k(8~'<<\ן?>!!`yxx8a=n999 "22r90ӧO?w\ff3QQf9;;c̙x?,8=b̴iBCCsssA̬VkiiiVVVPPPRRp59>?k,wwgֲ,`:::~'z}@ Q 1N(LZ,թjeUTVVVXXXUUT*Ѹ@wwZnjjR* uHn ___BQQQQRRVe2X,_F VdZN2 aZ}eX̃@EdTPxHnnx v`8f3(ryhh߄@,'&&644TTTClt=HP(Ñ1%m6[wwwOObq|8px<+}i#H""""""f^7 & O b AgRy06JKKјi0|wwwJ`zzzQ &ra"""P0|:Ào0:l6[YYM0: _[[[gg'˲jH`,[^^ `YH"⚚. Aqh4BT*Uee^G5zBryQQ WRR"|}} !^^^C3W\+&&5H`j 111 677r`jᄆd2b 8VZZT*%W\A`z{{kjj_i2Q?p`oQӦM?l]LL j e2cP(LKK[ c@ ?AdGCt@ $$HH  A@ `TPbtzl6, c绺JR a2Z-˲@aLRj ZGRr(W\ r$HN-''fq8xF@ P*J2:::11  TWWGGG7lgԩ.\ B Ap  3|>?!!ͭh4FDDN bӧOEm D999 GvJsuuuwwG t^^^aaa 8sÇϝ;wKYTT@pk7EGG*tvv655*.v7ZH$iX%0 M^fͺ Hj5:| AkFϘ1s̙NRY]]m4e2YllL&TWWvww3 #HLHihh!,\P(jX<|Bŋ^Akkkkjj !R444TT:noeeeOO… ^G;w!Ou-W\\楛񊋋YUTt6BHFFFEEE]]P(\`ͣjuYY[pQmkk+++tV绹{xxB***z{{f3˕d RPPPSS㸢Rp .NKKf XvFRSj4/]nfL6Z:::d2pl&t:PZm~~~II !nPFc`0,a8??_պdK.;n@gggaafx5 gT$l6FC3mRQQQMMlxj>%]h4ВFBJ0;2͗.]joowqqE&)J>~ENGhlmm744B|}}{`50WWWTjp;H7Q{{=Eq äD3gΘLJU]]MIJJ"\x2$$D(J$vgX4T*`"DEEM:WWWWRRo:m4???boooBO0K-Ng4m6nRooo]]!DT&'',{N:T*h4>>>ZVB힞J>}+!bBH\\P(4fjffflFT*ɤRNkhht4lE˲C joo7  D"B;7:Bh.Ve;;;JMt:b hooǓ4)))(KWJqqqС+)bh2F^MgU0Jr(5Mkk`k["D'Nu^^^lmmUq^G```aaassb\\\H# ;7B*  `L&2Z tf|:^^^]]]̈́W$U*X,vz X{dzwa4XUbPWWG qWΞ=Ck4.))MeY//gX W\\lZi4kf>>[L#((b0 C> jZ,pjVWWͅ"""ryOOmkDŽ׷h42 3t4k΍)bA `\.̙3=ǝ2e  nnn>~8}B@IRVk6 0&H...UUUUUUt]]]r|`0\z՞ /b+jkk=j$xyJVрF'$ 0mmmsd2y{{:`4 ! b7߆;#FQ\ $k2߿bcc%}oLfj:}pg@ J111nnn]]]"HT^3Y捉ajБ|??ZCjf BooHM>]VǺ"""i.X...===\э A4\QQQ^jPtv*>pX??>nl#,{9:9H$-"A6m`:huof]@0֢"LZ-mI{544477Nޏtǻ#$H$" EHHNVmjj}n̻H&Ar|֬Y}=`.Կt A}N8 $$HH  A{Njmm;ag޼pܹu6*3*h4={~(,, PhhD"ɓ#3l89T&&-IJ*kjjbEbcc pBxQI;AòͻG!pTBeOOZ vرz^P(Babb\.':u*::ZPWWW[,>׿>`(,,h4|>? 44f;v,00իfY,'&& BM*((' <{=>V]7'77WI$oo.6k{{;!&::nۈ2Q7luC4M6I2\ +cmѼ>--m11.T*NBWZ[[[SS3{!ܦ&SSSj }q Af̘rϝ;_^^^XX8{ld:rΜ9"h4%|\._``p@ 2e -55斗8P(hˬYD"Q[[ۥKd2q s ׮Coz Wbx޼y,fggEDDִ4.[RR?cƌg˳ܘ˗/+ . /̀˧:k֬ӧO755I${^smܿ8YՃnߦC0iٳkƜ/qh4;vh4\s3FYuss `_!pS G,2 }2 cٴZj }⮮(.+HBBBq\BRjBJ%!^^^^^^ݭh0 8gtwfGz=66SNmiisR2>]]ۘpaRi@@pwlVBc=`6*uy۶fZWW0Lnn tYYY}&Fc`0y---%gggx޲=BL&ST>,QtР߸=.!!! ±;؄!b A8,KiiiAAAZZZd_:5 ץ7777--^|~vn4O>0ăm?~|G,s8oaL˲2>^66m8\6}߬m n`عs J~xmщ뮹sy睎{yy}/Z&lܸ|߾}AAA[lYd m+VL6mÆ MO?P(׿Ο?_'f;MX|̙3*fǰ?x<{lq 3``fǧ!,,|tC1m$HLww7 r|>0KDGG ʐ:ߢF aήVLFH$IGG;qn{zz>dz%\./(({UUU:nIIz 1nnnbvʔ)fN,Yu:]jjpooVLB]]}FmL9r뿖/_^SS3o޼ׇj4cǎZ ǹFcUUÇ9{ٲeo&!ŋrjVVV !/++{}h !՟| 9tvv_tȑ#nRR͛,XIY,{1`̔dW^df~fp\Oqq`P*C ÉiCoHj-**G*Y,>%'''</00pGZPPV333BfRRRqqɓ'VL&;O2`_}v饥OX,bxʔ)^t`0xxx$$$ >xۘ:@gnO~"^Wm׻k֬9z,Xe6is r<(vVL&J2??Q i4Z>UUUuuu6lj[AAA{{{#p>}+y_;Xp;Fvn=zƜf@9tf!?> OȡCߍĴ!wC`1K.CzDr磦h;L8u9vXbbɓ'|ys'NdddKx?|m۶ p9mr_{wUuٷ,dd5{&$ƅTDM>@yKk߶"R-Ui]Ab feAB =IfW4ː`H<ȓܹ9ss9ee۶mkii׿tYZ>yҥKBᜇB?~<--78+VjP3s0̰$p\K,]?}իWmvvdgg qk6[ZZZZZBaTT0X,;w\~}BBœTd21 #jqqq֭{n+.o:<̀Γ'O*TPP/B,Y"H\ !(nB~;3Z(Yuuu㷤Qdɒ}q8zIg߾}Q.]}CCCBŋRxjz+f]]]-[vq!Ło''' @_/j}|@ HNN~뭷lNj?0EQ&޲k.o^WW7 撒*OOe˖iNOO )((}}}'e˖;ӏ bNw;drrrg?;w2 ֭U*++}Qj4O>rJz̒Jj*o].Bā_GJKKKJJ:}wN|ɭ[9sF*Ezg['|Ψ=Jo׿ERRRo Cb22,333::fU1󳳳 ! BB>O?oՄ//H:52ͧOvqqS:A;gggt:ݡCe2?V]IIIQQ?O===jNT%널>/ѣGy'݉TPPP]]=<vr:wZn`X6l VD:vX{{Ç !QQQiiiԦ&:9IBZC@ (//?p@iiicccQQQQQQ]] |}焐;ѣ*9N0: _Mv ۊbKwl<6mX,˖-{衇x<͛=@F_M$5MjWp;CgG ,X, "** 76@ãߎńVVرc b۶mӧO{.Y`X}D̖ojժUV]xq-SB]ss3=^N~zbO>DVBbcc㥗^ڰaCBB;qXp!]l?`۶md9tb1͇Vd>ㄐ?ϭl6{ƍGt# s=HOBdzzz"""L'{wBBBee-b233Gg/$ MeB+W,))KJJR---3RA>P(!nnn[l`Fg[}a뱱m۶k=Å SSS'1"00p֭O-KGG!g=#wÞc~ ! +k׮ZǏJ=;cSBcccշo߾yfDP(nfz.))Vb}7b8$$>J)knnnJJJSO)kށܗ_~j$ׯ_OMO jժU~pF# 7&V{ĉ1ݰ4M~~%KD"5P^^ފ+jP(D޽{|I__߶6ۘYVO]p~`iեyڵ^n;wPacRP۫Rԥr>:ΎlF62Jt:plvQQ`HIIf @ z]vuGEE~@?/pUV U###cFB&X1zZ=z ͶMNw B|uwwl^xVZh]&UWWGGG{xxL.S$r Rll x≔)>;ꡡ!gggFPH&DM1L d---<jbBApuu%bK,X`Jb&it4twwo۶ǝ  fƾ}222'Npl6{P///\9+==}J.B,KPPX,,--( B'KζWd2˗;a;ddF+^}UH`899}駩ׯ5Ay{{KRggg:b?Woqsssss}KQTbb3s8ZvÆ eeew ̌Яjՙ}t:AO}EwygWWW_}5& i&I\?]jjjYYjMHHػw`@[\o Þ={LfYYf}[ҷ( A 9O;vDEEYR>~*Ǻy.88888//(R__p2e0/^, x)))%%% .zN]onZd2bn07,qvv^h***R('+F,KkkkQQ^h*Ѓ0{\nzzzsssccB wp-L˗/777 ] L`?N,bPp08~ l04RT* ח@pr7tSDDDOOO___oo F#"?2 )7$by{{{{{۶L&ՊU( k Ao)00ff EQ\;UUUՈ A@Պ^J@~xp*((E_\o-; OA:y|*氱Ey`22 f jX Zh럏 `7E1L\ &I(ھ5ս N+,,LJJrwwX,EEE~~~Fќ9s`Mx,!$//߿`0,Z߿h4x.Kinnx`r ,S ۛJs .,^~ƔvLF_`0={l6;;;2J~رoɉ~ҥtmmm&fGDDLV{.̘2 Orqbة **J*NF#ˇD"G?}~眬aLv a2  \i:Q|>ҥV|>?&&:++BRczzzmKKKc2gΜinn& W^^B?yOhk;wNӏ󱝂/ILL̘z.bJVɇZ[[333y<^7p=ɪyuqVF@𖨨djL 9j9'+S;O-`vh5jժV)zGt:Ō\ &/KENE!AMY,$H0 F[L&!dr~=}`;BGan2LP/&{Z\.W"tttt+l|I&V麸M,Jb\.NV{?-yqnF7V (ϯ.=YM0;Vk_Ozh7ՍucfI56Ӹ{x+$z=áj'O>=-00($$d§Cx1[wUQe0\]]'+kwttHR.;44d`d2:=M/J"DEEt K8~S;YL.^XSSCStu!FFF\-1д.=YM0;Cxj0sQ)<:^ L jqL&Q3e˖oXr߅ |}}w9v*FFFΜ9N?VTTε<==kkk;::,X 6z~KvJbl`m1LΝc3g*1Rzܦ"VpZMi2bs&li)eOdj5Y,EyvuboIbx*LW?tvvDb~tIϞ=fcccªb+;F(:Uk1LOOφN'ɮ`5nnnFj X,;%wqqkw%[Bd2l6}%6v,rrrMMMVUV_& 7Yy&yZmȈ/ ;p,: z`&yyy566vww.3s\gΝ+,,4L|>? @*vttdffRpM7666GFFNxԟ\P(v[ZZGikGIII 'O4...)))vJy̙.188H1`8;;LV \Eܦ"V΁v;d\_D"JuƚNy<ݶkbPiސX`B BgDz(2[,ԪU&ȑ#F$}˗/G`jjjSRR\\\ 쨡ŋ-{9بaT0_XBV œ "b+Gh>jF\g?CB&/&=\)q'իW |=$azS&9;;|6ԙfH,t%[Jx}{r˘ė)'8wm۰x⧟~ȑ#7l<#apf[0!l# l|˗p[j*+.TFV{l㹹#BHXP0TrY躍yS> O׭]Ο kL 'UUdzG*~;00ЬSGh?X|y3HUWG6Bzm[ pEgw77T"i/t˛ }"BZfq\Xb'nr?_>|wI&"3z.uUϺ?n_77DH}VO?v+\xJ,"n""l]G?8j?v3gh4 'AG7~ ,[~WNZ tZz#wfztc{^h02 yT+Ÿ}Ge˗v 8: ?7 ?]JwBiPy]A֋RSrʕ+W{wC HG>>>V |y ۭb%p#G#imhϰX߿q'8 G;vaaa !bDR~~~)))+WD  <+ƞ8*RCٳgӦMaaaoP(-{{{ryiiŋ/_yJR,N@0K=O?Mh4}ݩS***~ﻹI$77-[/577;v@ (6pX?HPlٲe˖M?{0 eH㐳4YF$%''{_|EOOnnn~5kNp;=H$=oÇ8p`... ,bl6+JR900PSS#ӟ{3gNp\H~tĉn멧zꩧ!MMM̓?`X!!!b8&&vl|||AA : պm6'''BHXXXXX.\{-[N@Ȑ 7776}/tdcXkkkO:URRRTTfq'84LpM#q)ٹsۍF#rss u6h4R)Ho]\\p'8 \ OllLEErvOJJ:rl(͖d ,H$#VwްŋvmƊx|8䤤?t''?7͆ '[.666fee})))sw߽A7{{k{?kB({JUVVv'N6ƍ8>|g9[$H@yhz+7'gz~ӦM...+W\rN_/>; p##?$777+++))I$M yHl*.*:{OO \.7&&fٷd#Ȏ 80٬7kWX~kv6$ fl24&$0cGa4Ā8܈[ GCp0#Z-/@0\n}peM `"*F\fJ9P#prD0 ]as/_jk1[#\ 7 E`0n^ endstream endobj 591 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///3_main_window_sketch_1.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 600 0 R /BBox [0 0 115.199997 115.199997] /Group 599 0 R /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 493 /Filter /FlateDecode >> stream x}S=1 +0v^DqP( BAljU-0v x~ab4Yw HX q kR_3J\idBFsi@.}ݽ0/چ>cXi&5z7<&%1B_V,/|ڑ/\eJ5* $8cNI8r &*D2K-r~FXObɿ-ɺǒ58YFff:IDkR|{{.L5Y!E%ZA]Ycx?/ni!׻M%qQ^JQF؇k釨.dqG鑩Mӕ[L 5)ե|E .#.ʦz[aq2xKPż9vƓP0O΀QR>YsYsߌw endstream endobj 592 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/file_use_db.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 601 0 R /BBox [0 0 24 24] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 436 /Filter /FlateDecode >> stream xSN1 LwZ$$E(H t;ݣ> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 314 /Filter /FlateDecode >> stream xmN1 E|c夥ABX(]by vQ43q( ֍#-GwrJm}Mh夗<ݓ%?p/""=҉;tZI[#KHV1W hH '87pcx5i0a>qmѻa2`Z,GuR%FfG-thv+1hl#hmӼq-’zE~jXjBJ>T 5H[@,p(åsN d1Ԧ&6)Zg=ֳՍ߇!&^4<;An endstream endobj 594 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/file_new_window.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 603 0 R /BBox [0 0 24 24] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 298 /Filter /FlateDecode >> stream xmNA E @[$$@(  ϝYDF;c%(6+rX̣z}.YEJx>'z] ёtXw K*dVdh(uo+a( 8+A|[afI+{M@,UӞԹv"~T;97ݓwe\GVf丝`GV|Q MxӁhܣuLG艙w9*@@@DC V{Ց?OC`|> stream xMs0 >kۤδ6%9( ǚ ܌}#l@h\v_iEDG»#eBX"PrIF-Rt'v[*/g*|g9OdV)sGP z!o0NE{.O Ap%wsGP >#e%{ąEˠ]-cb !.6JUJi9cj!,Ar7JUUqKy+ ݓ;WY:mqΡR̨lۉիvoڬ3}NKP :-" Y\'+} 9'@;?z{=F)$8wTM|ǿYnzEc?h+a Q ',z,8 ٟ¿gE> >>>> /Length 295 /Filter /FlateDecode >> stream xmPN1 ɦAB8( !:qEXx/*=C;G~!8~On0[65ޝٻAN)a)DkWpDNÂ2)Y,7PC> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 392 /Filter /FlateDecode >> stream xen0 w=_ )Qk:$pC^?D dZ %ޟ@s@Xs͒C~,cos)aD2U1&l#r llX#n=W[C6 Ș:ՍwN/"L%mw dU\x}wN>兺% +gFJ J37IFuS51;93rm,SEa  f?3QmLW{T:q/v#-]=1*9! ۣ,~. EБ429;j~xɦſ6>LyM/W=[ľ%nF9GvY3+;v.̏nNfg+O>|* endstream endobj 608 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/tool_edit.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 622 0 R /BBox [0 0 24 24] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 438 /Filter /FlateDecode >> stream xe1n1 E{MJDnHA Cpa)fJUky+JóG+ nN / .Ft )b{ 8I+kW:1?o37k'-rv[tܭ[o rQԥE~kjySSttb9ӃC *d''KmuiuL@s@8Z27,sF¢c;DBLǻzX{4 B:XGEEJ͕{7d,݀+XUhJM,3Zi ,ϣGҧ416n/_i]$BN- v@5<$ pknfxgw@  i.9%#zR90GnrTߺe endstream endobj 485 0 obj << /Type /ObjStm /N 100 /First 915 /Length 2721 /Filter /FlateDecode >> stream x[ioH_6dG;c;&cڑDD~_E:س$}UWuzݔqbZh\5- i3!<gBA1aX!#K DŽ" %@@}  HpT A3i ɠ,ǔR^DFH R VZwjM U,B]S'RBGF p'I@FKwq A35jìhP;(Q)HPP1j(,RaN;讳g5;bI4TqP3T "eAp%ԅX!P  JR hPb Ւc.!Q=|Xxర(+<@g*_ AOw! 4Ȝ9TiGwF[sJ^HE 2$tqQFHwx (&hvH fa&!F$p !hSq(IYru(9ˋۋn?Q_%Ώ_r}lmhQrZ)%oj!MTTzMuYԳFsŒ^&DHh=Iyci;i&po Ϯժڥ)# Ԥ>/V =n\B1WR& b~m=|x{rlhXbQa5[r+~NŚA(;=R虼ˑN:3FUW^ޅ{[ uiٞSk77MzpJG 'WDнJHiu:c8/i'T}7VZwS릝-zrhO4OY_OYfLƜ:oz&I|խ\78^crMky3=;]Bp˛pΟo_~qU n;rcPHQkY}?ڈJ4WFxNd%SXil:w*Qh7ۊxsw)1n__쟯_*q_YYX[ 2QEeD㉙`ۂ𰎊>4ᛨ@3]$`Pr eU!],lG k98Ej]f6 Ic#M-.ď S P+|z_i,sOJqvzT?Os frzxNkWmEJn~"RF6 QnF_|~rcM)=A/+(Ec V"d(m5踡mM=8 Vń8$Fn@/q1;W3;KǍZ/XK6xTxx6ծ`\ngr@ȍW+٧w~D܄Igx4_>lN:[ %*,bu=Ϙ Oݒ0ٝ1S'Йh`N+VAN1u^oƘ?}q@?cy6dy: (N5W Lb Zz${ԕ^D1،9@2 $sG?ɩm0N\ذrczy`PlSnl7znl`@Ԕ=e|Vj"+6O?ghz3zr>pC/܎Cَ&`+O .>Ŋ+,H6ix%7Т[3_0csE9:г`?mtkJxٛHͽ?pORZ6+rq\-"4#1L7Ud?DB_,wLhzEQ6MW[4) HΓg' N1B￵n4nI viov_ݬ٘yjl**RXcE~ Un7Wdh.cG/%Ribk̓K[߿ֺf.|Z@>TKj士uR^^+'0T>Vvx*ReIS5(Sh7Hb~~u[\ITBImM6+R*BN*IT(> QqkV?ޞ<8.z2؉ZE޵!9gզ,wFnn!mRIZ!/ԔGoa m6˗7W.<*VbJX)R^\lyW+4O; 3ĪVAC/rt91/ &ڊYm6mL\Z-_^zͿrLzi|B:'A endstream endobj 610 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/tool_create.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 623 0 R /BBox [0 0 24 24] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> /a1 << /CA 0.02 /ca 0.02 >> >>/XObject << /x6 624 0 R >>>> /Length 429 /Filter /FlateDecode >> stream xeRA1 @4m5&א˲!y~Jv7dfi%˥RJ+HIVɗ$ܭ[5'?o }O>+*v#ͬ鄃[x$zH-'dl07=7`ڎM¥pytK>]7*'򠰄.}xIWxInO%z>*Ճ GH]k,HV6^vڸ*ϔG>butvbiU<,]ԸD:G5ɹ%P| k`7%1SK A16N,vK-Q RT疣|aXvͷyxgzLI5Ma=¨*6 #!hwhKwMCt endstream endobj 624 0 obj << /Length 626 0 R /Filter /FlateDecode /Type /XObject /Subtype /Form /BBox [ 0 0 24 24] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 627 0 R >> stream xݐM 0sw_Ӟ@\TB"VՅwb|佌$.;G öi0l& ,+VHoZ,*+X{[6R):_NʓTyrS?N.svM,$XCDH:˞n;; d endstream endobj 612 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/edit_cut.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 628 0 R /BBox [0 0 24 24] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 372 /Filter /FlateDecode >> stream xmN! :,Iȿsş[jWZٷԺCl endstream endobj 613 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/edit_copy.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 629 0 R /BBox [0 0 24 24] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 262 /Filter /FlateDecode >> stream xmN0D{ABX( J([R\;ˆ*g&V׍!{ܾ1$|L#dѷ7bB1X#5U!up+gdԢ,~4blqyQRI}(7O9quH)^΋mmʤˆ,V>X-;oݫn'u̮V[ *ԵPh2PPS-\WǣD4߅o7pp endstream endobj 638 0 obj << /Length 1146 /Filter /FlateDecode >> stream xڝWK6WpUу1cM4 {\}Z; %SK&!ίv_(N #?J˝g7/M+JolSUn=7٩mGE '4:W4uq>Sfn,䡓UoaC Ms7rBJ|#hΗ͟b"h:;̧/t=JqrierD~vOj' Mˬyyoo|=OK䅱pGa<픻4 feq|բўiH` 8ԢaqbĎzѐdRoYqv95(ezOf׸NUNj(HQco;a뗥~k*DޣE`w/t*",E&J4w,喆?E`=+iHPq+T6قb .8b@l0z3YYxE*E"(rXH-l=MǼѸłjcfj6r^BI̮+ c$^D X3^HHeV9(u:۽|룬뺕`oSKo&Zyk & e}b5A@ݕfGP&zwq8}}$ WٞTqU`(Ug_?zyo.v\*}jfSW  !.+C q^hPN#EVJ+qNtS8#ai觌}D8Qbp& LpؽҾnJMiQC]/{bL4+QQCgN׮56z%xk5tuRK6T_P #7U3r 8h^iԖfG_W)] &79_g0$ <3]X RlJsъWșvu! PW{Jf³$%=2me endstream endobj 614 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/edit_paste.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 642 0 R /BBox [0 0 24 24] /Group 640 0 R /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 372 /Filter /FlateDecode >> stream xmNC1 <_`; 0"D: ϟˁF}b+ [攽O0XXJ=]0 w[ܥ@;?3,L=/Xс$X'-$ +JnWfy' I-{Hy!yƟPiO\(jVr0$đ2ic Wڡdv.lGכ(MUutǷYۓGmւGhM4ڛj 2(^^7*E ζrKҴ[%욹>h%(4 V8y M)Fb%S *=F endstream endobj 630 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/edit_delete.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 643 0 R /BBox [0 0 24 24] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Pattern << /p6 644 0 R >>>> /Length 503 /Filter /FlateDecode >> stream xSn1 +xm'v+$$$ GġPQVlsv=NbcVIRv,rۧ#=V\dxswݗOIXKiN+FmUnHw:rюCZTXҖ7*$r*5QNX]c*V(u~©2>E^%GHgڨ'Jd}Po ghJ @#CSs?D*ldF ZV߁U1= UA!36oygi~`x̗o/yM7妠%> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 377 /Filter /FlateDecode >> stream xmRN1+n )8D(O.͌.w$x)>t8&#+>&x|w{|Œ^j+ɿ/i%nt$癀6I*lSq#]$c:Ot x YX2u"yU2KHW?CNIbu_v]xR ])25\ V*Y.eڞ]E?|v̄#%/bU>G)ؾr;ϑ٘ K)`Sܽjo=ۑ0 fNw[ܣMЭҚ[\\7me_ p G~rO1~%s>]U^ endstream endobj 632 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/edit_highlight.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 647 0 R /BBox [0 0 24 24] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 364 /Filter /FlateDecode >> stream xmRnT1 +n*(, 4EwQX3 43Ut\;; T$c B Mz~GU6d 8cNtVxQ\( 2rT+8M(Q0llv6N{|PkŸAp_k|xME/.M%TΌKR(1EŖFY),R|chQe7׆N12+;xNgBgGgU}JmԭpqvlZnǷ8d7evV],sY>؛`>Mm"ST uMr*o]ݨ6Aro`jЌKX j+tں+^ endstream endobj 633 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/edit_reset.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 648 0 R /BBox [0 0 24 24] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 182 /Filter /FlateDecode >> stream xeA 1 E=ſINbt).dAi$$'t^-i)JU8_..|w("xB]4 ޴@QL]R(Nj>J_!ٸDK.n%_i-шΔa-j5[M\'ɌS3u$Wm6HD endstream endobj 634 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/edit_undo.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 649 0 R /BBox [0 0 24 24] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 402 /Filter /FlateDecode >> stream xeQ1 L$v !Q-N]qP^&qf`Ncy*B_*,5K>>;OqRkH\3"aF$u oIu"Uvuj?ثӱaks̬_tox 幘9)qltm֒a[^4 &S}&=F*b,UckKP> stream xڝUn WpJ5cl|LJnmW$bYKt^6H cx3 =#>nVWiP,fx1hS&ޮ)dl<:N8*]ꬴ֏;G9T$XPF(\DW~`Y}ڬ~(!3]?T;DpZ2l',AW_W$"'hHgOCZ.i#)!$*=%xPa¶ฺmYn4d{wZx~D 0 O!I9>2+/)o4Xo [U?rF:Q,z]?^/# BCMؗyWN~)To@AȺT ɮFS}x F8fqJ҂ W2F.!@0wtP΋0I8Zٛ^:)^u[<1 $"el](|J'3 2^`^.9M妖Ͻl ^y8 MsXg<8hsMzJyaʀ6˱B8 ;M 8TWwNpYU#h!4pwUq-KS\d#OD´g{d 0s٫ryzeG'm7NyY)7=&0#W^~RwS5ZY]5n</ǣ05sK{6Xڅ83t|¸u7cWV{O'O5MpA<i endstream endobj 635 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/edit_redo.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 657 0 R /BBox [0 0 24 24] /Group 656 0 R /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 405 /Filter /FlateDecode >> stream xeR1 ~8ii(JDq']qPggfY%JFcy*Jq_ɒoI;~{+B_KDe[#1T5V12eib窐_,FVҞKo/uw)4Ģ:rjz 9f:/wZ%HApFxacE6H"+kh+ 9>dKFЯ: >]pj5&-tpj5 }e6q!~ 2UA Q;~k] endstream endobj 650 0 obj << /Type /XObject /Subtype /Image /Width 1120 /Height 630 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 111823 /Filter/FlateDecode /DecodeParms<> >> stream xuXTn, (%4b (( vb7؊ "؊ HKl?^^J_Ν{̍9siQ@ @@@ @ H@ @ ZW[U^Jy@NNNVVPPPPXX1kLwIIɾ1lz t s+cXs/ܽw/{S|!,Ǿb0ND)//////11j#F ԲH 7QQ+V111#ɿux}}}||˗/ϝ=;zqOֆ޹z1p\׻Ϝ|d..?ckh|/QFFڳـGOVZa Aav33ӵVtXF?pڵnnn֭:{ÇXY)..{-d2=x76Nvuy@h*\^^{…˖m޼F /rs\gg.p]|w1@ kmܴ56ݸG1 J up8SS)SֆKHHٮW\4iR7Oxׯâ=TTT–,Yr- r:TiéI/hF;Z]W bݙHko242:t谔Te FII JnFٳǏ3>}@$z`+2jXIb8yDz I7ܹsm =uȗ,qPe癳6l &&v֭իW{1d\ 'g[Y .l4SLIII>aٲe;vhژq keْt[Zt<==/\p] 5lzc^xl[L &}8s>FȣҢbm|T̝ؗY #%%%=##[~Aa={}N@yϽ{ݓ;{ Ὁ8gǻrss(ʗ/_qss[fMZzkXuf9U[h|Q/4a8el6ڵk6ۤeָɓ VUQ;ҥKCBBz666Ӧ6Œu RY\5[RRƶ1b?EES2ZWrڵm۶zӃHcӧhs ϟ~Jom}@JKD^i?HLPy=Bok$+Wbbb&""ZUUؘbIIIVS ɷoX($P^GvdW }K^oDs5mv:,^⩩3gΤP([nn<ɓ'O:::} kbo(c{̚v?{,44ŋ |6AAA>9r$|B -(縸x =EB|B7&D._F% }C 000%b23g9-Z:Ħ$>n KE O5J9lX˯999.]= HcAHH(d6o:̀eDuPs=̟{{~ՒZ_~ """UUUKNjĔJ+v $hNAt^+,oz6)cϱXʪJ s?8sC{/h;;;Yfإr…'e O@?׼u!CBCCO039uF36~a:M|899mذ[P A H))) .l}~ǷY55Z,G R)""#͌2zzzwnohӰ*B-}r\\ֽ{̳L&]~ ce5AP!eO׃g,uyjbbg"MYL|6qƅɢ>n+V9jŊ^O߶oabblٲWeccbţ_ۑ# ڽ{w]eU`AD7X rVLL Bi=k׮]ٶmpܜֱxrPm{ׯ_4)rlq>j zxx}m<ʨ;NKxܞa]`͗.]zxSSVVv. ..M[]S DHRb@ `+JԢ{v'|9ܢ< /f݀X ^y|/c!!!"(!!1cF/66n]{ce6&ffma̙6P/YX\\%h~ 䡈^2ɓǎKIIqZ7" %%%[2~o7KGH$_m_o֬^ q*m5Hp[Ųv&"GOIMRvv>?#K<==]DD) WG@GlMCCC*׻hmXa?bqqJXJ ]g$Ü,(㛫#Ν;G1*C̦VОs1 HR-Pzv@ZwI`]{s?ܹs9zԷ;uc%x)t.^J&h4{{@臷XX~}?┺x6ˠ!c9H\mX.|m]%oix6 ws8;qɸqʣE;|JR4߾ 9GoE̜ -#Fx蝗%BdR5 C==}4m?|>Rt:fh4xJ烄 hS@xG3W>ܤQ}qsoNZZzUO5+W._yFˁL7DDDL/]6VF 6M`эpppR ݘ#fܽq9;ۛn2 p B\>0pNNNnܸnh;ܹ{Wie}8no,?ѣ<>q{7nX]vر͉sx5#@%`98Wc.Z׷_ J YLOdP@7ټys{d +ߍ5ҳIRLS^ו#,.]ܵ -=U]-ߣMS D)"j'k8~z}}}Jrs33SS#_&ApeX5LY۷mw\R>QDӝßtt|%Rk0N%'%@dkXD8=1At۳2H~1$aaqX6 yeâ޾USSk=Z'_rE}eC(6*,ѺֈСQog)++xzXcC1k Xo!++oO4m'RRRQveDO744\n]eDDDJJJd2vvv-H$LrjFff/rgsU7u7TOϏݏ5^EEE66ow-j(}9Νn&Nr-Llidh]G qtQz6(4t_$""IȽmѣG+8߫544dUV,je6Q i-v_vǜg8ᗜ H };v~ѐX܋(,36_Ay}gN{6jYPPmq-s~MM4 H>i|عsGP`uuM돍lo/fP:ɓclؓ6ך;wjvv&z=ls9:_HZb˖-STT}kwk M{+稯n%諏8mQ7=kV&Hnn/\ݸQHHfӧO@8zQ |fIA0ۨd})]~+U~HWa' ;я+ UVVNqix]Qu%r㮗%LI2V N fk;/((kg|+֭[eعsjc WDDDosQR#0R 6ƪQ-vh)f_`:=8)55=!zxPĄ< lG$}C?eBd9wMX bI7y ޽{ۆኪGt173+> $$ĨSlh|8$$$'&&SU%h0[6]yN4BL̷ xf!c1WgSKJϜ.?"x~F^%ƚfUl2h _UdqJ}(;!~I=*+Qݤ 1O-Q4`ĉ$+eJKK ܹsN윕i&QQϟ? B7 u1Y Zc?TUUO>ǏÇ*U"H&lXqqqc(Wjl9$~C?c@Uv0[kŋmqYJ?3EqorEnz ,--Ϝ=,))ieĺܼ\eeeD\.W_DEDeee;O7gK EU@ <&iǀ>KشjMb9; -ݱtY2XVnΔAg9'H.N:jDFF&;Җk[.G>yVlkϰ7ooٲq˗}}}_z ') 72etm"H JKKzxx}Zz3g?՝jJJJ z!,x(w2D `.x &!<>rrrH Y^'|tk-s`>=}GǏ]>~T_W]~ Y QD(  xQ^^>cXˑTױR(03}l@e&8MX1gy_q܅ ]ɘL7‹K\KVSe`>A=g1LP(35OBBBCk]#C ܍^ze~1,22hFFF7n|}&""$tT3 Ʉ[u ey4&hTRRj~P $''>O]Y >]|=8͚DiEC#>_%/DGx[/-n"@'L#uI;um_:u +wWiXbbbxx Z$Q}\ 0~.:kvtFڽ{wBB¼yJKK@QߥK+Jҍ:P4.lF5;A]VRR3go9^"""Nprv>xʕ [[z*5777  \.W9EDDjjj:8 HMMMy~YʿZ5v`DnÔo'J6c׎ܼQkV/-vH~dnϤ/1%qnJPg8Cu/NӟL"?%0==/_>6L\\Gw+L!Y2__at=ټ! C g-Mit|@.I9!yQ;otqtE6&<:g | NB{|x3_x6y]ݯ޺qs `1oV&{?7SS[ØLYbb-[,Ybii,냲0̑DSpz|/z>ƍ #--8ZCw JFDڊF%A;RJlX,k4 z".))1e0AG[d&} OLL  R__ AK5}fD<n·dg2&hWv K,}~:bU8g箭Ia ?}_"&7!o\,eJQ3\ :ۥb\l77>Gfjrʴi222a>>>ZZZb7d8uٷ#BKn2k-$IIIIpX҃g {(OG^zbcnnsǃqj@N pCeDm|27g{tL$~~_Fza!s }}>G+>~zjx8NAAŋ{QNNNf̘1yǏs\Dμ[qeA"8孢xaaa֮ ,HKKsrrBdVWWw0FZ (((H?*`D{½&J޿y;}7LF767o.RSSNqj#B<$%%ϟxr..s̽w>|(w/_Zp̘1ZZZBLh/@jBQQq֭I) lۆ{ D!8: hɳ̷{/N3y1G8ZHSi &M2dC{0TWWEEE5ޙ4iÇ'Oܝ?099{ޫdzuY_^%$$hjj« i.A:c`2Â@0R@~hlQ}zfRS ȮY?5gx߼ta zE}w/)5Hi ww֓ eۚIF-Zz}__UV-Yd…_R{XZWGwoS‹/^pAFFfҥ;j_|i }yw}J o DE}ӄUUU{cMj~Aƽ># _bVTT_M'&]Rr>>̓]\\&Lk)))hBͻy.p,PK|)Ql^aբTM-( vXZZϏzS\.:^x g L F|x#V1Jʽ2E B/P\%mEY>/2N9N2ezMy:Ǐ/?|݇ ۜs#C.f=e- ...QQQ߳rٽH]KQQQGG244Ǐ ,hVVnTGPc$H,ybʪGNbճkCuAnYflp?>TKP65}o1j~ 1q􌌐/IIkVF -]3}ywdgeev ZT%X &Z]RSSmmmggǺq|2!!ֶft:A(Wbn?m/# ʽ.kky)T8 c_Vdi,!)B\]k)VP5vܸq·j=rժUsΝ4iR Kv0a**C] -|{{W17Zs9?j+a'i㎭4#4,70ToRx6y<.Ih```}mmhhCDF h ?R)+)vܱfjL022w^Jr4+++SQ6u֭ۮ߸˗6;-')-d TUWWr$f=X^G\yZ4^OTY4iq(qǛNN?۷o۶[nUPP_Dk7 1bDpޠ_;zwY`^o Qnqe@:!vDL5T!*2˟z:zQ2|~O%an1cƌ+**x[_wid~DIIQAA!((hѢEuǏ=:k֬_VٳC jjj^re…SPPPPP>}z'ds8FF]6 Ϙ>ȑ#ޭu™.67^Ln|>r¥U{ĉYc?Q6{V굹4 %W<TXG17}uԚuu~4@mmϟ?O07^_O|,&311wׯ]7nlF.HL6h>/i~3sX,&H-PT555{{{AdI7f+p鿤%%$RaEǍ;f8Wnj윜ɓG}nᯊF&Dfa0Ewg)0U,1xP=U| C0m}(t…?{:|􌔔Cs #M$$!ttsjWA\:9-4k*\ Thd2{XMQPNg<6sÚӻ{c E ;ϋ{Ι}cĆWM^cH$"i aa䴛7opȏ`4jS"dD ($j*ZMUT|R솤]#CWo7Κ!!n ^\VEES{PB~ǷZ9V?5uG8p˫27otvv~Yǩ{gϞ% wwºѣ==={^t@:ujRK,Y~;wZ0ad)㳑 $ o-]){ 8l$1*k/h׾YfS%wKHH`0Ӧ]reFFFؽ{ W^e#G ߿{NOI$837!3Ļ:,O***Z# K-!ǃ6V4 ~N %ƣ;cǂdu6oNوC0\,#>I^xH$MM͸X,յӧOQ?$?Ȭpa "&":J`́y0ߠFpWAy))/OayGSV=ByYN+3I@6mj]BBƦ+S_|љ-3ֻ Kqqq:k^LLߑe+W)**mr?~IYYY3f޿W]@FFvr=3f8x~jd"w61?tЙ3g++)/j1!У&޽{7{jNzL,gpcrpX\t8<&1lذ|())i(#gXaQB]bw~(é+..f(6r\@(++ה ^W)455555zԴ c˫kj{.V4PٻPQQ9uꔿNNNFF`͉]a8..իHΎ>G~۳w7cjj .ܱc{_25+ Eޫ8/ DΊCѱqw^xqcJ oݺuk۶mJ[l٬Y-[=^~k׮EuRr߶mУ*tр/^i&11pxp8,۾^paҥ6mȺIzc|KxԔ#[wFc?5vuQasǓ8Sz~4.Bgma BBB*C{~M¢]Nη;ĵ6;o{?z@GNnN^n^:~4Yvvc|^LKKbxw!%l"qqO~a|^ÃP9| ['5b\H9Wb|ᣪlO47e$'CT$uz։It)IƴL& Oґ*.a]!{(׼'a2vuϰR6a}1{X_JYdx ]5CXW^(5#?ѻΞ@ꫫ*7Ho OMM ksuA 5q uBBBTt'Z)+)u. &5ЧOSRRKKKd2PUUbe5u|߻f }V\\\RR qUԿä3%٣k O[k=cҘ"]yH7[Qw?bA,c`/!.0ag1wX$zݒ<aC!hѦ"R\ l)Fva6O=Zv'axOüdxZ frz]aat7 $Hfg>>bFlCUC6 @ d .#!x<I] @ P AQ I6ݛI"~l[f@ @ P AYHD&3t.ۏ* 0tY,׌@  t?j]mUyAqyb!D%%:@ @@ @ %`@ @@ @ P A @ HY(VTV,H@ N㣈IH5v) :1,?Q@D\,(  Es $ e%,cP<6@ Y,~~dEY1FFNA"é.MPXX\Rj"tb6TG@ GGauuҙ Η4ib >f |aXF8l(CDcldr cx<(X7zEG<(_,$ AJ;jl@ HHVDMIP>D"٩++%K0 H-p@ ?( !.ޗ $(b$&`H@ H~K>}͛߫BBBjcnj"))ٙ22ƍx(P?L @ 3AQ^Aa!h~|Ƴ1c?(?~r劥䏟>vueb(ʃG @ @JJ(nv+WˣP(-  ikkkkkϟ?F={v=wWh' p@ 䏅Jm7!ٷ| u{m ۷o)))$iƍf)))՜5HR $@ d`PRVh ˖/|TSE(J*Corm= krqQ1.0@ 򇂢CA1ٗ&O*.aXEi)}/\trrRVV{綾^(!@@ @zwzٮ{mSUWW\.DpE'/^25 99dJw.dC @ &(%e-ryl6~˗y\Y94WG E#!n+VZYY])$H@ ȀHʊKffFxxWß>E}vÁP 7sss_z,dAD @ XPiwv.,,f@8fj!Y+/o`}ʘ1c^spEC IRLViB݉>8es\|{{;BH$mߵ;hcM|,yab؀!cT*]~544&MTQQ;wӱbbEDD?BQQQFFFL&sf{?jVV\4$>BuAwaٯJN^湤U```999=|PSG H[w*}CI9I{!H$X#sg~'Wq ;hg:xsY2c|GhWUSيi?hu"!π;@}iii\.S?^" nܸٙkccx͛7\nIIڵkY,[lΜ9999p f---=7q%N!FdyРp!8mhhnݺtyF~ydHː OMM .ez׵jo<6{ȎАgTZV.WH!7{~M?jQ+'M|",zM,wt`.ܾ{i_B Y\US!0JJJT*U hSϟ?]ߺ!!!_~%BÇRENMG(v$INGGD"J‹d2jʔ)vZjUUUm@@@FFԩSkkkHMMM&3 ,>2dn:H.Gu{/e;>Bףdn1l0=MMMTh4x4pu3Q,Ť!}]Rv. 457G/r`$IqI[/76]oRbqAA=<ԩS_t'N!SSSv)&>0RMMM0Ws=\d;pdRdidg d{d"?%KO<{rn H|Kُ++kΝrD@XL=c=X\T\|~BHKK-oMMM_xXZkjh زmUm8xe[|]oaCBB>ӛ7o-]tW_}5n8ƍc)ʪU/\ B5- ^{̾tf;јce㿕}KJYesrȟidd$ψEJFF?RUU%?_bHlwh\ özf𬙶6Ɔ8&vqscWk?IDX,lnfanCںz2O>Ϯ]V^=i$XS~X0aB\\|!W_)++/YRWW7::پ@d9D#F xQO<(--566Ŕ#_UQ2Uty|= \2-yr?PYYI${>|ӦM^^^?SFFk2dȆb<3#xPgFy sAza)))qjj3^̙3B$gB]$R׊˓&M9 D{L*ψH$Bx.Bz䁋 zzznذ~3g9l7/KJJRWW뫘KEx.BjlB2Duˑ#GRSS_uLJJʌ3zӾիׯOJ-scA;w#4ȩU~ҥKoܸr7oJ$33k׮<]iiiPP z $ރg.[d2`dgĉǏ755uڴiѣUTT^u .x{{;Rފ'PD$g!!X2tf洠 ._c!Ht"gϞn) oӑ#nn"4z2ha7`$HfBssӜO <811Q$!mӄw9T*=zիW\fEnON$H;/7;HhJ}~2== """==y֬YJJJX3gDEEڵk?)_ufhb7A;jz+m-OZY$---))jjj8Jq:3Ҳ]9S}]]2o$3</H^H, ͈˗'Sh#'HbH$ⷶ&k xhJ55HdUkKRagV[SAW*)÷[C"END&ih6h?zdok- !N؂㍛D[$"[PH&2f*bkmyjmiQpOe%%K [wTV67/sWYjm9t1Vv m(ߋb$З訲BUi/ ˗#g'p'4/nP 0k֬Ν۸qcuuuddd*zyɷdff*++ hz~r-Ckk+NE^^^QQQ^{&|!@zBD"qܸq]6fddt!?k֬ǏGDD/B!LvרQ$>eh+KW\5k>Tp8`.d2Bdn%H$G? 05>|ԤyuS\\L"###MMMB޻wB(55u֭)Sl߾!TZZXPP  "## eڵ400p, ##!ty*%@zU1ϟOJJ_hQ,z(gMM͎;\nkkw}<-"D"u+99Y*N:U*h4DB H$SQQ`06m?ƍ7mB/]dmmMRtzkk+9&]<\EE!$TTTb1Ǯ2=:!HBP$dTݛov/̜9@ PyU__XZZ! y<JKK H̙37n!ɉ;vƁptt D*L6-%%E (++s\KBBzRRBhСg޷o_ll,5x+V+,,\dIKKb p8&&&XA###M=S,}嗣F> .x  " '_}m99cccuttfϞ={ua{v;(Kި7v$@wyYcc*6Çg]9"t:rF555l\]]=??k ꚕd2I$#BHEEO6'7a„hT:~.z.*L$i7/Beee۶mc2~~~RQQ | R`ˏ?}mA&mmmϟ?xbQkmm[偖s^^ޣGktGT*v6}e˖j>>|ȑ#^1/0~QuuuEE~iffbŊ_~l`Hw$o̢E"#####ۓT7oXgeeEѰi/_p… 1梢"ҥKߠHd2yoVరŋ߿<oP()gMMMLLرcx|VVX,y@@ $ɭ[ϫbqCCC8pbbbDKdd$6d6hdccu["ll;fp8 |>DmSl LܹsIMLLRSSDill|$&9uĉܹS[[;f̘WvU<zQKKː!Cd2٥KƍGPN<鉵|ónݺnB LOOQp//;0,D233|>B#|6YG]]ݽ{tT*=s Lnll'$9&)={`0?~,ɆM >@|^T86z5BBXZZB>IGG)++C>bX, fX U;"QMML! Vt)J #E$544tvvAI6@ي%H=z ",J>|hffF N2 O4A(bBm xӧO*-hgL͟:;;dJuu555,K tvvuuN "?[UUER͋zDL&zHJIQ([[BMMgϞĶ'O(++߹sFijj*++x"BaGGGII D"R^Te ~vQ[[K&544UUU|T* ! ƶZ, ne/`bbѣFcccNG1 _LdNNNP 0˗} 7ytz3{ ;YN8ѯ:`%tssWܞ͛ov˗5q#||޻1;y r @ۚ5km۶f7ڵ J=}Leeeb@P(?l @ꉋ׸q͏?^5jb/_ W n"!4W4:uO'8qbo3<ÇMMMׯ_p8$922!t{bqnݺ5444<<!TYY9eʔ۷{zz"JKK BUdd!CO>~]v^ۂdddY[[#Ο?ORTū 9|RRRuuEdC9kjjvr[[[544;x0訕+|GV%vssrs:35?lp+9O* ZbwOe748YJMM !$ eHtJJJ512i7o,_bbbijj*ߢTUUKRM6]b555!+++:OP\.rx<]l&;  hkkxyB0::SGGaUΝ;'H $!cbb1~͛7?{L~lEEEf5jèQbbb'?  --={r1ɓ'[[[7oᵵ^xM>_WWmT !ֆ嘖&Ӷutt477˃y .w(.gϘ`hM7v='cnj07[0_&͞1COW`iwjim8s6jY:SGgy9WcWZ v0z@$y29s` 8n̘1W X;:bX*޹sP(,//omm IKK+,,r'OFD".;c "Yyyy@ qqq%%%zzzW\Q5Ce2ݻwCBBa=H$ZXX$'' WWW333LXCCBHe#7nxx<^"`[#"">LY,֙3g<<<BOd E`bq{ww FlY*b,`o7f,KYYY__F!RizZZZeeeزP(}vIIeX<f#Z[[bqJJ'H$#@0"555.嫯-g||<ٿllٳgϞ kTTT̝;i>lllNsdXNNNSUUզ&l 300311IOOP(`07$QTh<[D뫫g*=zw^[[B魭]peT( \*fש>bgcoE>^çLddh7bMEE&$Bk X\LLLt</0/\]]=?? L&DrttDiӦrN0!::Z*?ˮ J&[ZZޔSGG/@o۶dK2l7nVg̘q52OB!LvrsspX1fΜn9s{yy]r%,,L"O5|X,Ux {%;QIRy4R4++ ^X|ȑ/V8WWWWTTfff+V_ @Ryt+++377ź7 !_QQ455zt{-uy_X^s$8b!4N6;{ai=O?gϘ{PT*FmO&/:BhѢEAAAT*588Xu묬h4Oi/_p… 1fҥoGL&o޼ xO>}7͙z(gMMMLLرcx|VVX,vss:jcI8N&R/]BGS1c3H$!cCÈEauczА*m -Y3#0 '$$p8"+Ou4-aRvv63xÇs8>M"Zl6{Æ IIIL&sܹR&&&uuuD"466V>E kkkssʷXXX`SZa#X,h|>L&cH$P("T Э;v@ \鲅@ #_;3?~D2L~K*=Cܦ Po'MNM~X0Э[큁>>uuuXC`ԩ?F 4_~qvvFֲXFH$t<@$I$H$>`0D"/Q(/))Y?TUUd2K,P']svv.**r8Ehii ng4Ɔhjj ~ 566v ~J>>=ǚؽ@Ckݺu_`pH|0UUUUTT^`Xaaa=yiaa aKƩSjjjLcƍW\\~Fb2 zQMM?0|p__tmmm,ɓ'C$08qbҤIWf2qqqpN/))9pIXX)JUUURǎSRR MMM555_5N 8qℳ]\&L rssL܅H$ruu`N<`0<<<✜l8l0X󃃃㏶ذ쌌7o<$Ht:ݝl6 \ :&v£ǎ=NF07_0r0¦(d.ûhg.NDΜ<4*=##xχY5_}"ammBSL'P(/F!BRtΜ9JJJe˖!$<6b"(vek>[e`ݻjjخv*+Q/xexGI?3,4`$N!n)Q>Aݻw˗=3xՄEx<}; ޽{L&Bttvv溸U{ ̘L/0 eY;bB>O '<@ 8fvnA% [bbرc  R[[tQ==˗ 7n 2$ !mffg)%^toX__cjj O*JeOI݉2O#\274$X(&B{OǻO6s6֝RΜySêe,KFOWkbM=ƽUiƌ>bYYg#B !tG{G졳ȟ,Ŝ׍ MD"nNrNnn}C#SG{~qcF\Q>:g'GнEQQ9'ZC!6|.hϞ=OF-^<,,K`ii@&b,Xpڵdl|0luٲeة;܌uw|H$xq;w>|kYgLrА`Pl|B}}á䤃Ľvٵζ{y9Ix<.2*J"twkץR)vȕ>#Sg.Y(!{[%+?=!(ںe+W|G`5`0VGdv ¬ Lutz;Ix{[ʧO{(գǏEbF< ${@E7sYn߽\USs:yH$CfN :֖ǟ="rU^R(H$2 a[HDLy ~FLD, ι7ҧ\x~.Malsرy~H*sJUUD,626|Ѿ#> Ux;h_12B-flBeeek׮0aɓlق=ɗ_~9w\EEE+9.C^TUO >A.((Z 566 2D__7'imm[nݠA.\i&%%S".]f7m޾gϞ =zTWWʊN;99!)|pU. z LMMcbbh4ZZZZxx_7o^r6U_uuIBBB"##_^υBatt4xٵkD"'|"H222RRRBD" ի8PRRoiuZUU ൲.\05Do 577p.L&񅅅***!$VZeoo|Y>|h׀/gIIziu'Rqq1BH*K*pCX,NMM=sLmm@ 6VTT~@CCCARQQq9 )X5@ڥ ]6?z d <@u`/Rbb-- ۷oXXXhjj:99q\l6BU,?~\~Dש}|p3{ٳgw2!!ĉK,qppPVVnnn^pagggݧ +顡l;Vmڴ)22FWw 2Y4ɱK[[NFčf{%%%X+5WW׬,&I"_-֦MHGG/@o۶d̙3Avd2Y"(nikk鯭@Ankk/noo}5k7~&gϞe0zzzd2𠶶֭[6i89//֭[XfKJJ.^hgg d2f߼ySOObXL&c/d26F&utt(F2ϟM8xnmm?T \͠xo޽K_GPuu|XÇggg77H27ɔ|>6[vvڵk6c- jooONNRc]]]7o,ʊFa#7,_|… . b2EEEKH555'O7o^xxx՚c,Xu255 ?Lpww_Y,VVVVFFkk哌=ڵkΜ9]Z(P#Gamms;L&J/mWtIjjj]]H4553)SݻE[[111[lY`D"qrrںu zOblliӦ}} 8q>[Hf7B*j77M6M4iL&3..n^^^.\%%%011 255RT*uРAÆ  P(rU<9غu󽽽}}}3D՟EGDݼU 'ZC[8TBsl&֗`f'?}b 1'׭[`ԧ⺺^Nѣg.Xßw͛1cBh/Jeee^^^ᣏ>ڲe#|>*//oժU񇍍mll.]ptuu&O1}gϞ]t_E͛76}%>ȑ#cƌWTUUd2v7ەh"(fMRSci444o߾rhrppxmt455޼jjj¦H$-%H\r%BHYY9""ǷT|AP/^Cac>T*3g6peˎ9ڴiBHe˖%&&.\ڵk999&M @wFcGSqom0?l1_XVVnlbHk++s{qP$^SQkb(d҆oA !dhhHъx<| DGҍ7 ?sGGGb޽[__x|Z3Є _Uv9b.8ԩSϟqpp8yG x&ؔi mD~Vu:B aN9يe,摟S,*** mN [!E">[loookk~W˗/_A~ .\}.cOGGbT>|8Ç_x$~=\EE!$TTTbqGGFؠd2D"a BP&,|?wtkni_\uzlWД@;[в׳.;jdƙiDZ.? )zJ aѯ>xسV:N :;;SQQ"ɷnݲkmmmiih@[[@ JJJͿ/wz3ç"Q4 U {٩"8`<{`D:>Hd23'7.C^U>}ZYD&-XmǡHh#F(//gX'NpwwtFúdffR(#F5 ,~FLD, ι7ҧ4=ebXYY{ϗH$]'#x/$ Б||]]^ѣ[_||{M|d.KII);qc @RiVV/HDX2w&&&RagXOX+++KK> 'b˛ .)kkkTSSonn>{l@?D"F ߱N}ރ mm~9.hE"fϘ{PT*FmO&/?t 0&b x<[~y7s .[t(++J}:V$AK.ퟵto1n.;Hz.]'j7H@222L2tP7>I~~{2>>~̘1 @Cݻ $P(J ť5[.*AЄ%!$,?̝ `@|{{އssJVurr Owq!\.Go7onܸdMfw|ychHɞby{svl{⧀QQQJD=@V֭[j:""~j7o޼fsέ]Θ1!t˗kvttڵ+55oqww 8@*,,dJSTT__Lwرe˖ݻ7((t֭[b?IiӦwYȈ]z֭[}||pR<<<Ba]]ݾ}rrr?$WZ%^ޗ g݆AA^C=Y]o;֮={(}G}G{)<;/_)`EޯZɚG1Lgg&|4֊D"ކ:99rJnjVI,))4iH$WE\~M$˵ZmJJ _BJ>GGtqqqF#""l~`e_~xѲ~v묤Б#\wZ&rr۴ڼztPꚶpA?Ǽ_Z0w.;qFs>>O>\@L<)`p٢4Ms?p;˟ON}ggw/wА!CBwppX,ԠITIE"QXXRH$WjM&B8z(ulXlH/+++77 upphmmMKK3x-[ݻqFWWy͛7|mHԗVj?9!fq߾Wn׺ 1gZSd2u :U$۷3ߺZW`8ZT?  7%b\.W֧l61S8tj 655!\\\AjڶZD~~~B EFF9s͍d5 k̙3g͚5p?{9sŒۭ~!Bɓ:6ÞFK+چ1"d:A>=@B |պ?{G7NS^oxc[&M53qHh6V+q`X%i4M=O6m|)X,Jt#Ξ=tRpڵ54-<R@yGGG~suu{::7[Ccخk.[ӥ^bTj6o+XeKMG58C==VF Eg%=gQ$:n;Dl;|G\.wΝ:g+((Xz5kɒ%fؽ{7INN\n.00 TYf"/GJ5} ,v iǏ7nD"9s N 'W"̙3& sKCBCCY,Vڶm[[[L&;sJ>RƍOcƌ'lS`XyKK/8lGs{'N;d2weK\GVܹcXGƮO?H$rzyh{zY~OwYYtM(3gk{ >_/O^qW%2<Ωy 1ó .FPy_~ ***BaFFFR?謬LWcE`‘RAA^ >/tx&"#VbvY.33sf9,,lÆ x@ dnlld07n܄ b".nݺ~Tݼylsrr1bĝ;won']^-_,z+d2 7Rz֒س'J陿MYO~o{}/;w:l6DFnYyXLѨ{[Fa?UCeeeIIIhhyZO> 7a͚5=OLLLNNf>`2=<<5nܸQCCñcǖ.]>}:""(""K.^;::O=uꔧȑ#a`08::j4.KјL   vܹdɒ;f]]ۣd2߿ɓWoa

$ `ĉ'O|WөN駟.\pZS"ݽ{f[,І>BYV h؟m AiiiV @#d2LȀv={v  Ff#N8!ccc7o~QF3d2t˗/GGGooo/)) rB0((?1`tt4> u8ۣtww7ÇꫯpO۽Y|2wlC}7Id0/ }y=<ŋC; 'K*>|MI)d2涴h4Du᭷ "J2 l6{ҥ!< |Ek{#d{.G1u~j/O1@qq1F 8uTBB:th bup`c'xo9rӯ\~G;vpvvNOO?xٳg')yWcǎ˗/\2%%aX=z4ޫ %%~TWC@zXrOOϚ>ji {>N#HBdCCVǎjxN{A{{[[[pFm%IR7442'Nj{.Ѐ+VV5M[[>~QQ>>l𩩒xh4S~駟rʕ+No\t .]ZUUx\:..aaa7n|饗BK.;XB.zj#GT@eee )|~GGBH|d0xcƌ<ш⒛J$~!((l6^xQ 23g޻wl6߸qCP5.]/((3fLW|ABBªUzMRBMY8o޼O>٤Żw&"66`0򊊊@`26'A}\\h4:99uvvvy---bfwttX,_UyyyWwX,hĉtcKK ^h<==RL&;y$6L! CJ$FP`0qvŨl磢lӈz{{{zzöh/L&6- [ZZBJNX,A▖RKcc#^5dT_ KReSNuّJXZLH 8ۦLrر{Μ9ٙ$Iٶm[uuӜ9sϟO石o߾d2}}}B%%%{ C>|xÆ o6))i֭/BbǎW^%I2000==}Ѷ϶mVQQh5k!p%̙{UVVܸqCѸK˖-xJ_(JV駟رСC!\ruuϷ7oܸqcEEE[M6=j訨HRDC |-Za?Fj7o^fϹs֮]r0/_^|\._vmGGǮ]RSSww@@PXXB6T*1J%A8 *//OMMxǎ[l޽{$u:ݺuVXO$B~ڴi)))]322bccW^uVT*PXWWo߾|>$UV\tsѢEf9//OP cժU)))2… [lK+uԨT#G)VUUU\\\SS#|CBBBӧO/--NLL;vpww/t:BhԨQXjJE,իWgΜP(zR vpp@eee ;wr\PLL̼yrrr6n܈+HJ4 |.B!"Jqcǎ;;w;wL&SiiG} P|>AAz 233LjnnK+!lutt|:SZHd?:B:99rJnjVI,))4iH$WE\~M$˵ZmJJ _BJ>GGtqqqF#""l~Ft:{ .Z`p8x !"Pնj5B~~~B EFF9s͍d5 k̙3g͚5p?{9sŒۭ~!Bɓ5fͰhJk.&z[n?ŋǏ///vZggg]]㤂7nP(xMiiK % L&;wm4͚5k=<<ݻ UVf:ڵ GGAiilhV*p_֭[ bmmm_|񅷷Ǎ7g*-0О:uJ,KR5bĈgR!VCCõkרp4-<<׮]\./++;ȑ#qbryQQT*'Uyj0ٳ=6lػbp9!x~w}i^>|xdd$:<GZ+$$Y,lPcc#^b0ԎT*H$bh46p8OOO6v5T* ikkj /b2*uUe0 S`pSNfl>#.sNN^dɒYfutt޽$''SFFF[JXpLFFFZZZZZڬYZ[[KKKB˗/XT*,X;F>~q$ə3gppP8AgΜ1L+___$:bҶmd2ϝ;V={60o޼FWWqƙLqገ&ʹcEh4f4qF ƍg[!o'2 5B:ӧy?:tcjն<$>eh4j: ;ׯ߰aCEEP(HJJ›333 FDDDzz:^y<BGJx=6|/2;;;++Kᙈ쏸Zu]ffSSSfsXX؆ RSS&@ >`0|}}7n܈ù &$%%ٳD\.wݺuh%[O ɤϴ[\Av˸P<^_qm:>lذOU{IVJss3@z>o2 t,d$Io <iСnݪRфz#G8pM111111LJۼysb2OSGR*bDDDDkڮ ?SzիW>T%Jv f6G!b٥k dFb;XNh:O9@dj^,wsdRF*zyyA0t:ݗ_~iZ1?~l0LB $IvIپxpIh:O9@h555555UUUǞt՗A~knn޶mۊ+ P(!_ߠd2[DO9@1Pmm-%!Ad0pmVv3 L&FS!N|ƍѣG\pYD"lnhhe~' vwd2hgN2F :n4z;< $q:Dd[&''gʕd=]O={„B d w& .\8!@He"<йslB8/Ɏ8pGG{>}:99yĉ<ASSݺukڴi!!!4:2Bh޼yYfNe,˙3gp}_t:2L&$I&i0pqqyh8yC_R8L7xEP lj.x?F@ GeeeQolٲe49P(]" h4d2be0E1 D"Z+jc<ֽدȵ744 VJEdCCN{N#I˸XQQ`hjjG߿ҥKmmm:qVxaAxfggC h[x1Bٙ$II{(x&Bx&V&d3=GJ|>!L&E"`gÓJ }WUUI$u6 8L$ Ã,Fdvvvf .lOJJ$**fʺ?|pOOO3L\ !DӵZȑ#]]]lxE/&A-X p1<ҴiӞZhц ~)Ϧq?N۱cnj3~mƍhYש~ N\ +Y"b'ɨee'H3fL:Q9rd'''Y[,(( f/]!4rH~#%!!*R*; !ۧ䇹wl6m?x._'Y?l߾IǺ:jVWW_x1??n ޽Ԑ[l|X.Sǵrċ+V0aBlloqڵ.rJJJJll-[Wx͚5M6!>w/^{kxUb+++W^ꫯN>}:ߴi޽{u:\.SNE݆u픚%%%gΜh4?ZYԧ$ZTTRD"L&5j677ߺuKVGDDOj7o޼fsέ]W/_|r\vڎ]v~70,, !TXXfQJ ѣG#SSS}}}333y<ޱcǖ-[wޠ \Xӭ[nŊ$I"Me1###66v[n\vŪT*PXWWo߾ТEfs^^B@ݒ}XUJ5n8. tvv޺ukĈpk6@QT#G.JUUUqqqMML&S AM>4;;;11Nر/QF%&&8p`ժU8Q*-X,W^9sBJ288ǒ% w܉cbb͛qF\$WZIU O|OeQ(`\\\R@|vŎ;vرsxxx@@ܹsܹ xؕvkv\7b  pkgQ֊D^urrE-3FVד$YRR2i$*PH$W^ŋr͛$Ikڔ)Jtvv*xO 8jlBNGDDVʕ+˖-qq@zvZk2'$$| ~kF=DGAX,-@9a0}At})|]ex<߿`Xpw+++H$_^VV/”JD"h4r!jM&B8z(ul=dȐlj_xجܷ~;445--h4l655@2p[^i4jT]ft:\Vk0bMMM!@@Z-V jBaaaaYY/с|>d2 X,htsskiiAuttp8w'I#11199^%ɴ'O>^p/x9FxI&zX}ԓdRF*zyyAFEDDTUUu{Fy<^hhW_R xZv=nR(^`PHqHÇ6CB;0d @ =  b' s/HwAhO< YAS* ֬YУ#x @KJJ0aBsrr~&߿a N|3f̘:u*z/ȑ# ,899@#Iט޽{fyڴiv ߬VkMMMMMM{{{t::tL&?-[?m۶UWW;99͙3gT9;;L&3<<<==!TRRgϞ0Ç7lo,[ !T[[u֗^z !TQQcǎW$>zh |g۶mHLL\r Y&//!+9gΜ{>ꫯb/6mK=VVVܸqCѸK˖-M6:t!$B999{*Ao*))())ikkp8>>>jT*HcdZoݺV#""HZvk֬9wڵk\3B/_^|\._vmGGǮ]RSSww@@PXXB6MMT* Ayyyjjoff&;vزe tu֭Xߟ$IP}}iRRRӻ,fddƮ^z֭>>>8x\u-֏UT Bn߾}eee999E漼> "..tzDDmݯ\Gu_P^ŚLz 8CêhlO#n3SN^ݻx< !4d, =`ee%IE"QXXRH$6jM&B8z(ulXlH%VvZbrss~Pִ4ؿlV#k<lcDA{} jŦ&@ BVV8@ ²2_y777&9j(!6sYf \X.N*x$^Ϟ={Μ9xqj4t:RN>M}>uX,J,kĈgϞbk׮Q#h4Zxx˗]$\^VVv#Gb"T*OO T=kٿj-kZ m,w.XUFӥO <@鶣0Ͷzrw7\t>+((Xx1kɒ%ϟ_t)INN,..6 8a]`` S*x|Q__^r̙3YYYYYYvRobw&Mt۶mh4Vzj;-KѢ?^UUOd2jF#JYϝ;qF<>AٶC%Z!fZOMhf7x HD"""jjjjjj=</44˫/` qݻ-˜9st:N'Ih4'N,//hoob$IF#H;x ooF#vxt:a5/f>g|>d2t:SQX,$I'Z...{!;;[$$''k4HXTT4qDf0jjjBBBoW_}4 ?ĉ jFt|].\5jT^^S6kkkD">&\p/F777J< HO$\FFFFFƋʵgqBbh4jbK$ jll0aBii LN+))h4k֬jN 4۷nj3|hRwFɩZAh4oKKX,6Vb jnnDV?h4bxƌ3s---tR||<.,]/ΝKܹs O `)$$S8qۛ$I|:B ?p4{^HqHÇ6hs駟fŋRiHHȃZZZBBP.:uJ"q8ɓ'SNO0v=vXhs`#IKZ|PإH$B988 z=1LT%UUUb!`0E"QZZڮ]lT*%Ο?UZZf]]]׿Λgt:]xyy={V,766RDŽ  lI2b؟rrrºLfe!h4>&1L |s9d2߿ɓt/PÙlvM+- FmNAl7,]{x)L&mh$\:H,$\t{u2ԗwr\.d>j?pR~$+++===` O @>|00 \.^xRD"Qmmi^@hb6}&h4Z,h2H4Lkmm[qw B޽{& )$`4q ?- MOzfT*'''Zsd& fZvvvnooommZK*LRggg6`0lsR-Kcc#t"ߠ "" jjU!$\3p8$I p1F3L\.W $" , .d2;;; :g`AL_?dZqFf D"δkZ80;Bklld^^^/Գ>yu3 oood2 @ eX:::~sj0$I`0Lk8wVUQ.-ܥlNh % HCQ<566F]]]u:hBPRI$^o4tP(4l6Fq8HبV9N]]]1:h4R=Fpww/..r|>wًḺr CgVmiiF lan457\nHHAuuu---:8n߾MzvF$]A z#ɉ{.*b|`ZAA {Q6C >>>n?dpJFKK ˭HTl6Ob6}zxx̙3ќ<999BѣGYf +))ɑnݺxkת-H$7nܸx͛7ܹ& N/pc:899999pm7reG P c0˼C1ÙJSSSmmFA7ۥRFFQRF(Hjjj h:-6 悂TfA^lnii)**d(m۶}W^ݲe L5k w]fP(ܲeKGGGzzz||#Gx<7ND"Q$:E"=z4 Æ KLLRYYYW޿(R>OOO i%Hf̘yז SRR>S@p[1"hƍ}YkkkjjFF$""9+++11\^[[v6lp@~OT:dȐh&YWW?۷A &hK.yzzJrݻwAEEE~~~`{qq1JR2thoo XikktVf,wlvddSf͚uڵ ۷oؿ֭[.\pBARSSO:GR(Bl2V =z4Ͽpرcʾg`VhDDәL&U`y1 2JZ&z޾@FeJJZ+Y#uuuC m:C  F= :XlllDёNcXLfYX&AL&3??3&''nȑh4,;{9s=O}`\nyP.h4tw|AQQѩS=<>P"Vw}@{_}@ 6^II=_8Ua0 X,$t 1Pxvrr4h4 ehXL U*+++l6kmmuqq#tMMMPD"H$\^[[ ^5L&Xfj0f=@ Gvvv6ʕ+U__=4 ݽ{޽{A ׯ_@ |>_x+õ ڵkǏ[ ><55#Kn:PYY d+WO6MV_vҥKOk;L&2Rloo46a„#K!ФFRI$gvtMj H$$H0 )4Urh4ufA*dP]RRC˭2P+ @%6 p8߃F2|Kd={T*Pݸq#jʕ sػw/D԰3fLRR*XMRrZfڵ˖-[lٜ9s ^fͳ$JgΜxbj>OcVXjժ 6(4ٳg'%%1I&uT8ydWWW,c0Ǝ`BBBN>rsrrΟ?ouΝ;Nڇ///WWWNW^^N$_Aїl~wQܹsԏvԩɓ'E\ޤO}R!@h:n5f{ۻ@6Ml@ DѬ"ߞU0س䔔G1̵kעYGCBBRSS322x|pppBB*t FqTJb|||r3& iCP;==}ݺu... jTTTRR{رc x<~ذa[nebbbrrr||h5jTJJJ||SNMNNvrr888UTTS(ǏGYes{nee/bU7d2ǏAU`A7˖-RlΝ;ĴomR@˰lVZ&K;,y@^b,@ *S MR %%% }l߾ŋ!v 111WIZ7|s>(k kk׮yyy٨bbb} :s> |tAh+ynU,77W"L<ٲ?}Z.MMM }M]]pq_I;#H:4iҤgAzdgΜ>|xo= /={= #h42L;;;WV5 HTT@рU.`U x`FR~@h4JR>8Y@^˄Fp2X"p8# r9yZsΐ eڴi={DDDޑ-?feee@ ttt>(7|||<<<?~[ZZh4cQ4`0h4*RN Hvvv`Ȫ\\\j*Κ5 ^ݷL-[,==?NJ DVA!Њ`Ť qMj9ӫh4 B^omm5 Vq\S"V* bj @ Ag|cǺ$=z4PF߾WTB~ҫ~ P(Z[[A, 8RvXy;@ t [ H$ J{˃}v$F#FTTTt:B $sݾ};44R pz.k2?>eʔzT}:C/򊊊jmmJ6mǏ7MfFEAAApppp)hyk2gEwP(D"q@ذ`֟NrDR]]=? R$DGG'''92,,,77׷7$$d۶m 3g8[C/1bġCx*jժS.]O> [n-,,lkk[bŴi,A|cc#ũSp8͛BZ_$`t:R4&h4+ T*HPzuG.ݻ'd1c yɓ'w>&c0O<+A 8Q5?~<0}_@ bݡ @ } X FJ+d0xmëITtGGG[1!khh˛1cF[[liiʚ;t萏ZիU*xT?D"Rb|||[ RYYo߾rGG7xc4 4/8ze5k4779rd߾}6n9$H***j5Jz ;vl}$fC Ϸ5J$GGy |LIF&B!HX,… a ҖU(=&ɻ%:zh4s͝;7---22ҥK2LR9;;{zzT;;;=| \{}XrJhX$\PP Jlv.lnii)**dwGJm۾kwwWnٲL&Ϛ5 AwYF(nٲ#===>>ȑ#<ۛN)??H$D"PH$b񨨨6lXbb"JZzQBR%%%}':tg̘yז SRR>S@p[1"hƍ}YkkkjjFF$""9+++11\^[[v6lpz=p d2~}!2av%AwBh4DR\\LRd<OӕmONN^pKEUUնm>gϞԤ/^oZmm-tHCC 8N.HzwwwRYR\]]Bavv!CL&FJNNd2̙3Ç3H9HbX*w򤪪X,wO}x͜94###&&åx92&&6lH$Z|d*,,={vffZP("חB d2C& ]p}n 1cƠM`0X,ڵ/$?s粳ԇƤ{zz&%%]t> 8p`ݺuÞ>}Bϲ`(--ꫯ"##tcܸqƍAAA^^^ ,x@裏@ʋll%0L^[[+HT^^`0AIq|ewرc.]G3bA@'^$/ŋ!!!].p# lZt*ڟʟ9..ۡsrTϟYGGz>?m4AΝ;SWVV޹s֭[s)++?@AH$L&_hG{n``ǧLB_|{n"h; WWWKR>_]]}%KAZmz3JH$vg2d4+رcvvv&LtrL&c0+WL<( f^B899H$+W[n/o}3g P( bٲeZ\5zh>…cVWW}`JMәL&5L$d2Y]zN'''H$A"N:5~ׯO ~d;H82*,{'ςL&ٳGR܍7V\0gΜ{Hv̘1III`7J hk.[lٲesqvvV(YYMJ3g\x1x[i̊+VZaÆB`57{줤$1iҤ J'Obsrr رc1LHHӧ#""\nNN筮uuu߹sgccԩS啗WPPˉDb?b6N#XMM>Abz"f̘!\\\"## B?h0:X`9j+롅;iUL"x<|]n!(6-7 IblO灹g a0rXipv,y-$f, %''>h45*%%%>>S&'';99YZv***)Ǐm1}<oƍmmm zeޚl6;99}/S>AVDZZZbICCCnnn\\N;qDLL چ@ A :{J\nKԲ<Nwww4`۶m ͛7wYڵk׮]ku[Vk J1[8wsssUU d,Gl-[,X}jA}+k7rҘ|>lkZJondTϖ>7S*zb`l^~ڨ n(**xO>b'ZJ |yyyJ:H/Ɋ% <`0d2\.e }@Vܹ3$$o=pBAe>}gϞ~?FYY!``}~Piiih@\Vh4hTJk4h+4/d2,m ^LPdoomg˖-K,b0Gy{{jGGǽ{z *cX ܸqcȑEEEJrĈmmmT* T@Z DEEٵQ(T2'NxzzjZT|%<<\RYC t ,bqUUUg:GR]]]ap~%x|CC͛ B NNNF{!)))6l~?|vpp &oH7~jkkVQyX,t\0`p8MMM@ ǎ&cҤI'O={ZmJjӧOGEEˋJV%4M*r\FRZq4J333z333o޼I}ݖ٬V/]y<˗ N>P]]b A~'^_WWSRpf͚U[[k4;bG}sN%`9dBW>R>@ x)gAPw|f޼y]Xl/]=СC ,Fna|RrQ$`0/ZZZqqqpr\RD>b(8sAWW׀LPUUZUUp'ˇ >xY@@ 2ǎO^[[gbL&dzwߗoK$ tVbbb`җAkk+HT8@ lR__O"ʴ!C<~bS---, = fDDDL&KmnA֯_6&Nh0)(tRɄϟO$`Mohh(8jDВ%K@ǏWTT{, ~A- y0t?•$ |>~rss#""aF ( :X[g- @ b֭O8188ǒݏ2Xb0NhлtAh***BaBBBvvv~~~TTTvvvtt͛7l'D"ѬYq8eU*@Va0k׮EEEjNP(z=@UAڦ&ZDPJ% @ Th4 p dz`0LFRdxK:HObY?GӍ5j֬YYOeeeUUՋjU[[[zz:NӶݨetX, CD'&&~WqqqUUUeeer_-++3 2ƍT*B|%%%>>>F1''G&ׯߵk𵢢v=a„tL`b3Ο?o @@~b1@`0] 0s :ӂbq8Frj@4448::toߎ:s̙3]]]nܸacjTTT=z4''֭o k֬.^v՝;w.Ydr-00P.\pH$2VXTTrc^~VWWׯ;99u @@d2D" Śf@ӵZ-T<>dxyyh4TẺT*uvv u`… \.~ rNR@@@FFFddTaĉgϞ8qÇz^g1bĦM<{l2i&lXXخ]oߞ'899߿ĉAAAQQQx<,mBd_fNX,V{{{ccL͛7ǎ 뜜<<<.\t,際[[[l+8Nўnwvv6 b>plقzDt<{lUU\.ojjZ|9bh* t ZV[[[sPf޽bM:to߾][[S4ǁ98D"Q͓dW\OOO4?BQrf744DEEفlf+W\~@  ڶmۨQ.1bġCCBB=zE*ݻwCBBt d0;H`0p8h4x>퍦x8% DqӧO7o\TTVtzXj_Ѡ!>)77w֬Y貲ǏO2@ dZ-ˏ9йΖ٬V+++333r_t^x/_ ,8}t[[[@@O?>}RZZj49άYjkkFczX,裏g~wfev#俋%OVJߖjD"qժU<*5RkkH$h4Cuuue2hB!>}4z藷"˿YfM:fرq֭4 ؎d_[[[i4 IldZ6007~ѣGe2JE5FZZZ:::gժU _ג%KBCC###׬Yb >H2, *44ᴶ2Æ ]I.Y#9H---w%ƍrzd2t&d2{ϱc *]Ct3fGBرcvFcRRR\\KZ֭Ç!%%%͟?ͭ_5Ν;ŋ?`e˖-yyy!!! L ٳ< KMM]bHd`v޽zj ~г'N4 \t)H*XG Z-xٻw/ȮKRZnkksttDԩSFs=sƍw9/ `0pP(LJdD'>+n/^ܴiӮ]qƩT AcÇ/\qb)^l[  pB^^^XX~َʒ%K{/ aС/_~%: ҽ{H$R<*w-;;1&&fC:OtttdddXQdh4Oh4 իWC{=pWy#/t`@v]@d@:Heeefܸq$I"Zהdn=z!CB͛7KKKVpZT*m__zu˖-d2w߽{w͚5Bp˖-Gxt:=??ԜO$D"/">>~ذaT*5++kU*URR'|@?iƌqqq wiڵk7nܸcwwwP+VX"@lݾ};44R pz.[^^.Ju:Ϟ=DxM ȑ#G޽HPnݺ5gΜܸ8NDxoܸ1֊~fEt:/vM$mXOҹVpIuuT*.\ptt933SחEFF>|O>AzDA.޿d>}d2uL}[oc2$^_[[;tP&P( 0U_4ݽYHz>]3gfddp4?H#G8p`Æ D˗/7Lg"$nOMMe2{!.\p߾}[nE6l0fˡ/,_[v*& |>(T* >~8LtyyyW^$`HSN?'O޵kW@@ ~~~ׯOLLJ6mp8BT7..nMPp8y۶mK,p8`HDDDTT:ߣ,Knذ\BǏy~׮]0+=A<ط%:d:N zPTJb/N.h4;;;L2{…ZA4 jY,Ç@X`(be2ّ#Glv{{iӸ\.N7 2lĈ^^^z~ʔ);vѠS(J3@`0@|YY\d2a0P77JT*Z ;yD"qvvqtgr P(ܹsNR*qqqYYYWxxH$9zH$;w.ƏY&p@]t[ Ȗ-[r6Lh@7==}ΝojjBD.#A+@-F?EEYЍ?vu..gϞ۷oGDD{xnӧXV>qÇ7j^nΝ;Ǎ͢pףP#֖C׶[sI! H$x<^VdM/\P(D"p9ĭgMx;vtfٷ6EEExt((tÉD"!.Z[[L&E2d <O׻޽2 *##2LMMM{onn;wn@ 3r^|yƌ`;;;|wʕUVߤ{Ā &((ݻQTЃ!B?~!VA 6"ɞ J6ܫѣ={!z3 00000P*8?yhkkCEk@@RSSSrշFmKeoy Gm޼yXBa0~V\F"h"05z-+;w.Q-[f___776pTZmSS۷0F!ǻヒXzyy#Ft`@D"fi+A1Z2d2yϞ=* nܸV\0gΜ{H$1c$%%uT*(7e֮]lٲe˖͙3YP"f͚g5I*Μ9s@4jVA 6=l"lobF+Po eBbꯕo8ġfGGG^,Yd޼yMMM@jYyFEX:TVΕ0#&lÇz}cc7JTWWX 0qČ dee *(W\ , HwLfuuBrmtG0 &*Jv3J&SRR=zd2׮] IMMHLL } חJ"<\p0bĈfddT*}t~C4h@3f|7nԡuf3'I_J:t(Wpp0Fs Q'/=\34v#n8pKvRv!: !VSSsڵI& 4H$T*W^ex@,Yʕ+}EQ)))Ү]iNt>,#P/xk>>'OX,XX,$zڵkfy„ nn&L:2zA$@'@[ntaaaNJJJ{\.?xG۸Vܑd'Nz ,J !E555WTTp863R~ҥKCQ\\ܡVܹS.O8Ν;-*--ݹsgJJʹs,Kllzey>L&6mZQQX,@ In㡙C|||fϞŕBaÆu/^H$cǎʚb3~7|3))W_7oҥKׯ_O/gdd|]C:N@7فr7鬨`0Z78N\~uhs Az^ZzԩS|IZ:tȓɔ BpŊ8 @^UUUAAA8NE{GYYVu?yZQK{ꩧ`@'0 <ڼ 6Ap p8N'!f~p%nEdP' @KV|H4L2d2)$$~MJ+}S ;: R pEvgn8X"Ow7l6|l6;)-rV+t4`V(Yj!$̾uh4޻w~p8z=]|=6Y,@@w hrbpN_B ]_ϣ>  @Ց$IDCCB|رc7C(..:޾xv:ujjjC B &չ… -W^umYVV͛k׮5kĉOrs>= ӧO;viNss? >=AZvh駟6nX]]NO8?~\(fWVVVHHHjjj@@h]f֭[`Op8D"Q5N&sʝ;wB#F`g-;v1bDAAA/ {N ѣj㏷~2::U9sfjj_y$115@2?̙3lƍYYYӦM۸q#}O.^pn=ҥKvlk4 Pvvv``ܹsXVVV4w6:Ad p8muqH"@BrO[444hZmLѣ޽ミLNN>vXAAȑ#BgΜ no[-.ҏ11qdٸ\n׷~Dr_~!4uԿ?>RPP  ;F[l6???T ܗ566:V&z <9EP(BCC=inbXb~fǏǓ"m?~QݻwۛaÆueW^5jVݶmە+W9996/B{(OO{pTWW,w8Nz׶+Ϝ9;AGQév8onn755o%V"jft+WL6ŹHrrg}kz~k3&IRdJOO qqq j+6駟t;w6m4al|ڵk'L0𺴾'p8veXNgj ݡCj4 D"q`pP @j… 1cFFFF3gܶmŋT*՘1cp }pbl6A$IX,D"B111nnGx8\j|WkmޚC'!X\__P(Z~L&GGnǧ CJ҆ JP( Dx{{?~899bH$ ,yf`0AVU$bX,|>XV&n<;?w}7|wϏ1n„ mW+J]u#z/n=.WcV(6MQT]Z[[yǏ_xuΘ1R \.I~z8|D(M&SUUU@@llOחsܚ&oooPX]]g}PhJ%Q/ @];` چ;6443gιsgϞ ccc]& a $fAdp( .kZ]sXX}v\!4dȐbX,C'X,\.f.ΤDžۥ8/Dno/{+)oo p8nܸqXQQ\nAAEQ"?/i4617n܀4F$ ^5MMM555AhZouu鬩ihhhhh~qtEY'tt2|~7O<;]# Kן+QFᅸ8رcBTB3rHŋÆ gm =sFf3ǃ I&=#ׯ_kgسgϞ={bqdddff)S`7=w Ŝ9sإ~MPI՞8qz lvҥKgϞH$EEE|>ˋ/Zh˖-/1gExƍ$I;wnH$4hPm}!!!˖- 6lرcGnm!m۶ŋ+ SN>}_!C,[L(.;k(h@Cll̙3BÇ9sBRLL̽{^TXXh'MS\\۶mqaBKo\|ƍyPDD4ioݺs[JKK7gDv`tcHd||<[CCCM<m>p ꦠYsss}}^f:.//Weee,xyk8z\.$:jhhj?8oϓzdX\ j}$I< 9pVX+9r޽DL&;v>-VՓgzRRT*xpQl0< =t;ڥ$I"L&[]}g6M&SG:ȑ#u,t3|E\YPH$z(ٌks8</A fIβd2{y;xtϼVLi>uC\2A,S9s.i}׷?G8ﺗnЕnh75:rnҞf4mt:KKKl .?`Bx-שv]w3͸>@BpG ,tvT*}_[w=pr:,DdƉy2Z _t8 ^^^6]f|$ɆsE3ТzCw0z_QVVfXI555xYyyZVj5IPЗ`*))咾ݨQ,[,lr(czRtCQE"QMMCա"\;jJZyyy|h#v;~d2 |P!:(  K ifdz c IPx$ H4l0f2\Kl$> nTTvЂP(6lnkhA>p溺Υ}677w]V5,, z"jw'}*:***x$I//^ۢZn}p0@j4 tA CUgh4v}=\.2z`0t`XD"H$뽽ۼl2 R{UUUIVsܛ7o$)LNc2<f1 `6V+3!!!Z!X[[kpoV dH@7`0R袣5Q:ۻ^.=:??ㅅROUTTfryAAA@@@}}}mmfBhl6^ B߿~Z:p@ff&^ AAAO=ԓO> WLcw]paժUO?4::n߻ܼysϞ=ׯ_ojjD)))fiZcbr9p c0f3ǓJWKdqÇW(2d2zyy BL&+..$I"pa6b(LWb@ڵkFO?qtU>ĉ~Bl6BBBRSSFcnn5knݚ{vh!HŕPUQQѕ5L&//bB7D"ݻw#""~wRy]|ӚF3D"Qqq!Cd3I6xsbV'&mkBH.+v544;"d=ݻMMM>>>cǎ9!t>&@o8[oEGG؈#`M]]Rё'H߿=NbA.y\N3((Q&Y,riӦue[.(( Efs #] IPzғ5UUU,K,5<~8?l/77w9}ln3?\.W,WWW4WLffT*uMRbXRQM :.((d2ᔤ* s,]VY,VIIɈ#pz|E(J_q@ bd2UUUjЁ)d .:uc=Θ1㭷j`̙ŋ'NPTcƌ]@p\LTF$e2L&cΏL&kjj2LZd2D6V(tFݻw 7'JfssssMM 3ooL?wX-P Z-A%.R4GjqmooRFf]]])pܸqߟ 6(JPǏ/..NNNv6X,aw  #!\\` bt&L9(uKmhА!C8TMu CMMRv$ш'O6=d7?~P7)j1*d[nN5$`0 3|A: _+zzq(z=wŋh¢' ͔)Sy___OHKKٰakoН;w.58Ů FwEGȥKpۻCSٺn."""??-F1̈>/ ŭ[XRGnm^{~# !R1cz{:in޼QQQW޺ukjjjrrJ2 gΜٶmfЍd0\. 96p8VD"!f;N.[SSCg26YPL&D=*p]$Il NS*t:Y,mlVN?WE?$6njjekZP8FBѣz{g:N (\jOK$6wYEEX,H$2FaX0T*%IW88O盡Vu- 1k3P dGy}<3{ٳgOSSX,̜2e fn#^^^`0D" ˵Z\.7LEYV@RV+EQJ"rhllldX<OWUUyw%"44[,H$bVF|>_jGGz 6ON7Ɵ(|5pq=&z\vtYY\.7<Od2Vb:&6w\˗5_`0\+_۾+\naݮ8 o:հH8 I_r{駟~Nѣ7m;h9w}}=BH*jZ/@n{!ϠD yyy,d2<O(vDg.ZvQ \!nfXnŸ27, uEᾺx`0bcc{4?/pJnǻ KFos:$jL&.HlSccX,sf|CjD"rv;evpp\$=j_}\dsKnR ndYHZĉk?#.OBEr/~::%88?C_K Պg [z{{+qM0LFƧ C&l9ftcԴ)Sp\rV@SSw ZkYYً/ء ܁t+ |vf=%0l2 ߴlqkd2 /A/s\ ]wt +(HEOÇ6lX ɴ&CۅO]O)ZD"h4hiBtKPin566677*1Bl6</c5o<͖ot%gөhRk<[_wحwndՍ8HtIcccYYYA2tІVw x<<[NfsCCCeۿ/<ݹJ{y<ʕ+_|[t:>\B.CzOO 랿=]֡>cZjn0Jd곅qPu(YnL}}}-KO,؃z >9$Ir8~ҥgJ$L>:t(!!fڱcѣgϞ; !n:F~zBW|򐐐e˖]t !|-[,^8::KV\\qF$J%\6ͷf\¾q\@E$Og 3:JE p7ө8xL>Nn㉆\g7r]-^WW1 \Zd2b<.U[[~V%.Kϧt?x111ǎzjRRRff1c&Mq툈P\\\MMw|'""µÇ űcl6xјm۶ _v] N>Mw;۽5% n٨ H$£}Rn3xJ6pB~U(x<$@`r\nX𠚚@ZWT*y>>-xBBBUdp8tᙗ7ޢ\.w sRiH<@ &Pyw|fsH-[<$B{o']1~%L,:WKbu˄.EI](J Ї8N"Uy>jTFA~&G@-,p ߬Y6mSO1+Є0x СCO=HDQTÁ׿>}ٳ=Z#J$I27lا IJ*((}35k֬$G(566JnL&zORT>@1H Zü< F Bzݻw߸qCN3L*6ͫW|8nCQԭ[^xÇw;6;=}(!!o 0 GcN $zK\upP(Of㴱ƍR?>a„{!p8wA$I~b׮]_|EVVs=sϵ:ꫯFEE K2\nbHT]]n3׏rov[|^o}||\⡫uxG&TkV^ G5x:qFcGCQT}}dmm-BH.wtm ֮]{ P#БƼyϟz-PIIɑ#G'%%9qij>`<66ҥKzsE;]///.KWUt:]GZBoO駟g(ΖH$aaaXarrl>wɓ'|;\.7&&ի**yaÆk\.yVD"9s指3-- 6HsNAAvb #22!tNݲ޾VVV7bdggfdd;uOGG͞=~~ժUK.]tqr6ףh֭[7k֬`&yiÁ6F qqq?ԩSJӧ;猊Zz֭[SSSU*`=s̶mڍR:ݗ^zik֬IIIinn޹s\.oUZ !++뫯駟7n|G;ٳggffSXhh7|k׮۷F<;DZ6=tЬ,z$ںu233,Yt:ǎe˖%Kx9y晈={ٳI,GFFfffzRխۍ?駟kAAA_u'Rk=}v=z4,,̓2EEE](􄆆+Vvz~m[6ؿ:RCCC76l6GqqqxnٯZ(&''?0p$V-3۵lvmm{, 333zc3f b NT*ᇹsZV^/z}yyرckkk DW.z`0LjDƌR|0ubb fX,v8F6\nrqssR4L>vX6 \.711bf6}ԩaÆUTTL>dr8&y!裏655t:Db6\.}H^/ RtXccvr, @2EQfd߾}C ӟ駟t~[![ pdZ\ޓ'O?ѣGC7l6L&AEQL&8nZ֞ tUV}&ITVWW_p!>>t>|̛7˫O>INN/t:WppR _NDyyO>nXXhjjR(Aб ]PPPUUUQQ?~Jرc|VVl bfFDDeX:h4xXt:ȑ#9B!|\ǟ?~„ p,:r >wꫯdo ,%%%--$ >d0!qΝ?˖-cX6㹾p 7EQ$IX,7ϱcFGGp8#GtPWWIDѿg̙3AAA$I$f@, r}( Sp,s,:tBwF?wxb޽[>UBBȑ#a>x,nTp,#-ibؓ;H (ZVM&l*Ń q_?qwQVV&,XpBok׮B3~C"n߾矏;!-[ +V@ϝ;>bݎhѢ5M```RRT*/+ $ZhF5d7JKKoݺVCBB4#7x≂]vX;w|8y}̘1)))_5kp/$yڵy۷l6 ¼Pھ}T*OBhĉ=ݻk֬?Ig̷x8eRSS޽;|p00=iT^^>:B :T&v6dVb4iVo~GDT?ڵkaLLaۋ âE\n~~>B(//<A%&&o.!!7X,VBFW\z:={,\0)))>>A#z`~XWWH$L&Sպ6j8B >\*EOp8cƌAb&9o޼wW8qg]`~xm0 1VSN) Jr###Ϝ9CX555ׯ_ /_|u ?~ԨQ8r111W^UT!s(*HgΜ9bt:۝P |'{t҆ rrr-[/WWW?ĉ˗/iii{cccoݺeZqpHUVUWW/]ѣW\9}۷o#i4 &|ǭ2l69rرc bq̷tN$233իW_xqժUs/m߾j[nӦM!!!wߋHK{H|MPPTծe!Z($IU֭9r%Kf͚u-[AO%ƽ{n޼TCII۷|6xV;Я XJJJZZÁꫯ9SNݼy7V?L;@ؿ:HCHHVuVuuB`٭j:NRCf=s =O>nF`0jZ.--m]bD` Wuuu~~~xfds6773sM>ٳӧOg0VUV{yyXǏϘ1t: KR jժUVA쪪|UQQA@ (,,$I?}ƍu: /pY8cƌ}Fm@1 sNWWWG/D" (2*IҦ&B"IRӱT* y'69|>?99/$[ i^|98cpB`$I_z%r{}}}Y$'L&9-twfhCGGGAH $IO+B(;;} n:~xIIo n)v9ǎ~4gwdddx_~ERUVV| ,@ܹS*'O22rǎGȘ0aBڵk+W4ht2$SIIɓ >K.}7-ˆ vڅ\._ޓJ^^^iii/_>|B5jwݎϰX,]&Mھ}K/4ydgH~֭[jzĈ#FhBhRvvvtt\.Ě; ,?>.^?+w}B()) !dZy<+9d-IDeW_!XV> _ܹS&K_|Ņ ϟ_[[h"ݎ;wLIIIJJ*,,ܺuŚǍ9ro!b賦NWWWG/0L^t:炂p8B )44Tղl6][[RF}ER[B-J2111444((!4a„Bx='`t}Ν 7$@oà xb$pB@;uKrO:UWW{VZ7l1e|>?99/^1 A{.^^~e͆E&Lx~^' .$bԩqHHBF ;wׯlC tkҬFajVVV+\/^/^ҥK]Q]L&iY/ Κ5O?ݾ5&h_ #&&o;IJJ7Btڌ^_u %u]tŘlg~^Ck%8'СC|>?##`0dggx-:;+N@ pPEQΝΦ(÷TWWFEgg>f=7Oh*//^ 3[<-a۶mk׮^lَ;:_|ʕ+|M%Kh4PxxD"-sssy<^^^~d2qT\\ /hueeeXFq˖-;|pjj*rJZZZjjjzz:NjP(2224 KNNy^GEFFfdd!mܸ G/iEN'ZoIKx≂]vX;w|1cƤ|k֬O^^ދ/Hk͛o>, """B!BhRO>C&Ns޽Nk֬/2~xZ_>|XP;v, f_k>>ð0j @YL&s„ I&}8T*Ǐ50&&棏>aѢE?C~~~|||^^.^DD^^3))@(N8 )@***2L0BpᴬR-inn&KRiVvP]\\N>]QQAEGG|>СDpO p||>̘1FQ&) H0̏?8i$a:::$^sرC&9sÃNtfR6MMMǏ:uRtqqijj:}IBbijjrwwW*rZ͖~Ckڠ͛7gffvW-[̞=7 <.\0dl6ӉNN:'}||\nXX؏?A7669sK0O>_W``] ŋKJJP(ϝ;RWWg߻o4lb2ZZZO^SSk׮gyft&300PV_rQSSh"sGGnCnihpal6 gߺT[?~<zS4rȮ>H$Qۿ#G^u-Zhɒ%K,IIIt|򉃃}UV BBBb1ʚ7o޼yRRR<==;::賶/7='M&Smm!CBT*UTt(Bń{O* T__?p=񚚚W* URF󋊊ڷo_>}\\\h=+zHTPP0`n{6DB:hZDb6zX,V`0xzzj4hlh;@|#4^ "{/^⒕LWĬ]677wҥ</22rɒ%AAbB9BSAAA_~ennڵkjkhh(FtG}466v y0 qͣ˭VرcE :l6x<0n8ƍBY2{:]Љ`puuU*&ӜarkrdBO .1x/↫Fy^~sQWZ@@C…W8a>YdB7|whj>?w\y$/)O /BV+˗書d@d2R)[ѤvZ}  g_f+e˖8s7)C$$$N#G\rnNC"Jt>^߾}^홼'{ 8|DDD@@}v&Y6Zpss_Tt3gvo}M/[ =1@7pttH$ꚓC c[Cprr.Ew0ҝٻw5kvO5HRSSriiiMMM`````୷*--e&88x߾}Ǐ?|pdd &!=z}lfu^X, @^` .ܸqѣGSRR92sLѸ}pZɓ3gά,// Q(yyy ;~ɓҥKu:]tt޽{Ҳm۶ɓ'Г3f:\.;'' 8h9~Wooﺺe˖m۶h4fddTVV.X<#Rpo߾\.7x̙-oԩS驩4^FF=$ !s}Gq ܘb!l߾]$ X'''ig̘vZ:45jԨkזBbbbƎzꈈny#-Ξ?dCO$SSSW\iˁFۄ!vS[>RrV5--M$Bz=o>BȦM!^wppJ+Wd稽OSOl6ڃd2' 7C;`fOߺT@p84:"tWtd?4z}gF;"mmmDBZD"1z^,j@`0<==5hF!v3 h^w|djr8a8^ooowtt4LfY z4= @Oƞ0aB2W^eg1bLȗ nW_9;;٭, ;B6Qhs@ʕ+gϞbŊo \x1$$Dպ'</11Q&)JP~Y+:4t_UR*JXjZBpsskjj*..NHHJQׯYť`0+ΊM]ZZcǎɓ'766666ٓO>I3Yeeew!CHp'<==nj2Ν;uÇKҧ~fid2y{{~J2<mڴZ_L_|O>4XNNguԩذaƍ{gϞc-_<***!!aΝG~7֭[Gײfdd,X 888..N.*+//~J;@陼٧zNݦG<. @aaÆ9;; BFr BV B___T* !NNN u[[[+++GYYY$iZV4 s[Çg3t4bm޼9&&ŋU'O6mEEEӦM h4\.W.jJ% D"|>_$$$p8.k0L&B"h4JP(R)RST...l¶BۻaÆء{kjҸ{M4Ad } 5k!dVaA)ٴ0vXL̙cZ\s=Gfȑ#O`0qMgf 8p2,66OmI_vm[(fdd~ꫯ TV+++s!Xx~o>}bٳg׎;?#B1uԄ?x̘16lP(NNN~~~555SNݽ{7ہL6.啘XD/=UWP^] &H 8[40h6>)jNbb" #^;KP(gZ !C ={x[3ϱ ~{]lG}T]]sϥN8[^^d:~KOOO_?gΜ^xrʕ5k<#/_h4,Ydذa'oG/^LJJbJ]]]nn.ɏt4RxL2w{qZ1dr!Vaf V >7-k.7d-ccEiHgB4{b &.++#b\^PPm6j:::D"ND77ۍ wHJzz_~_rH$N PRR2}[\EEE rtt$]%''9r3>>h_ʪpĉ;Al^&a[ eܽ{wWH<=rU^wrI$wkaaKdL&`=[,{uql6>(]2h By~FJ^ q8#F/G7\zӓc{yy >ZnhTT3gܱcٳgccc|IdQQ3<΂pv/ ŝ jjj'~}MRNgil48^wMII^چC~&Ohl444<= <SSKI˫?y})_WP^ ̙s_:wn߯OOAK/?wь͖+6w;s3o}<==|СC !L>=%%WsChv{9vرcQFEÆ cW+**nqVI-[PxGqU-'Oĸ^Y2"‰RP( +,_~`Jv{^O<ҥKMϋD":=h˳hFFF.H˾!ٲT*e˝ae駟=1@2]ijӨ©S}r 322h3g$%%њ >ɓUUU4bi%333o=$<ЯN֭L?^N)*#df#VOY2&{J8ƾ¶mEw&oش)9x43Mx썘sXhĈmmmnnnҿ9)rrrj5bwȑ_FD-Zdɒ%KRRRt:'|nj*6a]HHX,:YYY͛7o^JJgGGK/z@Wsp(noV2qw)S|8}Vܹs555-m6!aNϢܺ~so#OLNH]_SX4a l W{{;U(st:99 0j4_vח֗H$n{=T*7AjkkH$:j%lbXV (:::Yyzz*m?uδjuwwǝwa0<==5h1j%Dsٳgi'X, ͚52zhBluΞ=-B{9?11_~4orddF4iRGGGyFlnoo':%4e0\]]JdbJlp8au:Sf76 ϙgk<^ǝ{C׷rD{8qHƅHF<Sx,[nZBСC999o{Ѵ˖-cWd2i^{m̘1&b~V D7VەJL'd2\.0 S*\.7??b/T* $''gBPlݺuذatS͚5K~~~/_:uq:|2ۉt3&~ H[p!rĉ IZhE 6wpZZfZw3GPرC&겲2P0B YW\:t޽{]\\N>]WWK`~_U(4mCYY!D,򂂂hܧO:XGGH$t"gΜy^{  @OFD亙U9bVar4y䶶6777)},___eee П,,,l&l6Օ9;;0@RTl p8.krr7`M2N<):M4n8ٖ !>(]Bge白fZ8x 7 ޗ/_NNN` OHH`FTWW:99q={$&& BBr !--- wlh:u"ubl2ٳT[[k2D"Qyyj=|]]ݮ]BCC-KmmbMMM-++t ѧNJHHXbB3gjubb֭[j5.%=̃еL&޽{c޽bѣG{xx477Xl2l6Z>{lllOeeP(tqqioo4 !j* wa+>>^R'|p) _c6%?ѣGlvpp =;>+8882|a6nh6]]]ׯ_/ɖ,Yl2Я_ǏORm|~LLرcW^CTD"@K%5h b$;eȑ/^Ξ9sfee%:.::b`NۡV̟?ԩS)))՝544xzzo߾=))~QVVĉvЯ_'N$%%uQenA|^r%l߾}III..7<--tWEEENpO B}sJ:u*===55mz駥RÇkkk,XR ryvv *++i." ~wGѵo?GM4iÆ 4: ;@2cƌkYhQvvM&:99F8 ͛7474tmBB[ྡ`Cg򩧞lA}^/ 322(cǎ-^844WDI1l;2'v.RZZTUU1b9 @^~7Щ;E7@ꘜ>XPP  'N Cvyyy@.\hhh@@O$;ֶ 6 R??~< <׿0ɩMpȑ3gm۶MWl=| R4L+ar\(t:@q)tI&=Ho'$$$$$œ\hx޽:gX,67C PxU\M@w+v;y6 Bjl cbb`CDr~@ aÆٶvqơ8{g*** @ÃuTBBŠ+ Ŝ9s߯VnݪVDѣG{xx477XLgRgϞ񩬬 ...t*v???:jU(<tW||JO>dKK -$?N˴`Zccc;`aBH@@3--B'JZpB(BHЛp8tZx<^:ltD>>UUU"HՆ;v=rH$7oOP8qD4,kk'l6ѣf3[ x46`XөSSSSy<^PPٴ\.wߍJJJJe~~_~e/\Ѐ}zV託DI6ؠӠ hѢ쀀Ds|ۧ펉pRZ-66r*33shXgX{5!جVb#oY FwJ{ XVHӧ?SlZy>mw]]]sssRRһKaS۷.֭[GAhpgl6k;gFSmAə3jB#1pF˶ӱ<))Q. @KM}n<{/211ӪSUM7hcڴi삸]vH{-{]$ =`&Ivp?M&lL@ף,-o> e{}tD _Ty¼ R~O<駟.xAv@@%ɌF J7M?+ F1 8[믿 :u t7YH97'-(6 ׯ_NNB#b0\]]JdYw^ooo4vQARr$!!Mhnnvww- R9+<ڷo_RѴGBB™g ]<pfwX,&8::BZP(D^4_KgϞCO,~"8:bl.?hM>!Umڶ'psJuM63^p۶mkH.$Dccnkk7n $i/tTUi[.\SkJ2Fk V2KxabI"[E[ڵ~;{FUq"$[oF@|tY_L}}P,oxؽx o}ν:  Lx)0$鷀{~wwQo z/_|MV:{Z  ޾}q:{] !B_====///888mFڹc'6=>iU_v s1o˿N0a„ ?`/{o# @@|ӧO}}=Կs?\ðWl C^UVr_x6t ǧ6$^{ܹsAAA|h$xbծMy;/ =gt{o߾#F0aB}bUl1!%%%mmmg^fͬY 2jԨ LqG}u֭---Ν;qĕ+W̙e˖6WW^w~쬬,BF9ycNJyf777L6dȐCҁv.]yz{Geze;we&N*ogȑ#k֬齍g4B}Y%ITTO?w577M^ti͑saO>}􎎎SN?~i]\\4?amV[[;) [h~/\x≩|YrWK.!GX$ӛP3&22R"=TB߯o !bO?׾/`0=_mbDACfX  &Nr٤;6l1[:M/mH]X,N3 &D]phpzz[Z#$.hfZ=jU^sr!@"Q*XvM{,Ѧ/R t #{ kMW/[z".+J}K]9q' endstream endobj 651 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///3_main_window_sketch_2.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 658 0 R /BBox [0 0 115.199997 115.199997] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 499 /Filter /FlateDecode >> stream x}S=1 +0v^DqP( BAljU-'o g/߁gހgƇ0d_ R!aW=#L9;(fΙȄ*;%큆%]{9<`R _ }-*9>C MkQno©@+l Hj>11cT|ZjGJp)KԤZ6(܇f9JR&mhH8h PcZ,–aq? j*&2ɺǒ5`YFffNDR|{{.yO5Y!E%ZAYcx?/ni!׻gI\T`k{ZD! kzdjt%z(aJu9_i-H=ipnq9d1rݱ$̓3`t\yez endstream endobj 664 0 obj << /Length 1253 /Filter /FlateDecode >> stream xڥXMs6WHD0>INrH@S"U )/ o. EiL` xI cB&xY. \P,WpS姃,uUU.?{8`/f^$(DϵHفgq^ G;6sQܮ<`DY Eu;=x㜠4b_eV/)s#0bbp&>h|vܯY9۫\(7(Sg8r_jY[^ڇOXm형v4ڗocvhbSt&3;ZM*؇2;lZı*He:;8#yJU'AF#ק|@"yɖ.1f(ŋ_f' _g}pπejC(}icӕUEc^܎POd[:pA' Zv]•rIyxuH:)4g˷C>Tm4szo;َ4G8j(Z5s}N~b.s\70EϾ-dI}3;0¡A,~h>9Ӡay/5+[y#kqH4f(}|lzG*/{re^2KS2E̠Xћ xc-8p+o`fMrgh<#h.%%$I8{e;1@m?Ct0ݤPn<s EG'z uV=Kg|> >>>> /Length 224 /Filter /FlateDecode >> stream xeNC1 > /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 212 /Filter /FlateDecode >> stream xm=NC1{b.- EDPJ~R$j?3pJZ"G8nqR*u<[|缩x+{v.5}Y(0P*;nT+pd)—DF=I{.9?ldMH-1GS)ٰxx94F B!=ԩH9L3(ilS\Sk endstream endobj 681 0 obj << /Length 977 /Filter /FlateDecode >> stream xڝVM6WEn#./K$)nL[j(!n;IYfO73o3"h}n@U*w(/pQhUhEQN0D&>vb'9>v7̴_~^xW/+\ P{2qKJzuAA z.9gpU%z4;Soć5_2J%9+KZ诋p n Jj` cV\\Քڼ&#@E1%Dw[ZKeHH?*G |8V 39@~Lņ2K׵l'(ΨnW5+rr7SA}iuGB.jVKcuƙ`cyW[?Ux6+]]dݴ pqptM``'h^ޟ+.硛/-;4H-o> >>/Font << /f-0-0 685 0 R>> >> /Length 1429 /Filter /FlateDecode >> stream xWn\7+Ds_rpCjrD)qbY[67ygk1;7¸O&ؠ9JlO^҂qQqLDy)?ₑ >ŊEZsXK<yo&<6 6Ge ^Ls+28jn(վd$l%$[{lE~~w5"DZrQ|k%IbzOYDFPl=׭n n[`=6 ˓4Wh'zrf o{k\krAI#Uo4W*A0 : Ys7nwR\j.8n'gېAY<>gz<c Bj]m rk}sȳkǃy=p_:nW?7ExyJ|yJ)> r+ R-JgަҙZ1)K Lu0ϮȅTMH h[X3j:g)l}’/}q ,^3v#0d[aq4pųkL3V|k}Wx8Ԇ,Off[)1ݭطdƄĈKHhO8s%޶V%e)RZWiȒ>X!v91`ꄊW'$VS1 9i\̔w*I%0;Dž(do \F yTl &m%F=«$S˜@43C u}WJ8Xh'MznB|LՎD*IjeE%&.h!ZgxrA5e^[iMʃXhj> jD62AŅj~ի̗oV6-('.'˚GQ;r զM/z*6+xamlgy ^#;j큵&N{1p)3[~ݻp5Q ٪h״m7ՠoe6 6yDfRNx A##nM0{ ^ED^N5N|T/j_m( NJ̭A8Okq 2Ð+v(dUB瓆F 5xJ?!V$4ovEtIyg!,e![)-d*_ {=\~^0;y.T> xOeMB=nx7k` 2БevSU OR?> endstream endobj 687 0 obj << /Length 689 0 R /Filter /FlateDecode >> stream x]n {bMU*d)4.r(N ŀ0.Xm7s<:G&L`7G0b8hͪZe 4cKx"ЏR<[[u״+ h49݋ rEU|ut/]kIy[ t ˜|M1-#}#+'3k2}ֹe,j=> stream xV}XU?wށEďADj$]T G2WVJM̩lJ3CםuM1H>-m[S6*sMۉgyߞ}w|sDATY^g+^D]rIDrF9S˜M_q*DX4erjq(?La9,1}ÔYoFkvL>4'ge*}i'BtU6HN!*O[8Z3uDߓ{&j:9ڏ־T+ՖZS[5+9K3M=HwlaO\旋K19@)b4g`I66ܧ}9dh]+IlW-5.U|oRWll⯝8f^ZLɊK;Ԥ8|y-K":;lR'z ߾V'FF&" @\QA hBA^4cF%l1ِ_"0lr}>^7/9+: z=Q:f.ՉKhy’.K8ѶD[)nʹIdOOj2g$zd6XvkXU~Ki.kU>9j/޼Ū$EG6իw؈)˝8?|wK[kz4nsxG,HwSM=Bi/!\nesƧ_Wx½)NoN"YԮݲƕ!m n^Y.L<2hGsM*|}fOEcpZ%`?[VUܐ|o"/y FVZIVX ,fX."#a # v krm U\V7c(~{,TԞI#"EۭE-`r1E*l܆4[j6LJ*[Dj;ƶm/uT 1"IF3 DBj\ǵigssGjлL~1N< 6M]Em 5N gz#z^W, ˭rC(TMsd5}Etl8Xb:-jq9"i,o.m^KMq+EBn,?¶m qގ$dʖy߲*-ݜ^B*V:S 4}>eeTǶ7Θ*|5!\Lz^VܭcD&1 ˰# Iќl\˨#v.ʄR^S'7gsX]F TŹ&;~MR&hQހglhIjf"1|gC{b* HGJ;c3 ;>eØWXl! 9 HF8W2&ʤPP;S-upz֨LZs*UQz286:Z!;:ŋx㵑ΰPx/PW53( w=Nޠ-.|UD[ sR _*Vʇ/}h \g q\<9VV8k~I$EKRhz?Q6)UxG >8,O(OnS8&;V<)TxS  Px] )WxՆ}]rBAaRw?.{J=_qa|إ[ovz(;^#P9藃ئVcEa Qr/Dy/9MFM Fb3 rl03 `<*TYuQXǃXf\Tُ5\u1V+> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 497 /Filter /FlateDecode >> stream x}S=1 +0q^DqP( BADZU-DOG׿!i?9,;D3o@a.DḆ6bE̥8&Ή̄׍; T@ǚ.FcݽTi>NcXá4C1x ?ލ EΜ;%+)A*_5},|60fZJ$Ս28!wMv\UR>\ :6R(liPS4J6u^aRe\ UwR\x9IhXn|=;=+7I9:@eb!3w{#0/e'~rJn'u(\/@x{#XnC;|! endstream endobj 677 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/edit_commit.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 692 0 R /BBox [0 0 24 24] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 508 /Filter /FlateDecode >> stream xj\1 ~ @U ]E2Y]#YI0\fsm +^k |Os,_wyg(^4m Lc Ҵ2rbȘ]#2YfRzwyZY \m`]ԽOڲ1a-6WjF;Ox,z Eքqkz`n ԐtE"Vx#6`iH. ]dÚ˨byyڼc؇=U^*wRWQO E-ҞԢ62-ta;uFf^ej힦N>qLI~kݩ+Oj;6Md8ȴЅԄ1yδM>Qf5x%x+'^B.Λ!s?JVљbZ #6XMê.O+LEѤMO!7Hѫ c"e2EEtl1ǡLØANz[QAdnI=/粪"GNkOS!B endstream endobj 698 0 obj << /Length 998 /Filter /FlateDecode >> stream xڝV]s&}ўONvq} 8i}Xc'[?s.eaDY8z g!& HrsLyYIbz]]1ts,NG-ܡr[0"~~/w,qmc8+JB1 R~)szЫζҿj3P`5{hOU+pkN;Nm %m/ ;|^ƻб QB0 VA.5J;dhpgi+p9Qm-c 2]k~J?eu(Xӊ Ljcc ovjXjfMWڧ4'Q.ǖ,UeقZFFyʪO<=Neá;&uhmF _) |U!B*9K5G ]2 Р'?92'5|r{5NW:+Lapr9{{G/sJ> >>>> /Length 496 /Filter /FlateDecode >> stream x}S=1 +0v^DqP( BAljU-'o g/߁gހgƇ0d_ R!aW=#L9;(fΙȄ*;%큆%]{9<`R _ }-*9>C MkQno:6Du|(Ybƨ bi} Ԏx*SIlTQ< dsZLѐk045TY&Xj-5~;M%Kdf '^QJ VE}&~3|fW3GhIpv:cg-7Yfp!\咽r ßWؗXqE%|*FzڱL[> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 326 /Filter /FlateDecode >> stream xuMN1 9/0&eĢl 4H]\;΄BG͗=?g&k rѝGĉcbA=ܼx:w[| ==ˊWNbxdi}p+aIcg4h֚j`M8l׍ŮVӶ Zږe+v*8a j Ć)k4+T{6> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 193 /Filter /FlateDecode >> stream x]=jCA {b.`Y?o6M i.~֤ fi kXt#H\ @9 endstream endobj 695 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/message_error.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 705 0 R /BBox [0 0 24 24] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 271 /Filter /FlateDecode >> stream xQN0 +yعrAZrEP!ˁi\hxD(b 64% fl 'tq"> stream xڭwF+xsvnzo&o9MrlPʬ ЀTрqOw2xz DR@i* 10r>se෻_ _Gt)i^Q养,&cӤ'bup5 kj^s(*j|;|؃c[8_h=c( 2yZ={9/+-$ u%c|vxdηۋUTz`„e nYbα5F3Q;%A2 bJ~RP:CH^ P4i)"bܘ*Qp#IhR@f5AjǏ*9s ӁT8~H#@d[c3+QsOMN=Axʠ1"ftG#Hba)"/&؀4\3IfiY`v0B RjpЪkԃ !0aKs@g\vC:ǭ ,Z[;uC Cac:>ډ!5㘁ee!?~e,ל7-SPm.CM(ևmZuf>*J۪OaQ|e'gD߹u(ȖS%"ݖ?I?OaC,s~m`}?4(;?4Є$72z}M6sSNU.&=h{}͝ûeWesۀ2oԖYY4NM9:SaDm~ga?Cq }?ǖ}J▲O=e)!V'5U .a Ǭ."K"Gw%q A0-vu\a +?vsu n9UjL]4@B1,1\6fhucD(B Wp 7_8+B%woNL}UbJ\ܬO*1ݟ6s4,FBp9HpH eI*R})$d% =H^T=HR MwɃ֭#|.aS@JP팏{jr6iQg!CDsX 2ae"%-KE{ڕ$DgUaJ3C4#BWV/TiJ#+MCҰP!>9[a0"NȈ ٺ4͎~X4݅6s4,FBR:(p( eENi^ލDQ0DEAAC&j#qrPE:̎'q $p$PE034jG2@"Ɛrɦ=ߴ"V/1CJrw'Gr Kqld:paq4Ah8DŽǑQđJ +Va? ~I_ѫ{X0)=Wۋ฼ra4]hs9Gq Z;rFPH)KrIJ/&.L̓}H2B1[c4;%\pϕ\ejޠc}RtXdG۬#$YQ>"?DzAZxqPgІ~zyA =I#`_ĬhاpH{W;0H 8dn. IqE Hc{]QvU#qr>j KIlOd:HH B8,1 iؒ_M\=/0j4k; 'Dq1q=5#M;.vmngHXlAY_V + B;C1;"+dhznj endstream endobj 706 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_block.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 738 0 R /BBox [0 0 24 18] /Group 737 0 R /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 136 /Filter /FlateDecode >> stream xm1 A E_dgƙF,VKbh#|"BZqyH©U~Y0> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 288 /Filter /FlateDecode >> stream xN0{?żwni(JD\qG볎t@Q|Y{v=\-<Ū>Tl?qX>Ǎvy<[l_MRr؃#Ŵ N1LjeBli3IvY(G]u8Ph2hBa %Iѭl·΀dg>'=vkimZ}ٺArў8NsȚ76=M*JP_pgY9״|,MOsin1nݹmB*jQP)I؏ endstream endobj 708 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_node.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 740 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 176 /Filter /FlateDecode >> stream xm A }yci)"Y v g!.Rq!0V96?+,3q)W`}oa39$l0@&G) IdJ:ﴬgkܑ\7D)J &jMP^eٛF\#<1܅7 > /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 112 /Filter /FlateDecode >> stream xe1 @D@Vw@ؤ 1!H^O,e3CB3bڴP*TM 7W[4c4iLAIj)k׈'TfV endstream endobj 710 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_component.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 742 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 261 /Filter /FlateDecode >> stream xuPJ1 +Iv/OAVQ=<= {lL߅!uKd97W|d|&!тĸ-? 78BvqiRFYKWwxsn'JJ,0BB ' 9e+j@1uNpg0ؼ ~Z'ds-(mLj?R5Ys=L!7?@ɬwúhn\0-Jrj*]#H8yH߆mE endstream endobj 711 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_part.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 743 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 298 /Filter /FlateDecode >> stream xmAND1= '01q14.,F^_hu5G`~W^԰K8 \?#7 ? 6YMN@KvƠ3v sů7xC%)vVK 2!H 1,Hm' N'$(gcxKRiU&I]C0(T&T͂w$Q-I^0NzF&CtDFHbKA j..S$6-i2,cgV:RAK}#o(d]Q|GUZҋn?WݡƱt endstream endobj 712 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_class.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 744 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 163 /Filter /FlateDecode >> stream xmM 1 F9wcNN .FBFY oq܌|̓ R FzpWe`}^.M՝'\hNiY:*SW5<87S-#Tꬄ 3ӏ"f+e*~6sh: endstream endobj 713 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_package.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 745 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 191 /Filter /FlateDecode >> stream x} 0l~ C( zz( a7 ˳RfLbMh-~~5"^b*0Ak ƫC4L>8 #H.P4{o#I9'% T|r CK$$MB9[k H-bc uN޺H endstream endobj 714 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_artifact.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 746 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 191 /Filter /FlateDecode >> stream xmM 1 9Żϴ= ] ".ԅ738uҐ&= Fw2s2.clWX .O"+28wȧ7jӆCcahF8ŀ;fMN87T(mHpcDSGyJ=dJ4L+PfkcNjWH6P&Io"`[b endstream endobj 625 0 obj << /Type /ObjStm /N 100 /First 869 /Length 2003 /Filter /FlateDecode >> stream xYmo6_o ;ֈ^4`gKV{H}zxsc"r^936B m@kFAѡMBs0 $|@HD>E+)R"$ΊЦ(" "D#HcmO@09`ykT3 @d[  Z 1E\F"13$"L̒gAarFg c mZHUF0=V 烅N0(aU0Yy=#c$ZPSЗ˾cxh9  O! +. t1̰K'Aa/`CN`IKVb!%Y6؇ /ʾ 1, ts {dZ5}'HJ|f_e>뫫f:]ӧEytjdV;ːƶRi7|~xq<06*=A(eEQ%% >\u[aG4N>\բkn(!h~ןPޖ/Wʝ|]OƐf'{Q=TǢ|ѝt';|( 詸QJfaZ{M$t$CN"z!MAkn$C1"=)鐰$H:CƓעs"lbR!X󋋷Bv^z땗Qm F"5^GK}kCQ"-adaNO6 yu?#Y'2R0֑ ÓLʌAM1y0[D(gܪ8SI(\ h/779Us!8V=c//~Hp~L[B^sI6t5s:];mVra2W'T:<1nU a/w+|;Aߕ=˥mriJu@K.Pl#_{x&\b~7(p&-kWѺQi$q*C}'S puH2Tv8k=W;Kpq.s_'+;`7# 2!=$DsGAɤJMw1a""3E d_~5ʟ໣g1"ECuqzaI=Vr~N|)Ӵ{Y8pc(, o}Vtz6XoXZcuYo /4v/Yq|E!؀[kpj.^{vQ U{)=R/:ϵq0Yun·<_DT e2KEq)Ι\ k԰!CEu:kyCѻQ$Ǎu?ܔK&nאsj&~OC ;+ m+H6~pY3k)_Ǎ5H(\t:>n$@VՋEՓVwMZUD)9m8o}fz &l,u+|YqawQkva;cݯ2 K endstream endobj 715 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_comment.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 747 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 188 /Filter /FlateDecode >> stream xmAj0 E:ſ@Uɖ,2]. B^$pSRH}U gq}59~HEo1% +I&8O-cna쑩q+SuYCbɊ>ba/6(iCv- zwGͱAtXSF'Ϫm_/i_QO4 endstream endobj 751 0 obj << /Length 2176 /Filter /FlateDecode >> stream x]Wpٓ[w?M=J^`tlxFiB|)_u#^9wWeA"Iepwd".uU_>[*fW$O4*+h='!E! t')J8nnF1W/"0D~;ۛ#@(}| Z @[- %XF@1De("BDtS%kp#&iBD&݋A CW8- b, `e;E?CMϋJT: "!qqǼUzFʔpH4-#@ϋΘsnKTO`F$"pIHC_f1J(6a&'}cٔ 괰N/Ԋp2p1#_?ܾ>/ 8/߶VtR Q2$nO1o&9>j-߽m|:_jaNƇ2zHpO*#>z8\шR ıcD:lĖÈB!igIUÃRQ8JM1;P$a&25sn\6S'j4'Ej/ O阖OΩ 4ah%=@G*#';ky:9gU'ts'u!9kx"NkcY}XtepOsѮkzMK楾kYzMϾ* /(bRa͝8Qw!Lq~>>&9ڞe y|HN1Kbȭ*D:w/<G+}` |:!kWee4}@sME֦H'(4Yq=d(0_Qr =$FqD'7y(#kj_)_h*텃6wx&z~,O/ ͘|jyI>BOګ@S4ktmDVKPCbԶK4m}R-+ h֝mKuطgH[cܛifzpxj=&\Cg62jaoˬ]E]0wv=d/{ٗt_YЬ.Se*ʬL)Re[l0œ jlN/ frŻ$='I"^pŇXh2Ar:Bqi=c Soz.ȩϪW a S@Wɡ`;%ɵMm^,汰vCdZ+߁`jѲCbK4, }R!,$Y>t50 [ (6ˉ7EXMB&wUB .Q`AxZ  \.AEbxHpFBTF@%ci $ EѬ_1"ϪA>}Y?qw(^@T2BCFQɸF 9 'WKF>.`!1N =RqJdMH!6LdTx-a2R*Mf[ڃआO49J4T_4'Wr"tsrz;pR뚘dzIFB\=0qj \Hl2W&+݁B )CPqH~'](ߟ]E9^h|&ozS%3j V"=1;G8@Lo ``zóoi_ռ TYO3zrWvvPk3=vWfTyOYnUâɩ_GݞMKj: sDIä #Y3!0RO $P_״*nLB:MaW&ξgO3ՙH *b|D!1:.ѰO*it;(X/a8 endstream endobj 716 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_requirement.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 755 0 R /BBox [0 0 24 18] /Group 753 0 R /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 106 /Filter /FlateDecode >> stream xe1@PD=\|H$ D"Qp}JK v:H8-$-"eu7 *F`/L)jWѤU8sAz:q2 endstream endobj 717 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_actor.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 756 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 240 /Filter /FlateDecode >> stream xuAj0 E:ſ@UɲcB.KŅ,YU23 !&XOR?#H8"VqO5$_z[/x ڵRjqL#F^$@M*'KR *\XdQa۠"5ʶ۠^i1#6\䪼n%sKwvv.)֣| onjz]('iɗ\KYSlZP9f1a;?,o endstream endobj 718 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_usecase.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 757 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 162 /Filter /FlateDecode >> stream xe 1 Dcmգx ef/tzVZEH 7Xי$ֹT.}6N8"CU=gqeq*б~16hŨg|O`b5i 4B': endstream endobj 719 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_diagram.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 758 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 153 /Filter /FlateDecode >> stream xe= A ]NffO X(j6> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 186 /Filter /FlateDecode >> stream xeA 1 E9ſ1iksAp1RAq!.uQJC_󣐺Zf;=H8Xح< .OR.EM7:/x@'[8FEdI!XX%6>#qoqRե!ت|U9U}юs=x#V-̉㧵8x> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 184 /Filter /FlateDecode >> stream xeA Es. E;0Ӆ1 elX g-]7fG/;l7C{O:#8٨"u8`7Vӻ/JFCݐ3 v#zʡ]7 Gl -hAdܹXsb5Q)k>L &[<~zD}{F endstream endobj 722 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_fork.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 761 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 223 /Filter /FlateDecode >> stream x};n1 D{b.}O` @ 'e"@`v _߳qe! )>Р<`tL*ytbLx1e7~/OWx6Y"͘Vq@k+hbhuz@{v h5k̒DK2JY@mILnw#o!|RQZfꔘ]+~t.a2 endstream endobj 723 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_join.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 762 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 224 /Filter /FlateDecode >> stream x}KN1 9\cHH, Ke&쪿|(1x;cR1./=n_d*-;Dt>y~+=E*pM;+ h=p@6)҆o> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 130 /Filter /FlateDecode >> stream xe; a b.`L$9 Xb! 7>PA<§hq-,f 8_IY;Ǎ:Hpݾ'21AؗT)#QCe$ Y5z[z' endstream endobj 725 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_time.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 764 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 164 /Filter /FlateDecode >> stream xeM 1 9Ż1mO .FBFPY .NGA) {QЌ~C -I"^$}l)U;O9Ƃ3 g Mn]s)69XabeiU_eP뙿4[g#: :C endstream endobj 726 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_send.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 765 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 131 /Filter /FlateDecode >> stream xeNK PR\ t+AB23 16bJjUc?9*3L,dſw$8і/zhY$t:I ZVdEo>ΈUأBa% endstream endobj 727 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_decision.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 766 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 128 /Filter /FlateDecode >> stream xe1 BA Db.`dw,b! 7*X(!C<¢ aqYLso: ˃|*!!*} 'Xc؏fɈ E]nxf؛^{QFyW$ endstream endobj 769 0 obj << /Length 1967 /Filter /FlateDecode >> stream x[4SDJ[qx"X@3 $!ff"5II2η8tss,S5,P$ n!XFp Ip ~Y˧%xԫl\Qb%yi/Z@dZ+Q]#E)\ŵ90zu{68 B&uvo8xM,#$7W?\a;$H*p 1X0h ך]C),D"e("*DtJ9f5Dq$ B""]N n:CT1X!t283C!(´i:IٍT,2(ZFq^8nĘ!=`u}z$ii`6SCQ"D\tFG` LJDȴ$t攽~p&^s+'j*M)JM):-6Iz?# =A/Cڥߘ(ůX"h/yA'`RA1`fz|]K*Rs '1/1_&Մ4KLaSgP{[οIlb@ۇI+s ۴|4NQ\t[YԧrRdUK==Y>}_`UKz7WvEY_7SZk,,X|m 4rԼ0m{ݶKE~mmS?qVq5Y~HsݒA&D'ȲxԤ)T!mQY#1T$/*p9tRRSdpq u6OM5և<ȷQ0X$k :1dI$_3q$CќHp<|-a$ amMNs?  Gdyv@8<ϠB¿ȭJ97#[XLkC@ wk8->1?g,F81iIN_83qN3 (:PWrhMb-aNsPa 94e<:6sPV.X@ڼ60_ K$[G]ayC$L$"ہ4ZϏ X6fzzf8O*=]cvmVXn6׎nP+({<Ⱦ1y^V4N㦌ܼ-nF%YXV+MRV[ AxQqWL|:PZgQhyHLB -L@0ĥOЏ}Ns#j3cK(usoj+0|ɹ=&&r9Kbpva,:1)rB9Ϯ=e6 4F1q#"B/ϹwDmawG2Ivwz FF}J%^gG~%\4ȑy+xz:;%ظĔzHL%}2nDHAF_Y2#xP@B~ZB1Wxyqz.ƜD#eitv+߇)Z^ڏ;mCsw`\gۀg7ajƋm\UӤ?ە.)#Wk;\dUڲ}ρB?_}Y&*M.wlt\NKq)tK4 e8؈mDK73\Kul8 Uْ1?blDr^o7GB9BpGBŽ-zۏRlk\1ic<#@ !E~v 41 w D 67qGm@\;iWc-(l G;9B{D;X']  ^hWPVx 9 `) endstream endobj 728 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_initial.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 772 0 R /BBox [0 0 24 18] /Group 771 0 R /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 188 /Filter /FlateDecode >> stream x}OjCA :w^ 5d)  X(–eɧzOZ +HrL-.؝(p|+ >p oAXjpk 1z̀:ּ{T?Y mFKCixV6MHm9cie_^giO?o> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 278 /Filter /FlateDecode >> stream x}1K0 c&m(rpÝߗ:H$XwMvi–!#p=?#)kwiW{{dzg3z c9t&,b4٢&gNRT񎜤>q,;V5ŬU%-Q4Zѕ,Qƣ #J~/jgdC4-+;th}(8IWE1ᵶuբk܁%Uu"ypLF+(O[Xi::{lȀ(&J C)xa endstream endobj 730 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_history.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 774 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 775 0 R>> >> /Length 228 /Filter /FlateDecode >> stream x}P=KA +Q7Mr*"8TMB7gGA!= Y4vt!a]*D'K'3._NSla()R3 ܬ6>Ʀ4X[ >QcN5y'r͈HbR,-R0SӌKb/IWlk󈻕\dPm^z&jXϴ9, <ޮ'_iK?H endstream endobj 777 0 obj << /Length 779 0 R /Filter /FlateDecode >> stream x]=n {N1XR@M"?`HƸRyKS ?83@q+[@tlޫ$! > stream xU}tT~3a&lI|,DŠMPF@b$)h ""E"H"Ԩ(J ZJ'N=O{wwws{3$EU׿C3l"cj͍"#DNƓkg]f\sȑū6͜=_f5:9*ژg{:k+O:9ҀYu'/`4jf\]W=1QƑ93o^!J~#juU8['崓lO$u!i {zOϞA@47[+\d8c8ΰNnJT#ie.骏H''z?yϠX>S>KTy={\bZ*&Ѥ}թv%fۉNFYw4&&?kz%ZƋH~dP4)oU Z'.U7S/;Mp"!ֈם/rrw6Q+Z?ZO&r?ָIL槳e\"&X'7". 1< ^$ Td:vC(JY'G-Inadl%nF.ɅTie&&X%xG #!DH]窗Mݢ-7MK@Q)#tD0f 9i7*\0j.rm_۬'Z,Qj~anGЙ+kc#c"OSDW t*S,WGrBugQ+rc{Fx_ݸXh$h,rDKfY.3)HJ̪ 6v=t!LUqbU\xG 5żٴlȦfyrM2J0}hUJ|b O;JTqؤHܢ3B-ފJDZd4o +*#1e܎*c%<Y?欨-*ϸHͬRҼҥEc\Ѻk\$ٟf<:f_Wlk'O*:M=:xN0Z뾰~;ND*||,S#G9V/'MQ  r@&<F?oYsP0YflXfiakBg˾LeD9D=OOxy9oYuޟnLSXg1`Ⱥd|Y XXgi +lXZjtpRFؒb  qBuBBǏUpl,8kajKi|Rj?qąM|"]}?8~?h^w&ű_V޻QwxgwTctWoǞ7՞LlwVW|ڕ^ +0J6^]m%]Ԯ6jޝQ9 135~ ;vJUTϕb۳j[1mg3Smu6 {FU4>ʃ?Ϋ0΋ M Ʀ Ƙ(;߫|8ߋFGy&FQFTLcHH/F qjq٩8kX:+aCjXuȡ.F9ح1$&d$adgTvYTBV++drр F9Z4֥E#5〆?ׯ|uHFac]dZr:WLHpj8K94 *& (CQ"@e;eו@T endstream endobj 731 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_clas_deephistory.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 781 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 782 0 R>> >> /Length 230 /Filter /FlateDecode >> stream x}PJDA TaI&H+"XN,denZfR0yMBl4W:ǐ{y]p"eo2> stream x]n t&]ZSֈYFR~D&hAZ2_و"&NY)DL69(W_B]}T;ňZY P<q endstream endobj 785 0 obj << /Length 787 0 R /Filter /FlateDecode /Length1 3996 >> stream xV{xT?s3f&! a4j"EA$ڀ YES#B1%RMh"""b$A5*3X㊓`h?ufΙ3gΝ;$A TT־s &U7/ ~vhxju휚Z`W_DDbٕa Adg{:. xܚ<-q;c7TU ƻ{k*.1a?1>VnjGkN" m"{RwJޞ8_/ˬtzRNMvɣmy $RU/P#jF͎-N龂4d䱑CxGyl'Uu=rq<7S4.T~(4s_qfF#KCz]1h49QP5QNm>1.[g$b y}vϗX/\e9y J*KOR1O--z(oolҸUM[LT.p4&qN^fܴŕR,?/ف@Q`su Q8]EEX#r]wȵKt};=~wj1LTw Gz2bf#f1X?-21 /hȽ :i Q]G"]*4 \QM66IVjeYhk\BDiA͢XdQ,Ɖ$1覝Vcx^^V/S/2LGCDhQ`4!>q>+5 ˨9CtHJ+T'.:Ho3O4ODwT/#qf CLYm>q8)5Vdp6A{]ÐYΈX^QUlKx>ckNx]<1Xb4"qDDϒ)lky$7|Y FGP**H(v b[,5bm+HDՏG EI08Q iE4`Y\pP6s X0(K9#ak{<56Nجu)KJ ֊ PGCk*W*Ʃԩ:&k|qLs}uXρS:W&5>2C iYOh4~o@u0{73n wL_z-?zy3Ff `7Lcx~z= WeXݱxկe?^ۡ^5SzT]3{xQwa׫vkJ ;5v<_vx~Kz۟KV \O=cSux͉gyg55XV7Ok%IhMS)-ܴ[RuƓ&'46j<ֻcXr5K#nXyX{X55Ѹ[c]wTwj4i^ۚS$,u'uj,1c5nyE捸ia,017jސnŏLԘu4~1ʩ`FufjF؁pHVr*'f9PY*P!|":pL7OиzzZc:)QnW1_}ҏ+$+LLaŔ$MNRe&&OI(-xTݪ؇n\fb¥~5!1ĸKjqؠX96 iVc<ƨ.5*#]("B?.Ը HV1b_Hƈrå1^+pa~ 'oTC5F q8<A[0`sqN"NGvt ?١Aa @dd ӑ҂Hĩ$RTē&`F <[xCOU8xvHzb˄1K ֈҰkؔC4*$ )CRrAFQ!i3 endstream endobj 732 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_undef.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 788 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 116 /Filter /FlateDecode >> stream xu; @ Db.&~p= XX nXx}î؈L0o,qW _Hfvj,pi4X)G AS8dޔ{`@GLȼSn% endstream endobj 801 0 obj << /Length 2252 /Filter /FlateDecode >> stream xڵZ[8~_]uAmv2J*\S[yf$膱͵a_ 񝣣}`pwPE(Tx; $"=lϫx.x٭ ^ʼn6~yr:Ȭ4=Sx O0$s2x.Wz9{2%ao yQ}-'Q&|}nA"^Xkq0Gأ E!"ʍfn1 }?@fd>er;4&ficp 6:dӏyVr6s.ζ͛t_S@ A2/c~Pޖ/|c"އ@@AK`6 "`gІ 2 C Jȑ&QG(ݱ (T>7@k@'b[O-: 6t@mS" f_ȏV޿;eSrGjDd (OqD8bpF^Qs uJ"ZA$Dd qZSVkW˟`_omSxjNթe,ҧZUhi h92}2R˅&[7P{E(ɭ&&ҴJ|r0z\pᵜ;M%\p-@aBy8ERc[IvCQ:2c\bYYxۧ>v>9U|8X$lw"y=hv!Fmz#g%>DzݾDdaFfQ/4JdrLbL3igoOidN^ (&;f@2U8`^<ꓯi>έu`BfAKD Mc&7z hk揭 yuVƃ61 9_ @Dn>v@[?*B(¹ƬmS;iY \xaz=p};r!?鿄嚬Zť,>ӎQP+%L0+liJh,^-=W,#3lpLMsWKd+RJ{rT{Ijh8@6ځ+G0JtgڳKO?AVqӀ3F>ߴu4Pr GYDjg]_ 1nX,˼(fՕr (cvh}ƫ7Z}nz)WU<]Odve1T ؟Gw\;Z_JȷDyn=>_e7]|Ӕa jahz0R&ۿ% Gq40 g@82}( L)CMj7)P$*o(\C!(=og86K[:Q 0s8: 1L5KGt$ RhA ~HzhzF)!SZLpQP1HE\Ita$M;pK9 +xG@ t阮4Tˡh`7ciJ/)i'hM~0 ."/F$?r{[-WG)bLeG7 is,Ϻի|w _݃B5nu4mhϽVڟr/Yfˉ֟=ʧxs~Sg7bzh6@~!FTNGBo?kH,"y8rn endstream endobj 789 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_feat_property.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 804 0 R /BBox [0 0 24 18] /Group 803 0 R /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 160 /Filter /FlateDecode >> stream xm @ D$m_ G *C7Z/efEV"z`Mo>3o7 1t> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 238 /Filter /FlateDecode >> stream xmMnC! >\ pJHhժJi~Cgl zb Pt!k$'3-4)\E4;\͵Gdga ?=GqEpsZStTL u!W5,aSe qah%v3 줋o}VbRPƤ 3ŻAP:ƭOO.~BYo]Bv}{Kk endstream endobj 791 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_feat_provide.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 806 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 223 /Filter /FlateDecode >> stream xeP1N1 N$$Q!!3mVQFN23a\wNyH_$Çpo;ӋV]M mꯟxI]#ѵE@jDشs/8YM- ʛj;[sT1h$[n|J%WX]9B萙=x53d1}abu3:ǟM|?@L endstream endobj 792 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_feat_require.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 807 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 175 /Filter /FlateDecode >> stream xe 0yyl~ C( zN2da% ˳Qf o3+d ֏۫KSŞi,n&:SN<*V(?wЛ?E xi q_su2H$u(9F4f\22q 6 ;6X; endstream endobj 793 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_feat_port.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 808 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 139 /Filter /FlateDecode >> stream xm @DݻE Q E~Ia[̾uq oŴjf>, \,R>[A#HS"Mg2t~^GY]-ZrDМ2ٿ/- endstream endobj 827 0 obj << /Length 2110 /Filter /FlateDecode >> stream x՛M6)XĊ%g'ifU 6̷Hۼf̀ս?Iޓ<ܽPȗTzHS>|*=lϫ0{ɋ`y\ ¨ ڦq%EPiG= z=)DCsPOS;eGN@E&pwmُFײ#$\Owaۭ$Hj)T_j-j5>ӀB\I1vL֨F(S!,! *)DT3Ęn놙PF/00dD7]7075}6 qMB$R-1c٠W!T;& 3 ̺bZ Y+ap|.}~i)R zd5ަ/4T[(5e E(zEEÏiV'wZb$fi?U%;N$Lml&`םK_g306yW>$˿D,7Sy oO$IjGq̣ ٔmnE[u$"ml- ue/"}[Fe `h8Œb8E,)X͘j7cPH¼Rb d&2RzLY3bf g083נ`!@3,1 5hFt4BCrI@poI4A( ^!3}!)aEL!4a$d1 Hqtg\AFh~!Ȍ 1] 0zAXREnLC2F^3[\ fz#F˩Y3"f b0 ߋθF H`B̰0bfhԈѕ~pIߟD 9LbĨn4Tõ,[1I } 5Xp7,pLpE^X`" rIeAXYQdqjh?`ͭEE}\7Yo ز84ٽIRWv6idߢt Ajڊi%JچGsӼяØ̥ AO/oĩ50ި4+mzց a>d&-ySB\덤/?oK9x^Rl$Ҍ{]4jg6t}7L2JnUX= ((%ڥS^,ҳ.2 !Xʊ5ƶXE)y80(S)['|M΃I{R¯J&Vކ1M[g0`5U0K=&ϓxɑ!}xOn8<2YCʂRSTUt'~0>z9D3K0VT02 e(?F&fL"& LSX<խˬ1*ʱ¾N,à.ΐ5=s-ɹLh[ bہw ,i&+9Vs5r*"k/Ez"EYow){ݲnrfisQ99nw3+b޼ GĿiww7 C{w6:r2JByG;={ K!/P1 A:'7ݒ34\NNsXa8#orh)LьtjwcC;Pʡ=)8iǻKKF0VL"Թ6]jK/o>l ?Zά˅ߛ]CEVSCy{jZ)(zq6OaA`L Atpӕx0Ѥɜpxq> >>>> /Length 211 /Filter /FlateDecode >> stream xmjA }y(?m@ 2N0\)=_Y 4ȠXIeMsǺy{b˥8' Oz+Mx6S/JdSU(1olIQx-*d(g˭+_HLE|rG!hbQGޱϼE9^5heZ]zMoU endstream endobj 795 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_feat_tx.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 831 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 207 /Filter /FlateDecode >> stream xmOJA )^C(JAwIaq d/SOKw(G/y}!RL/Z)wB4%?|kq9l)n>ۏw(5h ~_1ׅ/4 L;4M )6c"oHHTrGgyf$xyF8lx-Z/j=GZ~S[ endstream endobj 796 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_feat_entry.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 832 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 192 /Filter /FlateDecode >> stream xmPA 0+l6Ջ xŃD=Hdawf0Ԋ#4V6xmaE{ʒ"βq%=5xrJP+:hj_^ZՈaPy:0eeGJMa15l˔J3˾P\0EH|[\3I*gͣFoZz;Mn endstream endobj 797 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_feat_exit.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 833 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 252 /Filter /FlateDecode >> stream xmN1 D &^' RJZPZ>Ul(I"փ4KE=> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 155 /Filter /FlateDecode >> stream xA @ E9ſ1L3'եAuMkAߏBC3N-u$KP0Gᦺ“kn)b:gE!p.Аms -5q*dQ18ت> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 164 /Filter /FlateDecode >> stream xuA @ EscR\ vQ\x}:"!|6"1MxXW㝄D G?W{*8`,?P'֌FY^8aH+'WE%5Q*5#βܔqlCz* Dy fBE ~< endstream endobj 810 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_rel_contain.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 836 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 271 /Filter /FlateDecode >> stream xuPNC1 qb  #b@!!:~k gERMX&.7~xbQt|mx/O,x);)RSq:L%ݡ]x\2B,;}H%Ի8`J  HIN>W*adcRMz,VM46\_ aP g~x4h]eT2jҹ`ٲRKUŒΤ2+u+H3@ hyf!pj` endstream endobj 811 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_rel_deploy.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 837 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 838 0 R>> >> /Length 237 /Filter /FlateDecode >> stream x}KKA+NUAݛ !A;-DbkRH;I8|> stream x]n <ݡVmI(]r؇ iD!o?U'?SfΛK$0<8^"q LJ\rZadˆw [2`upg:0h_Ռ+ ]^e|a_]kIKT2)Dڎ7bVɓL!ȐM'&8VMIմ*thM ++jkIYmD}I{cc,N[ endstream endobj 841 0 obj << /Length 843 0 R /Filter /FlateDecode /Length1 5084 >> stream xW{|Օ?~wf2g2`0ADB @k %au#6@JEB P+F ,EJ T#5EKY0ƛn?~v{={ιw_CTGgD609A{:2=z3&^xֻﭩoϚ}"U5}*碙(tfx^Lw>cP[LN&J)a:M3&ϟim#r͜5m>e7'$Zj#Gk.{9h9 zD@['ڢmD?Ϭ6}6RzYy 3f` ]nv#*LU QFj` \38;~ ()/h[@]Vvؒiwrw!վSF$BT,[0ԫOaL jk]puX#_4 ݢ -0>}J0*+Dyɫxt ʐB*V:7qJ"ZIP" 91aIJME| .GE Ev:o9nTe",ȉ>1r#:|B;e1 C'CA)eSvHA]UW[W{!~cc/ypQRcn[N-KRRϳ^۞s?,_ +b/ƸFݻ=-}yNU8ιGt]Q-ykΜ86iT~Wge]51Fn*RN4D^$"^r]Ԁ5N6m@Ӗ`&hAQQ~etNU[þw7[T95.Pbڢ[ݦ|LĮqDbljF7ӧ}s$^3>J~t_9Vz0-#O9ZP`F}g/-2CYYUk7d[;ttܣpc욚ٳjjW_n:I`Y~put P* dRCwѦֺ&rLK JGM%fExzRx|wHn 9ԯv+g{{]ceQ&C O̫UJt4'8Y$bڹ߻ǭNuj$yƎtaʦdo:3ʳʰ ӌ/;+'NjL tܣ©s fs:7|8B_2@-knI'y+Ȑ(AZDb,Smy*ffut5wJސ'k.} bXð"Zȿo;EXXh⯰+?SX%i/iż"fU(˧ba1_#,_d )z{acK{^,o ȴuE%."YD cXllgFjcqaeV3j"d(Dio?WiuXtBaͭ4O:;!vu.LBqA|(WNj"qK4`\ z'GHS'.f3s=ӨW)*U-$Cټ FK9;B`(I:!83jQz&,`?Ql9Ny^]N daͨO1R`37t\r>Xx+.b46iԖ@τЗS :ÖNF7إ*oZej V&ZAM4rvmʑrCFY<2>3/Ȑj1PSGǘr#UoTi;p?%<[6<$n^rf-I1K,Q714uzQߣŏY煼i+#u~pfk_jmƺ >C͗k?8uڪQK);FIj]⺔`?&ka4u| H>#f4CYoMa3*2J1)q ^g!B 53Π*4R-X-d GaA2wOWx^2nǙxn\"3ϔq⅓rgJ8<gtX19¶[ԐDa,lXZf$-0E:j1Z\ծE.b׮Pjqu>4.kW3.iVfS׈:Ʃ>+ou z2IJ#sL8K8/4>NtNuG2GU8:xX}IxO ދWm!b8qi:ۚ 5GX|$8tY8R6`x'Z*1 mV>u@4_cj_ o(uVൽ~Zgm~4qf/hī xEc4&er ۸KR*r/j-5~I_بz^c"zNuXפW5*Ԫf3UC"s+yuxHτ + OqƓ'ek<#KVK5~5~Xu)Xă 5j4=Ix`IUsc1̪3U{1̈qw4Ou[ӪjFUc'&WzT NܥQI'1ƝLG:'q;b`m)jL R0ڏDY_P:ңJbqk@P2̣J!a54!lsH^<ȣ{1ȃj`ѿ E蛈>U0 {Tag3z;ݪw^.+^TO| =\%y*/`X{ 7kDdꖁ 5~d[eŐEfʼn 0Ҽ*-iM|f u gĈph5lʩlGVE #TWRVrC4? o7,{ס` endstream endobj 812 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_rel_manifest.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 844 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 845 0 R>> >> /Length 238 /Filter /FlateDecode >> stream x}OKA 9æ3\չYź _vo2L2y I+6R8[D3C{xym.-$|i칶L΁A#f2gϸ PS7@BH&69y҄e˳R4*IJ9|+GCگ匒8#{sy> stream x]n <ݡtmJ(]r-pR By:i ҾFaF3y :VXoY<$%ԺafRg3vߗu?8 XӀ{UMM<۞d_G8*lpJcPnD&h@CЙJI? L5 ATD3S`RVkS&qUJ199H[gk4v~> stream x7kxTUunۯt~$tZBB`i%$!A48#2Lx#8#VcK$ Py+Dm<ٺ7Qwf]T9Tթ|3U_54iƣ|_KcS%ճ&K4Ҫݳ^^|@?eiW@6O=ֿ~͘F]#gUM{ZW `M&W`fv|Jx[ ,aՃ ,&Xds5쭑HV  1^osk'A\sA %9Vxob7rEj3WJ%^3~< Qp3//eBV_kʙ;-UH:4GNn9ꭑ,[+\Թ>P4:aѯ#CY$?.H!!??d3V>]|fU2LopuwS fCFl%ZDk-Ði4e3-JO_aqi9ߒMbpeedh26M&%`YVh5)Jaϩ=PvzvCjn>,͎^Q2wDtލ-zpΈ/w̸$7rr{ei^ -<;~Ӱۣ5r'BqYJr ;~v0F(bwZǻ%6J%8jy<i/d;/ mvT*RwT]U;j:6_l6xrr 9\Juzs3Y'K;O3s{P:ǝd8 +20eYi~+P=ΟQzzDBց5z`WJc)6(vZQc^{ҷ汍k&Z.ߐjZ{_~AT$JCVXj0Vk2+G,Jur7t.q"A},vXatql{-eIoIW|,_o?SӰeį?{_~ɸ&ڶ1tfMу9_jY A#"&f!B4sO}$/[h tO&V/gp>I R͏HRy~#*}3fVW寰FOSm_+?t쵵g\ٕmD Ղm-3ݎ0;8x?s<$^p[ %2jО=mN^ WdÔjIAӤq4Ǩ*HTBv^R-} @YSiizOEK_Zp֕s='p-am,B*+>+pg3O i6>"p\f¥k>!(c\.XࣻEI(.J…Q\PV2pnp8Ggϰ8K`8gVL& 3 N7 7+Wq X.8'%'6) ' ,?@xs8Fq 1$`} 4vpGypdtcIx;pGqؽ.>̍phXy X(M{PBVb<X쟛0&bI\دVɶl ̢va f`|;^J).7> stream xڭ[Mϯ`9]-U2qRN9y=Y%Y`Z!1mOA1pι=D0W?"L$c8 DE۬zU~ xfRmfݕ ,6l`k H_b>XtXc1MC_@1@l 2) Gt 6}If݁\F\@Hr<}C;Bɯ\ÃQI;qWP }94# āBC~DO A$-0@lS)@ے"c/]@bҔiDMk+N?S>PwtCpK؄F |F"ZKlonSx9:Un61t㗷ߴ,?׿| I A]<7&FZֹ:Vb2F;EU5g<1;/p" vLHz*B~Jh` &C78,fEâ"9I@LLկ>k.տFUWyDRo7[\4tt۟1(+YdEm~ypmeܻi o,-ʳ)-oU$+oB-4|kUy.v? !9x9*k~*UlK!1j/4 +eo`Sm} S!P,n,,vTVJ.,Es1~^cVON=Y4$ڿm=+-*w%P_^!f0#T&@k WæaXFkJ/a= AbKCX@;vlv+x 32(5(:vFHOZ#+YgqJft Ata]a,`B*~2@b(N@=):_y??}u)DΔ*:)JN3拓? aaM TgVT+j䪧X|\'PHυt/PQ?sտ3 X3IO3=5X9kTC>۾jp-i<.1K0s=YaK,\bB*1dM@f\Kx\ vU)17{E`!lOyn#5Cژ#oLKo~ۗJ`c^7N_p 0P 8"(%NSR Sc7hnur #DƱA g!%:65w:tPC`t:_7!Zs6j7̔!p\'q녊]d}"zhGתPxFa Ue)8,mdŮy-J51Kv6TѽR_ܷ{ѵ/7{%>V5t՞ ?NT/jM;OA0K_c A)Lt4iBEk aM.49!&Q'kjA@1_yU#IBU;ʮ|л+W2SPڧ]rsU#U ?uivW@=J?Upw4\l|s6yׇ4{ `]<M3¶v8^wfDж`8ۚJ^s B9]ٶz㶅8?#3uZBiswϬB3ɓqE[&@T`;F@Fז #O۝\d]6I Ĉ4#/;S*5Jm },+wvZ싇1O]b7Ts󭆙JkGVs9cd:`89""z7yGNAr7 endstream endobj 813 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_rel_communication_path.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 856 0 R /BBox [0 0 24 18] /Group 855 0 R /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 110 /Filter /FlateDecode >> stream xeA PCs\iO .l H]Hﲄ<10X.P2GL͓+B M/i1,(ʔ#e6q$u endstream endobj 814 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_rel_associate.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 857 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 135 /Filter /FlateDecode >> stream xeA @ E9ſ1Lࢺ ].iuWB> { h6IFX=7s"e5LJ]%xP#t2MbLYtx㌞VvlMQ6m&<kqV.EO_!(R endstream endobj 815 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_rel_aggregate.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 858 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 304 /Filter /FlateDecode >> stream x}J1 }I> rAŅIG݌aJ:s%=Ps%X鼥K\gt o9G2}KOPezIB2 Th#ι-Pz{idX5XՁƭ+IaSy(0+pH?Zf *րy *>OX(@}0xQH$$0`l/@Bx;/eG3 +cZ^,f/7KQߛj=Fgnl2m nn!q/H1վOq.tJ_ endstream endobj 816 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_rel_compose.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 859 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 322 /Filter /FlateDecode >> stream xSN@ އAB8(:W>@HEdf<JE$ݓu6tZ~[Jdɠ]+HXPFGX;=ÿ[ +-W2T QCrmJR~X(Bl߹C<,_ x)[MaO=*g~!BpR¡9'4 1^jզHQ@8 ֦QY(c=#YxfԵj:sc`Dרp  SZj[wLi|zZ endstream endobj 817 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_rel_generalize.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 860 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 140 /Filter /FlateDecode >> stream xe A D|1n/8,NKEk2dȼQHJC2L¹UI c?`}^x`)R+e0C{OTJCc a/[> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 170 /Filter /FlateDecode >> stream xu @ yycz=',27;+X. gE"$}dJ; ;M .RQYG!M Oт̮(<ZFGfW#4hL쳶_!jmΕP1:j䚔2[:&?y endstream endobj 819 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_rel_trace.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 862 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 863 0 R>> >> /Length 235 /Filter /FlateDecode >> stream x}?k1 w}7)lP iok: I %cO!tڊ:G:p}=cIY/㳹x z{mK X,II} *ýjB Kҋ'HpIe5[C̸{hHM@3')ӈ98P5N^5ڳ'b4uҍ ;Ka8Pע^* ͖Vy5:ZW endstream endobj 865 0 obj << /Length 867 0 R /Filter /FlateDecode >> stream x]n wu8ނ"U%C?Դ@H B} R_=z5bc-* gXہ*]rEI> stream xW{xTE?u:I_7B@B  Ah /,0* AwGw&PШ"+;0:cð,"ʞۉ;}~~R<_>UY@~ri""9H2 ';|ykj? 2xՎgլط֜g͜VmJY,p쎫#JdΪ](0ߗygL#JS_;m\xggѴ18cx4Qzhȷt͆k/tm "WG#l`ԹTcM4*~)-Qc]ZܭvrMsuLF\%ח^/}i&*1Pdx)'EP^0f^h,.\[VJ/VgBy7lN|bp31i&&ieLnJQy> ;&u-c\I^*{97sD'98QIkg}y뗪=[>"^c_dɨ$ D/$kkӍ=T&hH ;2^D(pu I*zuX$TX;/Ũ6*Yi_(Ԫ}jg|;鎽c? Zck6@ָ:Nra񗱅n'i N1ż}bAϤf҉Mnd b[%dw%9ݮfgyi|jia·L9-EL8'{HxspFV2OVJJB6)Cy'2 -_SӢ;^ڳGnTw NE/uӂf>pM\)#G8h8N$or9:xHz-<]&p.^VxV5{n)~M^2g&dO-or\+iC ^Z693}26eAQV/'}fsQ]̴ƀtݥk cۯ_o|_X_oe`C`g@Fyþ;e*roo)VfoUɧ3\,F xp@~AI1x~]:wI3WnyٮS9ӟ-x/.[2~M퍏}l{M屭od5q@add+d޸6ҵ c*hHbn?3 tVSZyޠs!ˉfeb<2Hpf Mzv"Qmv]d [q6E^?ZΎАnezi!O&FqR#l9ND{Ck=Jgy_]G[5YKcD.*nNM&.Z;,'I [2Ɖ*E3cč$Q(0̯#VLja#c״o&]+tZkkE Z@ٿHY nOX+Le:KWWY.'7ˌf`ֹRSZVo7.q;wVX%1YoLU, ׊Eo{[}sؗ䋏]lk*E Ve_:lϧF*d-tFt\*zqd _k_c0طqk<&PZķ~D!/j?cVD}EHe.RٙsLV^ffw-D:i1Ij^17gR<)FAw8s~h%1M$d0m`YR6L YfJ b+c43bRsesdaKƨBlGZL"b]٩D~oWQ\SR¿?+\V.FBĊHXVEQ|&E~Y3+V)| 3jӛt5>8(? >:Ena >8qʅÏx-ޏ?{{Yx|7'whOqV17iGGZqA?z;(WpX;ެFS.٦F^W8p"y0v׊4j@:~lՉ}6^QhQN+WaO/f?î(vtaG=~l‹ /(lW~!Ձa} 'jKyf/6)ؠV^J|+oЛVeS%*X@4Fo gxƆ,Z[yxZa aM rau?SXRI O(X?UXmď)4bK~8NᑇGގˇXQ̯<s0'(fGC~0kM ~fV[Lj+V9ÆVLi>+UTf1= S˩ S Q|_n]w+ܥPŝn1)U$VLJETY {1-yP:֐nc q(n[E(,qb [>Gar(f)fj)qd\&o`[>jܠl2ߍaPv9H!mG 1 H"9E_q e~^do'_/ !E@XEfF "Ù,3Rw=ݎRVTZ p(<,F$yCU %p.8t;kQBH% Aa q iXu= T Ր.CDoo|2_xy endstream endobj 820 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_rel_refine.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 869 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-1 870 0 R/f-0-0 871 0 R>> >> /Length 245 /Filter /FlateDecode >> stream x}OK1)ޱ:$ ACuoփ?P\w[L^7Xsρ$Kj!K*T6W$1T 4s2'=ucqpA;Y @\"kE[ѻ~?2j {yZuwrN*5VVqsjxiIx[+ endstream endobj 873 0 obj << /Length 877 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> stream x]n <""M%nӲ="-9g2&ѫtoQ!L8[-h=+Zd`&\g<'w8h?u3/c}~pAa} &^ħASݦD= %?WKk\TA3t_ɨLdU9y endstream endobj 878 0 obj << /Length 881 0 R /Filter /FlateDecode /Length1 4428 >> stream xWyxT?ޝI&g&}0A%l,YBҀBhR* ED#DDkY"X H4eiK Rdyƛ7,_k??|7sw "QKGN;s)xOڽgbWVtbf}d옑Ŏ lODz:(6cKHib}Fḑ1R`i#&N3񁑫>c~5%ҨDU%r5gkL6EnW}#'KtjƓxvz^CYzԌr: >&pݍs]ND<_+JH x:ej+2ZX,.:f'HZpXDث bI='zQ#NyhTq>J^ ?c 8|w}IJ_;(_snJEvy"'iiΫ]jT3/0) )J[ccNRA"FtSOL/[XU}# S;O94W_" 9(g]P+ 2Fح Sf:]FS=5Ջ~FBT#*(R~R[[³ǎJ\c;V6fdAec7vd{>;̸W6_دrxSL"\!DPpk=j8(u7T)L1Mn+KhwH3Dڍh7i|T:KⷍzQ1#̷N6qYY$n# xR{G; [45 "֗_dz>GEX&\yesOWqKz`CLwUd +ݕ&^+Pr>G a\&:v4&1WNb+@r8#s\*KnF}-%lfԗ3+43̃DAUZ"_d߃OM].5PĖkifYN<h93^BQ(mTE Ty4 - Zk@;8b98aT <4+s\h"EOHjޅ:H߭e-WGhtNB6*⸥D9grS=Ex_]SU1^lጉzuLU*NZcPi-tDY1 DJ0Ѕ[h dK*Uꭰs״ueTb-ŢS M!v7CpWk~=Âm@5 vjrXLF(Ze>6Y 5W.gLY;?3V+瞗7=&MWhw }fݮ_SzL~1lk*/wRJ^|)Uw\~;JFZ+KP,YԳ ~Gj~7EX0Z U҂h"ķDK<%ePWd-v& өa3LjS(a2w{$1 Ga(LB#?ʙ45ioYr& vzeA3.hL V,N(e ,3%ѕ1Qh劘\aL[3^XQGݑ(pS9C)4~%ɂpby _+SK-*YŸpZT&O)Dlɯ _|Q\34p '>Uq+Nm.hsY&'!y'!||0$?6p#<#ܨ0Na>` dC8]x+΋ޟw}طVSػg[p3{QM1v=ᖻv`vmom^,[o&ɷV|3 [k]r[օ-vl`ju/~&j"l0z~]22Z[_)_*mX*|Aa\ %+Ӱ yS²rҪri-VU Cj Kt,Qx-*yaeZ Oҧxʎ,Z\'=(O0_(,Px\a< =)<(<+lD̲Arf2_iS4S1rLR8!KNx3p8*mcqBI6bQ69ڎQ6,ˑ(Y6ܥ0BMw*1Ǐ[|m Sˉ{zϞ!{dXGwBw'uun MSF.蜓$;'sMdsN>t;feG:l;:_#;(gנm&+O1ɬ<. Ÿ^:?Z5Vi \-ӐA r.ztҐ(SCHq˔DpX';X ʑA \ -e|ňaޣ.閮xN75lWXEڤEa]7b@=RSܽRx@Q> stream xUktT~L( 2I&K.3$ yP0=;4ӟ$GnK=5qX9XGchF<Jnr4w渠J󪾪aJ32<GjΧ}!UҌqp2mn!@`#٭_V>|DU5VZ7UÎ@~vQ/7oAi&Q&>HH&x/\V~BlŞKR1f /E͢[xDc<{xP]Yu} :v¨z,Gr&AV.EToe&&ZQ@F!Qmt.;Ѣ]\C=ov{)1Dԋ<4yʍrqB|WNj"Yus͗ctfa0Dp;IO \P=@Jl2Rl!3-y[:@0Cv⨣I,d?-uzF:ՍkEF;[Θh*Rf0;e=jCnG]~0:-tE|Ҫ.A"?ƑAm&. "ZDv}+ՑKm< ۺmT`V[):h%u=P/i&$ѽSKF})$% u2&UNԤOƣ%ŵuqoŽkfzZeU6kդoBC28'̷rove Y1xzTq}N;Q):ȗf޹Ro7.ߎ&u:ku}&zQ܊1w|iPS%)QH&b6Q۞GJ0> a̶m`cA G Cd C-lC`mknGKT, [YKN*bͲ1Κ@3SmLXhpl_u)#VoA(h/UƗ05Νεx1qZ 5ىS8NhuNg:gԉOL|"K}񑉿8ƇQ?kI&|0PIxCD{{&ލᝃ1Y8S[PoMxA07q7 kz^PНl>SotZx;{rO h!5v%];_T;MTXXV/.z>]^Gb bith<34> !mgm5?7.¯4xBc/ؤFz\c1.c&6 nuu95jƚjM'ִ1>qstXu!xb[$ޏGyQɯ.aߋ`bm@M ƯjQ5~L2/ A\8՗xTx0vLL51c!>ګGyh/Fy0ʭFfʍԨebDyC*FN9V*J],,uajP?t3pa&J+U`LWbpI8o_AQ #(c ^e4<'"Tn 9LBN+d؍PnA b?x,Aւ1#CܯK)o&;OtmUtZz[ g\ijh8S94*. $W˭/^Y5d endstream endobj 821 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_rel_extend.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 883 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 884 0 R>> >> /Length 237 /Filter /FlateDecode >> stream x}OKA 9æ3\չYⶅ~|g۽0b #QNcϵ er b51I?> .BNQJ !I-RH]Ш$m*i i3J"<'VqFE"PzrĊunڠnaZkiqwE kͶwVW endstream endobj 886 0 obj << /Length 888 0 R /Filter /FlateDecode >> stream x]n <ݡVݺ4ue{&CZr@I;?e)3XM%I#89G0NWo=8m8&% .9m{2a;-LO iXc} Z*⫚x{Cq=2>p}IKT2)Dڎ7bVɇ{ 16§'qLIX>?V&Cɔ{Ym,D]Qm1Ģ}~ endstream endobj 887 0 obj << /Length 889 0 R /Filter /FlateDecode /Length1 5100 >> stream xWy|E_L!WwB] "hȭd0FT ,\'ì cX`Vgle'VgvV^zUTGӾgӉ,wic&>=+06" LDXWx )5U߿1g'O_!XNfk]Lw\=k]78gL:q<0Ly9,߳`)6cҴgob"뛤QZWɍ쭕w.X"6PөWs[7y"mo zU:DryunӚFe>|LAö6!w^ȱ2%ٯN*֜~)ȵH7 9Q.y.+u`&ʅ?&ruy= 쓕aJɹkyUm%"CD䙊?hyU=7XErz|IċBoYUL_E,k'wv$C.9it{:x_;oIuIo`OVs`kW+=թzQ5ݧ~SŪOu~WlP~vq\y( 'wZO.zj[:$ހO'r_\XrsٛwJH A0^ o~,N~_"6j82kdž553g`Vv+a81T׭l~1B}ލ,iI$p]&VQV(_p8Er9Zv=:qQ%:k])ZS-z㲆m?{v-NCۚCɰ8@5mErl[;H{Id 8NiSL)f΋t C8Q~H8{N&2ŖjZTiH`1 A!a8U5!Qcޣ8 ;۩LHnGʬy?Gg݃t{y(pg)}>Ⱦؾ` VXVafm7{+Zq~~gq~~Þ ͡;l0=Ŗ`;jFqk%zؘ1iŶ:c[mˍ7- n}أяǩU;_Yq[ ˩."0N~5E̽xZ~K-k13ܒQwtcW찭'g3ĻF<94xc9> yEEq4G4y<&hp{R v5 #+ߛjybZ<`\ji{{vF qO&N vck]8ؕy!xEH;  [fuaQ;^`DX-p_w8mMEBEjJ*Eq@QU51",bj}#i,ȣ / .Ix|H>(ǘ1CZ, Lv֘WavT_Տ}[fz&Ջa"zQ,D·@~c1c53!(yu.ҙ%%{LTOEB߯/d)GGhC:c8ԐD={qR%jXsNDPk=~@y_l]*vD V:AOzK^FQQK7]-\ }1 ɽ\WaxZ.Y!5FtP{͒JnXþkZwq5Ԣ`eQ#%!Vԡ xʆȲB<@68kez S5sNxGvIiYQue(f#e<4)f3̴ C7!0qrEϋ/z&Uƒ9_}] b7fou')]oZU*'xcƭ\wC6uTj*iIdwy7SؑVix0UmAiW~B^ԂA/huW"/î"H$EW2I 32bz"S4dPd]bb017e.snZc9p Yĩ8.MQ|‰!y"D|v#?mɶ>/YQCf'>y$ O|haN>:$)x `W[iC6Ӂ{ x; ;wIhH6^g[[m-+[m?(< YMM g`\ .l9PXS֥a-QͯIVjV՗UMXU/rԇVrvTXyp^㩯˘0zEa)ai"x8UXK /*,TOB ? ^# uIg9ZgF(jyz|FM=+YΎbV2fF1M͖STQL O*|_aD'r1Ґ* T 9с W^YS(W|x8cX1LIh(FQ*¨4<#Qd$>$KxhW>^|/ K|r%üćaC]rC]x0!?(d]oPH ^sPnV8%1EN?ENDB*ܓ]dd~NLJ>uz^Cs蝳IVs6=#P"م^ wѭWvKCV4ttL/2)3  !5%IN)IHi䚱TOvKRR$6T HdkQW/L{> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 891 0 R>> >> /Length 238 /Filter /FlateDecode >> stream x}OKA 9æ3\չYҵ_vo2L2y I+L)-t77fƇv\$|#i칶L΁A#f2gug\P(T) JIY^!$핣!rFIdD 9ȼHJOnXvM-,~{ZvZ]Q(uZ}|n X_W endstream endobj 748 0 obj << /Type /ObjStm /N 100 /First 903 /Length 2069 /Filter /FlateDecode >> stream xZ]s}_ԖA[!ĉ7ke5C 4Inp1ΜLp΄2Lhb gϜ1_lEu_ς3PEg"@з@3a"6Lc/ǎ5:ezn0U'&U `FN3#0L,r.0={ `3%S{Ŕ2eI|l;Vc4@3-TPLcB=X:ϴ@2M= ,vЅDMph83<fD0Wi4IfT"lcG f54dHx5{.ik ͙y+҇ץ!McP%' j Oa>^FHf@@6 l#4 ҨCACFm &x #@iT瀨XLByVHPO`<aQ-3 #Bf/^dͷ{)J a좪_X}^Ë^g=5_E^v^YWɥFpΟgh35O?~b;B4$1//?/jll#Fϵ+kA z16LM1L:h3ʀ`Ll쇻TܧF)LNT-Jִs*`BOK<7?M Z;cͷ=<)V,}r3, ?/,AѯF @6ku)FqU-|wDA†$cӢg肸4n\Kɠ?PPX8|q!RrHlCzc j-J-w8._=NMwc2+A Q&hjۣKG»;a,]ѪJlx̘}Ӗn>1]jpk}ʷ9pgI^E&2>||wz}JdN'NSsDt(&O#k0tIG%Y}5Kؐ)mze.FOBdt:"{w@J{oCJBJ{kOkC:Ҕ.gtS>4Ez`zz;Z0mLLo␺`zWAoQ\==nof3;.W,p<*?H[픭MN٘W]RT7ͣ7gYg8B^u?]n f_pzfzv^,3o;yP/TC2V7#nި*AVw)(EI~64pxY\o9讝Le1˱Z|~Xz?.#"<$"z>lV&CmYUØwM@|n~sAO} *| faΔR6*UumOJt'4[7')iҷN!3_uv endstream endobj 893 0 obj << /Length 895 0 R /Filter /FlateDecode >> stream x]Kn b"IZW*xч·Q*uw6^ X#.~ a:v8*]YI> stream xW{xTE?uUIIwBytt "jyeB8F#!dcudH$c.;ذ,mDwf?f۽uΣSUI ]=/_xHf?0?4A DOvGx@G5uOmeO$W͙YJ*%ITU_43kf$ r?ꙋjlmP95\)kKdPnj#S." m"U0$ DގXG0ŗ r+%uCn\kǐ_+,t z@y4mWHq.fx;cb_r x&rLW\\\Jy>h%7Դl18r];-rMpR qϫ+^1kn<0qMg8m2{`::SGV Krь1IòEO 9_l#O>/ 1 mc$ їΛ[[]Fx.gtԴ٬db+cl룹H$NP/:Ň^L>\  5\aV̼g.xYL\+\C} 5dB pڕ͵-KQMLEYX^\C׏ձAHdQ[p/YXrK6rQrMpHz*A8P밻;;ǒ^MQ߰09"_OʾzNSt^˾w$׷T:A}wop~{)}]>ɎSd_ӧH1ŵQ %\ NLKhbibybMb}YOl~}8/\.%rϝ^ޝE!}3L?SU^n}az/fo?]aܓE#F3î:\vȷ*>EaMGbfeۗ) . ZH1SrTY4~䆗^j\tceqX39Bn{mADNʯ# 7wk|NHd3Ī\ըzb+6Qh>ku4n6wNFFSr@oG9cmMj#S^sxD,*i}RmS)YlT>*r[-7%0`Es/,7]bQM3-G\[*6LVr\*Y)R b\##wLdbYӪQLyh4"]56,Uq:.Jٲ(2G]""H2Ut eA\$3YHتO4}r4 q.h3͑9- uJ #&dѼ\#`-GGa:ݴPE#8mlgkMx]ݘn,6*v2bGVYn%hketތ 39V}D.}(\2#mٙ}ϡ6T4f "Ò[E,jрD>;'[#Tzř}p,sY2sHXfjeIA,35`e)HF&X19¶jtYRDX]u uqWƩu2_qYKKކqA_q^\̡iEq/"يTƧqKg9qFqZ4QWq:K^8єNT8>caQ~W^ǽx?Iu~~,?qy8_{=?ړqՇCPp^vVf@Tgj[اWcϛ%jOon 7K ;7vQ|hTmtuvFkkCc{!-lc+7[[h榹?x9Y%MF jz7G:Ժ8xHS6^8f5Ս36êqyU4ؐOyOC+Yr"YxƋa25xR  5 o4q4aXCuj,X&PMX0?1?yq̭5 poqǏ4Fl.T8 *r,,f *NИO 517-4ƭGn+ٸŏŠ)(J|OMNM>e6&MILS0ޭ&0ލ}!׻XwchstQ5ҭFy0ҍ]jD*0%~|Och +PׅQ4į2PGq?਌81pQn@'AGA JЯQk5 oOF~l듍<zK#׃ܨ @v62UVV>3VȠ UFiDH!`Y R|H1V*O <{ wt3$^ZR*GT&j$h5lʡlTE|r) ZEţDo>Y}u endstream endobj 919 0 obj << /Length 2210 /Filter /FlateDecode >> stream xM6+XzΉ5Fts4=I?LWi31-&210tëѕw/ʼJɀy~>7Ut8e ^Q\~M^m踋2,<=zi=(RDAqg)*>_F=w=}G& /}{#(ʝ'FIxzaSFK$|x1ZP{>K&(J dn2Q1I=_0D}aGA}}Rce!UU:KE-QɈUCkDBT(AV D"cgf p%I2GB3M1P%췂`nJ蜀m_v)])ѳ"V!m`ΡknvR*e$|jlt"tfWa^'M@md;>Uo Hŗv8SH03<*"gQl+]}~#鵱N5YU0\\il0a\G$=/]El* ̘!a!В31Bbs4,5Te"B䆔q,oFKRHk\fcr#8!%[$YtHLߣcrtc aaxШ1*nx AP~v4v`ķkQ ^ʻA(%F/% D;Yh/<ߚaWaXT$K~xUoDD7!>֦ۢK맼H 6)xf^oEli/a>%YQaUP> C@!19hc24Ղ@, j?`eYC-c&Yl6!Rn l-. vwi-E:OBZ'7 %~'Yw%]$"ư01fhQ71h$!RѨr2&kiӛ Q@:!H4KhKu"1Hi4)R#JS-/Z 79*BLZB4) RAs茪8Fwy-s},S/Gw1*.6MJLCŮuQ5Mm>Wl54,DP4J' qtdz2 +{-WFVallUk~8{gMc_:#\}ضf]Pio7vz6]4V`3>\ =ٛ:m8mcR1mk'r$gr-/J<_av܀QtN7Bb0ٛa1Uq'{2yU7.crޟd=F}qRۄ-ْsv&'Ʃ95pQyv%M.v+'a֗ 9FH rFUq҇6rA[*u.lTڣWng8n qBۅ;~vȹ&ν]i BHĔ endstream endobj 823 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_rel_sync.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 922 0 R /BBox [0 0 24 18] /Group 921 0 R /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 152 /Filter /FlateDecode >> stream x}= A ]LF,VKqF\Gzт@# Z$VL Ók+)a޾?.RQYB]FܰCy,? M`9E䜂B`fq~fQ˷~~:z7 endstream endobj 824 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_rel_return.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 923 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 185 /Filter /FlateDecode >> stream x}0 D|v&YY #b@ !:~4BQ:8" ɥ6~Xz cYŸ-HN5CՒMX-zH`]iq?Gcrk(Rp:QڧlPt/*gx(Z-qt$AL%uE##68o SK@ endstream endobj 898 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_diag_list.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 924 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 317 /Filter /FlateDecode >> stream x}QAN1 &$$# BlnVؓD(qzهClգVH4L!-H$j$mRr7zU_Yѳ'vToPb?n0WRh e M\6"dIP*礀-,U(ȸh1Zcạɜs^fmpX7 )g4w&c_ru C8Dk3àz5 ߞk1擷 /U[Yc"ʓ%3)^> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 521 /Filter /FlateDecode >> stream x}Rˎ1 +88,0aOI@Iv)^BehAo>GcUq\jL-fPpZcatU eh$RPl%gAđM+B̂= Pmm15)P@ $6Y^G\Mi\Χ: !fb -1K q=0loQ͙h3҉ayNj<Ӡn; M\ t} [<>1-> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 220 /Filter /FlateDecode >> stream xuP1N1 &v$+JD!⠸7BZExqbFulx_%Dj1U싧ܿE|d\Cģꢈ8n=%'qD5 ?6Sƺ~naC1'Jb\QMdi2Qc{g/`Xl[_ڠǖu>ʫHFgpmM]>"#nd endstream endobj 901 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_diag_internal.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 927 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 239 /Filter /FlateDecode >> stream xN1 yy{Tq@*ɦv6_fu'.bx?c`JNXoqfcWxyu#$lqth)؅~%uF巚1wgjkh")n/f&T?jd)A/T2ٿcO[|NWeϏN?V*qI}> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 329 /Filter /FlateDecode >> stream xN1 <_.HH 1th؉k'Pt|98Peob \?[}pRp2nz7OdPLBrFt$oRx|ؚ =`R jl:lOkh "& >:JJXx-9/H4@]m.ǘܤ0;4?jQ&P,Eըuc{ ڮtF-[5aHaqbBJcݙTܗXͲqt?cbejμHT1rz!ۅ31;/ ^㥭ZF endstream endobj 903 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_diag_deployment.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 929 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 213 /Filter /FlateDecode >> stream xuOjAW<@x09փz3 akjy> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 331 /Filter /FlateDecode >> stream xuR=O1 +0ϕ 0"t"tZ}$wUt~_Buݐ*0y xu[rߗ{y .#kIH[&ˤhϰsWEcP0hvnFTH pQJ~z)K%@T԰%iAr XuVcbu zJzـ4;~3ӊ c.kZJܐ^vF~'LpIC{ o=JTt%J֍a͘}khdfe}WTdhҡ i endstream endobj 933 0 obj << /Length 1980 /Filter /FlateDecode >> stream xMw8,sjU߂4mO{:m2 I©Sc''~q! Ec{}^$8 p닗oeA"Iep}dVz|%ۧb7sgqjϖdN]6{$z<($!;HQSeaDŏ [?d"H` ( GA0LUpun$A2kaҚ\# yx\p4A BDt;kgY&!GL@ dpnӤy:RCKCNVtی̔i"3CFiW.޶}Vf݀D HZFqfƭoMB<& }IEO?BQ`72zflv[% ^h4=xD r5ݗڹl˕BbC+7EK˫nOvm enu>t(F$& []=*IWY^7l ݂LPj \/Qaߏ*SbI\%s`yu`Irp\D2/=.S8qpGhXAB%zYqFEGW8 !ń8 p8dqJW&5W t{ "JaIZ$Oz 9Ip;G? oveދfKh@%czڧ+=PSTȦEPrQ5#>?6ի?Wpa)fCIW`=8x #4, !B> ~~,GhTXztō%aYa#(5Ʋ&ۍ%#ıt**.|s 8+ &x :]AJ;shEI_D^8oH9=: bd] ?ets*f'swxs`C=͓rEWd물\4_0gw֘yfF[܂}7-n֎O IjvFak_:56.0jʹ{fUti <>힭 ?MϥيDШ<ף+nυؙD"9[ =&,TzPT?"|vOp)AQDAUrW0;-g4Ik+2?ř$xeM+z֫8O+_̆]0P8n!kc4]t.8kSمq,*rQa\ֳKڠ8u9qSI` >V08x #4,zD?#4*N=jgt*Ôbj74(d}%q* d |Id );[&ɿwr49a<ءC!oEwaZZxH kZ>]1- f Mr YQ3~5Ym1[{"m_ cADhg&iu/ءz.(FhX 6~~8_r~MjOh,pv|yȼ) b"/~ ԆLCJ]ܕU9.WˇȾ٧cJŲFngLSvϔ0C.ߟ ˿6T(6I2d#7us$#~3Ʌ! t5T|S͵ endstream endobj 905 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_diag_composite.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 937 0 R /BBox [0 0 24 18] /Group 935 0 R /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 316 /Filter /FlateDecode >> stream xRN1 ĉvABb(CIJ蜼߳uXa8#E)X`eIYt/D"<hz\,5 J~`9PL3Cio&MK(>gR,Y7$lhI+7)nťKFE0`Ӑ5']3j.晊{]hZlґMCR+R6@E'0T f n54*39jLr<:j-θln_i}Բ̡ؕןXgu6F˜JLedl7 v endstream endobj 906 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_diag_package.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 938 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 229 /Filter /FlateDecode >> stream xuAj1 E>ſ@U ,.KeZ eH#3!cI|} ΁)Uc-^sQp g?Eϐp]GtO!F:ej 8;z%u FԞc?hn6˭R)B$S0Y;7R)+nhSH5bF"1sl!st\v[ AۜSm@\a{?p^xa endstream endobj 907 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_diag_class.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 939 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 274 /Filter /FlateDecode >> stream xN0 y &v~$$# BBaIMCSU7_my i!b6`{x~_?^TN!£͋"| Op#&!L'.S0y˙foQ?wq>mE] rfH&.k]M, ]iL>0-KYp~t]Za2/KAP8d|#Csj3)ri^<͗6+ ƪ#yn %dP.e)7j05(-rhjCSJ]y\.Ձ endstream endobj 908 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_diag_profile.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 940 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 941 0 R>> >> /Length 194 /Filter /FlateDecode >> stream x} 1E[jL1 `S >w6daF Ů+qYʾe1`8 ObLmi1 3\!KsJ).K'ޗޘZ?u{]uv(v9$ %·*"548\Vґzk|s觳YQ=۵>DszmC endstream endobj 943 0 obj << /Length 945 0 R /Filter /FlateDecode >> stream x]Pn sLvԤd)J.>tQ~Ea|w(zfykMߣW&0鈋_BqGVU~58mI8x& .)nh?u쾮Cu k?8Kаʽ*g^ć^Sܦ@- ֑׸0J7!MӁ0cع*FedB4LuO??N@[c>c>cH[*1a|I endstream endobj 944 0 obj << /Length 946 0 R /Filter /FlateDecode /Length1 4860 >> stream xW{|Օ?ݙd2d&̃0I-BB 1ht >ᡐ@VF^RZ#FF  Bu,x@?}|̹u=sDdFNudH89N enz$ D1MHfƴՎ/Ed}~3;ltsePzdd"N$/,c-bu}gϘ.g~LըzZ)tŊs tLhg47ѩk6ҺΪV畋,гB*x%QKD2%ቸ]&ZoK3gB8WX+|W')uBU2Jֳ/:uQ%f_E}g٩ϧ0.IԭX{N!+Vz h3:pgJ]RE5+fPqKgح+]]ݘ"{GR y)>pQ0$+x1!_\*iwHq5hjMuLθ`ˌ~}6ڑg/nmUĵSiy)FEBH$I0|߅ӼvOyQ35 37"GЈdeie(UiUHJa eoViZUut"׫7IM/wk8Eh@]{FHpC;eBoG#iXPNhhK]_|cfRndaaٷo U+C-.e/ . m n QHNY`*X_h7ܕ|s]a"l C g]P6͜4~qznE?.8f>G qe옒V^׋TVk](ckyٟj.mZ nzk8ZN4KxB(Ωd.*$P>.zZK-7KBԓE I'7sŝb'`n(5ԷoQ!XpU?#xIyl:q@OWO=ꌿkAM_-vӯF( USSXsX\o& 6|B3 nEgy"LMFMqAjT}5"jfXwTIMZ(D4Y:T8ej6_\®-2] q^|6jn`EUZ.kqzNӇ'z@8 "=9-4yⵆ Ep4E^ןd)GGhG72ԐE{qR#Yyg|NxwmDv=&Z,U)z5Y :oƆjx<,n +͈QX>xhc}OB̷)AAr_`Kֳ}״kqԡb UVQ+&6_X-R&('n·V7GWL +2Ql.fތpB<䔖U[7n*jfYI17e2V5.q/,ZV4 ^ڽϖ}H7umrVvWG45==VeeY_:wX:jdZp7$k(MP]˿v6([n6s֬Giw}}]B<#5"0 (T&0{7g<@m T0#.MTi!9q;{aJ㣣aQ ~n<$;8Ya]xYx#Ã#,>^:&)܃)TxE^NEs v1li{ X[?Ux) ?QxQ [ņ ??RĦ6~liC ӱNamrM6<ߨ7-˦J4EVXٱFṁX W#x>3vb֪R< +9+SaPaR(<' O} ]E Xh(̏1+}l<:'M>Ü4̎aVf*=#1P *0 xeAՇrC<"?18ws`1 H!9E_oV:oː~d_&??2 %CȅPDzGFz#ݕ,S=c@R٧ij)z+2»c/ o5 x w5\Nt%õWwl,q`C-)I[DOTHP*XMZ P/RCjC hՋ?vɠ?;oe endstream endobj 909 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_diag_requirement.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 947 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 177 /Filter /FlateDecode >> stream x}M 09\g^sApQ] ]./A*!LfB2, NJIیvQ(z /U5F endstream endobj 910 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_diag_usecase.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 948 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 208 /Filter /FlateDecode >> stream xuKn1 >\HH,eE> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 342 /Filter /FlateDecode >> stream xKN1 9/qNĢD,PA . :#Dd#&]dަ]Xepy o_*| 'w hNk^ƙ 27|X ͳlP҂@<<6bn,.&"dqfRRbL(ڂӂԡaiK\[^r;VӥQj̣  L ;9bOuņe<vZZp~ i<݇mj'd 4{mxǼ|ݞٜ޽P4kcsN䫒c3-6z_ endstream endobj 912 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_diag_activity.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 950 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 308 /Filter /FlateDecode >> stream xuMN0>\a~>A%$%btQXjQ_x%s4r K/tx7DsS!z HZ]OeDm4"5m=>wvhyRo~fm}bc!E2V ;dSgPq*A@-rd-:"ϹDT:ƪޭ:DZI\ êh1^tYLdȜ ȊEĨﵸKxѬMTwy p-Y<"V,k8{|4(+ endstream endobj 913 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_diag_state.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 951 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 697 /Filter /FlateDecode >> stream xTnU1 +I X:n->c'RHglء\pmKtY~U~?#?_jz~2:Ixu2M~MK|+ 1yyDlo'Z [ 2htHIK3ِkak:O E&0eps?R'@ai8YvV}΢~jV܋&;!׆<ϹdSk$ln 47YBva9!.FvEC[wZ 8R6`0Tj pPuo{4dP"Y[;-p`Żu[: $fN fE\b۶(mhNpѕGC\ba;Y>TƖ]&>N?{ %;P(is>_^뎉 Q|<±5ؗ5݁B)SoL`I?[kJ endstream endobj 914 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_diag_communication.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 952 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>/Font << /f-0-0 953 0 R>> >> /Length 334 /Filter /FlateDecode >> stream xRMO0 W8l˹"!$$ԱIz8qڍnb9l5la(J/7K};lIkC1ZOF*c8H+FŮH3[njt-ڝk']7?&^\8aV)@Rf*H*Ue_$cɾi@+! ښPC"#b1PǾ:qfM;W{w endstream endobj 955 0 obj << /Length 957 0 R /Filter /FlateDecode >> stream x]Pn y ɭ(Ru]2GML!o_R0~kP@~P!:%dFBM .rmgd->$RhӳK#> B}hXsc%zjd5{|(ۙm-#oH69\H&N(Rh;.cfHKJb}sa9θi1J nj=TX_Nyw h9s endstream endobj 956 0 obj << /Length 958 0 R /Filter /FlateDecode /Length1 4104 >> stream xVyxT? ̖d_& D 5 ԆM"QdQA*H4ҀH"m5TPFnPK[e*˃g?ׯݼs}9@I5U>DF߱賽G xtkw"jwͩ^C5h2*<+ZXtfg1>Ǹ󔚙,IgIU{9|ƾlClCӦO@Ն+dPj#gk$E+DK"F=fHPyEE `7ZHx\]NOuecNQ2- u dHLPJU2cįH+r$E )#M ⡈[҃GX|T:M*{19"g$]xe@$C9I9TTܟIh(c{pcŅ=FKg=שNbkn 'NBlc3tFd1*67gP@D7qq?iQ4~L=q$TA->2a0=:p0&[?{{yx5^Ckԫ}:ĥz1ą& A~ a\̍\/>V!}\}\}SNN\FFj\SATNˇ^ugQCϐ,CMF!/܄q*D?K-+q]K&fs.[LzCNc"ۍ @f&2STFf+d)*)4I^$rD~EWQwI:dD\byk'!I#FîaSeP& ӫ ˩hEKE  s endstream endobj 915 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_diag_sequence.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 959 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 304 /Filter /FlateDecode >> stream xRN1 +8/;_ġpDPAH=}nڭPٌO&7IpK;-wt+K" / =ЁdN3DJӤ'ڠޒʱJ\}Z"); í6ɸ:Q[fhit'VV.5;M6 ,X3lGt9qv5!YX ' e8YbQ2Wi^ǵQ~XXDjxN+vdj!_Cvmǟ$9oMh;o,앆 endstream endobj 916 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/home/berrydisk/andi/Code/crystal-facet-uml/user_doc/doc///../../gui/source/resources/type_diag_timing.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 960 0 R /BBox [0 0 24 18] /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources << /ExtGState << /a0 << /CA 1 /ca 1 >> >>>> /Length 268 /Filter /FlateDecode >> stream xuAN1 E9/'qNĢD,PAHh(,> 0(Vm'BJiHǔن23}B+}L L/莎$sDO> stream xڽWYo8~У4I: 7qII m RtߡHg4 p3C;s;g?PIPIg QN'wnL>5G3aVWy]y_ZvbZ_S̵h rQ-=.xS0n;F%84A OC^ût:>&w<,=70C%1,Mt4}\_2=M'tY.=\x(d0M{#3{΅O#BۀoP~=?'0NQOqȗo®||F_띓%/1'㡦Mcko$!ۦmQ(!ٺ凈}Bfj*oB!hSẘQ-B)f9ʌ'ǚ#mg\,"W"ӯeJk>ں>ŬsQ ɋ\!\'fe.NY'C^5sW̠`PBmŬkСP*F ʠZN~eȝg7tDM> >> stream xy T33]+ʖe MRJ"h&FD[nPIv$-TR)]֙9Ǡ1fΜYsoc}3{|@yyy~&\x^…%.&سJ7$ φ'WDDWߚޱPvdttɻ&vig6nHp U'|fdsuET $><.h_<|_фY pcNDh]//L1kv-i|$~GȰ'T2Y!u/q}ᚌ(1딉e#6 Py^:pɆ+S-HׯwFZE^W2t-#7 ]tV%[7lÙ"eħ~Qq;w8ah' K pEE!o`>2H k.Nodmm*~Y 7ZI#r7*<+ZካGϼAIZ mϦ;XZ}1zk_(-#1t@Owc3쳣Ӧԅr3}\#)}=L -7 ţoڽOXXh22U&i  lg3 Q=?$md=A= 4xVUAP:v IXJtBTc^>KSx3]U+O guy닾i'!iQY}SmF)ˁJ\Zxmv׉LUZ霔 2va؈a"=$}s,j7"@ivSPPM(/4UlnlfÓSү]:cĄ$dgDY9iXM 4HVaʂEw %G @1.w6=~k~ i8yk-2u.@C ^WO% *.PD4*kk)ITB 3 'AEG.iWW* SwX۵4yF,=ŋՉ{m=Ԥ6))ABZ!@sii RD__HBvGk?<{8LŖ@9hbFǒ>$eeҪeL;u !#M"6@pB?(;v5~".;uƬjK[xL웯N(uYu#HÃduFXBiU#\qSڠDq`Kk;]KAHHXiokg;r|RXNEˍ,RR/q-!}o-!JNs)1mUiZAD7/:8x:IplDikD|Z0$)n=6$ Qh6*Чf #<嗰1Z1[p w+Qq'mGyccry uuu]~ۥ{a0 GxE6 #m%nsPtr]JZU? I~͛TUUYZth wb.澪ʌ6/GFX%Lǥf{0obӎAѸh&ɪMvYaE%<~jAYˆxV~'xƏ.tEH)n'Hӛ,(j2`Nid϶Jp[pN-<#T&Eߦ;zYɗ@r̕tP4JR&n}Rw| 2%C 5jSwSVܡS5*Z{Lz=/$i߾}ZZZ>>>666=nPW5.[wpHEDsVmI-U[p1v*6@$k"sdIǕA*&.*'Z4Lڍ !f(t(nNyi&r(!yg^ҥ!$${}9z2 j,d75n$xV7Sn,psfI&yVrt.Z|9ʱDHcee 6LGZ[ڨ" ~qnjEZy]t… vvv~~~˖-c{t.Q?HR@GêVV;\jz3%ewN{udiN&|K3s;mlL*a iqDd۶mObss .Q?$Cl9@MP#A~<’b5x/;kݵGj3{'QF?W}(_vl0w=W0 CS;/k^666N6<>>^^^M_k3HijlBXs@$MN뙕*sÃB``84 tD s9o1c?+Fƕ 7%,KʋDž-$m+S"kdl6 7%C~ÇIKK~ET6 z3z wwӥ%57?"T3 0)ᆸ0^/!)bw"8N.AfpC\%[RHs{N,Y;>E6T FA:0y|ӧ8[^0M57zzY8#5M0"3Շt~z7x_y6HcyiٟLllN.qݿL%|;4T!.)6vށDͫw'Х6M60ŞqE:v_t?3 q1_q'… K\x^_:}vKKK6oP˟_<Bۀ0|[McgOƚ}eKa  cΈuIq) $$m /{smCwlET0l){~\Z( :tb$X]<(P>P#B۴ϩn 9l9ccμng}(l)kF*a`C'H"m9՝xLWӗ,YcGH8|[ٛwFLMX)˪(T߼pT))VܞV5K:W+9uifBV4\(l=XӀH =>wU0V_EAՄ'$JIR@P*g$;-FÄzJNB6r|wj^DsCO?mj*ZM]C; ʃNy.@;zFE$v\dݻ{Ѕꦞ.J͡'Aj}[]tՂ@y /{䀘. G8 K\zcOHH0333f 8\h!+6cd ݴy}  ?W;4heЄ,)@yɖi4aW۝~U?XKwwwu^:BR+ܺlD32awͬ~'dIǮ L2!ohˆn'J(5210000txJeQB-:41,QbRg2~te3wީ-6.Tߦ 4ɂlb1y ; M &.045S=r2j#߳':+SVY$|$TtĞ$I /u!Mi{}zgl,_Uc~ٻ*8S|ʝ5ۖQQs\>p\c"Dn5MS*Iюu{T'z{ @rQnxG w+H<'nI(8xI^{RRRZ\ '_`!5iB<+~|[Lu?GT"6><JNoHyϮ=#bNԚW>>I:~@:m~倚݈=+Zm鷑HCv=C~/>* W^\ibС fnG`;6#~T"5):`^/9E 祣 Ѝ.t+4˺p^P< Ao0 ƲԳ[| JF;%}&kno&};'~-v!(@P33X ژv|'be)9 x({t8}$M,Lϩqv+qۈ"X u$"%)% X>3W9TǗx#3*:ea5;;OX^^|GzCQ3{ #UUP@g ^A" #OKGqU|睑ɪp ~nȸrDwDY}Xva͗v|Og?eLϳ$@{{kd# p)e-jE~tW)J<{8A@x||||aFGxU"ΔEVtƲcL" Mllvˌ0oƵB:{F$uǂyOmf :BʿyKcut: zF\6Ŝșˆ:J;S/'eG0uQBBPdqxט"KYД%AAOOJV7*zIHظ^/衄_aJQ8E5Bv'Ael"'X(j(vaQo\{0=뫄j 9>.uj};XwQZtHK4AZ dfyS\ :XF\9J#M_ }XvOxpp+Q?+rv)k dš"%\}*cF n/P?($Aj rs@ m]Jݬ0JJӗÅcFjK'&x0/r#Bދնd89wK;2@ʃ~{Pgec$cfo&v<+GOD̝7KL-~[O Z ,m_D ɍP7﹨sA+ٍ\8J3E_}~"uxovatur%a {5+e-z厤~Ë_d//87Tx?kj@qz`hb1yM1Y%+2/A' 0mwV~&wu@O)cm ܐ>dgm@K}}'O}v ='gfnnn9eyh덫[l{Nx|z':YK,%aXu9_=/;>{Yʮ.6ff6ӽ¯lGkt3k{L2p^47WV|#e1 :IpE#ʕ+WR=ƜLq{]a[.-(,"h{ݚ]a! UˀO_|//;XZ^[_X#lb\̣B _g(0Vo{6m9ǒ[fPEOq{Kjqie]v읫Vx%i'I+'ju0JYTWgTn pb/K(-4ܱ^{,Ι)E ID؏ DӨ`,\δǁ,>Xl&Kj) ܿ8Pq.Kq}o[S`dd6Q<9^r/_OYk1s POUV%_S%O_Eyvp W3 ׄ*17}k9↊yxKMk#([8Y5NQ 4eQݼ?o"Uy'5P_Wzpqc([ mY9Uss~"⌇Hϝ BAFo:2neٳgʔ)˗/R7opBXXX#r6m˶|@ۂrWMl}V+T;vI?e:^[z) MoO3UHzʀPI?.pm+W&L X1cEҗI87N؟̏KY+ZxF/&;\}UEm2/M_chx=*<>Ub wC"ELe;"-a?$eT g>{<=zMa nˎ}f9w<Y9\Rƕ"}ZZZ>>>666qa IT)pMƁ#\"D"IJTw[^{4>8Chg6nHp U'|f `:طO]Ѫ?x$hxFP}6\W>J apW@YDDxYL,@ɻ&B3ŧܹQSmT"-A Hk39qMQZ¾9 locKHz4enx⌬l*}c )Y]9ub=YI>L7u1nCR(ዅevWWKtRLku@PDˋLdfc3w˒7,iK5T& TM^'$F~΂tZ6e%|;4雼_w QjI:t 1DExmM`FRBҿi)\pREM3"?}gruZ9 VwMnk `M % L:~ƚ}u\<>x%.: uoqW?K@].L7q_ # )@BTW=DqSҳa^؛b 4$$w;פ8˖_IP̾/\L8 :\vҞd!J;)}cQn㉂K}b9K5F> - )n=6d4@+ ;ӅtEigHy=\M?lvs/d_"u9 RNVLQ! u29h cłD QNP\VN'(8mulCHt&/پ4um4CK<ف }?>q/qC@ .Pm>`R[&"UowŭC]F Ǒǎ7iUg%=yUĹlJ\v)D?c;wNNߴwq7,8A㤇[.P7J:JX}~s ?=KVҕ2Qӕ'g(KvEh僛(%9dXu9Vtرc5]QwsOq42*'^)c/[2?%(Y>j66EVФlݰyRi%:J6;(KDsVm&:i΍ZRO.VM\2?ecNDh]//L1kv-i|$~GȰ'E1])R`yI+=*#!oVP9\d^9>Fe;KLFJ[ss3i-Ό/z'H쟓iUV&m[BQ,q;^M3^HP`l+s%9;ev)Kln!AE%șE-w8mlˎsU'ؑsie9+CR3ĉşgRۥ`Kv l|/THn %șEQ4;v]kaGϥ _5LO Ry9^4#57,a#$*A J@wHBQq,69N i)"\YS3p]M= :)/.XKhFDfV0|(9p0ی><y,A.m+[~*;k%.풮rn2=Z];^_z[,\]|/b6%{Vu">r01NlWD\dSѳW]K;,1 8S"xB6 %ݩ+v\:Os.YR/H=Ef8Pg7pO@36m5ϟIw></A>>4*_Jk%G qynMʪ.q8ǗlNreOr+'+Ӟ|`K !92KwsǑVxĜn:IԘ}Ǿlו4Օ<8%eݴ$<1 S% co[  Ѵ92\Y 7{ ::ύ︠/ dȤWN^y\yOfNW6ffٞ⧺rIdӒsuN_voF7#"l\L7 fQZq&3V7<7lՖt!Rc^oǜ8؟}L•7 9qI`2tþ)IlAF&qG}{oe8D,Hp ?M#q* 3^T-oS}mvit*l,x-ٺ쪙y…UVmܸښaUfѳwLPNm9l?^s`Q1?HzP?}"/sOޖ5QhT I3 tFh(V]j53*jgb sÌ9ƤMhY<> fZPO)2Yt\ Q=6 ^Tf!}uvְ' TF EvZ O/12N# C乘4D7Grv4XRNa"If.PKفodIrS6oH,i0G_>Ncw3r )1A̬(y^[OQ͜VW˞b YnCzc; {R\Sw,Q~-ҵp֜U2SDWN[ vixpQj/{&#ȸDž[y0o<"?ޓt2XQARI / n6aN߀?ѕ~EEIOۨ@3Wf2FA{d45!#R-tV֭>R/IH,\[ņjX-Xp")S@?ӕЫoUfm5?W&KWK ڗWzu -'Ow2LqL l)6n(3+)ɒj?|y>$q_1sw z)/Q{Dml9.zy%? &W-7+uJpk1ũP[-پf0Y͇G&6^v|?M0nfh71a2Cf%]=/ cJ DDP[-RK*zd8],wDm-:d#zykv(΋3{T #W?KABBB`Hj(h d$L}c«my놆F\۞kۖ3y0pa{E絻N$K:wtnoq\%#SRIY<#WQ/ tD s9o1c?> stream xڝXݏ6 _Gh|/vWm0 m1(hu,ϲ{?R^݋%")Ǐ\m{9{]Ea[m,"|~l/&#_:,+S{צ >^[4*KayHZHˢ|n_@f|f~_$j.JٲO/ƞl\qhG3./^naҒ c]s|޺e1DQDGQV$Vt('3VB; Wk~eX=_i#{诿6 _dċrX8~8L!~ϐT@JB᪹ endstream endobj 967 0 obj << /Type /XObject /Subtype /Image /Width 224 /Height 97 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 7395 /Filter/FlateDecode /DecodeParms<> >> stream x]{\WA"R*i**ZhG"PvAK#,Ziq}ReQlKnU($!L j+(,XժdN'$P 2wΙ̽R *W@b"CUutmmmCCC777www) TTT222JĶ"%cm9IA%!!!偁7nD/***{Q#  $C%caP^^^ZZuв2A-[;::޽{?nڰa/gvss]d,,W lll՛?~:(`ժUcJ###,[ wFq؏_FFFFFN酄$&&>zhgφgffffff{xxIqp/~xxdϞ=-BKkjj޽;c www___f/%%%!!aɒ%gΜR𠖖(..puu}ܹsgΜ$%%|駎---.\:hKKKDDɓ'~555kkk={QZZ︗o]dɹs( @444x{{WWWj''Fmm{O9L{ڟL95~Js lK⢣s…Zso,lP5ؠEAT˯^ Xf v(??~BBg}<,,ӧ\]]}CCC/^R}ZAFFFN8qݻwӧO722jhhTWW/[ٳgfff.̒5HRUU9k`5ܭ!:hcee%qϦM&%7]]QIG >}~遉*hÇ@rJI|QQQYYƯjgg;7nܸq=o 077p8MMMs-,,ljjt;U~Q';ς63m755t mmmXAD;pP(Wr,u 1cLTO Q_ԊK= ;>r;ccc:;;xBPl6{ѢEp$'K漲ĉ|>_RC kG#'Id9TTThiim߾n۶رc555v0s^^^BBBpp^>N]]][z|/// 5kDDD#yee%t\%oA!>a?OR$Лᔗ:tmaۤqPAOBO555:::!" ѣGZZZ֭[x1,~zWWϟ?l\zѱjjjCCCwdSL9s{7 nI k׮qܦ&"(?1U~:)tppյ399ᔖZXXܹ6'EĈ{ z?~ĉ4#ǏcQ`L:RTi1֑xRRRnnngg X~=J#( 0mڴǏGf}7p<~sN%ۧ/Bڦ9sիUUUR񴵵oAnܸǝZZZ555(SX JkY1Ebbb?N6dVȾMKKqNN:u~;''M>}ƍ RݎDnGtP$&fddܻwfIL nJ*JA|PW%Lf>ҫ|Q UEB!TOTED<|0NZ Urt:}G$I/UEĪuBZtP* 8vS|Pb_UHUuDUE(`AhQQQmm-EU)*z*;;V1a/?yJ**v J'C!|PTU.UE::$TUF_c҂¡d||)SpEikk[WWv%K@/$("B>3r u*)) x8dʜ GAX,ܹse,\.WUQrP*:s *JAO^>|cRA(uP:zA'8*nGbBC]%uQقJK.]|$>>v#'N=rȘ"BpY5iOA"A[nE...T*x@N;881̀K*鶶vvvXhPp k.okkꫯ򆇇q0"I(,,xNNN\.;ёWVVB}P ԩS;v[",n޼ ^r{L&͉c8 XNH_,$my}=o޼^\\, .\|A?3E-**jii"##y<tPzAI]Ç!omT|PQϟ? GP&عx{84c͚5螑{*:89wJZ(Mw߽w{|=S7|PH˂flWdY4G-頲)OAŶǯ>}eA"{(dUpߺs{s;o)OAqxu>ꚛQݓ'O\\\V X!Gk*>G@<ë냮^999/o),(1 oGU욣c< :;;Ԭ_~ҥ׮]:u*͆'˂Ν;;v1c~r/X%?a`sv䃊BNOOrT',(1Ï;vG8˨9JAILhl&nAQU$HL%!#ƇD!jkkK%lذ”΄EK;\!5(bj9Ȏ@: L9,W L1T~j1!@&/gC s,3\P2|d/y CCChIqTEI /I;.Čdff:88X"..]r9555֮iagzL1tz Q/,]vB2#MMMgΜ xeeeLLofmm]PP&Ėot}{{ϟʼn:DIIӧ p"ʤ:.~,K8 Qрbhȣkww3%1#>XN̡LJJO[ZZ/\YDDDhjj-++pɴvB'qHX5ER$bˉ9)'$$paaaO>7oʤ:*ICj444vB'!` ]a912ִ% T \RR,6\.799Y.+d>:RiX(KWr,p(g̘"4}||f͚pc*‘=bhL&s``W 7%S ؄WPLb(NeA8gXe lEHN̹؝eł5ףh-ǂCm۶cǎUJ:>-ݻ*r8S^^nddt!d2{zz6mDQT>fhh8ZBBB444]vZDr, Ғ_~`Jcc㘘v%PfD+ ʂ P1TRq]v!<ظq#vM 届V @̍[l166EWĤO3M TWW.]tܹL7 g ph4/AĤwЌ &!AbIN`Po߾f,ذa!!!_~¢onM:bby:0innfEW\'x:84 )snM:b ;wٻw޽{###WZZmpss%,)C[07t:ZKܵ߿#55&((]N lBq-D)b!Љk?~bff6sL@뛕eee_YYV%C)Wm8FB(,RR!%P"Rk砐 T*uBn^zlg}&_;vxdȡ:x;"""IaftBGDKDtб,|P\#Z\\ 766}6W>s(qPR8d3 [P$H%/ry endstream endobj 980 0 obj << /Length 1832 /Filter /FlateDecode >> stream xY[F~_G#\t8ֹs}bx$bža#|FK|}/4a)E1U+ְQ@B v?ʬ/RIWʬ3a/[¬e*3+ԮF %x̊!. tbʿ&Un *ϼ>MMz,\A.RrLKRBmULw^nOVtt9t@GIeoV4R>@l>wWV> hawo`#&*H!I-LsYg6֊^ Qgq?܄uI`F50ApqLRPExS: -@&*uHW(Kp|mحK,f˾:c `,d&ͅd{zUQV P2"{S6:S拒* 4-JY].:G1\P͘by봫_P49l Wpڕ"Y a@-.@/8nw<[oYh&01o2+ OtP澘=Z]7lEb%UEݘ}E\z{5 pl N<7 ֒%xudPB=^ wXHOu9@NbG guw^@W^smZa+@P풁#݈[]2 @CܶU;.~`fvC*'W^aq!Y&2y`f #ZE*cFBk Հ^Ujs4S l%rؚDaf (D9U 3= P ov"mtu;7+dtOӊRŠ B2@ Qn}=&!I-*aY =oSEcG>Ytuό=&BD#YhԩHVcxkhSwP?j-S fDLPΕDf(OhC"ٚ{h;xkx{W;s=zjizZxj?( ;{=O:~3s{c 1mZfXEI)j$3VբRtKQ;͌/0}\pE endstream endobj 998 0 obj << /Length 1064 /Filter /FlateDecode >> stream xWo6~_*J~Xڡux뀬5K'Rq~GcI.(|G}G*FK&oi 8/4+a4Ք;Y.O:&iO+ɇVtZv;^ X/OziAqA n\*!7+|&o?'lbDc!N>ƨޡee2c0oIҊ#%YV\6c ]$釺d@VE0>p()N.u.v0-saV3?4v|+B.̭);qy!F⯻s^(%ԫM.Ħ;ّ|-`iJzEDDTmHVE^VבO/Mc~N)4$fCBK;M~(`m_z*Umh9?n@ vdazwZ7]h^z7@3aĻt.:0 >t -a%IQ,BAۜF$=o!82tf{/ yM:#, uω0s[(ЙԒ9p4X+oE9l9co5ʺ:.?n:Bb}nX~MQnixs?6ճ7cx? ;Wrc;P7ch4CSI$;&j P4l`S (L KBE\0˗WlZ+Ʌ_[$.~ npjXʳ\oJc%g`v+-;1onU/OϺľo ?*ژXg~W%b˦\ AS1gwyaSNIT?TzTV,wYVmha]v?g^R;,Y%e崹_U*kx5/eIqY?!KFow'MQ@2G c}-hÈ NCӮ|0@8c2b,]1_QT* (J~yA92Sje̓Qo46x.GraJs0fU4F"l #^Qj]\:fU¿ܮX֭X vU3Q_5X5Xjfwud"iuf"$fڍ*jknUV=>E^1rz쨛QlRm,?͟L%%0oI'2-|͔"9$? ) jIAbWTWV.<9+2dܙ^JbKVʌku9Қt@E!4!Ğwߎ;n =hxR^ȌΉj3'#ͤ짯2. J3m/Ya᳛IwŎN75_#vq~Crk ^ϟf#L0 ]Q:Ӝ.g|zU#h1||jQWY c?ny7K؟rn6y hkjN朗,֗y1Y~R26 ٳ+MLpf73e]*ǂR555}lgeQ;y~ۆ5F)XZFt& M('j0U>qWvaŻdŻϭ > stream xڍVn8}WcXIh:>%i~gƔi,Qsrf(JD!$(C -]@( H8Z( hF 0 KO+%( 8PLWJrR 4ӕ TJОYY`4%jKL&ځCYPxHP: V)mcx.j𜏵9[" s$oZI x uУd,8Cդ4(4.2b `hNcSph5 =eEP"A4CvOD"TBWV1B/VS1f`)qtx[:DT H5rI#i`^`&0B/޲{F%HLXht)IS(6*;MbQED%@Jn#.Ua0NTJBEQS/d^&.*c^4G(FŰ(4Ξ{5Vf q3V]{&)n_bT_9 |ͮpYmXy&?c>§j?Ź1gWCJZosCqXPŦJ:!Dd^W C^6"521Z}ch*l>˪^8sgY;,{;ʴO?M>L_jC6~{R˛v5oc~_ulb;‡}Sq>ꚦZyX=T}מ\]߄3_Cb_s}?)r $]?0 (E|uf/YyԬX(?U`={L cֱݎGi|kfWShC7 aǷSS _j+g}χ6$cqLYS34qaY$D_Uw]sz/fT endstream endobj 1213 0 obj << /Length1 1406 /Length2 5932 /Length3 0 /Length 6894 /Filter /FlateDecode >> stream xڍwT6҄RDiQC'ދt$!PMI)U@ґ"EEE{oedgfywyP@8 HA AHi8M,lB5"@$$ Da$wPGB±N% pp{ wTpc09] ' .@C y##bQY~4cwg@]+OkN#ay@0p XB$4`~J'g"W0C!H/hpTq8~ iqw%~*!ahVp٣4kVA)\]H>e#ܻП:#QHw6p ? oI݀pO_NO3_o4 'E ?o,a} !`8 @`Ax-@ C!] 5b!mC{|ZSQ  `a< ?uGgf?$?ԅtKF+GYWwE\\~?AA:( 5֮8A H vV \H=CGP̙$5ȟ{8ATC CT8@vb@o0Avp_ "Q8Bг/PpD  P/r {Kp'0I9UV*0{ Im [SUFm 33JT?tUux/װz 9Cc&/{ܚn$zj&Y&IA)gmIWux.b;-m ,wM>45AVv$p)2eы&3W~doyCծou?I:v\޴ɝq6> JWLFMg4`M:S>:kkyMw,xa1ͯ'sVٷ5>$e> _̙}qSa #™Af"")W>^,0Ƌ)rMUD" 53>iOBkaUQJx} E+^WToU;Q(I {ֳhF[eK]a{l1vDź9ϏwZDQǛM4.]'+wMdA7Xwd=MQWੁHd/}w_.C2]`ăae=yjG_܏/? \{բ۔3V疝vG1u=e߽oәWZV:_!oCۚ24K >mEЇxN)oN؂HeSA_ 20-fEbo6NTir0`W_N47Ϩ$ұ;mޙI)>fQtcݲ 8ZiH+Xv V&lþ^֏c΍.s6V4wsV;Cޘ9J1~p=2'D7ԨuŞ<㗜2pM@Yݥ…ワurWkrx-JBM[m5V ^'_Vrov-vЭ$TH%z] ;%Y,6pv\zb-;-SZL5,}nۑAT6.⢵r7yݕ. |zAN} !"Rݤ ?9aݻD2rL jx5"rWC,BjL1}" }j#sS%8 Fa8.?pDw3D ,lpp}ryպ:y"u]b%w Wf^Ɛ? }1dzuqzPHo sU#nlCyte;]U_eU[Puxge}(NʺS~cW3ղ.ӾhQ|̹oh~IU5%w'JAJhyN%u.U H@ࣘB!h Qėfzsofbʹ*.->xOP%0mnrY,b`ЉAVeܹڿYwvL[X%N˱:Kr+ ns@: abVX.2fu˹o$MBKh\V'p"&qyg/鶐Jz.Ty< Mta^|[T53ڰ5ҫy]9df=9{3$8ǂ?3hRO^wžIXAdrxz=nvK7ز65;<,:V}FPm_!!1gό2zgw~fL|ǟklà}O.RbklڞჰK+Ex96TސXκ٠1?xvc}J;^!N?IS9Ӽ=#Ճ^y^l>c1'? ڙTr~}i"d85 '1FwcU L&_FQWW@nQXO_8ygwFU&ڧb^Z>xѝo>SNv&2"SF~-mug"9gh$&iI৫Ԕʲja|ؠP8\5kAL0jÓy?ugNrw&Ң|#TMvݺo (ڑ_2{unyєՓ\{B5rV~&_w:(9 $eho©fN%\>eڵJZNc$+nCϷ'_kdRR+6q׼PWq^[6'I!*Dkr3[ߩW\]XŁ&q*Y!%Y ?Ɓ߰k͙NW8u[GlB~JokR*I 涍SWɰPC0"J)|_߰4|xr}QrĩG_!+ ]8@7OR%x="Kj2]o8W7!(%cX뇞j炱!ԛz!i#:U,ʹ a0]yOosVRΓTnE+tr]KO!ŴZN׿ze،<<^^a?4td)>:d|Ǚ<7pO!2;ZjJ뀲 *^2,x1&<٣ؗ9ЀaI7b" *5̖LMsdKӠ8ךܵ``Յrf%7SPd+gj|{_7x_KX G0~m[hh*&Hgk\kYz[waAUX-aLMd67l)|ml͸TwO|]M3,* ᱶXoLVԇNlkcni{[K;JdG69E˥d (5 c%۬zԅ˃[\katgD vo)7pnBCgNOVGPC9W!Y\ IjyӠ]r,yf,v$.qJ>fR߲2m Knמ`IY7*em_oW ~Pu+=)5$]{79yc1{7)RkWGM@*)CDshODeIۥƊ e4O<'-3fn_hKy5> ~H7wkfysn󥆣Lo`QXUh{ƣ/³L/mt[PV&&`N Hbo$u1i^ύlz>f~O)V ވ9 gnrՓm2]:R}^6wy}' zHyZ0Y:Jk˯2+rSʎzB2TSeW#a,=knBCZ]Xw:٥;Js#*ef11#I.neVpLP gQ48;utk efTVӹjv0”<'"mD͍`%zzQ1h%*.EPy>ΠAl2+.\k8!C/ۋ5Z&FKXJDHygf0;K;e4Ë4{mN01ܚ[!r,MѬδG {ĠYpi)q+@ҍKkLUJT<ꖤ r<I[V__|+8e<QCǚW$QOeCl[=ddW$kУČ l0>6)j%hb\!{o( S"!:aB+>R]iJT|6xޮШ&(d< "./Y99Kջ;Ԓj˚_&scO:柊Q:)N-I}ZQ&{MbxK9CEWBqHyuY'`[53зDV[0|{$DNLܑAI7{~K}P_zo 4P30mҠZ#Rx>ZZsf!w w d+FUGo4Rr y.04vBOK+ kݭ' /sXrϡ+ 2>(f~h<ҰUY+mAT M8xD)p;Ys!%W0ƮFaI?W'=E@KSJq3IC h\uh%T6e'g'rJ$mjnLv񅦁-|ۤZ5-?&H=>=ú9>LmlksIGtJdC._?j+)4/y c9q(*?eM6BRWO ^^37B}SLBsԨz^ftP#F]+ re x)G? 9m5h=xi/`g?.Ƌ1&X=י@Rʽ1P)61xa?5O$9#jSە7~ڤx5Q*vst/~ts0srGiKD%GhِWЯԓЈsc SYɦW4z"(n*KEs_0.xƟ޲N>cyeG{,: YMU~OE]5 ;{\c=A^.(0*{vTDMߥfgҏɀ{'*I u!d+h#g v铲.ƻ5_)w< phUq:M<}mA^O=̒KP r!~V%3a؊ '3qyM, huE]oM),&:A> stream xڍx4\ڶ Z}Nޢ1#ft-QK z-Z |y9oZ{sݞڜl&H'z&V" D89Mah8o;9 C"dqDcljh Px1@DBFDRDA 鿁H/@ wSsqEc} yiiIဲ vDzhW" 0)x\hOaa___!GEW]c q~ ;z@&D P9LP00„x#!^:` xBu6W?ѿ`#p080BG/#;8N e#3P`/'%(+ fΪH"՟ 컿uG }03ޞf=o Do  %$E=vUی!8 @1c@aP(^ސtsE$"8h C;; Ɯa'~}uga37 k_N((* JK @RRgCG؟>#VE٧[?Ka.7A`EL!?;y?~G\o4FzH %]=3㿽hG.F Ci Ά04/e778 1D`0(|1O]YWF:O9kJ̀Ƅ(ҋ˜(/Er#= <{[L0F=b3&Lr5-U! g3H:1xQ.- ؽSoYQyfؒ?BsTQLyЇ*pQ\&@Ie=zK@X%k:dUHo!〙f:,Ų+w7 s>u t[d=oraLqQ!aG${Y)[S-l}B+(rR**構ɇgJ/M^S3Lް~èu'CaQ;nkW };)mCɹ"f!TA'}:i\dk Yz0)䧾.-?SC*M!2xMKxA83AGΓVЖo"6g7) אc(+edO-[{jzmxVW*[)Jg_X^ۋxV $󛦧@^X2g%`|XφjKm*EK`8-P^CEFC'n6|˱OBk?V{DoUDT O'iHx6ͯ?39=dy+ܪF󽮠a(?0hW`GMJ8Nfn-#~4:MBɚl#ۢsd%Oi "+j|k̥2޿c9_oJDO:d/P8D;ONIo)kaW7.R;kk"}213nWƬ:?L)n>ҪiPN)lȝtRO GYIj'\[:%CT&YR~ݡXff=`7*h3l"I|$"$.H3xLu| Ps}w"Q9;|bp% V=_^z:T"ހ`ANmwy5Jsf@Z;{CeorH% ,}:x>>=sn9W-<3y9+2pښo.f#1jd*mX {lv楷IQs5+z()z&5{ }|Jⵋ}qפwlƪ.﷧dG_@2?N~Pt39s+n";w{O;G,P<<▛Z~>'M( KS9K)2)+VZa d,cd;u7ƞ t|\'zQ 5?y܃8NbII!sSÆӁ$||TeD2S/JLOEtJkj^ǻ)!`D52ދ{Xea9sγyR^1?̭[j߄yziT~mXe0m}^ Ɲn6y7cnYe׀Pgl~SY,\ym /9YHIǟVY fD$TKKAr+ϺY).TgI1 dƮ0\]yz)@ 7&JıPyk]N{tNV< R|+ΑkX8^d5ߵsP.=Gi4#e}|Ws(8hW\hp:U\,b=YFuҍ>:V{_k>~d~[cJ Ǭ2EZb @YٞB0u ڦ_hY^Cg܏ D=y G''muk%x8+:XA\J ׃+mS.:LF9.8S3|$%f"ݝe bc)+Uu~}}˳^H'bFgkrj}{#ߞ5a"^;Qsc$ɽA3ՕM1}]kTw`*-}ܰ`b4wGGtN[uC$A5<0gF\&Yw|闔*Oh4=}j$޼֡51dlg5KO*@CM‘96jeN ޡAӅbMyCM6#P-B˰k1"sw;Vs8⑅/ܭ Xu8#H6,Y,)MN;&cA/KMÚE}rMz ka\%U᪶bii, t9Ωӈ4)7ě^ćzÜTqۑt-噗 3aEsIdاޚ:.Yd{4^3=zQNDpP=Ha L$}dfJ~/ jgy?yvm5kK B C{!%kUekdo4C>O7-JPrY3'͑0+>'~{y‡$uxz>+H*[\TuaZqG<;`.'3xVIJ춄zK*F@sK2әF_]P 9A*p(@8ŽI4e >N"=Nvrr $57' ɤ׎tIW/HX0wgA39﮽)j! zOcZj~UGW4}<9H#*эw-NiGKӬHvKo<U/*СX߈>ZqZbf򔫉5e2)F+7o4:«e8 W 7"}'Al:bqvS\5@yd=@o5Q{a߾9PTxeTjKЩf\xP׼1y;˔Iqj+_/r(\$#7ƢZdp}s.֙l?C51%E}feRi:W?vzim;-{.aLGMe 4EZn3kr/ADO-КAtS5bMQ{j[yl'f9p!"K?9 D)_P9PHW8l+>-!p`֡d/RƯϙŸK]wzǰ?gq{Ѱ),}5%u>}qw6G0Ar[܅(qeo߫=X_Ե+<<ٶlmٻoݍt#~ zH,3769ϻ-iuq|.:\tB^IK-vg%ԤϷ̴N9֢(o2}c`uȫU@m ׾wۇh j΂"Y6)S W!֫>w_A@xOb)8N sv_oB>SΈWoK$- Y]}~ ie'ժzJ]sWi9 d5[a]H@R:;Q3i+/w^Yށy!aRR AD{KN hB+wv7>4O:6FEjZ\dDUQ5>]rv D(n4o4v"fC|*?ĈtR> stream xڭwePݖ5Nq=k 44-Xp N N}ܩͯ-gT5&9XKbo.:\ 74 , [@bmxO_)stX;_?xcmtE:,M@10[QE-mA.E*{DJwݕ y .6 nǪ*}e,`KFT\=9zir@ RH/}9nmRz'/LL#:'!+Ll3GlFbro;1.^gDaUUb=ww\=@|Σ0YVN2Fɇm!n 9vߠg҈/8UotH$(޳.HI܏<<8Ne&^QDZT<#xӠލQԁ)ܞ;ZUf1CdlVB XP"$=mB(\Oz̃Qɝ y 3b]1zG e[h' JӔ+G\_(7e `@|V ho ?D 2e98mOgZ/(e) J|OtPRnwLwGYlUenRzх'LԖ!g4 fу^aOk5I|aUzu,œ\|^'*"+ U㊏K~tJ>^JaqR.(r / cwۻ˭}x5yIbܺ8={-M'e B 15] pP-ɵ]d9~XGjmdɃW!Qw#Wg-݀T;p-SsK2ћ&VyDz%!܄!~Bֺ\>K=S ݈fhI44`C&k,y(S(.$-_{{?!$1SNJ(lD[9"ח\+רIf9NsNPF翕ô)\ Ll!ב\(ӣy68Q"Kډr=fr/ oL~&Ql6 B o‘~iFo9@X)׬N!G؎_h?El@e ;m%Thf!㡓C0x\oANA??O먔noo"BO`Z?b̵Θ13>Mw6 ^-)! X{72qv *['ƈ` D>uH٦9 /+5eR>dKoN< *zq.x ׻KlvfL"0?VYܩeYI+ٗ"40m.ꕘ[,BCҗ4IllgrzF)0/2/F;Cw,ap߬Z솫!c6HR?{눪 D1b\5._B˕sPh@ׂaHxñY_4{XwPEy>TϢ*!^ѿ`YW<4+4JݝgLrѮr '?x1B!neUxp!% Cvw\uvI=f[g 0 \./J|}zW7": K<82Ǯ)L!kPnaN>Vcn52D{tHru'BdrFqbqRj?6E r>Z25t m0em1D9)\=% Z撗2l~%t:9ҭ6g4Y !̰^%{\E} <-4Y1\&sPhE\ȚAuC#ˏ8K1V,euҦ2x=Lڧrb/z\'--u_ ,&(ϷAcA-VnO]8r cf*;r(PvKU@jq\#ٱ xQt-K U)kƚX.LV 1ER1XI2!7ׅD a8( KnLGwYdNj"/ R.`CL%z嶉buJ0`0rsRa4I;8*8VdX/rv&cQ:ë)lwn=(㚞(lؙjuj ;-Rk$?mRLӲ&/2Ċ3"N< lf ڨ q-Ajݎ&F\3#dqQ/`Xl,S~ϦXK嬖=>C+;u3R^ξ&.t[P^9T_m̂m1=ƅ.ZGK ݽһ[T Oyqq,a 6^u8Yon c16D[M>,}hC#fh@.ʭ=7ZAS(1"妮 uݠ\.Y.89W]{:?,sԅt;*1,.Nn$.(&:8!rO'Ep8/9x7qEQdi:R}Jh=fqD\\vزa6b { 8crV!<68s'|JbWRKgys0ڹdB <dql!C^y;G`BDP[G|/V;n83l\Hq}H-y֧^ lB畮dyW]2D<\aUTOX>y}t%Ш ڎr>vA%H>;xD.E-ePmp^1K4^dsPgm36ըD;q5}.1?cFȎs',AbnKt+rDߦ#): MlVMi7 ~wϗ-hs4Ioz"$qQE:fv|8]ug{o_NG~'Zp<עoܚ+Gxe/6H,yMQ2wRhtgn" _]HN]BS+sf*U~et@~:O@':vUԙ R,fphP`쇧o}3I묱37/@t,oEq/cJQ ueW0o 좩8J\܌kIs~iҎ]Y%vS蜏]>?F7כjdu&EK9~Kh6|3i00r"^H.gUE.)N[Sz7832 F̐kjO"z_^h?Q3⋐Ovˡ {rZf!3UI*DlݪS 69(hL5 ~?Q}9M ! iJĞ=u_F d6#~;_4s& //9gchW9ds iOd#o6N<*@M`jWwv5iÑ: $P@QcOqc͋Qm^)~\ږ8;_wGFYX4ǴK&=@22˥UF8ǫ$DPݾgXcV0RX{Gsih]+N隯ѱ"5^m-:Nӛw9d[ʷl.}o5^=N;#$ FRe-snUMi٣΍Y`aA)ԕ?Ӵ!D|yLg5^mO%^ǸoKg]SKԧk̇k:/B]kgmjWѭŪ5zG9}Nb蓅Ie?eb7+o|ui>h^ʀ^SjufTU5?UCas uAz*t95Į^Kj@hgH_e I6i)[!=\اbQ?hUhL˞EQt}oΔt/뇞PA@cp <^WfnZHJUY-4C4,lؘ-ThSvދøRH_@Q8zp.RoHسooPW\Ia|T_b7wln>ޣKe{/%-6KW\!Jk0KCj"J=-v>uHhW-]eBr-SR{ψ, '-(B~ Axӓ5j0- +mNjfFdA$$nլ#*),/|zfs o]nIa ?9uJKd\Dcj,k v.SB÷=@Ҵoۭ%y.A$ѕ3OeK⊝&.IQ7Gb=VS +_riZKGӷmj4H*J3F|>Z/סhhed旾TV6Ň`- ֙%Đrb[Tl@ t{Y֘G㈋iǠ#uQqj} 2 9쨖|CF}a~G`Mml%-eUYf2.Va$>9-xBi8 %T&8y) !y^P\/e&)z?p 0>76/-I7ɡ$IlG-2_FQ4饂u(Z"bK;hK>uilYq(`o/DPW&c}Ccܺ)wH3ˀ=T~H!1lSf4\]$5vq %yvƛTXȪ xzX\`χiVTrq.S9<Akm3VQM_:H+i|DC>ā$ Ɇ- 4|Jwr@v=z7â؆d[uMĉ,/'dtȭ.wSt+E؆1&HL= /\1SXȾw>Σ&8S5w 8q Vhqpi=%ӷY@>^>NY>SlB4fnRYuqQ7s7IE^6T $m6^JL{=q;U37 K a dɺ!v-%4G QyrCFmkԙ;fc;H#(b ou3&F30bβx{t~:X!W헅ջC03=3-ʸW`;#ӾlKݒ`;%m9Γԅ5Leo񫰰6;Qaz88uWps~<̳*L$jtFnA; ^8ʌn=h/U^z%!`'?(P`=8ى=(T[c^׌h0}elMBJ <}n1Ia=]x8o-5OZXؖ1)T Ӆei(38K۾k9C`Ds5TD??P򎵨IPjϟd9p oLUQڈVX&P"QōՄǡ{JXTgl6>Bgi݀ch!sִi7=qigQ3cH!G~*Nö2/g80?/_ :L}ϲ"۸!i2Rً,6WEmֲT;f7 ^pORefV )Եiz*eeb18/zXA!?DN+_ [,V`V5ݟ}lqEuljCo69\/i'Z(go()uA,^/E[x*#F"#"IC@$ܳD7}3氞'Q܅23)sSưӘwݡs>cdǞ_/30x$2~*R%3JiND+plL*?s%{E@k}dMK4ƁlCk`°͑m7s-P-z阨&+?C /YLIaj4$ r^*qv~#bcyΐUb]"'>-D*4 0= endstream endobj 1219 0 obj << /Length1 1612 /Length2 11486 /Length3 0 /Length 12314 /Filter /FlateDecode >> stream xڭteTے-A;q6q.]w n!xxsߟ~7WfͪYkQ( ٛ%A L<+;'y{ dAb@& 4)`+ Kg& --?=L<3~|q;A냪@ 0D$Ԓ I 6(ZL '  0Y՚;4z?t7:8vVNN+'>g{/~s 93c`JNN`+g{U%1t4v{`oifoWKaޣV '3Z&@{w04\@d@-f@'ww쿦>{c[O_ ,5Mk[XZi=~3y'alfKw*3D7Ho"_%\lm zclWp_5 v6~0]&8$܁fJVΦscIWV ໢@/15K+S_gG2W"MQK^MGQ_Կ޵wVpx'ۛ;ҳr8 r13a-o r辷wq_l 2{_r6uUƿ7ߋMWMy2ӝks't{JԊ {~r3z fhp'e˖'xOCFWyv+A)RfżAG©V0=?k?od_XNF“SģTc#C=W0}{9pؾ'$IF?0OnۼʁP IQ>CM^a_9 q(grUsXƊ%h&wpp4?[[&0tY-1e{l&@"AvR)S_.Ѷ9~j`L$2nYokƇz\%̿&$뚶{rhdiBzf xx NjbzC4=-&-孳ůH$0Cw$Py\-{Gv5zk; N\|"KߧQusROVH}A4Kҡ0= :9O\6!X8gYƋ!85/UKe>8{E05ON-}sB(! ~;4쥒|aDeX0a[ꃀOmtP#HZP[!Oh$m_uþomjh5DbR$IGBK2?Mklk."<[? B"(SqQGkxF&ǞÝTf h" }ީJ+yVNj ߝ~> +&L?٦%~a3jԏ{f[43)¤v~_!ӟD%2Z-n~@O 66˼)YP uZxw:P\v]Z>DhI9+b0ꓣd_|Qݶ=> [jm] ڒH 􈇿OOęu8[ʆa hel;7jQ>v{ Ψ38E"])EeڐSƣҜKex5;o-2"ЖE>\Q<͆X}v yJc[2& :J0A˵\+sZRx/V!.n챜DMQb Pm=\=AMO4y0+ d<ģrq%2$o)yRrLUGs?xY=qwYξY~:D>|myAG>`aӝzړΰH w%~6hK,_du4֤f( g~v":rɚtI,Fnptуu8K1);HKyZ51?$O %qf8ͧ9oO1Ukpek1=ĻdlޏAxNhMSPt;͕֮#U*OaA㹕ED+N Dp23%ѽe%ɫugRj,"_[J\ݙ`0eӡA]9,ClF8jq萈xnѯ!{p\$?\{ q z& vDw|!faKGLHCŖbXEL8J,@BWe2L[V3TK<h6Ԣ 9:ngߣI,ҥ㖖Iv8ȗOVM"ǎlqG-:q 4#O|4/ NۏUBw?f^џqt}pwj.|hv!#cy}|{"bIFB:Ĝ'WQ:Zwor"}|} ;r2y`gHa/57 c8 M:C:HtR<ƣ?;2'Vْeߎ! ɎWdqLH墳ۂSSchY>~_f$i{S'UzZ-RMM`5]'H3jjN2ChLR9}a,j z8L@ M/4L5e"c촷Y#7K{]8RMU_rsۢYZ>U2 J@K9Pw_$xshB|q J)EEʈs,b>E\Ar=~,p|y#Ŝ+dʹ))@pAl"J7M'mHZT>/u`*6ub .N ʡ+!ŰKQ.j-k&@-[ 53_mBa*K6 m61$T̎(3Vӯruǿu.oX_ < mRT a*\,jt qa:WR tz~-Pis*K7!Vkje~2hl_c0ی_}ə~*IDmOl#م6M"qP8,'-| 3-QWPZ,@ eml /OS'**-{X ^:-BEx>gɄdF"Oc,4e;KO7&O}D b('$=֬j'UB`$(ێ^^Vm͢l7차] qoXT›'Ol(YߌHUs~Cu΋V=TIu6Jg ڰإze"< *PKJ?5|SEЍP3@|5+ :jjAwPfQROQj@RDZU vi7#L.~9Esm*rН!D:ۧ#/z;G8]D(eZMZ|4"ÂneI}9,x'p{>ctG#+H0\oxrE#hFD \~u׺|Z&7kEU~ste< )`'BᑺbBjh"a&Iȹ w僶d:\SShpKMu9f~ҶTA~L*j:WX5FG3@N}VW^ %e%FM;lN$PܥRia~r7h" L ͏G,C+_VBDB<*2;jb¢Dk_CD-4.e' 3}nF!4}3,nE_^߂<0n%ɜb 1rleݾd?HPcRbz:;\t?]HD#<@U2pnq92 r u~F^l54wTR7fRYev(ز$f h{PI$'G H&bh?/iiْ1 6E(¦1*S[L.ldt!0hm1ft;]f\+ -ⱋו4?g'C$^{ `.Y:HedN5N NV‰,rִˬ0Us h'aj)ddāU_"AP>*Sa܅-4Hȣ )DH<^A@93I5Scu %י"pji<}[CS:ᅆ1O9M=yE  1qligyΚ~%9,,wCOe"ҫƤa0:\lNIYԷ SܛL߱榔v+iJ/2Wi'Ch<yԧXh$7ioɡ 9׭jTrx!JYguR IhNjA[A sL"=hH7Ӌ2d"8?NЊqZ"uFEy;u.Wrg6mf}ϼqqO`!ǬkHɚ#)I*jw{<K\ޗ8n`~uh w P!rb]]L"D%N6گ4K8e@%J~%n_/l$,8J7*N1#땑!tzJhqFwީB.1-yqHHJ!vyAMI j](B"uergʝК}z5XKB<"Hj@T5۸FĐϓgsh>{ƝV,!iSȞ; +zpq- &cs9ϾCղ98s3jԡq\L.Y攦,CݠWZm; %r!Vt؁cΰ i%1X mJ0brdL{ơlӃ z _/DwX#j)z2 jNyO״'$mӳד&L n3SoX6mRjD&d&")&ٖq`c_7v %H:Pl('@8hX؃(^5v2'߱:(o&ik0DgTOlhG0׈~ qwcH)N/]P5FG"#6r(:2btjhAߔ#) q(J(x)tJKuB'Cksq:\h/h/_^65 \)VVpISi~Ig*gk "CC}DuR>lp%[EK+;s2.Nki iR*)Ydd%IHwmXr` w [c\ܯ-qKh,8 a5Yc-'^E{ĵG{2b0cD长 A%9y] <sÊȟ=~ '0v'_(:y%z&CIg']?:T%s'Is1WbC "lf.xstdR$뙵z%YC#Y_ByFL:P% o¥YeCu6Fݠ{xcͶ:\<{S}r0B>Vp~E3%?ܚXfzk+![} }.2y?NHS)F7s&LgI0\Y|-U.풶<$sY{ğIQ)u)dn,u(3!?:kb/wBܢ9XTO¹,f3ojLEJlL mMd;$" B:3 C͛e0uMB Yvw{^|D@)NgʏYTtYp4'?iŽ;.S)du*)_4laG#Oͻ4i?_GRgWP%?|sdm0P9(y srZ6܉MȬ^abn}t,)S{u8ceNsDgj}V4,J6YWLziq|΍bBXXN Z(|*M 0g2VBa_Xv雨GJ_xd91Cv hgCI`E+Pƪ:*85in4%'`:Vp )Ei S 2}[Yq_v7ivN3Pfr;bP˕}[P{A~0O \,>qXK 4n@|InQ3{G1(ȇ!8O#"kh? ýn>PWe '9LE'~7+VB-fi覭(yH|a ίǍoWL6Cze +Ic #ԅs+>!R6*]#KLͅ{blv?q3&}8ŁuFaf7䞕LG.y*ZYFIhRVܞL!|PnȂąD98* y$ܷdGz{< 3E>66f^{L}$·¾Fe59<&ުLErT FX/9r-/64QE(Huk&=}N06߁xs.XX'BegW]a}A4ꙓP66*k N\A,JWXc pXd:{@alHԧbS,ϩ*@̉FoWO ȀQW8yv8BAjd.LM.p#2`3 # o5Meatkq}W7%7AgݫkpPBB ǜIO!nYV~+\Tgy(CAs d,qgb_c{z,:J]\u1vHZ{B"ԨC5~辜 w B W>_n vL[5# ؁k-5-.\0tʾ!u'CI~t g*.qm`^`vD30?gM:gC)rwN0f]&@ښõ5xr endstream endobj 1221 0 obj << /Length1 1608 /Length2 10728 /Length3 0 /Length 11554 /Filter /FlateDecode >> stream xڭteTݒ5Npwk\;hq`'hpw-]?̝u5sm^B5 }u|DDH`VOԆ[_S`_S-7h "$)nЋ:GOJᬏGiP8n1:葶($xעfdvyƨj  :dc|%Vm!v ( =Q6v~P)> ^ J4;=J _Ӽ'~;l%ͫު&&湤m fd[#>ͶJY1kiBd ܧx)ʩu);Ln^;d@GIЭʁW`>F8i°{_Yb 1VsrI攌A\9& Ym8qԐuxɖo9$jsמ.k d}V%1\FnjqADS#fPXk8dZ0}Z]**E2A_faz,uv>iQXD5(hSZ'lD"ၷ[ȹKN-ƥ3~wFkh;R:-fb,v`L3YFx3EL\MWyB!|/7hA1U]B& 'C$:EpDyUydFRVJM\zp@|#o{IڶU E&dlQ$w.+pTvmW9M3cKbP& F6.yf ̹tsb-i$ٞ>Y&$RK&yT55V:i}hj)B, eb aJϧN)TwFb TjF&jqej~9 s}qzz}_JaDԒ+_)}<:=F;V +쭀NE6z E\i*X7ph {_,Aܓ)*_Z7{T&4>$k}4=/U2Xm:#dcEћCDwKIH~ K3 "T,ruj}ժa02@|UJNab?4MJ9_ ؟$hPbRk £`9Z!ЩJ륯Vg{N`"(e.< 7,?>FMBzCNKFo6hG+welJ\ 4u Uk\L~6;v>aLג~y_i(6eg&2.κF.1nnڂ?#G5Q:aiOçKr僅OH'6 C r*QdT\꣔d؄݂: r;}w`Wb,N WjrA=O{K[:tć0{(8bp%j{?P?D 3c&=\;>ĬKYfL=.]t䩖kcp$h smܯTF)|;M1ZW6)ڡܞПqȰ;5w$:jUFa 36\`՗C6D]=7z9COJ`6 ߵ:\)XMսˊ$^wKV]Z?IM5csZJ$d4% i52e=N㪶u5 N9<'ڀJҘ[lh1Vf?h5)׿gJ,' tK xΙWBNJ N $9jMdY}:HQN cV!뜤2iyhz:|`$ꤜ`nQjVG4D7s2*O,oD~5KH߬x4e?M1s#\ՔR%Jư"kq"V8y{C.-N(IoqdxLXG<̌c;Fsj\5}}_.2naSrشbB,+G ]tY#uBz/Jm el1J[UsW;(yXDH::vM37po\@.)`y =A82K=pycϵȒ>_ 翵`lmǕV\q=k&J5kӲڼ4;[⻺JZTv+Kb=)A쭝ĥY!퓪zdz"5H]dhѸNB=%YiN)%^>W+vYGtr7e!{ c>Cis/~c7Ev޺MsBY[`vlHO~n?*O{UQ TB4!5Á{Ƴ˝WGIf˩̩h`W^JnAD'RSB'/_rxʙ;?aP K@: ~I8{m5;LGIѻ?$#8*0^}n~]Cre6[rugXZIKO}('ݮLsA5Nb-<$:Dq%b^b} rl2'.\mUT`,'N'W_XiD\L,_[@yҲs](+xb.K[PkSQqҭ<^:zfp3c: ?/h8QϟD݌,b,uÍ=3}VY+b~GAOGww`Uy9`TEEx- >P)=Dmt 1FX.c[U#Urp7먑FDC_|V0kˡ^df l"C$/f&IǺt.>0eWSՃgM{pW6#X|dRC]\*mNmL*bsϽg7oȔ\ έWwֿҷp.P>vc][KgҍlP?$F# `OЅ g'SPj<-6oG5CsZޕeΌ!/yrw1w5$ATP e 7;^y+hIgk%EVpXǡU= d6C80hΓ]( ǫf :DQJ8>Y+1zG`ymR]U[pSpؐ;'f=gVw_s8>߼{0_옙76 <>S4|luIhW[ɥ4p~:waϖxECeiŁBuBLnMhM)ҖӴQI|'",VǔYLgJ~g:eVG.XϜ4ȶbIhzγMlHB>RXhxǵcz@~ E\xך_20f%My9Vq2v7s@Y-lXiIEl0`޷3)Yf;c'Ǖ{Uf QNrHj}e|,kj<12*zរFf~bv_;\l]HJ:y}߿GD کұ'EIE}DZ;Ǽ @ RA)OxA~:r6; j#.8i4%RvF1.UGހ]F4 tWP$2$ki ۸4 |[ǽd/" 9rQOo唱>PɞQBnZףx f.Ф@ol`;j= tÉgo!?C|>! M2'N&4۹4LӍ)1۬xkF.~ Xnayd!aI&Ca tl 'n_)q Rsuq6xz0 RR^3^z@z*ɚmf=C#DBzԴ9'? ɘ iI(So 7%)E6z͇̊Yˊ9ʨ@JE7[׬uM&+A +Z_?ZKHD[YЏ$ޒ REQGH<P\TQ+ g ZsY۽XJpb ~V28L,3u(y+l.'TRXjp ]=rAJ ϒTpPmEA[JBg)(|̃& ةxzVw%f`~o@%lUh,WKR`{teWUS8^m`qLtTZ3b Ï@-Δ-_i#uiSB?{9FlCIj o\ =;`KJXE/O qXRovh^K7c=r5up+ c`N}[>L?jFӏFGv0t+̏Ԑ0Em;@!.1gO.3@͸] ӎc=iWWCenIo~+dzyEZ0+6r#eqJlA6/fS>)L&5 KM|\niPh"| "ZPZ1g--L*ChmK$1 q䧋dUW<~Lؠ%# {R8-ne6/utup.U(FքGw uTzPU!)&4N;~Њ*+{,|;}"݁y9"DP#gz;]'u5 vm{[=z[ !c^6gK4Fr*ǛXA08͈&TCv+W|G:q^;P6r/Pm/6o@cG$p;!GD}bCn{gtGw46?FI yW G^F[-2{zdG)5\gT?eBK< yz49C4KqHs֤tLg4<2%GJ)S ʻxФѧ}&q%!${'|%?sy=t&-\e_ӹG\d8+TW?v+'_1꧳1ic^JhHܔЅ'pfd˩|d t؀vռ[gx0U$gȔ$\x ] S8ʓ(׳e܅~v?WzXxss{ttc=Ss[=+ ċ:xN'ѓ@e'_kzo_W &If_uٛ *0@^pxU)~2v3joNSƩrQtNϞᣏ=!{ Vk R3 웬uw}|[겏I[@ DsnJ5#5qKD2k_7%=I*Sa{[g-K)Nc`Pa, #\NJqGQ=+*KsQzIvoAL%hVwks5_FRN mVhwЍe_I#'hqbGkp|bIX |s{lϠG;xԾr0a;B&Q\OF !Fx(9 S"3ZqЃX@K`&Xs6&ym7dǧTVʼ+ aUϢE99.eP(`؇2_;D]rjd}R ~eDCy_b0yL/OeG aG$Y$(ϞOFFN!$ Hb&MۣQ ^WI\;}b[i> stream xusu\ۺ5%-ݹEIע,XA,F@JKiDRB:A.{{>sI׀OaVA|@~AI6fn` ;x@Qk\6g$_r[#!5вv ⒢n]7 #nPRBzp #(3G3?)0);`|🵛ݿ?h[7yAg<{mqgRN헵 /6{0BQhS9ъ䟉(;VkNU}YB4M-$!6`/Mb UmwSŹ),h5ǧڵySB塉m}Èl"&3Y,OPOӵ#(uP52?uˏb"N EVꄜ$lƝ\1/V|]%&,j_̿WSՆ4VjB"[6#-q\9Go)sri+Pv;QlEv0},(]dlbzMJDSe@`^L:~6JQM2]lO8->/$Vf;2\]3OZa+SR mt#N l 2~A\#cTJsزpsy,-,,*A jvd@ EQMS^dc_w->n18vzШGÓ}RVc2rXfI/[EsZVн}_H'9@[lE7o^m&xma,[%X廼t:Eb򂻚5wnc#H)@naȸyIiHiދ2˸1g>U:t#-ԩ)N8 La~c_׎ZA(ի_rJԕE͘n^R̠y,`0P{bŇq _20ﭒuJhbާ,B`)&4s՚*.IW1Y.YNJCpq?],aJlXbi._g'5-d=ȁpm.ơ3 t )ZkWjw9o6$ⵆ;Od"ĕ- GLV?ۓcհ+RG.n t@ <\jw2?xA])ŏLWc AL!F:bW:Fghe}h,P[)JJ\7 xm;pM{-Z9e{!"骟8I5m|1]ixA73)4ipSX9qmRƘoŪڰn1M"v¬\4AӦ(\")0 7ؙq▃J{ةx"fGj\'Km:_rNߖ"c,g2wq)@tADn h. svug?G`|TaSGTn^ VbVgGj _Q{!D3S[ȓ3[~\yE%g͚&$,En So:X}cǴ&3F:ӲV+b3*"@<m[UJ3+~P]æi-ib 47_im%!XRKHh[6CeiZk(*-qo+(8cS*TVEc5,/{Kƽ-_0t 8M7Bۜ->>J%~]N,sQ/~C&Yh HR \:uY 5U ݍZ|g{tS߯7|XZJ)9oO{ ~X 3ʛaVsUr8*pWZ+T$Q'Z@ YbZ&c N8G]KrZ>uk%+^9tx^ Ӣ=OKgݩK)Q\fPst@GxWܥ`EifHjsM-sn|{ϦOFٽc>~5~>*Gy{(P}T4.F[Nd:΅ֲ=)(o#w)u'|KK"vIi 5ds 0p}V Uׁ+LuK ^t]TMm/0ozXg?$ŷJd~EƘSm̎OA[Akx7[rp7Gu; tJ) 3Sg(l.ԩ Cyt ~#  t +2 p ܴKc,Klq7S,A kU)lefE]ō_6ہ"PVsTy'1#.yFl-dHJΉR76b^I6(7}ZZdtm ͯrBi#"NXo ;mʒv A-Iv=׉ʟ>㚕k~ >c?JM37(nQ2ps_++91y{(psIEP "5+U;N#}WyUYhOy^] %HX%Ύcu.MU[ Q-|֥bu4ՋYw |!qH,dI >B1g/ۍɭDv iZ#󕗢Yb-2Sߦ)oSgQp*$ۓTdLE~pͼ4ii-c"9*i+zK gO0q"wu;.RMP6-g\U_~G^\M34BΘiL,!7]#++'7r9XJ(iFI395J'eHVj&7 J`UV!s$Թjc]'d_;g~y)v'7UfzV^F=͠V'`٧ QKԐd"wLonW)2k:2^67Srꮦ8M?Kߩ *VxPB Y7 բ{ob[`kǘaw,/zGJTGh:\"9L_I3p*38Fs%NI; ݌ TwReGysgjGvb]4MTgܙݕ7JxD6=k O6NfA{[ U镌E"h?gpɕNC#MktӶ%$6;z7\]jz55|x> TwVϯ~VjLBM54Xl7t3xTtnpW>o=݀qHh#-yPHQP?cе'\m ZdQ31;:o2CXJ-?ၣF+~.ᘹǥ89q}^򖇸{Wa\$|ON7MjLdOTwy|3h}_T"q{teU|AU7(;GѮh\)ƒ`|U4Қ{p,起l4CJ'-Jތ݂sSv\~˲]t|Wѱ̺I}cMd;TB Znv,ogA_&^9:ں_"S5܊js5.uo?^ qㅵ޳'YT)cYn*->_ T y>Ԧyxc{d6= %Jz/7yfl2NױgEZI`KE-߮ܖ(?E( |J9tI< I|OY CIɷg-γvҠEeTk>N'L^ثdwZ"Si;"=#1cjnpCnđT;ꏵ\56MT#LF" GZBlɄ+ ,cgDBl0Ғ Bm f*o $ ^D;gQD=o= . YwRO;JfcV$Ыn}{8"|JYmSM_uhP6Pfu'T_^ܶr?>@L/?cxXV^8E]Xgiw_ R7 ƛpcx6qv-7)O!]pbL-Z6piE.ys t}*n|jNݫ;ڡ\s7$K7]8ls힡n6ˎ/%{ȱ |UvʻO[R}Sf|6pW)=#Z&=uC.*Tk0 w?4 K]R-(aJTl*X8SLCK1 jUTՙSr3lDO7rυؖV񢓢e l՗-j&y'ׯO@]?9x56Z ã_ |e 㩠R%9i) q>?P&_@ ̲/NNZm 4 "?zޟ endstream endobj 1225 0 obj << /Length1 1177 /Length2 3288 /Length3 0 /Length 4039 /Filter /FlateDecode >> stream xmSyRO_ \#wH"X2H  $@D&eFA"ՙ'B EevSRP:G\ܔUU~!(4 f :Bc`)h4f K6c8sDݔ (QAA8!("HPf6kN$7 Px7gA`wwoz[[V٢^voo';kiItI+KH8A cqu>,ң9d4ܒaw13;rN$=&;pJJWqxD}5& Qsh\R.̺i`E4UU.~혡DK^j{m~6nU*N~mQʄ*.m([`u@OoDݘxxʧ.D6exeq8͖՛5|N'rœ04A2d:!k^f6X ӈбs @s9?R6a;_A`=4$N J5:)?Y@ڵ#heנғ+j29Ihw*%1}y[/H0=4zuKK׃qYMr^9CcpdSjDtexd?K_1/k~K:| .B=F]FY|Ur|^0:-/'$iXߣ=q*}q#߳7vDw^ܥn {e,\GGYNkR75, /J _~]ȧpq褔Е chbɽY̤Gufu?7=bй(RtCz jP"Ăudsl,|.Xxky1wpg~Ge۞ S pƻ)΃ ٽFqEIBK4YL]FP̯)o+t*1glexb-9gP 9!4 p}.+ ~G٠RYC;.}e}W|HOc.mt39GM5m ɒ].ۏn}wel}'eSbYMw@ ^äa} ƻ2ܸa]]FXʱU ]u\,yy++juxȉ1Ji*@!6Qs%x a;(W9gftB‚TRR!Ӭ~\ļ㛳6I.f[㻶)c fs߯YЖ3Pўp2iձT<9/lTn,nDaZvL*\8Ƒuw-HZq M> stream xڭweTݒ. !@piw ]'Xp .|ߙ3ֻܹj?T=kT`37JۃY8XVv&.Nv,J@3+F 4vI;Z@3$ @H;x,,Z LL0OM'+ hk`9A/jgK PQՑS(kd bbke P2 s{0=ҜX߰Ĝ'5)/3rrzX9, 8@.fxMla{Swrv2[98޲JJ_{H3{SJu692̬l=r9d'fha 6:9a՝ o;8z}`5gE|i ׬ȁ8A  c3{ h¦l@S'AyW#} -bkll61%c "Eb]1]h-?؊ۚO%b 7YYarrZ9Z̍m]dZoR ;>YZڀ. _I7y6 mYqUYa6Ο<޸G)Jfu F\`x{{ox}qd rwI_`@f1m ~Vy h4oo*d\M?*P\_iKSU0kݸKܡ<`'-]G24C{i7͠=H+lVq /Q5u'V.0?+4&  :6-]@_|)Sv 21o!eѕJskY}Ky_[S6\U핝R@Hq"I5?d{{Ƞjc)K5c;BnQ&yتʫ-:qX(JܹcN28A6XM|җh*k=s+m&I"޴f mV~sla9r7cTti-˗zت s>T_$ >d\|d 6|1dsH)K/QX;d nmZM:Dl`R&M8l`D|RoM*|LBC\c)ۡدFBÐJr =h-3PG,XYv>uÀ`'j\Xs ;kx=jh';|w;?[eơ#,,,kcN[kJ*'#DKSD~6N :;./ #|3VFjUE"+;j#^& NԧUsaѶ%KԶP*u^)# <{V/UPxvaPBkPf Lz҉Jdp&=oJ~˗w<*P솦`"OWցBBXDo nav=O,FHNځ /YwيwbGk:JEX^MۓsC fՌ_ȉ /YۋXoQ* Iȵ=P =ަhs UW]]8 ME&.!XݨJa"BEY{'զ`wKLNQ394;| 1^.[jʢ ғ<92 na7zyS<#\(CmY|>*ЅBq=(kYd-p~߇;bg=ɫfoN(6qwS6!5Tk uh]wO4$Xk'}^8 +VVdg|fVBMMȶCn6AN/6؜]?اWr_{5gžM4Z4v)h72K~UBmqkWvrqW$l3vpL}'*AQ} ?uZ',67ѵ :C”M{'E dwρ^U,s(뱂~8ى>'0|c,PSr7ySegsS׷q6ifLg'C9ns1T yY4IXieb~iXi$!,U$!D/k=be4 3u`Swv;Cefqޟȅv4K)y*t-˺}=TH6:63% *WtD ;mש,'!ĭ2EB+3 :ך@:H*b(|(Iz+%uRe"a֒mC^;B“^x?JRZ΁ K!1ZQXBPT" ga x_5L/$Q?۬(޸,UljP7{(W!U)hB@K֯l[m$ IʵnSNJE9rf-J-45Q'iB7%FFa}e2>%YcV#ue{ de7LbԚt|M8[EXG 3Yj&43#WIAa;]W2)>PS9<%4Q-^'ש%PKPr }k!Bk(" Vd?Rml~Ha~~$YHa22[HL9EfZ=x% 4M@0~uKKK8[[qXϺξ^5bEp<ϻ#ԩ9ԒJݲ) )νGw]h+nЩx݀^ c# ׵FrMfGo% ‹5^W|9E쎏˩\:,:hY](,"_h)$odO^/].}IN&6Z?>"2z9◧ }̋񳷫>,8w]=*s4 / wlk9t?*Em~)ttWm^#zO.zMjRPa>c-ŭ1?uz{">i%KT*-~N2؂GvbWO0K^WР4~! yۤo,p(XI6˞n,; (UNR`8rinڃW$jԠ%'qgcsO#_(`E.96^C1(A%cXFSB["b3qxa!*k݄r)'!/=zM {n)9|\M?p ^f{xXXYp٫@,=AKR#-F>, ~y+ݢ"8n}7= | n~>$TH %#XK%Bvq7;=[lGv>$Z>ŜG>MƧ;oS^)K"[߷l]"l ΖGH!XX&gR@įD~]{%7Ox&--dUgsͥݏؕIV egITȔ-;zAlx̩KSMQdeމck+,z% qʏt4c)5 Vz}@rE1Tmԙ6PA|m 2Sfh^(amA60 | H \ *!kNZ hjԲʼa٤*_K\6 JW|_Tj5l4%0b1))ڗerwdHˌthv  )LF8W})Khiv%Tgn =fa?r_&JΗ& .z*ȨԌϑϰc` ~TzSu{8PU|PTmtleH^i|Y[`SlfzmYvL.T́{B^-O9jJ%QMHRc%`νekbZ}'3P(8xDzJ/h"Jj)qy*uP{k|"{e n9RGyN0 }s*'Á7ZQ3-E3+ܗD8n 2xz! sr2Ak1MztdY̪n(V9bȽ[W)fA?Θrݻhy(c>]m ^'1 #vB3=M}J}ܲ\;gv,vG;Ǿt9$2M*S2|+ȁGu7qM ӥ6n Qc_>!faR4{qW}`I&7vHrzG6o}cd٦j,?* c*'#*kf-s S_g`%aOP7#Zzq?͏gbbDŽly,JhbXUN fZIzHCRdWoxGSăGnt Bղ'ez}.CIۯ{& $׷¿' 9!'MeK/ܞC+HEv56lFKL;`s(`jt(.oՑHE[nRP;ߜ&/1GԍY@W"eEF*?BNAz5Z[VЖ{tFѼ›9_`/)@Bh㤫]kc*y-?ߡHl5hx[ L#B@f^٤+Cʳ˾sgOP=zGǦ8 i^h%~bnƮ@?\޻yĞw:Y{_Ҩ%gvo;P؋V|!(Vh9`ͫ052Wg ]wu䛎6zr vs uyqOt7Q޿RPdV"f}S&+aMHM-Zhf/F=W,M+s[bd@x_{ (lאms+UݧƄ0 =',E9B9gm5#*!6`_)xhBSk)w+CF|R)z@O+KA! $ZΛ-q×ܵ^E\";֦K;+V,pfP=v]>~ EdYV'X)j>rJV@++ LژԔCUJ\bJ`ځ&f?/v*P66YT*-j_O88* yEљ@_Ⅻ"- i?cHs9Ujj=~uӁA|%W003+'FqSwaa5Ijw0>N|YUYm&Cո&8RRK]D5D$<{}Ť>f8JvH{ =Y1wa.ze+#iT90n:xњB)b$st.4aDQ18A׸,,8[eS6BH4=j)JۍiB|6$׼e_> rCj=DzO.^b@P@NXsLdC=(3>Oa~Rj)'N%& GBFZ @U}S1fjK+/*g~V=+r8Fޣ+6fG~PؗOWǵ1+S>ZWvٳOccE)*7)|"vEEܙ'H&,9 -$^XYtOJ},o7瓅.EFsELX2>|'6 j}d_&ّm-5'f \餜ؤ;ksqX1:$@ٚ~a؉pl׿= :_j$~󀒋dK`Uw:':w~9=!Ŀ8:އ3^˥G`NL Y<ش\A$Du݅~%|m򇖠<$j -}5K#^ VIuʏa{^V |fj!cU36#3>f)Vuŏ""$R玔桡x}G~U/)6S2yi;s!G'lA c;kR)u7O\)+jNOAo2f}z3 .3rQQ N cI0IvS5 1َe},zd}&K-[r(fݦ%΍%.8kBBT[G$D2zZg:mP6OR4B'0Qh'>{0S$KA3 #'93}"_,Q`gQ>J zIN6_>G׃!7UpHveHF+lPaEkIX e%R e|ܕ2|@u88k >O5*lbSos_h]Ц 8L!rm2lC "&W; J8LO3`wi]b1i$|%ntK2]fM4A_߳z^qeY=7^asځX"Ҳ юBW޽R8 / +>sWc:/,ϓAeG.μ;~HHg͜g*\yheBM2٣+KQe) >\ĵbb;*H uB1JS*KwRW!>f(DjtgqQHxЊbJx)Ǡ3ϳײI~~SYyAeށ$ŭg;Q^ š `1$AR=@ߗĴU&1#Aѻ" 6f X)>1P}e"ӄ |ɏ(QM!Ľ͉@8}YT|.hrOb%R7en u,)(ȥ6YQ6'FtͤٹS3~J0S cao-fq,4 Lb$9 cUH\k)cJ5 %Hf=6 UOpJy7IߕDʾtHm/ӣ'mEHh|#L8t݅-C|9p㲶"^p#M@ M&J瘻Ks'Ix)`EP+<2^OS ׏O-qLG9cdD ?. 8RҸ1'nJoM_.wl -m'kU=Rbe2$SL\oS:W!uCNu!O|nI Zu*|YC2~~aJ8 ++ƀ+1dN$֧kpNʏ`8;s;[`kfI] w<[u]V!R8\fN6.= svx^d}meϴ6Ak?|(*{66Yv} +(#e#_{e>#\,ܠi~KńyDoVLT@|t2S sb‹._6TYA E;J#ɑqv!/6h|w#x@{mq0y lI A_K-{mN|"sqlW`JP̾mT z5rIxtcl LHpB$1'm3rU%Eݼ/8Γ~_"^]aYS#)ZXRl0z$=kG&i u3a Tb>oRIRRVXlAzWR*0ʻ" {>.Xk$1`5] O&;*5휗.ߛQE$È$RDM`jp':\ǏA P`|brӦ'EY3JۇtClXJŲ%V$3? O^27tC ̞u$"~/(oV*%G#1̽dϘj/9X|X,jbs勹g jVt%\.#ŭԊP5l|;=>'+[_\k:^%Rn:Ĩ _Edj$k1mBeH-*{Wu{i*M`V>M@k~oGT}f<5xr 0=vUo(ʰ`Z̥9+[&Rr]AmZJn]Y.8A2fȷPoa+Ѱ)H,*OKT@ ᇽ/[P%@M2,淢\Q"pxG3&/r)ٻE~Y⻼oR@mo1 јL~8eQJSH#UlVvZh@W^~ZJh"t[(rDY>'^ $)w9MgΠ4>ˉi6&ErlXPw_nq^_T-]]ΊЩ’VMZ۵V*yI(̆r,/_:|ADpe$#ېjP-7⧊G١aj3YȖ?\%I^\άq@ d%be{vrͼ~ zwmQ@P9 n_xgcwR?rVYp\jqW% Ocֻ,= 3 Q}oNV^\~(iT6j Ԏ7 s~Inj/KK"cˡoᤷM479'">հ o2)BAv?%Lȝ\ʼz5 [J ݲM\?\?\ˍÙC 7!iS&"䡝vK 豘'EޮDDS^ endstream endobj 1229 0 obj << /Length1 1630 /Length2 17958 /Length3 0 /Length 18799 /Filter /FlateDecode >> stream xڬctf]&;ظS1+m۶m۶m۶Uӧt{&k7 "  =-@QZƖ]FW CB"`dnk#dP560$A[;wsS3'*J1毧 _kGEcc1 (+..# Q;[ R6[տC[#Js8u3v34GE 3v6wt0w:8큓-Ml_ 뿺`rNvNQD?&-l )_0N6'c7b f`4mL3j_t?/Y_V3s'Gc+Zz1 65Ϭۘ-7rÿDPMB`dlKoH˴}$7PB oWKz+]26{ gX;|ͭO^Zĝ/5tt;ə;L_re#c+sz:S237mkW$兤7 _rIoni[yF@ ICa`{& / \5zIjLNhoJ^Aoȥ0! 4lh|td*'S'0] ͅձj9U)Q}ř1f>o V*46(`BpVIBkE|EGe{9쟦4"/$r>Lx#1:6tyuHYVzl^aH:=hN'o|(js9nsPh?\t||!QOo L1\ )[MU #i1HW$oXHb[MQ$^:=izM%{P#b=@e<12y>LKMMԚ'Z8Y),Ixk&}R^ KŘ:dqG_tV5j NHLMakX=_MHw_JͼvHRh/帼j4n fd` b-tY8"1<0`inf r\7%',I[c)(NI/jQ#Ja_bljfkDk2`zG'@;T9F~ 9@ Џ{"՗(F A9| Fy2}j/di_lumљb7Ly-y.mxqesNqڎ箅h,ɴS",fHhѢW r۞onC/^on }2IM_7/>eh!W}bʩf|kx/q|dUA,(E(%QXTO1CQeSm<]X͠LYp*zٌ7 LȈFy  2nK=8WLl泮 :7)*d}E'Q?^#$/хa%\+wKAmn.Uѧ `Õ,ȁh?O1΅{.7XkԐ/?)NI']YǾK'-u, . ASa9qU;UN$|ב]hR@c'֚eh՟(,<&݃ؽ9v7,؅_:ו;/ynZ{o!t(c`Dl`6<3h4&{b{a9J#F3~3*~$뽿)LrQ&;\G4߽&/yyCzhFA1ro S*%fFBe}Wtuc$&fC98R#&g:n)&uWޙsbts_E)M;X[մd32Y,@OXm=eL?W\ժ02gx{ZkXa0>zĹݔC{D*؜G_)گuðoh.. >,dJQƢ&Bp ݰS>C+wEA獶.nrGJRW6=!xwGsw_015FNG\ʮEAM=thLKz4s=ѣuq,Urɺ&uZY9-W=vs+RaYghvѳ*o썰Ɗx(og>=44xdBPN2q* Mo=6B`$us^ʬԏ $<kUbC& M4ޏl PG; #/PLVĒD&(d3Aǭf@=3_A0r (vdFay3bID|E0GE07M%ҝyny̱2(G$V d$:DAytSG^?]13lˊ~Y= ǎVbN@G—)Q9uer!!1te'!2Wh;+=_> ]E&1\ѹ8Ke&,FiZWLjt4H@ ٟͦy(.1a6ʝH0C;jg:'5ʴGuMfO͗굷^e$ mEwZnȃ}]gXŞР|d-xt4)%\\r5JE3c'dh͊s(6B@%42`1GQx#7i̜2Cߧsf-1>^bF-5\> `#˙Z+~HnaE\Nut܌k_$˧-qM>TGD=BGRnRzo̼D<!x5R.7ɾ>E8%Pܧ^.ƨ_R=(>τz49SY\]n>8 cc^ԲNqs:4rRtT6l,5u)9ZX*n=$n0KkGLcj=; J"bt|UȅWu8*cm|Z#ŻwJ;'X,3IJG`'[3pgKR\芛\Zf?˟'6Yuef/{jp@$r~RW/Ԭ{n%8 i=l)#ƇNV'ż] T!tkfɂp7&!UVMF;fDKx NnM`Tg{ ko .~O]UA7ⓗhnd;*?Rba!I^>F-cڜjE$;8嬙"Ĕ{=a}nm{/aWLl#w\YAIfMҡx> 6%!h>QSE'ul f>$$ |IU(}f.ppK ԦhOSճܭ΍}ι08MSub.;"7jO%N|XT|,ˡ7*U1:sU,ؑg_kgZQ I eaatG z^uI=yM&4}Wrxa\/ruԹX"Vg nua6;X&GLoimNw2L9 A7hӼGNHZK"sȓxؚr2̪s㹩eUPhAurJU^hs?!15p220Lڶ]am *y9ᰧdb9+'0BD> ,D1#&p]Vm+BT#IXlAfp)ֶHKb5<.N&u]Vh-MmH4cah{ `P^-BލˏX&M< $0m¹BM:yW!>>m=ĨTJoƚE\?":_Ս[2픖BI2:'$u|14F(2#y<8[5bI}܂Lksq!bO6Ѩ+1k‹ ̘yӟʗ |A;Ê"%԰gR0D0 QB1@ALKK9RonIͦroMȬ+ ihK@)FgC*pv&MRKiLlCSն\E. 2R&\SZ)?$hJ8fJKf^8^|Ԡ./{zFoZhqZk9Ә%Fn;oi C%BM9dHM1QR];cVJWs,!jwVbWZoE;C֍Փ>ɽVmϱtt0Q2FpCB0-?64-bd^- < !N\of@5r #2H<(c])<3uJ3!Ԏwp8%ȕ4š#R+8 VB9 Ǹd3gd6;,A/&DP7?[ {40rE}O|ޓ|mw3o̶ l?{i7O|B_՗qF69I^@Um n#RzEF0XSD"es?7ےTdAAh?/4![mVm3&57OyQ]z^쑢 M֌͓[2@k!5xpr(3> ~wUSLKpDŽ[1& TSc?|AksI2B a GT$fDl.n:jz߽IVdD`ug mI}]YD<J|8\0޻)R:!yZ:XIx=0b Rv1fؿeGHsRI%=RȁXRɻ~DԙR4vQd.&hX[^0O˲vzZ&ި6ӗb߬dT̖Ti/D.ilI^k@A3uuO;)i`%12y{8fVKB WQoiKX!8Й$װdWCP`6^̂1i٤x| G6 E!{J5QNnZ}nl 4}2RқcbctZqoq(Ⱦ0]7|v.i]beHzonaE&Ti!r:ɔG:7G-hl5+RjW9ئ\tBqE@7|*䇐NG:5G闔;Y}"CW]%a*X[.jOE z9kݡZp:;@ r0tnyTugXܒ8{LRNl^'Ŵ 4Go S6LނKXMˮ@ ^9h'7l_2>lg 9N=9l;6qj+"R_KP}GOSBh9˩1.)xZi"beK&K_\RB"1PY^Q3ivM?q\8>Glwm)kjW&2$f fcLؼtƸ#k[;6AY5'g փy= ^ _UԨ톇gc2]>P\ [ij?7?-Bcкsԥc XO|}a* ömĚ'S kC6~XsA IL<8 W+I8gsȩŅ!h>#AcƟњPڴ^9ZҎO_‚ n&gMg| K܁۽「_6Cb{*UVG$(M_6y a4 /.CGq$o$ a El$])bG"'Ͻzg47M {TIRK~ ѥ+}=ly׻?3Ы' ߮gA$ [f]-1H]סn46u5(CA՞x;Rvaآus*ztc"ccXޱ4h(dU,9]Q PC˥r1Y!t+{@R5ӷd_+ *@ %a0^#o6xxDZ cO](Jm+YžxƶN%_tȐ׿}, o^f]:<¡7_UyY/2K6G2&gQ[Ҹ0ҰhTka(2x T;0+5b +' ۀ.{҃=*be|_,Vڶ' A ](JH۰Sǵ!zӑeenԓQsFqlHsQI(^s?dMj >*kMcGv3k%|ש7W'oբN~q}mk zoO~M ԷY,Q "i"-gDfOh(رJ JZƪѼb.fLxDY;Np걻;,eq|8LBVqM y!*izn؁ӏC:TT;cl<}ׂy Ox7IZY?'Oc:!v@7XzwA  @g%1n^c\$Ƕrܸ =\&R&'dD #ѣƄfү}V728 Yoz{XF,A Pko"*]5V4;1?w4!D+;15ٲ5rY2#U8%+j9=0O՝wQ uBOЏv>6"e $Nɢz W[oekoh*Q,o?(#8qHaQ֧eOjȯpH,s䴸L.65ݜX)bmA<96+EcR`X,b$\UNQq<|­МTYKis@ZG@8YxG{/ sfpV Yxh`A.&alzO>>p=D&4K`l`NK gL=3cYFK'r/WY[Pr7{uLP?Wi]Q˔k*RF13rQcA/)p[a=.*EIsN6F~#ݼ O|겱ARQ#(hD%; 5',05F3vO;V}wmlKo4\N6~XXػ}9Ec ق&Jvk(4Ve# uv)o \UQN`bE.D sZbSBǶT|\kAÆ&&̅RT7z~IV/{jm"/^C{}MLգOlx~^؇ۛxhm3>U]V \WH6v•Bp ^{8q>ljDyC:(ޠs6bdlK2PR+,j 5Dc'/\HfxQ (`cΦ.2@XaW+5J9GpZ,B-KI MgԶ2(kYR(f%?ɐhT,z[H/<6oz2&M!S+⏙_f;Ԃn頦/ :\؏+Dq%۶2,ʿIIs7CjM4IOg_oRR8łeb0<.MD֕:+#UC#dyiY#B&l%1E1%1K\™E<1݆QݪcǙO9r(1˪7h*C}1&CR\~la(;waj} T*LK\Si~)[/Z [12jy%%D4`m1Qhro"ivCA:s-v'Ѡ[}çMBjq}`Gc7H3|iFʲXKTB Uzmd9qִD *|z+l:@b0 j?{{qz3a[_rLFa;@g&}hWN:*ųRf~nPRwa/BiFIS8*.: ӈ `%<'SN˸M&u{TyN;c )·*;*Tѐl&?Z^1*-eab,BCД2$siclyeԱ7'ػh[CU7^wb"'HrHz$\Y[ e@U\c"/ xIDA"!ަ5x{'ٍFA rQC*9%`q?}S/˧MSJ+̔:yH bّev-Ayߜ8J>,HqF@Y(69tČ:,'a0Rc2jkÀ[(xֻxrӚXEvc8|½-R L##9n ոC8gLًl:f"4!9M 3v={o~Ppְ? RH0NSqNAhHdl% *TG<`!PMB&)hB|}&t+|JF̹DGQ, c`a*] ua<^symޜ"b?G#EwS0>~9y1bj1`->9JS rRJଚhz,CQ՜mKxQ̄2`ZQD֏SYrO_=/P(3\Fˀ98Tlm )ξitưQ~Cf,IHEޟȬ*(5Q^kux;kFDjL"T,\|ˊ=FlΧx%WWW@~3wR",,U=e$zh_n+1Az_38+i-}vY02p l?z1<9 \| vke:s$WEb?#NL0-&XQ][^Hc{"PC)λ_Hv'>bJչGb5! LHΜ.l<# 2bo Ƅ/D27%3R+W+jJ"b" Њ)|Yٵ0ҭ~?)h [8XpS$]̛?x?mnMy<31=.XqJRK ")+ y.^̓t]v4x$\ zjag [FwE˪#hrM&v@j@ X gx (^]7HRNLoad12)rD Djhɶ~T}|k~ځ43-aR5m10iڧ,cIgE|VCZ#LW-0Ҩ5ך3<:Jkٞ@>WlF] S%z@-1d`WS!?Xɷ Q6 :%smW"94f Bgylm*s,K_8sz:2 d^9-&v/q0(0>1v;p0"=Vz٧ovҩ'A#8Y46*&𸂒VAgq:_Hn'\~D_骑~j6oGp/h$}hm[ lߡH#47Y_>Y/OJf}wC}Q4DŽ :tA1۹b,QӉOK}7vyvڷ,o$_8a|aynr3ߣuWgԮ$@_Z8FWĝ ܩY\ c?z6 "4 eGk c &U=$fq#jIe;q5sBΝp˫; ̵)An {O"]._[ j= *#%݇ +XsW؄ՌnQxe-9[)ҞЬH<׷$tAXWXu 1!U$ᯈ2;@oҡh&A*h膼kb !IbIkr+z(PNuκ~B>23QĸHR e ғRnNCݥHqIsp)X Tl? zpptOVcV}PncL eXkT28{ r$ݖ։y];$@48}]lVlEk+¬#o8m =j*s"/V4bKYDM9Tq(|[z:weo!\W18H$a{Ʋ^'2|f`3}8.̡z&ٱJ&![*Qp:EVV%Tno^K.YsV)T)xa.¼+c8]0`i@U߲R*ϭwa<W]_o񡴫aS| GS~ff8'CMf"<Z|fʅz2}ܭyC6DMX<ԱPsq񒢳ԉA $mYx#SorhJ"^E?I G>c2679?5/r.U5*_zZMϚ pPϷ苩eJDJpԣ&WH )䠱]*utt^hWB=jX"%S[7r~e\1Q70ı?Fp /<9A=h>xz:KHu6 \Dl[N-#1}N˷c6P451I9P̺Yc(OXk 74?`CKgO3RpOZ/ɞG!Z$)ҧRB噣[2'ֱp&N5\(Gڝ.}55jir/z\ҥU/h)fPGI'V/06BSpao|1lsگ,Jmϯ ka`2@W/s!Xݾ.T:eHZ1;'oUf(|I‚f! w`zI -5-d g [AD~ y6ec(zGb[!TH7{_x%rC^BU*}g*.WM>l[$md UO^sI]1$x{{q @;sMt',5ӶQ<ȒBNO4bvjԆZ܍ A _ʆ6ڷR/3VPTsɬE.xo(+4% 䀨G B~߼nivmnbӧ .3,嬱gr1NUZ^O1 NFbf6\oEc-'K9WGy,r.CxsioDv, 3H-j2C Mt2DBZ|?{;|/6Ȼ ǚ{8;O>D }mBm/=̂1=mtb4X'URP1x"fhK欏<5/̃{jޭMU,^% [HHҿ]yK1g jvEnv(ňw-yq`HMoU{>0٭[d͏, x4@- op? _>_wtz1ې-O&;5bUSp=86k#VˣV^x39-a`b? 7_g:knDR*&I<]I鱆ߵ~}W61]=E'q??Uo%;!ڔ ϩp? m"ڍf., `~wc[V3wͼЛÔ }fH拂q+6#H< r6J8vPJ?}2~a8LOF6FZGS 3!*\[9,.vu%+(ݓ> 1{Ks Mց Mgfq[ݸ~hƮ+'|O,2IҬAԪO3|d}8T'\c!_[F\Wy|yآ\k1mvH@$31ϱ>GasYֆ.RIOJB>v$Oٰ&jvm+POʤgL)q\oHs8Ex9O%O3M~hVnQ6e+)6VsJৗ%cAiN;ɽpQJ 5홣v7O~)xPh r34Q|d:4wWoभ˂{]ni,Nnm;r;s_X~J8na> stream xZ]s۶}ׯc3_3I7f ˴ItE)I.@P EIvnv$p]Źa΍$RYla W p B$Blh"AGd|䉴h ApPD}hh4,m9Gm9 {Nt%1;{E w 1&ܱĸ x$#V1lb`XX/G0ı\< zJ [JX"$ h`D:d&:kSC); ~k 41kA#W*Z# TE kb5H-@|z`o?ǴY}Im|a= }:k}eEH:["H`o4m״v ٳ@*& E!Hhк~8!5o$qţd%?>ǽб:ȁUjR=== L75Qa|8wmƪOjإ-z>߽,ʛ[trD >;vfZq,f\#$XxVէ>}0#oFOkGo߾} 5Ɂ7[A]?5v6-^x?*gVӫamr,':Z %`̝xvW,jxStBhA YebNKN鴨k:sZ; .hM鸾K_W}VO\7jX+Y.; ,jesݢʥBER='^d(ԤVF3 o,U͋aŖ/h_A(&բ"䫋_^5Bw&~C<1 ϊJ\pJ ݖvZ\'>@#Ǡ)}E_3T~ :N?Q&x{oȃ_]~TXT]P=x&W}Gbz C#ciλrNg 9,QT踆U?xNe[j6g|\BL%@Mdw?wiNj'sU9ղF'YI"ֿ,ꪜ@Db6"?%RɭxH:J܎r7B6zDpCA {&vY1~i4ۗ5ĉ~ԗ Rٲz2[bӀofA.oBiltj5JE:ѓqvZφſ~bþJk/ooqD\F8 D`r[w}rR.`7ȉ>93n\|n[y:w!sAp#MNu~46_2X}~v }~={;5;Fp]Fky[ Ig]s9|B ?~41 Fpɛ o3` FG4HFM͈(1EϭTnfMα>zˈj 0t#X.pGը#!ZNaR7_bS{ptKeȱf"~ v٢֒WID%XgUu13h2@P t й= (@t~Peb `B0|`}AHѡd6fc 07)x`LY5eY3wvPdl7q]A&c.`J 0YY))¦DdSuߔμ}vcJjB{=μ|7N [fr[,Y@-I!݀$M@S@Ԇl~Pbwun::ֳl:Ʋذ+7r6e6]HAuǥu0=؝=0fv!gՏ[t!jgOvO+EVh_h;LdnBYqAijaI ~[0[0rTV0_0l0XV!dz;( vzYjn嬔XZSID6!!0߭6T;,۟t[J Y?eiONސˬ endstream endobj 1261 0 obj << /Producer (pdfTeX-1.40.21) /Author(Andreas Warnke)/Title(crystal-facet-uml documentation)/Subject()/Creator(DBLaTeX-0.3.12)/Keywords() /CreationDate (D:20211128145247+01'00') /ModDate (D:20211128145247+01'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.14159265-2.6-1.40.21 (TeX Live 2020/Debian) kpathsea version 6.3.2) >> endobj 1233 0 obj << /Type /ObjStm /N 58 /First 565 /Length 1822 /Filter /FlateDecode >> stream xڝYMo7 WXK 0P4(PM~ w{ߗԌҌ4S!GJ5:S&X.@+K2{썢hyrl)OtP22p*FA&YZ`l cyD--/Dƒ2XH> y"HX yRڠC$#(4{chbdd(($xpz=+kQP2"ׅ:0c{l4GV3G4"B璗A 9*R\JqP|@9.6;):J\8}7q^J Rº(嬕O5՛7W7׊w__n?en|oǓ̎4>;%7<=3+#!#*2o</h @]@m Їmb T @SNPu@j@l Հ @ p"<,4: 4hCj@hRP JRP m(jPS)T(7R,JZ)T J `l* `O)) [H]K#Bݼ3yЅ,vBOlS5PfMA|m}[EB^0W5EiBO@'(XðГ뀦4d =MB@Ʈodg53N+ 79TԪ.n.i^B( CLJwʙ9`]LqD1PvIۧO~=k;5wb0 {<}> #S?}xf,{ܟg$֖;8&hgv}Os}a? ?F~"Kt_L"3`^Aq8).0:\Ñb fLaF+O]Z%(TarG SJSY- XDs%%@ile:x, [_fyS8et5,pyU8x &Q/:ĸ ] /Length 3238 /Filter /FlateDecode >> stream x%{p9= +$@p@bKձQR۞# /^GҊE]x^+T_uZ-}O=M,qb1'&7 xjļlym ~~ 6̃JR0r   `Bx&dPS*ALjP u3a4lh-s Yp|p| =pu6a'JAdXȁ\ S`*C ̀Zqs@WF^_el6X aC,% ] =rX+a5zQbz:q|a`ϳchUy3a\@'X `%lͰ$w"&'-1z$ Y}l"o3Źg2Z)犣ZN \@e+lF`';;D[nёm[Ց+musǹ:sbsL=˵$[AX&,ޅuxgIwQ!񮙤a {/I‰6"p׾qݥJn}F eVI2t=`5+ɏ{?XNڿϮ|l%Zj9LL/-?؅{,So ?Xؿ~yʷ- v>fe8~8FðIo-5%[`3 lmv5cwN0<倖&b0@v 7S)͔fp3e2y_uFgRgȟ!zgJo\#Cv e2})YK?u whB|Rl~زf.ˏ9r"uF]e=q33nLګ+WȀ1>c˓-R=O[eCe4'$KCpi< }dĿj:э:c73f `1JRphA h Cìg֙{f2nn7 _6.ѫ̠G_r~#l!φ<j/ ݅dmH!fbwٳ+_QDR ڤYJ߷T-UHzFKCe>=oYʲX,6>{ nl9HmQAI*ZB0C B̀I;BqqP0&DIu^ca BLrJIo߻iPӡ$uٺuJ[ 9:Z͒:xZ٠A`,ԇ;: X3AE6B? Y0 :Yg{92zvJ=/;`Rϕ:oE42HF.xW KQX(EɒEyM2F,|CYȈDytDFa'6~92:Z %{LԏG/"TJ=>UPӨQ!tJR9j) T4|ȧu׫^|ZWk

Introduction crystal-facet-uml creates diagrams to document system and software architecture. Like a crystal shows different facets of the same thing, this application shows different views of the same system.
Goal As software architect, you create a set of diagrams describing use-cases, requirements, structural views, behavioral and deployment views. crystal-facet-uml keeps element names and element hierarchies consistent. It exports diagrams in svg, pdf, ps and png formats to be used in text processing systems like DocBook, html, LaTeX. crystal-facet-uml exports the model to json and xmi format. This tool runs on your local PC and is based on gtk (incl. glib, gdk, cairo, pango) and sqlite.
Features
Usage Overview crystal-facet-uml can be started in graphical mode (see ) or from command line (for help run crystal-facet-uml -h).
crystal-facet-uml-1.34.1/user_doc/doc/1_introduction_banner.pdf000066400000000000000000000233371415120503000244640ustar00rootroot00000000000000%PDF-1.4 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream xKm+j`*_E Y8Y}^sZ]Tk}=KY߅vN=k MFyU4V~5V1k3_]8g Ο(4xֿHif 3z|:{>hQ4b~67R"c"azHI?Ë пex68i{"2>E[M!iDmaW{OQ>nnUӴYYfQL^bΪs({YIk= -GU+of9Ǿ([c ۳ [ h2o&]\-zD~Xiysv+S߃Ri4[KZdqGhV+mޡgtͭ (;AկۭGէa 6Kz4NֿmwZPn}t"Ͽ~2yݺe"2ZSkYGn4_u AVNجlmQɱY6s(Q"j և%ѥ[`jn"X-ViS+a8q Y{x5H'6-/gyM`v,~9uI<_Cd\ 'NHLg| ڳ1\enꯟ 4~%n2$`-ߦO@|r5~2Xm{:bn[ m1فxB.tKd8 >qQaW$Jk VӉgbhF[6HIȗ|z'C?v1&bc{8ݚ #.gWd@=COsmaRwp䕍I/f9FQjhl@E֡h`|dlSwIS/tTBo;,(}ZF(l1PFRF)hlEh-+;Nݼ[zH%Iz27;Kԁ1Mhe:5 Дn/T\lIgfpbfa%ŭsqޘ}]$|n 4 VKL# ܧZ!z 'QjNn-R[6]3W{ʆNI8_EUW6eBhVG{hՓi5t{ep=|yr;u›hd%- }h =vLq\F7@i^!)(Ŧ1.\{!MC6@!v]憁5 8M {~3'_ uNs=fpǮn/*۟|%UlV"I+J@J;{$WPj.T|]f1g^ɭz44DKUVהcjbqzuhsʼn Ŝ5{>: Rs$\1j m6HjynjI7pHȠ[}ѵB e5+&Ed栍̤7 N=H1UfiX~Xݵ+@L]N NHiJ ?[EۦAn_ZI3ȂeD2cIFD4%7[/>p/b7{b Ŋ$,tBʌ p&K*X? eKUnKGSIɾXI3\dd4KƷnhNT[ -eђZ}$q#v/*vFWj#كZnO+V6sGۊJC EƧKx\< tVj;t|\$h?QbM2 ϨFW[h۲̀-vWȣ7@ \OmdgK3[HBflKf"W;Ie}՛A[׾|f>N-T9svl/d t:ޖEWsc9 ɼ,%*Ͷn,1ipfݬѐq&NХ.JYO8fZno|ż Z5w)VkY<?%ʬ3:cQņL!H`3syUv~tb`8CL2b>U.՛{,/LዜhZfw$#KDZHSf lx•dm?8*dw?#Ť\"=04ceSל¤#p1(1 c>n1P XFt=w8%V dxi=<>3Z@c oh\om5ê`s_~)w /L>Ld#X6ڃD8wat؄*!SȈ"ۑ人 @ֈiL " |DP,a W]P@ W6҅6]3IƯ0wX88U$vBx!*QC:JG O-*X?8a!ﶠ1dR>~ֵRBM&U"IBHګA^aJ ms ҙA԰YLo<( o YG;c&w1> UmېyX`7icg惔6M_#Pa=y6[j0&f{lpBח-GWu_¿H09TΣg@܋D0D 6`綎y=aSMGw% ug)˷Xa-pPm[cYcҶ!R=dmEr) |m ~1D΂-{Gb {LӢ? w|qݧ &l <1gT0 oS'pߝ~ v/'.^ vPIĒ|"?u КrJܤ?~@6z\~!j[p Z' }j Ph=F1xL"U>Mr)q$]`$P˂<^MNKDX-釅]$#r`LV2 qx7v=^z< ,u;zRy [V+v.52Kx2ݠfI׏ְ 4$&[V_M6H(LjøkX,fZ۱VꞾQ+.+F{kf|U\uSKZ1A3]Yfy✝ؕ푺fMZmϗqT^?qșVƹ] %ӜzYD"+p//23AwDvYqN+!P '~rbի G.ɯaK5+Ic:+j#L@,jD Y}sCW춏u>"\%V1w-?; #;Wwl)=B1N1NӡSlo &9%;SmR+:0Gfɓ.#fsbҴX8JX9 l0vqjGL{F?ydٞћ fRz8mR,YpdeK "fqB(? efE rk)d(th*u8-$EN. S0 sXQ_ p :%(ݯ28|6W:R! kAIzvOO u;L"[n!XRwkRXuF*_>+KDhcS[HW)M "\d69'483,7ck$@+lUs?:)Q%V6]V0pqg\!H ]KkZL=z?#&"\0NhDj7HޜI*Q0r2 >jxfEծВ@lRٍ`Z9*=P%D͉u;1AKh`} 9TgS5ΑsC</ևm?by\3y9ܝGm&c얓?3dQ2RXSo0B9OG5F&!sDE^XwБKxHN?8td7@+[ t}S?(D3=$$P#uA,/VO1T3S a} o丰s-^cTr߼|mQ6hF?X3z2]vkwn@~c]#&Ku``As LZ fgqfIA1w ggb숃 #oI[x6aa]XW X $g@ȘPbnc'^Rj."'`f2ӱρ#8׉dP"%uUl@Bnر6#s7,& "rݴوPNC˸baJ7xN){(B8wq`vCںdþ9(,.Zc= Sed}LbK)1 < A:oU {^1P:jŰ邱\C&;m/wR3; }H.AV9o ^mXHNEsc2|rHXɓ$)̆Dt!h}}#ʖ&U@d,Jen:rD9׽:p 1NbE Nc`@(IծK $~4#dJ,X.Œɢɷ_G5c (3N KCxbt. oᠨFIO<՞/=,+xrU\:ZON%16ĝ=G0Of!/&6JwtNQW(|쑁P)0X|O7Y|]zOv@ukmFtFMY5{3h 7dik置Fj.LEy;I4u4Inޕ>Gմ|D+ҧI=H4Mp\ʅ~ыe;SCr\Tm FܵU:]bD<;zt*Ņ"4o. tz:+f.XfzFʖy=M.dm/ j#^Q99yȔ~OF(я'uZG-;9%}(i8zl;uH k+M3&8 ry8 /R2 3 =X# (@#‘G|8~(gZG</NP49n/w#M;oZԷk_L H'@sܯg m Fbk6!u'-9oG @O+7? C? ٖ endstream endobj 5 0 obj 9071 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 945 315 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 6 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210424175913+02'00) >> endobj 7 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 8 0000000000 65535 f 0000009476 00000 n 0000009258 00000 n 0000009186 00000 n 0000000015 00000 n 0000009163 00000 n 0000009541 00000 n 0000009657 00000 n trailer << /Size 8 /Root 7 0 R /Info 6 0 R >> startxref 9709 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/1_introduction_banner.png000066400000000000000000002463041415120503000245000ustar00rootroot00000000000000PNG  IHDRv#sBIT|d pHYs+tEXtSoftwarewww.inkscape.org< IDATxw|TuםIOB @ eWŶ]qmowZ#U $E@$q H`&;G{Obw{]Yy@`rDDDDDu"""Rgól (m%PEDDDD;l`pQ6YiXð@oF DDD$-X@VtӁjq&=Ƃ= Vv"""/i@_vusX@2uTם(Ay""""RG(=3/jڝA"""""R`'"""U\a\e@.ɳ"#]x{ym;؃zEDDDS`'""R$=XH66BZ_$a:(DDDD$؉85j[]wb`уzEDDDP`'""R75Qw\A2І\(}""""؉ IQHlԵruuw[5]QUzMH:: {<s믛 &[8*u>oUKb]cWw^ DDDD-v""" Xh3[L9sfR6mrg0 qwZq]-v];q֖|8Ny4js؉įs]ti\ Ev;=q`o߾Tʩ;HS`'""_5: bjժUMwܙ Vu X :uAiwr'=(֞cW\]]A7uu5qWs)=눍Y;ODDDc DDDbr̵̷#5:XEQ{{QGM|x]GPef؉D_܍.Z(+--8#] u 0%%o6m{]H<Q`'""ỳ\,; :*Eb]P`0x\NNj w-~^NDD|B| l߾G^" üCTߝƼb)Co%ز\c}@`EHLd{ Y9曔EDDDM+Z/ tg8ԋ:<6=;;;q-16%@>"K8Ruk Jc]ڵk3o޻`0qܾ|)F0} x -)M]]\Ǣ?@ Eg..z;yp lcHҋkS:O{-X #E-]4o5uСdc#EylUlL%"""=Z:!"".8IM9˗;$+eM7xT']+QXղm LvQ˗/o`cÁ}:jAjjE^!a]sw`p6>x:zD;ID=|Y';Z'l6>uhXwG$Ϸ`M 7nx`jժ;vʘdF^R%acQ(j4]WqGxB 44J-""" G/$DD$uRKK> l<ш$,mtzIdG `KmZti8H,K5% Bñ@&20(݀ok DDDD:DD$89&Yܭ%MiYԁƣ8tIMٳΟg}1x1/[{ ٥ <\Sv6}26z(0L&:]*p%5 x^`*\m{xq8p/=u֗6v\^I v(3"7B.6g7y]H=Sއu>.XX@6޽F-Y(}X< NGNDD#p<—p˃Nܣ˚7B^ImPzz|1/D9 Yu!޺くˀynwvwXxwF&`nKS3@ pI ?q.atZQ`'""9u/+a!o8#qwTq FB˽$%iR(N .9 U]-gx,xzA*uΪxۄwqQ(a?\c(KDDD$l DD6@O_FN G7mF#z4>۹GV }ƛTGy]D=QUw5p3xſoĺ&Syt>*,9=;nލϱޫG˱ڇPDDDS DD$\w|Y.;iܤC2N|}Jvq_pH>ߡC1^QOuխ.V$,ӀX]l`jè @x bi p7~{T+^QH<H65H6ރFÎKjx|7 3Z[?'ȉ#Ou]Su-u\ 6zg0îzb9_>6ujj//"""+ DDdO>+pe n/u2鰳S㤴ku!魹|ҿˑ}WVVC]u!uܑX:쬺=?`.5=/6_lclUY`vWo 4ίj#BN@پ̴ܲMv6> ݓ?'%4lxj*o~=I.].GvW8΀쏽.KΩ󬺽9ʚmq Xc: .}Bx xZDDDKW_"")Qg;IneM~'ᐮ$lu5Z_M6^u/8HKKhº: 8_w5`;9n5To۰Qx =8h}:4oޜ^z_rw.1 {]DNW]UNQ׆`[c?=C[O~kz*1_H|itIjq} n-6LOrYA2@CFF~\۶mc޼yL23g㏧]v[cǒim@ 0qrkź. {gQRQ؉1gBZv""@*/3mPs<|㿴;ҷ>Y҉зOt݁k׮eΜ90|uF^^C Yf{}Nyy9>(k֬n2D_|۷u!uLM}Nlw ܋7\MInLXDDDP`'"R5 |],뱧%٥l`%~ʖ7Qq }eؠ׏ x]>-[B Xr%gذa׏Џ;w.>(v;vbQy]Hs4vVjP;m/RU7 ]&-w 0HNDj Hm?'59m`O.r>S >}:eee撟ϱ׭[u] '駟c81L:$ 8Ϫhm# ?Nk#@LNeDUv|\_fzJwUwѕPXXHaa!-[$77ÇӡC+Gd :'4%'0{7l/mҀl-!-?vIEDD$({:IBz05SM"wlܸYfQXXȼyܹ/t-[+GdoV=Ш߯6}u]uc+ {p6( lt3֕qtK+yWԗ`(p< -_H|$8Ԕ[x]OwZ Yd =z 77Cz֯_ 7@޽9sb~P83|PNNN- [4@WlKls̵<{)vv]T`5MtcMCbk:JHq/#c;s&ݝodwA/^LAA'O<ѣIIʺzk.$Uxz-w_a窝vaNagE1ܺFwS+j.5D뱳Z_VF#zۏT'9R]+--e0uT4h@~~>yyy~^Wy[nN:y]B`B0|!''g$nآXH7 (lg p 󱱲gȘ \}<%-g6~q-"""R(I|2ҮnvPJ&FkEO?4Cs 'кuk ُ?_Ոb`8/fgga~0s*xWZúahبP 늦S""""uHW|驣녴D4oV֬Y{GAAϧ[n3xrDv~] L|/o~I4o$h_#AgD-l,KXGݕB `M}ox\ DDS /3OK7ԅ.:e˖QXXHAA+W 6uy#DcDv10ܮ]"ya [u 6¾x1(Y`5XU.¸[21(a=^7|Jb/+Sg ו.r>S 6m撟O׮]k4^tEl޼O?#FG1l?#7pz투B Fbg+{Vv] <^}s^(?5 7kND$vR>MjְyYMJxp/XWoܹs2e 3g$ǐ!CΎfϞ}yԩS=z4q <,Zqƅ:S`08>''gq˔km. -=H!S⊈H+ ٟ/3u,/9e]W]tҷoذagfɿGG^^-Zn:ƍK/Ĝ9sK9ꨣzpU|va=l8]םޏe}Ui@_n46.MFiñJwG`SVT=L?6HS`'"2RӅoޑH u`ժU0ydVXe^uѣgu۶m㩧bʕ\uU|p#eÆ \{*nuyw͑XWZj ,;XWcZ y[$y&"R e>ngMv^Ze)lևIK. x_BRrssˣgϞuVN:$=X^xj=mO#l|z뭗=z5X7Xmu}p+JW"OWVub^v%ޖ#"""DH|ԗW=sL3^y_f$5XOfSPP)Shذ!q\s K.{ٓΝ; W^^Ζ-[())aǎ4lؐ y[2e )))5-q-u'dgg8V*3k:F`Zlq%?TLvIZ`c?{[$y&"RH]ⴸ`~^W]^W暏/¦M;w.̚5Ν;˰ahժUDO?qWһwoZjŢEXbK0dǎΝ;|~222"99`0֭[ٹs'%%%4i҄ƍkv`ҹ{0x8)X7d`eu(y7g?<-VDͣ|`刈H"P`'"||)^ixB_]tK?mwl:pW\y@yys\[z53f̠%KУGrss2dYYYQgyy9z+)))| y:>B=9@ol禨WX-֩}OצxU\5>`;` wuUH8IB_ ujSmO^bE`08 hI!Xl'O7ү_?rss߿?1ge…w}q7fp;R#Wy5M~[0]%ؙq oGL+.$Aب^))Njgשl %5\TaˋI\TTiCP^^Χ~ɓ6mYYY呛K׮]c}vx ӤI<@֭[#<OnO-`iMa!o|X`lH`6M"1:n=%\-|q-"""؉ćL'5stg8 ز' ^bmۘ7oSLa̙:t(۷i-?#saټ{~}Ջ~3fy'iӦMLk jq^pH'6v`c>GbMeXȊXx7 Rˢa ,|Dt:C DD[7'Xh`l̟?nݺǐ!Ch֬Y(///`̞=uѧOH߾}I_0vX6nO<GZ#!O螉(B,:nuk8 &K+Fg·z<Z:{\v"": YQQx]-[B Xr%'77:6mĜ9s9s&|m۶eРA 0Ν;ӳsN8R IDATz)}Y~aze}EH|vv\q"; Vgo]u=snF&6x۱ڻgA+x,+[H?7"rCP{5=7""""qDwºG ªSy]aa!.;w$77|=c裏Xp!Gu=zW[̙3yט7og߿mٲ[ҪU|Z7o2hРx}탍zO‚5f plzG`A*}<6 }'*5 k6:,/:oƨEDDD؉x;6p#t8Ot]_\\p~4 SII |̜9-ZСCw}`FG}Dff&F{,ꫯٴi_|1ÇA8/$ 'aH7=z\UWUKXV̾;|eρ=7ʆ*]+a~+Ͼ[PK*դV^66/k8ND$c8Syڵk3o 6>56mb̙2o<:wK']˖-ykl'wM׮]ٸq#o6| ;vSN;swz"%B=5#~3UGn»u5^p66Z[Yl>vvlJjyۀ^X(Y,\q-"""1v""uv\؛&eeeň[jdzAnn.C%333W_}_΋/H_5qgT;.G6;)AC=4lTq v{'mVΡXО;;^T{ =-ؐh ?^c)"""S`'";acs~{Ν;bg]E̲e˘ӭ5uw0;<w v<,kic LˀEs3b/Qp1/ؗχF*"vnx#LDFև\ם!V#?nK#p5l̼曼<z]NUuB@;켬WuE"=bg/T0CI~1p&p)Ԧ|s[Vގ3/Xf6T$EDD$(TIiQp@I/w"s}k(Q`'"a[.s֭>}:?<ƍm۶WNzu[.h?X7)Z^2 ұ++wl$6";x[JKOpv6u$lo  ǂȻ\ZUGhIIz'؜a>_]ھyF_al}2x;#uǵH(? UV5ݱcD,HĚ5k9S>|WeD[tH)p+,{ϮꆽX6[u{:B55K#݀naA2~UnʁX[r-ZfQ5ds,zIi۲Kvu+,]zdߺc#Wa0:DH\ o*č3fsqwҮ];˩`FtˆSm*MFZGLul$C+6FufD?}N1Lp`AĊ? xuv$/,~\ź'c!MQl0n9SZdiZmLyqˎDDD$~) xG^lŊ=\םnhW[k׮o䤓NOPҕѩSڜm>lH4  &bSU7 RؕOͰ vJtGd` yי(l}*ֽĺ)G`ݘ;X9gי{y߹IMt⵳5FA/5xDRuD"`CϋՈlu-8[>1 6E~]uckqTkяmaиx4phs>e3/G@ea2< ut ?pq%/"""a DD ,P٢ERҞg넹s裏r-ЩSH^u!]',qΥZ;p?p=PrD|`] U+l`(%y7;?; ;7ϟ*s?9Ig7pxfG[ʾx4os_ þz[CHzb/W/uen۶UuOJeZ~=7p{sΩͥʱ `?999HUlXp3Y֙~[h̍lqQ!u-F;ok}#صvGשUwv7|fpiEO7m]d0"HCQ*""0؉H<3Cjժ;w|u^Q,T1n84hS.  Rt XݾF)ƛ1X͈?lXp[}]5u}IϪ Ѿ̴>8}ܖ /Ϻ8%\`)"""qNȯ:F悀+V Ss?GynΝ]KH:t!v)Ǯ3c!k\op;zTM; `luuS̮ n#ϗ7Ѱ"2 [i-Q%ו=huwHNDdwWT, ˖-GxazzUuDqS6{ :Ƣk 8qt#݀Xj 3C fDHło>l|vXˮ:$i]ڝt؂D:?5>J-Ei#3o"""؉ۦwavUXb@0| %uygspCy&NCq ,ׁ gD1h}}--wbKŶ놢6"[DV35^B!̴i?{Ip`/yBVn²FiW݆b"v""%0'e˖|/b7Al r;!>F@/l$lKDllQlq߯ [.}-nlyex@PΓDxKH_i׮nGkvG7xݗt:F`]_bW`V[V Y'cahnH -yHύ~o.Kv[7 6̗ozcy 9^c]M+?7/#v9)w۾iG7o4ZH llaɊ7֝GuEZ+/H:OGa6lѢE)]׭#v^na;l$ҤbDlt؋[g?^^6 -FؼTwxA={N!ध|xd/=~1ŧ}pXP^W4F_~~Uu90-+0auH);6&Aۋ-JKK{ Á@(\r6 bTlk(k M?ba)Uv~^lc,lDv#g`gԫ3;F`K#cXǾT5" W$5k˞sMr20fkFS7u}xm,bW=onݯ/2eiyD;Oybqqq+u'Fx Y[tn"X``YJT,yX@ ;F`tk`q 뫃|itxNܣvo{dk\y9QI5:5_:_~~=waaNg`~QE׬ND3buXʕ+ۗOI1OCX@l*l. gDQafɾwĻx/#fg9?.(3?cț7D0;.ad'vҁ+s-5M®.Xgфzr|x-mD'fv/=5*n+˜\@.H&aήaٕ~,k%XGڛ@}7U9/INŎu""Q`HXaݲe:>#[^=]_/MT\,|빏n:`AC~ 0 qm\N$C-Dz 9—ٯFRwºl4A?ٗ+XH;.xwk1lLՈCu/""{c/4 ˗/`/ꃧ۷o_}b#Wc `߁V"uc.:FͰ㱎۰1Xuk<.娭؂e:E&[? =җD,:U`u{܁}?۰ð.y18RDDDv"R/ EEE:3F\,YX?a]-aV]doˉ|J̨[dyrͷqAE>1}oUw`!oR5یufcO ٜuxOZDDD v"R4FaaPȊOS @ Wc!ӿCxz,)^t7^i(|;'k#󱰡p6: َ <ֵ%>>'9z?~e<q/..>4j7>?3Gvb-N:SeWˠ}||-6W7Mgؑ "Wkl{6PຮQ,oN>n_*l^V s pi7x9 v~^$$_unFO/b}VĚo݉i޼y忾:<{F ʰ7{6> *urDq8,[P#"""Q;+Woa[6C-[ZTTgXnƍ.b `=C ;.Bj=.P/+Fltqu`DII~xܲr?AnaXsqb?+~Ķ~w6Z]Xh8vɵ/9|uZDDD4v"Rt;;d-|95;q֭NFՅ˰CEj3e:å.R9>\ '&8)C_ɏ/:5;Q'/Z(+j7<1 IDATZ*1XqU5Ϟ+ֿ`aպ!=Ch["la:DDD$ }It. ي+Z;ucQX:ׅG:p7gֵ@(cWflD:ttn:% q Fd|iyʔϋJo_Է&Һu_qKwol`Tv9 X9U <[`K}`q]r0 """AD6xb+[re`08ǫnݺu2}tV\E  놺 {;{q? /º.ϻ4`06 ӰF'.*Gd#AFdYYHfXn\͵{ \Mؿ9:_܊q?O~Υ 7[pVdz_ ƌ笈HBQ$Kڟ˗wug22Kqq1ƍctAlݺիWӯ_?^ZiI#X0<s`5 QXi}^~}L+^; :W'5m.Ku5Mw4K^yGnWQ+"2[XRc:|D>s߲[뱥ẑHBoD$6@a q {789r$1&Mb֬YL:RN=T6orΞEX5;0nhXc;@ldaymlwBK_fۍհdj?ݳͲe:Gڻ 苍V ǎU芅Men؂LN1ZR`'"˗TYWx饗xy7=z4)))C?VZCŤqw|K۱QyI!=E{IU}O1 zCY@tBҿ(/*)#錙xRHMM,Ɗȑ#tMէٳ'>, 6ȟ;0Hx&4A:>4(-u^@ql 杫g p yV3xyLCK\䵳,m' {s1IIInTlwLF"\1n ]s 8Áz=߂('@Q -醦iZҞC'̙3 ͆wNKK['A᧟~ĉtmrrr(_"511# ,GWſt7xI1?>.NA!\'ᛒh7j5gkJQ`Gz[қ v pqO"nv(0ZL !nOR7EQE /TS%Ti 8ngϞ>yܹs4iW۷' 0yaxR C~Es3w-@F1,uo*»c D HQE7 /!L+KlԨ4,1Qŏ.!9sX"V{yia!i݀EYߋuc; d!"ڭ ((({d`7ٳ<ݾyʟɩShڴ:t㯰^!D.h8nD{qt1 `<*;TFD"J.kiwO<ѯu2JÆ K:E }\<eWqNEj$ of{%".A:2ۉ((a v}7!k׮Dݾ'TVXAfڵONrrA XxXT $-FDiD"rn 4GRV!i~/,{I5՘:دG~H|\i v NiE o8~ȹR/\S?A@E\x((¯?EQd("K.55j+ڵkx4Yl"7Q֚Mxȓ 8lc!RST VRx FRˬX1#ږΰV\=tS'22TsGayJ䘸3FC:"ƿF}Iwnf?`@G"ߋOx@Rbaz(r(#򘔔H]Z4ԩ>MzM[LޠA/2y蓋[ Wl* =x(s|3H@׌5&4juny!Y, hgϞ QH]tg]3 4>#+z_bEd}@x,ȱ((JH(GR;8550[0ᜓ4Eorz;1;1m"{xGYG/A9q0DG؞i5|oX iB=t[o!]a}]|4)ߐc2L'9"촮(B;EQERR氧i>`\B<MʕvZvСCқ;y`jh>@4".ADIch%TB\YHk)pF3s_\v>We˖J4?+`-g{'{sg_K1r&҄"IGVGj E(#!U圠pqBdzi ?z͜9stmܸ9s`t|.6됚P"[/P#iH޲]iwșEO=qO}:[-ymIS|9SRR.02 F C__bA.UG:BcDRqW8@s iqXn8(:`(J |,T()ݻwG-6 cBG&%%3'_Bfϟ;sF1bę g-/^Xi^UAHڃcq|;zvY}qgxGɜZHARR!MJSH0&N i_ IC'2i U%((JhE^E $M琺BgϞݾwرQFINQcӦM\s5q74ͱIII/u'eΈss2CpC H+'x!Ƈ1Mhy Ň⤥|\zy+T[ifgC3};l:WW>GHCj$ݶ?}ts;`C8s p/^ԼC 7EQE .*)(Z+c{~^^Z"//ƍǨQ%11޽{SZ@p"''VƍObgejHOGr&nHs>HӄH=A+Pm?qymDD_Q5ٯ #ZIN|n|W7/**z:us'lB>ܵ.; θӮvllsGs <4脸^ <|6|=ם(`(J ,B df={4CXqwү_?:ulヵ0&"8La,$"U_@)_IDt.r-PAX܄*7]QnlR剻{, ø.11qwυȱy欁h.Ԝ} 4ns3I[P SsWDˍؙ~dpScQEQ5E77o"v.7 # 2gV^MZZyyyE߱cW0: f%DA _p3&l.ALZleUN!H#Ϲ (b?1ϻ_-㎿y-. X`f_n1@݈|х?ec+, H#ю{ u<I ww"A Ǣ((AAvېԖ+)\FFFWiW!·CcGll, 6I&4n[nĈL2f͚2̂|iڕr R<$Kl Rx mv5C}ף>qj3$L#?u![c}vB*zx9pL6ZKBBxa9@/J^-qGR"Xt=/z5zmf!@V kuήgW ;xf!O:=8&(rΠ(##/'6MӚza8;Ǝ;ؾ}?ڵӧOSNj-qŁ Lj}T?8@b /Bj3ӵgl{Rryn_?q "8S]e޽ rsspx=TGZZ۶mc֬Y=z_~:Z5kp|u`*Ri @k`+G" E;9=t\8[B•CZ! *qv5 ήUH@}ox q/qƁ `f8)~7B,g YtR= F[Vԗ>ngfn{[NpU yOѤI#~[ň'ŰX3`)t كӭ7g g3㵗NJr x3""  #1(^Pӂ(Eȭ{=CF}_yx܌ͻ"y'2V ~wPiiiv{Owgw+/7βF"==z8_lŌ" ER(>ę0RPUmpRq@&Ȃ| SvRw@Ę:).+"VXn]vg,ȭoם+``*񱈸z5pBwH©QËy+vYqE#]f!b]ax#^} d=]r~b"ˆ(^=|cq%=JYgȶxy~={66kȀ6ͯ<v{dwiO1X0Rh*#7#"4RW PW"/W"MBnTAj9EsH(%jaDGsggcO}4Mk{Pbbb 0 Dݐ8?q>RqcVv)sk'\%㛮7"+י+"J>&`@46;k*(JX(`{.M s@ w9'aDX3짲"f߇z6iii5}48p1cưl2_~믿nQ0f_F:cXH}^n򗅤mA<%Ȣ!|'6@l_K97dΎݑC\t1R>vOYU?zlq_>xFLIIy00 ubb?TGb"AC3 PF3_uE@u8@p [թmk!T@Rڡ>УPEQ!TSX-ё5Qcʵ:9U_wQnǞ>}aLӼvSNO>tܹȹ֯_ܹsYr%ӯifä7_n(}:Tw`u %# {# wJSPӗy^noA^S "B'W[!ΤA y B|_Z)mXb/an\h,XP}w}ȑ#:u3s%0qZ#稛 8do4p%BΙ==S(s %dZ"Uwe k /a"NþkWQEQE)ZT>ꀟ_ٜp ^ o{H CJm&C@:6táHg!!_v팈XS>7b3eWrs6GRZ%VՀ;wVHE.͛2e O<Ě!CLDķш ݑZW! h: L^3iqg7xq{z0kHC{}q.A“nuG}!]Y*$ZZQEQE%-۴~Pgfsb?]a܁iGE;y H֤ܹju']06]HzTRqsѷIq:}ZX%t(e_StUڒ= HMM}lmƼy\rzFywnGjWQmQO(`"z s'!K]#(ĥ|.]r } PCX(`(/b-c- j68;kAn͊A{QnˑwiXn@`z)SI{FiRJ`H$?͵?D[NuCklݺ5>&&&Wm-ܹsi޼9_}Æ ;{, Ҁb"g^0֝B"eAӐy_8{ 7!54y y RVQEQ|I謨E) ,ؿM v G[!Ļ0W?y0ddhiٵkWjuo7MwRRR,^bh"|4B\0{y#"M+b~EJh&GN4`#JV񎡈݀I#;3f hժ??S͝;+r  =6wyڟDr` |w-/9k* ıhw3nR.&-,ɵ8ŻC 6f_ua5Nd4D΋!^g F!["8HldZfeeUG| "> Э'"0+b?8s/[LųΆ ERY @5ęq'ܷxRI{l` )Hb]}DQAF`n"8f?pL@^p y'"b䜧((a v -񱖨5r䥟(JxY vqB/"-vB\(7!5 9-\(<Բ+HVQn@WHnsT++lT<q܈;P*F$&|t3M:taÆ1~xb@VV3f`ԪU[o4{#B[iCu\hMj#H)0u+R*; 20sJ@UBA#w}rHQEQKPL.)sW;NY!SYd(ia gH,9qb 0t#q E'|K/Gy%'aWz?7TEP_И3/@KsT@D,]t~99]طbym]pq5D^ ܧ;EQ%QNQ_gf,:OP:k̜`2ㇴcb߀Ǒ6D4V" +={)H~' IkW6,|CK D`S%0w(Jp؄M HLLn9~8#Fn`Ȑ!n}wlڴ)Sz;wt.H@tU~u] ؀tW}fH遟UsD4.@>r~q@r̆9*)(a* Z_+s_ TJ__2~:7NT+&Ad|3n~q@-@~H*p"q<=N30Y,R|UcH$97d9sR~{#Mr<4 ZdJ8p/"ڿIgaZ h''N`Ӈotgdd0}tf͚ET)^j tňPOls:|9`suxd uO9N_ym:Pf8s;YhkEQ%Q(2(vܣ'Oe5:3{7N8KLֽ/>(" Fj=8v ۑ:r DtUǮ(E}H8źRm|B"cY#I1nnX- imv$M:8G _2223f =z`̘1n㏌3>}ТE u%q(/#0"X\ R(7!F{GRw?@jzJl;j,g:/%"EQE!*)RZ!?voӏwO|zom~zC=ĞmAR3}Ig;A}!oB{J&Ro"0|Ѯ"L%#aY&i=b)R>* Ԡދ#b%f -zEq}HsXևSdtЁq~y\{L8q"RgJj h8>!'qZ"x6 BKHB_6PEQ(Jii0.cƥLz7Ӧ_GQMSkOk;bL^bRrsu9iZquJLFRRId#H,|HB\e{|\%fn5n WL߶)X̟e=)[Wׯ?55?dee1fZnɷ~;C=B*U"i܌&zP\$VtBRw]ڸs(`(Jii͙j]vk׎,>#z]~< W^FT2 kh3CJUwDv~lmagRGn"m諐O~H~cO_PU%"4;Vĭ8ڈEW3w(Um"+kCc\mByzسNO lJK%vi7Y '' &pp֬YyXnM]$"BE'Pc=Lq].b)((aE {E4n ޽bN8kxoj~O#aĵUVh?ƜׂaÆL\0`tlwCE "sžR0tbE)qE%U6\kdʹwVZEb';6Oƣu딒2ҩp=HII0ٹ?ڵks}9~woM5gּǭp3|)m|q;+FAZ{zTEQE)-푂.IIImW))))\%#'6<'QZ SѺuwj!"E+ ι@n1F"B_+JB!_ v ^ cDZo6^SyH}ZYj&9 o(%҄ggϞ]&M#J*aݗaza @?DkvKi7D )z5oP.8RFY+u2sb"TMRWcDů:چ{۟*dʹ̳H3n6jf͚]ַo_LӤcǎmۖ#GеkWLBtt47x#/\pA1MslRRRaA@M1p|/]\H@Ε4c׉ uz {]@a ͎#+"F*(EQE*)RF B[RSS!i";;?WJZQ.T'+b󗞔i,_um.]sz=)!8}~ETY,#]-YdSr%>=;(wy*7tpeDծ^?&6ȉ+TX,=4h(H.O%8Ic5Ν;[]O{:u*ڵ,Z8}Qu+Ur6"UGR}}m\sB;wCĠ"a*JnA\tGw')(Jؠ(1D*RPIMMvZ^{Nؕr7)~cx [avŲȑ#Zlz:UWb3y8^`\/`!MrO ,!tyXtnVVK؞#wl>N٩v;|j퇤Bwls$^P'D۴i.>r>(7nN:hт|LN>MŊKI^59993@;ϙ uކ_sa7? @^>-t@E^P "4AK`VAEQ(cwJG@S_m#yl|i"f%32 9#.H7тmO#y"u~@RLítc\<69uqƍ[~3ꫬ^vڵg!l}A]dT{~Dĝb%{84@cL:"|@Ii\p |XA)ͼ8EkD( TS~B 'JáCXj%W.I nV5ء&I]iAx#/#[i VrfX bA0kv9Lƈvӹl2}5ʕ0;0в-Iߋw;/vHHciǀD_z)HCW1?GmW^_|,\ Rb[m6ۗ.x伱#κ) X~@.Pc+8lG.^B?qA^P!Ãk9EQ%,PNQR@4( yyy(Թ"IG]jۉqd G颁ߐsE"u!_Ei28q]Ũg)c&\֞pu/]ZO?Mm۶qsbbSrvٍFavE#i5qmM!9e.pnttt*bŊ>k;kpBVlEuRN@ELtMCRW c6^u}Jh5Y銪1㋈)y=Gꄆ26"o JQEQ v8PI sIN##Y%A]8A/ q$r{呅m3đYAWOfkN*QV5vF\$0 dFƆ-o]T;ꈘ3i +& !O/۷o=cƌ3g,N6lٳYpYbiɯc Rq ı[ZXXԳ3:V5cDsNǐ:i@c{8h<фXbHm(E) !E4K˹ < +V (/!BR&p+!FtDsRg˼J;ETքs{ΉS\9]OQ?D(^}ԈHw_f"+_~?_ΝkۼάYX`jr7JD`u:"ڭsĵ9wT(] Y7z tݏ\.f!.ty 1bDjժѻw"'>}:Jbj퍤~DîsXW xu]t1+5M1@j&蘫?zs@x}(E7Ӆ4Ks `V%%%} J@:~Y_i-UGr].ݻ{G7shNQPW%Hd vwS`wީ^xᅹƍB kd[log$%%yݧIy+"獊 r!I@\pqWyHe[?l#i1+ P{]Y7)HCcl{!k(#e8(~)bu~&uEq XJ%.Fܥdʫ;va?# VHݱ@u 5pP?/ځG)7bffڵK9s&&L`۶mgٶm&M^iӦ-..n-`8Pi8Q͞""X1OpBjйxI~"B8]K~ ?q6(IJi01I#]EN((eE:j aRRRm<3;a,UiL= //  <@ B pPg9.iڴi`F[=z4رcOҬY3v?LMM}M6q@s#HCHMZ+ ;WR2w]-^~I^4q3y 1/5@pbޕ=](A4HQo 5(%%:xPi% B3~Z;L8[N'e5"@`6HG!#vzm8Qij@ LKKc̘1:tCd?θqx'iժĥL 6^zN50D] G~#@zޔ8t9G\D1j . ~gZo}(b7QEQEvxCcgf0Z&s4NJJ8q\3'\ b;ġgrSq} +5C )zIŜ9#rw70 ;p/iӸK5j#Gd֬Ynq\mZZZsź-"56 M3 3<"y!D/$M nLC:~T"pvɝg5B%;EQ ;EQup<|Iy9srßl!icҝ/8x 鴹yOcF!zo" H7{ND ^^$s1nliiigϞ;hӦ/H:~7ժU9A6 qW}8\(넸$sgi,qpW;8YtcD*,Bp݁X" K1 qOID(B`(7\,˥YdY%11q]=fye]M['IѓО޽f.@ǃ );x0]fxs;w{'nm`47'dƃ{'OgϞzӧOԈz Hϻdzc/RV8 cNChm2\tمHnB덜Sr x +FUN8M:RŔ(|#A;ݾai}킲{n垷XI}+7r .M6mi{S,T0.ZQ t?}*"<5@osLHDj_H'|rFOQ ,C1n/F4թSѣڵO>Wo|!AOA]w؁d 9 % Xq 2 ;2HqdVTDuӑϢh80Z㼂V )RF3R*hsNn4bcc <m.3ĚN~ҍ齇iuU+nos74 .'::z?PkS7nJ C,W ې>I JvmH@P$(@c?[d atSRRxGsZ\͵j{ql$kspl; D͉df~du{*A&dy# n>s~^h|-RJbGN(/8Mlv NG2󒞵& y+)ވBz% բ@pWA5(R!G3RjtDݛh&tҋBt?;'O꒍9H˫5שVZ@oFq_)UH6)͝e)oɲ)WȐ~^~*klo(,,l?$@V`<#nݚ'xLdȐ!;aaaڵ*#66x>g?/yH<֤dݶ oo7ho% 'X9Xp,R*hN)孖bOtD֦M-y:TNd{_Oz-QQvS;nxEZjExx~pe[_^=\ݏ .$ M-j 9ѻ4$:`ݰa8z(.aaaw6ܹKz~uH+ '7!AE׼&GA2HEiiioEFFA(==}ϻ}̘1l۶Sz87~? ҬEye`H*W x&ndl&2Iu-.J#H_xJ)THрRa?0ޮ]vӮ!rwx#'>[Oi#믽6{p)[l O_h_WniZ YHf^~^ Asr$0Fzyk B8Y` Go@2>ES?#qǟo=,##'x9EH@o$#jE``@~l6.?tC M2oYfyLYr% .r}c۟  s& ?a$W$ueڢ>smLTRJ)e9 )<1MjI\wY>\oJKԺ~Eߓ zn?\D*T~vGXW< SX \dۆK Q~!|+=dyk )d9|8\dB*kHVhdyvp`z~Y`ʕ3X7sLVXٳ ֹ\.Lk+cTX1;vE2ez׬Y3%.ϴC&"I_ ${BRJ)Ul٬ހR*5@&'}p8:pNMzAtڕyU2߄UU~^\O殴jzc[Ļo}E9X 0]4lC`u9mFMӑv>7 ̇ې)x"_QX^u# %!X2pbE111_}Ν\uU]Ȃ 8q"V"gv~馛X|9ٱc3f M4t߱cG=I&p/R" V Z= c7A'**4`uAKahOI]tHٲ/a}q?FlTeԋaSƿGΝ 枃f UFk"S%[ SL&ҟ|tFzMH9c$8M1Pw!ے9l2L̙3X"ueҥԯ_:swb 뮻[իZfn2M3 ? 9Wvc~[pl$րRJbM{),͕q6e5+d֥;iG'Qzu t֭ z"/#CBM]ċ`*lȀ6T)F7~sn0&)))$''SjU ƏOBB™ʔ)СC[z 9q={K|xH5Hv߬+RG7 r5')9tRJ)e) )܉.ŋwMl#""X :4|5>[vM uqԨQiX7 2ǎۀ >.'4u9}d4GDx2_uaO$ j/)`u Gz%)&&fmRR 0Δ=ڵLvݪUx7;wnVZrJ>cUe˖zlgffnr8]bbb~.Ac[= 8sZ4$сJ)JG)kw|9i^lll_ˊFxظ }yD"vn?dw0Mŋ3dȐ & =;dȷ\_Xdy{܎Lm|4(^`p'nJG4$,tѢE|wtЁaÆ1{lj׮/ x"66vF<#b#$[1y $[)*괇R_\6m7aL#'SRb2:?ҥKdb){ې^oڍI2 47 D(LG]?뼑W[ags88/̬Y ցdOw8嗈C(%>)ڿN)T ;;:!6w[ JyXS"v9;v+`ɽz 쩂8 T>7sOpB > 瑉 v7^eW[516$`cON:uEL|,22rn~EuՁx+H9$6uR%SJ i '՛P:)d06bɛoɊ+1c5M6m0R @gHTw4$p )܎Z \\H~~V/"}ERϷJ^G5[nO:u r%kjlƮK!cCz'!?AYy#`WϣRJYN3RQB8z&`Wl3RSSyGٹs'}Yv`OyQN8i=R"ze -C&6E"qHΞ #Hf|9R=T34|R}]9 Ap\A٠_Lge1/Rr]媌LH̀ `RXӀR*?Qp8FY y Q,v'OGTRSRb3πcHfsn>Cc3B%IS8ߵHH~@sUi [^jǀOU|^l*_.q27;!= ^: $&&2uw l6ѵ!¥~-XW:${~ ;R%Ry1@j]}MWn筷f;ױ@ Aqm+4kd=žxA7|HJ-LN:̚5I&1o޼ l@*p8m޼4l>Pxv‹H/A:_P%HSJ),;T^!/yZh 57"<L,6Co2vX""} ؙQ oAqʰ;v,{/qqqd!X 2mHH]W̪Uӧe{!?!/ CN |ҧO oP3`iwCai&4a93f  `&o+BŊ[sG#*BL yuRJEvJxaR166v՛1n'Q,.\o˻[yYyѿi\  AKdݧ2BT-w SO-D$8ڝu2H&"h۶-Çwl߾=[,80":R3ZUF&}4N)T;TnVO uDq;)ĮY[nӲr؃gYfgdvEO#="LV` uҵ>LUt7m6ۋ뮻xիIIIcAݜu(:\ 4N)T ;Tǹ?MNO111ˬD*%i?Ӣjr0v[+`ؽ@;0 e7ɢ }ퟷM`&2tyeDnUTn}d[>nQtt ?ٓݻo߾m޹s9>LVY:n)a έRJYBvJܼ_' 0aV# ǏStiʖ-nىZ-H@H?pdZ3'eTlZ+ 26aCn`d9x :uD9|846@X)$do4ERJ0SJU:8Q0i}(;V3ӉS4 ad#="妣H*] @ȥ?s_I#=2$_? 4h\s ={رcb^dkp/ۑ~VuJ)J )rkvlz! YvQQQ?~m9or0Qfn!^AJE!߳,M{xPR"0G.澞W^yzmfܸq%cMY0 lRJ8SJt!2O u pٳganNl"_[tiԩd=Ǻ\ù4WL5A2] \eF_swbbb@Jc=z4*Uikg:L>oq `"ҷO vJ)J )rjlhYla$jРH6W"##2e bРA\}:={6 .dDEEaA@UF&}>RJ)J )rjBio33) OSbMAc:uЩS'F͹a%,@OSruٶ!;}+jeff3sLo͛7O?*V}umsC'**4`fWޔi9o.]zk+#S@%"~F& !ُ C L-6xx F Ӹ:38p vbرoZj"Qu`(D~Ѳ | W A!RJ$$$f͚~O>>`Μ99uv0ƍuHj:pB)TnR!#"Mcfs0o9vye2f@kjΖ߁$Kɺd\L (u{! bi ,'AK@)SiӦѳgO<Ȱa(S aaaMHF]]6S \w L]$^#[[6&22qz~kWNBBs˗GnO?iӦ- 'Nig]?BM7RJv?2 O v~dddԽK'I $HRR]Ɇl \dVAʜ&aԿ>!Y8y[ϣXHIIaС 03˽=`&OܹsZjk Xs_OlWz#cR)*RŊR!%KnKGu4cC)))$''Srel"[rll>8p2 5"5Hpb:08=3Xon_YCmO"_H* YW\f钐@n:..@wW#_O9?90kK`1Tl 8[yR*U v맟~G9;/\lǏgΜ9TɣGVnѢE_NlH(Ɇ(R;Tgnw@M~f̘իٿ_*"##i۶-< kԩ]we۶m}z$S ^xEV lMn_ tڎ4qqq[nGdr?U1RZBن zE4p`>" 5@pA~nM$4'6U8#ǟx4oaz͸qhӦM6;@VrWކB44jg{%[wވRJ)lSJ ; r;nE2t2n8LW\ 7_LZZ6mbɒ%-[Dbbb}z۳g}۶mGB3Z`x'0؉ ˓gDzr׫WWUGz7G#rcYHv^$cɛ͋x.-.BUH$ȴʺ QHYn;wUV,^t۶m K K B^dǀa`[o9?A[pPBJ4!G ށp<-4 çA<z{۷k2|pf͚U>Ey΍#ڀ )WJ)J )@26yZdf d=RJy\_JIO[K,'dȑ < 4v Ye‘A*20<L,;0" -7؟o؏#yH`s$x o"2mùu2_OЩS'wo6l3g,P sg FʼRJHSJU.MVk&< UT>N4 B[`̌n #,,MA vz ",-1FJtfإ*UjENN[tn+TFI$"C^ #^[tdJ;9ܪK^Nj,;y$`Aq5УG;?ƺ~z^|EL%&=E^~X<4E&e+R%R>M'™鷀7|ɓ'׽@A ڵk4({u60 #uj << ]՝Ki1`rcnsڵS-:w{q{ ;[n`KH8$.ɽs] u*i$dCbccr`0xW_>=g̘1;w] SVo$ڿN)TV@WJyǫuYVr}5֭[iܸ1eʔ6 l׮] 8 &аa쫝arw\y _,dX.!}u\A̰6I1=Bvf90&ྫྷVqR* XfK 2-63Bm6G /wޜ>}-[2e yR<C5A3RJ`SJyտpT7 ?Nx֭[ǝw֮][;33ү_?Z:'111xy0嬋ht@@zҽ3 ؋ٝ <0b7%tZ1-6sOwϛ`O`6299;(_P2)WnnQttn4zp&LW^ 8ɓ'S~7?E@ywH(vZR*:N)u%E8n:XA'Odʕ,__(3fPBwj0}8LW Z <4 <#"/! :guy,xQk7$''rp*T@ʕV5k$<_a%"eO!pRz@J]RHHi~ YbΫ ljIXqh0z L:}2i$4HE-8hTAyo5SJ)NvJl1H//ݖ-[r|ʇ~5\cy#G0yd͛Gacbb~Pɜ& ߏ[Kl=/{j6N;2< Rp,_x,lL314~7oζmؽ{7DDDPF WNTTJL2\.N:Ezz:ѣҨQ#ZZnMŊw?28WV=<? A(|چH[ p ,B yTNa IDAT^%>FwfBzv8L|/_Yf|r8 |ȴB9TfFV7PJ)UiNui6Wf޽{k^1Nʇo< f͚7Lzι4W}Q@$0"%?L2LMOOTR!P $L3ty'5~zJ)4`TU,~+=~8Jǎo'$&&2mڴs7MsE\\~!RBW،tqGz edd~r}vkꪫkҥ -[)[,͚5Yftޝd -[Oc]+P\B.F9k8;QٟG[a[Q-BvEt饗t8ovv%4"SCѕAglN:bfmHveCuBF7|`x);EOkdOΓa$FH(i_i&Tl e^4^Ah!5(RD)J\ğ'6lȪUHMMuwN&Ǒ36mZP(|\wu^󭇻 ry!RPo#YFD F\ǡkN`)))|'tڕ￟Ν7|ðaøX'&&f'm&zKxCKTC,F6m Ip^D#A;?+EGG1"8[ITݺu;la5^7FԥϪRJHSj@bر#g=gf۷ӣG>̙Cڵy߈;:0s:}Y~m^z%n6tB:uXhwf_tܙ-Z0g_HPBmw--l;Q<~h2+ٜuiaXXIAqԩZlugR&d1C%` Knhݺ5SLbŊUVQn][&NСCgqHM0@iEӏÐ~tߑ>1@ |6|KH) o~Tr(&&'4? Ζx׮]YtnV^{Rm:b4`RJSdf={ILL$99]v4μy7o]vYY1J1ȤPongU03s}ѫW/ݯǏSOQjUzmv\yDDȖkժ)Sm|3""&)H0(N X$H Fz-Pdvz#N$PB0^"tjcəm".Z{',Xr&.W(oXR*KPJY%_OGu42pbϞ=lܸ7sAʖ-Kff&c޼yӱcG:t@͚st,X)UO>$ݺu㧟~ڭ[gk)Z偡HXksx1t4S `{M=իO'$==_N:ѼysڵkwǏD [.Nbҥ̦M+U7vfT!ُ&ңQy6 tΰz#0Gdvu챱;L4 ?zXWcl޼uֱ~ʖ-Kf޽;͛7>B <Z 2j(FEFܹ3۷Zj݆RRRHLLdɔ.]L.,, @-!o+H/PB^$4d"6:0|p6lcڼB `"Cf*!rAZ |vڱ|rjԨHB4ϔ@28!-p?/ɂEH_?_#!qS:u)Vc:eJ5x#6uKvvM_ߥJ)%4`TӒ Xz5NGUVr۸q#eʔ!>>ׯ8p ?3K.eʕTZ՗x-;P7i$"## 6-ǫLiH>Y& # x}yc0G^\r:I΀@FXlYkK*uu?37no^^B2ݬBʾ k)HȠAxgg^w\cciOtO6 퀝PJ)hNkI~*'M֭[xG}i\܆+>zkȴwpS*}nj7#ӿ1ܕ VtuΓӁJ)TTAv𪃾N'V}8[)))̚56mGsϱzj^w:L 0G&D~ <E&T7{8dj Sf?hݢEҥKA2Έ+T޽{y6m/۷S8-5u ov&7QL |ˆw7/ @ݙXשTî)SJ)?•*Y.v.E6~z..@<u'NbŊ <;m.'090 3%.`q5H['R ReODoG҈r֚L^_Auؽ{Ʒi&Hہhܸ1w&M_)&jÄ^a4_Yb-`'07kN6*ڵ9ޗV̊/?@D׺R 0L)RhN_˗ӡC@)))̙3)SPjUu9ɰ>˺.G2bɟU*Y 999r4.{`zOaZ=66@3g+W.TvgJJ N *CѮ];zE]a'%%/@@F7?_/;_,D&C~^[xi*U[ lϖ^Vw{̮p"4vPSJ)NvJ, ^ H.33UVGg$''3w3^z3l6[ uQy ؕ3 #%<<<7ߤJ*DDDжmmpΝ\r%\pL8ÇrH0縮=2n$0 >j#ʳc$'兩d5MFV-2vP`m,/i CWEF=wa'ta:6BsQStRJ)uaTX4[n+W~8^ze˖ѹsBLӼg߾}>O<윦izIѣGbĉ :} Zf [>q^hҤIA#))Q{#m,02%Ⱦ#C_T`BvC<-}[ 6ڍ/F[k/:Q*4_k+ R* )UrT@d~p׮]Q3ȞouC [.:ʓ)4'N^5eap饗2p@GzzY~='Of}gTPᜏ}v@dp#=,58"W[diR"RSS1o!")C1$`vJ)TZT؊ ,p+P'222Xz5~;fvIQ#Go0 i=}*7C'6o|Y|yN:@׮]ٲe  w`̞=URn]HOOnݺAZ={6qqon:^xj֬_V!0"ʛ hLq <~) 2]/vWX87,vn%a{}'p[o:!V)EvJXf 5jKرc;>*{>^@@235 ,ر vAD;ueߊe] (t2q%3-O2sޯ׾g<̹<,< ]taĉ M5pdIII޽{HF)*\ZoчvXDUYYYTWWF)ѣ9ꨣK.3wޙ5kְtR s=ZlSL[oey^^Ѫw; I" 'qLu gUJ]3i^V瑜vg͕(tґ>B!6$a'Dxڄ$s¶]6g^mg4׆)&lx|rBͥ\<?g&++kDrǎeg}Zr%=o&sSL!77`%K9zRGӲclNI0^Tym&ӂ;m5$6)2^ŋ1`ѢE~Ӈ{?;&YrV!؎|+D NTWWGqGG72uT9f͚ĉyw9c3Yf08IU9r5\]cgqmos_~q eܹp uQضѣu& "vJTU\XMցP|!*-D(p$w$%nzoCȄX!"I zb=n~)={E 6l4i+-]t76Or5aСCW.=Z?=Xs_~N:;mp-ХKk„*L- |zSd`G0v[z<b=Z>"m^=-ZS (A& !AHN]N{{=gٲetA|gL:յ`lv Ive~;J).b6nܘ |7ۏ>K./1cPPP͛lbR%ԝɸ1-&\0gi0G\PJM#JXصr22#/ƭ]bH+B! ;!R޸8p?o=/''z^{>8a~rr$,--b8nvGo0b)((`̙/`.N'M6p+Үot^#T-Z{'?4RRO٘d<B!Z:!DjS!Dv| ~^zE:pA;xԮ]w$8MmZ,b֬Y| >>5-__ٳg_3|k/;0ƌCcڥK>^XX2Y&q57k Lu7@?#kشzhNjkk'iRJ,i[{L4M|9PZ_*?ےBVJvB$?Hl<öPÐ]9۸q##F3gҾ}{>#y&LρNx^+Vb ,Xٳ_׏.Ao<۶oMh2Mf5X̟݃0}fg WlKwoDEd߾}.^^OGF޲) IDATs^1rvlՆ6@s2Os~T64gΜE@q 8Yly<etRDٿ,rEQٸ-={ A !T \8GѷodLdddd %j 4'C'袋3aÂԩCeС԰b ֬YúuR:йsg:wLffA8 p ;&)Qq IWaƎ̅S͍S+@e-l;=q6i>76d@鬟zKMo݀BINõqOؽ{z0$aO[0ɖ`G7p+gyyNoA^"Ѕ _TT۱ 8vYJHDI`uuUkLQe瘄pɦVWW?=RkmȌ7zhRQ'sl.M6sT66b_BɔX!kb9yEk=hҥ;G .|9笳ΚݬQ5?eYVǂ]6p(5s8bSD]qn'TS-$zfB'(..m 0o9\O\oώ鳺]^E園lXӄޘgc "xXi BF$a'Dr|v܈k&77]-N 8H ӗ*if^bvssA/n婛0UL:\:p0pQo x ؀Xw=85H=7Z̵r~vbv?œ3 UT^ + ! " |Sfҥ.o7ޠ,^lRõ~{9.fgR*_XZkA4Ti&PŘ ٚ;%1?f"8L]NSRRfgz*+GLks1oZ5抷b)D@3%KBH>4 u1j(.b ;Yt_xn$x R(a--LcSp077}M}2nN=ktX[ɔpD-zo#(-**r>P[|xd\>o|*W#b?T !q$ ;![$⒰mN:; %,v IHl(E|&\3l|} 1}/0zk~cB',+?w]DZbwˊlkmc7#4I !q# ;![6m5|JKc= iO3gNq$,h/;'آVQQJ̑`"[ ||tz2h 9N(o>0 j 7۲J)nfݝڶ?Y=i:^}@5®# M!H."yuҁ9as1uTۼ9%r333Ov;$Pi^~ GYP'v(͝;q4s>u}뺳5#=h&!P=lv )&J5zNZS =}dcV/f/첪xVf/a7Vrxd3.Bč$H^఺.'MW8d9kK#{7MuM-KϝRnWo$G ]j潻9+B! ;!Z똪=lfќxqnY)]xqOh)---*WW ֵ$Lr=n]NN"CcvLX<ύl3*Z{ҿ[9}v^\>?+sM5-bB0$a'Drݷ~yHKK:QOk=\k-3s;CkIiZs.\ؒ=+_s1Saa*t݁!tܝ0[0UD Ǽ&Ԩ2?dCe{ʱD̟x9 {.N8_[l !MvB$bLCM*ao]c)VaЧdohŪLkSβ,vh s-0 5IRoLv;sT{\~`>*-^ G}7o]UsW<2pgL9:UB!#"9%|D}ߺN8au`۶eDUIV,^pS< {=*nׂU~܉9vR.Ժ(Z_`s6w1m(7WKzBN%HvB!DX"9uQ xCk(v .tZ%&I.+Mn!Gm̱͘307l9`Bݵ?g0I-|l۞~찫,kJF;^~b\ucz˖׀/q?2{w' B!q]4'[}YNJzzzk۴i evㄝR*v{-]tA48ˁ/AJu?aÁHkAy nyX89J]Jyb(^|ֽQU{qωn7$a'B% ;!O.ϯG[~uwwVءcqZ sqZh'O1~.cK-đMV)nszcw91Z+7s(rz{l{G]U{63(p&S0(L;I !aHN3͜'Mk(UvJc,YRv p0;;" ($ߜ$TĄբi TIA`^[XXXz{=`*#}n8X_kWG Bn94fl B!Dʑgt#<¦M=z`)--u>ip;VHF@k}… ۸G׀Sf( nR*`YVj<۶RJ,˴56YMY7?S(8$$:ŷ2pB!pDvB$q޿~x lߺR®LG˲gUd .C)KWy%W _ZqEEE w6#gN?@C*Խc 'LB!''֯_UW]o]C)cɒ%D+s,IFW]RRR6᪌V6p (h^UDp R p~{4qޛ_hU9rRz+B8$ ;!KL3av <8ڴiCuu555N[%۶u;VF5iB%ag.RsE{ Sp ?> Н%oee0Y9cWTSrvY0L13@E B!DHN] h5UvJs?P3Ep588"(=񏒒0m0|2`$&q$6il+ܻ>˲&wܡcqOG1* 3db,^t uY®&A@ !"%j!GW o]C zyibjA;Im#-v+} ob<82BfPZk;wn2j1JMKYՁM|3Ys 8Z!$H.+jkko]C mKn[,Zh?@&FC';ge7W>pڝ~KLA`k_p_ ng=0rSw-R݀? B!D$a'D0~p} Uߺrrrx<)N\tnъ8J)RERc %u r;5sSHTJ3TFz\k} Uk[Oxylv$Mni B!" ;!*`!v>(6mk9(yyyZu;VQβ,ށK,r 1}r9֤x8@RczمlFmJTGFis[VgqSHi{YL5]ɮb舳Ra'BD@vB$Mh<2찼Hr;Vёt Ak}s\cReI@<b;'Xy=Cg/U>Ȥ񷐝Wqqq{'E>ip8B!I r0qXkGk>(WkwliFvR*lCs8LUWWK.T.qp16 bv#fjl4n-rqk]9GypAHuV:X''BIN'+?llSOƭo]C߷m۾ Z G ;_FlדعsvpqpLlߘv- Ds;Y9Y7NN.q7_mӁsM!8nDwM ;!"B"9Cd9ۧO^z%wߨ\zx w+rvJ)H|8Vیq.=\chmDH3fp~[hd]ґVYscs<~6:nO)T !ao 6pB)OD\|><O)zwG+hD9۴+,Xuq7#z o1_]sNv1ea>skS˲"M tLď|sg5r`m !)GvB$vNZ9:[GvMx/T \$ ;fY .nL3 0T`v )n61pebVY |ՏsqS\\r WV/p p6|7SqUW$BINo_q\/qR$&ve)&ED*8 Q JfZueJGpQZP׷3|Lߺsuu׆>h0sҘ52n7B1I uuܪI5wxnJ9:J/^|Kw^qiJ/pBP ܬFdg3tM-.~7'77wǔRN)iL`t`WuONr$V!$hҵNћzor;V $윻[kˁ13'([1'iӥs2hbs omۅZZq-]~p;$8a'Gb#[)u ~ .Zm>TN w|pX{vEZ l\;I !Q8_הj?SJ|{h)!A$ 9@J͛Úyn2wH~=޵C7 l*gOpmHK 8ؗ xxcYS c 3x{9B!D͠5{u3΢EF*D+jH"Tؕ+N阙K';$1MWn g- J}Y9?o fwojY 1C] }L-]C,aY4NӯtNB!CRa'Dym~G?(O>I`U 8@H$=.r{^¾¹ȴXbV .F=_WoT F_niQuASύ̗v}.\@ Pc B!DJST':j 8T{`~᏿-J+MKN$ֺD)]~ pK{V9nB굫1SVOZgJZ]`%Әpi\u[oN`(@>S a \D&;s !)MvBN1;#vYem^r6Yi7>oZUUZ{F)u8P5hmےReZlTRHTMT9O̠Á_GS?>u|;tbqgXհa6f%FK{cOTTGKݽ¼'Ka!'BHNƶ/u 螏i{~uVn @xoX\\\{`xJzD#Žgauu1f&@y=9VLbZM HBc®լ nh} G0rW0/=$1gGlGB\nHN!$Hh`sQ IDATˮ?W[2=ӈϴr{r{K||!e~>-/r;$8agYTEHk][\5_D=cd,`q˧)l?iu{t梿_u'Fc>dݣO<< i g7T !1¶ l5tRM@ X=m/߁~~0Cxтl'wڵ@] ],*q99+TT]TUtUjb9/'_OYP70L[cWeOELރaօ8 o׍7B!DRĶ6W(]9+//>]xp}]OzdoҬq$mf@Ųpiel}我p=<$"vH,ɕ8*?W1Gl(>\ꑏrpx{g}1=%"/拽i؆%v/1 !)KvB$۾/PZ1v&ih;d_vc2v++c"=!|6l)NiR7nǑqXa-="T[[[rUanM*/0Ga |yO+, :Aw(++[ \ LOX9R; 3.F% ;!"&"Ҋq$Y jߞLϴK<{;nz3|>tۅݎ#E8>[PPPAIb}6n.N&)*ft0 $Vݭ5h**Y>1c#z駟?,yI l v!_'BHvB$+۾#PZ1>X 3=]za{uh'?gT܏|/|>nJ1U60TL6BL՘&c"4`6pjc~fb( [põch߾M>u֕a1}8`ZWL2nlB!HvB$3۾-PZqkMNUxYaem²z/,=̶}>&I!vus-%aWpہCU`5&/j_rWC{"=f[t%SNv>k姟~7 /~Vv柞/1Ǐ⪸Mz^#S^ HANԑ ;%n3"YxZE.T{OޭCV$vxsO? h}mm-W]u7x#ݺuCc8:O` Kݺ>qX!"$a'Dkb%2](ן1(}/V~RN)e{w|>߾y]?ɑZ#`sO$LṮ/1f0Ut0^[vP(ߣ~Zʕ^Ǐ稣b}Ak=CHB" ,c~ r@N!q! ;!R]kҥFHؖR.3z[eL@_@e۶TJ5HHvr$֡Va0 x DBx1[0殫穘a]+=NNؕլloOVV;KTVV2|p,˚1Z4ⰷufPa=EJ'LPN!I b}.gI;NGsv?}VNf8 8zޑZ-Ju#*5aWD(a ;ZR@ &Ma%$v `Z/#k&<Ϡ]Cqt۟3f0qĆ& xt(=p{55!6 a'BHNduis$P6GAOQ;}@C\)>oRz8o|x^DC'֒sfSaaFIL2ѺXas#%)>LO$WHl6<8G7\v-7pSN%;{pv۶KEc0x88Љzؾ`va&A !""E{.x Px)|:osVǫN>j8<~U~ݥn@Wq!T)"WMdG)H-c[TWu+ 3tBkJYqݨ[mm-#GdرѣC>Ϻ/TƢ=,f*9x^j*8B'"L{sʮGLJ/hGI+^Q=ȗѽ,O p*ZZ?G ZSUUuuBј?%Hc-5a&&v b;V}9:Ut`MVح}}]d38n69:m+(p|e`>?I^sa']''B8)NsfNjUA>7vܽw.<bx[~G?̶YN-.. T4} %Y@1/q;C阞iӁv);b=STk7絏W.- ^I;,E!ӷޓ}/2֩0{⪨hivo`zçnQJַop}|DrSJɑXZ؆^Nq;II TF:+u@?#, w~T% vD?$?ׁ"|~9@/J ;!".$a'@1vigqM٣Tܧw˚ ׍5>oګnz,q9Nٶ-Gb,s,AB"Lu]0C@'@ԣ/l|rreY9Mbƍ;{wK(  }DS_2=B$/]@.Q.Yui~i +)n~tׯn@ŇA"nOvδ 5"11_W}S]lu)VA}Bɰ)vy@R*;!pWrWӫWl{$vM^$]N 9}Bш$ '@"J#ϡSԀ3T]{]nYS1GmmY7%;;KU5r$6lRv avI*d]fHDgVI5T$V+O|6Km@ ɓ'3h 9&wYC0 sn^ѯ }},|:ᰵp,Kvᕸ0?XH``p0LfK%FC'r4,a7w\x≦L44/܂& = XZN!#I !BѶ;lo{\RjknJz*/לmhI"Iصʱ%h58h!c0=b* UtHf_k6\b6=6nȵ^˽K~~-_xL6]UaI/q_!Bԑ)ڶ7WWʥgLoc[?_Ǵ+:g!J`AlG`(/ /fX`Lon<^H~3q%. G;Hlw'"'<n7BWB8Q  j2ʮ_ϻ|9Kf9ti&AЏ>cÏ(O_P'?++?g%pa7q®NyIiii%n SE73,ULL``*"h(9Jz% {qwcY}.|Tɥ5n@,S4"xD8!Bę$X ih]l*f/Ͽj޲iv_vy)HHv2x"4!wWM~`v_`*|ib^eҶM`cُZӿM6mZrkbJ ".lX3(B!DBDj5[\%PZ>̮}᣻~G)+0X Rtv_6>']r2xZ'ZC'HVwڵ RPg`zn5']0X9 35֞cd¬ xH+LUnx<5 2RC&.`! Nc>,BQZ%B?1M [EMM6^_(ameY<K=hsrˇoz4m., ;A1_l#!znkxF5@9ZHsҿ.xg]!?YX8BwRa'J0Gh&xTѻz'9rz lH|n%gw?Wo[<]:87ᛋx#q*q;$TIQw*L]}$C*"R9֭}opĽ\Lfğ2P2pB!HI !bSI28=vmA[֕w-MjAOwiO{v]6vxͪYBH4/{)_af`w1G^䒉#٫W <O#`gwc_gm1#Q?d:hw3e_Ix:~ߜ`ugq7So ɡ`)֮_Q&;VnV%J(O  V9JvXk}bL_0G\}lג%g 2" 31Iwg HL8!B"fa~}=b;0N:1zH3.P֞6?o}vbF4 =Oz|o;QVvrEj"SJI%T>ۑUtb*@Ki]R*k'v$&n͐B rmRa'B$$p K>o pi~k,.:.wsSl}?7})OPW̴#yjH$B*q;fTMZ#f"!U"vܶGbamum;ĭ|DC~r.X=BI !uћaI>o f;c=|z͊P,ڟ?כYSҭ4`6 &)0 s%lۖ)A(®3jG0`K̭ER OҪҳ"wﯯ0C&nTKuV8o|DC9V% !"I !9`<лJ)z/Tԯ_?u/3xmّ_ΟC'Rm~񑳻ܬ[s1U=@j 8ZCaz݁I>9גDIݻD3p?r:ngٶ.X,BseDC+@N! % ;!DsxۮkS R~5M{kˏÅ;ȚS&~Wag@Ai{ު紱||u 01`lZ":aY$H3 Uq_; SEܕD* [arʨvu<SUW~":琉`v2pB!H I !˃#9fR*P]]}.]Xyyyy|ɧLd6\o`WĿUU1{ڟzPwO~;ʆ 9&99$Nʑ ZlL;9u~=H ;TիMTX0a,! 5J Ra'B$$>%Lk222b|x<?pޛ:O%,g'WS"ёYY˾U=0G'?c"nh":xn{k;Jd}0NT݁I cktoz/Ds 5 IDAT۲eKΪUԩSD7.))Xby{8a!f*V 3P8_!HN&`*e>L GGU,w1Ͻ_Sp}[nZ =\?p-n)c\H~%쪫%a?R 쐻\yrS̄@̟ٶH7MYj*:wn|msꩧ ۻߛ4[ZD"HPdQ([A١,"(Qp@EQP P)((uMr IӤ)m4iY*әkDaDBk z9s(R SJUH :ud"R]xԯ_iN0:5=Ȟwqd&0T#'Xb"^HxdI@'?U QMMmӮॻkWō2)+ 8R[UX% :tȯ g}/|YZ8`!.DF=ZRJ1 )*$\t%r1_,qruGYJLL oƵ6CIo8CϾ'}Iz"-aKh܏\u:N4i$76*_%8qĺHۍj-׬YW_}$67;sbk]j0L܊PJ)ʝRn ,GFff'fѣGVy>%}Grྗpݾ)fi _cHy#},N~ 0 ϲ3M$fhnn|kTfKdxnH-Շ]=¹k5m`u2S1V Z^* (v3<ȑ#w㑞s,M,@&O'xC&@j_F^\:f)Re,7:Ȁw>x^HJJ:k׮.N@ZjŋZW^be@ľ_T߯crW'&Hirv]f8U ` | 39 ekL\p86 <{X-=ٹG4M47b;LQ*<.ܱH;X * ay<(4Ʉ 6m'Nl21=ygq-y켹gH$׬:[Ή ;02 ØgƠp<uՀȰq_Ə2׷m5iHAd JUf>3vY3><%L{+ogo~#{=EL |&`|J)*RAA. yINNvqp ^:k70Gy.`O[mxG{3Ff۸t46 JgIo94va7n\AeZaKxQ).jvHo ^?֘WtGwhi I ➕* >vNVBB׃̙3uo>wG| 2v(΅ȴ!RRJ)U$V)UY~v/"|<-v8?dddt5MsP=lۗ}ef<zqr9/_M䶽?[DDT5QF#HLx"TEDǮ*rcD%`B.vaX( XKT`L5&#Ō2,A/*pTs"IRU]>v?j*}7ofΜ9̚5{dz3=p"nek9RJ)U4`Lr `&pgno߽{wdz2VZZؽ{7/-\R ~Q}r/xkDDD$SBBBKOO_ LOJJOkd=< ؽΰ3 Y0 $@4͏_ " ӰZoFv4r#Շ\eۖ 'G]OҲ<!P鑖iz=۷oe˖XvݟȐ/}k yRJ)U )*L77 *M%&&SsܭUv+/"ǃL77n\xya#Ns0HLL\`H8+`R1VV:Qҳ=|zM!q=y1~̸~,1bʵ;A#ysP5$C2)؃dW#%#LNFzE!B@M@$1>g0ÇW/$633;G}իS^=j׮ =#Yܾ/=(R2}\)P [dyt:;ː 2͒wә.`vDD uڷ`40:RNy6"%~at>LH `UVyx~+p:ɓ"y:YcZrJvvOw@*x4@`;2`R~R t>DJ? 9*$]4?s̋bcON0M;3;ү_3o: fq_F~vu"9q%XRJhR:\C2plHG ghPn z8##cy*))) {ǐ>wど?8veo-oL`56r''n;?Afl-10l!jIt77\ e@'H7}`?0?0&!êg]VVVd`/HՋ ۿRz,C&Q\S%\RJhN)UmntoRyߪ90[NRLrrr %$#i9>w mUUAYlVIQC'2/>tkC~FX-剈n߷mHk[c[*qf}TJ#kHlUߊM^RŋD.Wd?#l`0) )Q0 1@͛Yn ,(riRH`(鐉ZbRJrQY/hR!j=k 7rUYـej̽{~UWR6mB2W0) :=,]x>MNN)_ jm.wק۵ӱ9Fjf*tF"Y_o#A3. ܽ LwC>Xv6l&$臢b_ _i}#2!š;R\T?R}@'Ne8))i~FFFiSZ1~SNܐyOGc"yYH |dT"~ x<ʡ$45ׯ_߽Fa4K6#c:6wZוjWtYέ=9PLtHIܔ~AsvY ׏z^wIHoRJ4`jv""MNt8SNg82X̜9#Gһwo:wmFÆ R=N4Z }]4z !$pɖ ,reWIo:4+G {K-8kLdwOVNKxu0uO1"١rc Kd8F9:yOEV{ WLkwbUIvu֭{csa2"D̈́+NR:iRJ )Hn%0*}v1իWS7|C+;KRja\3tbf?  084Dm/LCЉ$օ4M_,_QށX`%*Lbvmj%jQDo3?uA'3o ɀJ@2ޣr҃m7R{O[eUҀɿ;Fttt}L<sKD'RJrt](ې -4 ôvЁQF~z2d_=۷W= NiAt i @(2Vk;02 Øg hp8s8c.b,V:lBD4K|Û5!-|װ/~?jQ崝1vu|“7SAbA K9ufè(`WvY$!!vC&nG.$䅚phRJ)Un4N)Um#O[hi-@^̛7crr7ꫯrӬY3.Zh;R aaF8 x611qaY[C6Lv:ޯ:^8 XnXKLLT6hlVڬ#۵ȳfXD@<&pϜ}Nd>VvJҖ eHȐʨ$ '85`r+ .X- ;RhN)U}@z al22...0ŭZ 8E1tPo9r$gԨQ$''s]wqWim322ҝN笨kժu"L}ip vxw:[ӯ_n]>dbbWW_%eBqk]Ȱ<[Bc{t/~ şKi9k; 6Wxg' x)c?KEz >ve1d~ O'*RLvJ` 1һXGͯ[ciiiktؑ;vpDFFr 7vZZxzŊ+0J3౥aׯ霺wωkz 5Lv!Z-%2lOlIفF9㭱/U.Χ,ᣋy+zOr` w K(R9ҟ_2 'W]Å?a&KjQxDY 7H iRJ)U4`:dG8x&666mڰrJxu[]yGٳge 1wϞ=xH|;|"9r'Ҡ<c%~~퓖={$|ZcLwlukv_d-ǿMӸ_2o핳H5 <$8@؍Kp3`WfMd؍G2<D! yoRJ)Jss: 8P_322:hTԚƍNzz:Æ c…3EDDp 70l0y}Qf͚M7D޽Zh4ǺNZ0f&&&.7 E725r =OK3"i 2l!-W.ODtmC][:\؆Y˾1]cx+=Kծ<6R6`)$2iE 2S#!$Pʩ-`/p GWH xR7YY'B v;R\ ߅G@2!iQ0l "8RJ)UBSJ͞!nLOOb'SJ۳gO1|pwΒ%K]6)))E^l6 BY|93gdܹ72,@g4;gdd|>',,zep̭4D`Rrx,}I{%͖>fNh͸.7bRaBwb).7YfpMd.̱]{=]} 'IUHr:_' ON=f.%L!ϩaHI,H6s?dAi\<7=`U/>/_Fb3r֩SmaFFF"~l۶>}_^p\,[ٳgr8p`eɸ+lfFɤLu+{ h DGt3\B]w]#M诽^m1RRRv\uUŝb\bX$+Eoq5@ ) xHړxΥH9db֭E4>!Slo@3#b_+R6 dQY= (ۻvzbG3BN IDATM޽poܸq&[w p7 1 )^WVJ)T14@)uYZ\ (nnߙ4uwgmF׮]Yj~gg o߾\wuZ3f3j(JhhE F-Ҵݻw/JLL,ExQHil lFz|L̥Ijѝ=9 kzhyYJ8f"mathӖԾ#IJTTɇ)b#B26SHM"2Ɵ)%1 ɰ;^vB3@7QHק(>` fx t8MCz^.+sWx<zڂ[j*͛7M6S45(̎,RJ)ʆ)5V$$胏fN8/ ܹs[eѤЩS'5k<Vb9rI&ѫW/dv3EC,$pWɐzmh5VA!].][;;nY89k̑N\ڜk;vK.ԭ[7ïp8$F>>!eڽǑ, ?H0es)o;: jTp89'Rz)݋E(Moy+euX`ؾ)]@22(k+N[gロiӦ 3f /2w59H@vJ?uexRJAvJs"ҽedd\cHi<ڵkIKKĉRJ)ΠSbR"7yRLBv;7n$**ɓ'ӡCVXAffM\t:ڵ+-"//k%KsN:Tʻ4mNg  A.;zrl >IMυ$m9͑٤'fohnu6mDZlԡ'.nRRrX GϤr@Rb  ˽ DJd(KR^~T .}\ 0%u È,SL_~ B+2DS- J)TЀR\ CWy}>LJJZjFEnݚݻwo>S#F`…x<_l6,YBnn.}!%%ӧܹsb,Z,zaO8pM̂y3RƠGvi ?>n/:=!RJ<2qH/IRJ3 )eYHߪDl+i7"IKKcIP믿ݺu駟4Mz!FɓY|9v.#FEM*WdffN*z<7?˞WlIJs>o}ϲa4͇yHڸo-q%xM6q7ӷo_ `ѢElٲe%*(둀Ci,Rx ##%%eѯ=HIi?N J|f!So9qQQQ'L<'Hfi4.!UGnwùRJ)u )uH_^1M3?oiiiWN6mx7O˴;|԰5jЮ];z)ݻ7yyy,[1cI2M={6xQj+o/*zu>WNH[ðy߯ix1zAtt 0MuѿLBjj*~)&MAbOoR~jpv mC8UZA,SIU/@$x<}:9/>}x<,X@zQ۶m]v 0'Ҹqc=YC4O w+<dzo;~6Xxy~ image/svg+xml crystal-facet-uml-1.34.1/user_doc/doc/1_non_tech_intro_para.xml000066400000000000000000000045421415120503000244550ustar00rootroot00000000000000 crystal-facet-uml provides a graphical user interface to create, modify and delete diagrams, create, modify and delete UML/SysML elements, create, modify and delete relationships, cut, copy, paste elements between diagrams, undo and redo are supported, multiple windows can show different or same parts of the uml model, search for elements. Diagrams are layouted part-automatically: The user chooses the relative location of elements towards others, crystal-facet-uml selects the exact locations of shown elements. The user controls the positions of messages/transitions in sequence and timing diagrams, crystal-facet-uml auto-layouts relationships in other diagrams. crystal-facet-uml manages a meta model: Diagrams are organized as a tree, similar to a book's table-of-contents; Uml(TM)/SysML(TM) elements exist only once even if shown in many diagrams; Relationships and features are consistent between all diagrams; Diagram-local messages/transitions are supported in scenario-based interaction diagrams: sequence, communication, timing, interaction overview. Diagrams can be exported as images: pdf, ps, svg, png, text: utf-8, DocBook, xhtml, machine-readable model: json, xmi(TM). crystal-facet-uml can also be started from command line to export all diagrams automatically or to check and repair database files. crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery.cfu1000066400000000000000000001460001415120503000236470ustar00rootroot00000000000000SQLite format 3@ 3 .Kn/tablefeaturesfeaturesCREATE TABLE features ( id INTEGER PRIMARY KEY ASC, main_type INTEGER, classifier_id INTEGER, key TEXT, value TEXT, description TEXT, list_order INTEGER, FOREIGN KEY(classifier_id) REFERENCES classifiers(id) )P''_tablerelationshipsrelationshipsCREATE TABLE relationships ( id INTEGER PRIMARY KEY ASC, main_type INTEGER, from_classifier_id INTEGER, to_classifier_id INTEGER, name TEXT, description TEXT, list_order INTEGER, FOREIGN KEY(from_classifier_id) REFERENCES classifiers(id), FOREIGN KEY(to_classifier_id) REFERENCES classifiers(id) )D##OtableclassifiersclassifiersCREATE TABLE classifiers ( id INTEGER PRIMARY KEY ASC, main_type INTEGER, stereotype TEXT, name TEXT UNIQUE, description TEXT, x_order INTEGER, y_order INTEGER )5I#indexsqlite_autoindex_classifiers_1classifiers #Q0 `G+sL% 5 nstart route guidancee,Of # 1 nselect destination ͯz+ A eAnalyse Customer ComplaintWVw ) eRoute GuidanceW̘  + eListen to Radio#;UlQ! - dService MechanicVw  dPassenger;UlQ  dDriver̘ % esystem startȺD4 ' orunning stateȺb@  xmain CPUėd{  ysystemdė{:e # config fileėb@  Note 1Ⱥ{:e" / dThe standard userȺd{ |examplePackageė;<  Diagramsu"  / ZHighlighted Classė9q@   ZInstancebRع9q@$  3 ZClass with FeaturesbRعD4   ZClassėD4  % Zclassifier-7_p % Zclassifier-6_p/ % Zclassifier-5[;s % Zclassifier-4 ;s % Zclassifier-3=/ % Zclassifier-2= % Zclassifier-1 ҩ "!} qXA(eM6  F#9[ Hroyh3SfA)a Amplifier1!Tuner Chip0+Performance SoC/;Vehicle Microcontroller.Box-=Graphical User Interface,5Speech Dialog System+-Speech Synthesis*1Speech Recognition) diagnosis('shutting down')low-power mode& running% SW-update$ booting#off"/reach destination!)Wre-route in case of traffic incidents $Mlisten to maneuver announcements5start route guidance1select destinationAAnalyse Customer Complaint)Route Guidance+Listen to Radio-Service Mechanic Passenger Driver%system start'running state main CPU systemd#config file Note 1/The standard user Package Diagrams/Highlighted Class Instance 3Class with Features Class %classifier-7 %classifier-6%classifier-5%classifier-4%classifier-3%classi5dr%classifier-6/Network ConnectorV 'w`K3sjD-R&/ ,+start recognition- %'trigger shutdown % #(diag mode@$# (%end session<'#? &(de-activate energy saving8"+ $'update finished4!# #&save energy0  &"timeout,$9 (&activate energy saving$/ ($trigger sw-update ' %(start session #$sw-update '"! +)depends on# #%normal boot "#turn on !finish  continue  react  confirm finish listens listens  starts   triggers  performs  ) 2..2 have 0..n   shows! ,depends on ! depends on! depends on!  depends on! depends on! depends on &+%kB$wX 1 *`C' jN2"tV'! +statusout_signal(& dcommandin$% dstatusout $ c # b " a ! `  _  ^  ]  \ Wpwr`  T0\ TV+X# QcoordinatesSPIT Uvideo_1LVDS_inP [8080IP-port(1# R16 bits @ 48000 Hzsample rateL* 1' S16 bits @ 24000 Hzplayback rateH# XRISC 64 bittypeD# JClass (UML)(' JPackage (UML)$+ JComponent (UML) - JDeployment (UML)1 JStatemachine (UML) ) JActivity (UML) ) JUse Case (UML)  5 JRequirements (SysML) ' JBlock (SysML)!  - :deletevoid(*)(int32_t)  1 :addvoid(*)(element_t)& !/ :get_lengthuint32_t(*)(void)!  coloruint8_t[4] + 9Basic Libraries  % 9Drivers, BSP   9OS( 7  functionuint32_t(*)(int,bool))I(?2 -,+ ]ccn/tablefew##5tableclassifiersclassifiersCREATE TABLE classifiers ( id INTEGER PRIMARY KEY ASC, main_type INTEGER, stereotype TEXT, name TEXT UNIQUE, description TEXT, x_order INTEGER, y_order INTEGER , list_order INTEGER, uuid TEXT NOT NULL DEFAULT '')9''1tablerelationshipsrelationshipsCREATE TABLE relationships ( id INTEGER PRIMARY KEY ASC, main_type INTEGER, from_classifier_id INTEGER, to_classifier_id INTEGER, name TEXT, description TEXT, list_order INTEGER, from_feature_id INTEGER DEFAULT NULL, to_feature_id INTEGER DEFAULT NULL, uuid TEXT NOT NULL DEFAULT '', FOREIGN KEY(from_classifier_id) REFERENCES classifiers(id), FOREIGN KEY(to_classifier_id) REFERENCES classifiers(id) )5I#indexsqlite_autoindex_classifiers_1classifiers nnX++gtablediagramelementsdiagramelements CREATE TABLE diagramelements ( id INTEGER PRIMARY KEY ASC, diagram_id INTEGER, classifier_id INTEGER, display_flags INTEGER, focused_feature_id INTEGER DEFAULT NULL, uuid TEXT NOT NULL DEFAULT '', FOREIGN KEY(diagram_id) REFERENCES diagrams(id), FOREIGN KEY(classifier_id) REFERENCES classifiers(id) )$tablediagramsdiagramsCREATE TABLE diagrams ( id INTEGER PRIMARY KEY ASC, parent_id INTEGER, diagram_type INTEGER, name TEXT, description TEXT, list_order INTEGER, display_flags INTEGER NOT NULL DEFAULT 0, uuid TEXT NOT NULL DEFAULT '', FOREIGN KEY(parent_id) REFERENCES diagrams(id) ) mtablefeaturesfeaturesCREATE TABLE features ( id INTEGER PRIMARY KEY ASC, main_type INTEGER, classifier_id INTEGER, key TEXT, value TEXT, description TEXT, list_order INTEGER, uuid TEXT NOT NULL DEFAULT '', FOREIGN KEY(classifier_id) REFERENCES classifiers(id) )3vmd[RI@7.% zqh_VMD;2) }tkbYPG>5,#qYpXoWnVmUlTkSjRiQhPgOfNeMdLcKbJaI` H_G^F]E\D[CZB YAX  W @V ?U >T=S<R;Q:P9O8N7M6L5K+J4I3H2G1F0E/D.C-B ,A +@ *? )> $= "< '; #: %9 (8 &7!6 543210/.-         210v/b.O< (x3dWi (L?   UZInstancebRع9q@8ea48e55-8309-4065-b246-1cc0cf8403fcJ  3 UZClass with FeaturesbRعD40f6ce44b-3dd9-4d97-ad69-bb0cc9c4eaa3WH  / UZHighlighted ClassėB{1a8f51c9-abb9-4791-9a73-a9738761db9d<   UZClassėD44aaf46e8-822b-4947-8b05-79342398adb0C  % UZclassifier-7Ѫ~fc6bb2c59-4159-4039-b775-241454cb5755C  % UZclassifier-6Vv@0c049507-72f8-4b08-b938-24d197605a1aC  % UZclassifier-5=Se9027f4e-e1f1-42ef-a153-3b401848aef9C  % UZclassifier-4~f69f5a52c-a207-4d31-aec6-826d2242921bC  % UZclassifier-3PRi~fd1f5d48e-08d0-4bc4-93ce-f06353ba0a5fC  % UZclassifier-2=^LJ8cd005af-b559-412e-a86c-85253a8c2becC  % UZclassifier-1[ҩ41738b81-a52b-4eeb-85f2-18ef9d0556a2C  % URelationshipS'Ҿ=971fff79-422b-44fe-9943-eb296e4cec27A  ! UClassifierҾ=90179656-1de3-4a50-a7b9-8efe048abffe r -sA-jrrC  % Uesystem startD466ea7e3b-6468-4b47-81da-3c1c149dfe6e\'A  ! UdAudio UserU3Unfdc019fe-a641-434c-b356-c8a9207bcf00>   UdAV UserU3_cef7c415-6d98-4a17-bbcc-4b8d61d9725a>   UDiagramu65cea034-ef78-49c5-9e2b-03f7cc7a9b2eF  + UeListen to Radio#;UlQ514bbb3e-8902-45cb-92cc-0368a554a589G  - UdCustomer ServiceZ#b747dcc5-5504-4b72-af79-408ddf245eb8D  ' Uorunning state yP117e7ed5-fefe-4fee-96da-8f796e4e1313?   Uxmain CPUėd{cc03adbd-98d9-4a8e-a95f-651438aee431>   Uysystemdė{:e018c49af-80c7-4ff7-8314-07fb7a28eecfB  # Uconfig fileė yP4b696cb1-514c-45e3-b5d5-733799d758eck  gUNote 1مشاهدة أفكارك watch your thoughts{:eeb80fb50-80ac-4abd-9675-e51150cdf06bD  ' UdStandard Userd{36ddf5d4-cd9e-4c34-96ec-c1d6b28939c8E  U|examplePackageė;d%j/9  Uopend79865df-f6da-4607-8a78-a133302e2713<  Ulistens8a2a4cea-dcd1-4fca-b45e-588eac486f93<  Ulistens3a757aac-6e98-4c47-b231-069b85a3c662=  Utriggers880509ad-e230-4998-b611-4f9d92a0d83c=  Uperforms4864577c-2546-4810-a804-fbeb6579d0fc7   Uhas3c7e43b8-acf1-424f-b6df-258bb60a1d52;  Ustarts a698d18e-dbdd-43d2-abe9-32aefd0a0947&<  Usuccess506abd10-0ec4-4cf3-9bcf-5cd091d39d7d9   Ushows1f75ceb4-aad4-4546-9616-2566efe1c3fc=  U,contains 847ce9d6-56fb-44ad-8159-8389ef7c8bb1G 1 Urealizes interfacec0d0b8e4-59de-42ac-8d35-ee340046f570:  Uknowsca58bc09-8ba3-4447-a3ad-9266d620c2ca@ # U specializese60dd961-054e-4708-9202-0e763ef1dcec@ # Ucomposition 086b97bf-9c59-4e58-9c3e-5690ddc819a1= ! Udepends on93e79047-4c2e-4812-8f93-37b16a1d8afe 3w@t.j3q0VVV5.  U,-1457df35f-a9db-4704-85e9-6c6720fe698c5-  U,-2 2964157f-9151-4c41-8586-867012e672575+  U,-090dbed04-2ece-4791-8353-e93d4678952f>%  U#(diag mode@99bf2414-c82f-4679-bb19-b2ee74bcb40b?1 ! U<;aggregatesbcdd0f5e-ca7a-40a7-954e-bfbc72ebe4a3@0 # U<:generalizese267738c-3708-433d-9797-c88e40be45bc5,  U,-/f29a4485-24c7-4988-ad8b-d184a42f908f@$ # U(%end session<fdeeef3e-3eb4-423e-ac28-de5107cd2b4dD" + U$'update finished4bbf83d15-41ea-49a7-a75f-97f3fc86fb5fF / U($trigger sw-update f9e7f7e6-6b28-4f43-9796-5548c08f8bdfB ' U%(start session1decb293-1b82-4011-a0cc-39e921ff6531>  U#$sw-update18b52f21-eaaf-470c-b79c-8e119414631e5  U'"4def7aff-7f37-4418-8b80-d7936862efb3E - U%'trigger shutdown 4d8126a5-f7d4-45d3-bdd0-d8a7dd60fe89@ # U#%normal boot902930b5-a617-42fc-aff0-27cbfe485780 /v 2%^v>6.$ fPG?ua@1!Audio User+External Entity,!Content DB4'Images Server5 DisplayU/Crypto Key Serverd'Application 2vIn)Infrastructure8 EAsymmetric Signature Storage)!MicrophoneR EMax Temperature Config Valuek+Listen to Radio-List of Stations<List:Join} Iterator= Instance  Actiony/Application Layer'Application 16/Highlighted Class #Heat SensorhH1H*2v <2 secs <100 msGUIbFork|/Explicit InstanceC#Event Type?o Dial PadQ'Diagram TypesJ/Diagram Referencet Diagram-Customer Service3Constraint PropertysH ! Classifier3Class with Features Class CPUXBox- BlockrpBase System Layer9'Audio ManagercApplication Layer6AAnalyse Customer ComplaintAmplifierControld Amplifier1 AV UserA2 instances of same objectA 2t\K4zn\RA&m`SC7$'One Component[ SW-update$#KREQ-1003: Play Audio on SpeakerM%classifier-5%classifier-4%classifier-3%classifier-2%classifier-1)check validity! booting##Web Browser3 WatchdogI Watch TV3Wait for User Inputn?View UML Diagram Examples?7View Feature Listings@Usera'Tuner Station;!Tuner Chip0 Timingm TelephoneP%TLS Endpoint++System Boundary9Symmetric Session Keys*%Subcomponentf State'Standard User SpeakerS'Service Layer7 SequencepSendz#RequirementZ%Relationship Regionw Receive{ Reader>7REQ-1004: Dial NumberO7REQ-1002: Capture MicL9REQ-1001: Stream AudioK1Powermanagement ICj%Power Supply23Power Management ICT+Power ConnectorW!Phone CallN+Performance SoC/'Page RendererH Package3Overtemperature Offi+Other Componente Note 1 J 4Q9 vz4J@(   Uodiagnosis^I2146b0c6-11fe-4e69-9d4e-15d2f449f933E!  ) Uncheck validitySh 1c1002f7e-8291-4586-b7c7-94ef4bde710fJ  3 Unread CDATA contents[ĉv361316cf-9fa0-4670-a23e-01c498e52f35F  + Unread xml headerS3f84af1f6-d215-4a48-8667-07086a444d1bQ  A UeAnalyse Customer ComplaintW_f4558934-6975-47b1-9645-624d8cefa68a?   UeWatch TV#.c5b660d4-3766-41af-9e61-99a7032d3ce5R  C Unread element and attributesI=333aa2542-3744-46bb-b032-38e8f514c0daK  5 Unselect file to parseSĉv836dd632-86e1-49a0-bdae-dee9e3e89363@$   UoSW-updatexg/a8f03903-8d9e-4a62-bdbf-a1f54d39e043>#   UobootingxcFhccc4ec715-ccf4-4ba7-b58a-4f8a05639080@"   Upwr::offg/df0f8e13-9164-430e-830a-fc54259ab4590D'  ' Uoshutting down^I0b89728c-13e1-49f4-9d2b-3b3ed1b7f907>%   UorunningK}\.44779792-00ab-4b6f-9686-4f30da0e113f n\K=n(FD6  ' U|Application 1ۘGMdcc0baca-6eb1-49b3-80d2-d979e253b516D5  ' UyImages Server ѝe3062d023-6dcd-4805-a090-07d7eff81f32A4  ! UyContent DBc]9ѝe443a7597-c5cf-4463-bc9c-ef7e576ec14cB3  # UyWeb Browserc]9²*420ad9b6-748a-4876-9578-dc13270d7983C2  % UxPower SupplyF))Ĭ04156c73-4c79-4740-8280-29c8b9b06c64@1   UxAmplifierF2010aec3-c246-4155-8ac9-28f67d5c84bbA0  ! UxTuner ChipFY]eb86f050-0a69-456b-aeba-52da0a304bc1F/  + UxPerformance SoC' a4057f7a-9030-4296-9a50-96354390febc:-   UxBox)+Y]e5f05f66-e9a6-41c1-8548-f54aef76a2fdF,  + UZExternal Entity-֑w]y59b15ce1-fc15-4d63-b88b-b16c8b3a2b74C+  % UyTLS Endpoint_xвM06e05a9a-27bd-492e-a87c-11be2656d363M*  9 U}Symmetric Session Keys[Rn871926b6-af65-4078-9067-562b6c436c62S)  E U}Asymmetric Signature Storage-[Rn3f625e12-c9b0-4511-a198-308d5c6902f1 '/Sf/tA/'CB % U/1audio stream#J96aeb3f3-ab6e-40a6-bde3-cebd98cdc7af7>  U,-I#:1e0367a9-ac97-40f5-8c72-20b19512495f7=  U,3H+X29e0a87e-1052-4e76-bad3-433ae828ea4e??  UI2switches#>ae591f89-128f-443f-bb1e-777eb3feaff7CA % U01audio stream#Fa7e1ae56-37bf-4bdc-8906-30a7f9da6d3c7<  U,7G|00828876-8dc5-49d6-beda-47e2b48e980d7;  U,7F-@a5749fb9-2328-48d9-be1d-13a04caba24c53  U>?b8687be7-647f-4392-abd1-9d6dcfcb68fd=2  U:=realizes b350cd84-a48e-40a2-8c72-c32baaa0a722 tEZ+j; P;2))^-U7bd25e43-4323-4552-9af7-e23469ead770-U06069509-8519-4d59-92f1-44812fa9f6a7-U30e69d45-eb23-47f4-bc3a-9605617a269f-Ud34a4ff0-59b8-46eb-ad28-7e6a9aba18bb-U 7fe4d98c-fe91-4e47-9751-ffa9f170a2f5-U d43beba7-ad0e-4d05-8838-148c56c03f8b.U 5461d913-827c-479c-9538-de93b51a27aa1U 6b30875b-d0af-466a-b475-c209f09648eb-Ud4ee3c92-ea47-4cec-ad2d-7f0fc6ac72c1- U 5e9a589f-96aa-45b7-8bac-cc469f61bccd- U f05ef644-aca6-404f-9e6d-734b1b4228f4-U1fbe8563-7949-4531-8cf2-8289ef7c9f99-Ube14d267-0a0d-4c77-8af3-f46b44706bca-Ud223b3a2-436c-472f-bccd-3546aa310a20-U7e1c8ff5-e6dc-4fa7-b57e-23f1f1a1e24b-Ucb83a620-e469-418e-8c64-6975f9a34410-U66361ad1-ed26-45cd-801a-7ce83c2b4ada-Ub58f199f-b3ce-4ea4-9a78-3131025d7d4f, U1b484bb0-f9f1-452e-b3da-9423eed84e77 Qf"sDY*fn7Q/-;U #d4efd315-74c3-4556-93f0-b30bf0bc96b3-:U %339adc8d-90d3-4c47-b699-d46a60b24422-9U (5c633d7e-5369-43e9-a51a-f45138a0260b-7U!730d92cc-2ee0-4e53-b811-32c1354b5685-U990bd4f0-7602-4fb9-8c57-de16b1fd6a33-<U 'c0c3d76d-bbf3-4274-b2fb-3ce3395f424a-6U 7b6b290b-98ec-4ecc-bebd-90edc5e8c268-5Ua4f6a103-c740-4c3e-b0a1-58827db9c239-4U4a6a26d6-0178-45c1-86b0-e07228dfaa4e-3U965c6d04-9b90-4559-999e-13e4a0cc30b9-2U93d9d966-7455-47d1-b14d-47829416b647-1Ufa8f3502-b267-4de7-af58-3b97ef8076b8-0Ua12d76fe-9582-491d-8853-7cc198497b29-/U36657fc1-818e-408c-bbd4-5b9a647fff5e-.U61b75026-6065-4c13-9f22-88980f3483d4--U1155de7a-b36b-4cf8-94b3-f742310f7a1d-U3cf68d48-a834-419c-98ee-21398de5d632-Ud93d9189-56f3-4e1a-a741-575079751ecf-U5d16378d-5eef-4203-88c2-06886f15d1a8 !u-R !M  KcUcREQ-1003: Play Audio on SpeakerThe system shall playback audio on speakers )?K6232c069-8281-40e2-bced-6a0b78c51491rL  7YUcREQ-1002: Capture MicThe system shall record the mic signalVW352158fa-5538-4070-96c6-9b5eb1939784jK  9GUcREQ-1001: Stream AudioThe system shall stream audio )r ) UJActivity (UML)69b155c8-bb19-4356-a4c1-6b0b68e71059D 5 UJRequirements (SysML)9e686748-d9ef-45de-a6a0-2ab4e318f5c7= ' UJBlock (SysML)0e2cce8d-9a82-4e4f-9a73-5a6ad45c098eK !/ U:get_lengthuint32_t(*)(void)d0ee9802-bb3a-4080-bd28-78740167d5a4M 7 U functionuint32_t(*)(int,bool)5c6f969b-131c-4f1d-ac17-8155ffacf958? + UJComponent (UML)9c516583-b31f-4a3f-89a0-c43896bdebbcB 1 UJStatemachine (UML)07ea7ffe-4146-40b2-a966-630212683438> ) UJUse Case (UML) 5a326c6f-c3dd-42b9-b60c-e0f581da8d9bF - U:deletevoid(*)(int32_t)26d9cea9-cfe0-4a28-a62a-2f0f7ac14f02E 1 U:addvoid(*)(element_t)8f28cfee-74a2-49cd-85d4-137353502bf3<  U attributeint6d019fc5-1f6b-4d75-b4f0-cae9e4c9f73f? ! U coloruint8_t[4]124a7efd-6f19-405a-8312-d321a9bca414 X1_!XQX1/  U]921756bc-7e6b-4679-95c4-4dd9a3d371626  UWpwrfc0820590-cb63-4730-aa05-c41e440ad3ac4  UT0jV\d300c769-e3f9-40a2-b368-01d7eb0bda0c5  UTV+_{438f6352-cc9f-4a63-9ad8-7c9f9149743f1/  U_2fa49589-316d-4472-96db-34b9fbb8b128/  U^18411ac8-d373-4180-89f4-a3067c555857/  U\e4fa4e5c-a1cf-43e8-8916-077b1b6b5c1eA # UQcoordinatesSPI+\N6efb0a6b-801f-4bd2-abcd-631d2fcb0461A  UUvideo_1LVDS_inU06b604f9-5cef-4ba1-9b0b-46310ff9f65b>  U[8080IP-portE2758fb84-3593-477c-b6ca-eb8cc3b906feM 1# UR16 bits @ 48000 Hzsample rateL93ced61a-ae31-43b9-bc4d-ae31e5f7f73eO 1' US16 bits @ 24000 Hzplayback rateHe1a0ffae-f6b6-4b31-936b-6d598f8f1040? # UXRISC 64 bittypeD28fa1e31-acb9-4261-9fac-4fac097c53d5; # UJClass (UML)d4c3ce64-203e-4ffe-95a7-dd5d094195ca  @~GZg0#@ =X  UXVdata out<2f17e5dd-404a-48b2-848b-f33d772d605dAV % UTXpower supply4ac2104cb-1977-4aca-b27d-6ac7743592485O  U,PR45a359a4-8486-4d92-a1a7-3c3c1fdc563b5M  U,PUec6e20da-7b67-4d7c-a053-5bffea33a6d15L  U,PT 5eb37c6e-83cb-4da1-9a0b-ac510a5e9a855K  U,PV7db9c5b6-c58f-4dff-a99c-27d4e2b2ff4e5Q  U,PX c2179e9d-5ef4-400e-98e2-cb006df9d1785P  U,PQ7e8c4448-d49a-4e81-89de-07760899dbfd5N  U,PSff1429f8-f700-41b1-8716-69c85ecbf5d25J  U,PW877705ce-7533-4426-95f7-90e04379c69a>I  UMKaudio_outd2c9e312-b121-4505-a8c5-491ad9030a4b=H  ULKaudio_in 204c5fa0-ca58-47de-a762-50eb949640e25G  UKN95d7070f-7e09-41cb-8bc5-bc5130efef1c5F  UON2ba5f578-675b-4be8-bfe4-c1d325ef3c63?D  U/1controls#Re1d0d4b8-036b-4bbf-9363-8650c6dc0c4a?C  U/0controls#N9681ec2c-c8f2-4de2-aa98-9d4bdbca0f8c F'm_JvY,A/R - kZN@F(7data change animation/communication Lib!next token5select file to parseendv read xmlB diagnosis(+create result 2D continue?~#config file+common ServicesF%classifier-7  nav::end%decoder::end pwr::off" timeoutx startu shutdownq'start triggerl+play music :reqg unpowered` systemd%system start?starting operating system^7starting applications]s+read xml header/specific ServicesG'shutting down'n)decoder::start'running state running%nr#storage Lib%read end tag3read CDATA contents -perform action 1Eoff" main CPUCread element and attributes7initializing hardware_g!pwr::start/fully operational\ o`"Xd3o.A/2  U,d46c62b3-221a-460a-a483-6e4b84cf4d5e/1  U+81cf1538-9cc2-4c5c-9359-dbffa2d99576/"  Ua87de2766-3cbd-4614-8993-b05453bb9007/!  U`1dcfc895-6759-41bc-982b-874a981e5791/0  U*04340b08-e0c6-40fb-bd1c-48a199b27370//  U)dc2fe71a-359a-46ee-a1f0-0318b35e12c9C. 3 UJCommunication (UML)277c4cf7-cad7-4bd6-9e09-e01654cb764b<- % UJTiming (UML)0886b9b27-795e-4351-922d-2af76eeff408>, ) UJSequence (UML),df016e0e-3f3c-4b4f-9a5a-966297d79ecbD+ ! U+requestout_signalKfL327a76b0-a019-4618-a15c-5a06bb18f6f1@(  U+/dev/tty2PipeL6f81c351-1dda-454b-9c01-e25ff625a7f0@' ' U+session token ub99b01d2-fa42-4534-9f69-f1ce77f5a3b7<&  Udcommandin5feab7a3b-46f4-4ad1-8ff0-0cd6e2930e6b<%  Udstatusout榼843bada4-520f-4946-8d4f-fc469ea39d03/$  Uc02770a10-67fc-410d-a08e-5b1bb47aca2c/#  Ubf2e9a281-239f-4414-996d-56803b605733 |KaX|3IJe  + UyOther ComponentwͬB{ocb019de3-b5ec-400e-bb88-b6ddf7e97354Hd  / UyCrypto Key Server_xѝef4bfd848-e203-4170-9af8-4ac7385e03d3Dc  ' U}Audio Manageru6 e9156e50-cb51-48c9-895b-9e3f40d1382a:b   U}GUI},l 6edb18185-61e2-481a-9cc7-1d615384eded;a   UdUserrpf40caeb2-68d1-46c9-91d2-5c9cdf3e35f9@`   Uounpoweredj334537079-00e0-4c76-b92c-40e918fc6d3bL_  7 Uoinitializing hardwareSF/0be5fb1d-6ca6-4077-8520-8b893b448804P^  ? Uostarting operating systemxCF/accefb21-ca6b-43dc-8848-3c203d0b0e94L]  7 Uostarting applicationsy304ad2c4-77cd-4e41-9326-07136ff7dcbfH\  / Uofully operational?E{24ea7879-939e-4973-b7b1-69f1a00e75e2D[  ' UyOne ComponentwͬD43aa2b31e-5e64-4272-a89a-77c624f4ac5dmZ  #cUcRequirementThe system shall start up within 1 second.4"D4961c9cb7-0e7e-4710-8279-4431b95d032b )D `'|C l)Ak # UQXtouch inputd814777e8-eafe-4ae1-bdc9-9cbbc83cf625Sj A U_^load and start OS (100 ms)5՞ f92e9b0d-908f-48be-954b-78b81812decfHi + Uabincrease volume`J/"#af7202ff-103d-4468-9c3f-980de43d064c6h  U+HD'7a6d07cb-907b-44c9-988e-0fdd310f02a27f  U+d<+&7172b7de-37c0-47a2-8526-8350557bb6727e  U,c6 f6d77278-40ac-4040-998c-b0069da0efa57d  U,b\f45aa8de-987f-4b21-b840-a72d5d4a0ff17c  U,a8f64159d-f2eb-40fa-bb25-edac7d876df07b  U,`37a1d36b9-f6d0-4892-866c-5cd179544a167a  U,_f7e72a49-2729-4b1c-ba75-589ab68756327`  U,^F/e7080b32-8292-4729-a984-25e1d77879d47_  U,]yafbb7427-0188-495c-8ff9-8c03a49a22367^  U,\E{f493c1e2-c56b-4ddf-a59d-22ced885225f<[  U 2. lock04fcd7afc-eb7c-4d2e-ad3d-6042fd96129f>Z  U 1. unlock,e07754b3-acb1-4a16-a7b6-5580c9507a82?35709a3a-475e-4643-9418-3e4fbc66108e9  UkiA=e707d760-7d4d-4464-88d8-e633a8bb63a19  U55dh87a2afe20a-e3cb-4cd1-83aa-353ecbf044909  U44d1h654e89d341-dad1-4af7-b7bf-20e9293315d7<  U3+calldh4838a30f7-945c-48e9-ad06-797986d4b9f19  U++d1h4(da091386-0cae-4adb-a2e1-13dde71f1f5f9~  U[[#Z-3fdb958e6-dc9b-4921-823c-d7d1d908609bH} 1 Ucommunication pathb3f1d27c-33bc-4011-a162-6efb169ef3dc@| ! Uaggregates0d2a015f0-1da4-4395-81ee-028a20c2f48f@{ ! Ugimplementsadf1d1e7-a0d4-4d0b-ae8a-87991feea5e0=z  U*+5. ackX01557f6552-432a-4f84-af68-eb9f0120381eUy I U+*4. store generated session keyT10e32d455e-81e9-40f4-8e2a-79a83e9dd055 u/]t\99;D7  ' U|Service Layer58509a8e-3833-4e32-95ae-50de8926c2ac A  AU2 instances of same objectSeveral instances of the same classifier can be displayed.ėP[f04ac7df-4da9-479e-a24b-68bcc371fe0eo@  7SUeView Feature ListingsThe reader checks lists of featuresˮb8e0e9de-4ddc-429e-a92b-1b9fc51d8b8ev?  ?YUeView UML Diagram ExamplesThe reader checks examples of diagramsˮ3328cd45-4906-4211-87b6-1fe5f466d0a9=>   UdReaderˮb89da5a3-66e4-4577-9e2e-86e0ff92d3c2H=  U{interfaceIterator*lt458884c0-6398-4a61-ab99-3c8cfba10b70G<  - UZList of Stations`6gm4cec37b4-0b32-4ad2-af76-0bb6b0d93426D;  ' UZTuner StationՎz4932e997-c410-489d-8dc9-d5118ba4ceaaB:  UZgenericList`6tcbb8c23c-04a0-45cd-8c11-9b7af21c91a0E8  ) U|InfrastructureURg8b9e7f06-0c23-4765-b77d-534a0df36e84 V@Q--FW:X   UZCPUϗM}a3fc76c0-97a7-419f-acc2-8b37823ed0bdFW  + UZPower ConnectorϿ98f22d96-80fd-4f93-bb88-8a1bd9952cb4HV  / UZNetwork ConnectorϬp6b78a168-49df-4ff9-bd5f-f4a17f5f2775>U   UZDisplayR259cd218-e04a-4b67-8fe5-f58ccdc55ae2JT  3 UZPower Management ICϿ}e66ba866-2fa8-432a-88ad-853589e18426>S   UZSpeakerRn453345e3-49bd-4803-98fe-09cff2f6ece9AR  ! UZMicrophoneR787bd029-c41b-4305-a575-871a19db6078?Q   UZDial PadϬpfce3ffeb-62d1-4689-92db-83387adbcbc7@P   UZTelephoneϿba881e97-1072-4296-ba29-6abc73b7f252zO  7iUcREQ-1004: Dial NumberThe system shall allow a user to dial a numberVYR6f5ab8eb-fc62-4560-80b1-5d840a9d3661fN  !WUePhone CallThe system shall perform a phone call҂OKc42bf08b-b197-4820-ae47-89620833f159 ]QYz1]55<HDq   UshutdownDԱ:E5fa79a3e-12c6-462a-a5d1-4a586bedeb05Gf  % UzSubcomponentwͬ9q@kIt1b7cb77f-656e-41e2-b67f-740b50234856Cp   UpSequenceQԱZd62ac46e-8c4a-4be3-a4cc-6099c9e930beGo  # UEvent Type?ZUL880149a3-0a40-4383-84e8-f2c43432d912On  3 UWait for User InputQ׶A6be8ee9a7-9671-457a-9a71-48d37bdc3ef5Am   UpTiming̙A9a94c6cf-3f13-45ed-a2a7-a5c6d6d7aa3bIl  ' Ustart triggerDzyba008ea0-6445-4889-9ef4-eecf2104b00cWk  E UZMax Temperature Config Value>U}#a0c004e1-f501-4233-b283-bbd2968e3437Mj  1 UZPowermanagement IC=јU}#,f2289972-e9bd-479b-8437-8f5f598a9885Ni  3 U`Overtemperature Off>,:179612ad-6bf3-48af-8e26-e1cdd8e79417Fh  # UZHeat Sensor>񳡴a226d506-fd43-4fa9-9116-17f6bf5dd902eg  +CUcplay music :reqThe system shall play music_pҩ;sc57b4136-d09c-4883-a612-c9f731fb9387 n XI~<zV..qK!Cx @}   UJoin^[h*iE493c2a1e-a1e8-4951-83ae-68b66a66b7dc@|   UForkq[h$f10248ad-527f-4bdb-b021-0c01983fc266C{   UReceive^;<L04566201-2749-464d-81f6-85e63cef47b9@z   USend2 ;   UH1q yPH52bd1747-16c4-4d92-838c-ee6c03a351aas@   UoStateT!IAWb3a6da4bf-cdce-4db6-868f-6830af0e9331E~   Ucontinue?2 [h857cd108-b57f-46b9-a1b3-fce7757003ff lLH  7 Updata change animation?301927545-6bd0-4f8f-b357-be9f22ba9609J  + UfSystem Boundary###8fe5d745-e0f6-4777-9278-5ded1e86401d}  U<2 secsFor a user, the preceived startup time shall not exceed 2 secs -P6fce072b-27da-49c8-91a8-f3503ccba13cK  -U<100 msmax 100 ms delay̧a3cd8172-13f7-4dcc-9caf-c8ed9aa65a6cL  / U|Application Layer?͘GM 2d91af7d-9b41-4405-8397-9064ba27a35aH  ' U|Application 2Y"GMGMeedb3c67-7ed0-4dd7-965e-d24b09bcc374F  # U|storage LibY"RgSE7034e944-2fcf-46d5-a450-3743c0f67838 <u+_["<Nw ; U+)2. fetch own public keyL1/a47766dd-c89f-4b16-8adc-cb51d29e7102Av ! U,+1. connectH2114895cff-4d2d-40b4-84c4-4c0872e3b39bS7u  U,efkIt1a0fd3ec-d0ca-4e43-b9db-2d30171209d7Xt K U]\system up and running (2500 ms)h8ee38347-bcc5-41c7-81bc-5c36cfe091ff]s U U^]load and start applications (800 ms))Jfc6b084a-2e08-4f75-8497-c617f3a86cdaIr - U`_power up (0 sec)rY! 5a941585-bfb0-47dc-a274-42c098d8e957Dq # Ubashow volumeR)#"accf65f0-f097-452b-aa16-3d74632035b4?p  Ucbvolume!$#e8ddbcdc-043a-43f8-86df-59a2ff1ccf7bCo ! Ubcget volume#$38c3de31-0b73-40a4-88d9-c79b2d6127f2Hn + Ubcincrease volumeG#$c8dd92a5-4019-4223-a450-4949d45acbeaCm % UWTpower supplyl8a835c64-91e3-4ee9-b260-6026d639cb59Dl ) UXUdisplay signalh5f049be4-9bf5-43fb-88b8-ada2d7f762d6 RWk1<7  U! c326d3f5-465f-4e5b-a4b6-f5c29296184e7  U,wx*Zad0a1f84-1cc5-448e-a9c3-68a7a7c5dcf27  Ua86578a6-b493-42b5-9ae0-621e77be359f7  U#1bb666e3-5a9c-4da1-8b0b-8562a2dabf547  U35kB@:88b07b73e-77e8-4ec7-a9f9-c8540a88bd797  U34k@969a607ea3-bec9-4a7b-b9f1-1668d90f464c9  U33kB@:J09d5cf53-b08d-40f3-91ec-b9d03fd5e8ab9  U33k@9K6393d42d-0925-463b-9b62-390717e0c941@  UXSamp outwsHF859f57c9-e56b-46e5-9f61-09990fcd1024?  URXmic inwrGIe5b2d3c9-a797-4f63-b5d6-9f97f6bd61e38  U,z4589f9a1-fa1d-4dd1-9630-71132301e10c8  U,H3c7580a8-88b7-46c7-9af7-4f414cc655bb7  U,w{L834da566-1aa5-40e9-8d3a-40c007279b9c7  U,wzvZ8a7654e3-365b-49c5-939f-316693406b787  U,wy b4f1e859-f336-4910-87d8-26593d18e311 Dr4y>@*t{{8'  U,8SE23f2db54-6d8d-4ac8-b723-02a792af7883B% <+  Uerror e67a5491-0932-4b6c-974f-7e24bea2d9ff?*  Utag end16df1484-75d3-4349-aadc-3136b8a87c5b9)  U,Xy31d82ce6-980f-4626-8918-e676548b1f588(  U,6Xy@11be0044-5c1e-4e8c-824f-df83ed4f64988'  U,8SE23f2db54-6d8d-4ac8-b723-02a792af78838&  U,8Xx27b4f178-ee98-48ef-b744-288651c482d0B% # U!end of file cf957307-a649-469a-8061-25b1f0b7cc7d;$  U dataf35140a4-cf00-4800-97b6-c1e94d6b8491D" ' Uelement start17c9df91-ec32-4d4d-a9a9-08825c23b1f8C! # Uelement end 4021742f-9309-46d6-951c-e1bd8414bf44B # U content endef4db10b-cb8d-4218-b341-021de6bee8a88  U,BN9s64d881bc-7d1d-4a87-9f2b-59da0a0c7ab98  U,BN9s67a834cc-2fc4-4447-abeb-aa494b61ae6dC % U/Ialive signal#5eec75f4-c123-447f-9f29-c01fc6c600a9 BLLBG >5  U,contains0f15458f6-9e55-4720-82bc-c4d874b12997B4 ! Uoqswitch offOQ141dfd31-e842-4466-8063-c82d10fa9559F2 ) Uopvolume controlOP3f939ff0-2ca7-4cf2-a9d5-11b77e0d675f81  UnoNOd94cd75b-349e-4fb9-9db1-0d095f27b8c48/  UlmLM30641c84-08df-41ac-a747-904b5b52a3f27.  U,471a5443-4e3a-455c-800d-b151cacc8520>,  Utag endbb55ab6e-6efc-4c0a-93e8-7b7e1c197dae 87  UcYoY$b46591cb-73b1-4101-9d2a-3baab443e02166  U,f9e96b00-3266-4c20-a647-944982865a6888  Ub̤Y#a842af4d-6e4a-4822-a8ca-dee07b39318883  UpnPN57b2d642-6764-4893-a6ee-115d2b0965a580  UmnMN0a0d58cd-e6f4-4d68-8753-b73f5ea47f337-  U,42db7b7e-a09c-4149-8506-25cc8750b759?89  U\VW[df58a5b3-d509-413f-9a83-e1b187667608 M >"i.>\cMMME< 1 Uiactual temperatureb4d637f8-21dc-40f7-8ddf-58107fa47107J; A UJParametric Diagram (SysML)2c172c04-ba17-4ed4-b301-126eec77aaba<:  U3TunCmd_IFOq[7f645ef7e-2dc0-4b27-8aa8-2935abcc2c15<9  U3NavCmd_IF@h~4855a2464-0ec7-4a3a-9d63-5e772b40950d]H> / Uiout_emergency_offbooldb8d3d78-3b63-42b7-a0ba-ee7b9574fa7dB= + Uimax temperatureF{3218f250-c091-4376-b0f9-063f9b5b65fb]?3 % U[http://admin6839e5659-3c57-4f91-9e29-af221b24ba3d98  U5Cmd_IF+6e614a66-1faa-41b8-a432-78f7f724d554<7  U580IP Port;47def967d-e021-4bc6-9cb1-a42628630e8e96  U4Cmd_IF ,&078b818f-2cef-4208-a636-ed4fa3d75ff9>5  U48080IP Port.5bf3239f-343d-4ece-bffc-e3d22fefce6f94  U+Cmd_IF2bf08931-160a-408a-b1b9-5660ed659cfe^C? - Ujin_emergency_off5640b074-ea0b-4ad8-a137-3842d32938b5  Dw:DocWK19G  URouti2sƺ47d836df-a0f5-4d1f-9fb4-59e4470a61c48F  USini2sXA2fd25990-9b40-460a-8659-ba2aba7fe4d8;E  # UFeature [ ]1593e126-8932-4075-8f27-715669de3ffaBD + Usequation resultMS?;a8395b5a-504b-4032-b993-1f82685e880cKB A UJInteraction Overview (UML)34dee792-530a-4499-8839-9442da0d67efL >I  UXaudio_ini2su0ac28a630-1679-4693-8001-25e109ad1bc9?H  UXaudio_outi2sN2Fcd460687-2492-4a76-b831-68c1c7eea81b9C  Uroutintǟd4197348-e376-44fa-a8de-396f86a15d06+BA + Ukmax_temperature9eb82a67-3826-47ca-a72b-61d96a134616C@ - Uhout_actual_valueBv6f52ddb7-ad1f-44d6-a3e2-ad31ea485d18 RO1a'bR0[  U364875a2-aff3-4362-8a07-4ef2dc64bba80Z  Uc5ee457b-84ce-4fcd-aeb4-25d3ed7980530Y  U51da12aa-60bc-47ee-9562-e20245d6f815=W ! Uyresult pin_f886e125-18db-45eb-8f27-f4eed47eae5e8U  U abortbU557f050d-e424-4408-9f58-385f33c5720f;T  UrinsignalI[#8f389872-9f81-4752-bf5a-3fe1b34e10ad/Q  Uq2ef7719b-e01a-4b74-bf64-f904f8a46fcc/P  Upea7572f1-8eb4-4130-8734-01de78ade5f9/O  Uo295a7599-3725-4221-86fd-e77afe3581ac/N  Unf40210ab-d6a8-404d-a160-485be3f0f199=X  UportsignalN696346027-e293-4592-9ee9-32d863e59f95K  U38443IP PortDe 260a0431-47dd-4076-905c-669ae0f69c4d>J  U38080IP PortLE9b7121a8-7cea-4e0c-bd55-af1b8b372f64 7@@_$`kK,uS7} - UDiagram FeaturesThis diagram shows the feature categories of crystal_facet_uml42ecca29-2edd-4b50-aff8-7260ee4c34aev +U Overview [root]This model shows different features of crystal facet uml.77e513a5-8cce-40c7-ba3f-ec58754facec)z U ExamplesThis diagram shows some example diagrams from consumer electronicsea677a4a-7a4c-403f-9e83-445273c7b17bF 5 U"Classifier instances948825a8-3255-4e0c-ad4e-6c4b595826579   UDiagrams6180ee1e-d7e4-4378-ad2f-9a4654edb445? ' URelationshipsab5b12b1-6046-4637-aa3a-7afc4de4b3d4m #mUClassifiersThis diagram shows supported classifier features37c9e2a2-ea47-4e3d-9e03-3d6b10d0f77e R 9v1<n9RF 5 UInteraction Overview 95a317e6-1e0e-4180-8aa7-22f146f312ee8  UTiminge7606880-e793-48ea-8e71-d10bd9fdb1fd? ' UBlock Diagrameb974623-3fa4-45df-a4af-d75a9cb6a702> % U Requirements4f7453a0-4f77-4c16-bfb4-f568ec3f8288A + U!Package Diagram63bc8070-fad1-4b32-920f-920adc788a55D 1 UDeployment Diagram1009c159-98c8-43e9-b3b4-869122efb9cc  !'U ActivitiesThis diagram shows the activities which are the base for parsing an xml file.4ef6fc5a-9ec3-4725-8cf4-a996e62ba187D 1 UParametric Diagrama32e5511-6cff-4db4-9e62-aa06d25f68c2:  U Sequence02d7edcc-dd6c-4318-a287-4563f308c33a? ' U"Class Diagrame0bd4c2c-3e4c-4551-9da6-123fdf6369a8C / UComponent Diagram415ee3fe-314f-48a0-a6a6-3f40e0074a61G 7 UCommunication Diagram977c6946-dab3-4966-ad7b-d066ddcea371? ' U System States5b2929bf-03d2-47a9-bd5b-8833647e6c23 @ ) U Classifiers IIf95917ed-c5be-4f5f-b1f9-56ea3dc6c908 qAU&j; Pe]UJ==^-OU8d4c5e44c-16fe-4b68-ad89-d4abecd08c41-=U "22545521-35c5-448e-89da-17e6e4ed16bb-NU706f560ae-989c-4a91-a5c2-bb71810ddd03-MU60e911425-fb00-4248-b16e-b4367f7b93c2-LU525a47adb-fde0-43d8-8205-152825ce1af3-KU+62c4729b-8a82-460a-91ec-83bddea93e71-JU40f2b5e8f-c05f-47f1-8aea-1c4c252c23ef-IU30d91b154-7e9c-405f-bca1-aac60baaa0f2-HU2e0022b98-fd33-4815-b2fc-0c6209f288db-GU1d55eb5fe-efc6-4c53-9865-ef0ead8dbf7b-FU070a80f9f-34f2-4bc6-9732-9732665cb078-EU/6bc78d34-a886-443c-92bc-5336ea508d14-CU-08bcf3da-54c8-42d3-9c84-783c6155a718.BU ,22802d7bd-fa76-40bc-a6a6-6501f8ce8ab6.AU +127549038-0689-4205-8419-01b4b3141bd1.@U *00b7cb37e-c68a-4711-8fdf-489b65a4db8c.?U )/a516cca5-974c-4d92-a08e-50039ba0eb74->U $99775a66-3218-4fbd-98b9-9276d81ebe97 tFW(k< QH???^-RU;672cb111-068a-4119-a363-90615c54139c-QU:cdc0cddd-2af9-4b18-be12-fba1a4e114b8-bUJe5e2f8d7-98b6-4337-9071-d4f0ad961043-aUI743db9d2-8b7c-4417-9d7e-8b405d555cf3.`UH383d0309-9889-4597-867c-dbd0c3ec37c3-_UG147a77c5-4f27-490b-adbc-6985a4f062df-^UFef7abe9d-f4ea-49b1-8ef3-9458a9d3aa91-]UEa260b7e8-3eb3-4187-8f67-3af1dcac8821-\UD66a1c369-3f2a-404a-955f-f3baa66ed8d0-[ UC0a412aac-74e2-4305-a838-47ae947137ae-ZUB01c5240b-94f0-4534-8e52-2a4ec925d4931YUA3b6db352-1089-4a16-ac97-f32175a92ce7.XU 89541588-7d58-49a9-8034-30f27f8ec9f5,W U@7c2ece7d-e5fb-4235-8961-e9e9d6d900dc,V U?4be79229-c87d-4040-8e71-07ee55cad6b1,U U>7c64a41e-8f16-4a7c-ad98-672d292543d5-TU=dc43a3e6-865d-44fe-b548-2c59c46a0df6-SU<0a10320d-f3aa-4fe6-93f3-3f64abd95254 sDY*m= O-" .t0.vU^9e69dd3c-ee29-4a0f-9669-1949b21908b5-dUL00e779a0-b468-4faa-8684-eb879c29a909-cUK8a05b85e-e40e-42f9-98b6-4788631bce3d.uU]c25be54a-2b35-47f6-9b2e-7d5b70278eca.tU\723e0824-960d-48f5-912a-a347c561fa50.sU[a818e657-c691-41bc-b69b-cecd652cf979-rUZ24a405ab-6224-4613-9db9-5462dfbd5472-pUXae0d267d-aa9c-4e30-9f04-705fb8b9f2df-oUW05898047-b55e-424f-b1d5-6d7debbc8dab-nUVed39ebdd-5be0-4fa0-8e43-cfcd3e4522f9-mUU963033e2-0ea9-498a-88b4-3a19b4c8d805-lUT1c0be3da-af39-46ea-9b73-1ab4dbb8748a-kUS8d64cd58-f6ae-4b84-86ce-f8f35a484ca1-jURea77639a-3f5f-43d5-855e-10a4aa381002-iUQ4d5dc09e-d04e-4779-b0d1-301f85c746d2-hUPa2377f99-7489-4b97-942c-bcd5b22f40e5-gUO611a93f6-decf-4e20-aedb-69bdb8f0495f-fUN67596eb6-1e92-4c99-b4f2-6ed0ee753839-eUM10c18bdc-7d55-4f83-877d-8e132fc53fc5 p@T$b1n>vk`UJ?4.wU_ 28f2a692-dba7-4095-8d22-3d0c9680da8e.UoO90961bd5-fa4b-4164-8369-7b8c1337cfee.UnN1ccd7f3a-b2e3-4ec3-869e-605577070d28.UmMd3c5c5a1-93e0-4497-8fd5-902b34016844.UlL27d99ad9-2be8-4b73-96c8-73a84c95e2b3-Ukfbb90d38-35f2-46c3-82be-b32eb8ee1941-Uj2e3db93f-3aee-4fed-9886-b5fd0d4e1447-Uid8410119-5a04-4779-9e90-ffa4af5a564c-Uhd869dd22-c9c5-4e66-bfa9-8c3a6ef1f3fb-Ug3f7e0285-0dca-4858-af21-1a7627bf6d0d-~ Uf5c09e4c4-6796-4220-a494-cdae9544bcbb-}Ue7f0bab45-6fd9-4194-b523-3ef2ffe8ea49-|Ud9fd033f7-5dc9-40f2-a32c-6b44c6ad8e00.{Uc$9a4e19db-6313-4093-9275-e33f9493a9ce.zUb#520ad7ed-bf42-4f4a-ba1b-55f4af126cd6.yUa"063579f2-c502-4fb8-9576-a8270ef0540b.xU`!14b8769f-c6f9-40a6-962b-b5a586a3d86a .^.p@P yl__.U - Usa100550e-1105-4fc3-93ad-d452c95e5dcc- Ur5825e60e-dc25-4e77-b12a-f5bf50ac5c5c. UqQcb33dc25-8f14-4ef8-8354-98f3b8ebb724.UpP341839d2-4c28-4c02-aef7-2e36ae5db83b-U~69aa89cc-fb27-438f-9dad-60b1da9b7a64-U}48e785b2-4c35-4eb3-964a-2dbe67df24cd-U|bbbfddc9-5c7a-448c-8ad9-ffa0f80b7265-U{163e288f-de26-42ee-be66-7d0b9f93da96-Uz410fd655-4e0e-45a8-b8aa-c82edc625297-Uy1e68d359-13e8-4fcf-8640-134ac1d78d37-Ux2afd881d-eb96-4363-895e-152deca4ee2b-Uw007cfcfa-e077-4134-9e4e-03d8d896eb4e-Uv9db75e93-20a6-486b-8fd5-2bc01c4cb1f3- Uu5036c2bd-ef99-4cf5-a499-e79a5c74f229- Utba73743c-8616-4bb0-b764-501c1b987c09 J^n= U$z^/(U[3d1d25df-60c5-4762-984b-bbd8498efd10/'UZ6fb554e0-47fc-47f1-8269-c17081b04860/&UYc9cc5d9e-ad22-441d-ab5f-fef2afbb2807-$Uybb698d93-2d28-4737-aca5-42cdafb98978.#U36937cb2-0b4e-4000-830e-f33a64486c45."U72215b45-476a-4d76-8e23-90e43b38bb09. Ue5a85f56-3a72-4c2c-a2b1-ab25a287aece.U7c9515aa-d03d-4b5d-9fed-653e1b51a5c8.U2bd8e87d-e542-4feb-8fd1-6b11fe64088c.Ufc663e60-e5a6-48fd-ace0-10577845a0850-%Ud93be3ab-6c48-40be-8fee-d07cb90ed438.!Ub55f4db4-b40f-41d0-a097-9d1d4c425276.Ub596fb2f-0950-46db-afc8-f9ee081d11f1.Uce82f181-03c7-4df0-b09d-8801bb1fe810.U 71cd7f0a-ec8a-49c8-bd47-5a581971b991.U0a309bda-653e-4030-a176-ec181a6fc1c3.U331e74ee-9fa8-40e7-a089-c451be97eaa9-U6338b219-8364-4c87-a50f-03f097880158crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery.xml000066400000000000000000000200411415120503000236050ustar00rootroot00000000000000
Example Diagrams This sections presents the features of crystal-facet-uml.
Feature List This section lists what kind of elements crystal-facet-uml can draw in diagrams.
Example UML Behavioral Views This section lists what kind of elements crystal-facet-uml can draw in diagrams.
Example UML Static Views This section lists what kind of elements crystal-facet-uml can draw in diagrams.
Example SysML Views This section lists what kind of elements crystal-facet-uml can draw in diagrams.
More Examples There are further examples available as html: mouse_droid.xhtml / mouse_droid.pdf self_architecture.xhtml / self_architecture.pdf quality.xhtml / quality.pdf And in crystal-facet-uml binary format:
crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/000077500000000000000000000000001415120503000244675ustar00rootroot00000000000000crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/.directory000066400000000000000000000001041415120503000264670ustar00rootroot00000000000000[Dolphin] PreviewsShown=true Timestamp=2019,4,29,20,29,18 Version=4 crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0001_Overview_root.pdf000066400000000000000000000204561415120503000306060ustar00rootroot00000000000000%PDF-1.5 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream xVMo8 W(P>lm.P4XKC0 Zc6Kɲ<`YvDIG=1 ?<\nadvoD^ح8@C .$h7€WHV:9]/XkfZGktH.hC jϮ7u^}z_たAɮ'.ީݧKcbbB3-`n N%#4{5sAwe`QY? ZuPנԵ)9\'ɀA.n'%\I-dɥLrQ99[{lB"p\8%8PP: 4N.Gɠh񘂎%[F~%=5(3GtؗeL6 *BvZAXZQIy yQ^~A1T]:z㳙_,^BG>_b^W5‰<9/Nũȅ &:tVgeg-Mj׹>yw&JoS=cI'vH !ɆTE^=BbRC猪us)/c<ŘX>Fyro~Vϕ.ցw_oԯcPw\!.xV{LX!TeZ<)2'[2$F (02w 햻B>md{q ?S܋!H瀽ɐ8ԁ/! endstream endobj 5 0 obj 888 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-1-0 7 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 8 0 obj << /Length 9 0 R /Filter /FlateDecode /Length1 2824 >> stream xVST?vABTv3YtCb褓!P >  Wd[RdBJc$-,~MmS !2 $bĉ0&"vL@۳~; ZxDfm,)`rl<-ٸwmo7ф6 !)e+V@2&኏Go˷s]~n-P]^Or\$YHVȶ[TR~fbL$u2%dyBEGɷF}H?kAX O *WB||B&VP Te^~zPkg?9|]tx r~-PZ$ѬmӍj))()f  &klUe"5ulۤR.]EmxvǧɵaZƅ+*b&BB:ѕ>/^})}Af5ez8*P p?.8Ij? Όt3=ڴl2?& h枡+| 5WP()Q):;Cm##ڙ3*v- R^/`Hź~o~^o^"b8nd[D,']K|!=ļKvsd#9 Վ _lU,i^/jj>Q9gQi3|8q /[XOSï6Q0 ş$#V:F(VPQAnBGo^Պ>i.8Ԇwowz=e kaӇphjmo~eωg~Kx'B(ϔm(LiQ] yßSuv0qD 0|OzdW{`Jn5\Sф/_Q/)\NNuxu|(6 *=NTLn`"TCT9}a=4f$6 şA2-P?jq?$%P+9X [Zh>TZ9/&J!J&YO'"b2 ]Dt$>ZM[ # F@DQ*9zyrwU !F75ʡ endstream endobj 9 0 obj 1940 endobj 10 0 obj << /Length 11 0 R /Filter /FlateDecode >> stream x]n0 yCG(hR4uC! ώNځgsMfq1=lMFXk4 GL^ny"~_7;>p.OvAH)h!N"_瞥7{0Rx>m=,Ӿ_25 / tR; Y8dt{BWOc 딿b"2cIgI<351ELztK]`<7W+b.Eu)EQ-Ώv|ƈ#I!͂0yJ/C\ endstream endobj 11 0 obj 332 endobj 12 0 obj << /Type /FontDescriptor /FontName /ONAWQA+Roboto-Medium /FontFamily (Roboto Medium) /Flags 32 /FontBBox [ -907 -270 2051 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 8 0 R >> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /ONAWQA+Roboto-Medium /FirstChar 32 /LastChar 125 /FontDescriptor 12 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 568 568 568 568 568 0 568 0 0 0 0 0 0 559 0 0 0 0 0 652 653 0 0 0 0 0 0 0 0 0 0 690 0 0 0 0 0 0 0 0 0 0 0 274 0 274 0 0 0 0 0 0 564 536 0 0 0 255 0 0 0 0 0 569 0 0 351 0 333 0 495 743 0 0 0 335 0 335 ] /ToUnicode 10 0 R >> endobj 13 0 obj << /Length 14 0 R /Filter /FlateDecode /Length1 2852 >> stream xV{PTs].&)1&eqt  A%F23IMcZnlS!TJ4Z51a`RcK N߽֚?Wϝ8; į(Ů}V_;4g Зr KC/@WO"rm!@A,{/(n`2@H|,HP |Op̺&Nҡ`"-!CQa |R-dr kW.`6gDJDAFUqӋ]7T[L_%(wDMkDҾ q !YN QFd'Т 2;m61q]_nK#+,ė~%&yH}YSn(2ը22HdlH9vhfɨ3]NEc4؟K.dgYmK8SZvuĕճug: 䦓\@fV22.ʞMCbΦ#v8-rm\۪Vդ݊,^:EpEUhzt_=|ww_i=m9Ot˘_~Rxtc@IU\=zuu͒"1pDjתAlVKhE37ý7lcǖ.֡ ?ɫi8Z!ը!ΙùR#.tF-V5>ZB~Y㒟7i& #)J đ$H^s:B2 ! -j\'CCV5?ymy[50WP./aڻl&0eN YDL!by3mh _x}]?/bM?Y8Uy);R.|ϼ}&b.+LQ|yyKOoUh@8d2].#s6ȯ|Iw:J5X1f 5-Wlw$n*(4p>/{_e݂gj|=PBPJSC &${&1[M?Q6Ѧri4keǟX^Dž#7.>?]k;y屜 7Y[z' ֥bd/KO*~m f-RgrTn 2kq:h>v,Ƞ=,^‡%l(XEOk*R] x]Ԃk@KˬSN_g=}֑Z~ \|>uBQ,c+ %TP($b!zq3=/0[&'s?jaj\O$p/ӷ4/=|wtPJQ/R$酢=wf(#V3܅#VEο Ӄv(G?jkhnyo *tjG=2ަm[ ;Hz|b.dY!nt6 R2P!} !cZAt߈I_ u4IZ_CXeDd=IAJi}(71gtc?H7O%:IOt3҂P#Q z{jM9kUß O9m'N| endstream endobj 14 0 obj 1940 endobj 15 0 obj << /Length 16 0 R /Filter /FlateDecode >> stream x]Rn0 !#"]<GS,/))I;RSy=ΦU|.΋֙J3 Ad(e,Ffxq';AH)h!:S[52m+-h2a%xm?@i]pIf@DlƱby4CM]"51F c@\0.W+Ěb"Α9Ghhe0MMb\RG1_%>T9#aΥ)bOErլ9NbO[45FOzi.4vH_UQ endstream endobj 16 0 obj 338 endobj 17 0 obj << /Type /FontDescriptor /FontName /EABRBX+Roboto-Bold /FontFamily (Roboto) /Flags 32 /FontBBox [ -913 -270 2060 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 13 0 R >> endobj 7 0 obj << /Type /Font /Subtype /TrueType /BaseFont /EABRBX+Roboto-Bold /FirstChar 32 /LastChar 120 /FontDescriptor 17 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 650 562 548 0 0 0 0 0 541 875 0 0 0 0 638 0 0 658 653 0 0 0 0 0 0 0 0 0 0 536 0 0 563 540 0 571 0 265 0 0 265 865 560 0 562 0 365 514 337 560 0 734 509 ] /ToUnicode 15 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 18 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154042+02'00) >> endobj 19 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 20 0000000000 65535 f 0000007773 00000 n 0000001130 00000 n 0000001002 00000 n 0000000015 00000 n 0000000980 00000 n 0000004114 00000 n 0000007332 00000 n 0000001348 00000 n 0000003382 00000 n 0000003405 00000 n 0000003816 00000 n 0000003839 00000 n 0000004565 00000 n 0000006601 00000 n 0000006625 00000 n 0000007042 00000 n 0000007065 00000 n 0000007838 00000 n 0000007955 00000 n trailer << /Size 20 /Root 19 0 R /Info 18 0 R >> startxref 8008 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0001_Overview_root.png000066400000000000000000000522061415120503000306170ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxy@gvvO@EEE QR<#̫23feeV[DvTPˁمO:;f9' u?zBB4ŋӝ=X (XpcǎI=IܦwJ3I0eh813g jsK,mD[1bĈӧO ug#%z"dqmV z\<\]]]AjյQ7c[-@]vs҇xŽQqUƐ522r'z&Qۢv:]qp]Isq99Rj\x rVZ84`%umi딖vS)If7`ކO7mw|ߦz+[#@]jgg}m,O޽:5'p"r o\H;kx%EɇJ-VT*flWWQ5j`X{GYQ/MѰqDtSظ6oj#s'"S4׷Iד``=zٷ jh :7p3^:y:lV̔*k^vW 9Whl\l-\m ԏY4ҥqCUW,s!v" ;י00Z9cUˀbNü >BN̫Vӌ%'eZ}`{l!ܹX84̙_iTkozO׃ [Gu1t=ë|mPz,zSNԒڮgt#;sN 7ǯ{?b"}U>}z7Sc̞8 tvU[w=dȹp v-;[STTH&ND:r9{%U S5ԩ!B^ZRYCKUwBfaaNmިNDQ k?<;ʿ 4zߟ!;L E=kuVǾ͎/0_\gNv9~-V|˜{k;x`Ws9 Na :ӭޖO^deu3OeD$8nYq@uqi|m#[;  2 l[)1T1/+Sll|`1 K KK*ICYfX˜];ޕnkS.*N81Kz[dNN5V_)n=B2b?=;];ļCuxNb5n#980TU/O=lP%&02Tk;y+*~j-,,+XX*k׾ii.ͭo=tФXK ΄ ChB;}WO:sٵp9 x譛\O wa3|o{ʭnܻ^[;:-?^?lƺ˷(7o''gSu_bJ[;웺T,n9C_$8wfNmzKY49hsn۵jV *ݒĊyޮ%64xJ"b|Y1϶6Ri;^z/hQvL]æB߰> <9z2Gn,Ⱦr""C}^ޭVb^뉕^xQ)[ujr\-Tj9ԢS*wne?ĿWG]i0xa6DD Qm|<䍁"R|占___51L8Kǒb>_[YuaN6zwQl *oɢgBK])nj4L 8jVӦq4z9#%S[|?)--o69<(((((8Cnگ]CK3s&ʏf:ؚ)(з/z8*v&-;Q`\O!s}_C^`%)pιr'usy44TQ\@d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2,`  @d(X"C PD 2 3 iiiyyyjӬJCF4iҰaCA@`tgΜ9qĹRSSZm( +++"R(Z"Ŋ|ff<==۶m۶m.]kN.7$w)0F),,ܷo_llʈHTzzzvuԨQnnn7nܸCElU(///77mϟQDdaa`mm]{_','9'`"v0'Oܺu-[;JonݺvڥK-[`0;vѣF.80<IX"..n򊇇s@CL Mq9AAAAAA۷ `nn>f̘ÇK=c9tѣAxꩧj b LN6+|; 9sfrr޽{wz,~~~VJMMON:5`=zݻW@L)PӧO8p`ӦM{9'?akk됐e˖I= PZ=z?^8x`˖-(kȑ#SLy饗˥BLU 1UW`999{^n?-Mݖ-[̙lٲ>}K=@}zTe]~3gJ=1aDZcBCCsrr~AL=bA2mɽzJOO:tÇoڴٳ{ʒz1Su |r޽KKK(8&`6Ȑz1o! ,SV[111:uzѻw۷W{5==]q2PLRnnn ;v(8&& `Ν7n0`N&!'PLZ2d˗oRm޼9))iȐ!jZqԓCL:,9?~W\ 8&,00_~ٿɓNAL1eR_|v?|ذaRbF׆H5kc^Y͉$2#ܻܲAq dJ(c2)D=Vk .@oݜk۶m知TSGҽyCհ4^ެe=1erPL@jjٳ{]S$ T1ҝܶ#@Dm;$8=gk x۩LҒ%mVx{K-|͙!'e=/D\cQs8NO,炣~bڴi]&,G28>6iXwZGD>Tà5C 1eZPL/9ԫ{0AÃ,mݑIwf[e= FXTɮɿE4bs@;9?YO}FGKD-ҧ'd/׼f'Z*,G28zu#AGTwk.#6;ĔiA2v[lٶm^s[a d\}hkLRTy F?pNJ_8*C qG`&ĝܽVѬEc06@^3ZR(-[wTTԳqcʸPZ)]\.x[2ߨaeqjbʄ`7|m۶SN-#B/ٷ5l:\GZ<^]ƉZ|W'%\ӆRO~2}ќܵu\޼W@Sc~{۴i3c Vg@MĔ$q*=KK;A~M?"*`3M%R1e:^=?\x믿V(5)TDk wxϣ\6$"@,mm,+z~>fd#9i/jW;,|(V_ A;-ZtQYLC Ĕq,mmȐs ̔6w&ҒR3bdg3C7pːQOZ+X)SeJJJ,XЯ_}cPfٹe52_YT=X1\ڵkWhh+^xg0R)i!P6e8^^^**..NY/ɓ'!bTnS&sԦ^ٷoٳgO. kx!0F)c2f(X6lԃk#F^bԃ#Ĕ1@L3,STT~#GZX;wS|+nDS\;՟_kƘͬ:""7Z3mw!):N7=[hҥKiisy󦷷7|ӠA |7>>>999RUOnL F.Z^O%_[ʫ"MԬ& {eU6.*]9gKϳ\[5DbU~פGtkfR4ñ؅cz4W)m4HҎ2FsyPPPPPIODTP ' DL3"ssMVk֎rFL|JT~y#*6t> ~눖sh.#R.8_moHyYGoT .\ +VHzoĉ7cT*դIު"t*3 8Wokˈe. 6m"cDL0W^Ts0vJ]՝'3}][;)JsWn=g)1 D6=XF*Em__6exֺ'> Od&H(Ky}Ǵ-;vǎ~뮮_{ڭ[mJّ/k6oӉϭvT*+ j_tt#2ڵkDDΝ;ޒ"d ]ȈF{NWBOZdmξ+'x\i{U¬~sclθAtsGO[;Eດ{H1e$%%lRKpn 7pR[I3}"3"^w4"ڒb&,Q]!2Θ9]Fu#{(Djhмy/(??޾|$)Ω_dMczO^ jB< T)v ݣ\Z[1Zx{0"f]d $GPm~'!9vGG6jW׌&M\~]w111.]kJJJLLS[Ĕ3gu#զ`mg+c 33KT*26(XƢYA/9ʈxI7ggwNÙuOƮr1Lƈ 9Y:""V g&O-'CɽoV{ 7Z_ousssZm=zW^&%%ELNyɓ'ϟ?ɩĔq7yC1j͝z+5=@!egg`^z͞=C[nzzڵk׮]zza׮]:u2ew||ҥK1eP $|X [޲eKdd$ 8pРAr:rHrrrrrѣGt]WwMSW r5&%%% 4(44<222&&g6Si`KdeeI=TƍtߨӧO/^x߾}ĵj*RRV\/Iz{SPFqި\<'9nomQ1OU}+WjzBӭ[n Zv^6*fۺY>͚N\5ԳmلKx^+__s!Tr%%9ykeLjxYڙy6^= O'403'g[u^QBhhhZZ|Pw;bʘ=$@(XFw2N 6|jmz(**ƍcƌy粳wxNcK'Oq"C;*hӳen[:[[ڸxnjWk@cfkaj[_b /v%Ǻw6J9#"J'ϖ.VNJVk bxѣSF1 ˈlRL;'Sx=q!!Όw? RRRS_+Wttt߿XXc%2JuwUlwhhVmiN^!jϙejxS:2F$HDnJ7rEÖ.t2:ʉJ,+,ݙZ.2zFέlyN`L<ۘSˈjNgeF4[; )/ MCJJJ֭*,,ܲe˨Q ň#6mTPP^K8lNEΜ mzֽݣ#>b iu̮eml /K+zbBU۶Dl[߈O5VL1&% X1elPH6m j;s4zOEJV+/4BiiiEEEH._cƌ1cjƍ>]iiV"vϏiC΅{o9ϙJJˈ3/L֒L.'Nljt:=rVLtvk`gIVR\JDO:qǻq>1^zaNMM<ڊ)Y9Gպ+67  ԩI=H%YFMʪlN~Uf =_X|+nDS\;BfxwmjTںOTi&JϮϳi.gWU/ҹs0ʕ+=<<|}}+׺u9J66*uYٝŬmE7*>'8ů#3F˹ťI.ps9Sڙfg)X"w-L)-[ZYWg:qUÖ:2twHSo&؄p@TvhV;3ɛ9#?N nl4Sڻ>;wSȐ]9c I ߏNi;cɱ hnR61~i|v͞Aiy]U nl4l:p=>*a^!у'{71@$oq}7eD~2}ӌ1U`x.1ejUǶ}xFWsvS1}.60gD̬˼S:n01β`b/D9mvߞwyGPfᖘM6U^iӦGPzc:}Ɖgs ߳}[TCKU2u{vlݺ=z_Š'iڵ}gԆ ݱmW uP/rOd.=nK%'{KT 1UmyˌɄ7/~lň_zE݊;xtQΈɛO7p}fçsN F\խ%#brYG+=ӮE^JFĬ{}qV{O rɅvl-匈*6j 1e$*),ݯ_,;eD?f8/?EX6m,^9WG-4[Kp"Mǹ!6Yw3F̢;rڦ ;a[=:uM8 gJM)qr3zx25S>phEnNsCMdh 3 םޝ-J(\sbnG9VŬpY˹!Hz|[^p~_,%WrNtܧS^)7~{ڎ`狓ŜkHFvؚިSFr½Kppi4#G %RqE>7oٺ욷tP_Px`3U3z D|[Ȗ'٢j^~,ٷlMMFJc8(C-:7S3j%VuNSoӔg9D$s`F'3v6FD\[]Ф%Krs|Y{4K w+FY o/FdѬ2yA3{KW99׏O73N&H!ℸOBL' )--w7-B~%'>ߪQWW-ks}a^qsx[ȋ8U˗/_|}DIW)㄂e\ ETTԃTIl'/^O9SC~8o1v2F03,}ZTTy```mIS}Śt.ӡ~ ywEhڌl`kB,mm,+/cVM^=(2N(X6$$dR }vvNw8~ַk憘^MIdȐo>5c[xٮ%r*O?x$ZaÆP++$q. W 5ZsQt!sά_xjĠ6vOp5P^prB/m5ۨIU~VYTFK71?Փُ2N(XFgС/^]5ӳC&ڧD\[M6x{Fp;N <__=bh`CիW97u%`ϯܽr栎V7FEζ]߅3"yL^yJF2kǽ.s}ԯB8m5) -ֆ5k(LDԃqTr9kfX׳Wy:RNj_ ]8un ^>cfF%Fߴe~3rY|myQ#p;모.DzC2ZsNDD+4PaРAW^L*fg?Sz3&_כK[u:]ӦM6l ƨŔ!>bu..k&8 1el*)2F/bzzΝ;u"^ģkqV<.m222Ə/ ƨŔCL3A1a_]8[kiyFOm? ps}]&M¤ĕ"c\i0j3EOp*h!g̬gj#Z=)#2f(XHPQQQR^t{BZ,jj(ӧOL6M.xE g^ؿvި^*z*XL M^ݣ\aBSFHK*jѢERRO}'Nz:CnQNӕo ?[U$A̽hbJZ)#e&Orʔڸ TvUVM<^Yt=kS֌ gOU nl4l:p=#?N nl4Sڻ>;wS֚xo^Nr j UBCw!):N7=[ĔS&Ȱ7nԃ;G̔z:[iˈz|眫O. Leko)gDL=P ݭ1Gn匘|?ruBI{ uկ֭ouvo^ 2N`/S\ԩSRRǯ]^kذԳE;/VI"0@E5]F7g~}E_L%}O>џ'>/m 4uP Y7V}V51UkS&d_~%++ {kڌ3n޼l2A5Ŧ;sCΖ>-&"R`H{pIeD$y^3Mϳ;:ՏF icwgsk-'^sI2s,֭3_4_r}5)Sy`fΜ۹sԃYw}WA>EXQsFLs>,#fqr͡T|ХӭWa˳ \OZ(A`]O .wj$}S&TMCL?||۷糲|}||}]g_?bHf侕3sX?͌d?3ַǧz)066o~>엾x5u55 n{|+Wڵk'@uuu^wu-LDO`LO>իѩ}7>>~ɓ?϶n:wܩ x{֔55 ӟ}/> ?THojj7nܸo߾7NP :::~\.wm߾} 3ϴl޼y۷oߺukuuTW3PXn]gg֭[׭[nݺݻwOPfb..v'?~]v}x=u`&ޟ_Ϛ^2i&Iޞ$Ɏ;voccc[ly衇֯_}mذ`vv:W׾%-kr+7 Wm۶o|{oqqq$cgu;zdќnŠ$=spޣcEUl)ɼ͑$8m.d_zawK+OwxڥUՂĚzkjbK/:}!_RYԼ̚ro)_|+wwo{TKԔU-Zt+kkhh?~衇>|}]^[k{wdb~oز`w4I;.Zվꆂ޽os$IGz;w棫W-dI~o\f]_Ϛzok*p5+o[}cG歩E`}UTT<G}jkkկ_~/GsHiRw8߯wYWWo{ܚzѯ}kgϾ3'.iqMŬ9iK饡9u r rcCHzcg+|ӵsJWA/9Y&療L&/tԻ̬?aMSMyIiq0cMM/w 3TQQ͛7oٹe˖G}?AMM͆  6MlHiII_vngN8QTT|ǦMό4~S-]wO$I2 [ۛG.e5e$ILY]ʺ$IOL$la&Idrb"#乡 Ͻrjqrk~_ڳg/ϔ)++Kgdyr 5gT^:_+^WIĚFIsssGG?'Ox޼y7n;֬YSYYA300?ev̙O}϶5̻ tG2/$I >vKL$\|tb|"/\r={zk+ԯlf,={WZ,eMuM]_ɔ,C{<2xmc55,ސŋO=Ox#dbb"M&&&l6)|둢‚Y UJ9uة3~p'mڶcǏvŚLkkb::vz r5M+KC`7mڴiӦ7=܎;:::y$I*++-[аdɒ~SN꫇:x`OOOww^jՃ>~y腛>Ӝyi[Oid*r=o`4-L`n-tiXX3ڦ e3ʒ'O Ϋ85T[R6GU5'zOꟜuՓi}ݿ8T| J3ȥ9s}5u}yf{^ͭlY\rYE$dbb{Νw>p@OOϩSZ\\\UUUUUU]]]^^f+**.4<<<99y…+Ʈ>)&I#^|oѺ]zJڗVw>=Z676k_1ѾW;s1_;?kɟ;޵Iy]*;z϶ҶUvo;Vv vLG551}{_9u>_6e˗\SbMM7ה/488xرǏ> stream xVMoG ﯘa$P4v[ @Mt3|0lu! ]d!|eEuW RwUm-X$ K RSl=?E}ä>(_Ny> >> /Font << /f-0-0 6 0 R /f-1-0 7 0 R /f-1-1 8 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 9 0 obj << /Length 10 0 R /Filter /FlateDecode /Length1 3108 >> stream xV{T3cqe](XY5YvP(!@ $yOx]7n|`X8hj%5>z-f} J$M]* ߷&=;o; Bd_6%TEb._`~!y/~ YJpHK./QI8./`>m8+ηU@<ׇ77IhD0 Ռ…BzRB(!$@C|S -]Is\i;OmR.EZe!TkИhc#G&r}> }>cu|`/'A@0RLm1Eu!(h GbBB,XUvqC| LD#!z&`~]><c6uANBom˛Wmǡ;%)>e'D>}Gf]9ѣ,afڴs,C`2@G1(ٌ.P c":y2FcTؽϮ>iߝ3GK=R6g^]twު%~$Υ@-[Z%nKƌDpBLAjLcbH┽  yL=eNwo. v*=&|wKqz)'YY4WRIG X*s>j}.B\\賌If#*dDE`Y{CZ37yh ޶[?ٵt_b7bbb%KXo&kfR5 /  97J㄃I|'͈XrO41.8t-}Hu ec6 `h,`XUhps3+7>ӪkPٳFkʃ9G6fb)bQ͓yZ鬍[\]РR#פYXO>W,CnZ-PHJԮDܹX[d:;y[bNĒ.^lo|} :oqbjO`]o^?źv{y렓ސ.P0ȷ_i NaFy4P' 1DXC +${=yA=d F}&n#_m*/{=m(A>%̥yUz{3w~(&O6vo7zw0}W.EJ|q8Q&T [˼O8n VhBpA$Ƞ aLC,Ry;% qP=(f+PJ@/2Pv'p#ye7<,_0#`q^,G;%No Tz&22sgs endstream endobj 10 0 obj 2175 endobj 11 0 obj << /Length 12 0 R /Filter /FlateDecode >> stream x]Rn0 +rV<d+!j{ЇJ-R Q`}xzOOb'9ϭ6tqr6\9er"˥v[ſ{/wܺqu-\Ó]xR-X׹TwfpLEH #{k?LZܟ?Aqbaл :MYc#{yŒa4}uQ 5M1zqFX3ֈu1[[y1Yq͊8%sJҲ&/y"<0Hy)R<ΣSp͂j*(f^%y-I[Dxd> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /DAXZZY+Roboto-Medium /FirstChar 32 /LastChar 125 /FontDescriptor 13 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 568 568 568 0 568 0 0 0 0 0 0 0 0 559 0 0 0 0 0 652 653 0 549 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 274 0 274 0 0 0 541 0 0 564 536 0 566 555 255 0 0 0 870 0 569 0 0 351 516 333 555 0 743 0 0 0 335 0 335 ] /ToUnicode 11 0 R >> endobj 14 0 obj << /Length 15 0 R /Filter /FlateDecode /Length1 2452 >> stream xV}PTU?Vw۝KN~HbjaD% MRNSX4$̔B1$aTJQl5*.+Lwߜ9{~{@LvDhuՊm?l7j ! @vӀew'tqʻo5{ȿku q, V> ^$- A@E 2$ nESa!vc~Mg{ˬ@/kxӀUa`DZFr4TPk.3UQ6wO Ǚ-)Cv'>8vwn쥘gk>SOxq-Ceq.+MsӡjtnSͮIex0n}ϼe%!3>GKj&d[XGer 'G4;a .+杨$ve8[)3EaE9 ];qNcvHˋCA8j{%f^nukMU ՞|Q>{݃ )q0#ꘘ.P[u*Q]fS^z Ç'ex9d~ l$~]?s8I00NfzVZbLިh:׏ : ׇXLQ# j}SSZ{h J+ԏ)^=w9qf޹Hq[b1Wc(q2{[yb!ˠ>򓾀,Y_&I8:%GQ_."Z%٩S򂠵M~Vz\,97[މ7>M\'@rB"kх)>&)7Y^~Ǣ/sVMˈa#!L344PRt{glZbӊ}~tۄ$Uk7?4/oaz N>ͿB-o2uy#֮Zm#:]d%5sgC[xܼٛ+_Й_܅s;cpzFi>W͂_ l.#B#LJH{NuNL~/2zz>ސrF܅{{j8)_wp'NMe3$A"P+okKS c/ҿWл T_,^<4h2~)vIw6 s!G TXʤPކDq La%YXK7cEd 8f| d}$)dȾb=٧tz4GE) tq-V_sK endstream endobj 15 0 obj 1634 endobj 16 0 obj << /Length 17 0 R /Filter /FlateDecode >> stream x]n <huMIxKR |&=(3Ȑ]hٻ[D6lN 8iKo1e!ǹ3jaMGhpxˈ 7'i3S߬$3BN1"i/Ejn0ZF'J|5cP9 kN"qXy:9_"WUt rq.^F_"#1F>Kʖ)[SG2vxx'͹0tqinqbnbc*=5!l endstream endobj 17 0 obj 295 endobj 18 0 obj << /Type /FontDescriptor /FontName /PYRVLT+Roboto-Bold /FontFamily (Roboto) /Flags 32 /FontBBox [ -913 -270 2060 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 14 0 R >> endobj 7 0 obj << /Type /Font /Subtype /TrueType /BaseFont /PYRVLT+Roboto-Bold /FirstChar 32 /LastChar 116 /FontDescriptor 18 0 R /Encoding /WinAnsiEncoding /Widths [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 654 650 0 0 0 0 0 0 0 0 0 0 0 0 0 638 0 0 0 0 0 0 0 0 0 0 0 0 0 0 536 0 0 0 540 0 571 560 265 0 0 265 865 560 565 562 0 365 514 337 ] /ToUnicode 16 0 R >> endobj 19 0 obj << /Length 20 0 R /Filter /FlateDecode /Length1 424 >> stream xc`d```cp``bPHϩLe;P$d&06/e``2sf@JFnIGC%_s''@&c M(`Pc;|Vf @;9x9YSQ F'LnZwS߸5<*11-& Ih8"Pi.u?t^Y}髌cN39ŻRe7>bR++m2Hr0@8^(Ha`cY5Pq`baHar7b3/10] endstream endobj 20 0 obj 367 endobj 21 0 obj << /Length 22 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> endobj 24 0 obj << /Type /Font /Subtype /CIDFontType2 /BaseFont /AZETLJ+Roboto-Bold /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 23 0 R /W [0 [ 443 608 ]] >> endobj 8 0 obj << /Type /Font /Subtype /Type0 /BaseFont /AZETLJ+Roboto-Bold /Encoding /Identity-H /DescendantFonts [ 24 0 R] /ToUnicode 21 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 25 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154042+02'00) >> endobj 26 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 27 0000000000 65535 f 0000009173 00000 n 0000001170 00000 n 0000001023 00000 n 0000000015 00000 n 0000001001 00000 n 0000004408 00000 n 0000007283 00000 n 0000009012 00000 n 0000001388 00000 n 0000003658 00000 n 0000003682 00000 n 0000004110 00000 n 0000004133 00000 n 0000004865 00000 n 0000006595 00000 n 0000006619 00000 n 0000006993 00000 n 0000007016 00000 n 0000007700 00000 n 0000008162 00000 n 0000008185 00000 n 0000008487 00000 n 0000008510 00000 n 0000008776 00000 n 0000009238 00000 n 0000009355 00000 n trailer << /Size 27 /Root 26 0 R /Info 25 0 R >> startxref 9408 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0002_Diagram_Features.png000066400000000000000000000401751415120503000311530ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxw@Vp .ESTD3W6,mXi6,SV6~}J+3oYe GCM̜nqdon~~wOyxÝ<gP*3vؔp]kӦ#X)))]vm޼S|ה6m$%%9g"\;v7p- 2ED3(Ea>g9Y#5x6]p-jNik7F,pߺ Mo1Ե2̪{iܼex^BnO;kqk6:H\G񱴔' mn> ZĶ 19ooJhw5"w!EQ;YaSʰ!P,7]'N{{ɻΞ ZJ-/7hVakӣG؆"c%jށF;6MKu\y];5֜ؑP|+ɗk}K۰]} /[y޺/4ֺB7 1\y xz*mp?H?5_|p^x&CEqsCb3?{FjZwۣqˈS]y>ogfT !Z{Dyt/Q/aԅYg-w^+'v5za,`ju֫\-:фpԠkN:DUc[V\-_mfBXV=ZGk9zWQ^M}C+UHSUKٖihWB-/T T|74K>]~Zv"5%ӫYB1y}{8F֡ZmmU󖏾y͞6! 1pz²ACCű7-[k@ĀaWtsvʀcRb5t~l׹3?r‘yf!ЇevG&Lӫ(Qغ6O|`L{7Ewoȹ_b/ًGoBݺ7gjmچ=Zp O8ri_tmbN'l6*f:N-Ba߿mgqH BƆ^r3P4*j^q_&roLL6)ֈ=f᰽k7 ߰ݤ 9-%~O~;)oM]sj\ܷ*h1o{lٱFT6ڵM~mgknS8U6?_^Fdׄ>8bNf qap)n&"||{3 ;YԠbZ6ClNM&K93ԒRU?PʑRsyC-B߷n BE ,30xV` KB(z^Q ͖K`"xB(^Mtj~Za<3wj+9UT]ۻzFMѳc^l˧jEz6{HTXl qب{x\p4!ؾ6S֮]c/E*l[In~b"4BfuW]B]^Ah*;ROl?jw֢N:qh~O}vV{>wW:Zů~E_vP //̝[fKܯv/ZٸϦ5_Jcj>k8m\;mbe K6Fuxw9g.6]OYK:#Aeޚ{[ov #/*:XS)yY!ҲJ3ˢG7 X,m޹K.] қ"¼WBG+n+jiqC!,ʾ"ry{i{[x[>}|UY{}9mEkD6fsDئ˨G'7n?k31{wO&~;fW}6Uu:,fΫ3Pgﴉ>U-#}u.0hRܯ?S)OdCiǟ?ߝa'W[VR^͛>y㫝E;y_Pwt(--[>cLmt>a1>,}HKv`ُK77{- u-@寍[аG:'gp}a7ؓߛΏ.=ꄢd*.6rԒ}Eǽ8WQ{yfL_"Ξ 5,[^x"&&fB̘1X@m@`@kРAAAYE1cP8Ed2eeeY,0w\gZ z_>77777駟v, `Y=y*ǜ}[71: 4̣Kw}6WtOWHNN ,zEqytҘFކ6Z|3wn蛯վ`j7'y~FONn/T' Tڰ~ctB5oI›,)W*ӪM#-_OkU5<8BS_̶5خiU?;m:u6>:UW~. el?jk"ȥRG+jd]ӓ7[c͛~zN,¾)مG3pĥҧwҍ;RpOu}ӌm{n޽uZ^QN/kTہ_$dKNN_*xQoB֒btJjyInYoސjUcOuQc&y&&SvB*43,N$Kfm-MkI ZOѣ~nXuZ䲟<Bqx1r^{y?/70 TU~LUOuS:c'NXqT}˖ E߮[G oIy}.VfEXRtMi}}P O,%Xdqen?jfU[`Q6&6w⨉#ﺥ{﹖sk7E-[;{BUXo〭]pgZPUh[.<iyoâ'y?mVPYw0cݷM҂*DUG.Tq á15+~%uq· r2Nw|zqnB %V3*@{4жnB(nnnF \"11QiHԫW 68{V-I~{gu;ilB0>>k45k\~*dM#~qHX+5k97nUxh^~O\nF~8u#X\[{ddddddddddddddddddddpsJX}Ǥn/l9{K)))ݺukذIʜ=p9uc=gϞ7o|ɒ%Ξ p\7V9r߾}}ƍ֭{]wu?p!MZ7 MzwV_zr^`44e/jŽ{gH|c?^^\v"D!Z !;'s7}!9&S뭗 ZfMllرc۷o}w}Gq 7lذa2d_a9{T5{;_> sz(5v`'){-{vMA7?!W0-9宛?mzS[6Ztb6۪_conjKFܳgOfffQQQ~~~AAAQQB]A~~n?;h4!CvmgΜbŊ-[:eZ j0{F|M#FdܮA7avBh>2oQQo?SsԶN$?+Q/wg6^\ҵ{kO8jkrϧ|{@CN¾XGyw.]zС'totww9חR!DbbbO~-[vz \t-zN6GϾyc['n^zE-cXBh$$FjץwܝЭ㽍3ݽ=9~?v~TO<'#Fp8{ꩧ7oj2=<<;s=˛2e;ShѢW^yeȑ:x322o/u֨5X5{U};eH[sg* !E9kXWw~r֬xv{n4W˲eznݺ:to=z7شiӺuRWoکScǶjd„ QQQ|+6h N j*5Gň>\%퓁Ǘ/XVzg%eL}%TB82'{lT' 7t7d,|ia7։;g3$$]~/eԨQ۷_|yz^cEEE}K.Z0`{1q{7==}„ c8EXc)@OjgQNn.TEG(|[Ǟhǎϧ4=ESܾM2wsSFWo>qG ًB,_رc}Uumg'O^tiΝWXpҵzvɢq7,yqf {hד<)|~iܔ]Do!5ݫF}o ѺtZ߿G⫭ezq۷td \"11QiPթS~p W^7lAPx//իW;{Ҝ_SBuٿӦM=N@`ZX:u8{B(,,BL&gX6#P- ,Tr!o,T !h jQj>ڄB8E`j' բP-8E,Tv"$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#POΞ䞴#6g9{jNik7F(gn(ܷnCaӛi+y%'=uǡ)$uPo欽ZŴ+lQm%3di6pf_ןϱ~~SB3?^Djy~~)(רEʕ!i-OP86رhZz-Eקe-:{:G=OBS|]E`T*4=玣E#[ViS*"ǚuJ(:ؽ]KZrxww3' FQP;p@ Z F"Ooس'ԼswMyBJyq*!}bsrdTB14o"Zl NifSo]^`e>6Cݜ܊ h(+,<E`l4Du9XjQ~زB!?*>!\,M+M ldD*+9ݽuE-(+7Lj @hPpj듍>nz 9yd IDAT&뵌-Iݱe)ElI/Uض?DirɖKuBkM)pj @M|| m1+xM #/ձG!}_QS7w]!֜oJwx54mvE0g&MyQJ!҇4q ^LHF`H)B&KOO=*ަMgOX@ᑔAP `gOX@駟:{ @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2 @2@ԥK\ooogX:Sطo=.gĉΞp)2:,Wx zzz:{\ѣcƌaBm2X\ Z>^z9{ \lս{vK`rM,S"/իW;{(8eC`j%$$ 4(...//޴iX;ps=7w{◽{fRX#P^zm۶ٳ@%X\\ӳI&NjܸqAAʕ+=\e4ӧρE;{u#XZ :EyoW (,U[^;(5B؎yឭFhM^Z4Fg0DwwEW^vu#}-jܦK/#Vͧy[!o|@vRsxcNV?~p-'sora7ݹfs_]W1dğKwJ?}+n~kV5ߒq*'/z,J7E!p}6qSf];Iq䯟مϵX5]Ȱ ]~{)3=KxkG59#ncp7u8~iz雬G~u|+d^9Ͻ<^5*O50q7{Fgu!ZS7nc{։L/v!zEqytҘFކ6ZojT?oE8 v8ZqB+E*_,??Qߣ'ՏEgy*pdmxZ3 ^u"U=٧̜ B} Ώ~V2^8yrC?_q~=?<1h05h;hLlV g۽i[*4Z٨kO{ߛr =xծ:4AƮ*P(Y|l Ы{ne7x6!Cc/Ewx=:G^xnМCISKOt}_x-3~(kuZ*5"P P5JڽM"&Y}w+z4z]z[?]▍F.#7yO[f+;CWI /^r/2zbWn.>Α ;Zk$낿k󦴟^hSmG7nսuI߭}G6oIkM(a}BhÇoF}1ղ#'C*tMjf2k͓_~?­%>}g?zqzJ0u{}]b98^4~w˦;>Ť6d[)>=3; ;.FE-Srn%0(7LٻecꎯӪEϚ?;2umj\|[G !TkI^VF:%$7, "å}2ﮞ /?{U$*{-WW'Be>c#BLjqʖ=B!4Az~54h0|Jo=mvnR1{ڻ Qv`_f{5/yrUĈXoECݻ{*f B6ЈBGA~RvzmTYȑ_?3,oҒkpI{Ν[j9Eh4P~>Y\.KʵB_/XE\Fuf穦<U;װWi|5"QTP76k8fqm<޴ܥ1z;R^0K1s?w˭-āW|Ȟd=tO"{»9ocVO|,L+-jWˮQi=5~*C/nfrZҚ|XO+ښCEVk_|=6 {K.5kcnx'8[G}e?Go`{m7݅j=r ~Ƙ^]a0Ņ˄PKҿyǗ e}4^O*jWˬQBE*B8rNe]|E-^5;J^B״{FU~ !ZZmtCz|L}_HQZMML>{/-tдI^M h.L_nմasfUjjx(gVng³-aڻioL*C 4 5o?vޒq4 T^{lW\fRІGGar[V\px^ѭjgbF]rOV}M!Բ?&v  ~tyC8f~\wO䤹co psk{3llpE'|;^"'{ǧ?&mo&tg?-1^mZrc wY7)27|ٸ;;EyfaoZrP<9yhV-E'ի\.F >}]mZhNx1:P))_Vr딤MMO={c=abM^pDoAZ) !IIIΝ6۰aCΝWZիW/gς^w޿[||geruc$[GTLk#XX>XT MQG9{ 8G$#$#$#$#$#$#$#$# Imݢ_ls$/XQ9eyYfU( 3n--/T!ABBBBB|xqfuKqCBBz&p~Fc@[& !Z{DyHBfzo&WH/=:rUC|5Mew\R|L{1ӑݜ9oK>I >A߿M6-}3=1mΛC7bf!#|ayys7nݛ38EҴ Up?5_|p^xB(n nzT,[E/چ[6ADg!roLL6)ֈ=f᰽kxF|M#FdܮA7avZg @`4M=y](ʵ'pb !^Q-fԍj1 )5:"]vi=#&w1/<WZtQ }4!h05h;p⚓@Uve+/0z+1ng ޲:ZC9'T{["n~G ϸɻUpǡ9=ol3 {U};eH[sgM ,f;~p#Bǡ=֏L8W=QTtmxn?KlW|} bm8ykn??(edˬ_5z#^pŖOz_`Ua@N8k=ߨmg2 Z[脥ms>[vQ>]vmӷ_ZA[e V͛>y㫝E;y_Pm.riȡ3^=D#W(zf3O7̝ڣ'Jhg`Q!܋ <_6wi~3vr%je'K'UC޽SNzwlq/U/wW\@寍[аG:'gc^Y9ӗޯ~Lw/LY]C+*K9O?4***>>[n9x'8G\OVvqԼ_GͻhsUcKF_SrN-\^.(+UXk>.))iرg/իW?'N4LΝ D¿YxoE>5=:dȐݻ eƌ: j)`Rn~co~=}2U7lWC?񹴴tԩSL)//>=|0mڴ3g^0`{S a\oTu\3wL]uɣGrUj\g\g,iРE3fƍh4>/,Сo6u^tSwox{{;e6X?h rW^yE !bcc+V4nS9a„wFË)WXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXp OΞ䞴#6gL9{@ߞnTv>kr}66)YrSw*B"[ aڻ=PͯQL rU[T[I#uڷ 5(~_Rv(4h22c PMAAFF-T!0HvVMn-|w,Tw`aQĎ5GsW(}SEVB=0ȧڢx4pcv^=(:XeJ`/@juL:NTkaahTD-{䙚wޱ)O!Y?o=nUB1Ol^VB(ƐmCPm6i!t:l[pw2(FТz*˔G!˴ԉ L4 w,e[!ٕK-/T[PT_R(G'+WDҗuW n W\cRNdz5,S5h6'yт&QoU.xIۖc֊[ :tom4(eeBPO[d2痩bx{(3Z!& s/ AvJ?VQe^ؒ[qBZĆ![mK#)ͯQLF(Wá*-9wRK8QjVw%%Տ2,k8m\;mblyF=!8Oӿd}Tzp @-e3<˔Km Ml9;G4m8e Gt>a1>,}HgŰL }$#$kyWf͚)p,g )2j,Wk6;YPX///gO8˔cr)ٶm*LWk$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#$#ڱ A A .J#ulDRp1X1X1X1X1X1X1X1X1X1X1X1X1X1X1X1{if]ff?uv6IDAT:Ak, f5aa!IENDB`crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0003_Classifiers.pdf000066400000000000000000000551621415120503000302100ustar00rootroot00000000000000%PDF-1.5 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream xZYoG~_я} @d b7V PhV!HE~U}̈P2e$kji J~Ђn_'J0ЌʄKq%~ҋ?1?J*rJ ,bvU/*=;&yCݾ9oAAƛljV D_ ?/-]l+˕΋K+,?E'Ӌ`wQZ?=6tB1[*JR4897B h4-Xu\#4q U1TCc̎ h3t `et!hC%ht䆰h_b(_EJN1= gۮ3/2 #Sv'Lj,=Ar;GǙO Լ;< u{r.DzӪ𐎇4Hwk^Lj:d>EvoGJ*FZcJnmmV0ܑ!UH(HnimoHvYrcLo)Q)~n6u]ҳe꿠#Go(֥5/a1L:ZZ4ZhɮSྯ[k=yzi{nh>>򸎁X~dn.֨{ۣ f'V-)p'C;;-Of5ٳ` }&} )K2u1!;jUPy]uѓPZw2T5#ޑ*E`QtROfn%UzsM'w`C|6]8kM}!2$T[L5'*p@-X! `HW4}P5KpxmIϾG׍bˌoցۚ*` |U[Ӡc'(:&5ĸ=iK_K7-ݝ@2vNO:4sJUClqnXiӿ,!ncL'Qo n>e<PjRx[.α-XX ݇(4ꁾ #;:pSvRP0٣h44 »' |gLqΞ-poK01KxмCn2"43e1:rښ!2×nn,yy27 |\Ojjk̆Ւ?+96t@9Hb0ʑ4بK?YiHh)/W&\䓕3^r}*+ ǜ Ib'H: ޱsϤr$\O|D6;bdNtV`*i%뉂r t*Imȣa3Io endstream endobj 5 0 obj 2614 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-0-1 7 0 R /f-1-0 8 0 R /f-2-1 9 0 R /f-2-0 10 0 R /f-1-1 11 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 12 0 obj << /Length 13 0 R /Filter /FlateDecode /Length1 4692 >> stream xX{\Ts.P.,YȲ \HB((*"&P]LKfS3F/DL3)[oBn9s^cD!$G#ASlD B$a%F]+0!S#Z7x3=cqԩO FH̩yY(GH c$ ؇{T؅8$C;ꃐQU"V iq9*c]®*n&IbX wx<1$!ь.;o~00ʐ)L7:FVC¸[*BUXjNv|-+piOb3^@[Vn-yM3g B2:Pb' _(BZCLLF)T 3xijoM`HXIQ{quЫ)1.9_'[*F9ʎq~s/NsoFNAL dK1zyHs|s?ё”ĢS7tίI |_+YVU]><564§Yٚi1$=mL8ܘTN^X662r,#L!cQ͛G =P 2!JF+ u2d0pvܯS4 ) K1Og1z8/-P&l27 trz ddZc.PֿhquC蛤\43M!a&fG&C2{3g&N;>=~=6M$ozƻR[ ښZ;w~} \0A?KoQ8dP8YWRQC6(v_ĥ9YKq]ӆ/ QՍ}/im,Sk&Fwd_M7 z!y+*D ;phm' rX%-[:Zp5!4 tAyHۀSSpbP!ixXhfd}9+;3F/c3N}5q-66L./ x@oLΈ 0ݞQz]( ն/N-lBIL^.΢N~F/;XGl.Iqd]nK'jS r$>\'g4:'œ p?e`Xw<8=9wn^0c[f00ndogiD˲%)CGֺHc1n_bpJr JAnu8 \o2H}ݱai]tQ9|{nUkS+m ,POh+fv ϥQ;Pf8Գ8u"$ )!d>W9թo=-{!Ǭgg\Idxmޜlb|tsb90MD*&DSK-A RHܥüFJw[Z/f?DoMvɼbДhi5!LNєw) ­; 4/b |.G^3)F ӏ!J·})rō+gjĐ5sl r|œ&,MnZq>=bmwDϤ b' IY%&ЙRLy?Xu/;}˷oOfϟourf@WXssy4:ҀQ;0 F$ ٛe?jc>snʋN/(p`bo^!=XU6K+Z;0lWBۗӭ |ʲ `26\ȼ};ئ\c*z?]E^daFpXbHXk]7< p8=6TOǮ]6y⻏xsG5A|7䊨&vg tIc+:mLr`ߴgOC{WGfrzwer'qN![6(W*^<*\: YN93xĥoq=.,(:/kX PQ~mLkkw8q%E2$V(&_ֻhH drVp'3KBR?=]-͘V&$rRoRw:J5Aeb@+ *' Aj]iۍVۊbd(5?, Ú'5Ϝ9@New_}RQ1=XXyǍ\;YxCRd Ǽcr_W?Y␼ڜ{Ƥie/[46J/-+e#DCgR1 q;ETz{7Au3jkE̎/蘓d)72_|aNfҋ.,jϞͯ=3'iӖe,sl67AD]An(5M>\g֌ONfZg-+Z+p:r5W6 ys`;˛ڹI=_(lXG˂/ޮtLJvv5őPVˁ]h\,FV69^3A?TvYp]#uHkZיq2J}?H ##ペ+?A+IO(7  3ƲCʤس$/!SRmok[Ufl^!>Pd,Sj^ubz6}jUQ+^WüY*%㢢Y#&Lxgv; #L/7"ԅSq^I5i7?)]#x=ހ7_5c○Fy/䖇@R/0 /pq}_@ xtӃ;TЁj!C>+G` *؟^nu>CCHa!t:4px3ÅuܽgBV+ȝCU]Op(M@3;*P"CGh VT&|)}h1wr'ku I>'F HG>@.`/Y1 wUE (楳=Z +]rǯ9Bf82t?T t&> stream x]SN0+|C4NmJ.=pMDM{;HZO&֦z=Ҹ-OaO3s{:Iǰ\?R:0{yyZE<ĩ[^s<|܃ڟ]VGݳ_t%ū],*eL5")iOR]]ou7 [E){6(ZSu] ;hh3oX@0{ִд(/V| r;1Ǡ> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /YRRXXR+Roboto-Medium /FirstChar 32 /LastChar 187 /FontDescriptor 16 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 568 568 568 568 568 568 568 568 568 568 265 0 0 559 0 0 0 0 0 652 653 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 451 0 541 562 523 564 536 0 566 555 255 250 0 255 870 556 569 562 567 351 516 333 555 0 743 503 486 0 335 0 335 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 485 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 485 ] /ToUnicode 14 0 R >> endobj 17 0 obj << /Length 18 0 R /Filter /FlateDecode /Length1 420 >> stream xc`d```cp``bPHϩLP@JFnI C-_s''?@~M(`Pc[|Vf @;9x9YSQ F'LnZwS߸5<*11-"& IYMMM̌ԔDELmW?/]5W'}fnSܾEe\cb Rx~  pC<}$NǾW8\N ${?A~Ȃ#sC ^} Y endstream endobj 18 0 obj 363 endobj 19 0 obj << /Length 20 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> endobj 22 0 obj << /Type /Font /Subtype /CIDFontType2 /BaseFont /THFUQT+Roboto-Medium /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 21 0 R /W [0 [ 443 582 ]] >> endobj 7 0 obj << /Type /Font /Subtype /Type0 /BaseFont /THFUQT+Roboto-Medium /Encoding /Identity-H /DescendantFonts [ 22 0 R] /ToUnicode 19 0 R >> endobj 23 0 obj << /Length 24 0 R /Filter /FlateDecode /Length1 3580 >> stream xWWT{Qf`fÐ;CC=)>PdTSMAL[eV/+}-͊PZ YgIEi0wgs{o/ x`0*0c59y77V_Ǫq/DTӘ'/7RׄSXSP P[0x.fC*&Sq@E  40&I15k[!(#0+(+,KV)}FVe,]r.@jFqQ{b:=҇8"9~1MhG?vX0+秫/T k@ӝZa^2pH 4[TG`9.v96JVlܜ6ľ4|}mKSg<;{OdhNγ./]<őuuf:9;w-&cY&@=Tvme{*z01+xk/]9oSb?#E5vs]Qd:2Bt\D#ZSϗx7f^3uGwu_ =cϼ3]Lo@b"T5yQEox'IhJ|} 임w[']-3fm^&]Y;-8v ksk;yo-uIIoٝ1WI]K8ޗjcKGtٓOHl& yLXtGzfQj46=rcKHO_S ۻ+UU~R4SiG;nW3Q wx"@,/x?u`4r1elmI|M}67զ=ANeEQ`tn_9WcM1zzq|%3V5bݗE$tr1v:y2_$k*Ғe_3yfkn)LzAvQrK"ooT9Eoڬ˗eq !LmM(S4DGJn¯a{(wx*熇}131gwm1x&|ŲrfվQqm bA0YO$"\bQJDKՖʃz>tL09l> stream x]n0EYtâ5=N YxT"028;Ͻ6âϸ .נFLN%IoE}p]DB7-px2ˈ`0LәK?8 ]m{0#d|Mܟm#bp0 6;h:o2Z=*J<.mtD.Ȋ54u8.Q&yGX1+⚹&/k+ə4$zCuU\wKn͙5eG<װsbJ=pfMϨ茒Y7꬗I=(Arϒz[_s5ӤAq ݝ58t|i'W[h endstream endobj 26 0 obj 362 endobj 27 0 obj << /Type /FontDescriptor /FontName /QILJLJ+Roboto-Bold /FontFamily (Roboto) /Flags 32 /FontBBox [ -913 -270 2060 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 23 0 R >> endobj 8 0 obj << /Type /Font /Subtype /TrueType /BaseFont /QILJLJ+Roboto-Bold /FirstChar 32 /LastChar 121 /FontDescriptor 27 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 573 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 673 638 654 650 0 0 0 0 0 0 0 0 0 706 0 645 0 638 614 0 658 0 0 0 0 0 0 0 0 0 0 0 536 0 521 563 540 358 571 0 265 0 534 265 865 560 565 562 564 365 514 337 560 0 0 0 502 ] /ToUnicode 25 0 R >> endobj 28 0 obj << /Length 29 0 R /Filter /FlateDecode /Length1 424 >> stream xc`d```cp``bPHϩLe;P$d&06/e``2sf@JFnIGC%_s''@&c M(`Pc;|Vf @;9x9YSQ F'LnZwS߸5<*11-& Ih8"Pi.u?t^Y}髌cN39ŻRe7>bR++m2Hr0@8^(Ha`cY5Pq`baHar7b3/10] endstream endobj 29 0 obj 367 endobj 30 0 obj << /Length 31 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> endobj 33 0 obj << /Type /Font /Subtype /CIDFontType2 /BaseFont /AZETLJ+Roboto-Bold /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 32 0 R /W [0 [ 443 608 ]] >> endobj 11 0 obj << /Type /Font /Subtype /Type0 /BaseFont /AZETLJ+Roboto-Bold /Encoding /Identity-H /DescendantFonts [ 33 0 R] /ToUnicode 30 0 R >> endobj 34 0 obj << /Length 35 0 R /Filter /FlateDecode /Length1 3056 >> stream xTkx>%?B @&Vl)4 T.A .Hj!zQ1Bb) ZZ`p'=?>3{Μ<RDH+9S[f sȸg梅?5fϛˢ9DZ0=wiVdT*:WDI !\O+lT1o{  N[9\59|IYi/Bpj󲵉 B1Czdke]V zaR+G!ѳGMZIWiݗ>^`/ΔW$Ә,kyqrTE\-Qԣaxo`p 7+x>Ԩ2ч黋>s%1Ymi&E#]Q3DMY$o hZz@U52!_YXV4&Pa}iQ~cdN6fFfYfVئ;dר75TMqCq,0tmhTO۩FrJZnӄyUQH䕶KvJ'aiꐺZD\zP#$*|U;T"!d/ft"Swt9jۚm~{:kHԎ{1oZ9ʨ^|7BjwcYYf!+{iRQ\lHM#U-Jqm*'Yr^'Hy2s)%\:@Ƒ-ŃF%²h`fES'3+7j1k.l}kI> ]o+X/2]je|89 Ս1>/1q&qT>)1 eK3~)'~/^\eZt3cz_ 0`:7|Ə##! ~Ʈ&iɇ$bx}|xf[?mn|7F1ii-Nʼn͛R 65x4xT"d<q'CGF~6h lhя06OZaY맣>|zCNʬkzkX- VMPw+ꕌ6cc9#sY81a|+7KKXĢDWjFRn˙] X;`$zЍ f  LQz@XtQ62< jV*a:;Rf4 endstream endobj 35 0 obj 1810 endobj 36 0 obj << /Length 37 0 R /Filter /FlateDecode >> stream x]=n {N1XFM"?`ƸRy2P ?83@q[ @ҁ 6Ub52BkE\3pzvq'rNn eP/׽f~.؟kO]/H6:\ȆfZ@r1,tWJznq\@SRmŝn endstream endobj 37 0 obj 222 endobj 38 0 obj << /Type /FontDescriptor /FontName /GSVTSN+DejaVuSans /FontFamily (DejaVu Sans) /Flags 32 /FontBBox [ -1020 -462 1793 1232 ] /ItalicAngle 0 /Ascent 928 /Descent -235 /CapHeight 1232 /StemV 80 /StemH 80 /FontFile2 34 0 R >> endobj 10 0 obj << /Type /Font /Subtype /TrueType /BaseFont /GSVTSN+DejaVuSans /FirstChar 32 /LastChar 32 /FontDescriptor 38 0 R /Encoding /WinAnsiEncoding /Widths [ 317 ] /ToUnicode 36 0 R >> endobj 39 0 obj << /Length 40 0 R /Filter /FlateDecode /Length1 4188 >> stream xV{xTյΞ yLLfBHȐ5L!! I M`"E^K@1@ ֦0VUz^{Sja]gs9gڿksg`6w ƌqX:Ѳ ȀdvxU7M}6HWCGUIYtʦ'-$ܱpn4גܹ{RuagI\z_k׌ 83Q5=P *N2P٥HtAvCS"CAT1fac(e^ON'%fu${=gX,9pGLaց/_HQRin~gፉ[u 5[ꛜyUݎHS4'gL3e;2g'S6,$lMImy2T۴aOL\-(qnGaz /KdnVMkR~`#Fϙ,+8sʒST*E׸]cs+'@wDxqVcm=+M9lo.-50ۄ!n|mɊ8xȒ܆ʾ_ ONyRڅE(kJC7+ ? F"Gch$UmʕF=WOGqqvSݯw>IG?~MUQ8cڤXWM3|>O Fq1D(`K$§/+ wQ[ٹȎhҞWQ@b:  Z{XytzÕfML[p%r}^Win.OWM8{C󜘔`j S.z@LM*W *S#jR2\T܋G X؛;!1[^EN51C͢kO>8[CX| [QHd{\B|??C^92i ۈeW 7 ÖLL*;ٜ=nq.z^dhǘE;O!NvMXf5K: G]||q5w.b]95yDi#F" q7c!{٠Q-K[2ְgس̍ #OQFS?!}| D}k*/vh*\ڀhԴvfj_bf`- 2CHK&f p OU'nWSKg+^HIDjEI̹=۵Y۵yPnMxE ߒXw6&&Z(g^-tKSMFĘkDw"ΘI~{>juEFP"CƬȐTET/UKؽJ[3$‡Æݬ_&Nv'u;=luR{kzAoBERjTu)Tj]@5o(Knl`uMIRD[ 1_ḰUr$A%0;?K|^ş$Ņ >#ħaH|dŇA^ {';d~Nzqv26MmޕxGmH  ڃ7%^lk)W%NJ"/$^xQ f%BNıű8^=C]yH<ij?3~Ԅ;~>d8dS0~"A',x\GM15~ A<"Gbďoo=؛=n !`AkIN~'}E WwQw`}$-v}m۬{Hq[(R[l&b3~ ^bDM^qDo/&8ZbJNJX)qGø=ea,X"XbI,0׊UIH̓K̕#]0nl%n+fɩbK̠gԢÆvh1IJaD4M4KL0Uz$4јѠaJ&KGAI\uaԞ&HLPmJTOU5DO@D8U W eq\CYJ3M$Nx$JP\'PBQ=. > stream x]j >]NC&?3Ӂ(MiM*4*,5^IG>Zyޝzg84 JDq, n=N k>8{IdoNSz׽n'Ni@{OY4[tcU|SKH-է00Zd],CRHE"*#W*I.D7+QIHF4N%ߵzq{ĖX oly(Yc7WW  endstream endobj 42 0 obj 272 endobj 43 0 obj << /Type /FontDescriptor /FontName /VOIXHS+DejaVuSans /FontFamily (DejaVu Sans) /Flags 4 /FontBBox [ -1020 -462 1793 1232 ] /ItalicAngle 0 /Ascent 928 /Descent -235 /CapHeight 1232 /StemV 80 /StemH 80 /FontFile2 39 0 R >> endobj 44 0 obj << /Type /Font /Subtype /CIDFontType2 /BaseFont /VOIXHS+DejaVuSans /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 43 0 R /W [0 [ 600 535 892 304 527 524 523 277 478 552 482 824 ]] >> endobj 9 0 obj << /Type /Font /Subtype /Type0 /BaseFont /VOIXHS+DejaVuSans /Encoding /Identity-H /DescendantFonts [ 44 0 R] /ToUnicode 41 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 45 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154042+02'00) >> endobj 46 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 47 0000000000 65535 f 0000021892 00000 n 0000002935 00000 n 0000002729 00000 n 0000000015 00000 n 0000002706 00000 n 0000007452 00000 n 0000009384 00000 n 0000012897 00000 n 0000021732 00000 n 0000017352 00000 n 0000014664 00000 n 0000003153 00000 n 0000006635 00000 n 0000006659 00000 n 0000007153 00000 n 0000007176 00000 n 0000008065 00000 n 0000008523 00000 n 0000008546 00000 n 0000008848 00000 n 0000008871 00000 n 0000009146 00000 n 0000009547 00000 n 0000012142 00000 n 0000012166 00000 n 0000012607 00000 n 0000012630 00000 n 0000013352 00000 n 0000013814 00000 n 0000013837 00000 n 0000014139 00000 n 0000014162 00000 n 0000014428 00000 n 0000014826 00000 n 0000016732 00000 n 0000016756 00000 n 0000017057 00000 n 0000017080 00000 n 0000017570 00000 n 0000020788 00000 n 0000020812 00000 n 0000021163 00000 n 0000021186 00000 n 0000021457 00000 n 0000021957 00000 n 0000022074 00000 n trailer << /Size 47 /Root 46 0 R /Info 45 0 R >> startxref 22127 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0003_Classifiers.png000066400000000000000000001677711415120503000302350ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxg@W3]JAQED]c^b1!b$jƆ%FX.(TA-}PD1+yf\g_ܙKB!BiB!NMvmfKA!jjݺu> ߿qU BMVZ3S` {.B!T r웚 (KyVCE{MB! &$/;wQ2e‡ tnc~s:;t9|Qfȳĥ).nMMԇ,QISIzVB-r6Зb>NoiAKttj'H,[u `OO!%wL ғǝHsN/91m!T* u?koE|7X{yز2YBJ?,5qoߘ^J.MM$|dQ=XEu X`9pB?sݿ)o&BqŦmL ԉ A(g뉴W!B5Dh,R 9G1:B{C6O 6~!%ƑWP KtBSÌy0jܡkc rf)`(BWsSK`uqο^<9ޖ @wҼEz~2m㻃j!i !DYXX& )Xx/nTsz>{%V~d%%4U*pJE_@d7#=W[0@(*.P{VF -@Ju;O7Ҋ0fxGg얘dH#V ryz-xWq ]}?#yMHc| [EghP'jP͒*Bvt+ EB\#1/8,C>/kn{[B[zymAPb+ѳt^R%?R-u^-C?vWX}Žtk6f`ۄ$>u {HWNAWUP XoV/W.IYV#&Lj/$WD~ۘe&gG]խͫ89}3nW69xDmroݣBOB$A $$"=|9aϮ|@j\V\$:K( $O L x&J%Ly,qkc˥Ʉb1lS{ QGI 3RӼ-t?ߩ[S9wW ŦT%K^.c3(]cc!@!ǠXUӳ[w/E $lN$Oce6[Q``&:ZxހPufEqqiM+Gc6 Ū۪[}?)EzJl㰕AWS7 rmY~0aU;_L ٳnU jW/FVN/XRBsg<^ŒB6J d\\/YYUĥsw=k#ne]a27߸^T`t֜Sxz'cH?sj[WFס!ň'wa-uҪ<.)+/(HOӷwRJ>BB)M#{YG?8Q\mcS1B#p.!TOQƁk#k`!gkX!=X! "9Qku5 Df-{;x"$@QkH y%ze6uݱy Rg{~]UڼL:s@Vp5`ӞcGO۲馲U?8a)V5bCEmo¶fٺo}пM_۵X_4_^P<Ҿ!Bi `!4#761o`Y9Kn'(X`Yu7e''e_oJqi*UH$2sZ4*,ބ {OJ=Z6|X/p< p)+"!Rxg BHSP~?j(W.\N-V PU!-A~=5}jBaŜ^UЙ"ul eߺIMٯ7 :)xb_YY'W_=I춟VL"tEm=yǗΙE~_{.sU+=li <Îi:Bitaޓc qu%!O6a&$WJoПCr֓Rvl>{ }b`!j¦ٛ)ؖ6V#HIxgBϣ9l;c8>TW|荴>3qF@@Uv1ooo@u7~~3(fj~eŜ چF-pyRիj5+Rٳ<}ȑ#J%NB57{uCc|t]wNdԞFvFdޙc dvHrxa#g hrc-ֆo[i*瘟@o,2q.]0[CDDđ#G!>?lO(7뗍ߟT;tnl6u7O]5<^YV\TT"Wx6n]aTy3[M}veOOϰ0mXΝgToǧUY˖-k `!͛ׯ__:ܿԃB5 !Ξ=W_ PMaBi#6ݮ];(..{1 ۫bj, vuupႿ. !BH{k.))i֭)))qF۶m. !/"W``m`7:t(E!)))mڴkY˃$ 5@BB.hggWP?~`` 2]BVtXi;wDDD4P?]Lt /L4NTTT޽{۶m_nmm=dAHÆ 7ߔccc㯾ן9""K,^͍*Л̜>LppW_}?x䊡J***8p ,-H V\믿JR'')S8;;[[[W }8Zѣ_xĉF1cɓgΜ)N>#4"11jҥKlAZZZHHHͳlhh޽>}: VjϤ;lڴҥK;w|X"00Gcٍ7 \re||իW;udɒM>|V ={t]?){z )aeLR)c0͛,i\v:tu ~M0AP0]R͛7OMM ?m6dȐ$+++B ^"D(..ݻٳgFS Zn}˗9rUސ|ڵ*_zQ-4ϰ O>ϟߺuȑ#.p8K.uvv9rd=_>tQH̟?LW4/Hc| [Egh:D5@I9 )2D'0%:iU{I)=mB&];vnN&:S/q3@mkRAŠ7jԨg޽# }3] |:v/j=B!Ĝ( ѹas][`N>:nFl=g-[MOSuC4K[<2ĪQ߽{̻VFGEEEEg4f|~&֞kj{"?w8Śm,AUVRWyIVBp8s*N^ɣ 9Z\1` St00Kk\YYYju|Zjϙc`fiΨa}Dg8oyG.j4.6M]a DF~NQf' ͅj>"_38W*S7 ryG#o=j@WS kf/LY3Ҳ壨>}sQF?ϐqӣ{?+'X% .*΍ srr ڶm[ff&ӵ1b,J->w``1#ۜ6m5Yip;@6u2e)SJyzyyyy6mD>}YK/Lm@~+J1è:4w1$Fe25al51)FߩI[>@siەJ̙3.2@??':(ߺԾM>YgϞ-wt!u ټ2J><2Gȭ{TL- X-cdː%s<'mµky{]|UP|qw[\.¸u36%vMsWYlZQJ%{ֆ mNŗU {:Ŕ&am+ƫٳO[&S? {MN8][ȩhaKx61 $^1Dsy@~z\#Ju&&@g_u|fb@ϰ3NX֖GQ37kc%$6cǕ2_jܸ޽{.b݆ @8-IߐM8_HaY0zνa׷{tM {|&D=ߕ2'ꢘMژpuL Y0K2WA6"";6DL< !\ʹȲĕ\V.yX [X{UJwV] c>ѣiiia yAyì Y@6:< jty_2R,#'C7S us]UDCP<gӪ\c`ݩxǩ!֭ m8MUA6! -%!DȄ| X 9K 杍PMxFcOe= JͼKL򙞦Pi>kϞ=t!Wg;pضS#dyH(>SԄz=Vwʉɱ{SC esVYKUz(b IDAT!wYt!MnՐEp<` {PB?Cb7~rmطoӅԌ^J(I95j0n/VaX ؛|P3=M1x!BB||2shmXt6o8NBBӅ%m[/ 66bιq;oLmZM9w7}>Bᶘu8" XYiiiVVV\.BJIW@uSHEwU@j,&ȰG?nY(&243/a72or޼$!?ہYZZ2]H]¶fcٳgφHZUe Ygn55Bɔ*'8 ,T3(TkkN+**H$LWQh:k[7XfcJ *ޛJJbϦf?f߽sՇ!؀EL^D<9 242ӛD"),,d:ҀRq{k0FmϦS(2P d2@Yܓ{N/T @|poӯ%"EXtE=\]ݿّFPl6sgFxwvP8lwKiyNSVVPwlˡYZVWMwhІcGLk΃'n| UC@:ٱ -ƅ^Rf)@qd萑vաCk[둶+s)mꘊi {B!4 VVa zٶ1k9e]v!€^beiy3y?)!laB/W)t,~̟cBcaBM/LzFɽiRO``Ӷo_IԴ]6虶`[2 :|Rp{ |w RT%)J{ Zb<_t޹ǯѕOcOz#E}P{|f]#8?sGw'C ,/؂`y5 #TxWK)JEHuoqk׿S?σ fޚ DY]lhi͡be%yyrBPiAy7=T6QPH2uy=<;cO_{Gm/'r:KO d7``>'zzz8***c Ч Q,˦(G nd0tʧWim~Rp[!!*:|LP>cyK{5Jln.zܤ(;_ڻҒR ~uOFN:t 'OtڕBB ^"DlWe:ό KPՄ 9E$3wK¬AJ\ >MM^S?'h>wO>eQߍ*Ӓȳ|EǏ9::j& Օj,.$jdP"oMUGG#f jْKs7,$xrZCo= ۗX@Jg Zmڴ:4U&$ E<(Z⩛OI7/Sg/I/*_IS:w%>[N$Q[/@w.FeVЀNI̯y###ݽ["nb (9υ|лPFZp(Rp$iM,]fG Q*1Ϋۡ}l(Pжק+*u0'cƎ}ݹxKs&H_ "Jeb>i\tʬogB$?nee%@^KW,"e招{e=S:D"˗ּK#,,аUV51V_K&'ځ #)]Anzc)mq ʏv>ݽԮɝZǩn\R3ODӧ}V؆p8}9rHiiFh,R("tѣ[a\\oelHWJW-SYA\lj.77(2BXck+WM5ӑ J% oE_pGӧ~H[j󫢱LPAY߫{]4x]u~i/ e۰, կamim~,kՕ5- ؤ$n]/_5P\fM^QJ|вÃ!۷رcҤIL_eaa@(iOT4p0PBPAtأ۶m+** mo-ӄGl s|TC$#r- ӳTw5o[b&/_y?L7)RE:S2tcGʿ(.U?){{;SӔ_Fna]o*))Y|o ͯUNbb,墚7?T iʤϚ+8>gr↳?w5?~?ӅWLeJ-}~񅫉RB ,l%9PT@R;&F+6mBvH ӊZ}… >}tio~)R3J /T^Լڄ=XH[p-LQx{{1b]vbGqbLZF^ND $$"=|9aӯR$~Rjf8ER LM9@D$?'i""?Yf\#][{ (U*îmee2XW^=zhr{ I-)QC Bu룢ekkt9bQ@Wp3utzvHn`ut*97kZ{fD:ډ)6ѱ“.Ut'OK~1oŵ[&þRRRf͚mjUqt_l 5h~aBDw@@ٳgP %;GШ|}o;9T^3v1m/'kսl*ܜ~xQ@@Z>z{ׯc&Ow Zzu1jk 44? X NNN'O֭_պuk+Aiŗ<'6yoč7z%bJ5bĈWKhf^p۶m+))a\b ,vEDDzzz.^xڴi8Vp$6.xoRJrڵgΜi֬YT ~jCCC_e2WܚbF_͛t}֬YnnnGih㓠iȑ#sѣGttt}NWo =|t!}B_ 9_d޽{;::.\0::F4`GGǾ}TСCL-jE $$[> !Mٳg``Cnݺ`K$'''Xtuϟ?OJJ~PZ;WAAAZZZBBBAA_dI߾}+4~'Nhk׮R p޽)騨)Sh#==P%vP'<7ՒѣY N֒f8pYYYϟ|rBB­[e2 EIIH$DYY7@  ߰aC<.k``Q KJJeϗ<o…{(ɓOPu=b`` ڢ.&$/;wQ+>\ؤsfU&M.QsŦ-[1qy [S>U*y( I.&?ՠegDS}CQFsww Ο?HHH8qo6rM6^1bӦM.!ԃoL*MLN؇%2kY";OF=%WQM_XOO/99_^ XyDYXX& _MS fME9wٱo=QO%rk+I$д))VaS*Q@XRPݸٹH8P((+,T]6 Fp…  """6lPFy *RY T 0`!=)p XHZH77PDOбOYTK߳׷{6tp` bKoоFna33JWWwssΙ=Peeeyxx0]BbE+Ȅƕ| ?r)uێ"*+-YE8PT*8~sIUP|CK >C,M.)% ,JO+jmJ L4iժU9990gHkM>կN;`ḄbP&-{5M=%2'Or ,#GOJ=Xl3I5%?H)05P>Ai%o@KF*mܮEyVJJRV&<> fΜ9w\ss1c0]-Zhт*U8iEM^_::ܽy'p3[NGYsWk*fD{ήvb (6T+e {VK2lbC_ x;WRBӄba&M266+{}AJv5Q.P|cw? yƎ/JǶCW{2qp'enN_V<^BHK`Bڀ2hy-y{N.4vmR2*+î\VV%E!aBځ#q0]+|S'kpy )!j BH0]"=97:&5C== =wPCD?€]q0f\M-X;wѮ" C֭U PT O_p|aWX\PcWHI};蛐MT+ ԿuyB5?yB7]e5(>>:s1NؽxÄ:M €zm'U]-m/z /u(niw٭'ZUwOʲ1arP{v&٨+γk]uiT֋ 9a?G85SJ7^~9wi|B"C >* pTfqSH.Er;Q4?0iM'{nÂ/|=uz,ZZ@񅕞(csôS}74vݘAB$ B!߽I;lo= wx.⣏.ƹgN/W{ h|M~Dmț7v¯0u"4I=kklogC6Ke7ҕr5ui5qSݹ{nYoaxLko~ (/)Uυ׍w [<~U&t}V9ig%6_߹ۑ7=cYSI* ҹzsוp6ϯfٴ^=VRi%8mn]}ys9p+iϱ#'g;vܠU/6!ޢm6U<ƶfٺo}пM_۵T5LgDYV\TT"WJ8-f -c^ojm,{_uஜsw}:5I8.g?6<O[?sirp  !qHbT*%/_d39nn9N:Ysfյ!zrR̀U0m X rlȋ -[_/][\믖jIvBygS7pQ,؎:^qnri XOHVN:/QBsgN/N<,lϜ=V~iO Mj5 6S_۷ϜA~㙞ܯL,ЧC6u2e)SJyzyyyy6mDPO@QZZ ?(djè kb9v<g#zu|B}Bwt7NЍcW˯\v^Qʇ?X4";c&ԶCRRE8Rȍ(GRPU:sc|1ޡ- -ntiiwK"/=ß+84/h跿$،xd@'` ,_fO]IviӺo?c[rq}ңYV.$!Bw@xx8 GS'j67kRõ^o?!>i {B!4 B! wPyE1*B{B!4B!aB!0 X!B !B_ IDATH0`!Bi>!'$JKJJr9Ӆ|N|>Ӆ !&8q""")))J>W\.ήUVLWjB! ?k׮pMVVVm۶ӧ}~sss>|xL4ݺuc4A0`!n޼9q7n؄ 4ޞꎤ}m߾/_ܘ. rG!jupppvRqqq/^?|p.tQu9rd||СC,XW_0]z' X!>FQQQΝϝ;}[b+$Ɏ;lr̙N:3],B5T*[n9r$((rѣG:t͛}QTLܵWNNNHH JKK9?`ggt-iy;wn׮]=z`zW^[l ^t)7aR999:uJHH077gNV?yDR3BzI& 6Z#F\zuŊL*v'NtԉrgϞs8GJ8qʕ+?IAe~=QHDfM=q ؟`沮=5N%YԩS'NfCp ܹ?YѣG-bEhh{VZ% 5swve&(i' qDz ?dĢ(Aj~RxܸͬK1';JtttVZ{a 7 +*]8qŅr>}'55իWhѢW^`~N1%i7h|\^z~i@CJsE$"d3>orz:#B|}}}}} bT^^^֭B3gj֬ !aaat]QjjD"122?M,#";>TBn}|WUE܆  66V{F5R1M,m흝ݹsP+׎;VZZF7{l6mee3gtuu3g΁.>:|00`ع*ztQWi9LˆRk(!˲R` Dz?rʑOqu[ڛK'b30S[wľKM:{_)<``r V/q9g蟉 "F=mIQߌ|8id<ٻ(/o: E4 ((KK41ƚhI45FLkԨ(XA t8q(E,p'~tow]q웎bF@}Upgci{+|m;иE~_'۷+~k?\:VWԩS_~?;z!`閽{WQvǏׯλrr>M0[!u 0JJ McHޛ9bߊ8H  ERֱG?pT;}"~Ɨc:xμa5(+-5eʲvuKեK۷7CCp;BH999ݸq7nZZU\\D'#1PK jܓGeҢ"i(0FU/̭uA^sѫr4J)c7川oN;~AnNӷ]oyyڑţzFmԴ^KQQQNNN4 ,Nիӧ/]ŋO>ݧOF:@6mNyco7*H$Ǝ3N%& +[yP0G 7Xc;dۙ?ۊzҌB'jǔdJvA<z333~. !͛gmmݳgwy筷ٳ'|Z2000hD&dN-Q(N<C$}o% @2Tvöo3UʚbIO'_sa.PŽU@X,P]KFݐQb2F "~g @IIIS5&X!&G}ȑ'ObqsLjAOQT0M!lcF,N{~M96#_:TLТ>fƦ&f9㾙S*ÛKy;hq9a[#"_òZcvlBMtut4JFBh|V^Mw{t&X!]giifaaPS!f7DEn=gl;hړ0AO_3 )+V ]4tюyo۩mxd_̾Ɛ񚙝8[7ų[A-̿ HFӚ;w[nxi" o j6Ck ޽#k}eM邚i@6mڌ9> C gB^"D&iy'k'&l[0obq 19UǧH5w: yiNX>!?`snu4kS>!D0lU>?7mڴi&ߝB5,X^7ɣ N ފ}iWizU#K#aX,QW]9Ð' z B!a֍/2kD7 d2SYʖY_z\JR]9Ʌ76]d3׎ZNMMMMMU#`*#~Fي| R#W^"lNWBh V%v#LٱDŽ0m{ .!s7.FM-vOˇJ\]B]٠XyHYBQKfr*nFdW)r81MLcX3/n/?R޸xcɩ鉛)c`^Ǐ:JS.پ}H$m۶ٳqѢTkWibE^@QsN}:Y5+OMH[-;1dro%-s$^a -ۙ);t9گ%~>@eeG[o_[EVU MM[7e&^!*-/)v bOL-P׵$56:1=DQ=J+_J0iߵHWFBMGZohvvdv 9 Pʸf3۔K;r؟m3zٜ.8|Rwߥo=zt#j !;nC$^ܕ =@NueY;2`\xCZT&Tc=[^fW7_ -)L?aB՘_! zLM]7H@--(1ˤEEEe x<@_li5'oe<>q=b=a۶mVVVAAA۶mkQTQ\\J7o ݻu4j>܄ǎj;OieE%k" w_6\P)fRIkm`qObUK'N|W"+bYu[z`j׍u'λ{Xʸ%&㌓b}v0+fXjFH&/TC-NnnǍ0 0cǎ=vXvv3|!+%EPOd,|#jNKRTYbN.[7WP B;츸&Yе-&31j4LPMdD&dN-Q(N<Cr}_2%[ ,m%.b+k.B;h{)={<޾K ?yZ+&Lؔ"Jx>(ZuZJXl6(J TfZ[jOXojF,jk*+-i%f>>6۠!ۢn˭j0B5ukX1U@s#i'rE=?Ϧ/ڈ`&,Oʻ;C}M=i*"|8 5ضmO5tww޾}3$PPYQK %"YR.+Qإ[Hp.Nb\SKSUF݂⬔[w&|W0\%:-1e//*PЊJPŋۍtݖ3^ 5|P>-|AilJ/l;򛈇UcTeΠmE|~O?T8 GX R@d?08~}CAP1pV^źO f7DEn=gl;hړ4g嫈 r5g-dܒ._Qb!Ν;駚[6lذcǎFJYXk&&EG]ˣMkqYlcK/<,{8 IyQԱlڻ\=s6@a- @jJLÓu[4a מI/U,Re>36iajԟ_ 1ȣ7v~Ho~%|7kMRIaj,-݄]`o `{89#< Pvpۣ=]RJEpi` z ϒH5yS*m񢚼O6c_^QPJBzh`9|#u!\`YXz06zÒ~  Wմ υq2İi JڱXvʲ`ĽVJ,Q, v(k5QF+L0"ԔR>"P]>ق]vXtAl GB-8#y2E#ˇv>NXeYK;r!#rj9o*n\V|bކG̏=&1#E5a,Pyձ,ܼk0lE 䋩! @b 0@E1222cྺ @mΌXCuIQVNnP=޾9eJƉ%aly+LBgmHlfe-U5ȸHaF-22 9doi~7! xgɾ?s}\E zfSГ0F!">~|BK7T O_*`;Q8QxwwoXuh@@qn;R*hYp$,srM70sd2JD} 1 =,B+3<(bjofT ъ _w065u|(W͈BfMY|a(xĸˈlYk\K\W'T 5 ca~ BחaLjBʊUvc}z6c2hμ^}K1Ց0HԶoۉhI1hw:Y8eͪQ Eˆ; `L;9X!t/Y_~Z66grrf}/݊7cVSk{]M]q&O۽%24?dzB)w]گo͹[6b۱ v^y*as֟O؜[}ԇO &}&QkD wm&qt < v!0B=ICo>@d@&|z⪷!,R~ۀ)a6bQUaA)MOY#_Ѳm*N<5c 9啕w~ԞKխtm^]cQzϫNģv%c6F-&XѢTD"M8{KZK>srf=_gNk%dbOXrݵK\>qߣ'c׵H/.I/.hENv͎l zv,?q{c| "?zrs 6~4C[˗Xx0@us?^׹d#Ev&Y\X;X 0v١{5NXB (dt{cgh2aGjB0BZ@+*~#ne&^!*-/)v bOL-PB+'' tg2R؇pMLEE2MD%W@@~[y >GՐm޲~Oz+f@|Pi¯Wee\뛑}g?ΛXV"(wnԉ?$@e9Ħ+U5?*@\Rvo,{ؿov?| fj`GBw%/{W"Ï#'Qf䲬L 6JJeB +B$/Vo`n'21 uGaBu_'y8agopw{3N{÷~RF]R8x^y'x޾]12FCMubrүCʓΞS$p4OHWT}aIw'^7l(OSnUg#;ζQ@s|MT{[TPu%Sӷ ?/ie#aUWU[7o ݻ%],P&oέS  w_ ZT"l6 TJ%U=8AQk XNy8s~'rpl3l|?iWH}Ɓ+3* sKm$@V88@l`@ZZTwm%a z2ѥ;a*\Vy c;>I+^5~fAw\D+R`4@U=OGJ.Ҽ/BAՇ|kkѣ^++C=X0F.A:;ckn  ,xuC6vqq2@.05bbR~3̬kaw` {L6à |Tˈ(㗿1bޫS>/1EB@]'9aC穉苄lͯNB8Cÿ-8!t⺛*/r74}LsV1f$HAbm`ʊG 1h^FfI4Ps+ c-$J'1*#nAiyqVʭ;RcH+~QT.ȒrEb~[hīXEP*U}VTT Bn['bgkޝn[s؈yz[uCFa?51:ȿ3h@-vR&y6p'q,_eAoK6'(w Qi*T;xu;U/]Zx!%%YYYi;T,C@]cM"MG9gǖ_>y.Y*q O;~!]gY.˻u<<<ɄluՔ0W*Uk:eY!]Y3Yo`o7?PHgyz[wG;6ҿ&z:Y{}%T!W4i=C?dʨn,w\\'5p ~=K4oZzahos=6qvgu5p&8nvLycqRJsY7 b׾FKx{BU.c>qֳJ޳hl3p G&7ZgsLFu0ѡʼn;oo$&|xZ3fd-) Xu䙛E5z$VK>FK艨{Ś*sn8ѓT)T(I~{UgE]ra.ղ Tuۀ ==ٳg?蕪MJ)@dd6sܹsݺu ۷cizJi %_.޸%pW#w~dgg޽{G7A5;z<8l0mhEZ<>LJ,SGg;dY{+Kx=; В-H>@=: lVg^9f^[Ǐӧ˿0̦LK YyfW=O>aaa$2eJlll̜9344۪K|7!nZr/\X u/`jȀs irXֿUZ[JP_Q:56oliiٳg>5L[AAɓ1B&6=mڴ*!!˫_&wΝ̠:1UkB.W]:;xyى/T/..ѣK. X:,6cƌ\̮zʌ3~ᇏ?ɓ/6WWBrƃ.G &_{+C=B>~֬Y}}_5@M,]ѱcG B8am7`[[[mGbkU3\ +IQcQ|O&,%$]>{SZhjj…TQҸ] 7@Z5jJKK4h0XR`B蹙;v,00000رcڎH̿gbhbx&~!On䚸tzBx~5Τϓ1ܿʨ6mk֢9}v^7xZxhƠM~om:ba=?gq?{p8FAsg`ά5hRcʛ)-y͇K?\ݦs|c_#Zy{>zk 7?1o]פj4DBʦNH=glJcmI޺=m7.17*$ ԃ=>.z3 n:@MkΔ9rl.3lߟt7›?ML*]͞ Șp!gu>yË́3&vaJitLBuE iJ.oX3y ݓ @8gJ'"F' /\VYA/džA!ά)0<>PLN 蛘z*cDPFX}msBLBRT@xA}[jXyI<@㧎n;xy?xoQx<=%&,5;Fv<m5ߎ-z6s9X!:#W7 Frܽ[ݻwh:2&Pt)d $p-/-S˕+K962D'֪{E{Y Q r*G} N7}<. ;|9qÌCq~ Oz8>JivvÇ322233333Riyy\./++{'p\}} BKKKKKK+++ 333m8>c섷۫vh|dƏs [qt*_XNeul"p\۱ZE7m~"XTF7Itf}ݷՓ;͘5̘{eDvqˊ}%tOqX:ٵ)<ɰ;_E&XVXXxb ÈD"c``PO(---,,,--U(?RZ~t,133sttH$Zx<}Q2o/] =M^k=y׹i6ZҪQM߾e txn.6y#״ Q3=GsbvYbϾ˯ςxۻl?A%<hOIO z!D3ڍ!"UVV^x122ܹsIIIb̬m۶m۶533cOTfgg?x ++OIIINN.**ceeWf)/-hWW/}ٞ`i5)B5gϞ9sŋ,ӳO>%wwwkkof[YYYYY~qŋj>ԭ[7LBM,ЫT^^w޿by{{O2{z222j`giiillɓ'WXd@ЫW#G>\(6gl /"^ƒ߿ɓÆ :th ]JJJ:t,>ߧOzkذabX!^K5)LB/ʕ+lll>dȐO.Zw;w޾}2dʔ){vh &XUZZcǎ7;~NK|rXX؎;JJJ:v3Fs"B=Sl "O^^ނ >Jƍ322~=N:=z:Jrʔ)VVV_|E~~CCf0B5&_zAbcc>ݜe ?s 8pŊf! &XgZ :4))iǎ;wv\Mk׮;wLJJܹsj:000**J ,Z 02&&KἮ|||.^hmmݧO={h;aP~#FX[[k;כӧ;u4v؟Y ,Z3gbXFFF'N2dG}emLj>|xLLLX)]ºRJ) H{bbb <<\ہ:@LLy=<<,,,߿ ߨvF|נKU J)r e)Tm `wX|MY!54>SJ(k҆B,ZGnذaܹ{nq)窳G?Mwg[[JwB-<!1 3w!p:w7QE jnQAAQLEO*ZY{K7|#TύnoPgΤ5Я_ٳg]MBHw,Z~"c;>I+^5~fAw\D\X #EF ?`{Cj<ںZi*T;xu;U/]-~g9Ce2%cP5xaX@ 4 8),uo}~٘-Xg#J`P~ܹ/B 4goN/ɏ^鰌zw@1Q񞛉q#?ز׸7/X̙3Nv,& z6*Mض`dWGSOľbrd3lm,腬Xv„ .c޶S 2ȾxXlE"Taw$"WCXS֬m.`PO6-;-)8M.<|Q'N3?F m۶˵VɏO1g* -\,ܓ\T},n 5ڥVl?u;<* 9RZyh4qFmz+%&&B[mRoa^X&JLLv /tSf ! b^q+ -C nUM<2nzZ ,44QO(ɤwO-gFd)[f}}[ٸq@ 4iy-iҁ|VJhh( v ZrbRTߏXMHE+W+mM'vm=cjBM,Ԡca;Uv]%\ЮelP?Wi V%v#LzHq% OsէV\4؉c>o]!CWޒ\%2@q;6!+od:n{xM^:+֐iU;Q~b_h?nåv"ۮ7U]ڬ$*M`s7.FM-\~j-@vs'tq zqV%BE<'c69нR IDATeqt6 @FcEjJK|%: ђG=+ >3^߱ؿAݻN>@+DjS龷ET 1@XDM(U_a뉄|!pWܔX`;zAA)9,CݔRHe5 zSULN&@>'heOuy1+5iNϭ nǥW~O}mL~ o7Ւ%BXB H%5Z:8::37xJpKO,dS}b ,C;vWہ 4_eݿmh`$E|ړjƨߏyEEWWX,K&%Q \R>s&h ._LNuPy V3jJ^Q#p(<{WfUY۲IBeYA%S ^ɓ'wﮯ@c]t9qD뾝P#gaǏԏPQ H7K.*N*o1TYc(,uO_p|=AI^^5ӓl-Z@ӂ-[VQQ̕t ! V)=bEOyj3ee%b5#13彪0h .$UVi,ӄ/p:yP]hF2nDb8㤬oXju{ q?i($$$T*mT*UEXp;|zE uav6ϗ^UP 5H4`K(8n*10kͮFݐQb2F "~5IK = ߠVN닅$:呥 Dؼ-UƹuF(1+rPKnjd=ӫ?,0eC]47bQvB.Wdlʱҡ3wG;6ҿ&z:Y{}%T!W0(襤Xmj;4kkk@tݥs|xDuw?]W4}ǃLu<ژ?]\=MP//>ǧEm:ոZd=ӫ?5E0B@o4{h';#=Wwд'cy3C~zkfv(o%T43WSA/,33‚ͩ&3"sQ^p-p8fffD'pf~3ކE+.~pwmh${^^C"Su:kUw,~Ɉ T`?`9J\z^ +7 :XH5-03bĈk;"!*1GvG纩ŮֽT ujt&SúOUv~{k_[ jSX`!bQJIc*5cK}{1PE+#kX p3 _> +xz۲2.Ⱦå*=^b>ubpZׯWB5ϯbjX7@,zk_ ,N()_}PK_Baiij TcWR6kUII &X`8PeiiV7PS`i'/>xM<YfcV7kǮye3Ӳ@Pq 2d߾}2k6 ؿoe"sjnJ].-VK,BeKZ*D*+ʪ-̛7 \ .sN]OF6~!܊J*0"pJ%,f@TR[\5oc"+T/4y;w޽v,o^XX8ydmO3wS<mKdTPnE i߃.G=-)*&& H10F.ATs@}Yטzٸt.F??7Nk?zuuС{ڎ=6y v]GnE i_[o\jn}2Pߊ@s>0IEyVfݾUbhfRQ*Uf -uP>8='!sΝ8q#G pZ&$$=8n}&DZx7"apBAeQΊJDfFfA^1vOCw%ݺ#`H̻0ia+rױvuC+**B!e ˖-[xAg^jJZx1c znMQRr+Gߦ!!һZ C@Ms-\$Ҥky|iu=z1B۱opM08t8#y2X|ZR>B닋LXZui;°B";/wXxn^vb-t<==-[_~E۱.6lW\XKn =LjE̙3hРYf%&&j;"99yܹ1ccA5LjE!7o ƍ+/VJKK~mXuV,BPuʕ+mG^33[4hȑ h"|fzR, aDzmYW]{VF!(Ajj׵F}z}}}E#7i70`\.*=====]ѵjXYY)㼽80z1c9r#4nݺ)TL)%pvvNNNVt9rdFFƯs=tК5kƎZwS,EnݺUOOoҥ.G,YdÆ gϞ7okA),M6.[,77w۶mx'ɦNgϞ'[N B I˗/9v=D"ш#N:`իWe5djXl^@@utt]TTXXاO{ܹsɊ.!`xB~ӧO?x)22R?k۶mllc0]!BJ~"""lvΝ-[FQ+h޼ysǎiu]BNzuֱC Y|ynݲ]Q]׳gϙ3g7..]v!TW`BGCCѣ{{iVtQuMh޼yxxx``ɓ']BЄ ߿omm=vXwww|2=zԩSqČ7N! XjGDD:tZ  .Jʖ-[⒔iӦ[n)(P] !T= F4a„m۶Y[[oذ\u)FYYٺu,--W\9a„|#BSp;w޹saΜ9 -fVsvv{۵]BNÀmۆEEEYׯ+IIٕ5=mCBBZn-jDOR9[0`!j5,,,::m۶s522]W  Z3;)>-oɃ&Mdff6o<&vmZ0cfL5(ٝ!CN.J3E^r?Q 9-QѦ^%RFB_C/^5jԕ+Ww޶m2EYt%_նhngVsKKKۺu6m;vlĈqwöc=\O@HL-{oBf$Q/+2'k١ RPBEOWY̯Bλw޽{T*0a~>}>\W $APE/%fTIڃ!WM0fEEk׮&Z SjFVjJ ])4MyZ<1_P9zVMUyz:DBU$h BvAAAΝt֭ۀ飯ߠ%Ba%͒ۛ"%ދyC$ۺy[+E%ؾ1]* LȤRZP5lj -X2 Kh.S!i5vujz BH\]]]]]m'O;vl`ii٭[7777OOOsssV06ccSw),ąb)4nh3Nf3#%"iս &KWK~<";a1%yctzBgBԼy͛/[,...444<<رc{N:9995o޼e˖POaaa||ǏjxZf&pU<1޸ðI~]h!IT᳨L  5 @W>VcodT*%ʀdHɱK;qO}:w2t!.\(Joݺu}U5022jѢE-MMMMMM ē$J_~[@OOɶـ3v0*d:B-;SFvIzAfk,~ғWFF̒^ ~7/qYBW$Ħ1X@" &)p jjAQ$WOOOybA)㄄'O}$ICCCmmmUUU6b@"Ⲳʊׯ_S7xZQELmLK S)Mck qWEbC+[}6Q7/dn]v%^wh !en€R$ssssrr~)**JQbT"RWWWQQQSScU_&266622"R ]t+NlLI#3=zn»i " cccccVZMi7s|U 20ԅ%*(KfRJB ؁"b9(Џ_B! B!aB!3 X!Br !BH0`!B,B!9ÀB!$gB! B!aB!3 X!Br !BH0`!B,B!9ÀB!$gB! B!aB!3 X!Br !BH0`!B,B!9c*Ƴg~EW>g666Ȉ~yff&ϧiZ3Ahiiظ)"a+ Ϟ=ۤIuuuEׂ>TZZիs*9KKK;x`PP`jhh(z,''(6lؘ1c]BH10`-vRtCaaaފBӗ,Y$ɺt2uT;;;61HɓK.-_|ʕ#FXbNh!9X5,4MoܸԩS?sjjիW0]}'6pW^M6-88nxBp ]rEEO>g֭[RR҆ 5j袔ƍ>>111E(:t'OΜ9ӽ{wEy{{>}?PC YZZ6iD()"9X~}HH֭[1])ƍ/]i&Eׂ0`!/^xӧE>^ztҁ+nԩ}]xqzzkAXגfv|fZ\6gԴrGtqIx(L&s͊.:?:h跙_oݺ)Џ }e=z/-1KP)~wQA(y/^8qĴiLMM]K5h„ȸ|oMX] 8{^9}UШQS;v˗!T`B_Ez噈&I+,x<Ɇ~$ (JLW;4Yϟ5k8p@х ~ XNj[3}56ggn_ODQ7v:,C]1q8n'V8s[,Pgi[ZnLvm@^jucAWh$Hݱ-&<<8V3vF쇿o"((֥2ufaO ?\Te@5ےI*|&԰̈QaFW3͠fC $iW iD0z@|}jE4(ljN»p4qT8ڍ]->Rݻw uB,F|BUEiȮdPP?w$O)G~yꥂ')w6LF<(I2vce;O&Ѵ}.nZӣN곂J +S/_Wj5?y(~o.'J8jDqJz,S.ǷIi=<--z&[Vzd|&Q嗾C /"]6C z,]Avd"H]N]\H?\ݫO* Z:Y0bN53T@TXCO>/_ģ)1 XLob KKۂe6=,M'{◇myuRwo{$hqbv]tԞSZpY?3evQD8x&N6~EX*Z]=z IDATR](*wm>uJtt4taXyNbͿxaofK_AZá ;{&YLtY~R+|-d1iWzk̓'3d)%MZҒIKNi,ߡ _*B~Rtq81MhviPcEwz.QkWW҄)@Q3=ٵCnjm&MuIRl~t&]Mwd|a74ꢸ-2K<aff[8;;i# S6mee]gNd_sEK/}aʒCG=د{Gs>cO?`:ВRFL"Hc;l !1 XJh >-H.&uRd4:&ܪ #SC2bZ~)a@Fij! @W;_r9`޽[~ BN̰zLVE6,kaW YqwaZ]sq/0TN1%`0nX)1gZ<07L^Piͩ2?]U %& 555ܮގZiW -E߯<~q?uwLiu҇Zq2i /PdoOR XJqtdtɍ2@GٹORiNr4tמ2qjY2`6[F;7GAW\۹5FH8+o黸^ DoZ\@=p b1ѱ@jjHYbn=(|P%KE_KKs{icl= В2  @Kο$ ϟקֻr&M200HHH 5221cׯk,e]fY&BH0`)3e㚪й'G65\HBi _9%_lg=d6j2r o>l̰px#F/kodߛHw"F xʽq{WA ~_D~5ZtF.voǷ01lԻo[0Z1 .ie4Xשuc&A Nm٬ @K" h#Gw;wٽ{w˖-cccn}/~[ R#t|6svM4$r_nۘ W6MjG eWw>Erhz7]6%S<t+bSKG tịKEVcׇ.i#`qĐ!Cvءn:/]tٲe_>~ t齦WpWn2HɦNLYN&.tO>#hMĽ=Ԓ57Z紥S A[%zojm׵1[/8<+#caBCp<[{O3\Ǟ'drG|3>hڵk`ݺuP]vgΜ)//WUUz3c==m5 Uʹ.;oG:Y#w_S/;M woUf='ԟ@ط"v@ 8OIf.P50`!ybulEO}Z$I@M(***Z^XXH4AEQՌٴй8}ôrQe9"& pikL:> = P/!TGFF4=mڴ/[lѢE۶mmTʉx.S، >Z !j… Μ96]Z*55588|֬YU YMm-,ߑ;0SF$>ˇ;:ٗ;ۣfGtQcMiM#RUtMlz@_]ۗrutՈʈWIȩBJb/CBOO/44G999ڵ(****,,"$$slMo9 X.,kAbOOOybiȢBCC] PXXwTTk Æ {aRR AׯNNN&f3gPtin“RZxMo=}TUUu̙III/t =1)DQӄ4>Zlmm](8IMM-//{M:BuOKv$\nɆshamLլ&.LO|_&ci[;0`%*-Z곉jҲr9]$K ei957hSqɚv;Hv ""qƊE.jwP RϬs cՏF7[n@AY) ϯj[43U=|D /&N=\O@HL-{oBf$Q-)IWT"z _>f6Ւ8"Ty2SZli``peE"':N芌ljŚ-:yvhBf'T3r}\|gRbP]@S4A|QBP%in\|'ć$?+ajT_CM\MV)+)OUԘ' *YBZt\'$dG`0AM|$I?^ (q4Gʶ*OO#H(x|8.]"!R>>6l4i.'tEvu;7G㤰pƍ{vpp  "3sje\!x'T᳨޸̧ 6CTW]QrL&HR@*$>Z I#]M]s^EAa9 0=ټ>*W..._]q"'>.5vr4~b~… Buo>}l˝]B3,B{()++377p8.!w`!C$ώB OrG!3 X!Br !BH0`!Gr .! X5(þ\RcYQ] !,Puj0`!4ha]lUU8:MƕraF/VҥpUvf_3m#Mq Ͻ*x7$KYAe@s5_B)- X) ^SMݰkF Z^a:M=p$-tZ|b+N NL˅΋wY _;lI I_^<ªءw B!%7EHY֣wciIHRuy;:UN=zɀ$3m!KOx'L>gxkgR,u[pzw-ZPHGiwn[!p !%AlZp4ٙAX$N-&zlfժǨ7T,t jzz\y:!TaBHIPv 9ǚ11nIgՊ~CS?bC!pψ=y:~`֍uXKY)ppFօ#{kpC_B)3< !%jjkf/^YFUϙ?~ӦM]BhΜ9gϖdǎ_{QWWgX곬L*xx4^ĕNDOӑSm;uv #!tZ"D};/ &YqxAGѫګ'i '%oP5k;;9rd>}RBu,577 k6=,M7/wfiҹ{cM,by2ߐ:/h>hu]{VёcNo_waɡxBr|TB OrG歹=us;dGGݯ S545c)}JEhwޖs%4tמ[RΒӶsg Hf00/_ ,zuR?u4zӢF4㔥] æ1>eR, Xu˖-[:(,,[UKtz̷7%_9ks Wi%%`5j3VL"_ֶz _;R^(U5oE"1,rGHn+{뽻p_}5lĮzDPi:| +Mk `hKG tịKEVcׇ.tp 58m۶MLLa+V̛7֣TT4}. :όj: 4]HŰ?N F0Z./Q!75R1mc䬅b]h2?ki}:P] 58|3֭['Hj*п$IBV^WN[qܢ<hҲȸ|2 XJ+.ell|O֭Bo0}Lz!M}7ŠˠfrKWE$N!sPCAQTTTTnnn_|y}Ek0hdȊ9jP @矝3fg@V_T=K-r+T`2$MǁRTiYzT\Y~Ws Ї0` --'Oܹs999x1<-xNzy{ WiɤiGA|L]/.N=;a&=Vi]'z%I6x QF$-}qG5xxc$Qm<6"]HF3-[Ef̘.Qmo1cs}nL4T{a?@KʊKuY0ʲ"ޏ˴YI.#{ּT]A52aecuD KE#҂b$D=9cM,RڝoXN JF933sԨQWlUPԆ,Z_1&ʡ\ĩ~<ìR;񆦄 F SꪦUR4+!XD&DKhÃz98l5kko+/nӡkc4|C9{ڵTEtq6sϴ83LڮȊ_4kQp:UZmz{$DUVQ9<|}02{D>;I"i~}:h4ڹ9έ1BYw_|ffZYBN/ulL ?ϒ ]]q!(u&XC4~RǶSg'c@ujEvrBFD^Ыǒ;PKocz:t'U(%e76=Ce25rqq ޾}SLܬȝ9j8ɞaL]~XFvZ|lcujݘIЂcmm[6k0?BDfX]8J7i2pU>M2À$qg$i.ko^ }e,&♔4*A޼xM@WD] +bpqj=dI :U|66_Trτ߾BR .x"6C$$I??????3zAq? 1F y}g(Mt4y'I/߇jcΔO>ש׎OL!yiJFQ$W¹!1aK;jWPi^P~mXg O%@rhz7]6%S<t+bݹ|+fV"y*u\z/\ v\cdd'6)Ǐɩa:R{b3ͫ_b8ޖL\Zw:F]I"[ezzΟ͕?;nI{BVdgY0:o 틿g$Gm] }3&osl/ѧaRfdcDz&vu/aۀuz@}D?6jɒ7"Iӫ|.ϯdFN^PLP~ 3gҖ$Bѭ\gngcY e"GJtpEh{Ěl*'lâERAُL?pv̌bcϩ[ haRfɛkiyn/m{삭wVZ"*-itID"y O쳫  \WNH7- JR8לN踴f- <,J|<ťޢ?|AQI( ?Ђq&jB˟'׶?hnX"*j} Ru||}~ [Gƃv_oUwۑ\z&i~XycN}=bRO }ZJPo>oIJG-m_~Џ2:{JqEqZۧu4 Xʬ19%[z>/LL0ͷzU19*VL$KZi("MG^I ekg3hك+}ř̖'¿jk[]# T+.6@54?ٷ菇#1rRbd4Rk4/ }egr߆ f1st5 RadiT̲uP=1cj]z?/,.ct_Mwlc?߿,;[ !0`)3|GqP}/$Nv;%mzN<H>üx_^ai q{)肁.ytIH}%mX*:pqӨ a>;pW0:c~kW>fleA""4,f R~1}ۋQ7NKeг3~K*%S{^m ==Ls^,]MQb1mZ4-86i&=~_>Ȫ\nUԔtIÇ9' < $/+]fl̐)[_d}{R&xS5տ(N >ʧIúdB%x\{4Z ԰?>lk.n7W;*{MmmT]k3~2*I *j,`Z[Wnܲlg>abXUxKkaUVhǣ8j -֍f7.}TN3aް, '3Ys,#🛟R9?74h#IjyjDUoZ^ü,ep W8zW8.w+sogBśߩJatTy^{aWK-52:nٿWks-60|ףoyMMM'N-k֊ZMRwS i g(`2 z/N*^sxb;ZuT#C-HB}qȋ7bOwpd@/1Yͽ-~3/>럞yBs*-cbIIFԮ6Ep^nkG17H44l%5-7{sc 6, R(Bhw. \ Iť" O:+/?yg X<oG gB?+O3S>{RTZqm&A#\hQ2 _q!^cGGS 1G_vY0I;ӂgr4qjȑŃk9;R @c;#Tc*c[g6A& ̿#dc?\Taeۘ8^c- vM (nK!҇1OC}Kg{ּT;UUڐZM |~a81MhviPcEwz.QkA|nC;i .P ?fZٚpܧEv?kJ/j$vzkEtKhiY~ZRLăʪm \z+6M(PѦ^%So6ϤUE!3ʹx! x,@}s읻g˲wvx:Z (~~A=haz⣇d7u ,TЕ|~>WۢZ D /&N=\O@HL-{oBf$Q-)IWT"y$OTm[?{QN*zb~eX0J;QǫZp̢9LYZwr}UNSwq%4tG_K 9-i敥49EoyCdiF{o*;*m'?ZH]qkm.Gı }ԁŲ@:р+²< r {ffX]7DsZ*KiZ^4{ͲLmmdVRB ET@Q|~7gsyx6Uwք꬯Z#i7TZuhsV(0kXd8dÑyk@;pʉ"9^`Sz>gu  rl;T|CCCB& ,31q(Tjv#2]>珃g 9|QgZ+W*dJDcytӻͭUKMv.r+6J+u~8L#:LRqi=A{,v #mdm!BVs_erϵ9aF̢ZA8D߼p!RW,ǢfI~[<u׸938ek_ґ:4&\9˟X=mcڛ?=߳{,5{\ȐǿM wId5N.9c\ x@S;;`[^NMEk- p옕g[xn3D/nx볳"Er ptheꧯ~ُl|Oz989>:Z xZ'DL_ZZ%J9V,oߦ 5Ȕz߉=#"$]UEU&urDDT>TI @'wD"b#X*C+ -3荌RTǬĖpP}q#X'n Bs06bDZjq=dD߉kOU;cG#/N9nCt>˵|z)}o܉m^'rB֝ox.CGzmgsHc'f!*|ٶp][\u+v*DLDsTS ,Qڨ}wI\#+p>d3:K%I8jjԗ|{odSc&ZQC QuyuG8E/.=b8mc߿o5d|̠`mT'tqAs~ৄ};ɽZcdv-3ռ[% {O˟ n3!AczйC r&`q6v VsR]P\}*0[DN.NƜE啥y3L,$ [qinNI:'O-RJfkWR_rsXUF*A""t.nw,tTuDܑraGz k=13WzdHw CGkw✇^ZoʕK8#"2L`E1*+LDDJCc|Ug9;?ּĄ$-TVݳZe2s3u<cRe.–Lӕ(b>P(O=xi~NL:(Ճ|Lv{7IRq:x|I$WvsDv^=O>!wH]XǎdGhh[k8^WD$YS6l@_%Oj`e-޻HNmņ+FI8Mš7O;:ih q|~_y.7*o+na/~ cLS#e߯ޫ9iSצڍ۳ak }ï{]0l䠵K>000yg Ԧep&~3ezXosm ZKsT4CQllܼy=7www3Aߛ55u!7鮝ڻLѡCL:φSŧ 1s_$ *KZ\L(Sv^1ViLD8n1{."#|ҧNJL~1OTk[L;HS ]5^p|wXd8d m]oims_gMɐa9;AW]g%c^򔋥NA#=g'_CBG5mޠ]]]NzzlL= j)1FD*a>|gϞ3ל[l17ZZIDAT=z \`ӦM/7'hԗ|,Jk7С𦭬>ӦM_\ԅ7[{(˅J?6Yrx_=-GmРA֭MQ|LXԓv.–o۷󡤤\O Ϡ&SYC j1cƮltQj>銌gWX0|3?xͺaޏ/]@Ǩ|}o{MZx_{gEq+voy :X`f~kVm*9˲,\pժU-//8\kl hN,Mn݈\s Dd2̸Ɩnݺ4u!< `Y;;v̼sVE2NNNf_/@ dPg]x[yi-r'VaS?_^=ǯsko]a?*^H={\~*" '47f{H_|1ظsŌHdog;)nfކ#nTI @'@$9b,UWLדW:U9TRUZcVbl=%4hЅ ^F(>b,#lBӖ |"2[9 LhB4WOJ"5r62يR"Gz Ucƿ̠7L|[PŤ3[w=mⓒ<Ajɬ}|| K(ؘD5V*Da+>Sʩ8O-R4;'řB!h)#bUU\.B4LXxMȶUb|+&Ds82E"_ a _,F]C*NO3!^rΫ2vAލ<$,:X-@ɷC`Ӱ ʶIhiKZ?TфhN ESQC j!Xca>"ylX:'ٜm+ -[7=cƊ"aFXK]BǬ>vc+8vRK ~Yi;[u<]VRTn{˽U,?]"ke!w\ݹ;OyT֪gFKԥ"agߚ^*xg&}9=I&{EN2B:(<[F&-Ee! ⒢Ě+_)O]7*у_;8w^ld??IDdՐayS?œ>N #…DĿ(b[^//^_c{ZKN.9/%NټԔsO%Z3&ӷ>Y:gW9x!WsLv'3bdgWG\(mҤIR;UUW˂e!n_JFu)?0wwVqb ߹{-iT_Ds!a3r"ktέ!]DZ1+L }Ҍ{Huvڞi} DoI5޸}E C$ikk3q糣D4\zg0ĵ'TrN#z͑×w-ȑ# hCS7 `Y 6!!μĿ3^v  "UtCw"OHA਩Q_)qO 8kA[YɅy&Q%DDX*&`P\}9O,rL1/E"$_.j*Md=XAAA߾} x(M]BClU4XFFG]}PfǞ˦팍nwWki|k ۧ8){```qqqS%00_h,UiDB2\8t4l}\\c uȔ{0Q7G@x2GD5x9+ڿŪK }ͣ}? MLH TV5|ȺDܑra W`… .l*, a1S$I߬:ej3hP笞045R:v\IXƻ)sG jOWmqՎįv,wZMr. .f aAk|Pyϟnfs0o+]poEֿ;/z[{+W̠vB                                             LPdJt4cɝ:uU3> stream xZKoϯa[~ X!6oĈR2%N|կ̒K %J= JpBaIF>7}ъ +v&eu3Ig|4⃧~,Oao.:i VZWo\c5$p\Y5wob+ unCu~ffsoe|OIO~k6_z6?[[s{]")˞IHL .Pw\{V?bH0o+1[I&c6-[J?en?[+(PjndyIȢ";BAsL"SLޟ0)7f7!DW"y\xM$uқRNi' Rj%A!0^!S>')Wr@"<*8 *ݍ'UCpv'}h#5RHJ`r~/*VFt X_a#*; TX& ZR'UMqSR=D2<銍)Ge,.QKFrl*oFDn-_o}jK*۱q4;湥{F3H1$Jeگr n9@w0L1%: E9YdGrE1 g@NKq,b`j/$4_p{eR.pǺFA%Zɚ>ܭM;ǽQ U3dpP戃,(*g,yr;ʑ8iDXHCMRiGD2B}M`|QL*7Gj8ٖH~hgQ)[QLH͕sP,W ,DlQ*j[%a"|ͱCW|-&U$e毒En&<͜RY*TaA#LB#GIW 22S3C3 9uTQtdhKJC(iM>6K_X;A{'Z/=X=T,ZBNsI {"Jq)%⡕0M0$:.Қqt>N02v# W wW1,x*Ǧ$KoҊnsw ):ߑ c8ROTKV/Q`DF$7FvNyƶ*&D2Pn'#\0f|OIo~irun'KrܔЧࡏ΄)YJߠ[ W;k'hrIg-w1δq^r4 3G՛^֭d}irc*ًoF鱿Qa}-Mt+]vz*+*>ʒN 10V7z(F^xtbfPr|DĘHXLNiӮru;$,*ICV*Ϩ*DzlznV$Q?0xP endstream endobj 5 0 obj 2483 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-1-0 7 0 R /f-1-1 8 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 9 0 obj << /Length 10 0 R /Filter /FlateDecode /Length1 4540 >> stream xX_W739lH+E녥H-V@AA D(>PuֻjZqǪ녥Vī Z+%(0~Scw|HbGJ'd%nDBhlrZ}%|ǧL#K J.k!.jNIUxK>H@q_O QJr=^{$JGq"]1*NN I(@=;XP%[h' N-.4Gq6YML тVWjxZae)Р.:VJI R [IBɍ@q3_ܗd.&Qm I4!> ^GL&b phnnƀ`)&k+k5$aYyR+}a&[>Jc ]נ g3 ҌH:kkZQOm3JZLFdN4J24j7wu"a9wǏInr8*X>8d7=tyQv_XY'%Id*&R-NEr76;ϙwd}Rqvl WmM_S@k-†I*?lX-Y>xw&^S O45A_4&QXF˒EKb u܃=M+3b+W<)V~:;nR 4!Eì3O~z:+XʛWѣ2F#7gp^| y[&..xwX;n|sn,*a#=}>*XXV^dѳh[d}1,|Qߏ66ft:+ڢ bٲ!p{6?"ųYMHVuJ 5^wH?pZ0jg;PۄB(>![)>Odb_1^IfPhD@$\q֝K=":0MWΤ OͅiۖX1DܼY X꽂rvI񱥖 #^ea/jW*G_>G3g=[˙{C%6:nDžW*c6b,x&Z L,EssM?n,`硼S53bĩY{Fӿ˪)>7wo vZ(uPom\ʵ cdrk4p"2enXe-[&^ʘƾ*_Hϒe.cM0p>!¾83ݸ߰6cHmܨx^ܞ5n mOO=eFlj$G}z ^n\={/^EP*|Gsz:$x]$4rG-Ozm~:%)jk W7g.|;&"PNDup#bQV4zv'Sk19hhk15p٧֊t#0Nfg6ycV[Y:Kl.M(X aDY@qz0TOd5osxsK9Y|7 d}Kz?" q,?(ٜJ>PoPpvl'n4͌cR5/f۰VDY΍UPȣ @wfk}<4k_~sη8ԉs:f\ϫGN,p`buQ`3|#ڔF@ȩPj;",b,MR_!uX U\+x;Y*X){#Wi$= Lf6x&@̂bZN ^~^f]ZzW~ѐ-U4x*铣-e.>\!Ij>NM/=- g<^GFxK,t/yH0B2Ʉ=2s# !e#E!OMێD}Eh$:zVM9Ff䗐hEE1 i4a !a?)~wӳXs #@6!aVGA {(V!Rvb>Gev@wKHج{=Kq:tDyNHvEF5 >P_Ĥn endstream endobj 10 0 obj 3271 endobj 11 0 obj << /Length 12 0 R /Filter /FlateDecode >> stream x]Sn0 +t ;+`^r6 Ktj 9W]`ƣ!9vfeG4T\Kd;if4V m~VnkZFb͏dAgΛm~oO5ݷ~g?Rc }[v$!r fh۽io8{8PUi Iq=*QxWף/_O`f$3g[x ;OIq=ЃG,I,'=^K]B_$}^;Cs Cxp8x~Ixzs?*a̜4'jCe-d?-^KK;&5g*Q endstream endobj 12 0 obj 414 endobj 13 0 obj << /Type /FontDescriptor /FontName /ONBIPM+Roboto-Medium /FontFamily (Roboto Medium) /Flags 32 /FontBBox [ -907 -270 2051 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 9 0 R >> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /ONBIPM+Roboto-Medium /FirstChar 32 /LastChar 187 /FontDescriptor 13 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 279 0 568 568 568 568 568 568 568 568 568 568 0 0 0 559 0 0 0 0 0 652 653 0 0 0 0 0 0 0 0 0 0 0 0 0 624 0 0 0 0 0 0 0 0 0 0 0 0 0 0 541 0 523 564 536 354 566 555 255 0 521 255 870 556 569 562 0 351 516 333 555 0 743 503 0 503 335 0 335 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 485 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 485 ] /ToUnicode 11 0 R >> endobj 14 0 obj << /Length 15 0 R /Filter /FlateDecode /Length1 3156 >> stream xWyPWPf`z@C8"s@(1D0PԀgQ$hn-b#FU)_$U[mO}t}{!@ђ(BIy;w =!tv²WʀU{}l}Ihlg畔.,䰝킅lvIDA$!6ld½-h'&>X r` IAU@ZWc}BmwTG4BR9$⧓s8% dvf, F&:&a>2/(뀴glqZa _,; SAxGP͚4cNF"YB4 nsXv>D/* O_Qk]^)kz$?dY"CRWmts)i81519z"n0rYB,*&I6d*dcN׍?_H-};__ߙ0,hvO՛$*1$q/%[~n,սKMQ lIH<1*9fO1z  b!!0_QT9Jv]-`xTN8@:;?'ҹKz+"ݎ2_aU(c 6Z$#GbY ɟ9͜)ˑ|D{Q߅ZM[VWhǪi1B=q ;’;n,Hr}ǚ֧[kkkgKvF 6Ð{g;0&V􋪁 5`k*Ccf%=WU-pe$,F{`(]ݺW~ dK͙vnjoZf4#gL7v.bGc F$Já$H!Xp&* VsQGIv]~&OAwe[jWQFLHNF97DW HZ>u6X#}t o{ﲣ̕VXh0\c-0Yɖ N_ٝUUۋJ~T5sKIHv>ZZBmu|2ON7 S-v5 *)'lm͞= =2G l/(ߟ>+>}9Z8{]?DX7^.lUkJ2e|U[ǁ$R ĚY -M5nሕ);5#$6΃X9$#Gpɏ3r#}pK,d(S}*E^OY%N94ϥ{w9ۗ͘[&ܱ0@oD]:_D.d;V~gqɱ<5..%%..uStjjTl(_'ބ>g }0+Y@ZC#Jf\] Ǘĸ U_.w~p7BԞ?^ DeԿ5!?T%1?r)M#.o4gl'N߹-mCu}G1 7 znI[dKI8>3I m'P Тr2DǗr+I>m"u$Z/WՠVC4"{dy?{hhdhH짛txh! y/ 19v\1~kKЏC?@]uyjOB \ٷ endstream endobj 15 0 obj 2189 endobj 16 0 obj << /Length 17 0 R /Filter /FlateDecode >> stream x]n E|,E V%RnCuRv2LJ];8ϽW(l\F\k4g^T5ѬYIQa[VzfѶP|e|[Gip '+Kv/: ަq)O:+>-.A_PeA\'k┳3:V$-4$6̆b7iG#ijԉk9 #Gr\qܐ=ĬoH__R!VG9fGQtH{qj{q (55Y [\cLm&:5z0/?# endstream endobj 17 0 obj 343 endobj 18 0 obj << /Type /FontDescriptor /FontName /CXGYJF+Roboto-Bold /FontFamily (Roboto) /Flags 32 /FontBBox [ -913 -270 2060 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 14 0 R >> endobj 7 0 obj << /Type /Font /Subtype /TrueType /BaseFont /CXGYJF+Roboto-Bold /FirstChar 32 /LastChar 121 /FontDescriptor 18 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 388 0 0 0 573 573 573 573 573 573 573 0 0 282 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 536 0 521 0 540 358 0 0 265 0 0 265 865 560 565 562 564 365 514 337 560 0 0 0 502 ] /ToUnicode 16 0 R >> endobj 19 0 obj << /Length 20 0 R /Filter /FlateDecode /Length1 424 >> stream xc`d```cp``bPHϩLe;P$d&06/e``2sf@JFnIGC%_s''@&c M(`Pc;|Vf @;9x9YSQ F'LnZwS߸5<*11-& Ih8"Pi.u?t^Y}髌cN39ŻRe7>bR++m2Hr0@8^(Ha`cY5Pq`baHar7b3/10] endstream endobj 20 0 obj 367 endobj 21 0 obj << /Length 22 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> endobj 24 0 obj << /Type /Font /Subtype /CIDFontType2 /BaseFont /AZETLJ+Roboto-Bold /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 23 0 R /W [0 [ 443 608 ]] >> endobj 8 0 obj << /Type /Font /Subtype /Type0 /BaseFont /AZETLJ+Roboto-Bold /Encoding /Identity-H /DescendantFonts [ 24 0 R] /ToUnicode 21 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 25 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154042+02'00) >> endobj 26 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 27 0000000000 65535 f 0000012696 00000 n 0000002745 00000 n 0000002598 00000 n 0000000015 00000 n 0000002575 00000 n 0000007144 00000 n 0000010776 00000 n 0000012535 00000 n 0000002963 00000 n 0000006329 00000 n 0000006353 00000 n 0000006846 00000 n 0000006869 00000 n 0000007755 00000 n 0000010040 00000 n 0000010064 00000 n 0000010486 00000 n 0000010509 00000 n 0000011223 00000 n 0000011685 00000 n 0000011708 00000 n 0000012010 00000 n 0000012033 00000 n 0000012299 00000 n 0000012761 00000 n 0000012878 00000 n trailer << /Size 27 /Root 26 0 R /Info 25 0 R >> startxref 12931 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0004_Relationships.png000066400000000000000000001702221415120503000305740ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxwXGwpQ& XOcXc5l+D {좂bDѮ|"xݝ}o{!B!C B}kX͘1#::Z BjM4 w=Xј`wUw!7t6zWڤIW'" 80..hB"?%!ehʣ H3&No)wXeB!YH^RTұe~;ܦmtfYDxخcSSY1H r)f=}#cYz8qJ<Ӗ>N"}=:,*Iɜ8]zjAQEQ &G`Ҩmwr+1/>'!ygۈlǟɫ#q<8lyw5|"BUH$B##e#'3aMoR""8fMΡ+Ut4껟Jr$e_.BE[cZRw'wUgPluC+!ډB!&(:.xqadw09<к( 1!|LWKdf+˗THѳ/fFo)"tYC Sqg3]_y4ylOz36"6M8B!\,.HޔrέY1W"5hHT GRTDSIXLP*D'O߾Wd]_=1q>Sٛs+S]р7p45/k[rN&0z Wq!ȗ< w)C33H0ja'(ӧO(^'%;ZJ X 2RƅFe/ӲhJ@&~6錶GJ0"'v;imk[<9wad}ӛ)^Gy?8Fn^5ץ31mB6Es^KLhs~لշ@^oII̺fJ=6C~(|4! @x5x]':? B!T5M>BJn|H&]zleC=7?B~g{"=Ki;Nrňhˁzfi FN:%ow6$[)L1;Olnσ"d^Sڲa@p_СAV߀(B!TWPl/+!&z$!-@Gu0aF@bSʥ yBF"iyF];| [꣯$u|h2͌G _(|S,y!tl7yL.[v?&EJ%XCc {~],Ӡ'pdĤw.Ǟy=6:I.cSD&Vc`{ٻ}.#o$"q'(@` LUİpwǸ8%յ D!B1(ɻ 8&Nqa|]7yzLu(гq}5gj%h.\.%MQ@NXvC/U_jڶzypRZofXPj~mHן=M?amA{>6ԻCP,u;swW؁&U~V* PTYs,B($սS}UO bvI1CUKTYϽS=g]:?f՚B/>Kwt2aȓ;jݺuqV•F\ /d{8Wc{+}vLɜ4ʠw;4F@ MTj5v+'$9!L]vWvr.sEd%Մ@`cgEVD!"{C*TCΆv2 []g#.X7eͼ&ta j9`ވ1kZ:mؐ|e, w*\AoMIB^.@RxfOCc\Mˀz^fHPzg/ǵN:xWL:R{E˽ƶE>m1nx{m2+366v!B,]+WpM>{CmUɠe3l^ʹtvF9'W̙ =?ro0쓿-thԘV<:Y/$ p2IYLGO#ܺ`Ϊ/#gV tdNMْ`5z˼?jUF6mtm\XuGVv|aI]]zuÆ SG!PBT'g7䵭fL5m]!B_Al [0B!>Le]!BjIp,uG1̮B!uy`^tIbŊk׮ٳgС!['X111;vTc(z1L̮B!x`[NehhؤIסG!{`uA B}.BBj B!P5 !BaB!T0B!f`!BU3LB!&X!B ,Bj B!P5 !BaB!T0B!f`!BU3LB!&X!B ,Bj B!P5 !BaB!T0B!f`!BU3LB!&X!B ,Bj B!P5 !BaB!T0B!f`!BU3Leg~n L]{;TV{)~%U<2ymKzf BE!%`}o.Etx‹[IB!TXՔ[w<$-ofCLrɵԿI;3B!o~_+GWEPT}cp/k=>O`kËԳu7x6\U*Z_ B!T`7KǵT׷( ;r9e7m庯I6aɿNܼj@7;yqk}}% m?G:6xcȠ~Z5BuP```ll},,,E݅ V@5aN;|.x'_:OpbE{&҈ <-F Sb$7dnޫ=jsԩW(;ڤqƘ`&Xщ2c3;&N-kWz` b n|5:522RQ&={LMMUwu4|'&swK[ += nUz؟#{݌s}I!7oYQ#jU謤 QyCcd˰DVc7N($%,bОVJQoh`՝l,g#pE2MFEv{*cE{̖]>4A9 6s6;~ :w n^ޘq;9ҨZ9dP;lډ7e ?xI̴z|ߖ (D, ɴV=0i:`CM׽;fAfbBn!W^Uo4!GTq{ESB!f`!BU3LB}3|~V~oe;SQSKy@zi͏\E|._?zs%߳waɉjBU?y/(;,* R8*d>">]̦)&_|zwY`/!2hv=wpI>F>Ky:ERԑ{{4iON+4j켼1;(e?fpn`!'O\hȑ#tCݺu3fŋ/_Le,Bj&q~VvF\y>(,c/}{.n<OϪɒ+3r͕t6ISm-..ɉT*͚5;v옙zcFHş: Xں|izu>Q fQz7Yn~]Էi҄4GfI}6rrsSNeљLR~[]GUWމ8υEσߐ?d&9hР3gDB"a!Q2B k0<vDvc}AL"f[XIQN yԳ#EoGMP4%`H6M R}/A Fgj:}W_7eCYsagncJ:e$3U,zT#N;~gwg``pĉB_U`l?zC[~'{v@3 @߸ոSUո]vnzvq˼1[ٙZ?M +(SܹsΝBS#Ź.zWư0IZcmiǬW]@ V٪Ub<==#""j.$ JW_Ĥz!┸S ?^+. 4O.a[lbSVN`IҮ1feś*Mp7>S[doŔ}d ;ئ1i_ ULꮢ\++*eeeZ3!PUQ|)9|SNУ]nL ho$^}Ԝ͇?`SB{}F̀JHQ??r#>l/e_˥!27RIU:,;;Fi64g}9ey0ҋPQMbQ$Q.vCerMߑya ]bYtՌ,S"d ]R<=8Xwñ=>Y ~\AS}C#}w=V2DgMkǫB_&XuWff&ԯ_JG@FFFĄBUEwx-b[O!FY}?״ ;%Slţ9Wpɼsܭ,_M 6Ums5%R[QΟ_ԴRi%Yy%$M-Jq>gz7ʭR+!W^Uo4k:w\.]===+ѣGgg皋 !ٳgjjjddMEl {.T $cB!T&\R%I\n:WZx;skɒ%P^%Kd!P V%H ܹsvQ!B] XJ%}?*tww5jTGHޙ6"gp0(7lذl, PUgpX72p۱R@Zyر9h oo vK\B6R%XUl2]]]r+W4"}ͅ<簍9{YyS^O<2nh؂ l<}_مq FC}ZqTFZ?ZR^U$,\KǟyqB V]W,WM߿eqk}}]!m/Y4џz?H}`YAV 6zNSZ5`B&ELڽoz36k3Q?/6=9)No[3Ή <*9G'wRn?;̢$ )">t?;<ݻa==~/hI*Vc'`e>rB*0 ;6*,nѢj&VD+J>WJcmCc٠*F[5܃`T!j j5kּxBQhw/s=$eFLElZ\ͨCcdr~fǂKC[ W qn/]bWa䄬[zNY}dPVըXuGY,,,z,rС87 XܵkW I^cyXnzHk[N|{wimv0t=[+@e U7Ц$[g/cCV.lߙ$rE滑;{V?(x9vbѾ^.BԩSP(Tw qƘ`iL4NΝO<(4C(:'8H2ms2LظoPS65iL-[Q X#򻢸/{L;{c[ cZ,E thGZu2\ BSSX9(H\zU sssL ReөOK8Dt6Bi 3R`BHްaCcff֧O;w;(&X!ʕ+Nrvv&ݾ}UV{Qwhw`!RXї~v1~[v~aV{V>5`AAAJ\q\---uPV\\,˃@%%%_TT~䞟شOVk$ IDAT^!Bi0L6___[[۵k6h@ݱܼQXEw)w[T$IUU{^(AzJ'XRqV~ a35f~yƍ򥗗… 7nlii/ B!QwV˖-OLL444sqqٳgR477܇|)/2e=&X_!$((̙3~~~sxcѐy1Ap#)aF_k-R%9T5i`|0g]NU@>{MN籃5ϲvԩS}A`۷.߰aCFFƀg}"hrcLj MK/^lggw޷-C[isyMz:Hm8<= 'KV%= 5W$=71úLw};H9qlRSKj?\ވm @fj{XR -vl0KBOnܝ` ԯ^5ӧkii]r+ٳ>}\v Ǎ7{l__nݺUTOޚvkB!m۶m۶%Z䄅9rdÆ sΝ5kָq >z z:τν0ŁCP,mKQz}( Kp;xEKСb6mfobY?GRx'GE1v:}gʥ̻YL*{{wlnC06;Glхq)JB$x͢("LSj܌0綼‹x֋GQlEQwCBBYF1 miz͚5rg͚%HT;ݽ!ԉ tV#o~vjce9Φ0-[444lݺgΜnݺ;w|snnnLĻ(w(JM9=֖Egr0Inw6W]{'<Q<>|Cc$WO ?^#EEޣ ,L^b҃_k"rr0edN9ieoŜѸ蒰-- ?jԸ@)(5kVzzzxx޽{CBB222֬Yr+sx]h*o-9d4j1 y a}_wS::o'̿=S2 {MlYIddޑ7C[[ӳՁr|o(5SWx`Uͮ]qƙ3g](W޽͛Ns"c#_q ǷWmSo<VXz#ո]&|y7o3zC*TJ J25ΰ2)s333ߴ*wn7f MO8KJJRO %zyk&i=A|cپ}WXQAvqSN]/bR@eVqJJ*W])i2q\}-{v61q]+'w$i3jsMDi {Rs2}>]a1%DnY緷^޼-JܦcyVjD/_Ca_~]^!T7Ntqfgffff+ ~#P!:C}<{KŧVu%;eږ̰O*:zwis'[)Rrxܰ==ݛ]j7u+P)K'AMH$2У9-l"8EY*\mt( 0%S A/R vdT%%4i}UniJ+W aU$KϽEմ=z\R*~nod:λ+{B. eakR4= yZH~{ⅅE;tرwcGpHF0#SuqiÜKFQMbQ$Q.vCerMߑya ]bYtՌ,S^,l芅mDNY%JQnX@f& ǎsvv7o^aaYwcWX[@hb޼yǎTGۗemjR999.Q7^:xpKk]A(Rtx+Yȅr{GN!scmMK,zv]~IBH1!:+lV"WĵO _O3+lbhlZƓʹ*#t.|"BrϯW>i$''gڴi,K__? @.bXvm ]Uuj~!֭[[hq֭қJ_t1lذLU9.\KCΦ4.Bf/+NkxAw,ؼlNk[ޮL}`Y7 Nu?UI/Y͋[,n%ėo871DFsP*DP(n/'Mn NLLd2U=:y</]P(522333!dff&&&fdd₂X\\\\zDQGTaagn޼iiiyȑOc0Ç?tPDDġCΜ9s%ww1}1MOb?f@_~_brHRps<@yڎ=-ݓ7?FLl1lȝ{ !s8'^WIU͏D|''!Cή՘FQկZϽ&4QIΝN_$H=zhӦMgΜyGUѷT*ivߗ344|aEci`ˡ\"2dĤw.Ǟy=6:1AulfA:2y*S,]AL~=}P9::޼y388ϯe˖k׮}ҥK8jF݊+MV_zرݻwϜ9sE!FۢEx<^ΝgGG BP(*fNNŋ#G,Zhʔ)G.cbb?njj}Dz`;Jw>}02R&Bn9߯`0ʪܿ*/ZԩSNNNG~UWD5j߾ 82cƌ 6̛7ώaÆ  2SNر^%7n۬Y3fO2lƍNNN/^022JHH7n@7I8<.E hYqKQ]ͨۡ12eXhR}}'z~VMC{[*FVw~a²3 ttt>} .ZZZ]tYxGN`eW lذaʔ)֭ T__~봓ӹs炂$IΝgGG3ftر]vx?/]jg%u{S>XbZ6q3 if]qݦU~[im 4o],,=k8VcnX;gyisP͑,]=TeJHqz\d|jRGE% wTt1RHKAWwS ܧdMuæX[[jC$yy_ȉ]?̤鱑OVMOG?={F,=} rb&4|03!S+w~zTFVZFgy &P(SY'4J^DMVX4PRaU'8鑂Q Yr-_Fxe#Jb510@>aDNRo"_B>_BŴPbh?UXi1 j^A`4PKT}el}wMN#rSvEtYzBBйuܝ\:+JDP|9%7S*b1) J(?_\>2څER+ |^X,#\ T+}\K5ǖT* X萤bMwk]&MNK|sh ybʰ@"".%jMbs)WRWBL,S_xf( ףR=-_ }SJS=q~T\ALiԃ/귰cS0̛xd&oRLg?q/U³lޮϣJKD@VBAP(bQϗ tSs5I[ g4&-0BEORJR"!ޛ,&Jf2͌E0!QSI%%x_wNB!_WBM;I tIBZz\)a1L'?\Uѓ|qL36*UD!g$=zݠKJ$|SWZJ(JaP} NUfSI&>2ttKO*T2>YTBAYM%_7c)YxOWt\Hˇr"/T9xZd)C^%D\d@BD]O_G[x_FƧkįvq=XHԽM+R)efDHm`Jx_FcZjr\'WuǀBT}\GfpQqJ 5 &X!Pըloa(ѣh(l B!T5jMQܰ4#GbR4ނQ08qqqӦMSw"55\Q 4NjjZJ8#M"8cD~> ^glRx"ak\# %ys~/&G[dhp6Pfe!Q2xCǙ-{D,-qzx FK>{lDu,@P$J,ܒcib`kL4KHHC@!MwuƱwҐ[_>|$5[5&X!P-بB"BU3LB!"tgDꎢN !Fӄ{k#KKKuPaBHi=՜H,B())iӦMFFA,BXfMllED`!BUŋUVܹ3**J B!Teg&O2[`!BU~ȑٳg7nxɒ%7o RwPH`BUMӧO733iӦf*..VwhH`BUݻ޽fmmm`07nLMM]vCC,B .\5pw^^^ XreJJcCE!*kٲe/_dX͚5+]WRRr)S+6Q0B!*8==en?~W i,LBJڷo@B!f`!Hޙ6"g*X.1/>#P] Bb MZYT4Iޞ|`1AۅsBRd !0E,ju}fB.GĥOeL^ےv7OcP7w$?bXo}>OhREz׾BOsRz'w0mF|2Xj#|4_ܳ9^@iґ> E|-c糬_Wzgm{H_xeoh9Ֆ¸#NIH᡾|KNS_ҥKYYYi"LM룓;)ip۟Y >^ Hej͆ 6lذ~~+jЮj}e^@YoG~0F7}$+P<9c>|=I9oh9ɤ7cS6sb9)ÆHJJرcxxABi۶m۶m BW^-[˝7ogygqB$Rbx ^BVJc;sX,r /Mk\)6͒X M='xG /8qa>MQ|e|ԃMihR| _ָ.4K&%"+i9횬rEO6h|B)wx#j|$Bl^WVDDD')Pmj<`l@l/{wD$<0L`XcyL.[x&Eu "̎ y˃t߿^Cc {~],Ӡ'm4;xy{]-JG//&(G``xϣ -S!}I^j~pJ Z:9xX+Z$@J%P\E'wz5bA4JܓO S IDATc?'2hg?}ْy(;{Y/bh.aOfW.)+JUzm9B)&9!L]vWvr,DV"y3ƭ,ؙ::0IO[nݺuB[+ɹ%ElڳߊR~W ^?Jy7Ҙu\[/5ǃ~g/%Rr. XQp'4J @$%wI^H!j+!>{M;{V?(x9vb^ @;yhl[^_ㆷbkM_3ŠXsdWcִ3cǢu#C^ r:6ga86d_Y=?-J+W*X1jIxw̐?˦ӏߗ}fer_Uy9bśSnŎ>X[q^弡U[7Ц$[g/y`9ՖNBUҧӲB*8ɝٳ{Y|;qFiT8\ï6pí<ByYgd\/Lu8-s'DmDetɭy ˛|Æ@Ag/%|ZʹHOik%\MbZWHZ~!7j 8jocpHP~ՖN$w>R: ridUOƒ>K~,83ڄʿ X,x"^EBꠌr”[e괚ǖYnVj@ С@ ,Z#W'-ܱ`>׼鐵bʿZ`PǴ.(Pe0yqyf˿Z2 !B ,Bj B!P5Ӕ9Xb@QhLMMBrܾ}Hݱ ) ֊+V\(4ÑJ!P:vxĉ={;q4%; pر˗/; BG`1cǪ; LB '#BU3LB!&X!B ,BjABZŋnnni"LBB tAQ Uk3;BҰ !鲲ϟ(4Θ1cZh(Be !wءFP*m۶ ! bl^:-(v5䣡M}{"'n>z%固o z۲׶i4;\uӣ)=ت\DįL*iӦC; lgg(B s zgo/O ^gvEaK]X233ťHq 9کb+BՔڐ`QݻVLRe{ver]GUWމ8υEσߐ1G"WO]'%7N]Ȧ)NA1B!e .]@& 01iL"#Ntf[X(rr@A@Wo:x^}kF!ђ:v@&]C@  {v@3 @߸ոSV@vYA^ plǢvj\iR yl[8TR ˴,[ZHIo^2Wv?QR:26*Ea4 M`ԮoAE< {9:BSE 9 :s[uov :ֲֺB΄$9+HtԜaK3K}Ϙf>=~O~2K L^'/?TJ;v^]:K~ u Pot1 U/X`!}ST`,*P- -%Ïk" #]M6nbâH 6~YAJ*N2۽.&v2OT0 ,^)zCX FV^+xDr73u<{.O&v<-xFrH[a3 gi7K4+r$ S凁Iյ[yK>UV|  ΓZz-{%XpdoM!39brlGo55Q0[g(*DKqkE[KyiE_᫇5#svv_C<:6j0FzGq}a:Mrӭ}:ٟ>l>ڰAC%RGX YmÏN/N ~F;hc(׬3KF*$#tLY ݴeA><I|6tmWjr5Vee-P- d!Z< }V+0^n[&3%Uf fG-ƍ'Ylor(ǦRԖs\`5~u9hlWqzd޽zpu}$<}AQLJ:Fl=0˓CwP(NgT)gܐieyelE26^Gmz;]O._ [S>+ꏭRg؀w_Zw{[M;2⇆W9mCR$ΎIx\C GA/6%-؍/k-9M/g?#4>,J\.˥;9A/j4\~]?|FCVn8&yxʁ{f|Ѩdm;ۓz]`1ꎽ Dj-Ľe(U;t/E(JRS6?pמPE h?pwʛD_mY^߶ub=sFyP(}l(Ev8K~|+vhɸ4ϐNkF߭Wmbrbjâ)}}T*a֚2ut4T&)*!IM֭[nbDYPP_;+qIօ_Ǝ[e[gLYQ9Q*\;|(.BV)ĭWRݶ%deg'nҾ>7d'r'Ȗnե#O- pqܺX]ѪQo:5i7pٳ{~t+Mބ_z9WNJ˒Qpןe `Zv\{wOt""RT(ҝ}9o~ˆo˗N6tkr/>8t5is7v= 9V[vn_RB3ō+7ySJY:; b6KS: K^Ǫ0b899d_$]6ٛ7{ƫ Jtw$zU~vzI]ku0?+K:y3Ug~oqѧU0Jy #F`)bO$έGoaݤi]s@{>dj4>]jvv6^Y^BӾK"{9qSԴ.W+(d\0ji#nLA?o^' N;x 6qB&M 8ZvځEX;[[ .Bx 9 yQ u!#,eqI?V&//6lGWU6HȦ8iȿ4ۗO[9.z~*77ɓ'tAHak߾=8q z2םMمP6@Of?+~I4 b3_<_~֭ׯ_/?u t``gjnjK?ĥ &bu5OyewC.~*)V6c3_ Vm#Ol`fjabsK~ ZzjGG-ZН~ t;LJӵkPi5z;.sfܕte˖;/j$`]}Z Tr=pڟ )yV$Zz3K#7Nnܼ׼CB:SPOsz=lDD0˙3VR9bĈ˗3z~'!!9s&UFߺ|RhhW}͛7BwBټy3ŒH$ .~zA޵@BB޽ +V(jѢE_/::=Jw/WSz6%e=rCwZk֨_D,ۉ;g~-ͺI_ҋ|>ex6I鋶Ǿc68t޲I,Yoeޝ PjNRάhǙ;2w+u50Ӂ!ߎ:rvw?kxm~v3ƒ[r\0g+B&/\1 $Z}ͬzOV [,?&ogZ֒_|}_46$C~|l|N=P˧:7XN,&K`r/2Fp9mi ޳7tb__Y9-j_􃗗שS222.^OJ$)Ą.!!'LryxYYYݘd BV[XX`0D"L&eΌ^z׽qysqRRҟ)J5$&&ٕ^J_ԢE74|9ߞ<ЖKǝ" vU˛XӣT2ɖ ZD&o+-!؟;89QRxll}_ݒKâ ~}b=uPW.[K U]ߋ)`G^LD=e)縲&?,vu[!U1Ы[5" zoVGyyy?>{MtxEehcom(P0뻻 )kLH#ٹ<Xņtڭj]rYA 7ײjDߎ-2. (!Зbhhhhh(H@ա-hʍ\ПeR-øyM!aaatAke2jʌ\ٱ?L"OlB~~~tA+)BImn茢*9.s%dž+Wq%!2j" cOHkw2q-BH/Ǐ몵,7QDzvXdoc̕@ya~3gS$r69CyrY-8YU.rmߺܽ~$S}A"ϊC}Vޛ2n>ng丢TW'PBQ&?Je;[>mH{46B՚yffZU*$$j[ƝmI"KפM-˺L{iz-80cf)֍<͹Tesbc_k:.]%|c하wBF(*Bo*BB sr |ckVHlڧ($)3b·-#%.1K[%$?A÷]̗2\TS7L& OOO; PRn>o$ QFD%(mVRʞGG9ve9E*e:\`(mXPS" Jd 9Y[q178,ɤ("ZIBBdd$An[!!J x|>o(S=|,ȸw#@~|Kxp ߜOP|b1) h>&ߺ|cդ1|>@*UC*ahh:i ,Ћ;_ڈXD#ܬs))0LZyM$AQl.ZSEK({kܔI9ŔRLLI|^ 4o<44nݺ:i ,Pƞw**K5*HaZcj[Ţ_ܴlb\KldVQsd<“/R TsXYY5,BC[(wpQcy2Ufd L`:}[ ħ]jdO'J$,'szca9*ԯļy6~20dS@ B!G@}X!TŠ@KX85x}e]50(kޭKNH5}7*"mlޘǗP,.E-Ԧ@BX!T yIFj-ݸf|K.9hKX"ƭ-PefrbS0 !TeQPɸLဣ-[飚z '@U%i$;{\IFtg@~~~t@zf~W$D2yܢg=el` BzF.YYYq:mF~W$WdTڷGI0B!aggj'xm`Ldc |%){ǢI0 0w~["w\Q|Jn!15joN ?L D~ I0?ŋt !TujbU`p8@`C0 Ų;400;B\5R`TM`Xu BՂL&rww777; ;5{$'Qcx*fdz0ub 8暗=o IDATOҴI[4 y˴\H\ƠuƓ؄7i8 Bɓ۵kGw /###QMU`q0EzzzJJ )B@,v l[ؖ NBP{{{Vo$!D" 211Ik5 $!Bx!BH uS$//!R*uԡ;p8tG@}ؘH_888#})w^~}S&IwЇƍGwG)җYf͚5;?~tA!%Ҭ\LK7n܏?IwB}Qvvv:i =zh޽yyyϧ; B!1,5yd`06o|= B'N:ujԩ&L;B!+}N/J5eggy1c=B)LnnnNww ?~f6 #GlԨє)S 鎆#ƍ ; tA ,x͒%K;-a2k׮MJJ 7BHz '@UXO?vumҥtC|S GhhNZ>Xлwo777''^zΝ"T!=$J3D" UkX`AvڵkWzݢE|ޒJjo J#""rrrGRT Н!T `Uƒڶm{ VMOO733;B[%8::@|| !U?QoX6 o0NL4)O W^B MjԙӑI'l>RnAv4jec%n.f {ߐӃ[ZD^&$=bq`s#a=)SE$Fk` $ܒö~DwWæKhFomg x\"}T;'s{1Rb zX"UPnViVWI~7r[[a3 gi7DyvDmA};rU|g(hZ`i6޼OSu<ȺŀuYCTkX`!&iYç=&31oC5B 䋻~~$Ǚ^8ŇsiMtLYq- bXO[8䄉ҰBU!,,e˖Ŗ9ľ&>p`Dm !ے@lZ=?~9J8W]vڵkfwaQzm:4:Ǭcmnڲ uiukh*: c]m ufɨUIwOhƦxmf֊ ~ݭL=:˛[iܳg¢y?8 uך QmB!>>>>>>!T̛7o $$ 5BnvҠd ! Fo5_XM,fv]\߬6bBB<ѽ''ٱl.reޚk-.?ͤPNX݂0$B 'ќ2L>>Fѣj !ʋ㭙lԄ9)4/Ir6b9OV@)oOYeub6z\B Soi مG| Qݘb5wGE)4BdƸH+CTWU(^M]R^0k)ڞlԭޛO .cz v*3Wi5N[hREb=mʇ6i bgj<̌@r>SK[/}LIPLNry\Q(ׂBY~E4O8uD(qg>O[gλ_Ǟ&vW|P .MB%rO̊oBTiӈؿ( ~*m>D/zM.YYYqo ,^yN_>gќAOVl|z$Y &Ie{}JC5 pkݜ9t,QcCv<8!ZY[Tij5%o{/+""3Gr/?wBzd}0@ӶF՚]4NnۻU-Nf:~E;*mfnӢ`AzO~1Ohs #oxO|BH'RDyYZԥ LPFQeB,Bz4#` kcT2"ӊ/[s:v=qoΠ9g:jԂtx!"G1 ^)7m¼%: 7v8t_jDKÄ7 !Uxy!SWΉT|]i[ u/? uͻ{ooQ!ZN}JwBNS'nfL|Da)۶vBd16 $M/Ӛ0w^y5)!m9%y)+qc%FlwĖRm:O$a d !D͔1{0)u%:{#nCHT:qDEEWS!J*h?nff&b/iЇd2YTT9Ysֿb"PBsQlĶDȪ 3}T0.B} Elmߦ;Blnina;?1oWM܀'n364Iv=FyZ,={GqwFomg x\ʵ_xrخjko8vZp QQt?$o_w+HU}r9FGgE5CXXX˖-X!S'][i s+pcjȦy#g"!kmAHK}O13܇-XS.ma,~4ԔTM%WdW/ˡ\"wqr5$qgǁs/t0wj=,B2"""bccuX:S3P̠(^??s|A᫇5#svv_C"98M֔RD?hz?s~tEh♇ɺgzyw!*o"T6"VZ^~敘tXssASrb"_Q:@E(&{?!ʂB WeLH Iro5 Lm#?rVBHօ5fNY,ps{l~kUA(B4 Q}7&Zͣ3+vzyvBrZ`־Ny$1`Ӛ-}kLop^εں#3b>;'9#no7 2s|SCKUC0Sر}٫- ޔRΎҍOdPYsC.OTq{畱Ɍ4{39w \h I;;&uv#q -Jڔ\b7d4tA u5[QMusI ?ALDZO5_~nJ}&,ޠʦc JVih{pcC xx7?(zdt D!ѣ>;։CP,CKQZv%k)<6@Dp*b67b7mhʢbَ<%$dgE1ޝ;4R@κ&'zv5vDmwCb䋌 YwO4|9fDJn^F0h\Gzv{쩢S'nfL; B#::=Jw'NBj `!}I:x%em[BVvv,!{4%7|Seܼ6!U #%( ݪKOGZhuUtrc?k&ngV:y:_};='++qW/KF_>=Ӳ㒿߻{|[7/^) U/ngٗuj""s$ʅ%X޼3^eVveܑq@Ty&uY,0QWV SEo}mҏF%0RĬ0 _1Hޝ[IӺ66u[hSյXK6\sqJk99M_ABjooְBzdfk0E}h톌lWԼgǗM_ǩ;/m mQ6 u6(~6Co\ŠUO(KO/ Wʿ|yGhٯ_~[`3zu-ZD~y=ULʩt@$IPPZ[HQ"1mNzFQQBb>xWzQYޭ碃 xsŶT|gM^^m 4lBCMp=I؞SjkFݱ]ȹs%BŠ۱/)&!,LugSDva/Ԡ;8ãYϊjDү_~ w1u/4 b3_<}{fY{/gkZ22؍60 ص\1uJII8p`srrvnaaIB!,,e˖tA"/DDDЛ"cƌ +^zʕL&sԩ3gpL_jk|B !d׮]cƌ 6|Υ3"x{eb BX, 4h``P;B4+++.FT , Lv \NQT^^NTrsse2R|nz: !t%""sQQQ^^#B q&O|)33kН Jׯ9rGtCr_U3'OZ#MBZҥ-[:{B1|ן>};B ,+.;k֬n߾]V|°a6mDwTdp| ,7DyD"|! [n.]tgA5ZBBdd$A> AMݢE BC PٰBU?NNN@w#44^'as=L-$KP={[STfffEwC"5 ! 9 1疹qnpqH/]:7d23PVOP?{d6R_~}̭TF)Mv+1 BGPYB!!ʆœB9ڵa%gzVNR[6nUN~rn–F-w:tm+;\ s劚x\.W&!ʆW%(mVRCoc"{(]e +IS)_3 0w~["\Pb%2%BbP%,4 EX_O(JRS PٰBJ*-]L}([ ލlm/Uk)($|s>@%.VŤX,&hjw9ToSV^& |^T$J^Pi|>ӀNwB^ܹF")ef%0KIaێXKǾK_}x )|A¢MXFp)&&٤u QE^Ct~~~t@z ,NcˏRr;_Jr|| UW[WG 0-ވZMVkbQ̏/"9G\ݠDLVˣM=`0B\.OKKruɋ- [Scx*fd+_Z8)[k^&>ʓK'.\髗9ܗiW%Iy!7[#|CQҡ;;XWAxWp$N ^G߻ro*b-dr JMõtȿ{֥GZPa'+ IDATܾ6ndoK/յYp5NZB1*^B3,x"1/)=CȣC%z>̱cɅ3>u ½DWUfF.W\V BH-B2vOef(䊈"#{8(+X!}WȦq% ѝ!2,**ܜ,H!IwB!1EL&ׯ)ŭ[莀B_9P{{{GuֽqAH鎀B_3DְBhϧ;B!a,B! !BH!B!_888#,BB  -BB!III B'aB!vvv:i ,B! !BHǰB!ұZNHHxAJJJJJJ^^^~~Rl6VZճwuu566;,B!"ɢ΂N+!ׯ_?qŋo޼a>obbr~~wE" B附GҝT`ݻwo߾}{)j֬]]]K_R(?:uΝ;y<^Ν۩S'Gˉ BH}!-u_p/*ޑ-q޽{CCC>,Ǝ;i$SSӪ? BU-P{{{5wr'?͚5 IMM=y>Z]+888%%%<<< `嶶?Sff#BKH$AAA&&&:i-Zl(Jw1c"l߾:w\Tfko!B_R* ,hڴϋJAXo߾{N4u>QB!T|mVtttӦM.\ػwWQiU\ ;wބOO˗k4*="B!WU`߿M6Ν;uu2?pٳgw)''!-ZlIwKΘ1O>[~׮]|cc͛7oݺ5""UV_>B/F (L_C%ɺvjժcǞ{X,;'3gNTTԌ3:t@w,2,000""m۶s񱱱^~۷o7idz${!$''_re߾}s=tӧkժEw.H$:].߿СC-rss;AQԖ-[x<ޠApBhPu7|W۷C QUEQu~?~ԩ޽{BΥwM>a„͛O<,D"Yn]dd ΂B]ttϟ߻wo taݺu'N;ީ6֨QR;_H 3gNBBYB?ڹsh6p:uܹ zzXaaa… ΢6mp8SL;BGΝtCXXX˖-B'p9KjP`iڙ3gN0,!HfϞ?;w,!ɔJe|||&MB3@gnnNwyzzfggDTkݷo^b˥;L0~f’!Tj;;; P\'OryRRRfO yyyy8,\͛; B}l066; E|;;Xֆ W^MQTU:U"D•UucΜ9_0T*HDw E ^XJ288CUw󳻍u>a1Ju$dɒ~c"}~J*z'`.ۗ:uԪ:VK@vnff??Kǎ]\\֬Yy %?BLz]`o߾*mJH[.E]kg x-=J[1{kh=hWb{5d4j7+JmƁm_GY y<# GϦ}EK܆߫Ĉ[y"떃7)(8qbttK5D!+B3LNw=T~6ՄXΝsΔ)S*}~)Ǝ&ԘCsZP K`ۡ'T}-JsXOtcr)Uq '/>+oA.;jԨcǎ%&&C*VUz(uzZ`~ԩSÇW@4IF1' 6zW w֣IӺ6wm`_I7 %0G<{Z1rv m-Ym(f}w7!``m[ @rs+xߍ5ݻw !RCOAЗ`0#44^'tҊ8p@| cS1^ie9io ŕ?Rly$;=KCab)-aֶŀmVF-moڵko?\`Ex}D"᠛z޽{===]\\*t-CdRK,dSu4_ԍ+ elf̠@P7h&Ujɓ'7oެ `>d2Kzɍ7MIn;ZP>,-0{6FޛP@cA@oƣHޙM[(K ڶW{|>޽UuҝfҭW^ bk4RH[XzM;.b_r[ BEA0PZDBf{^@@"}QfΞl̳gÃE @ o7kmbۢ fz/6geVY)(_Q;MݶOe2Æ ;@f:EA֡`0N!Y$ׯWKKMICĂ?HѰx|}2rUP6/Ka9l.KnwBvKis^e :4kb=?0a˗~eAb``p}KKK;{,Q..]D_⸸8oo5hl9wGl+($(T.9I_=ڐ_$omjْ 0J>xX tvv&0@jjkpbEEEBX D :H[c2ݻw͛΂ 111߸ogÆ 555>%+))ϟ?gDAAΣG[7+>|בqq\ߜY9;; p  C$zݥM [[[&JtAA~dXϟ?}T*gϞ╀  Hk3$e0FFFD!ubb" 䫬 -**"::olJVgaaA&BKKKJtA233  C\`#X VVVD 5+~ywCisB${2Gۺp`t[Z֊klosw322k,yOrt4A~:ܙ{MaNjZ?kͨ 'tLgs-yAfɭu؋cؾNLn&VuҥKқX 9=]aAG p"9*&$125~E/N{Ms2Po)ld2̬.= -* ^hpYv+=h!o_@E=W>~l|`yfy9 TeK7xfە"P}yn՛ҫK' D`gj | äz׭#Ng}"a(>^moC$+ ?Ew[;EügPyѿԾ Wd- KU)eC} vH"DNIt.`Jờ:6.ej[A$J|+l=lö&T3va[lF vsOU)lsFfPgKw{Apwww@۾4afMn=iN? PG*hnֿSC w|_x%me 5H %%k 4)!hY_¬ >8k7g4 KO5I{QKˍczjuSqGh}fBqݺue$Ѳxӈ.1m]8H*8XR12ؑ[X[w|#u0~1*HR5 bӆJR(eK.>}zBQ:-lx h~E3[Oa?U6æ=pÑ8CFY{`?Y Qj3rvK; Y\C=;벬8>}̬###KKKHJ%'Z\`aJV]u)^~uŚ.y|l8k Ͽ|hccd++W^߿n (Gd}jfIvծσ) Z IDAT43{-WE];. dse ԭEe^. K (6}Lnn]~~~@@Ǐ;wܠ [hQhh֭[[^ 18noooooG|{ׯArt]qKͅ uEpQɃ |/mRLl렧@R0Z qEEҕKɪ[ _=U7*]q\mC?#qQӲ wNŤQe: ]{-aFFF'N$lo~~~PXXHtI!PgDDDiii<I+fǎ cڵ>kp^ԭ$,<'--]SSSQQ~2laaa``pe=z4hÇիWϪUPcԸ卋O:onn.༷GNFsK yˡ 6k=Hi1tU򐅞 vʽ|O/'[z`^y% ԐySc ;ZS Ǭax'ȿ|δhjj޺u{bX,ɓ'?N6nx1" ͛W^^maa7jԨ .|}`ee'Z+1I)p7DH$H$*--D P]]u{'c1jT޿P(͛0a:8;l`+~#:@vwp= F3"F^NL*Że 6\|ewh 9Z?-0xRJʼn eTO^ LML.#u6^I]=G"H[qvvvvv.--NIIɩTSS%i嶼1"kjj0 yyyjF=OzP/_7nArtM0GGxb!򌌌wzxxtE+)) m-#S4f ZSx8Y*$Á,GR$w>$lWEQ.d]'0nV;{iv q_Bִvz$ӻ.B]"l ͝3gD8|P(\jJRVߓ/{K^zlmmVXXHl<&''׹sg-[$&&!+V}6A俒*ԫߏZS8#Pb)**Sa׾wV pvF{\);1TԢ) *xi )82IQG ,--j6Mteggkjj0 ENNm%Gtl./~[N :SrĆx LӋF5Ľ)/ʩk5YrN^>#SS)z"I$ ݻwU ` $;!nt˦iF/1B ?\h6s2GRC?rwv+zs8U~Pj)6Mzs3X0b!y]JCzvқ?e`n7zDr)V NYڝxiuoj~-72>UāFW[R81O}T컛zDtߑ+^ޛ7l9>}hET|W,8,9!#~P71VP P(d x 7ڗc0MUwD4w֍,q:2f)HY$ܹ3Ŋ':+** `΄4ur>.?@/9ÃrpIR$-;Cĸ4AO :,SL.OC-i  Iѩp BKf}(rjD5$xIBBhDhX|^FyFGH#Lx',h]ZV6%o; RIE%Obrv]c&0pNJES}Y T@ #{ ??5 E<.mף#/}uV]DXYXXHG"i,a%EwY}dK7{O8NZmqPm18eBc*7yl.NQz#Xd :vTffS0:K^*cn ;2d UAQů#it /0hc*>>whDAzeS5"U)x[FKaxMUWS#hfk,OGU3׍mfHs ,5s y!퓧E3m #a ndP_S5YJZZFLZF) 3k,+r.zr` zXֳGD L(R iiiiièRR pHX^IXZZVTTdffqqqRR7։bcc)@$9666K4KUQҁ',wl vI| /Γu,VV|rFv\ykWeٽs8/$q"Ɵ:m|?0gciqs$XVY̢b)̎6ߺ&lݡmiFNF;Ef=H %RXaIV ** DϞ=ڵ+A!%##Ct D"Q-^o׺q>1E[GW9*_ع[:~GX]ל90դvLՇ.{)Gp"}o?[ I_?V~kÙ Ѧ0XI1衴O%@AjO0񈣃y:Ay[`1B__":uw-_  }Ν;Ywʕ+kjj#Q$"HK,yӧO2 ҜS "Ajjj6n`bvv޽{ #i$ӧ+((gyɳgϖ-[&!EX,S "Aٓ;w}I#WrBVVv;vذaqZ;A!6wx<`0꺺VVV躸;kja$DXz#GY&88,aaa&: |+>HNNNYYb ?r8h>|ԩS H[9rABBBL߷oJ%$D=S7n >YZP(\nY΂ xHHۙLm>|XRRR^^ի̚7n,_pҥZZZsIHH z!ik_RC|;Nhii9|LBABΝ;˟T*E;(h4w|||@@YZGEEg>}FItVPPnoo_YYy{yysss;vmٲEA-[_xy$G;(`+W#:K+XjUaa/|v$.\~ŋ7nLNNMtbƌFFFGfm۶9s愇nNNN111666&LXfͯt$ "ɣG%#M-[lYnn.Y+Wt Rgg簰cǎ}СÃ.\{3f A~y;vy&)$K{*H$҉'رc\.q۩S;{AtwTVV⒜|ՙ3gRؽ{w@@ɓBO}:AIӞ ,;sX^Z`-[΂lsbb76Ojժ[^pah AJ;+`ĈO#:KK1BMM_=1c$''_vmРAm-[N|s4ǍwN:8庻#ĆQUUzj^^޲eˈM qSUU8pݻw/oݺ_FҖRRR9@tnݺmذ׮]#: վ ,|葾}jkkSNI ؽ{Ξ=Olޟٵkׅ A'jhjjFFFN8qʕ'Op8AyVRJ0իWiiiHH톛&C -@榮{nCP;V\\zj DBt:ӛ7o>|߾},-6]Pqjy* xey%1 O+^nݐ!C4;(ػV@K)ܢԧ?<~Aȣ6%F޽C ʈMcK3"ѣGҐʕ+O:KtA)ðM6ݸq#77{^^^<9ee9NMe%hXy7]v͜2zl;KE3:_^"V٬<7IF}캪դ&gMYaܲe+Ya+WAgu ,1WW &l޼{-{.aJ@T壐 yM9"yӟ#-wz-T;k5Yr)/ʩםW/aX)5" M9%mu"#0\+ر`Ϟ=DiܸqcXXXpp0YA~_EEŀ۷ol;;;ggoY8`;r{-gڧM\䈊B%xSYwϟ&e̠B(2@A(_MaEy5ETv?4<]@A2WU|!AhCN4k׮Dgiμy׬Y /,Ć k;;߹sG hWڬ/^YV)kj2YJRIѨ'ڪ69ta8 ++[ׯK#\Ddy=nFr)ٵ@0!D߻J,:A~{۶m#:7Pm۶%&&^~, -`,]NMM:t[hh(׫~l9K"ޡX[Aׯѣ]z|\)OO+B@BP(X#Sd2do @FI+WY[wjU"l'NCto;v % IDATΝ; ~KF͙3'33͛zLrС芊 *'~)0 /.|">4ֵ =~Pm|2?|tg'fҪr\YRsjsi,yz#S( *쒚R4.ssR e4^[aZx=UUU{T:DZ|/$ mFVUUݸq#(((,,ܹs⹊ ,AYYYMw޾}A5.'O|a5uu={V$B7.@ׁ zl٢Nt nM2mSHYZVD~RFAI7ZǝZ>REQ5sӵg [j4n9 4*vꯌ4OܲŠA!*p8l6Ν;䤭 _1`ǹ2LK;ۙ/#DcgU 2M;q|>]cG^;t58 U5!\6nಐrLѸ: )sm(Oho9r3g~AicBv/**۷nnn?|y\ʅ'"%n{b!皒&^H:>v+W Ҧ~p ))QFΎ ᘜ䱺4U ۼ˘11X$aWI@tp>𪸘7^._.R֡` R.WrG07'0a±c1@7e%UEe];}4VdUWh[8z 6wqt?.Ȑ!C0 }vgRPP!oU )BGMVo*?zS+'K.I\RXbҷ8oݨ]\DFVb;F}is|wq+d`RMeСUhhڵkt&NXVVFt `S HC="6 %66&L :K+Xxq@@&lk&00 IKtIի9s?D+Vl߾ [M,iǞ>} z":H밵{9Y$رcQ=񅊊 q,iǢutt:lmm ::  ? XҎEGG2W&CiP UIIIFFFϞ=Қz ,A~B*)) qkkk&kkorܖ4 HKeϽ]禙Y-} zԈN -DiMFFFB0==-1 CrUNSg]u9 e3HI׸_/D"*zYp8RS Hhii57otҥB#+wjQZH$ݨ;tYhf/-`PZ~So޼166ŮmllL"ăsCVD rz֒Y:SG?˭w'a9bÍw<EYGWP4F5MTr:]jc2f8 Yg5'^xrR4Yua뮿.~W͐*YM)LQL8Q_AW4'P$bE?X`&5v;&Hy捑1ͽ&O0E߮qt2UgҥtX}6GIKKkii~Wimw@yG Jաm 'tLgs-yAf-1rBZ4P]iyv_e4V{@CW].4u#)|W}z@fK;w=9qi*?M(]{T>UāFW[R lO1or=xP8a JZpToK{׿B}s,.!v}-8*yzz~Y' iWwk WGD XȲG8ϼ4VCFJNoO-~v?q^]鷹8Ig,/ֵup\TXYoŭ\;r=CkNeJhXZUWE"Wĩ%H7o&970)c"4Mx8JT|g!  A:tؽ{oF077=z-F`o2Q)WY 0>h&UoJ,hgYUN<1[B/|j5I8^ywzWCW)k98~$Qgim䎋pǫ.h}eqyZP(FkqfC&_E5'FS xUT-㜄[ON؋58W:&;qά'nu?8ޘ"I T_^^H$ر㷛DFFJYx{j9B'Ogbha{-ޗecbOe<p< zx,//T`}Xk׮]D!fY3vJiRyߞxi9/ -INQETZFTث(]z>ET&,_f·_\_ff 8Ρ:dۑ{7A |}ޮ.5#.{R&:Rb疽{rb~‘{JigI/D.';e[gg0cc>^8aݞܧiws6ڧ2KԎE3V8ws/*0 cCVgb(*`Ck]>)$X\O8BByn&OG ʐeݑ3<>eMþ0myk̒];:Y)0O.t_;z1f7XJ$]1ֹX14m~ '{ =_a\aڵ=|"jjjy7/sEsR"qvv^U/Ħ9cw*݊QCW=y7I)sc̺mb/,;˳*%y堽aYHf?i1LouIx;s?% L&7nڵk?q2>/=!Nƚ..?:.( Ly.1Bd뻭uuv{81\w{i{m;W0-%Ouװťko x Qi;nX,?^ n{oݺuB;RRSS'Nx=ܹVH1`7׾xZ~YϽu[׾62ٯ-[5}߅Fh8"qkW`B2wq% ƦRI쯾zf0v1"bWЛyQPp"gu:^ |ojS]vv>/Z\?eoK SMWaV]VëӉq{>is6}&;lQPu>3g>999Bgq?NɔEDiii/>pl:ܹ6nKDuuu΍YYY999urY\s޽Rϫ;;s0?9ݮf/^FD999AP6eR ?W_}չwݺuF555/ҵO獵cgw9rC=ϟ?_~gΜt 2ȑ# .\f5JWT>>>2m'­]]]zY;h4BGpwvA[\>BBBjZ t6cDMD;v6 \hGYdsyx@" P*ӧO7oANHHرc/_.twn6I!//oСFq۷ow+":ZrywKTx,wdZgΜ_ϟ?رcyyyW,%cZc7r$,w$JƎ`nGV^bOax(,w$vd^>N>>21NNkǾ~q*8M\;O8"kD.mj]Njw쫵꟤1q"+p{TR]]!tTUUDq uNbKN}ع+50;>Mgpv7ʂuCu7yCWkI[#X&RJR iR{s-V7YJS(?`x޽{ O?) uLZɵIBgp `:oN8Ԕ.t  edd466644'",x9ܿddYx~___2oNd2 {(X,99g߾}cƌ: ,us=BqB~x0TuV@ ,ozj0^_PPOb KL0lΝB1+VlǏ:Pĸqz Xe˖۷Y%rI曊 j͚5MMM3f:P/d1dɒg(X#000//>kll:˯۸qcEE믿.t`x^{16g >{lN7vX N2eժUBgɧ~zK$ ۼoAb;>Yn ,ohf͚UPPPXX(t-Z̙3/8N, :uj||ɓۅKUUU_nj!t[ իW?~|Bgx.]*t[ ; 2dʔ)K.ݵkY~p={,_<,,L, ך7o^ll?&t"GO<f|}}WZU__2Ƅ c0Fh/_.l eff.Z諯zwp8y/"44T$rӦM+//;wn߾}nj#H3gX"33SF߲e&L{.\8u_|uA`x?\aÆÇٳv~iӦ=|B#<#;vfTyecsWX1mڴѣG_9hm*;ivBS~wQQQ_~2cMI]16]Ѳ-?6ڻw~`>ɪ_ۧ?iҤ{\m;}KJswN-ܺX{cm)R,P8^Rcp~n,;H^RSS|7xn7CDKuƲCuOm(33bw/GYzɅS,:=;=VPV{A, j-wg'pDhhe -ncMPwEEi?~Wk1F#Hdf(q+-ikRRc}w|HHTXN+wq@ }-B;=3cƌF_/bmF3 pQnHOuwb裏t:ʕ+'=_ED׎>90[ S+,a=JL?]2Ԟ0:8UTsI)>CsnذaӦM]zuKWxrW9Zy#Jv֬'O)96FdI"pblH"ߐM]ڙբ RE--팘T}[Xjj\#-B;]nnÿh}i+o-˗ }wܛ$ :'rx`eb"ˎc.^XZZ[ݰljF=7j<ᔔ> cch$S'(8:[$3 ڻlM1>̪gsfN!Y,JJ`IfeLxWT;˿9|xƍD$zIׄFKvDD 8O3d N'@Jg@#9tRMtrFDܵ[|N4YG>ڤJNHL6,Q%UGƉP3q1"& ;K:Os*I}C\٦0DiR{Wi+8".z&]B""cBLMJ:ß> stream xuMO! 0pGL6x081w,~&@yB:<'#d A5]#(۰ռp~<]7Wai $zꢟҰ! \ܯ1IQ r58G 5̥=r,y*v4"ڭxuԮ%R@BTa# @x_WSKUF2XuLCم+F]WTOf=rεrOӶk%HɑKO_Wέ\ƥpՎ}q5oWXi`b{5P̼X endstream endobj 5 0 obj 357 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-1-0 7 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 8 0 obj << /Length 9 0 R /Filter /FlateDecode /Length1 2464 >> stream xV{P\ι坽.)}ęL kQK@$k AJFAi$h[pR Z&&NNMdT4A# mZG܃߹Nz|~s&(WjbZiC݂UV}mU y4 ycO?5T _GmY篩 6Fr߄$I= sTšDS(B.B De7B6+LHm^ZWIQqf+h s8g4Xస5#Q2ݻA24gٹ>{FaO&CD)>W;>X%ӫf$٬^[ iYVAAߦE1|vL!82*r6Wx>ŚlK4fMĘϬ{wWV\}ퟃem7mfiO|coz;W*.zR7VSfKJR3!P QH+}ۈFg_^z~❅v6+'{b@77޻eCKٺdپ&6B1'gu? yRd.}Qy^[`Qj6)΢PTx܆\|&bf_iNq]ʵSK x=plD-73.nwEaY.z,(ˏң9XiQVƚZS ΃>y{*(-|%j;85m[;s^펔~c䉚{sŞm EnƵeن0&&c|E@Q}.Y7Pz\;S݆%c(f0<ߑYQ,xb}qB}ݿmiQt=?Tg1u JS.и 3/ hC'OS_ᔎCn᥈`S\} Ɛ'Β*?%|$*٬(WrB:`H͌=E.gVrk+,ti{7 /~1!O2W8C}z,<}Ԑx玆~1|Z60ϡ4IҮř>&y}05̔ "-g*&6,T %tWYCdG-؞m.1Iyt'ry ӌ1cU?=ڸE+Qh?X8g9-ăcGƨlӈbx751VǦ̍"hˡ\| ,_"zĭP"AǺ)=M̵ m0;9A#6 b*䣽Gb&7mTFt BeXe1. endstream endobj 9 0 obj 1677 endobj 10 0 obj << /Length 11 0 R /Filter /FlateDecode >> stream x]Qn0+"LL*!*pCR1q}(zΌQ{Xt&Lu0:QXoEF;7-iH5 vOfA@ .:.m d2aF(xߙTq's.%\1 fZ'h*QLA4njSHd\ ׇSHyyCyyExd<O䯘$cIHZĩس"O=(Ag 4mnrߡ֗F'U~2J endstream endobj 11 0 obj 300 endobj 12 0 obj << /Type /FontDescriptor /FontName /KWMEGX+Roboto-Medium /FontFamily (Roboto Medium) /Flags 32 /FontBBox [ -907 -270 2051 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 8 0 R >> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /KWMEGX+Roboto-Medium /FirstChar 32 /LastChar 125 /FontDescriptor 12 0 R /Encoding /WinAnsiEncoding /Widths [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 568 0 0 0 568 568 0 568 0 0 0 0 0 559 0 0 0 0 0 652 653 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 541 0 0 564 0 0 566 0 255 0 0 0 870 0 0 0 0 351 516 0 0 0 0 0 0 0 335 0 335 ] /ToUnicode 10 0 R >> endobj 13 0 obj << /Length 14 0 R /Filter /FlateDecode /Length1 2012 >> stream xU{LSWιCZc˜mV2ヾ@Tš+mU>5{ hbh1tfɔDLa{wۺ,fɲvN~;s@ S_{?`7VVȿ O4ؚw:>kpC70aWpu%~5ȯG>^H[@0QB 8^KDHQ%IWTbQJ頕J$&hX6bhS Qku e,˥k%6~ 1›yw-c|j|!CU2 U1 _K|Y>.Uu F̓q vBSYR̜`2'd=.Uc4//oy<2l{tɨ)6zXΙZp|'g/hܽ1S6=[`6&z{LѼ1r9ѯ#zx_kCU _yJ2(5,7TZ n6A0ɚR.%'6"E=kH2cfAiANZ_*rgPaޖݩ|j⺚+=k2cej t4Kjο;ypzyqU*2[ϭ22%UL#8v#QuIFdx>ag zbFN8t22$ZQqۚ\hl7qu[&iOnŞP!_"$t@Ռcanm՘[jrg?^tojBW^ j;7~J%om @2P&Ar2KtSM}_9xh1~a oEVC榀<Gp}G)h?#:Su@\Qok]J|s^[C$74y拶On:)&ێ;o@Rya? sȖd+I)Y5qyʧ) 裗vM3?)k2DD_CԺPۮEiX krcϺb:}xlM7$SJ_zVl'Aj@pd2k +B6㺯##I$1H h?{ J7E5 endstream endobj 14 0 obj 1304 endobj 15 0 obj << /Length 16 0 R /Filter /FlateDecode >> stream x]Qn {L*!KUzذH5F] J;P\ΚŻ_dl^"8˪vK p^P|Ps ~ÓZF|`Py _>ShmA&3BNQ߄H!^puD? (-CWd{L4ZT<&Lpq1ϘuTWW2a*L4ٳ<{ 3&kȟ2J 6nj{#=D!&`,-. 7* endstream endobj 16 0 obj 284 endobj 17 0 obj << /Type /FontDescriptor /FontName /KVDMEP+Roboto-Bold /FontFamily (Roboto) /Flags 32 /FontBBox [ -913 -270 2060 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 13 0 R >> endobj 7 0 obj << /Type /Font /Subtype /TrueType /BaseFont /KVDMEP+Roboto-Bold /FirstChar 32 /LastChar 121 /FontDescriptor 17 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 650 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 618 0 0 0 0 0 0 0 0 0 0 0 0 536 0 0 0 540 0 571 0 265 0 0 0 865 0 0 562 0 365 514 0 0 0 0 0 502 ] /ToUnicode 15 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 18 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154042+02'00) >> endobj 19 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 20 0000000000 65535 f 0000006221 00000 n 0000000599 00000 n 0000000471 00000 n 0000000015 00000 n 0000000449 00000 n 0000003288 00000 n 0000005802 00000 n 0000000817 00000 n 0000002588 00000 n 0000002611 00000 n 0000002990 00000 n 0000003013 00000 n 0000003725 00000 n 0000005125 00000 n 0000005149 00000 n 0000005512 00000 n 0000005535 00000 n 0000006286 00000 n 0000006403 00000 n trailer << /Size 20 /Root 19 0 R /Info 18 0 R >> startxref 6456 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0005_Diagrams.png000066400000000000000000000217351415120503000275040ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxwe=s&RIH4Zha@@lbV".?,]A]\H $B!!IBfRGBh{$CxysuySn/~q֬Y; mĉwӆYf Ѓ>x=t{qM7N8q3#Ȝ9s@J)u,tqUYwRj{f#m __SMMMn+nKy]cwk}ݕ;5WYJm3g?\{y6e%_5ﶛ)Tj;k,6Ѻ_EmXC!˲PVQ}}O SJ)zDO_Fͭu}V7nU>`9iPZ0͙4eXayϕ6i%Cwng}iпU[ߺu#VlAz֙g!9={|J)+?lua<Y2OoO=lkєUTUȆ'֖kooniݤwVѣG5,PDXt).KW9e?_k?oye" ~+VUWguJs.vKܽyjxMW>JYѣMy=5y̙ ^~L7~h{eyEN8./>cg;㶶R}gߕӿxpo.:&76v󌺏~so}pgM:‹>}ϕ^v]>g\_?x9Gq]oOx5Lܿu–K/\=7w/{mwʕU=j XLyJ]X,fRVk6k[f<+_oҤ/;EVF{/?>il]1rޯw5ΟdNר/^swJT̖ 9G^6zȔR*樳齅/?I'_|':>Κ=k^o. gO[Q;n3vuw$oym7UVX]ʞ=.oRJch[v]m,;nvY*^y˟iUUmJi#f;ls5k]Z]WWʝ|5yֳKՏپ8uxƺ^^SϔjcUJ)e/G>կuzuT*gm,UVUfy[[{j^o>v_k>xG$EVREߡ\̸Ɩ9zҼ|]UXbI3ofwqX,qCwMҠF66ikق:s:u^w]L}7I/лnS=5@˪_swonvyP>c; d}G:-mlO=xȗO5x!}_mw_krqx{VdƎO}Xfٳg_z3lnCwTʽ8Y?ݢ!vdž%I\~1]w[iܣm)O:|~׮[wPsQŔ^1 ;|??uז_>/;_.̩U!O ZWWӧOK9ey翞p3REO.71=SǼ䧮`KrN+Ζ1_=k?1sw^}aJeÛN1, 6^˗Qo|͗]vGݳ'/}&NS^ۯGx{rEX@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X=awygT)HP2eJwOob3uԎxw,HGqĴiӺ{ Mw饗^{=a-Ұa8xM>GX@0L`XRJm]eYeBE>v:suӂ 7}nλqױWgP{ԯ^!A 5͟qE'ӁgђR̪eod3P( RJYB!wlPwvv^|U'ZLGt2eX~c>~_ klyy{9l O;S )3:/t.)e=%[;>K>[jy֮={iѽYʊ>}Cs)KAeYJYGqEך] .hxOq̩w~SmsVl1y}ʳBUUeuw?GRV{]}:E2T+V<5,e|i)W]wlBwߟX wuUYJY>ؑ3RVV]أUO8y/ȲBݨ{Yʪv8oN+//)``U֯Ve)xfK^v5{:F|ȷ=wi;'Sף~OuOuqӲ;s[>W|=۷L w=[96˞oe۞'˗5hH1{usϵU@GUvk,4`.~4 T{I_~^Te=PL)m=|h, }]R͐a[g-~0/{Ӎϖݏel۾}\y6 Q],Z\J)+j>/nOa֢U/ʛbyKWk7{vMg}9^|E]Y#?8z  iqiegSz궟a5~|բϜtti0e/߸Go[Fަ\"6fNg*w{Jϗ297 [ Li{~rQgӖ ȗ;o}-j}4R1~ɬYθ;-ic0jSnmS;;ӾrԠOk؇~kN=ǚ:tPYJ=G׋\ܭ}~%B}Ӊ\9oWCĕקV9;YqZ3{߷/=+:oD`yT*T7tgλ?~mW\A_ 흖-xbʗS|x܎yo ]YS\RV^^Ku7MծOR{<7|җ5 u&}__ّe)UM8w^qvZ\sixWw*/ wpÝKw=to$<ԔR>}zNO>쳻{6^:,_=?7uCӿ8l\ˎZ?lEJkSG++Қ9+w^.~ٚmRJK}t6U]Yࡵ̜ה!F`sm3q[.l>ūKvJ۽Ouj.lW[]]6gyxemG,Sggg;;RX^RJ)_ԂjR3O,\"Rg)}w]/ߤ+d ++nm^M6s=gϥR=^Uw@߇n]\Ï_̪*^y˟iURySk޺*K)zu)Ku^ń emku]]l;YVR)Xq1[{ח[,ynR'~`ν-Un҈,; +o2~dc!eXIsEoUыŔR*UeYyee1K]R[8U7T=diIzJM_>wnŊ>c;W[MooһRXaxbsɲQg˖m&жtY>iOeKg X?t|}wAeq{`Ejkkknn)7][[[w ?{ P^^#&wy]]]=)++ XlyN8^X@0 wIDATL`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0L`X@0OfjjjI`f͚8q? ?aĉ*{x,`kR|IENDB`crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0006_Classifier_instances.pdf000066400000000000000000000331061415120503000320710ustar00rootroot00000000000000%PDF-1.5 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream xYmow@P;nAZldܸ̐I'9I!i9K O WPJ_u鴠7L7:TpLP_ZzcPRN+ V=i4kziV^uG+R{?7ʸlXL0:;z8>G9x9]ǗKN89OzZ8lN'YaHWB@ (Í0ʐZ233)hNUDtFh#Mֹ~'/pg+P | ە 2(-~Ooq5f~i +i,'h#] \\=-6!gS=jdv|=ﰌo`? _2Q)zQ7ǐDRG)ʁ| KgHh>FN[cQYm>;m;d y-제V:,-,UB@EE٬2b{bB8;(0P<@T4qpSqlqJL٬J7spF?1@B䕠vzi=މŐ]CC^5/]\_HtJ b EjҖtγfLQO3^Kҕޢ$ggC=:ZiGz`Ј{AtwH0!shJ!3gM,oM!I;s8g+1wzB@E2|iRB{M]`ڱ8Ȯa~-C‚`Vekx?Rq^7E}i6T@TaG?g g a]wױ*h;rhlʲ)Bf̬ùAX϶fƻm-4@&T âض5up1h)6 gU@jجSKݽ(Ā>=`,!'=ʘm{P mZ-A-ϏVy [/n}=+l4!J~Kfa&+\2 V dRmH Л2c$DPH$.)2I%Hg K3ѐ⍝oI"9 3# _Vd1nWT]A&ǚ01gm< pr}^zw|#1kB{&LNv9RprdH[L(I嵨8klaFP"*/.h])eQ`Yv# : *y:͊&4JW`" endstream endobj 5 0 obj 2182 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-0-1 7 0 R /f-1-0 8 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 9 0 obj << /Length 10 0 R /Filter /FlateDecode /Length1 4972 >> stream xX[GA^2/H ÀL\(> "E$BP@/!\qYUqY.M`5_Fytz@|nw:9 !9IH_q;bS_"DV'{R oŋGw#{)piR{9gPL1s)ÄEoE9hjݑF C24 ٣Z0a' nL0J *{Ä\ c<ƾω䈱$!. iݑN.:^!hJ__E;3jTV;;gmWq6~'*^ڙN7ke`<:^k^ tq4FHtz` ~EhԹk9`&?슋[1f!}/i^@qlQ4 փ^/SңjU;8;kԒ1ggYVq ,qGw~? _sFzm/Y_[W69!<8u̶m[;fJ4m5dǢ꒖#3`b"&̘1۾:$͍ك䆐2B ~JF+=drQz>]xDSwmwGҺ\%ng^!$4OS HNGx.K"דy/E|ѕ7fC ˅/*,=Uo9i0sb`@+t'z-=eF§ K6r_8jfg?u'ߓ2ٯ=r29aF8IN2+<::|VOnl\ {{L Ǐ?аRԻW1Yޯv?`V9oS;j'-/ _2jTuYpP]E"8s"n|gzs 'rO6A9lG52@ھF{;[c!.O w vjwPIgп ]}Ҟ<[$ve SX^ރ7K,ks?=.vp ~wbícnۧNI:AGp 9#P@8O-$%V>/wo{f)宊ߪW_&,3ʚ_oл3^yYMo8VU^x<3Â+`!ۊVL@w `ae@S)>wqkthܸCI l#*!_ F/Yg$H8ʗ66[ Xg xřH"|p۸='23%/ςIW/#_ofbΕ_a% kzHB6늞?~j^i4 y8obn,Է`afQ7zqZf6R|e߶4F7;x!>guF^iJrvMOoጯpYo,']٫֭E*=v\ieW3AFؗ~=YC{1θMki7v;m^vמ轇⩢uqNRhɥ"ƽ{-i^4&8%aJݤТ:x>N@8`p/*# "dQi޶! v=¶Gn"Lx"@EcMYKKf˵k`8Pp]AjWVx@Y:@|*CWWsU'RMPykW緿ݝ}j9\Ia T3Y.e*dB!UeXW<'ɵCU؀˒-)\Ip`ޔ~ndhb ~NO.f|7ħ/x Vj$C7-Vw[KGL,NM!ٰ< /=N4S͖VkM/G!xxmʲ\)=}6T?%#GО^@_q{BLT4VMei(wqy?kU*--J5an6ѱ#ttw;YLFQKZ%!A?@Jf 3'(hlwpK $ík&*z= jy- = ZwYSjˊ]^e= e^;+%.=j?:nϵӘU ;v 1jduE:]@xU#+ x 6(W ڴŦӇ _0ͽ u5yxSC[[j_#_~z_2ji1s>Ž}rRn{Kx%WҖYZHv5,9O/q"b+^PASrrӓXM'$4JzBkk%B20hkϑIBe8|K/_z/`RZΒۅ+,k^'gĐq}ul>70%EiYG?9ԗ1PJtJL}2^IwLq|U`GH:i Slbޒ9J8KU*@3p^.Jqkhs?j8@/n;qNQƿE/u`S8ؤBb+FjRI˻R|RI8Wu/N>@pXˍVIP{?^Y8v⃣Igl=aջ!n- 8BUr,RsF~`Efd. ?"chh`B;R$<0\0 3Q]`ٓޝ BFoaa$A[*nH*6]Aq-r#~h1فKa_R5s 8`Yx & ;G`}D P }9# ]H,9BS@!;貃5. `=> stream x]Sn0+xLdH&` H.>$-X9bIN=H #rY^g\nf!e^Mi.v S}}wnעL˦<.EӘWlfSi>?/GR~YT~o[g5e^pҲ߷U;FA/kklMUM3B9WqI7m,ZP48 w jB<vKMV!iOOБS㡑!4_/Ç0 0 0 #rzxyF`>ďQ׳G9-`,bO$0CF %n8;[f`"s?xK K Ks,HxpP73 hC |v1uPӬwn]V_b endstream endobj 12 0 obj 455 endobj 13 0 obj << /Type /FontDescriptor /FontName /PNDRNX+Roboto-Medium /FontFamily (Roboto Medium) /Flags 32 /FontBBox [ -907 -270 2051 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 9 0 R >> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /PNDRNX+Roboto-Medium /FirstChar 32 /LastChar 125 /FontDescriptor 13 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 349 353 442 0 220 328 279 395 568 568 568 568 568 568 568 568 568 568 265 0 0 559 0 0 0 0 0 652 653 0 0 0 0 282 0 0 0 0 0 0 639 0 0 604 0 0 0 0 0 0 0 274 0 274 0 451 0 541 562 523 564 536 354 0 555 255 0 0 255 870 556 569 562 0 351 516 333 555 495 0 503 486 0 335 0 335 ] /ToUnicode 11 0 R >> endobj 14 0 obj << /Length 15 0 R /Filter /FlateDecode /Length1 420 >> stream xc`d```cp``bPHϩLP@JFnI C-_s''?@~M(`Pc[|Vf @;9x9YSQ F'LnZwS߸5<*11-"& IYMMM̌ԔDELmW?/]5W'}fnSܾEe\cb Rx~  pC<}$NǾW8\N ${?A~Ȃ#sC ^} Y endstream endobj 15 0 obj 363 endobj 16 0 obj << /Length 17 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> endobj 19 0 obj << /Type /Font /Subtype /CIDFontType2 /BaseFont /THFUQT+Roboto-Medium /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 18 0 R /W [0 [ 443 582 ]] >> endobj 7 0 obj << /Type /Font /Subtype /Type0 /BaseFont /THFUQT+Roboto-Medium /Encoding /Identity-H /DescendantFonts [ 19 0 R] /ToUnicode 16 0 R >> endobj 20 0 obj << /Length 21 0 R /Filter /FlateDecode /Length1 3604 >> stream xW}XTUs>a23@úÀ|,(jf( !b, fcYh6hEf>})>P!x;cb=}sw~\@h`0nAaүOmK羪/>{-);ӻEBnvek~O3Ԯ-(Z }9 ˖BbuR3i&b l4ڍFx/Z6m :kJTf2r{<%FQ>do)e,Zy_rݶ'z1]ۛgOrދDyv܌hMI5]hsQDk',nO`vމyQL՛yӴa*H{f$;02fnj B1x|Ijyjjzϻ6X\t[q7o?o=G>2j  @r ŢK/^ϣuaE…+rX'^S/oC'vZSFFt&! McK]&;k<;>oL.; yWڳٔu 7](CKu6XlA-n<*b/ɫ+CUS2> _\K5<4 zxy>Ф8hBcܰxbE,f]BrqN*]gZݤa>Xϓqv|g!JQ tAnFkƏfqxnx cT#Q)J3{Y^ѯ7xLhe~9o 0O>x$MU~Tc3 *F|8rF]-Al(Dl<ʅ׎|%cgep_?Diy5o9I/ZܜD~njJcz^9HW<+>]5X)1x5_wNǝ:wchp#".JIBIgMiIۏ ?^'^^^U>4>' Ϳ3v|@3UUd*399##99sclfflLfK[l:#)*Ye&Nۂ;wVR{W8Wz?Cq zFG;Ljfi.e7P?HO}Xn!y)f!,Db ~{3bVf]F?TV1Ɔq&][-}%Ժ#"{cJC(y^2g`OC jP(nxUl/ Q\=0[L0B% ib.EHBk!um] E4X/1F0mi- ~r?:5,r> stream x]Rn CV,UŇ>ԴZ1]6JeR>,lJ?`/ɂ# igmYvܿj9y=$Ѫ%nj 6 a謱-b2Ƃ=a5 y77CXPT¬פˌ`i(sCyL͸7瞞0{5yc^g=9'W?ߏ1P6s~,4xn/)c˳)n1Α\=M endstream endobj 23 0 obj 364 endobj 24 0 obj << /Type /FontDescriptor /FontName /DNMVWA+Roboto-Bold /FontFamily (Roboto) /Flags 32 /FontBBox [ -913 -270 2060 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 20 0 R >> endobj 8 0 obj << /Type /Font /Subtype /TrueType /BaseFont /DNMVWA+Roboto-Bold /FirstChar 32 /LastChar 120 /FontDescriptor 24 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 573 0 0 0 0 0 0 0 282 0 0 0 0 0 0 0 0 654 0 562 548 0 707 291 0 0 0 0 0 690 0 0 0 614 0 0 0 0 0 0 0 0 0 0 0 0 0 536 562 521 563 540 358 571 560 265 260 0 265 865 560 565 562 0 365 514 337 560 0 734 509 ] /ToUnicode 22 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 25 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154042+02'00) >> endobj 26 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 27 0000000000 65535 f 0000013032 00000 n 0000002444 00000 n 0000002297 00000 n 0000000015 00000 n 0000002274 00000 n 0000007254 00000 n 0000009078 00000 n 0000012577 00000 n 0000002662 00000 n 0000006398 00000 n 0000006422 00000 n 0000006956 00000 n 0000006979 00000 n 0000007759 00000 n 0000008217 00000 n 0000008240 00000 n 0000008542 00000 n 0000008565 00000 n 0000008840 00000 n 0000009241 00000 n 0000011820 00000 n 0000011844 00000 n 0000012287 00000 n 0000012310 00000 n 0000013097 00000 n 0000013214 00000 n trailer << /Size 27 /Root 26 0 R /Info 25 0 R >> startxref 13267 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0006_Classifier_instances.png000066400000000000000000001451051415120503000321070ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxw@I XMP{{S?Y,Y^ϳEPPQPTZ|.j$wEB!>@!հU>>K!Br!XC;YxvFmf0IK [t6Q Mz2U3`ģU O{r3woG=#r+6'3B׏hXEWw4p: 3umF={Vf:<̩vdfB!THD'22;9V*̥Y&uC|l@ҞG> -בLJ侎kܨ.@q yi2 M2Cj=uscfN\[ۿC z{8"SK+ SeAWXv=nXzƺ:6Xٯ"I@=.B!@4E1/D$L櫰.> +k t -mt_ $/=]*2*V5$y*!YoRtlU)”u^"T> iʙі,2igKt֎<^_lpK9K!OMD~&^ɔdPUַV>VBrðt]ۋ2>yKհy_"U%Xʸ篔v6OEB9YBTI;9cX1=JHqk:?υmWWImk\6v^1/i=`r Lf.,#>Zũcm_F}N痎^yK^RpG3ɍC=g:<ÃS&(Vx`S;:^Yr%!BW4 U諚Iyz=J[1EMK33e|-! ,6 P(frpXQUc] YY9$#>.Jݺ5xEK$/7PFchEvl 64 y#NiHBS(~ >X`GN(s("HA<XJLGnK7[v$h_bl(ǡ BESO pM߇E^9BO(,4^U zeao,58ܿB!T P|.ERv&>eF[]kh߰ז:5\j|z/OINZӊE[j}mt촠eAPpHr31l>'IfO,v^:oO9RI_~NhJc^lܤI&MD6OJ |*&P kV2܏QߩG%%}]rrr={BB(=ۺVTJ.Uir Xյ-Q4-SjdybUʆO8V죗V^TGe%JZqQfFZ1fPfՍ+S cT&ޖᡀA!WhQyfɇN^׷Wyل"Ӊr!$3#\XC=v |ֆG=GaRnnect-=Gy?!D!e1xUD.aL!#F4gC IN|a#`m:1rE7NeJ*^vvvY,ݻ5B!T fS!>.O+"P]ܹs! ^0B!0BB!`!5 !R|aZZŋ5 -_ʕ+v߿cA!4sÖ-[j0cX]!BP0]5k4 |B!`hB Bp;B!aB!f`!B&X!Bj B!aB!f`!B&X!Bj B!aB!f`!B&X!Bj B!aB!f`!B&X!Bj B!aB!f`!B&X!Bj B!aB!f`!B&X!Bj B!aB!f`!B&X!Bj B!aB!f`!B&X!Bj B!aB!f`!B&X!Bj B!aB!f`!B&X!Bj B!aB!f`!B&X!Bj B!aB!f`!B&X!Bj B!aB!f`!B&X!Bj B!aB!f`!B&X!Bj B!aB!f`!B&X!Bj B!aB!f`!B&X!Bj B!aB!f`!B&X!Bj B!aB!f`!B&X!Bj B!aB!f`!B[ ٳkj: :u@ ,4)!!a˖-zzz\.Wӱ_L&KKKݻ7&Xi&Xi(/"$$iӦ?wG㮮`B[jeffXPQ AAAyyy !W6mZV4**(((((HQ0B!*odrV?4 0B!*6mDEEܹsh<`BU:?~|uJa*&0B!*\^JbXSLQFDDDie2&X&X!P@IKKkԨQŋDAoK k"mdciZ0~J6驁4EnO"V451?㢤x0\Ϻ(YHU #))ɓ'O<꧆ B zqw+z-?i|&N|FUxt޻$goo hV!4M}c\ gV md& ܻN~7a=<}ZQtHQGVdQSw+}~;kҒ>-75gi:([.;7a5ƪ9vW 1 !]MfTk˻wԵ֨L(///tP[B!i5j_|._FӏҥNs>~KIb f&V6x[ycrŝYԳ>62˛>> )!Dvs-lx$IN@qݬcV`Le=Ldm;buxSJt%=? vV4 B# 9]"Whd9pE]\z$v3o !D:Œq_-`dw mʹ:-ǩ.?䗊cLN4{϶k/S$lOz+I*p8iss/#?}L+MVgOOOMGvڀ4Ey)ܹI6XȮ3BBkW/X޾ż,}kec~N\ݦ뺧 &ܲC5K5ds†}R"Tyzb(2nnTC {9i={Ϧ.W>HS]~rϷO֢yO/8j+S9!}SYW%%kg tï!cPšH:G۞͢JZׇ}i1hO?s:|9aYزuL-|O].}:x#DhT{]_mL\~h-!H$ȼ^VLmj|KM^|pз*s!PӟqC i; ?k:Dޟ_ @ >Gd&[x-BdVio_6xW KO.n#ks')4wz>kC!F^uQY Ɏ\D@?VU#X`gߑ3wwѥmA!Ҹ==X@H-Ii1,K8&1N;uߣҍ`I/2hágoϲgF}|ƃ @ :Nt(u=7Gc@q-T`. @b=-6@ ̽c ՈTA8s,rb՜pL12~rz;8n^嚫DxkQMС/T Fņ,aǯd I'@kK4iq/.؁Waʌ {NRMxPK.,C2@ƦUhL€N~~ F'b3dFswMW]916?ܴ#~o'22vjbb2o<S \./mSAʨnr݈Z~ٔQK|3lavUqwj{>]_p}ۗCc~Qz$3驒weYvFP\-PuYe3m?6KQ~9ގ!9AT<`e26j!Z գ/orM\V/3 du4(k')3Ӽ"ɇmI@&ttNv)ؿL*S2i2lNߏҳ]Kk2tIzNw#Η(rvv>ڦMܡdw'KߕWm)yÙ]Q]+ _DZ|3e g("|{njo7\Ykr&6Lhi%wՏW)8m?'!nyor``,Zx.2uڶl}u+i޵ ע"Rg'JXTo/_eu ;u,ȀûȦw60/3Wz_ZZZ9+`L=Y_Z /1M> _f,?c/3˫nVmԶc#n$ֵ'RB_2gǦ1͌tu }6ev2kÁM@䯞+T$ʨWM6#y*vhZؠm & ݋LX, ITEOS crHvS>ZYƱ -wa2`\ +MwZSb;6'ItFBmпrvDeL'ZW~CeB@snl:u4jժU6o@`qd" ib0T:M uTǤՍc}]ʹfoKd_o@ݎU5:׷5<3_YF66 *Uh}m9'Blh$=~!HY@ |(r9N~F_׷k0Cɳ1B#j,p$/hi%rŖO85|.TheRςMcCjV=LN[w܄:߫wN-f(v87 eČ,mkAٮNm/3fX6l  =_>SR?XоǺ㻖n W~x$W|dw7w-:e~!̇~}{;%VlJų?oI}vv % 'r(?1#"N(̢Q+؝{&q(CgxzT< 7vdž1oLy>9|8S~ȱlX_I;9cX1=J@zkm'D|OOJߊUtRDd5XjI}N痎^y\*DyH#.纋PEtɝ[ 9\k$ߩVƽ&r0p5;Y?>e5hNulڣ26y..B6,Ń!Lm^.&B6Gfr{;s2"n/vCֆ$ !e{H!OLlnMjumBw~|ח:-F.‹Uw;:A$tac"S\^cU(βz]FH{nJ/](PHOS@jϿ++=2>KrX5BH^"w !iuS}ο[E̪V !2BQ>_ۘK;UuVBO" a$O$!ȮL4g~1Ui0!L4gk-1P!m"_m6~mdO'>{x\B{Ҙ&XEeNɃ={46⪾m }VW3&X?%XmE"^|U/;ߠ&:<@ܵĀ>%e&Xe%e_JnnDs}6+˓`YLJ]eWgqQn}zqzd̦?)bCWv6q 4gϳ>E 68=Xf~ibsGPtQ* PC'R.yطя^ݶA#S9XlWvITU(i̮IK.|yBRYn@$б5+7\=|2⨁ IDATqU¯@r31l>'e`gg7Yygfaʔqnہx%mZAY4l9vKV:I8mjb>gc?y]ܫө3xեŗ7!aZT޵~{ Lqg^pP=6Bεn}O S^:RP -rµ+&w( ƃ֤#={ߔö7bRv11O-p/aU?5bz{o @m.//8uxuK7]70Wzgŧe!+ϪvOMrGBSE&@7Ә"p;j_!PBh3i^ %BT6ժvP|UtDSyn {U uM,Fʟ6V  {9emB!~R`V&έg&!*LXA۪UsO<1쳄7OX19y{u!eoj:R2uM~U~$$n;o1yYíTU)eU;%z=]q2ƿChڰUXJ?ڷK.ݼysvvvڃ7*B`/]8F?ZZjUKOӏ qpX<Ъv+:߫vׯ(v8,q4r_a;v̛7lk rhPœɊ>?2 XHH cа9 F56IB42ߞSiVӘoϹzjݺu˫[nl6ZƻU» ShU',`} jKnv*JrZZZl6jԩ ̦p2}ĺw_dˤ/Noe?\[wvǾ$rZ6q]!p@f'rv_Ʀ͛7NJJ믿BBBj֬pAm80%%eԨQ˦Mj֬yMGW0B+dgg/X^hѳgHQKZԕq6]Hc9&ÌL^ve\wyjA<[)u>ϨlYܡM*m۴~G ^o*, }G+Om 7 ٱO>/BX, IּzEuرjժϮG111wMׯwssP[&XA-T߉~xDZkW tCl;LrP|هhR[U=:~sĠϝΞޭjљf({Kіw0K&{3P4/sY̪D}N痎^yDmw-D\ز ڥt)z D˥("00pذa0ɡ_~6lصk gff3..tDPeB {,8Ҷk Tsԡ>jX niʀ-6iƱ}[Zػqw4̎Nljějx{ê>h\&ˑ(ш"ǂ*6_ ?f̡a!32t_:oa/R"+փ-֘b^eOaèsۃc궝vV+Sh_gk&M*3zѲ 9]^,+Zq**#<̌/l6[GGG(x+)Z{' b:vy zowq1p8-[\p[QI`*" U:4J ëi/egWodضoVҝ؇Q/]:,iȗ2ymW#UB Qd'cZOAzLhx;¶mfΜc``P]}Mpp_m{KU R_S1(AU'@LGGgҥ/NHH477\*'䉌zNU;.MBaI,y"I{G4_GƦ2%d )ϟ]54IkE.)_q'4,fcl_g; }N])mHnzj97aaDƔ(rr%L;8957iҤIzF<2~MMժUsttfW#Xr }H$PW #%'MbUu6ҡA.Izpӥ"Ӫb!_`*~:=ݛ(^߼>u4MR*X;X^Z9zaRIЖoD,WhQyfɇNUZe|;`DK6PTֿRǀ7}^ww|\pGcz5y쇽 y\k ޣW[Er~E/&7ddd577M`432ry%4Q:QwU*n>5yD`$(iMWSP͢l( ,Z r:@Ȑ-74 _`ܳՈEGͿRፗjBBB4ٍ77n|VZi:οQr{Ok O>̣Ka .UOs@#U_8sҥݻ?S!J)BW5ZtB-%&{oTϟMt|*7'@@={_FBAP(fS%%PBYgx!0_roJQFqqqBcx> g8ikkUPQ`!ͣ8" OK>^lt$mBvr6ocyѓDZ/Mj3?}njʦb]ķcw\-P D"L.6l;B[n[Qxe*"0uʪNGܖf, YvN7 Z'^?ۘ%Sܛ[1x3VG7EtY/>  (|Jkj>,*@QxBa$sQF3\S]kg]!=6z4PJJx%&O\ *UT/!./_t Ivpi8t0,<ɖN=5ȽC ߵaNXQ_Y܏"`Uo;y!&8cuߖ8jV1B_$%+jmm*ѩSK | r 6/(GRSyVS77BH^g>p|62ƌp|o?&hXہS[zQRO]GbFΪKzDaIh33gڱ@9ii[yJ3/!TTBg[׊JIVG#ISI=X}#_+PK˫[[#ie> ٰZښLFF&C \dy_]HP"D,$xؿ=2w e̦^<K&7޳Y?sjԎʵ<&XU2C FHΌֵugGfw6 ,=!OcYܩy]Vy:f;eiTD&l"Z XھQRƮne[N ,sKUՊ^zzW} ϮPJ2.Kw] }$Mzzҹ|/VBr"C/={W";Փ{p1ieQ&֯}{E:MZu Q2EaG%C{Eۧ4b%MƁY$:&Wqqqqqq[?wo݈K;[dM{tK~D _shՄj:7|zBx-3; 2'I@=.8"SK+ SBAf`7Üչ/;. ,U7}//9s) (l5?gݮQP[j )$!tȟ"X(^ߎ]!(¶Z,ZfQ+zEG}7W%9_[Ka]oY-C Z~7Ţ IY,k#VsnwC~{rogciiiiii~fu֭Bg=Mȧ.cʎQν$%((۷ѣJ\Ucyjy.xdzA5Z}|K:v F i؞)V4fqϩcխ9YMkBeѠ_p铽=p |ya~W;zW'qBɫ|c''$&5|gkk}\\=˓2U^ ;=s*ҢXZqIi a5/۾iLł>YG)x*bMrU{Kx_[mf,]Ŷ!XD h q@eH.Hj &X˚5k4Ҥ]u~8kK\ԫ2Q ;?Z=70"uL7z՛M %n$iU;]m}&瑴C-t6Pꑞ|?N'* ^쿰%W/Os~[WOok؀∻wYa5P-Tm>%`(GLkn;c GspWCwγ/EC~^SVۙ{<k,=q3Sm־C&>"ʒ3qj=|(3`F$ O]Da-% _YыHp䪠@P"cX6j O'H9فM}]@JV= Ay+p#rP<~+ tV52] }M}.0מ)-ز!h/PWy?ԩA֬Yx9?5<-Z6,Ս=z,=iS-S;ݳcp?"={7 ۍXA l/pgMR e5s=y|iZbRzJC IDAT_+}mcUZz ?6z+ʶwkbDl \eBUo(J89`;y~?{5L޿Pa%n'vl;tbQw^8=6MaĠχsd~܆5Z0w cRlߵwbCky77䖶[ްԾC]h!??e;y4~.1~{ȷJH$2t#.Zësjٚ߻- )*;%as5<<^y)cI׎kl\?bp##. tn"tzbt);8m=lX9߳{zS}fBpDmSfFx l'Ll@/oZHwdiii_s5v)kߴS:lŃ2겪Zy7 Br$2*5eX0U`G2&,xRͽS!إHq/߃iu|)޶|~ޑ6Wn}u ]ͼ*%y"pa8'XB7S?,SfF݉`_Jوݛ8SF]Mc7c= Ƭwf ]ۈm9L:dJ/_v~jU)ɋi3ǃP+zq =[*IzScyVn~lBcdPzןʝ{ls%oeE}}=뾗)~mG[V O˧]耲hU Zɇ9IeLGnK7[v$Kn<|-4ujdDN6K7i߉/n }CBʼH>qy~uDdef1@-5H]#UF 0L%BBDC\NHσܬDkVT؄>v9ІuٲnG>x*{l`y5,2F[$h3 |,+0QZůEw1O?hhScV8[Eڵ Z=+^]c7wKR>5o[¥.dL)+T&pw$r\yp>$BFOSGiڭ:t;i.{ͺ"plIQblE ŧTѢoPP氩j&G%0)Oo~AHޛb$@ϓbAuaQ*KRE]BhG53~LWkj益zA2)PejE/s*ՐuU+zQzֵ,!7_2k}ZѫP x~;+vɿD +zG(.GIV6 )[2tY~ da ]tiƾ1L K:zGYlᑔ}kO]D.W|1[s_I.hYGWF<:X1rbHS/W f>7&'%3'=`G+" mu)&ŋ4¯+mLԘ|(v3Y5-6~~&CJAzvlx^r4d,S,%jS_jY 8`!Ty]n#R3cHm uʺuV;?- oXWtPʄ֯BR}=}UUq>n ( *i^Y92 GrLS̜`'ETeÝj_g<{A<9sxhO,>"O{N=W[+㫗'"bo ԡ]ϋ۞p5mJ*IL<> bϱ}agF#:8[1e?`㎞ͅs.,Șa^k)C՞oйt_VdۚS:Ake˗˿^){һ}:-{KA(Ό׍)k7u>)UP>9Q - ]Ǣ7+ǶR&n/R>yb.bIcz-ڹcgNz7xD._-Zv|Cqf٤v۸sNu*u>6]1~ƎOX)j7iA|[z^w3Fx`䤍1$~LRju䥍U]GGHϵ=Ҽ#1+@o%;>;% BZ8qF ^;Ys6ݬ+F.~;{M7}5wPoJm3գaѮ={`%;3⋿<|ppppp0sR9p8p\ )VKnpsy{kUUO.oN 6Ko{y^q-\R5[>N>{Sz'y P9rM2p":r䈹 yMSEœL؈/yzq}3o㩹zwN~}Qŭȏ:?ldQag84,8zm;}HfaVPP썠 !`ߍ7Ο?o**Ɠ~_.M|sVe]M“+J޼J7JzHU98855&`,×T̩N:7n4wP թS%޾W^L `}vJo ,Eժj`B!`!`!`joooBa&w7,,U L  L  vf.i6l?ؠ/ ̉ljru5cM7g{u{ Yrޭ#cD}vJuyse `YYsa[ >i宒IUoMw'"SпDlTr":^Gf_">+z'=-R[Е<&oNj6RܥYEQ<W rSɤ6zN# TʤߞkZu=g_l$XS!CXP/nۣe ?>9tħn ZM^ӴCs?`xد1i7 m#:[/{NԔ&s~>xԷS{&o ~gR6}tq7 \ueHX~籛:}t+zup(G4aw /kӄ ipP!+8:XL"l|:t\WUs;o~tZn]K!!^6L瞸 -KhOLcuFۛY'tu1R~~I~OXל># 4@_W1;o*,+LH{z ;4oѢE%6EWe?%"2&Gl_؛&B`(瘍?e' LXw29{yșLek /jny'RgD嶁%O) <)6%;<1cp'ae;77HQa#[/:p_3$i=w "/ܖ6xm5yKw,eRQ?7O E?iy]E;W},|Eo:qK6Lnh/LjM;8lRw m9'~P{,!!!DtAVPAMS01,C01,Cx]o߮RΟ?oB!`.ZVV Ϙ*,C01,C01,Cx]<==CCC]5 |}}]zL  L cʋ .=U@i.\m*@*/juDD\.7w- .jsVpۛ xRDDD]Tl߾]R?܅@YCV%hk07ZZ6 f3]y!y!!`!`Wjڔ5NGun3]b:at{gu;mfX3㥟o6ܘbb@'y˯| 5V9{&綻>|1Q Q$0Y/344\\p!##\GgR(x7@e㳲"ƶW#&jиsޮunQt,QFݻ׌@ڵka*@z1+ro'JZ4IgW`sW/]FXo<Ўg~:j$fyk'>zЫKOi7ãk}G\ͨ;ش v];<i"EcȈvi҂KZQ߄jĈOa̹[3 ,BWx*BP%?B0w !`Av''7XwyIŐV7d_JY7j1.&mt &֪CADƸy'ZgLf#Թ\ԫ4u_l)8HD"T xMqXvq{Eΐp뻍O L蠾xS1 JBF|A:dGe#64AHDF67wL Q-S2:'6M`ȉ/Npg W^qL (:wrNtdv}Tr$rV6ԦA%# OUcGF3fWK%AH6@&|scwjm}K'pyS*7 V(666DeB^9#)`=i +'xQG򶓿bDD mpWD9GJ3imGd0 N܎y}VPƩZj$bDwցwI{lXUN72|x߱Ǵ'mo)~D{mm?1|C.S|LCvFyZ Z]Ԓ iʱP!`cDƬhsc-K][Ty19&oqvv5j )܌FGCEu&֓쏪 ׎{C9$i.`~tX\_\|vԒQ%89XV1]hcɺ":#7DFo_39ΩtĹ]m?t4U-/n={vb8usC:z~]䉳{'n8-ψih3LJFzz^\~﷩_@Ņ1X… ]EB.= 4BiSo("뀰/AtusVHstѭyuh-lZULq~u֯ͣ5l92ffdjz^~#սu_>#AD.W"dqRVDE䉳D/5 9">'E U*,7s̾bs՗{IҽwMqrJ[G̬38}$KZ4ٸYyuI|C%"Uk9p9XY_}}(\XSRy"?~)./DEO-+'"2\_&\%'8R^|FƌY7ccbyM3%\}Ε>k'q.7\3Go7)h0vm$yvZ)gDr#-nc*,xg &B>}o>gFdI{m]F4m\?$L<6l':rz7 ? FdLZW(Buɭn\ix|ʱ4<|gTw?| dHEX)A:]ì^U8Ϗ~pO?>=kȶ#'5_TB:̋1#<9].d;3O8p>ӿ4;-rrP2a.o>ֶA#W!3Uvz_DN+-irF\ՏgOn`kz:<{.زzf 3N8V IDATa%eiQhRW]~bv`(m|K+.ۉŸ6Τ#Kܺn{1UElÀֺm?9bʥeS_o9۴6]JDqW'+)S֔wT{vgB'N8x;=aZMDC}zUVM44B@`eq&[?"bá͚et-:㯙Ϥ4^f/KԂK!`o3㳔ܒWs!!!DhEbF|M4yzy᫣лwq??TJX1]8H^"OkO,j<>=%9Ⱦ]t F^l7Pa|ܼ3JW)yUpL"H$bWլYfَ͚˽C/pse ߁o#qrڕxAWU YVA6]Cjt=/}Nxu/ cK^YE{5@ʌ) FF]zus :-@x}GWSStG8WU >z"TkY}2}*ӄe*3̃U ,r¤Nhb?f$yyc56IU!̥mD sm'>xW*5ÀR'/[g]O;E=q])/hY~>ݵWW;Oţ5|({9~Ul'&Ƚi(eU,@[Ӭbv<\D^=)n@*L< +m'ySEXKAu7I2VK\e(ЃUɱ*U~<btƮ" gaku?-=q#!:yv I㖞Gf]>t4v=MKk8ya- Ҥ\>{-]+R󲗰bΝzO$[=~áLڴ`ĝ7TF|AFFL)-|>,͝g]p\hQ:JuޥYmgB2\boŜLԻ pfDJv<uFc^^p=WZ5xRA&nY{/dxQfƩB*s_Y[%Z)/&ɶJUkxqC;_8xQ}L''!KI껙bymi1KJ{[iNw DDƌ[<llĸ?&@JqEb'O{#l…Ig߆q]4m4taDJgL)]+9bO/}߫dW]ƈ7U96< XP1\!װc~!5?b;f=K_YhTA%Bm.-5SU.f==s.% N\Lws' UIgϞ_ (K ̯l'.}F™s9N UI5jdPX`~e<g5qNB&WAN>/ʝ< py"Vmܾ=&@YOMD̢f`ǚҭEgVcmxy ݰKKՔy06`AIo&`bEXL8q޼yf"A*/5kFDYYY$5kfmmmBb@*/֭T`bX&`bX&`bX&i"##ϟ?o*b4h@ 0wO? 틀988DGG .]:k,sWQ `q*$IiX`ӧo?~z꽾z*.,xh4_VReAA[틀U,,u "o۶mڵuVǎ (+,7n;ٳgϞ=ztXihȑ殥bCM6lhB*<*L$ΰm8eKZMzd ÚyЛ>3n$K|ڵk׶mۈo߾v]T}|v&|rV6/ɭ5d9cL{k,Oglpa]?smZ yX0Gzŷzp՚5kz3f7#z(2\}շJzeF"g׃0y/\Hh2ݡ $5}k,ro6R ;_yE`qf/:ׯ&J,<=l "%$ 1*Z1]Jޟ-K)۸;k uLKDdL9v6RGPtEZ2wj/LjSIO&q@ML*w ":G㇆dRj~ܗ H[˧׸\*6l^[^}/oϞ=˖-[bEzzFy`HCutt|uC=D-5\(&bnkԺEi$bDwv}/1R5wIsJK!#bryB} =CTrl\mWeH濥̤Ą+ώЂ1Fn!dDL6x{QLtka'bDJ%2'_zU-zRQQS_')#b-?+[~#o #bF3Ζv%s |A^^z|K>**vٳ(??U )`2O5qrNU8"ސr?k0rHh5|nmŦfdj!c|Ӎ7My8mIHOO\˙ˏ[6N31ڷ45O)mE6n8UM32Խ ^m#ug.>y Cw^;{aC?G_G[sԱ %+4lSu[wԉs+0^h齎WQGRׯ_v'ɓ'{lԩrJ4Yq =-gƎ\5:=#/*`&O&zDT91.?ثn*.UƊ]̫G,uO7fD.sPakZ1jaD.5tTg>=IHDwpX"S+ RyT-GY̌ηA{Ia j׮ԩgn\vmKKKP9 `lm9J3޿{7F"ګ;Oxx!;%%'2܎"+i9T)33絹Yy:-)8pjnSӍSNi(٘tռ>7><) /_:Z~!*wF6'|ODd aV\^+ό4ںҍ$pi;e}:ˠoVbKkT|)f%~ܼ܅tg)nהWٓ[*ںv*;Ϟ 23t|O7]-X^{{gtS0mЌue|ƾ y|(gȆ/=kȶ#'5_RG e  LɛO8ufVގLu0X܇.ӫL@kew 86&r>[r0/<|Jcѳ+WUe![غut?YpH/;eXË$":13ҹ{3.x_|_#2 GɅ[ ŰaömۖlB*%mG;scE; &KRsbNEzL  0~@󹹫r =X&`bX&`bX&`bX&`bX&`bX&`bX&`bX&`bX&&4wPܼy3++U@,--k֬7ndgg}=𜬭]\\]XlFںu9rC ٻwoϩ]v^ ,x....bL>3g,bM4%kE.U@1VXWZ[[[\i.^# r01,C01,C01,Crxu~ cՇk] \8x!`A9cL{k !`AybR7O4\ k"fL0vאKrCV-\wc׷7i+KxHӪ]VDa"/ꈈO;NɥbҵI[ } qZcםyXɥK~s$+/p<<@qw^^8f0'[ʼb"f_<0_DDĄJFFčf93ܡ֝p4O6 Dnٮsz^=#&T72bšdK=Q񹧘1ZWǚ b)8"&ɕBFd'FgֶmbWk. ,{qڵ+#=C::: fϞMD.̊)`Ay"n5mOf-kz;qIpn+.:q.~eWkMFo;Aˋ[9tpǞ3;xND Fn95fxέ_?y uƟhK;>+/kCU jC܅{;K07My8mIHOO\˙ˏ[62vqx3+&(ut" "EM7[{-)9HuA~([3bDr)9.BW)ifvn>S`6)Hž>FƌR|ؘsRn#bDE E,kS2x*',(WV/w_I.C ].BX?xݍ+7 D#2Or ϬC>Y<[TC}`z2#wk_e[Z1]8q]B>w?| z 1Ew-O&I?w|^;[5rrP=We]]Rg)|\/e5kUZ•T O봺Ҿ \}G[h3 ̡>>xߣQ*q^Zf/Wgpo#yp)J殢2CDm6c j]_̈́7:*Ѵ׈fdD$ppΩaarK&n6mo8|]U1 kً:+Lq?['Xs+[T}S?pHZfN[j=O5ƅ̜9sƌJdcci**3<[ O=zzjll bk.//ȑ#Oj߾}NNѣG˾*x@++saömۖl'O}])]MгgOs`bK  ʑK.噻 S*|һxK(_9qℹKo01,(3C* ޭ;cWQKxkI+ ca{eS%s-Bx.ʧ+7|\)??UE][ٗj$ƉBcڵ[ ߹~Lss+nZU%11nݺ2F IDATPҪX\1ֶm[sWQn`T#gqεUۿK&<sT^}ܹ1}tJ+ksPeĞid+$v0+4F+EbX@ 'ytGx/5 ;ٻ}]Gw@nw?|ݡtLvuxlW_M]Иrt˶OL78cWo-i>⠱YfnZhW K6ǝ1FLqІ eOt>w6N\ υ5rQ?OzMYh`] "3c~6iK)zF|6Ľ>N[ݲ;F"D ss¼@L|y`8ݻwWm600Uڵ (z9kUgС&l믿8y_ cDGaGuȯ> t4/Fۥ~cg&kZ829}ZY'X|#[pYwtxCkF}G*uY"tuwq\V}_FdRQ@g3f$$bwppپͣ)jrĎ̼<1+MQ:}O2GĜ03,fWdjxbb{EqSs <XT)pȱY}sg鋿 2xK7!WqtϘ6)%DDĹ8511%rv=˱jnSӍsc1/i ٙIKl_?`%SRy"?~,l^nS{ =Xϋ{.NNNN5z|_uG'5\wlY%Å+ }}oL8:BⳢG=8aHKI3qrg[1#%p,>f|lL9Srwiu?S*_[Qb$j%_Rn#bDE EF,k#~|u\^gp3E~3N8EMTb]կw Ͻ+Stɍ#čf7 mg+#'|ODd aV\^[ό4ںҍ$pi;eڗoiHwtu D|ncdg3@iS/Xp(a/ihMݧ6rAmIJ!wh'(83;IR榁Y6>$@1x@71ws7[{[y:qd6hƈ2>c؆Ul i96rDd4{o!mXnV`ow`/9_kL:tṋ놻 ^}i; }Vk܃ ҸUЅsz5p H`- 37nRܘ%mOL$t{{Hc|5>XwX )uB't<=9IeIƢПP$x7Ti?!U~2Y? =-EuY<}Ý9qW?OhLZFp޶h4yho9=K[*CL~J`• y*`qC#4޺w:O8DmWuŽǀ~*IeRɟQm{ol'ug|2_/bҖ7n("ˠw:k-#ogNO>'V ?AE PpP1ax1+5ǚS?CӁs=w$d3زKO(vD _; `1#C:L@5֥_ha]qV Vzzr>Ρ;w> ᦯[Z]\*؅ =XbRϟ+ ߽jqɹ;WV&! %DD\A٘"Oiql,d&P$3""N"1^>5:HA#u+BZE~oҞӥpv NSrO?it~uYwRr{~XPpPnq??yCv b ^b{p/~mʂ/ ɨ3# 6Xjui;2c~=j\Wc2fs>(a߻HKk8ya- Ҥ\>{-]+R󲗰bԤ7n9Ր2"}{FO:N2`U W]paŊwd}/+PQt̹"-eBA!ɲLKTiRC²E1!QYgwgzzzz/,gDQ{ ]h:*U_(tDkk// Bli-awOg~ME'gm?,gw|>+R}>1Agc\mktZC1(5l#x*\-2D2`4FD\ֻ\z(ugّxYwuOgrw%oiOEo4C#z#0px>$6%ZΊbcSqk_zKKڝN59Jr9N'ux ,x>꛿K=?moћ7 #~n'o9ؾ>_f[?v;,5??C3BCowYk7wwC7F+]zR#T~`0CDAƕ'=q{/  "sNa?Cb?H$5q%HijQU8WT=+r*)qV9"dvs%Ù 0:jy` 'ANݲ(J]zGw>O5}zoAy˿kkkZooN&sʯʟɟ|ww7~#Ht9|=OSDbU%-nn~Rcrs%*˛ _$;]JԘ-G3D~BL_7mǡ#"9u&3VYLdmqPQf^bUI帱m2XtFjT`i]WUD*))w{ǭ^8^ `~(~y7TA{á?ǩz(Tw[IUW(Oɜk\N&g.فFshPKyӕ6[@D<>ݍk:c.[{i7zowg-oܬ32"x<8q}>FpF Ĉԥ}-6~sؽϗVε `[DD<y|wBXmuFdzpgFmꬷ Ď,9ucU{ktxɩ"( gb8qPPrxqbUo.ӝSZJ[ypt";U2B;M/!"f5%Zިki՞Os ' f27?~reqi؎Lv<<8֊vLV8cZO_)v7S$8qP8< %-.VRnoCk[n-1|w``~J  Neddh4 "L^~=o%w}U|b)\{` +[_<^yU]}ͬױD63WZ*Fg'a[d:kvrm%T 5ֆ,PɵUz+I,DO$zE/ ~ ]B>%II棏ӻh~%S,#"t`4lDDq7l<>4lhڻc'NÖecj<>x+t0 ˆT*ue58'^g; tHcߩ;iӰl^/@`eex>~WZNi ^'QAASpƌFh|i&Z;[srhg"ux `kdii)L&ǽ^o+SFht~~`BI&$I333:]Yᜐ$izzt嚚*//h4. N ]dJ ]Ňt:;99kmmsDWWWKLNNJֶ϶>ljjElX,.CB<,**Yb0jkkgffyF0LٷmQ* 'S-,x-۾3#1FDˣn*tؘ( 666aʆƍ7n(tb8Ν(---PHQAsgĹC[X,w*,cIҲsyyyyyy!1QD4e#@A!`kw\666Y8pY     5"IT:.t!"DQE |W>ud~щ+[N  .T*1;;;::jpFp8YeϵG ѕdmmu:n蓡M)o[bcccccU !ё}gKuA'ܭ1982䅮cGj}bx!,s `Ţ7^]"򋇦f27?~rH{?2UfF|n1RɁ@Zmiviq9_Y\XxtNFc)-oQ,rxaltv-ީAK7j z6΄T1'7h.)RYZ(. "w}[*+>|rwwJ)'WWI;k:.5:D̎mFS\mrT47OBIKKoӷO{7ʴށޢ7ّ̡y^u~84d2d6uU%lWOl(Άb{ pSާ#KQND~xol3KTu.RZ1fO)j(*w[ӡp3Cw߾1= iCq ^^$sKu&F*,l$+ʃGtX6id"bj#w3os9*:TH[r>s𖙮![X~(ݖH_YUSiʋ􆵘8 KHB3J.INL-A""7ɓ1UHrKψ&۲LbD,4͜ 1^DܨŇgVX2Hhse_O?[X"I'^_ 3KCkezE˂XXѬMN>$%dSJP lHQncq'~Y쮨7q}kbyMtۺx4ar"-`ofΣ\SkOXizraOztX,611`XsN${{atfFD3Ӓ5{񅁇ck]Ǖrz{a,5++>SG:z{{ ]@aTtl}>mڿR IDATmek;30]շzKDz"\[MH,sRr&ǟ-S!Yt ]倀g"Ny<jL&ݥ&v(3DDIb.v}Kc7 Q1`(EèY2sVֻm"))y9Ӂe_pN1ŢO٭ lըGӭ=X*Wk|lfTNznt"J\k Z O$zE?MsA37 U:GWH+R卷ZljZ_S;<7Pq'E]YFHp,LJ[$bȳ䞅QB3kQ9UeSV2Lc&0R^"eȽ-*pDmY{wlh EcquY>$ m+ gUnXR0c46>13{l[ŗTji31!&ÒhrvĝߟZݞx:6=e)gBb#L.M sɁp~1Ho,1{z<'Llk]^^.t-, K+W\%(ڝE?~|Bw^ X2KZ@xpֱxjknbjq3Jk674%u\Z;hLtbiuIEDbt()pSesA,2]/~Dj\%_4EZkYcg[YES˾H"#h VWeCsSß؅ɽwG'A+&c5F^$K#[-E<箩NSgқ^ 'i5Gǒ=Jvi IGN8666 ^XS>sUm)ncgη.WXz'r4L+zL!rzGĨ.IZ{GKģ7XKWj-<k.OSk*kMv1:po`5_ִۑTcc]~ꎜ\NCښxUaRrƊ|"'cvd*ALjHk0l+ HD*^K"I5^ոDDL:ԌHWZYY[L% Kɽt&>O$f=ePqJC dԓ'|D*ܜuJ|cf|jIʧOFJKڝU2IDDt:CD<XY | dNWR'bnw14D .%cq<˹w= XuJhD).K6$syW>' e&:82/iV\ommVO[uwcGf?pePfLl+OQ3"EJ"ɉh\Lc0բ@oo1FMDdItk+wՕXThs3V5^^&"bƪ2Vň[㕮ICDJնXߎl=ԮWmKAk)Si`D$XsD%E48*[]k2v\akbz{{{{{ ]Ν;~NSZ"/?(Ҟ]š{OӝNa8_ys>ؒ2H9_|)vra*#Ri̎措SL ~+G^y񀯤[rIC=;pA&wxQg0t"C\*{ۅ.l!`3rxaltv-ީAK7j z6΄T1'7h.):|O/ͮⲠ/r׷zˈBt)Ξ\] &IQ:0;2:MqQT67+BMMM! %B ""_0xj7R3ƒbBSxl+l^mJ=W(<^J[;[+'Yķ7|,g(:xbCq6tt6]__̲=X@D ^dzĈ[deRYy8( 2-LDLWV`.w֖m.52SEJac_qn72U8rˏ֢4%+j*mByް3ǓDDR4\1HIt64WZedh$vSgzE˂XXѬMN>$%dHJ`?0Fpfv{cޯ>۝bwEMY:@K,OMxWi.,Z%S5FKWbcC+$+z,NS[o5#N3zo(ɑ@L"X7rs"-naA<#I q9-)Y,9WNmbil6w2e籜< H4E2UֻmfA-<=i;26W5w~-&7},y VhJԓ7{=Rjݿ%W/u;+XK+mV>pxUURZ^~2O}oolMMeYW_MZ~<-opP`n߯qK558w׹rlZ'Eg?64e#EVm#>pV8c*UtenrG}O Llr۾G"3KDckOEmMde~}jhRD~Ig+*v®Ɩىř~<:50( [J]z]QlE%\oK87.Dz`(m-֗W_..e\njÿ ^_%i3Gc vϜzybO7.ten:hԮ"##"]oO^zu5k_KGIR;9F D#1^^\g$k1Ltythr5-%qW}<+2Q:0;2:MqQTO޿3!x̉ͨ,K;:jԇVeTwFU't$\ΕrMjWpQ.'~r45VRkcVR᥄B[~2x$`MmUf7=<rOR]bm|S&#i}SO.%V N?]5 UvٿuDD('"ⱭR{)6d'|a֝bRM nDot4=M.H..KcwWQ1Rj+:TH[r>s*ZkUGkhlXEܭ6os>\R +jםXJ`yeݗ;#'+j*mByް3<ʛ۪Erڲ_)Nc[ T (*ۥ٬zb'W/t4"ȈDW[79:4HgL:U#c( ':|O%3iY(Khse_O?kX"IUR,&ffDDLR-Ov]QSoVSl=ݖ- cI?`FsbR}̿RmneTNKCFji*vA~B/ <X:[۳&8`omvΜe\ ;~`\YǗ^w͞s~]Җ~ߺ6Q( IDAT|E\FNQ! rdҒ 8xx VYﶙedY!"p8IӚL:cnvFP chԐ nSL_%myGFouƲ/EDۙFcPDQ?);-q;Tչn"Mji*vAz.My$7$ץvSCSi[\Lpr#ǩ©bZ)3Stu~EVm_R' XZLp2ZQB3kQ9UeSV2LF5xry_Ueot wsnjsC""fQm yx˺{*$ ҃ERrf'&š*ֺ Szczr.JϑSm,̮%-=-./_m0I3s[Bi{OQ/wz,|PSQYt(3s垺"yubp`d~[_qɱss3)r`f픶Ԯb];CjsUEwE|Ν;~NSZfߙHUxBG)_,޽R~x,{=NWZ.i\".,--Ĵe-%HWuQ.x|;Wlu 3N݋Vpu/=XygXygXgC/& Mg">1 ]MdoP{vԱ<2u~+e,/Ko bxcV|sVҲ,KwC*VߞD ŗ-)-o~,3PRm-*)'O{7ʴށޢ7ّ̡y^u~8> stream xXMo7q ~i|@!Pԅ䦲Ӧ(Kr. AΘ>< W B+%VF >S%>^6<"~n-βB -K|m޽J*Jpb֛2 f.m%E/qR[ xImsrP P˳]sN[n;Oi7݂lοrj1ܭІx^@L(A+( ZQ*swƵCwxVsVACW琟KS"BZObfRKٞ\Gى{,R64h0؄ O{Ӿ]jC\=-m5([E_&Q&Hh@9̸@/b77I ӛQQW (`U@k6#hEQMH+3"nLě(c )8pRʆCѦܑ|[G );Rjlr2F*$IK[M$y8XL*&*νLɪKNSU3i2L2 V2yg$'t ;N^рĢ&(Z KNL^u&0<~ N|:'ϧ˕xt>;ScxYճAHttg7vlǷ0M3aW;fD-Y$7^Z7V&#R\ E@lMEz i2jil(UMQMTw.6#xUSv44ǰ!(N6))8U2xKeG &2w$Em xWGT87GSWy:[Qv7x5;60b1nk=s4含w(hDD~4p t1 E\ \Q8炯، mauAQv=${#Jrwj3gFCyQIpܛ6y+zQ9AU58XX.2bw"E4-o [=,R031S qASpTN Gk75QP =#Q5~9B5NLDV/K^g~)t!ְTnkȫ8AƘ5Srj2R0f\eDŹYCA/֨-1d֤cXcCe ^'4cM&50'f,p#4uoDi LiSLCF_UirT57(,BTFhғ&& }wТjoQ\k/<Z%9[ ,1[XjwЁw'I2qPbR7wMu̢T}=l@ hR0[0w!hC;^؅->{e1'0(ӲEňċ:BA4\ BnG L66n62~G9@2|{uwpoǂ;3 ѯ5%~@X{_GV蘪AƝ;Lѻh;1R"O;ޥ]빏=]yyWv]{9ƍRZ?_ȯI endstream endobj 5 0 obj 1706 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-1-0 7 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 8 0 obj << /Length 9 0 R /Filter /FlateDecode /Length1 3844 >> stream xW}XTU?{gTJRflu,bu15$%#P>Q H \ʏm%aY5WS  iuKJsPc*}hُgsV*5k8ЋJ[q?GGʛv.ZJDqKr4A4z?L| c^uA@B 1*wwjLy=9o[g{ӛ၏uc+)!]bҀOKv[^ 2B0x2Evu:^%aKVz\t`=GlY Ofl\uxMޔ_D\T¡sBr𘓳8^>Zh ~Sj{x1i{z#&k'_^VVr[j+/4Q]hħO Je\a\jQP-._# Ih$! QFv~KxFKa-ehGz;Rڢ𜋳1?gɰ8Ք'ol,;A/ ~zQ ΎC6Hj`\}KǺ$??%&e-Zue{G}XZlQuu.oHy\7 %0J!  29(c:`hbFF؄LmظG󊮆;]ꮴNZݤ56Hq:,p{: "/@-L0 GFbr~ s"`!SaP`t^ s}6cf~ Zշp:2{E] pCOu8rR12nA?wv<}ώH)e7RݐF  tgۂΡ>==O M~I?.GY$'pL")$"!Ξ.3^K6Hq /囹z {k8C[apA`o+ck|xhqдangB;,js`;s/8fSP*2OT_k]+5; l|ed <ΎZ`s7ƕt~Gm8^Xkݪ7].b^G^iCok8!O<$q1>>3KJlXnSFooK7O_uQ6ZMGnؓ:#*A} dVxhb5c&ˋ`7+l/ב,]XEow\a9OwJ $^3'4 2DQȍdhkM|6(yx|;}<ˠC` B`?%4.X*6&Mpޱ%4񰟶0^uz(]OvJ=e'iׅw[vIALbA|ȭ5 XBl9me]^^zM,lM> "zn=E)a/ p@+F0rF (4L+!VS`wpL`}nГk;\Bꗟ9å7ć>Q:kSr_w^o6-~o9qa-S1V 1M>t_ȥ^ѮCn.;'S#:,K%/0BB_?w@.~|Q""mC-M%[EH^3Cmd \g"73 $Nf'd[mާNLHoX-ϕWڏiPݡkw]_N:;COvo^~}ȁUF y69|unYЙ$#Yl֭!xj< rX[?ՠt~,~9JBY 2^~4ŨN0ϼP/1dI"a~4Őw,cf<F/Zaߙ4R@C/9cXP'e rKᤝZ.swot ;| endstream endobj 9 0 obj 2748 endobj 10 0 obj << /Length 11 0 R /Filter /FlateDecode >> stream x]n0 yC,B E! /NNKUfaҎ\k(> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /DVPPXE+Roboto-Medium /FirstChar 32 /LastChar 125 /FontDescriptor 12 0 R /Encoding /WinAnsiEncoding /Widths [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 568 568 568 568 568 568 568 568 568 568 0 0 0 559 0 0 0 0 0 652 653 565 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 541 0 0 564 536 354 566 0 255 0 0 255 870 556 569 562 0 351 516 333 0 0 0 503 0 0 335 0 335 ] /ToUnicode 10 0 R >> endobj 13 0 obj << /Length 14 0 R /Filter /FlateDecode /Length1 3264 >> stream xW{PTs]X%.YdPc`P*jQE A|Qktj vL8&>4M58#ՂbMQĸ{%1}zv{}܂k5Z7,|iޕ_D%mX$ljg\rzCq򂒲uh|%9kkt#h\VSV14 @!Ձz_&^ң`F'k!C`(n1KuOfJkC,[Ζ+%lMn@ztiC3b, M?v`pfT9h]<0Tu3b 9O%]%7`sQ7ۤ:$Ο 'ޭ%3 v[Ƙfj PhX-6Dm\w̜y+A~+rFvo!wd Υ2V1wz֙r;R GWRUlRR#ؼGƈVkA4sVZ^Z{Fx{8@UI!{iI_=yCn\P2mQtl.?p.k~/nQKE!ĎGF&5(y^Xĸ\wwcv/M;֎/ډn}QkX@5C=zۊJ>W (&T>թ`{~L% 5# lS Ī%,=* LÃ,*?zs[mOZ>3廩L+mcǏ&ϫyC[*Jard}RAP!RyE$| t~bO0^fX5",c8ߌΣP\?k?~8CJ||8 T2 Y"PJ;^jۺ2;PQkZG(o4n+ AP ]1w7*׍pCWNt|TrHQCS9nм9nYrv,/eNL2QAijE/_I.$*%F⨞(R $0UɠA#{oea.  KW3O_|'$/YT^# J{&aRqb=[_0g"oUtlBnU/r߉?~8~]W'J/ l=z٘efv=>&ݐl\}kW5k_Pw6L N)R"h95J0+ΆTb! q $I/v4wiHu $[!T[/J UPHULx/^kXD%60Z'K3ӻH2"Ux<%ީAC 4Sӗ}P/:apx7xc,4 endstream endobj 14 0 obj 2240 endobj 15 0 obj << /Length 16 0 R /Filter /FlateDecode >> stream x]RMo0 W*( I+EHSwF=U'~yy{ "5Z3^/v.S۱ Hɧu^pl}? cHW<0㉩5/P}*҅nD(ru~XmJS|[9tc/(LY6`ݿj)~wQKҲLAZe0Uq ֏ b^eb"̼&^IH=dH)fzGXSg S1d/E})R.{As:&{OM~$בT~kW2N~,}cZg~Hy)PV~ݯ endstream endobj 16 0 obj 356 endobj 17 0 obj << /Type /FontDescriptor /FontName /BFNASH+Roboto-Bold /FontFamily (Roboto) /Flags 32 /FontBBox [ -913 -270 2060 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 13 0 R >> endobj 7 0 obj << /Type /Font /Subtype /TrueType /BaseFont /BFNASH+Roboto-Bold /FirstChar 32 /LastChar 121 /FontDescriptor 17 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 673 638 654 0 0 0 0 0 0 0 0 541 0 0 0 0 0 638 614 618 658 653 875 0 0 0 0 0 0 0 0 0 536 0 521 563 540 0 0 560 265 0 0 265 865 560 565 562 0 365 514 337 560 505 0 0 502 ] /ToUnicode 15 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 18 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154042+02'00) >> endobj 19 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 20 0000000000 65535 f 0000009777 00000 n 0000001949 00000 n 0000001821 00000 n 0000000015 00000 n 0000001798 00000 n 0000005774 00000 n 0000009326 00000 n 0000002167 00000 n 0000005009 00000 n 0000005032 00000 n 0000005476 00000 n 0000005499 00000 n 0000006241 00000 n 0000008577 00000 n 0000008601 00000 n 0000009036 00000 n 0000009059 00000 n 0000009842 00000 n 0000009959 00000 n trailer << /Size 20 /Root 19 0 R /Info 18 0 R >> startxref 10012 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0007_Examples.png000066400000000000000000001413171415120503000275340ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxg@Gg:厣HQzE.JkDEQ߈-hLXc5v ( UP@G?5Q|~_ԹV8J) BèB]ĉ#""T[ B!P|rx9vz۷U]B!>rblurr QMEݾhA!@.IMg[KifCyx B.4?>?)DB!TTI!Dt/^L ߍ͒i );|yg lThPIʨZZtl(s22zl%|ۂW5o#QSؼ1B!TVPP=o)O6v̎̊pIKqܲb%r`YfB.E,5iJ"K ʩ:5LZEp_( `wVBiAuS-Fm /HXږ˱?~@mu+S M;ݗ${}1^.F| #3\R #,|a#s3Yli,q5 v$OB!qDX+DaCM5VEam۹Z×B2=SkHHLixxj<`I?eGgL4η-PFrBR /frkE4IzFvѱux !2iYQIFlBADxqOeJ"k>WiKtm ^AKKB!͑Xl+3dǤ%@s_'8sY m}nrJe%JK_^cX糁hhj <>i9}eY/`\:x6+-]viV:v1`Z*B!Pҗ OF_,q*Y<5WF K?i60k\زYX͐JB <;\߱ETyۅȚXDܸS~Or%yyeTQ/2yo~pfڱK{SH P+ &B!#|?)+[͠E;1z]z:յmc[ u\߲l Omֆ@Ϝ,uіIKJwCqڍծ6磧A2YiimTm;{CFTص}7 4!c-s߉6@ɱgve())yB"DllAr ivX8[(2=dbumoby=3{JfvoNV6?VPLSSQ i7z#hܻnWА%-u-IU| LW!P_ Va)h۶mQu-!t.]b0]!BVa)HWWIU BsbqWG!B"D!fB!,Bj !BaB!fB!,Bj !BaB!fB!,Bj !BaB!fB!,Bj !BaB!fB!,Bj !BaB!fB!,Bj !BaB!fB!,Bj !BaB!fB![ W,%%ɓ'YYYҊW9H$jР1v]B5RsȘ77H&666vpppttl֬Y۶mkvGB_\||S] M4oMLLtuuutttttX,V}˳srr={ѣĨ3gT/ccc77]v޽AyWaB/%!!aǎwNHH[[}m۶b*͂rFFFFFFGGG_zڵk.\ dy&&&~BUF*{xx@HHjAz@"۷o׮]cs}޽:"4"""((ѣ7o$9K |"^S9MaBjhѢ}:88 :to>}Q{ݶm[\\X,5j/.ӀB 22oҤGqΝɓ'pssiӦ\xk׮K.5778q'OjfBܹso߾NNNgϞ1cFJJʪU7oڪ!{쉉׮]kii9f̘G0BM0uW^={vRRܹsuttT]+lْ0zm۶ϙ3G*.9 X!([l^~iRRR̙#U];XÇ}?.^0`!ya.]FѸq㰰khh*iԨў={*Uǎ{cUP !>ƍ6maÆPUW<<<"##.\|iUWP= !D"xyy=GF"OpNnddԫWYf) UP !>,<Ŋ۷osNͯ^'B} .1b{XXX۶mU]1dȐ[nD.]8qB T`BN2e :~xm[z5nڵkNNN۲eAÀBoP(Fd;vp8UWikk;ws~~~K.Uu9mBu27o;wիӤSWW?zh'O!Z !gwB6o, TZZr0`!jƍcf׮]lvUT .LJ}j l߾-Ru-B_Ç>}?hԨQwR>:p( 8_kǝ[.]pxUׂPm !*--_4i2f̘MpoM)e[873'',EV\Bxm'D\Gn*ssfD|._lj# ]^T$,mcs3 Ppp6CHѩ?oc#4<-.#DlgF">O%3wniٲe|>_J)ݝ"Wc̙K1)m3 6>QPJ),h le xpϋSi[۪EK66؏"of*>ogҢcC b$q an=57 ӯPJiٽ%nZ a Dbu6 f3WtR8vؗ:BuV4#XQBBҥKGwwOvwמ9{vSВЀ6als~BBˣ/]˖'\-ttƒ۷MoʦG\-9c`5BBҫ( ^摇ŗSnŗBN]?={cSŝqr>r>huZۈ)\X^7M0I&'N,+[B_ŋneW&ʁeأO+V>nJo}X[KHqFD=s+_TQ]bcĆgC$4|?1s2Zq'N۰˗'%%mݺ zB諓k׮QFԎ!uݖDKoWavG߲9R PrbwKcvQ*&n6A](Qs1Øڲ{Zw vʹZ xP@ J)͛7o޼9c-).3SE:uruu]d\€ -^R:qďOr6H@!1ucޑoOyĂo?U{:6ӍG޺!SQ>;$8!iN?LO~|BΦɥ~bD]$ۊE u>}iӦ%''ٳ Bٳ-[ :v9'N(U C^}τ$urMs{{j{i΃0T*R":EzZZk\zN]{'Qbv |ƮRZp۟#|W^...R}}0`!.˗/J'O <+j4LY"߹+qjn&TrήR @e7Yh3mnX{~aΕYnM{6l9aےLC:hy!: umsxۼMR'O9vؗ>Bu,Wt}\,qF[Os_n9j96,߂ }K &"Uɐ {;j<t#K{{ M:q9`jVf"Z'հr̙-8?˿<<< $$D s!Cw)OC G~ڇwPϚ5+))Lյ z`!"7oС y;}(;]޽[Յ T`B}-RSS/]KoS9BXD!FFw W|iT]B,b߾}R///UnZ޻eiWU]L <aaa.Bkq͛[ZZzܹۛSՅ T`Bz-F GHrssoݺկ_?URhiiuk@5}ҷF8BCs 3C!Nڅ*ʎ;z{III.Z(i(Z;7. QWWoٲ zAAA֪G t/E}PHXږ˱7;m׾Ra%Pk: f.N%w7t\ TPЬK4M{M;\SR\x}_~+dnnnnn~%UP- a;ٺsBKwwv?I&Z};ERy_^C$7cbOѝeoW&;f~sNtWkOx}+~KK~\=]QIdtVzcC~Ϙ io[,%),:%44RO?ɐvrMxٰ65 ғFrnx4Jn^vuu HII%#XӧO'Oѿm۶U< U++x?Tjqo <=*2E.FyeBx&#ݵur1dEo')fhw]yoŽ""j\T|aA7}"6a))M- <wVAпS_yNώ #o+b±zK nEq ٣S~\Giy [r!]P~aLC^r)hկd̺] |6nCM2m'NK~ni% [vBb_dwCxaDlgF">O%3:q9o&v\ppp`XQQQBzkȑ'**… ˖-;x >3pJ%b[;p)-+)m׶7ddI%]۷o߾}s=L Fs/=vܲ8m4y& 3sDGG7m3; +so2M9wyvθ(4siӖriԞg_/e:x:rcߡc;u2nCg2%\9/7Xl,z|;p[_(3a>v2i}Cg.s]8zhvPR9MV}6pTMM &9s"l!Tlڴ֭[&&&>>>[vZWիID!&ia阹2F X'lZ T`c[=_ρ1p!`roGnd[{>p~uO1ը勽 ,`iԅn Ν]>.).P- }|TfN\ڿI5|>sfv/(FMMM(,,r@!RVщ'vh֬l߾] xcqJ&M6`K/-55t˖-!ը.z+??iJD"yuaÆUK\iy<x<O[[QF|>.2YN:tȑiӦ͜9ͯFT*NTn}0`[>>>>>>  }||.]Zpi!l555ը( dׯR/b@YM7DÀ^1iҤI&}xORTTyΝwZj̘1_둛YF$͞={ر,\}9cW<>! XD")++%O444lll^{bI@@#ƎkjjڳgOUՆ:Lu֙3gJ$#F̟?_WW%.T,P68 Ɏ=ZRR_KRcj1>>>o& :H3cI5P ]\\FaÆ }ORZZ x B0`sGN4?>}_C27^ > %Sӷ/ zjRO +Ir$аH/0=LQ[@׵34pdXɉ2%Qhf*! Cz ՊϞ=õv,,^l׮]ڵ2d\.߷o_UR@cc]]s+B2+28ts(-+-].(r`YfB.o:z$_ @Ro ׳"K 1bOPG7* JOS5okګϾ#*9} ; =4ZLίog``PD€UoGEEU,eooPGeE/-/ jtxѶmBkk_F|sr -M 4; aZY=KʧDhb4<<0D RRR>+X,ʼnSV+"ֿɕJ%t'm^5sޠ v#h8kV 711ܼP~R*{ٳfٻv྄# JK_,)'%켊[[WXk)$$d%I(M"-^AƓɓL WK -ˈ {IJl%T* {ϊK%ϊjL ri;Ul{5 ى\礿ؠH;rF92ښuib$5ظ Yp6Mʴ՞/6k5`֑2M>c [q ᵝ~W /2s%˜jR_>(ʘ'O2l̙7~٢`mVaoPR / +:"NE#hϨsqdKJRHĖM"o$pĦVb-Ibz>\.BW& .*:fN,RI }M޽RJȧcnR`tڹ7hd7r.vX e4 EWuax L^3{_K:xc7ϻyFFFہpغNVTc;Ge`0ofkUz~Yfo^բR5 zvf1KɉIspWX։uDo^~cٸ8fV Eb]Yv<.]!#:.-l>M~N'+RJiHERJ.Ȕ*k~-R{/Uh=>Y~=$%%}N'Suݴ[nH\& @ ~ NYU\umRţU<w!_Iia /\"Tsό2p؏"3\5swD9ҰYlFg2J+o%5MNَ>B!SIN ~ϴ~svP]V9M%B&"v 9[1'JsZ_SoBCCwѼgoQmOΚChȢR+10 ,fM@܀@%y/&?u3KC6} (}R雃xwܸE9 XXB<<<.\9p[8PfߺW?[:Vźb27a$ųgJF[3_eOH,+ QF,[9B ʁѻ-OܡKK>Ego.(Oٻ==M?J](2k׮ B ,T[T`mB>*_4.B.Wdqƙcl^-X7柟䬯k3tc}6-9cYJF1aTJ߈Ss36vvM\R*+U=i,da] e|Ϝ9# ۴i= T`BŻ`!T lmmMLL?9^k/lاcsLM.N(y >ɝ@F^ECm>fr|| <.*YF-_d `KST线NP?~K.8 HŔ Qm5kZP4u'==ϵ2mu'q!rQA6t᪺;{ln\TTBu0`BG.UgKTTN.ڳ%/Kw"AHOqFUR-X@SSs̘1.Vm#kOX=zwIhIhGJ 9y&d0 zy{j|a/܎/~z~6;@}|$,+?77aSf鱗YF=ybbyj@V:udɒ2UR%&&8p_KK0`2eW&ʁeأO+V>nJo}Cв'sIAAr`{y{qX,ʯ,:~SEv݋vʮ P  `hQĝ^?Oʠz=B5c;wTu!u؂ lU]Bڥ8$Pnt* 2j_h1LjaY~7=0,tv|{mςYD}O<\fԩS_6WAsaBQWW?q… wѢE﫺jv-Zܻwo .{B!SN=w\^^^6mvޭꊪtѢE;wׯ_T]B,OOϻwﺸ 4'33S}O6mذawuppPuE+BΟ?͞5kVttt۶m[hqMU$FǤ*n~&M,[l4hPV#͌z$WkIBYZZ:uj޽O>uuu2dH\\* XuRRʢC+k رc>}/?۷_ZX4+ƅSAdI[[E]9wQ%hIzSAEPjyuo\j !>wLL̯zƍ80::F+eeB==;;{l<==V^}Qє9wo T@%FP6m̙\-4~tILztB9Iٖm=Y'd+ WWOT_5+ X!8 IDATBEO~)GGڵk5u|MVH :wmڴ֭[jj5kY6zB+uEI$RaCVCCQy|]+;K 56_!) |>X,@P%+ÀBKWWw޼y?^`Ahhiq/7rU'dkkھi~{6f+W_CiYiWD]pA!"l6 r9}- sg70aѲ ?w\XRL@/-((Ljr\/BUMMͩS:thK,Ydې!CzꥧWG| "Pp|ݿێ]JIym[u4q`WrP @GCѿ*Ȉ {WCR+kcoh/f&fSۘ"T`Bꤡ1dȐ!CܹsΝÇgEݻwwsskӦzK‰vE> ()Z߰K}҂ɉz ߴOJKJ,a\vc+ 6r9\6MX:m$ 4'Tdb#jRrJX 5P߹ +uÀB_̙3gΜvԩӧOϟ??dَ͚5kڴi&MMLL\nU,))INNNHH~dddDDX\\<&O_ cV$+JJYغzXVb>>NNNWVV1K]]][[[GGG__^SSń۷wԯ%CFgﳝ*p !TCOOOOOAdKkC’f瀅5+0`z%;;eT 88?Л T"XQl XcK,Gw!P *65 zKpݝuqqU'$$̝;wҥʮ!TP=k.oooeWu=z(+"""** ֬Y3qD]]]eWlP=pjk!5|LPL2ECC#''G"o7oVvQφ""PiӦׯ0m۶k׮)(gÀBuEQQܹs]\\`ر:::&L\O!Buŋ+WB@EEe…W\ٻwKC} X!T'^zĈZz8tPiӦ(6€BuÇ\ l(jŊ/^TVaBu´iӒiwqqIOOܹRB ,(jوN--SS(IF2KWk}}K3 a;"6{DzzzՎ0`$qew7?)QPںM_RqO"iC;P "'w{0`@ٿ]VPZyQZ^^xf(MXۦVVd2iCc"?rӮ˪B `B?Efiޱw+ & g+l͡m P?uV?҇dcs:nCg$auYS.K肸mh rT\^x&BXF7†8X:ș?I݌t^nmYL_j^X lBXӯ:'|6D²_TpqJĵ[V|RiʟڷcJòue4]~+ULO$b֕Zh0Ll4YP\.@[5WԡM!iZrhL3JgMtQL> Pg6qUbj .]m׮]BB43Xضq wm@ϲ/OPzp8a;cpf{,?qJȢVf)2`Ʌj5@V "A>fV~nn_},~_^6?7o\KChѨIWo%KѲ{/W5#R3L} YAq lڋ;zz)ׯN]HhIbliCZǿ3cQX O&5kWlΤe$wYx4:1䮾UO3Ɨ5P*IRxxZ?óǂ 8f6]O~ UyazhwB;}My"2"K0XNCtYڹGcvf(Wj"<k^ )hԖ=3:7fY=sDO&)jh(+?ڵy͛7|"KKJ?7_ kCϞ={6Z,8CyYr(u}=-u t(Envg>wM $'7ںFW[eO A=X4M{e +Ni^CLMM˦(Uc1noJdZ4)ŋ˷ޗU~zX͸w:O#*3yDE$dtk۳߼f8f-Х>5M5"yi$g/qˊ"EdqKzfy1;u7W·&#;3T,BKrf,Wr]&C\WhvR"o(U{8iR: X5޿|0p"9'NJӴbڕriyjw>%-};-חO.+i͵f2ͧǔ͊ɴz= -BU{,xȒQ՘ knܽouս_GPjӧ}<騠e-uy `D*b}DtQ^9v/+r\P08j [tx2j@LXP.lܺ]XMa51x&ly]f eP o=4ة!':7&iޑ-4 s;,%!YZ`OYl6TTT|t˯bTrP2reENj@ryZɫb:'> -vvP \% qz)eQ .F3ߑVt02x~ ~n@-R(k֬ڵӧO]! {X=%Ӕw?׭*V߲*:L;&A~K[ _Kv--_2ωy7|3&`ـ*+_^8v?͸*y \VܗxR0A^8o> B(,,Tv!r9 @!9{gД \~K`[O MjrcӃ%jF5P(^^^!!!vvvZZZ۷ohHs y{~Qk2 |h7ǻY+L%erKY 0ibiaGISZiӦMVZyh46 1ųȻr~M>_tW4x Zmmٲ%$$d׮];uTbbȑ#]Zp aTdLZGdzVԙxch8j;FtaLo!4:AVt' :'i?[|d}DYqu҃rVI}[~3VVVF|٨Q)SL<977W]]]}dQv  77WمP:mۊ.}3GK;l[2}7꽳8[UfOH'zo'eb3_w0z`_I쭳 ]еf[zE[[霜 X,s444b]Z ﴪ;|qSH_,]kJ^oY- 4C)I1L###%U. !"++7o* TkZnɓʗvc^cTG BEK.Tv-Ŋ>>><رciiiigB.8pB믿UtmpVpܰv-_/,,3O΃Dgљ[w'ii}Zc{X1]3yUc-e?ϱ}ϖ 7.ϰb(##T71qƍ7.11ʕ+)))Ϟ=+,,,**zQAA D/x>u:u *1 X G FC9sj`r8XԴKW۵ HjˎtِuY4+mM(#wg{#ef͚5kLU >^䎪a!"f{'6Qw^X ɫ7U45y5!걌SÀ¶tȟm9;Pçu33#uU!#8rHqqP( Nt~jl\M \DJ_t݋gT+I~Lȩgn=*ܨ"+%S]IʪlQ?u&TK Ji"Otc)[]Mq/65qAx z_ )\;mtؔ>&/e^ViTVETzW#ψBJlhh8bĈ9sBe=SCeK{;3ۏJi FFتZ0`!B_]RRRll+_xOԽAK[Ǐ ގDo?1Ir)Kѩ4𸤬 )R`2A&2L&y@zv^ ^΀q6 jJKJi 4Uv !vd2ʗ"k׮w>a Dtӌ҂[) sv/95`kkɟ=-.-|r0 W$>{_Zy[$VB?KaTRLN"e%se|U>'5X!W׻wo}}}-&MR(>(ʕrz料7"y"Ve#=ofSx="Y515F7cXj֦jw[ҧ2J+;awi`FQ$| IDATl' W(hBa X!Wggggggf{H̽-["hd'KۍlMs'fP-3vo$.s1a}"D!2Ħ1ɮ#"Td@c&j >gB)2)8zʮ;!BaB!eB!j,BZ !BaB!eB>ΦZq+^z!WvU{ !sNm2x{%IiN͓kƷo3Ͽ`ϊ~!N2BB@GULDS$VT<8H6aReWW3!Z0`!B7y$5KzZB#GX0Ah T^Zn埿 f'+ `!Bɣ(57bꛘ6UЯKié,"+!:[ʯG@ˀ'v;Fr +a%^SHo-YXDגnpZ!k4dR[I{Rŋ.qYi;|5{uC£щ'&~Å> -B!B> ic.I/Z6$ ϷkݷJE]+16dp@`mD``KM muMٶpcTB!od=,6_ȶFoDjbVM@\=zTny,5G9ϭFa:*hoK]uə-4II\ظu[.綘z"2xz#]Wj<4t]ѷBh777Wn5G6p]vƶlٲƃ$$$X[[X]aaa:utR֭] B՚7`!B2 X!B B!P-ÀB!T0`!B2 X!B B!P-ÀB!T0`!BZ6SF|6GEım76|-_WhT|BzLs T]4Х +jвݷ_WSwB!DΖG@r<BA?6o۶uL_}xЩR K1[9ѥ6b9A>my.rR Ho Ue/o73={u^>+2O,~ }0`!`o/O6>W`"~, mY0~׌޶ ,;TZe_쟻(2ofէu,՗%C£щ'&u݆GgI@t9Z6}#_6xWB{mI{tb)SybT 1 X-%3nl'dV{Ag/T#x!zJygo*RӐNC?sɯ6H>&&EV ks[S%ULS^]&=v|q )Ͳճ ds4Pbm-NeCa=Y|fU z 謈e 9lU^3>(1x9]7ӡ nj ]p m٬~TU7: 1%!T){P+SSSiJ}̿2. Y2]NG=(=ޭD{.,=޺o @Q⭸[wJ XZtq}f+wnü̈~?u{ᶝoYx_q{[`b;ř?|myrY>Y2k~ieҪ\qyMӏ?qƅ N|P!YC{O+n]~4UZwlJ@z9h2$>x\߽Ok.E<`5m DŭE}"E^Ԃ66+x/T7)BT-Tc[509f,jڥZ$5peٵ4~rˌLDwZ'0Yvl͋@Bb.m12yI'O\x֭[iiiiiipLLL4ibjjڢE WWWCCoP-Bf?O y#lυ 9 Gp{͒;̈x{ Ҝr}鈞tM65NWиqQFر#==Ν;s͝8qb ks $8CW-=x(g 5THyiæzv'хs3y:|ޘ}Cr˗/ ׯۣ9s̙w-[jjʔ)>>>L&#з3XZ7ݱ,AW' [{h+8mY.Xf4ؒzl'Y4~333__߼k>z(00𫦫7Y[[/^Ç7n,--߿ippGB_Uڵk׮ 0bccdx8x`mUU3׮]kӦ =zT.פP(N8/_Vn=p%喁B43Xզ\???GGǴM6]~ۛF֭[tt;r䈵']BOuWyy3:w,\d@좪ܸq{...VvQ!T`BK;88,[͛666ʮ,--\2mڴ]vۧ*"W0`!Ebbb>}~7D?ܹsʮ! XܡC<<PMlذܹs.K␐~M>=((H wg۱cǘ1c:vw^u+,kǎ bl6{رʮ!c<6lX=ZoU%cǎRUU+"^)B>C\\СC]\\=0X,۷o?jԨheB+ X}>}hhh.11q:t  m8Iy-X[l:ݜEbUYT+O^&e>9roܸQ+!ЏBP(F- WXQ6N6lqetrY嫅t^B#9U[Ǧ⤟EӆLFF &J^B /_+u;G3eq)2(~醄ˮ]vm) ,k'ۺwݼP(\n]||<BBŋyy{{l:q 4\gF_'ųL90S@ĬץEU3r;hZ9X׶\"l.te)q袁.MT8\Qݧ]蕃 |MSޫ]v.\ӚaBCϲ?Cplm؄ގ-SdDߓ3sm%]ɣȀrlƒ-a쿡wʴ4d<~hOljDݢ{K=4,z6S@矙c ]bw>VگI$d9)g'#Jh:vT#WKu~O0`eyyyZZn]AA؅cbbFx bL&ɤV{c{˖]?8}5ˢNW٧*MBB}>-VVVW^1bĘ1cmll,--bP(eH$zqx<xH}͛7̙37onӦMΝ7oެWTT-/ }\^8[|tܖ I̩3 zTZ iiiʮ!. Xα9qDLLLxxxfffEE{2iHH˕+W*WF(S΅:x%=TvW8V|~W! Q_VTT}WZZ?l2B&u(]/_woX)))QU!aBp455?ƍj[;wnĉ۷ zt@ C$:^>n*O\9y6g2|TeTC/rG?4__:TTT߿ٳo>G(~Nm/_wUBD<{t-Pz=|]ߴSZ"P}3XǒokkKQT```@@@כ^phṭg\ЌV IDAT޾mu`qʮ!.B?Xu֔S@[[_{5w.>Dv}>VyqqǏeI@Իx*e4ۚMwyrrr^xaaaBB€[*͟dLĝ}: 0z8V1Vwܾ}y!Az XD4MPwD/WAӴ,mKW/, XECCCGG'11Qم]o 4Pv!!TwaB].\Pvuׅ  FBLOOgUӧwر A: BLaaa.. iSN.!4 X̙3..:s挾~ӦM]BiBnBCC]HRRRrnݺX!avޭB)0`!TkkVZ_^م-7oprrRv!!TaBjÇy +RRR._yDٵ|kٓ'Ovtt;vkA ,>vZTZ-[0 eׂB X}ɂ =rJelܸqϞ=kA ,>ɤI|||NZhOOϙ3g*`BBlbnn޷o(+33GOOoϞ=xr!jBJUU2o߾.k)..ٳg^^ޱc444]B}0`!ۗإK"eSzq]v5o\ BSN~z.]]NmH$>>>۷oVv9!ÀgիWXeee} ٴiS]B}0`!T۶m oӦM=XnnnNZvСC]B}0`!TC y𡃃ו]N%&&:;;߾}СCFRv9!T`B:tp٣rj...R4** Bڂ /Ҵih8;Zh}iٲ+BB_JGG'<<|ҥ.zzjVmi``B^P-`0ӧOx۷9rdfff-CV(1)aǍ"#""V\f?  d_X BWLePaoo͹s?5kĉ9NmMƦ- ]ص5Woލ\NGHrdYBV۾v%=u8<@̎ P WR3E񓄸BKԠM3=n"*6UjLCW#B޾}}ƌVVV7oqrOͰ xe-n_rɭ7ݹlr@KL ܜ i DVfNq|L,G\$+ٳO`X7o>|06fT2,hsSVj,C $I߾}x8;;DP|e}N2e -<z<=hhٱgM#Ʈ]>3Ϫu^O|]ʛаwLLLLLLU+ŧzxE)ͣ(@Pzys@῟:c(X:cKKK H.D"Cˡ`p/+++666))))))111111''GTjgd2E ZnmkkIr 7RRR""""#####%OGHR###aJKKJKK322 twwڵk@@@@@ w?`Գ]vڵ+66'Lо}{OOOZ͖}֭興lٲZj~ގ @}())ٶmۯz"ԩw}׫W͛x^+++++]~g,ǟ:uj ,?ȑ#ǎj:wԭ/iԩ**88ݻQQQ3glٲ围g0 ӢEO?4"""%%eժU,N>?OOOՉPJZZĉϝ;wʕ9s8994i2k֬/^to߾VjڴرcݻWקB -jَ֬;&Mt֭{vԩknΝIIISNݻw׼y󊋋? [ @Ƕodɒ'$$[NNN}ݭ[b eYnS4b(X:3x#GZ[[GDDرёPߺuŋƏߧOs qBЍlk׮tR.]NTm۞9sfӦMϟٻw/׉!,7UQQ1eʔAGGGO6aCՄaI&ĸǏWT\hTPH~~~PPƍ̙s…͛sU={v[nѣGvv6׉,חm۶XАD#,YwޫWv1>>D kxbrssO81rH㼾C>}?""8 |rPP\.?gu۷94x(X$J?upttfZvΝ;`\~~)Sڶmzjԟ`iӦa3@m`ܬYrss7mTý'Ơ+gQNbn [9uK lٲt\gh`P^"<<|۶m}3hkz`q<mY{9=<<,X{?SW(X58q׼y^ownvt4wnՋٳgN6,  @M6o|5kלܾ#&7u{KTrd]ņBu_g*§ %%*?*Xe/oD&[y i F~\~;GH$s%V;6܆OzD&VU_ [.==g탂B*jz͌%hϥ|s>="w2Y}l "W=#wq5i ѳaT,# :W}l孓/M޶mہ~7%%%MP@_0 u߿?33S29O޲M!v.> /lQNNKv{HHHHH"Kz:b[agfg+[~Μ9{yP@_T+BڼyCϞ=u:eθsrb#8n]G22Cd枆&㇞/WMS SC̬Ml-Uڲe-`i5+!e稉ĝt5ay;ˈؒ?f dOZ5mE1ڻaz QŽ6!{8ݸq"##o޼Y킂ެ`Ѹqjy&~Hv]c.hm^*À MP啅m6G._UΨeanefwX O91~iĬZ[Zxٓ5pW1c <'o#,zZDzZӞqxCCg6ɺx=)CD|ɫW/3Dw(2t0?g[TPn0nձc rg,?zRfLIFڴGKqի~իkI>}46ۺuرc]\\^{8oo{6'ʲ]|ܹs_{j͚53g|ߦΝ;0lSX}addDDվ^?~e޽{sDӇN8uB*R:?~LJ 1,, z  L&#BPDDDϞ=6zyS5Z`x{{sCy{{p@`$Lncܼye͛sCU=9\_(X/,--MMMQPjR(XGڷoYg9x`EEŋ  6mZ1.{{{L H~nܸqڵ;EZZrڵk}@FF@ 0\_(XGƎ+HfΜjajzƌ666ЋzD*q@`6l8u;3XGg/ݭ[7{N.rؼYS~tnG=%"mι ni'L<F/K|ӨE"!@ Naa%KBBBʄBL&D?=K,3 EEEgϞyseff^~/^e˖5ǰ"b QEoûW_9CMej4˵lu)"OpL)E^ARK¦SBO Ѐ`~ {رcGձcZ/..{Æ w6lիW:t;D"j$W$hՑGKmGo}Vk6fa{/&6j ϊe/F}ci[dmgmހO4"b+K r5UI~~9}iID[+XlAd%HN0D['S4߫oV{@:u*<<믿v"˫v\:t(>>vEo]|>axc aVuޡE;H$fV6Γj J-ƺknlAN%joco#; P3,#vƍS899yyy-\0''?4//u.;I@ȁUG|{K\QLYہ#IeRV[/”ǐ6?3jD [K337r p`9uTztLLŋ_]ww79Lyڼ.&"6Br~忇)|P̯°_IzR57bLn/bc?n^BTq kH޽S=.--MMM}f"99> $7i^K?2!7ī1i,`X5k='%b++*YAoԦUw/넥ZY6'Ck22!!AjOY"7{Wclov\}S^jaY3 RߊK$Q0Bǰ)%ˏԳSR6ђ~lUhzr(EBP;{MLLj] llzrmkG}˦l IDAT籦m=?ퟃ.| m <.7^h:wM777s1`ߛVu(nc賳gz{{p@`ГEDzr 1+**:|PPA 苪O+Zmxx8AѩS*++u ]ڶmknn~qǏwؑ z  V%g>|>W^V\g/Z={'=  ˲Dşɑ#Gfff>| ĉ)))F:Ӌ3zTaubnn>p@;,s|1c9u}1c K`~ѓEDǏgYv\!!!Ǐ:@pqq:t5k½UVׯE\ghP^hEEE~-AzEqa@x-Z|k֬: Jw}7d???4 (X5YhJZt)Al2Bxb4(X5:u Ο?un\ro0a7Y ,X|qT*YZE/\l/_u  ւ;DҘo7,\pر?0\hPja׫T%Kdee_^ h4͜9s#Fl޼7Ұ_0͛/^|Ν={rC_׉|{ݺZzfJ۷/k?GyfB\Ra%,xgmll>hM*c4ʸO,K>s#GOZzjC1}<ܺ~ѓo攳D-u"*AóU܍:yT{'&@A"e`1#~w8ÊI0uu֗.]ڼysRRRƍw]˪ RlQUw%Ymӥ[gy魏Q۶m}6m}[%k-s1 /-.)_˖ݸ^ m5 /zR-KTfѲSGw9CZXT ]4>(X@jV*xKb 1Oџ!x&L}9sv>|/٬%h^O+bE)O;zl|v JNeNz^LdNu蟓ͼvrWS$r{[YBbUJe^fhX[3W#HSY%<{kk cX-@ulxqE'p1H$˗/>}u~={tuԩ 222lleaaH,fHp"#!@ܿ$""mε,#rl%ϣzL&ϦOޤ}qY*"Oը$xr]݈yTXy HS,hcO%M]}|]d|F,VBX=q͉X9ThhbjM1sP|WlD*/oj&IyZ"\_РŨtw3\gϿho~ٝ H{wm=qї3i/~ԇ /a'--d6ӧ'&&FDD3&<<|Ȑ!ˣ**^R3U)D>.PV_p~{t9rݏ> 퇭ۏMR)ʼu51jH֐@ `!"R+(iD1|>JnjĂ_R\J+uɓР!&58vʴqDmGEwM h'$+[=hc|n!{ӟY&z>uڵk׮k׮ ߿3gϟϲX,nݺT*:1J*E[TRR_|-&6\Lyr0#Fxwzc"3旧_OkFPtVVdr +˂L]Tzw%&JL-e7l35FDlYJ, P-Oo{ ѫ{cfk!≇k:~hOА ՗'0lEy9.|>w޽{&gFDDƞ>}_}ZRȈa,,,8:7XZZ>m]Kߒkף#RRԵkN20uv3[~' '"}>6-)bI&#[6b4Z-P/f=͞wxW}RJeiiiIIR$"JeL.psssww5N-<z<=hhٱgM#Ʈ]>;'yJ (X"lo)e>*<>:뱜eƬ-Dbris>f Q٭KI6dOnIx&""HԲe˖-[V=^|^t$##'޻wat t+,,,(((**s\gЙ'Vt  @Pt  @Pt  @Pt  @Pt  @Pt  @Pt  @Pt  @Pt  @Pt  0\GxS(X/Z-x3 ^@_T,`@#eY 4 x1},h4P@_`  5fqqqC qpp?~YY׉jR^^ND\xS(XVdddv.];4m488800\/T* \;wN.?L>h+,,J\`5N7oޜ>}zU"n:<<`5@Fq*--%"cc'MLLJJJ8Jryyy @89::ܾ}˲ovww0U<CjA.]nݪP(FvؑiONNnժAt0 33?ҥ˰aøUCi4޽{s@h8qaڵ'N8qÇ|>׹RVXѪU+???V.]K1c|7\ǩR5jTBBѣG998` quuuuu-))ټy_seÇϘ1رc=@Fںm۶DjmmݺukzOKLL:uj]䩨(,,,,,T(j 4oQyέNmY b%)V8""դPޤO [#-͸~%~Ⱥok'lL4v@xyyEGGs R(TR'Kװ3$} c&˻Kwc:]K laVt\+R -NVԲm`ìn$Xe%\6g\fRPFPPd@}b,F|/˔-JSi$WjIZJxdQpSd rH$NSXs#'nYU1M;mJDlTY5mf/5fr F|al=Bjvܩh>gnnaOCVbTG*2 Ir_, "\ ^1" TR1bmlb>C$IV~挪m[2(3O2..)gՕb5)WFnYYYɓ_:܈~\͌BI ߖ!Uf]o)K]un!S&<х}~-Kq@ڲk`'^\mtZŝtUՋ:cha)S(TJU)~ǘ6V3]HTP,bJˈUe޺SI|j5KVkH dl23S6X41)S(Y20;OnR2JDla"k__G+x;`1_~XZZ_ܽ{MsAѝ[J[[#Ʌ+, 22.sܗi*.0DĪ+U[ƎH[VK>o `5Z,ܹw666#Gdfǎt<<ڰhs8Wn䱬LŊʐ4a!#kW7cTXٚ <#!im(hNƋ1ey m=LF^e ~cB##*FF|"ڵubR#Nu2ĘrfR>}֡[uhce3x>|"b }JƮMXexW VyݥKc.]m6X_;xa2>0s˚q=>v #E9jo c@Ǘ&hg>ȥsNjO QyJ^g>` 5664hP՗#G}.w0Q+(iDUfM+)sXؕw/^L)cvSwߦL^n,QS_wGXjT*՞={ fbbR52|3fk׮ct#Aܕ*j_`ha$֭E Ȝe\xLhuz8ٳL&۶mKQ1ʺ|l\Wv-}K]HJmvk++>d`fʫ[~' '"}>6bVgP;x!Aj|~^|^숱kNȳ &" ǘ6O-ғ;v̙3,XPpn`Au\iЉ:XXXp`A{nSo1,C1,C1,.9x #pwfT0VҔGwX}BߺL$4"Ҧ.dIKg:IDshP1σY)2f "o?akϤkX V=cM5 4aKτMyYR__Zi*Y/bReEmycKIml"/~k"y뼵W?1XXq}շ&:*RA__Q'mn+J߮}_;46h LlG-qthx&Yca½'7eHE]5m6,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,C1,> stream xZKϯ#yQ"tH7*IYY{ΐKR U[S]]]z{7A~_SI$U3TzA?woՠV_̮~OAvI^Pov[XM{qwnޮYXڬ[=ot\s}c귵ߦ->oGmo} R2wlb[Qu &F-[=oV38?ulWCr6zeV}ZR2.?Q7BΦ9|9^-ڜd{zgxگ5}nx?~z˻N)^^~GE/&΋8;訓7䕗J)uZ lZTg]}Z#{`u"c"ϸ< TgdG,j!9 lF(egʺh!;P P*[.Ygi7 ٬mj͹2!ESr&2$Şf%Ƀ#y@AE8Xrmh6y]kaTO(MĨp=5&zcԘؔT'QE,[iĩtuIec6Jg#B0dO1oNjKCtXݖѺ6G c]{ (V).0 2pA00DǢCY莣6MT%1R kVZ4e&"ypllFe7m5!1_.9!kvgyFvo%֠\G4_3;`'ktuLvZYa'\ӏ/c9@!!H4Np$V.NQ*Q"Nu;NYʹ*#N-)8ѸFE7-ۍBnnWʗSqlH st#;$`Ձy. 2o%s`x#0#C8#`SAMq0\MI85˱ҺlCD`-XAT6.:b0mm掳1Zk]B#fHH'g4[ y՟Y>T RbF4Zp40J$lG҆:aTN~a`ҠIQijv cFB `Boa[| UФE]TNt Eg/CC֊.G=kF 9@.T Lڟ(k/12/ cp %pB=Ze,Ep-- lHdDewYŬwd*{j}\U.S-m\vԝF_x 4C TR>{p[eiees|7gkrG~r]u]\c'=_n.h{p&-s.^cѣa.רV닊< hUxShҦ0< ?ըMn g4kEaزqqvᜤ|f(nJv{D߯> >> /Font << /f-0-0 6 0 R /f-1-0 7 0 R /f-1-1 8 0 R /f-0-1 9 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 10 0 obj << /Length 11 0 R /Filter /FlateDecode /Length1 3852 >> stream xW}XTU?{g`@cfBfms,b11DDCP> D` F0EpZײL3wWE]5-12TR4-(STbzvg; ;ޏgFIӈ L\&#D2Ko((ovg.IMǯmAhX ΄2'3gemK>̯|T#41U9\ y?̽`5 I3rE dk΄rN N'-`܇.K:5 Es%$OK9'a7bHqp4lF(5!"Ts!8&}E3?s#$A CC]ML%\/744hw|iJ[\%eƅU>B¹N$ Gpp( rtrwHs[ |+CR#{I$fkE2(TS grr)&6.vzdt[X30Ad/kI0!'vu_У JuZTc뙡o'eЖnR)Ǐ_==w-0W]H,4|~p|avtAjFKzj\iwW痯E,^oTU4ԆRS@DMR+yy 댁ZL)1?sNLBB̜L-ظw˒ֺ{j]ִӦHk]ޠ[obYp4~`Tb\kٝmZ:&kҤ;8LBD^ 3p~ NgN)aF1 _|AOmBpFJ1\4JB7=e3ZI?*osQâMY`;& \$b8ij)Œ΋,{< 3:I`op'U~36жK#b4@qguZ!2hh_YJor^d.7r,'i{UK+Wwei.DR\bϙ+*ˬV'!j*~vVC @NgF-LN^-f(CQn:uR(զ{u`Q ¿HQ>#cx&Vbq|g޻}:GŅBlE:g?Y!v邐Q"lYZjäևPs.Vl}.}患حk_; IX%8gRb*_;`JOku ]p+' /!9vߝ4}ҁ~H,gbDr}S#reV ~04H >@֑vDd& \J-ɳ6^=1b{՜T~b]ܽ,ig2]>Ӛb)-1w Z 32F&\P[[v^' dh"Tl:&D#Ɋ}lkwU/2G!L3Y%-B㾄"'  h,ؐ;ʫ3S~kOӖYė+[19"^wGºƝD)b.+pMHi=vh,뿉e΍uZJx=~]O[sXU{ljBo)l->N~0x-ÝB {̓e9ۿꢷ2翺rV3wՅr4Rqrhcj5>c2UkFFXS}=Lr$7A_@:C/68z0 $ek-E+e<|#  ed-jS&!$hH` ,)݄h ֎)|_E!m.淤XμGlY mLUxkʫx>.*>$<+s᧑׉``y!i~{da<*2cyCxV!z\{ UmnLؒVӁxgqρ =U~A]P^?/TSx p'KU䒘_Ȥ󞬩s&9D܅mb]:Je ۺS $f*Gƌ#N3܍q~6*b)Fbue'[]/lQ?8%[znWykfUE:oKY&Uh^z eWĒ DTF|-x%%-[mޭюp NV{%?4U pk7#G*.~ !2ΐN(#ZqRC2F|( =$.n\P[НxlL]Gݲ SҹHhWD\<(jR(-A5 mbQH&{rh)$D1|]0\Q-@ N4]bĂ@D8&f7@Ke`J*Xxޅn"HWX|2>)sSC`y:~ѠX`}%Ag endstream endobj 11 0 obj 2739 endobj 12 0 obj << /Length 13 0 R /Filter /FlateDecode >> stream x]RMo0 W*(*!p؇ 1Qb //<7~\eg*ѻ|dыC!hۍvRp-+LfQU2H7{rsBJEq:L~`\Եt0t/]x&uۧ?@t?%;;XBg!vZVP ߛ*8wEU4!*CT$ğ?!?"ϱb{=j8<NG|I||#a!=/1*XS fo )(p_ R\KQ- z< =`MA}jƺ}&ƘOGsljQ f endstream endobj 13 0 obj 371 endobj 14 0 obj << /Type /FontDescriptor /FontName /XPUWUL+Roboto-Medium /FontFamily (Roboto Medium) /Flags 32 /FontBBox [ -907 -270 2051 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 10 0 R >> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /XPUWUL+Roboto-Medium /FirstChar 32 /LastChar 125 /FontDescriptor 14 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 568 568 568 568 568 0 568 0 568 568 0 0 0 559 0 0 0 665 0 652 653 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 541 0 523 564 536 354 566 0 255 0 0 255 870 556 569 562 0 351 516 333 555 495 0 0 0 0 335 0 335 ] /ToUnicode 12 0 R >> endobj 15 0 obj << /Length 16 0 R /Filter /FlateDecode /Length1 420 >> stream xc`d```cp``bPHϩLP@JFnI C-_s''?@~M(`Pc[|Vf @;9x9YSQ F'LnZwS߸5<*11-"& IYMMM̌ԔDELmW?/]5W'}fnSܾEe\cb Rx~  pC<}$NǾW8\N ${?A~Ȃ#sC ^} Y endstream endobj 16 0 obj 363 endobj 17 0 obj << /Length 18 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> endobj 20 0 obj << /Type /Font /Subtype /CIDFontType2 /BaseFont /THFUQT+Roboto-Medium /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 19 0 R /W [0 [ 443 582 ]] >> endobj 9 0 obj << /Type /Font /Subtype /Type0 /BaseFont /THFUQT+Roboto-Medium /Encoding /Identity-H /DescendantFonts [ 20 0 R] /ToUnicode 17 0 R >> endobj 21 0 obj << /Length 22 0 R /Filter /FlateDecode /Length1 3228 >> stream xW{PTs^޲˲KbrHc#}BP@B `% *- jvLkfl&UɌ&> (T]IG=~ _îp/ج%yJf/\ڱ{l4XHP /,\Z,ķ[tI\EC"QA8 5A dР3 Tv Ce`5<[a9JR ׳r% ΋Sa8ulHnsƘMaL0*EXvla3j i~]phMه#_b^Q-77~]BFnza$/$cmb2ih|d*:v)n}}OI ^_w?5[ٜ{9>ʂ V6,զ["%|p7FsIdo8$FXiBFVhg\iaoŜS\_9nH+bȊ&M j7DUŚ" d6 ϴQ>vls> _PTHO1 R55j)4^mC~- *+,\f!-=ފ.DSu&<1uHRshneh1<v/9֕䆖q])XByqia DBlAMfRaD*$5v<.zt>I39Eָ G7铱ٵ47s(C{bdc뎉"~"^K2w:-9N)qf{ͤ'KƦ 05Tԝ-BA1fwvٕ%cvig]ܲptcGGk02,P":p,&3+o͘[3Y3xl6aAE'ŒǐzQzwL]˻wDׯ7N9%/ו4vpĊ ְxk', 2|/%V](4ԷY;"Ҳ2/H"kxV'U`'v4lPEWՖcݪ> )"̨=A#q)JIR mS8.3VYqgb(]>^KBLOpœ~ʠ=q} fϾ>>ӪF$COBr^:}໨3ՍX4+zx LY9 vh)ws{F р_wlg vwn乘]_ݨQ%_\OՔj0 cA@_&~Iܶ%6^#6=߾'T>T-'>(S ˂Q|P43V>GSG6ET>fIB'd[Ci2zIRPh 7r>h z *ثB?-÷6ѥƆžP׊> stream x]Rn CG4eJ/>;}Y6J.Ź{[ygʭ&2_>yV8N!"%۲y;G\ָݓGx`-__C Kֶ܀Mv/Cx&ENw&ݻuۧ?\QKz6ACXS-omxV2Z=D֨Ce njSHXֈI#QEuq IcIcQC|E||M|> endobj 7 0 obj << /Type /Font /Subtype /TrueType /BaseFont /FKDSCY+Roboto-Bold /FirstChar 32 /LastChar 121 /FontDescriptor 25 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 282 0 0 0 0 0 0 673 0 654 650 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 618 0 0 0 0 0 0 0 0 0 0 0 0 536 562 521 563 540 0 571 560 265 0 534 265 865 560 565 562 0 365 514 337 560 505 0 509 502 ] /ToUnicode 23 0 R >> endobj 26 0 obj << /Length 27 0 R /Filter /FlateDecode /Length1 424 >> stream xc`d```cp``bPHϩLe;P$d&06/e``2sf@JFnIGC%_s''@&c M(`Pc;|Vf @;9x9YSQ F'LnZwS߸5<*11-& Ih8"Pi.u?t^Y}髌cN39ŻRe7>bR++m2Hr0@8^(Ha`cY5Pq`baHar7b3/10] endstream endobj 27 0 obj 367 endobj 28 0 obj << /Length 29 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> endobj 31 0 obj << /Type /Font /Subtype /CIDFontType2 /BaseFont /AZETLJ+Roboto-Bold /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 30 0 R /W [0 [ 443 608 ]] >> endobj 8 0 obj << /Type /Font /Subtype /Type0 /BaseFont /AZETLJ+Roboto-Bold /Encoding /Identity-H /DescendantFonts [ 31 0 R] /ToUnicode 28 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 32 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154042+02'00) >> endobj 33 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 34 0000000000 65535 f 0000013814 00000 n 0000003071 00000 n 0000002905 00000 n 0000000015 00000 n 0000002882 00000 n 0000006897 00000 n 0000011892 00000 n 0000013653 00000 n 0000008685 00000 n 0000003289 00000 n 0000006124 00000 n 0000006148 00000 n 0000006598 00000 n 0000006621 00000 n 0000007366 00000 n 0000007824 00000 n 0000007847 00000 n 0000008149 00000 n 0000008172 00000 n 0000008447 00000 n 0000008848 00000 n 0000011150 00000 n 0000011174 00000 n 0000011602 00000 n 0000011625 00000 n 0000012341 00000 n 0000012803 00000 n 0000012826 00000 n 0000013128 00000 n 0000013151 00000 n 0000013417 00000 n 0000013879 00000 n 0000013996 00000 n trailer << /Size 34 /Root 33 0 R /Info 32 0 R >> startxref 14049 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0008_Activities.png000066400000000000000000002001521415120503000300540ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxg@v` 5h4-K̋+ѨbbKRTDAQQ"HQ.ee˼ Y93.̜3i@!Bv!B ccc[ B!P/Gbcc1`C݋v!irSXXv*BU9r;wBYL{s.v)ILV9X )1+B!TВT}iśnv).Jre挷hr/LWЄ7wlmm!MIxTP[moo!5B˲˔X&NybMDLA5ZȽ6LJ HKNL=+{T!B-H##زnǰXN={vwn 鷣Ji4õ9ZM{YL.][0iH(/+uOSӲˇNfik, ̣+K`ּY{fB@)xw'?t>޳ 0\߰ykqFM˥RB#0Km! A8<.& "C)B96viOdN"ے ٠ھ!heQQ# <+1P͞wf!&7>v f|*c^_}i~߇/ΟÇ/{^h]9_NOٝX]YvCD^zWÊ@v-$>4*Q}k7i2t ygێ%W֌fݽ:xSB!T&N7y#Ci򓮆]~z[^+˹:0LPT4J&Ij˄M ̅ey2bgfS%N? g62ZR1iɾkŀi՝[)7q<#@rGDwXO"d#_ o=~k}Au{VZЊ n{?%ܕP8sBMMRۃB@KhxB:13XO/PA32a]q@BX/۩ y,;1U"hJHELQa-l%laxivYY eer@~wNG/:lٮAcSuIj͡E;d|7A:U륛18JvLN_uZRůp|Aꬌ,5=Si%~Ӧ6^7B!;BмveXz'"<.fUGGG ʬã3H"ncEoE>4mc#jefL 2Z´hhBU@rKr(0_SvɋmO;qۊw@vZKDW=uO?{j5Wj}ѩ_$8³hv[?p*8x~qxLׄBOp"fG,=pzl{5PcjB}4RqxSB!p/BBFV= !j0`BF, .hܪU._{1chB'V|||>}Xg``B!Wm۶k׮b)9CCC'''mWBZ*`޽{kB/rG!eB!j,BZ !BaB!eB!j,BZ !BaB!eB!j,BZ !BaB!eB!j,BZ !BaB!eB!j,BZ !BaB!eB!j,BZ !BaB!eB!j,BZ !BaB!eB!j,BZ !BaB!eB!jS 0F\XX(Hhv]YZZ:88tڵgϞ.aB}OnٲeϞ=ТE [[6mڰlmj=zgϞM61>}L2/s BÔ[l)//۷ʕ+{mbbBZ=uT@@W_}ժUuyyyii0I!T988[nԨQgϞo1]!>ѡC=55*o߾cǎ-..viÀuݛGFFh"g`|7;vmU XYp?<|(mE]t[n ڮ}0`!jժq.!޽{xx8ׯǏ]N0`!qܹ ~[li@SxB]pp\.ꫯ ˩~V"'//oNNN;w$hpttܳgOLLiaBR}\kA LB؝HRlj(BskwǨ>8p)SXBUJJJڽ{ٳ] BmժUB~baBU?xsv!H4bӧݻZކ !T9LvСѣGiT4=9N^>Òϵw] @Kcw4]!klݚKO7M߮抭\H?]pc.E<}=:e"_4ea6"n'Vkd)qM]fLbWhebLb޽[ۅi{ѣG!^8z(\|YۅN-%vo(qkEab]& v #KiZԷրI0O hhZx C SGP$X.׏Wvl%o#@})_Abm YP\.gֺS[ ]@oSco3miHlee*h4#Xʅ]j- O\ƻU+% &:WRP0œ*BUjxҺmދp6LZ堊߹>0OCI$Oo,WDTnmP?;V\)O[>D}6F'ގ{U)gߌ;SV=|9/G M߾}>|Bހ7{FU֭[L&~J|(?3NIi1gOy6@JyL%M-$^^ZP nLVxMdDE{$"b"S]`XMə OZ٘3Ecܔ9P' ?snnnp-ZhW!Tqi TŹe4I>W)Y3+Yz-К"T@雚p;1?[DrhA͋И>w #))IۅO"*QVV&J-,,]P"l i.8QgmEŮ:|hӏ:w7wӀ@(4gy<~s<5*0''GۅB%%%BPG@yo249~8sWЄ1cZF2邳~CbmW XJT* Pb*7Q=?Xn㻗/FeIh mZ6m;/\Ar%l3F&4Gشk?h ZM_u&:}ςu1s^bXZ,BL\tqB}EYl%7YYD%PM}ok3>CML/bRS#܉g4d7=PmXw'D i<<< ,,L lssm۶M:U۵ P5۶m{Az,BZ !BaB!eB!j,BZ !BaB!eB!j,BZ !B\Q#SZZZVVV7e0@,[[[[ZZR~A ,TG>~Xww9R,kBujTJKKo߾nݺLOOٳg;88  999::ŋ?w}`͛e%!,x1bĊ+t钒B}*P'Hv믿޺u{ڮJfffgΜyI.]_B}PV\\uC\lg⋨(޽{߸qC }PV{رÇk`eeuss>|P ePbŊ[0@۵|0 F7ߔkB j-[6nܸiz Q-OmׂB6aB լYbk׊D!t C WXB`B RDDDXXknOhk֬Q*8B , mܸhҤI.XZZ=߿T۵ P#HN>xj+[:ҵ{_z-ӀvM\wk.e+{)3WH6q%,t.!SMY6?_SI&"À3ٸA)Q#f[`/g›XwR“B}ّQu3q_(f=o(`L[}k; Pc.{Gݿ͚5.--]tݻEF?-Dѣ;w[bʔ)3gg`B'G9o=(߷sH46>lcfl!Rnn٣3vرcǺ!"L/YdڵK,9s&9A!P@GG}͝;7--m֭]v ttt v̙xww9stѣGڮK O!Bk֬0`@&Mbcc}}} ]QMnGMMMСCxx+kBg޼yFtppv9cذaѦ}=˩SBzgÆ ˗/2e?r]dz [.`B!ꗈ_~eذa[n[՜A``%˩# džB5&2lر-ZA`jjzСLooomRGO!jVX]v}ڵѕW`GsDDDTߺÀB7n=ztnݴ]K/^B,詞\X3w&"'4n5q](NQpjBe2… l4+/~WcB\yԒx'S*/=}];VNqvE C!T_xxx8::ܢ!v|ݼJZ]c[\~~οmzvM\6Wl2Dwi. /8XU{P}j)I 2׭gyO3RbMch.zݻwF]s>/LQį9\BK S \U!:{$,, z]ٓ O\ƻU+% &:WRP0œ*BUjxҺmދp6LZ堊߹>0OCI$Oo,'==Z9z￈>-:{H#Kֶ?Nk{ο"hMDMM8-!$99Yu|b BѣGwmΜ9ڮs! @*N,7ª/ C43Y-2bh֎j$򌍍kEt`oHSӯbW HMN;;`:% (Y^~rzٳ~nݺ~]~O>>uyĪՐ0 "b>. ޶N)@yڡ-2lY#>3v ;..TٸOX#Y^v7# @鸿Osmg^UD,m3f̨IOKK려 %%eƍ[?~QQQooaPF/j/2tomx/&FҰ]1˹nF5zT4:uڵk[haVë6SVp21 Wސ-^zҶ/q:Xtԩ7V(#Ft6l]>|O(z=[ţAͫ5T|#=1_m0>kDžY^B 6%%%}Pw7^pÇT6T*TZVVP(*l{ԴiSmWBU6}F"ܱcǑ#Gjz޽{F v!!P50`iqebbM6VsV~JKK5kݻwE"@ l6h'O՝2eoM0#BڅK:tS;v|wcKOOo!1bĻIT_/dӧO_tP(J!ЇY4|7666*o4,yK)ENbci7~AREDD5tugggooN:lذBGo߾ݺuzjMXʞ%)1j.҄79/\+j٧yegS<-UfZ73I1 Yb˶8hUi^ftq͸@%yT5qtjeNX"pwWݻ۲ewMNN۷]PPP߾}k B `iٮ]bq?T-H##زn `Rd%D?T;uѵPr/a t;iks*#!@tqgʊP{2#g]Z02>̯ a 兒GΜ9cǎY[[ุ8LW!T.6FzaguC2!b68pچJ"i9=T^h >'VDJdwP?wŒ^x TUucǎ֭ DUuEEe\UyVbb[6&_.Mn AӴLNt+:c{{c6U*`2dZ`:Zu>BZL*kCx~@> ]ׄ(Rv^*{ٌ\,͎>0rsa{gKh?TRT*2}sO6p)|Ew ̝;wΛ7~Xxٳg/Lʂ~C*0pc]3@Ee='KQruIajx]U]B}8!4{=Pì``w]B+;\ݷÀP-S8t߬G}{z|,1zwo׌_шmhڳzuq0]&:ͻsz>Z:uݯWNQI9Jjtzctq(uu3mуW_]0;gRN{v&(2pE?G[K$/^.Q5ѹԀTY?OE E@#-6jDJ%T:'3[@XƦ7C QA]8@ #tyw޿*GwD"n܂)tE^>pnY*jޝ2 ]+k3&=1۷sg{O兹M-4//̧4έlLMlZp Gn!sb<2$LJSl=iҴeA]{+?}Bˡ.MFT1K] b*LJ>y CW==!PSe4}*h>#€80Vmͫ1s3V*Wi8`B DXZDY2SS_j VS)),ׂv~󯓆tki޼njdtqnn ~_5-+Փj؄' 7g2n ʢKkLTeP5eQ{f^#猱?lym+"TZʡ?HHHD;3P]X䃮&5\ %ƭ:|hӏ:w7w*bYZ .-+M)QMt`oHSӯbg!TS+Mѹi!`{. ~J}nWt2Y.ǖ7"djpe/^*d޾ʛ4P]h4PEJ5Phhaٹf}M3M1N&u_O#cKIo:ZAx](-ܟR@;gG2PP-!& =c`~쵿4Qk4OlABwMƱJi`ڍC>4Ԕӓ{;~ӧOjjɒ%={ܷo_mZp,T״p.F},fOq1` M`o\/?Aw}/qo͖rl6N,,Ƭ'rG9ϖK4bICvĻ je2y+{#GʞͦʦW,W䯍ո޾}77ܻk4]&Q~ka]3sخsfud+nj6no޹=t=WyĢ7L\tqB}EB:999ǏwqqIHH9x`- U?MGioon9 Y^KoBqꓣVW{o=(JD!TD"Ylٲe^>bu۶m{`TP= !BZн{gڴi٭Z@P^paժUk֬:t ߀E8Ksg`ǯgeZ]c[\~q6ObLFӠ_-yK{m}Z \=c[qB2},MfO!s]Wd }4o>P>>tks7&4KP:Bg@2Քe5%7M߮抭\HC%ǵfy%BZצM/SN+nk[U,;ݣG=zП] ) L!CU,zrMT5" 0xB.^4) a&+sLi.YW a¶t:WqRoxnS(@Mӊ7\c&tз9Lad/'3 vWE+bVt#@6;0 fA;ǵ0g;{?zl6{…&&&?Bm۶i>#M68q 商ŋ_0r(?y=M}#X4k}|Dz^"\^ks%#̩-*T\rb$JN~i?: @q/=%#ńqDU74ǔtOW0}!M .IEnVC,pyL%M-$^^ZPo[kn@EEE]BS`>hwk)&߲χ133ruty,MDMM8o=E'#^md2I~JdlTыԞ5 =„ MAޓ9և^ZNYMu 6kf &n߯ںzNeά`lfC5 ڍ>}*jٳgPۅ P}'*g)BJ Pɳ"B7_;P_ >E߉Ćb gJB1EXV&g=EEFFxjh9}@Bt؊3kOJ_>3_L҅6sڙB(~| <_M]VD(w.!G%_t]+ ]r$ӎveE[ g;0}F3tE.EQW]DaiUNkazi򼶼 | N<|ܱL(׬CŴx~g )s8>3Uk !, yv3MZ>Trw" 'O٣kQ*Z!~V|FYGy歐gE%Ҭ+R )t-wnҮ^*.-LLMgp;]Z{?<ڣR M2o^}XWTVV7cƌ~Oj"DU:N e(kJkЂ 鸿Osmg^/Oqr&|a.VBPg>amp, 6\8.Jen}L|^H-huғ}iL>Xbںrgj6no޹=t=WyĢ7`L[=ɔ_KخKeo9l9~:TI qva|0777(B4dǷÂG{V^273aakm6U˕\*U,:" 3aD*w \C{kS=>WTjhH#645ӕECg=uTIIICBхbi¯_0pm[7Ƈ7Wq[5܂A+.W [PDWbդi˂^͸Ot+(X,_s%C%& TIE IDAT{3?;9Ն^=o=(J-Oe{qaV-KoGU@qꓣVWV>3-G|rֆq+]L&oٶmۓ ʸ<ʳ ywnhrCog*imÑ]&yF<@xf L`2Vh[@@$ր 4 9nIV)40y!W҂7by 4=VRM}`[,Z8۴e%E‚#4UJ߮ [O=|eYzf \󖖌'!!Ij`iLLzW|rXX?LQz ~|ֽ:D͸VEQ&z?Qdee7P!}׌Ov)px\R&蒖$ť*dJT*50L$%nS&#`,>}h)]@8;7{{UʩTٳg[ZZN<Pcq<-K8㪪Um,>+WD%kVJ/Nዅt^fVLWX129ז"l#s#ufꣂYQNJC)aP)ΔȤ9RPĭd -N~̰ng#JhR.}r'ns><]oK.J1l'-ޚMkm`d`6NIȠ'.نGK.lb`dhݑ, {ކI@ b*7Q=?Xn㻗/7}k?*wG1hpo!t*,>!}}]&1Xz'"<.fUdGGGΖ$֕kwVDlƊ|iFLe>Ȓ)]܈~6o߾Z Uxu̙+V|C BQUԥqU~;ݪ6QUG>ee^7m]6V ʟ] [+Wttt\\\JKK?}] i@͞kh;v|}K=\EdžYyk|}%7X=ay¹cǎ;ygΜѩ5!O) 8…۶mѣǃZ ̡}!lΜ9_+W8Buj!+V8z۴ih"D*h>ܪU+??Yf]t@E!$0`Fbذa2d---gΜyzrdzz٪U#G酅~GoB ^33/X`7owuuupp033uYBKNN}vJJ !K.6l.(B,شmv޽EEEgϞ uVXXL&wM]]#! P8U8pYGՊ:2T\LQDAAd&`8{pr}5*jbb0sL???ss!R`&?ûAIIX,nӭ5qYĝb U).HKx"LF[9iRDy)/ t.EOO{[&gjnlFK_'=.ҹ\zZ_֜Gj- ~#nC lVEq)Ik׮իR*GB!Uaee5|-[L2C븘7,.\_L7T#H-&Q mk/sER3 ZMS[UblJ:dEvB L 8F&݁bcc9V kgB5"AAA4mڴi/WU_Ӕb۷߉N"*+ħIJT*%Rh4 rrR:[Ek= >_DTZ1&Fg,ibT*++kѢEh0Bx,M~KϽ,mc'vЌ!, !̵,Nk\ˑq+n7i]-,m"#*344 rJ``Fᰅ>G M.)Hugw-`ʲ^礦 H&`qo催cSs*945u:A $dP͝, Je$YQ!ds8L#F {i(`>%KmW2+%ZBcĉcǎ]r߷Tз GEtEBe+14w1&2Fܺ$вs1@L{qQ>o!ԍr_QL[P'W._|Z[9r9IPj,GFFٳں/j9XYͿt*ȝ zornGG.d7޵o*[|q;]ѽv>z jwf@v'Z5/.!}vҤIeeefbK]zicnf >V62ZXwb kiQ'HrL-3W>ՅBѣO:~aÆ}%&GȂפV'&,1.UQl K+JĄRiwN2Yl;:S1tLa)Yjt3g?iҤ Q/RRQ~X~===믐 6Tl*GP%${[\&#d@0_C.lC;d4H!tX'O^:00ƍSvP0mT"$$$00f;wϯ"S8>F;{ bg25{'K)nG灦a [}$5mgOOOOvL&D:@RWZ޿77Ç);/ZnҥK7 p UBw:˞Q哽 .Ox 75ٛ{08^fʘnjtԇ0^p|Q[ :(DB􌉉9tPPPѣսtbcccddpH$< I;~S.LЧV'.H-ܾR- [҅eYL퐍 VN o9vQVC[׎Bt Ə'N\~=,,LAU`0:vjժ~;4i`(]^P;={Vjv7|O?Lj~+4WZ"P3B'䔔(1$---clllnnNӕ !j|455ܔNrG!G+;&,T#Tw8BMɒ%K:( LB!&X!Bu ' //Ktmmm  P j?~ԩ7o>z(??_YaX,{{{ooo???///LB 5)$I_>"" dccchhѐZg=zcǎM6ϙ3gʔ) B! 53f̈211Ynȑ# @EEŹsBCC6lذaÆ#FT6BoX$`77={<{lѢE*]>|ܹcdd4jԨA|eDžB`=T:nܸ??'Z :us͛/^رcǗ/_*;"B,ԸIҡC:th͚5OVvD_AP͛w|OO/^(;"Bu,Ը͘1̙3[n]tcPثWBeBaOfRv,fggw…qƑ$pB%|5V_={v=V^Xƍ?aeBbӧOSRR ép8vvv:::!r0Br={zvw Juw[S˙3gƚ,ERw`Sk.k솛odɂ{fqje1X<M,u\'S-6[Ǧϒz9S^|^zWao߾ٳ… wٳFzM[[{Μ9ׯv횋KXXB)&X ?W&Y5nb2_ېj'l s OXbi 5T$|4-/Ɠ@#4aOpX翽S^h>>>7oެUׯw^TTtձc*;diiջw)S4u5g!j|lW[د#*]% !:gPҸp3j1 ²BY3)'ڲN]RJڷoR z9*)))ٳgqqqDDé{jjjgΜ0`ܹs---{B ,o߾6{%yy$uԑQSIU{J͆'|׊YWWښ$ɴ4ggz?M>=55ڵkM2R'N=zt\\#B5(EB]]As9te;Sdy9m@ ˡ8OhHv#GX[ٱ/55ǏqWP j|k>ۣg $wBM 4+TD>~9ZV4 =* zjI'{kY֮#t8 }%g_kl8X!$a"?1sЏ]=368osV/gD@JjC&e!e?9޴ ? DZUc^jLjhT*d2UD$>htԃmR^.;JWg;*puvDo*[|q;]ѽv>zѮ_i&2Qf zB),444K@nѤN/wePZqgue~CkY6FxvkèN<6ki% uf?tv}~{WSʼnCjhޞN/h8kĚ ǹƜ JKÿ\Z@.ʍ2 ׊ˑ9ݎ/8pƺE^޶g;]&D=L<0X3K)7>o gBMBJr빤5=N {qj2~<!M, hgfAjd!ԌMC  sBtSI%ot* mCmg'ryLr.=')tIS\,4n|]ix =qPG&% %y?V†N=bƺB5'}F҇1\.Gz~Ai3pTW ja; N.?zݱhd[ZU Ҏzvѻ*tŧN.\Y]q-noFլa[_xpfǖ3?9ܬ&vҨaN!/9H)+InRkk1 7.{?tkXGtל~ Ź _5m~|EV{5" '"%ܹ/^xQoN IDAT5v,bG^Duwo0YN{!@WnOӺZhYV[y=_3o!Y@ڰ"lowX-'t65 ;ߛXQO p5EJGRSϞ=;v)Y@a_2.xJ]C!Vo1SeU㕦6w\+~ە4LjwUb/I2ͮrѤ洧.KXAye{kjՕ@j=j_Q}G "DJ`jj:t͛7߿}޵zܹs'L}.]ԪK̖Q~X==[%] ߲d; jo2N3A>TM{B-pjwf@v'u'N*MWd?'vKŕ"Ourp5Eʱm6]Uz5""󅅅^^^˗/ky$eCP-*r]fe$) Kay$%kӘ+ުsF!q:沘-nl&cD Z9͈bqM:OޗX.1P@! 2Un1NCICTe1^פV'&,1.Ud (L "q!JXu^+y|aOiLMM~np )ݻw'O?OnnnGSSp86}Ǐ/K%Pᓟj]xlC;d:wDRQQ9kTC`!iٲsN>yŜ/lm۶w޺uTGΛ7;344֭۰aU{bŚH>hu~n#=hq'~x~5xgxW?tJVoFSҕ[zaU9_JM3PƟךwŏ#^:v| 枼4NVQU-l۶""cRe} ~uªp3 ["Ľ L% UX mcO^޶sOm"A&ɡIs-"tZ@O$ ++b>`QL&+...***...))DRٳDÆ Օp8p7﮸Ǐ/Z6lX^% !:gPҸ5]_D`s 04V ɱ>C5 Y7Sdqlnֺj ה+@zLarnlɜʗE5 oV^^~^za3fc``*`\ۘ%6Ҭ߮ IįpQg?Hr5StQIIIIfT 4:$I(-sw\t}!f#1Ilc*ay\D>}c~~~nnn6LY|q6jvT*|:Q#WQP.ˁ'#ݎ@0,h;o6*U 4/Dޫ /+---))QԾIIIsիWKKK7nܨ,Lj(r9IE%fGb׈Ĺ.yfv>d8|MQ+D.J߿U\\JJJ>ެT"uꀉȑ#g̘X2LPFEol|>slε@ )dTJcܮUS,;I ^,޶gr>}4Y5_mnK0iE}ь7l TO5 =u}!\Fr~dϝ R\.oݺuÆ [FFF[n <:f gq\MMMmmmkkQ 5]{-fhRaI1c ծ|G[{eTmsggʋ؇ ɻ<0orɾA$'?#5,K5 W'aIaA6fS7O[Ŀ2+@w;qתI'tݑ$6:Bd.\ٳ֭[uQSO&Hë1ԀREҴsGWOOf:v[ ҄=ar gpB>jOՠO ګ7՜0Y5V+|жѶ]IY엙"ˏ'(-08LÒD'VNmgWx~[Ùȫ?r'B'9^ *_-[ŋ;w|A0BMj|#T(%ꅼ_^jtp3j1 ²BY3)'ڲN]RJjFEo~~ob@E Vԃ|js_z63j7nouX<77w֭&L6m9;T&X9x7і˾_U*xզM;;;ww={?~ڵb 88X&õB*^~իk֬ի7Oy߾}kmm=k,Ijj z!779M:mV_UŋE=%%%@ɓ@˖-ϟH79#Ea]]]]]]-o޼Yf̀NZ^~t?G&ʍew:]޾/ ҫb vZS{qĝE_7>;ZWTuE7oܻw%K\~z 5u`!Lyymr/^f mu]oA̭ZQ@\r_}W\nc*j5j0BՍ__߬#F[u5ۯo~y"RV}WF~ B5D~4) !giiugW |+Ruϗd~q*F 6}ŬB}/RWڴicnn8:LPCD+_I$4~a/~EO`%&Xikn)PSS+//WvuLih__*TKBMNrGv~~cHcێ<"_goy%nH9]K^Gw}{:\ !#X񱰰HMMUvuٳgA( Դ@YEM&XqppHLL RAB IN|*~>411ҋ9PSSwaPx&#RQ*~~aiïsZT|fb#Q^JK\~iEO~.]MyU0y籩E/n޼SkP#E j0BƱcǀB.glgk^gDى1RgOo;.I\z1 d/IcwwSʫĴB-dYg.>:Q ؆` QvZAA WFFBM&XQWW `YbR ))̙3?3.͆ LPԿ뷚:`%bAj1bh[{x+ I}|>o 4tJMI緲} 12ьv72ysҚ3gNF,-BXm޼Y{Lӟ~9ܾNt*$lQQC sRS$@@*R h4Y 99)ѢF/|/8eI+eW{~5k +`QԴa+Fދޱ~6B%KEG):֝}q"k+J{QXZ^. 4b r ?O-UdE0jr $&&f={2eJ]Gp]WM]Wۻ2 ?*. B#X` ,ԈM>e@;8v^з GEtECe+14w1&2Fܺ$вs1@L{qQ>o!ԍr_QL[P H$(5H|}}[juСa .סdu-Iw$F~_? 0BMBu|՛6q{uBk1[Xڽ[h\cgO/%)0X_ɰbbb|}}e2٥KZlxQ;~i- ]Vv@f 7Fhն-8o޼ѣG+LVQ~XEݻ===lvTTu6d]38,IΦ 7f($DW-_rG"W;Ncɲ^]ziq&3HiVزtXW]ΒȒu`z})v =8|ZsYLV^c7|󮌓$Mu f+qndK1P jh\+7;vѣ{:ohEnݺM:޽{VVVmٌ򓊖Ԭ 9жYNPtltnQE'4qϲᙥ2*ZZjVÄ(Py(T1HjV7oa g\׮ĞُffSx-  Q9@@=L&-Xcg h|-`EjR(ʐ!C xԩ7nرBikT#|}}{X }J¯V *~^w}MbA Y,˫ dR^VNLgִyۮ\@[wvQm(G&GMêUH ˵`2k9ƭ0xuDs6 5A:"++4+}=#Թ:"זg7gWYaa?|~֥^1i|;mU*=62>YX7B5DAU"#H3뗙Cg)k?zR 7O U [ u9P ڵkĥse;Tć?ʗZ(l]4N YzϞQ3_@Y=FHX+}-Uks'y\o dG2q!.ɤ#'~qSf}G^z B!%d/_!жէHRvlXhV@:VV- T'B!%JʎYswwܹ9o޼mlmuBsɄmhn2ωe$W"%>vU[G NL;#I m*uN}pI}h e w叽C50:vM#F"ɔ}{,BJ񬭭Es׻wG)rf9 vO\6ڶ˶?3K2S@we={XҀTJ(VNmgWx~[Ù[ONr,mc;0`!JŴfI*.F1}}}eI.'''wQvy2q |0W˷xڋm4(gnJ=C6~H9FW^(Ycv{+w׳S.ߎjjjj Lف(GII hjj*;UT9|CU#';m ߕyn š>B ]]7o(;Px˖-JPLfGkj=.heƽ=8x 'fYa~)B5++#d&g,l T&('H֘[ONʼn[YYCT˗/ˮWTTɬԎ"*..~V^\ 1B5WWׇAScd< zDࣇgfW3K\0j?Eg(6D߸ϥw*[GW;ߔ,/GB<"yΝ;<̬{6 255?@(ƍݻwWr|͕:JUFu ,PڵkyyyTTTMw |pege'ƤK =='q$E$}M) 執eOtdFJJ/Y[X"QT.WXįe$\<͞=U>N GVjtAEj,Pٳ'=rH $PB^U /xtQOr$9<:GH]&B@7is|P7ݥŠQT*q]iAIP()e۷ogdd Mv߾}I?͛RF١5kA嵟W,Pñ3f̖-[j8akgW}WO3OܾNt*$lQQ^0'%>5OT R) ʀFH#-ZiT2,8eI+/xs5k6 pY:(Z rUeV= !Ԡ455nj :V,Y%"ECѱ ]]YVڋԔtɤ,M\#`pX4yl|jnY 'Nj49F '[N[[W ƾ J#X,PݷoÇg̘G0myQTSSWPScPi`bLd>u'Ieb!;n}!o`|B۷#¬8[?R.' Jҫ7n,YdРA'Ni͛4mJ>`QPC۷WZ֯_O$,J˗:Sh}{ªOݬB;{֛Gow/$Y ޻wo{MDD۩SB,\`ƍ;vPSIVTr/3K׆ϝ;7rH0Elv?~_~zBʱm۶+W߿#))h\Ƕ]SD- `ooe```5"ϟ?HHHPv #LBJbŊիW...QvDN*:tm۶!!!Ḵs5h >p/`!ӧƍ۾}ѣ˕WM$+W**PDFFnٲN<.sfifZ"$lEk-E"rK.)KܐܢI%\["JB)EHD/6r~亶T:#u;=y>Sf۷k?r䈋޽{###h42G쪪'۷o^  ޴i\z݉A ~~~ׯ_OOOOLL,))':7d999uuuSSSCC)S(++Jԥnذaƌ6mBZ*--cС&&&D@Ƞ6uԩSvDҲW^Ǐ8`޽{~.p pիWmllX,t:=::0sssќA󃃃Ӊ+ruu [!!!YYYk׮%$ ,@wW^8n:m9::~݃`{Е@l2HNN>uщ~!-9r]tiii .**222RÇ߸qcmm-ѡ~ 555fff bbbiI"UTT̙SZZi 8P`/^۷VII !o߾o~6NRUUmlLLLIIɼy|~'$CA6l@R=zyv+buy~~~,kǎ&Lh.zzzNHHlt(]ֵkΜ9*;w$HRRRfϞԦ.\m۶@ eݻWCCcݺunѣƍcbb`¢O>? 6lɒ%yyybXΝz7>x@MMT]˵b111L&zhT*'z7_ e1 kkkw~_듓;ֿgϞ999B@g pDFFlܸҲ]M4+""B@' dgg;88}g͝! ,fLfxx8BJhhhXZZ O: Xq;;ϟXOWh?)))fy<{A]cbbǎ+&8P`q +W!ϟf͚ݻwGEEuX~PAAytuu:t ??c.Y$''C@X#8NjбT*b2:Bz괴cǎihhtpJJJQQQ/^qF=f'N8z͛:mP3gٳ@m233/_nllCoذƍ<4m6(//777WTT$ɝ 88XKKkܹo߾h%(@ ),,VPP $dLLLCCEcc#!hXZk˖-/^ 6l1455CCCܹL`  ,r۷/[ޞ,h֬Y %: |nРADgg+V : _ @ ̙xLL :d29,,L^^ʪ8| ,-Xrefffxxx޽nݺ>} .D?P`[Fwy(4+55uÆ 3fشiYj*;;;K.mŖz:~8aD/X ??, o666eee,KFF8-(|k|||``>YZE]]=$$$++kڵDg ,_stt%:KL>=(((88,W.Zhȑva9,'a}"{455]zuZZfP`OMM8}qڌD"̙38p=uꔪ0hCzIce}*3i^i:Mx] 7"a$_o#az0Cq8W+QnH𫐕)))7o~h(h! &Wbv1a„Әg *دRW,'o\VteGj߲kt;Rٳ pγ&VbuM4ДiNOO ^^^9hVӓ7D|%%%mNNNm؍$73(iGf01͔RA1kwR%~Ieyyq+R}g+p> zo6z߬AN>Kg;϶R!uQ/OnYpömbcc? , lM>}ʽD`_-,,ڶ LVC;!L< !AUeU+U8$9.]rBBxMfd"qrn.:w̵^6lؒ%K:d9@Uk1C,^}/@v\WNbç}Gx魽 z2R*z+G,rVVVl6;&&dh7)8.`$'#!ROs#I !j xhh*jnn^WWAVۤM'pOf(@[ΟdRϭ&,+{ދs-"}ӜoٺΈtcմM7kKN,0Օ`T1_>99رcF4!$6~K>IbƬ=8B_~1={qppAPT IYrZn*DYK?_cVqN鳑`7eg_*Qvzƭ'xO<=Wc/XƠ5H$H&^ddd@@ƍ---'`8I qS"#Ŭ{k>BH*eo;W*!L&c ʊK3I"""<(~q`zey7]ӹ=LBA__eYYopц4"oI|^!$!!At 0MFFFB얤jy ˏX MNAbolȶ .^vϫjWVIP=DK%Z1jnnnNNNB|_}N1jLAORi_QeJHshη q?|@|oэѧW2qǿB$ ` l6ʊdS(-ۄ|>)eui];~x;"IJs08u$v8s=h@v)f]&LE]1S0SREK~ U,NRV01$(LNOGA~(YUU*H$`} q;;ϟ_vMYYz kmtk=/x{>~I {z{q}[#֞5KIIXѣG[[[ _ju< :8cZB!DҴ=cihĸ}L 7!dLjӇ^fqZd"wP V, _jj=[k-|=ߒE 4Ah4. z?vXt%&&r"!D7}cZ^\;OwYIkj4~3"{uP` kN'7f2]v\l0x꟝RN%(**4l6 "!!!zʕDgT_fݻ5]VA!GsLw&;nuUWW#mɍZ|cug}o7:7%B89,Mj&j?~,''׭[7!h8!: ͛Dteff.YDWWWHRa ƽ9\TįiBx:@5S?SNBZ-@@n޼9rHSX``‚ĈT*b :ݻ?cݨ3w\"}i53X|)33sĉ)))GУGyyT&33sDg 6lruuqY@4Lt5X?+.۴8a\.0''͛YYY,kΜ9DgBaɓ/\ph}j###d2qDEppGΝJt*111={!:H u߿|ݻw>}ZZZZ]]]YYYUUK&v&9rHŋ/_~}DgTƦ0))IAA&]SZvb9111#Fq㆘eߔ|m۶eP` 6DFFx}vٔ9sFRRh-K8>wڔ===uHJJٳ'0̦Gh}(;;իW?|…C 鈹!ΕJԝo>UyK;yf!&<'6aJLeVͨ*3}oTSmz#e2Aa6+P+C f[r!C ADTQQQ\\\ff&APcccmmmWTTTWW|aDȂK]pΝ;'N 0lٳgϮyannnIIIuu5ͮ2+!$%%+++~i87o>(b:c ӔS|3.%IK:>#EtOVw) Ӡ NL#8d*򒎻L{Py-{x{7hvw¨7gp !Dw a^s_pEg`$3iHr*ʌ-d%$ZP^Z.PA!ЀBoy(쒒z!z#}7B}Mjj36m$n,k{Mt@8x`U%aHPӴ_\X,@$'/O &n} :X"G  ~J?0^CAgb{A+vh;F]7eS\?LuLqY/p1Bߍ1ry&W)۞kk"s9_(sLgknWg>QKQ\.1~YPerC[}o$++SRR2o޼"E8dɒSNteP`O ~5 N-ܺn rɱA^Hg.=V$aL}C)wDKY[~y;S+>v8s=hD5^Z5g͇xPn?+ή{Zi P碟5[l1efGiwᄄOOOEݻv1a볆X,Z\ŽE rO`첫}bz Vsmxv{Ilq9e!87s EN}sfoէ$rpld0ڔ#߹:ޟBvNq!+rȬ *s=8xQLE%)V}UWn988`-̟~:B={@ :kj Vr9p+^xQn#_#VQ@!:0I)I !4 p*W!41 !H4:9[2aB=}O46]+CBo^;~I櫲:NCr-?dff_[[-|޿omm @%P|{6 cRmgIDD|9%ű6"?d!c=m:/|DѢjeeum vt&Ҹ\%;z*,:\#rp>f _&L>{QرcǎHcUئ=/z͞+=b!%g9鉷k4_(_ٳgdddNNCKmbNNNn:vX~P`2EKMܻgbqc-rܦ=!'/5$}A'1n%@jLE[S=UCsm{|Ͷ~y\7ʨFI&yyyEFF5l""";>.nof<63ku}7(7FrYx'Kޞlj un߼cw/ Q5;7_>))u/`ddrkkB644D%&& 䰰09s攕z+++`0gвnݺ>}N !VX޽{/AUFw۷8p 44t֭&&&DgZV۲eŋ }'=i9sfϞ=6(? ,?t>}jkk;r]vupX~D WUU(--бjjj ӧ:t, ,?HVV6&&d޼y|>Fq|ɒ%NRUUQ.(8==Ç'$$xzzvwڱcDŽ :h ,pBoow6{l'''w@ǁ @{8p`ذavvvO<b߿ 5E ,EѢtUmmPrl6;&&d O: XgϞ999B֭[ǎ߿P:3A@8&Mή"""ί3gNjܘG\u :RTTEbccz ^,#}bՂ544>|:fJuT趱,/a~I-TKiFv~y#UVmmEp^mۂWu݆EUx V@4ܢ7UF 31h}=ڕX .sZ#]G!)(J7TT~3X:ֆ ޽ꪧ7yO?}y& 8ٯ2ҟpe8qKޖUGh(Jd_͊U \ZUa*Jҹpyq^߾YԴ&BQHd2C!B)UņH$ @} ,.88ѣG666=zhXVT69ň@"2Bݓ'cJޭ@!AIֵ\!0zp"C!2Bx (2BF|!q11q9PQLu@Y !yYcD ,^_]݈Kо8 @@IJJČ1ƍbbbܦ<>9YAB8S*%24!D27XFS+W:;ڒeϞғQ_͌Qjn tqo߾}iiiieeeg+!!d2555CR;shDfhhن 8x;}ˆ}~!魴7MctFR :V_W!}S\ x8x|G \B%Eƚ׵X縀'@wѫ%^P] tAOTTTbbbaa!anj3mڴw֍0k֬Yλvjll rpX|be=>T4;di'#HZc ?"+(>WDa?JYѥehO VvSx_%&ݏ{o ӠP%TAr|!4')OLOOU &S v t)l6; ߿{cƌRUU\.iiiׯ__nƍ455;'"hiiiAAAÆ ;OaFX`!1e-I yijF2M\$ڬi7ĘʺL !Y$Qe" ڀ`-2F( 8F X`XNNNk֬ߚM`,͝;WUUΝ;󏉉 tttٓokk7rǏ b(**jhh"rDd]NiVObʔ)Ǐwqq}ÉN,EEŠWܼyD!??!(ʌMYg ܕ ,s8qϜ9+RV122s玊Irr2qlaaa}ٳgA@P`333ɉ9s&qڠgϞ7nPSS9sgψ@Ƞ?1//ׯ=zo.]D&Νp@?L___{{ ddd0A~Vwn^'#0rrV0aYyy|޴ׯ(KTMqIII[l!:K{رC ڵ  ,榯f~…޽{Jt}D={;v, ,`iiY\\F.~zuuuQ^؉ϟ6⾾m3.c GU/xEE#{1 S6~^4M4&Msuؤ!{D92F kkkccc[H׷ۻwonnǍ={TX3 Ҳxe37<8-k σ\Tx eO. #id!=.U%wfZ׊BHPtqΦ \r +N=zŋ@@%*||| eiimۦOnjjJl0tM))C6׀wtKPn#س򊊂})¤VVfnrA1kwR%~Ieyyq+R}g+x-v}ֶϸ^VO9ٖ1 322JLL{ݺussssqqѣBǧ">|8p@ xEFcN\`.P7Çr%Ha!IqaJ|AEye+U8"Ir2]j($!d=.oæ /go4AΧZ}=y}}r990%B֭[ptt!ŋ}6}#L7EB!%_n3VXL.KJqoÃ%/ IDATÓjZ64pq^ z Z»IJA5N9N+`(;YsǸL"EcHNrX#f10%^ѻ0 kk "DLLlΝM2#:4&-'CƐu9oj%!ͤb.pBbbSQ =m{%++ڼ'>(bC@R׍st? uWMFRJDS-7wѢEDh5kGݥ# FQ/a_?y*3'=@zOsk<`8kR"Lnv2J7HuԄى+M.lӻKBB!T[[ۖ@}^Otܵoː/~{ b=X*8,՝9(D?Uj:H0a„ p rrr"ܾBPvbBSAN"uq, "Dq1٩7!'<>sxB#)Ih6kNb]x5("r222BӻwB":i#KI38/{>m,&t"8^(]BeiȔ_R%{V$t[>;5/k[z)z0)L:[k>*(00!Kt[MMMddàAh4Z^~'쟺ܹsO)9:::/_&~43w5VeӶ+Te).>[橓{'g]~S;~^ "l2ܻcoՑW_Ο*ӳyY.Q~p~*B񞜽4ywl}Ԝݣ^G_iZ|vȡ|q6ӜS~[e%#;i;oEZG`I}ވ҆l8:MO| Q{|ͿpGaL;wFFFʎ3D]]]RR{ ͮڳgoϞ=WXj*&i1D5 Viii~~~]]ADW3X?!>]- e{jf]uCUJV[qhSpV(ވ8ސ Vc 2E 8F$YXuբ|k NY<qAf?B;w$:ϧbʕd2`,]4))IO֞:ujԩvr0C*۷9N+(([\\\NNnΜ9p]Y/y,QRRRR_^0#Ia!Dѩi>+E2# PB,.Nj/zˌ6ԧ!xCMrmv=!T__"O͛ 8rȪU󃂂Ǝ+"[YY]t)==]__Ŋ'Nl:Ne)Byzz=zT 5IEEEZZŋ/^ٴiӖ-[.] /#6㬷MCU^5GI*!j6*W]]BH\\ŖࣣGXo߾Ν':N^zC^pAv(xΝ;fffeeeVrqqQVVͭ[3gDFFt~Ni(>{Q9 ԥfn55Ѝ{s&_[Ӏ#/ %Ij4&I|zlvڵ4Czsrr6mZdd$qZfkk;bSSSCC#FP`ҥKfff={LHHiژWUUխ[aÆu}̘1V200HJJ'69jruKM)YNFT&fjc[lݢ~8 p-_9j㸣m Ƌ? Ohf,y $asQG  (Z-<<"""'X[nN6-%%i-_H̛7OWWΝ;:::PWWӛ3gΒ%KObddtM˗󭬬\.tdQ閟qq6;Q)Yh#tpp044 &/_0Ҳ8AGzzz***o޼qݻwߟ>uttlZ+,, ð۷ wvQt%cǎE]x $:᯿>>^WWW8]@ׯ_Ϝ9޽{Dg ~]:aAIѵH"We8M!MItoz}xٝCLzH#,6rs~ѽe ymS׳ڷXB DDDt"'% xꕸx^Bm7))iС84אշo_eii!%xn-}giϛqw޽⾾NNNbb߸QV]]]]]f rrr\BPo---Ӊd//f[nFQ(d7f%Nf0.T^KEf;d9IiޖKgN B;+`q8]FAC(:M}!tݻwtww߽{@ `0eee˗/_|3#F\t5-J,TϘv9;E X}fH)eoi=<Rs*&-tur.?Q%fy}^9~3jvy_5co>N\YDݹ9enny癞eVkjj;vر~\tA7m__enݺkת'r @`ll|_[fk*gx'U"InmD}upY瓃q5 Xz=E.')++|2ٳ﫮jZ:cƌ?qℋKllΝ;?ΐe\Ru\CfΏo`fe 2?})]uiYw 2 ]o\I*l+OGY1:8R4`[}/>{wޭ6g$r G/o+b'ׇ*B$9kө_;6KOOG~G æL{.h*/Z(//ãJ,OO_qO`J1~7ׯ=#~bĦgfuXQR!S!AmyyP{'tG3تw ~xȐ!-*..nݮt3$)Xa^Z6eee^ fR1{dKIL3?7 ^q g>$4^g^Qyyy'G4(: JmZƦg͚գGP\\qxUe\dgg{yy 8u8dQZDjxy׮e$ħsq 5UmB ))aQDXMFFfʔ)GeيKRRJ縸ϟ[YY}MYF_V*;~h=z νq)]36݈xF.]pq G!W[qZRzZW"ƕ .%<,B7/^xVvad3U8IyfmՀS$#^sӎJ?0^CAgbo||| ?oh1j9ce ~S6%TGQT .tݨ.gB1xe&Ҝ!>7Y6tB>'t5&CRuVDjhq2/?b|79-!ۂ2x򃇪S0*z~=¹\2pi$A?+*ܒRa:O^^^%%%;wD[4559ΦM?7TV60j:266~:˾2x]ʜ8+?|2՛:;\pv^jrvAq9k rr 'C~Eas8ѽI 01E醊"OI*3ޝt3$e!,dDZUE[uVUtSER.R߽j*"vB"  !Ȟ2yLHda&|yr{9:=jO!hN8dy^.yA70TQ"PW58 dC̥_=Xlo `gIw.ћ= [r5։K7ܴ>Vgzro7=9- qk'u,;ts4lOލG㞼hSݹEqNV˵*4 ;9FxhE7fÇw#6m@##g֕`HM71}kFzJ8&6fp:ci&J)e^^cڔu3k' !eͨƪ|@Ov^9 )^`W`3z~L޳gœ.7sN^wD&ߪ1sU$95^O)~7MRCP.7`yM]xMQJf[r"}KiBbf4ӔؿnRvlhEFF4R'v0 32.jlذ!,,_?v!d޼y3f5_ uݸqW^,Ν;w˖- .8pMQZDu˥QQWlqʟ:~RFKEv杈5K`>Fr9huvڜGtQ"nbGXv#DBZ }ʈ @Csmy߉kWsq#s`13A 1PsYLMm4,TH$nL74 1? @%@( Tӕ7/O'@#Tkw44Ŗ,yDG,>q76jqp{y lٲ3fo~͚5k֬1rƹ'O޿)S͛HSw/ypV()]"&T. j`z T7`CwvP&eR {AQ ROoIBRRC׳z.8c1kYӾrJz^(Ovv__"f҈;:o[+): zH$P& fe/k "\x.c)lpN3o~S8+jejO>+̙3'((hƍݹ\^t飏> 8vƍׯ__wva]\%QҌ'jTR" ZT[q%.F#0MS~S@eڹkJ2Jװ}bTsmx+忾V7awtzXq dWE\CR_o?bMqd<ܦ(/f0UUZuh*z˚wΝ;wSLuww充YYYEEE\.Zx #¢J؎G^;_FPF+Je!b2]o.I; <<}z)巍;OY]MD}EvD{re Gc^׽Ewrˏ9&iBʨ5^|={\rݻm۶:thll/`!] /:)rA@,ݛ$p JIKLHgR׎>R}9||OꫨyW<8jv5w̲0syѿY dJM8Ao,C.ow΋<<_ciWw oZۦԇ f7%뇒w>uҳGMg͍ @1w@||uAO_?mk#]FWὃ+,@ ̚5kٲeOu+INN߽{# {6mڄK堧^pqq9pQ=zv"p>EYН;wZfy1XQw %:+)~OB!!!.]gB?UʼCl_kPU~ /\`Dfȑs}~֍yaZc2=85 ʽ+ro:N'V\c+N%}EFk1X`ή)/̙/d!I$ ۷?n}K۷o?Ǜ:IDAToٽ{gZ;)3݁ !ۿ ,899X; +,,gggk'32}S~W+Vxbu]nN>k׮cǶ_NӀZ7FUNz>76 o\dfs8B6nݺ._O>B$BJļN׵kW;;۷ܹsɒ%3fhdJ޶5(6J^xE_1#$oqˑ"pyaML$eϜWbcfqߘ.3ɣ翛p3E:[h?+Ɍ]- 4ipwd4kX ?pJɤ̤,S`U d,pF׿[}Y)iU&տs+HJ.^]nĨuJVa+ *9(SIҘ>Dy٠ P"a WcPTr*OXe].ޟq wO4\0{~֞EumC՟=e5l57#wluTWT *#żz%9|FR0ᆊlոCgʫo;|,T7V<}0jQFyܡD(5%<}m'6m9-6mv"r.]իt%!!4hP۳?`RIFq^p}y70\#lä@0}ҼN\F1`jjR^\mOyPK)ƫFtܹzJurqԘ;wt/8ۯ}̇ef;w ?4Zn)B-OTTˎ;F R`an]. RЊ;Iҋ bHO 2s#|% _Wi R餮2P*RpsP:>p8=!m={TUU9PQZZx 6kN2)kWQ`uI릿 { LNL7Q#jVT$^a";A"Q>ݜSMO}i*PCUyqhtPyLQ>`"#:p6g=w,<X-R]3oNWk"y>?=\()IP]3azv kTl^\J\r9`2$Z绿IAꍈDBZvn߾*!5k,]T~G}T*mڮXCLwOm|8S]U]wu}ITKfE&U:e*"uwoҪ|-;n\r1{<<~8s;P`?柫߻_r/{+N :kl IB61c5WUMjPli5e*)DS-ȸYl F&rNt'wjbQ*un:vEpϦ]& iӦua„ :7![0L\\ѣG^ g~#S@7I7kM""@G6'S.QM̃Ңb#s'(NY}JGu9q}>zQn X`S~\se֤(GY-ڵ`I%\,+yIrc֏ ~'m^ْYV^=_.[&֖O&WEJeG%[>]wEDǺ_4KK?#DgbƛbxjCΔ ZtU_1"QhI^~Eܼ6#ۻFٔ]VY.̸.n+W| Bv/s^ъroՇ ؟)Hۘ "wڕ\DHdvpi49s<cFj M}1QAgx{i w`?rFټw}ج2Udޞޖ\n(H8h'S',fLW@$]b=ُ"4ʼ¢D%wh¬qqqofddڵk!B$!o|x E}}SןͯmiIY{x_?S_LkםZvDo<g4u P3PNji^w-_s5{Qu2'P` uMEX l|2_lyYdWK֬P*7nhyu%!ܯYF۷o"Z$Zkqr #tx$@ã?8DvZq|wZ2Kxx7MwZyxiUۿmo ~}vc՛6[tvO}ʣ m W嗟-Zutf#p 7TVVV~cƌ3O)=]{Cٺ{:::9s[;z ]v ̞=`04LYQ3hL؃ {pB0?w/zG{AUs<$f#kD&ic9ixǪG*m/&[iz1cƬZ{ĉ'N0m̥K;m۶O^b7B"RohV+**$I<<<$ɳiJeyy7srrݻ3JH ?wۦM}ksGrN8h"sN,WSx Z͛7[qqq/^ܾ}R||__=z|'x9  ,Pdgg7r'{Jx<<"B R+C)m]z.|>Ō'C=bquuu۵(UUUR;;;k' wBȶ2kgaaO$˭3B!d[|||LVߍ7ډ<#X`!B%$$D]v I!Y;'˄;Z<'ۄcB!һwo)De J=vAеWqpF׿Y)iU&տs+HJ.^]$/NNun]<uJVa+ *&FD TR4&5qر`ggyrZ B!lgNvTTj"W w&>O|ݻgGZ-5Z~36lf@+ΝJ)*0WEU9nT;сwV)[7BN2m=j%%%qqqC ih !9cǎ={vZU1֕ˆ t) yg UZT:L,n䪴Qט{6мsP:>p8nPw,mf0z뭿sNZ,B!3a„ŋ/bNhkripT$B9[w)@г[l0_"g ".h.C\F1TTxjB'7" 5j ءhV^/Xܴ X`!B6aʔ)+V|ٵϘ>(hRMB%bB!gy^RBx͠PwvP&eR $!))!KФϲbŊ]v5i`!BO?uws%SҌ'jTR" ZT[q%.F#0MPҬT*(Py"{v.RWO:vEpϦUW)))+V3fLtt ,Bo; g|p?F$ -˯V(ۻFٔ]VY.̸.b5 p 粲ӧGEE@BBs[]X!P0qĐ'_Iڵkgްa￟ԭ[7k'eMx!j?o߾˗O6m̙ݻw H$dB)U*J͛W\9~׹\ѣ?gE`BaÆ 6,--mΝǎ[jH$ɓ'=M6VĦ`B;IkZJ'uu2R'B+.uo+rU!mf}j3b[{o"צM^z駟~?H$v:!KZ#hk"ripT$B9[w)@г[l0_"g ".h.C\Fjz4 U-J>YQQZOM}vJo[ ]U!lʬY {k'ɗ =< ZT'wwX(78C@ϘkP's F}t 3jzzK rtMz~{n> XիW-ZT\\l\B.67WU$D [q:DsJJ"!Tkj 2dhF \.'0vm vNjι]60`@߾}VtB6mҤI&M^VjBl\.W&d2k'` >dDBp;B!aB!daX`!BYX!BB!aB!daX`!BYX!BB!aB!daX`!BYX!BB!aB!daX`!BYX!BB!aB!daX`!BYX!BB!aB!daX`!BYX!BB!aB!daX`!BYX!BB!aB!daX`!BYX!BB!aB!daX`!BYXeB!Ԃ%''_X#B'"RfB!,B! ;h!IENDB`crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0012_System_States.pdf000066400000000000000000000303541415120503000305440ustar00rootroot00000000000000%PDF-1.5 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream xYKoϯaG~ X6!! (XJ )C |U34egQ{o FݍzV(w5#_G|9ғVWrKūV]U``ds0!;d[^]^CŸqqv#>{vuљ+˷..m-fy*xP&) vpx^SRi首V[edSroU~wxֻvfgF|5\'uyu#v_}\=&q1bB46Lr:N!fJ,]Cϻջ8LSp h\bS3uYr1h/<`b6ʳmx4Ʉ䠬ScѕXvvX´kwd)!OY[[wq.lFGA͎Q^]ZS? 8Tx?^]|zAW?pߟk>W_?y=(*~VWi_FC\RRHA\xS9Y9Kt$IoCʿǁeBn$`Pb6wԡ0=j b2u1&ܚ ~} bA O8a]>,A"0h>ɣ]K[?"3ŗ4K,'2O$~uh=w'ۦ@ӈ I0K$i0Z:'-:Q%oL_RL]{}LomW ȶtP"0MBٮv[v T.S6^J.h,O pPmm&ҾMXQ~Gr^+EM{I=WvOcWyxz+}!yAU;M m88;{؊9ö5<ۭϴu^es-MS㑩sݎ6[1 : ;cY#ihϰцN9oXu6 ZEZmP'$4$Kcsg% @xy8/-\=n:`NC?8bM ܌?niwn#~s"_/t*{)at6|To^>"qRkdjs>yޞ3Ur9KS4Esɬ"̠jK bn"s+7Y4xnDxq;戫-t/m4YmVuni( _n1-\E,'pݖ@(L/* GY%j}}L$Tr#t\d!)<˳GTǏ)gmꂶ]=tp߆5 endstream endobj 5 0 obj 2324 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-1-0 7 0 R /f-0-1 8 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 9 0 obj << /Length 10 0 R /Filter /FlateDecode /Length1 4068 >> stream xW_TUsA@dfDdf`6Wd$VS$$⑨X +&0Q1rMs}ڮX5{` (W3Ic=AO~9{}Jx(N}:MU8:2({Yɛkཐ 9e̞[+8߀YoLMh/N+Ȇq$Gq p]+0t>#*AE8IG5NvzrG#h, N]@L%Q0$`3@k6 փ7f)([Vx ',,YJ|BR0^gwYsckyket+ܨAo 0{JF=3gSb[@mR8Lhd,%kB' Fsp)?lP!f|my )$$W~KcRcDw+UO 1?=jŁ1eݝzl4W/`65d܁ͅ}yg=D7GA^f;ZW(uf nMgW&guEj$PJ4#; _#i|e:e@Qp *$U8p iWuS?x*dk#/gpwxKIщϋ鑂q.0zxN"ڔƳ|`0dvDK $W;{'uS?NIyiFOnŸ'؝q<9eZ2T5 8O⹠A!fDBB+Τ34fLMLش|\0aKaל[ 2a.2K:9VCR%)4dX 3kTDD$څQQ#Pt!ƥwc0μY.ߢ䅸!Шw߷ȴ4(s҂$̦O!@UUGg"OUU$ÝCnPZYNF.,׭O#ҺNxRFƕd'#Y]ve֦S']l2}*v"\u6D}at; xU2xsIH^Ės8B7)&`[eKo$ҟ]WS[MMky E^4LW5yd+uY$Yk lj* 4i-(.jkNǧ)qoW:-7)ρ')BZG!\!P'3_BFg\mTe雇<]T:I?,yϤ)=28PK{[]fg_1DCԦ}ڝ`Ť g֥X{A+R藗1%2t:LvgB*µt'ԲCZdYO/'HpNb{3J. A=/y1̈́Sͮ7.ʙ_E}f};476 =xTCjAavqDZo(+[KtDgCŃ=@NJ]Һa6N$"ScQS:.|"&Enc?y_P2%n jf[4Fzv ʬYӃ:oHB^)yZG:5Vv]P5zʙ.߹->3oRɠ) 8lٵ[-$)&NٻG>3 ?:E& ?Y2R<%zu9d$Qzn^9p^ Z1uk~2or]^OU)-dn{kl_;u#w0 _kiUQv/r؞U,-+cG6 ߗy@ch]g-߼uX[TAF76V&jguŽ C? 븮\;ܟq饢7o)ӄN^%/QH!)+SBoC.}čU2Pi>|'Y.m7cɊ_Aշ%y Oƻ$p6fԤOgIJx/= #IY"3cj-}֗,pYG_3@υ_$*"W5oFc9xSט::oWQ݅v.=pQr^15>.uoS+2g<܁̷ 㜻58!3FB#k9vWf-]u{I"+90Iim|ND;muďѷr}CbA?Z;Mߴ13}|2^|{;u_v~B[}R <>wܠzȋ$H5mF@_G7Xϭ5<߿F֐d~6~swޥ?ܱ w~T\[,Z$A )Y<)})R}_.T|[YkJ?Nwr.'9"ut*b"y2a,U#]+?0kW^8}u $A]/ +a&v[86ĠEBS`}*bs:@O7BtW8hf :`$vp((QCo,K 8QSXq=~PXc'G}FkY#8Ieu̒8̩P[# endstream endobj 10 0 obj 2910 endobj 11 0 obj << /Length 12 0 R /Filter /FlateDecode >> stream x]Rn0+|JRE/Pi? 74Rq"}w=J=NƞYyyYiu?Đ<^'qjU0T<^<.R4ģ^|iYjՁz{iD>0_,yHW{H~ tZOGRMYnu[E1;3kHI5kW˒jc\wkv180ʌ0mm'<[xZ41S3O#F&7wN0f12A6#ٌE'G/+x#Zu᎓;fdٹ#^KS'H^μCN$Mz endstream endobj 12 0 obj 383 endobj 13 0 obj << /Type /FontDescriptor /FontName /ZCTEVZ+Roboto-Medium /FontFamily (Roboto Medium) /Flags 32 /FontBBox [ -907 -270 2051 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 9 0 R >> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /ZCTEVZ+Roboto-Medium /FirstChar 32 /LastChar 125 /FontDescriptor 13 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 328 0 0 568 568 568 568 568 568 568 568 0 568 0 0 0 559 0 0 0 0 0 652 653 0 0 0 0 0 0 0 0 0 0 0 0 0 0 604 0 0 0 0 0 0 0 0 0 0 0 0 0 541 562 0 564 536 0 566 555 255 0 0 255 870 556 569 562 0 351 516 333 555 0 743 0 486 0 335 0 335 ] /ToUnicode 11 0 R >> endobj 14 0 obj << /Length 15 0 R /Filter /FlateDecode /Length1 420 >> stream xc`d```cp``bPHϩLP@JFnI C-_s''?@~M(`Pc[|Vf @;9x9YSQ F'LnZwS߸5<*11-"& IYMMM̌ԔDELmW?/]5W'}fnSܾEe\cb Rx~  pC<}$NǾW8\N ${?A~Ȃ#sC ^} Y endstream endobj 15 0 obj 363 endobj 16 0 obj << /Length 17 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> endobj 19 0 obj << /Type /Font /Subtype /CIDFontType2 /BaseFont /THFUQT+Roboto-Medium /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 18 0 R /W [0 [ 443 582 ]] >> endobj 8 0 obj << /Type /Font /Subtype /Type0 /BaseFont /THFUQT+Roboto-Medium /Encoding /Identity-H /DescendantFonts [ 19 0 R] /ToUnicode 16 0 R >> endobj 20 0 obj << /Length 21 0 R /Filter /FlateDecode /Length1 2772 >> stream xVSTι.O.wwD4`qaa! ՕBWaP!>PSN'(h혎mc L`:#m$5aR*ޅh:&Aoι{Ao)u<ݿrdgAZ墭nٓx 8[wCG} 9%-n砞W.Yԣ@ !1jB(G4pFR3H E96#=X-쒎|)_çԴZʧ6y @ OcT*:HՀNo:5I%rOX88b86V$.'q~qX_1 ѱd6j6^ԡKssd!v6(d&gg''eguǻ䵩_ 9͢gq Î!ƀ9NoZc9L#2lw'_z =pR/JwV*eX7Č=Mvuؼ4c:/Ŧ~Zތ~:8X!7ΆVg/%_-˧/$7澋,\f}1Ao~`W^L=-L B O фdq8}MH蓾,s}!#J[2=-aT=ū`G[8*qfbjmZ3~/f~b8}Ļ|=iV6~3_59(bDBFb w }}en]#X$.f;ĽB33P;3A>7D&dqq6{>:RøATi;hퟱi+9g\\a_~Gn8P{ЍvأmVm! Ԇ*&/I4YUq_lxWlG+.o󪶤-ߴh?_+?zI׌ws##3)kxc`dz/Ut051"a~ wU?#]SW!2[TpjVΎ?ܛ >|:Pj`RGE/= wxZS|~҂Smkn_o )B<>ÎR<%(gka!Q( (-DD|;'| endstream endobj 21 0 obj 1877 endobj 22 0 obj << /Length 23 0 R /Filter /FlateDecode >> stream x]n0 y CEZ !M݅hlF=㪓vb Nsܸq=̦ـ| Tz[ŷ:۲ԸaVU5l{s `1s+NVЪ@{k7!$Qo,uۓsY\%3[\|g0tҺjjeZ$`Z@|>1)s)\202dT39ι_E̋o}?r^J*&>t)P!q.9Y_@rs };t3Oxtx ~/yg endstream endobj 23 0 obj 315 endobj 24 0 obj << /Type /FontDescriptor /FontName /LFSABF+Roboto-Bold /FontFamily (Roboto) /Flags 32 /FontBBox [ -913 -270 2060 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 20 0 R >> endobj 7 0 obj << /Type /Font /Subtype /TrueType /BaseFont /LFSABF+Roboto-Bold /FirstChar 32 /LastChar 119 /FontDescriptor 24 0 R /Encoding /WinAnsiEncoding /Widths [ 0 0 0 0 0 0 0 0 0 0 0 0 0 388 0 0 0 0 0 0 0 0 0 0 0 0 282 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 614 0 0 0 875 0 0 0 0 0 0 0 0 0 536 562 0 563 540 358 571 560 265 0 0 0 0 560 565 562 0 365 514 337 560 0 734 ] /ToUnicode 22 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 25 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154042+02'00) >> endobj 26 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 27 0000000000 65535 f 0000011662 00000 n 0000002586 00000 n 0000002439 00000 n 0000000015 00000 n 0000002416 00000 n 0000006593 00000 n 0000011231 00000 n 0000008387 00000 n 0000002804 00000 n 0000005809 00000 n 0000005833 00000 n 0000006295 00000 n 0000006318 00000 n 0000007068 00000 n 0000007526 00000 n 0000007549 00000 n 0000007851 00000 n 0000007874 00000 n 0000008149 00000 n 0000008550 00000 n 0000010523 00000 n 0000010547 00000 n 0000010941 00000 n 0000010964 00000 n 0000011727 00000 n 0000011844 00000 n trailer << /Size 27 /Root 26 0 R /Info 25 0 R >> startxref 11897 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0012_System_States.png000066400000000000000000001352341415120503000305620ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxw@SWsHT\LY.DYu[GjQjԶZV܊ @}?PH~x{~Iܛ{J)p,]ɓ-[ @l2t+11f|s,]@l=m :re*ySRR@5`P_y1.ͺzME8MEEE=}g~7 U%\7R%<+l-ڱF徸aZpZnB}|둎o$d̴PCaν;E41 &'^T~bxB,}sګ$waJrPz⃙ePR99]׳nP۶m )!4FmHd%ُ3.ãZq2S\Ԙ C,SƆGi^sn??Uj{Qn!HVYmr ǨØݼO 1߉?lˮ:RG7O;՝ 5J+s's*FҢ]tӆO9zxԱ"^o"pj27t"4۵c udѿ]/i^6UVE !TVbh2^͓検#äCBQQ~A`+h Mk0q`[>s4$CZ^< dBsn3Uol{4>bۿk !TfLB,7@bM+QvޚO:7vd.lXmT㸶NH1DŽ|Jt-R/JWo;@uw7}QOO"4_fՓJv%xe##^}ziqfR}ƍFU !! XzFw;>=yN1jݮmH=QDS{PBsƜKlmBߙ5џߜNc_3pd/'53[M ӭt[N9&G%In ^.=)1x՟wYъ& zi] >;حhN>j~P&#C|bPG>v:M|_m~Nd#.G %`0ǔj1_AvRsP`}1C!T~;vppCaRJiddddd$l[aa.>ޖZD)ƻ;H8v~/zo1?|,j~7gޯI} N>={Cw ;FCס|nÉGtRZ^zH)'~yO?XmMw:tEe~Xtb +EYҀ|}}-Z@ o'>h!G&{. uaލӱgԠ),,(QX5Pj̾/6nQq~sbN7QjztPɴGcʹ<N*6QJ8}n(:N7(5޿szijjJʂ ݻW+VrJeP3!`YVv v6 k֬zj,,qIZ]OP,]֭[۔RamLOO?>uBǓJ϶|Tjgg're}he=4+?ۘ}vV2OTRJmJm۶=zt׮]_} pvv~jz!]B=z^Q/SPPVsrrΞ=wݻwq˖- j`hݺ5˭]q+rB[n=bvڏ>o߾0?ZI֣VZڵxAAr%SCP9x<޸q~#GlܸI6jxmXVeL=}(%Ĕ'Hl㗳ue{<6:^ m=ըTZs=Į\Ti(#qi.iC'3q$<eFnM) d+p8 5!_@5e&Mt.]?DlNjuH,wJyj̷u&%!0@?%b_ʥTSboO-1 2x\b4 \sc$*{3h0w"\qVX,*VJwo|K:ݻ777YYYBӳy9Cn"p9C_W+Ռ=vBFM("PjIm1mRRx+N_;8!TX"/5bJg*Fj/Wei)qn שӕo˿zScDr;a{ZNyY*  w!< xl[bX&P- `Ai !&4`w)r~I#W(<$\rU@!chz!̑|{O{316.qGMb oG.a=^p9w4hi!h2Qxˆvs 딴HD5,o3W(ޡm_)q OƥVj׶5vB9*07E1ݙ%0̓Aksr{p#s `o"`93ag|wEBȘr/2cTw.P.%$8/ő!ygM/0ry\c}ה]1B ?,<6S9=rhV7ӻvT1Gg84oe!ą]ۿ2rq&A.{ɱUkZzs-vXztR\4Ԋ5}yp%b1KBhщƌl##l!|=nt3ΎNdܽ m}qs o٢Wg!D펵~^s?3>>="7>#|JVAl^#1'x<"̎)ٜi=[ JIڌ鮹uyȭ.bn_2ü#zm]Y=w/{Xhc4ixn\m;q1Լ0cJpl?'>\09w&+jױ?:;3Gjݨ[.]w97IZu\є ߿DGn/glZE6};wޭc]-FudYvt_ϵhB{z#_5jH\ػߗ/h/ߺݟFj,U&ǿץeƩu/Ϥs'өe =O[YRi:9FPm~- TFp\SnC!><wEKi& m6,ˢgrvpr#49Wx\B׵cg_w3~@D$/1clu/>zF{&{OtٜOzxy]w}OF >RB^7^d `YDZG%zbS7?B?$2Lnݎ]iTpp]ڄ"ydn"|xrthӴĜ~hr;jBc-TG%\܆ٹ÷|Hnz tʲ 1&_5{7 a((Bȑ#G,[MaXsC1wtX7Qtt4!Ö.BMSXxCXQ<<۫ėC*@Men2T\h28 >8U@ f>K`&_3&;e"S ~:.S!)9]rh]dbz-F\lx}xl;Ȅ[&fyKW@et6רS̈o+.,w"ivҽlx9,n}rGϙ79ҴnwN/I>puw痫{ո%hO?fEIo!p%Q0&Rq}i{ϐ>;,=i@22׹g@sRVQBBԏ&'̗C`h$0ظ:%Ĕ¼|=H09ʅ.m+8`t}Yl2h'u0TB` iѧ,mݦM6m: eҲ HN]B@Sju>:_vuvog6;19&P؇213qI:B1?w(l^~7KoLںjr[_z0ߟ};hvh6F|F=nюKǶIrNrlivf:{s:Qzr&߲C0|eCDHR6/;k4qRONUV =\LN"ߢ> SY->cΨٿ~թ~cXS ]xMmZg(sk_Eفsmaf`lhڊU5yEOۺ())F ܋P!T/!@%B`X2\Ν|۷U*Z'k4Kصk!͚5t!lX,ɤR] ZjecccX5ȍ7.\m۶8d2L&d@,bK#[K.jVK:u9sfhh  سgM&vаaC=F\r88 IDAT[J|uֵifѢESNtQ ` ?-]>aÆݻw_n+թ63ۊo6^qebԩS-[6eʔ۷rKcqqqڵ5jTM{U!`H#S[\rҥ&Moklllv9bĈSNY FZ7ŋLҭ[KZ ;wlРJf+cW!OE{*"W9Kb9ݰ07{HZ7]t;g}6槤~Jo]bEf:΍$"Kn !T㸶NH1DŽ. rMR$}c8 ߣKVL&رc |[ffٳ-] @5_"՚C/W-(qKN 1vש۳G}1or4]g+xox/Ğ!n ^.=)1x՟wYvO:/]?]7ߝ1O=-F]vIf5AqRs># u۴0~e%6o|oVPT͈F{~Qt]SiUجY &^ʕ+U8,@G)FFFFFFRFR?t,*****U \GRZk#|Y&ɏ=!p\Z4wܸmk^Vj:z˗NΉ&LӠ5]!fFU| yQFm۶u\XևB !2neKvƝ?aDWdJbhrO>)cEac"yr2eQ 𽧟5BwZ.N]]B0VSW߬\$sr!Ʋ"ژ=^ҍRtyӤ|jوlj8_e1bV>j,+8cgtbw)$A6&n'^ԼPqw܉{՟SWa<ǏI^Jc'shOC/5IYqyywd瞳qqq &@:\ZªO/G6m%Q/ˇ6ݽO8Zdʼ^Ρ&~%`ɶ}l]QVvIe*l;inƚ㫗N+勞qM4;8uhZϖ~=H{xعy8p1*SOIzʈN=놶pg甭&Mdee4, b_6P/^Hl㏏p§n:=SO首PcʴS>3fw{ϽIWHJLL,i?>!DZ6mؖ@)5$-mo!0ۓ'OBbbbX)*=-BëW޻wOV+JZ_u0*JVkZNK[QJԩԹsXͪJᶉFlk0fgkԬa,ٹsg;3 cgg'{ݝ˭[T),k|;v\zv—bH$WXXV5 })0 -%(&rJ-1N}i͆O^Љv6z(ۢh^8;޾C|Axx89={ :CcƌsssJ2ձ,;;ǎѣGͽr]73,,,-Z$ N:sLPx٪)j뷛ݔbܸqƍ{Mz}~~Rξzɓ'wڵm۶QF\R TRP:u_~6mt9K399yƍ 2:UJƍO=x%KԩSJ|BP(CCCG .ꫯ|U,] 1J߰a}d2KS֮]{?wޯٳg'Mt-Zܹ344*_~`Xpѣ6mj؄4TcNJLL={vMHW+Wj"lݺ5##cOFz̚5~t!,Cbccy<^^,]HU{KΝ;7--mذafO+[gW,ܹsll,8,j,!!Ϗ轩!aaamɝ^zڵ%Oeefffeeg BҼ,]E~:!2^3!ݻٚddd' !iiiZjY*Ys+WgB1Sdjؿkf]MzW\[.5999BrssY3[՘Z!Bju% -։' 2-ѧ*YaposڱF5w=s][ |WC)Ԅ[t|{'!SŠy&]} ?gу 3leo:&hlkٲeW{ %sXVg @ujZT*t!UDRURr%wcyTTjdNNb{l*Nn +/'TSBnܦ.QnL[hakENQm[s]kЩcǎ;!::qNrMW233/^ضmxʅV  RTrN:~3Uro}cǎcj0G7/dSBLw?~9[WF?[Ij#ƨSJ9דK9uJt q$<e|>?Xa䯿J)߿GJ+XK3!B҅T|?իBXlYdd$zX$3uW|[HsRBaҡ{zJ!a(_A !0bggBh@x<.C%F_l!I?w)['״3}vz&^ ˆŢbZGm\P+VoԨ{Ϳ{f@uUrW]Lf2*J$?pܹ,^Rn"pӀEjѿTP;!&pa%'/dHQ9{-o #FHNHcBlI6&k*=uVUϷo^reza?> `Q5W3)T'(b'O\v &$WV qddϿ Sn#G;P,bJs&+bC=x`0PB #xLUee |c:JB-kPOR2,UίܰbÇ~itttΝRV *5*`Ur\.Μ93oC1)396#z}KIgSljFP"y~5IX?0)&/CbBҙ#.¼0.qGMb oG.!Đ~P;ΩDNٳg+Wlܸ1F !ʰrʴ]tcDr;͇9uJZ Cѫy ׬8z~i O幭x۷>7G%sN.^xƍ?~|#`)>5_Ubݻ{f͚?ƾQ;}C>,mN.qnt'Θ1c+V 9 :t7n}zRRR6m> 9Ϸti,ڲeKϞ==<<~ѣG_zW^ zIeڳgOBB?cǎux<777///LVoT*=ztڵtBHL2a„ X4kPk׮XԩSǎ|۷SSS|CTTT@@@tttPP BD"Qttttt j^`X2,!`  eX,C`X2,!`  eX,C`,*a^%t)75|"*T2JieRN Tw%4o  lt筂}c8 ߣK]KU'8D RxD1!B׿i%{Oatz(:B5c"<b~HyLew6רS̈o+.,w"ivґ'z~:.S!)9#{q=7ͿOVubXRI'\'ӿzqݿ? ;4>p%pC1Ė!ŗ׏m"k1⧳D-=̑+-b4@~=!"GP `AFsM;s&Ӊww.e|F>cia|{b7~ꯇ5Hi|ώ? P{~{deew:N-'py#Mt{xv cow=&Gs.u求E^ce~5ni}P^-OR%݅p 7krWG5/o/c^dB 7K4eb's[rs^c^86ʃ2OWUҪm$=1=A{&mD]of28D՛1=p#[5u7_.!J=5^QQ>2Fy϶Nm $㠟6B2s[3Q*{#鎫73;5ˎz}cqԹefB /]99R@=9mU,S+9fNKMOO_bl4y߄jӯT/i71' @!ڵŤ\ڴbHwhæomBDn%!eOсgd5c W [F 5VzgHa4k`aۿMpm/StZa":C(uF/NNm0$JR4332fK)Ntڵ B~D091$B8B:V@fU^K2IC#!E˘WeF,!o+̡r]0>!p%5QM.n9%8Тñ2ϟMc(d9Lraa!K 'LV2wm%;Ο0O{sF#{xK*NJel-'RgYƲKT 77 ˘&QsV9flmp.Mrx-2i´j>:_vuvo}H Co6ȩ~ب\|c{vFgnѧ,mݦM6m: eRbsL!u>?<#q׌F8*cۧ'l\Bl2>fKv?  -*(4B3qr$s. !XXy^DoYEv<;vi\&PaCg-q)V6i[Ω>^rFpa4q>>0PoOwT7Vo^>c)'oݙ4ߘu#I_77ٻ suf<އk,24&ByAvnU IDAT]z:0w䍄WlgSf?~~?-+/Hov^(s~ u tl:ƾkVOەcz0ߟ};hvh6FO^2Q i۔6SgV |{C'l!֎RJ)`Rl*^YTTTTTT:n#ٖ;4 j(aE?qv 5s%̝͆FQ Ҿs]'Ŕ{j"-|.Lev6רCDDQJ)5fzpKP`Sۿ?k)y|ԓ:J)ƌv)͛7~WU\zզAL(v ;7IDzΫff!y^0=㬞gOڹ[丏zpV+SC/Ӫ@||eLTJ)5\ιhŔǓ3V_S/x6M1RBHTT!ȑ# {P)d2رcKj !t!ok׮y{{o޼yРA*T)w'3R(,H>9ݛ[V뵀jk Ϧ)"Lk=^!]+6>m='v X=b񜴹?|JX٠o|RV;X,JŭڃU.2,!` `KTT*{>R\..FCM߿߾}'NHMMϷtE,x!!!={tvvtE5PYYYK._rrrlllBCC}]wwwLf^F)**LMM=uԶm>;N62P5h4 .\d`ӧ۷ooRSS7o޼v/_E8jy755u֭]ttE/o޼-_EXP_-[T*۴i+ "hĉ;v-]Cbǎ{OLLl߾˩jNNNy6nد_?`銬:ԐѪZ?WWWKW`1;wϟfaϲ}Rf()˻~0k׮&Mj(`Y˗]"Fc^L&iذaƍCCC +tΜ9&Lh!ڽ#v_H֚;1ck3fZYq+uΞ=O>9{l-*y={vݺu;w"}4uu?/;@PY2PZQqԭUUukqѯ'Rd&aeXk}N'w]__Y_S*b(JǎG5j(###mBpCQ arHDReVle3Z9 9IzO:~⏛F{YplCsNfH}H0ﶜ$IRv[k*k/SLߙC}q{-7dh7O=w-L&g¾2upe`maЊգ@=['IgfXŵl `5P8z蠠۷zѣƍsttڎN3|%Kn߾G9R"?a߿~ĉK4 5/ܿ]vƍJ !)X,Ú?~On_>{{Rk'x=6?(  Rr/ZQ3)B[ӋO^<8c{-N]ߓz=_p R|5@~`J\t핰8o>cǎQQQuU ^~+WX,mGx\\\+VIZ!Ԙsεݑjng"@v137ˣRR^68۩ HUqP5з5DBnl$ݦۅOMݧlQ(OOOB V/ccc===P˗:t_~%c5 B@ .AZZymwXM6joj0ʶ}&$Uϯ=HR).)I ffͼ4z _XXX\|Dhȑ##""bbbp`RT@5{A4PUXXhddT!t/֝O{$_\y¸:=N.cE2UVb?k~47R9bRy9cccm}#FX|yDDKˡNp `թ02}[7c}}J= '&X>M˖J &AR Ua^tځNWv {{IO `.ևӈOv;7떧-o >fz:n?/ UL(\鍊[:dYҶ/@NtBHܽ{wn:vXNZBMh$n;w&$d0b2xq-'B=YH70Pe()fQj:oao7n\M6&noZ6ttI {0ϴ#$Yx{>y,o5xo C?:<3V,=+|mM#(I{gv ݹbH<gu77cŔby_y[LNk?DTTUUѣ5>JŸ\A\..W -~ԫyN1մ._6!8aT*o߾T~ߞ)P4˿ U}{,]F5usZDjA,&XEEEEڎ!MKT*ϭkX(RP ڴHwYC=-:Vm&o!Û8HI sVK ~==YYzq2YB 4TclD"+VL>F}^z׽{wmtޝ ga_ggg777GM &XZCs01EUxn!ߦز" :ZRq]\&'\-b͚W6)H0Kzڙ5Q"S*wﶵ]fMS[ӹ ڰaA_AHLMM{. k666Gɪ"Phc,X8-ػ-$ZٷJVdx#bgPmf':"5)E^j MhD\Ns@+!XDj111:u}z&! ]pРANP>|xYÇsT@HH$I2 DaaavDen E $U[z)@0>U6Zu:h srrFMyDDJRj/&G*&''|RTA5*|IxGeX|>?444**V/YN@֭cbbԍ ruu@pZS^Ri |m콛MBY3PVVjժ͛7,Ξ=vzСC6$) bX,.))yBgg_~%88<RT*UzzzjjjnnH$*))o7-.<GmٲeӦM`0t:ht:7^~u̙C3{ Ttޝʏݱtӷ3Tܶ-Y [M'C~kliWf% k_rDž7Nrg/KxWMǡv8U>&0KŦئ>7a)ͤZ˗/ݻT*tzaaaBB»@\\&L&Ғjժ]v]t˂-[_o rTj)X m۶D.rJ%J%۩|e?xqTWlbG.&iy9SI*^*>V?9.QFR;S*2Lf]-ʕ+/_5k֣Gz?:99 [1"eVZr%8p```p8ɹrرc?Ng̘eصkWzƖr[/hRտ0sg7ϧO;ωvJȇ ƅ yJńukN?ݘ䫱\Z7Ǩť$Ԓ#!!a۶mwuss5kB\|q㲳7zhOOOSSS̮ޓأGϟzY\M1 ?3*Yp/97bnicNG_QPt77)T%e6DxtK >:>k֬pGGk;(p_~={0J?~ILL@ HJJDjm(p U`tn5Qp[JI_vߖ٨ՒѨ 5[޻w{9pҲ_fB9s ޳gOjjjJ֨㪋mT_ CK'q;^)u~L!֣JAWKwrmd2{LL!!\xQہ4u&LhۨF%0DS ){tÐ|#v@-&XG7Tj xBMЃE3`aaꠚbUpP~TZDσxy1f`IT*8''Gہ4i2צ$77^ہ|ª+Qe1 Gi KׯyQ4kGk(;%є~IsSҤ&,y~ *J A].Xہ|~琈!6]V3w_Y~zۍS%}lM婢7=&, `g(avse⴫bL+[NV,LI:PIϊdte{Gc&QI _?Wd%m|t;~-@Νq6jԋhn8vpu]*FEEi_R"Jls;3aI_&0u q %<@?I$-)9IEJZ@%|B!F~13VqV AU^^^ddaw6j `!|%B aaaYYYꖔ,6ɛ˔bSWGNAbU~bT 9 @z:1*$$ۘMl'TJhTP*Lɢz./J!lVX,#u5T*ǎ3P$H@3 BG4oΜ9 eyW, , #33P_P |^YχOoZg/֊:>>[Zg6x`@P}$7Ɓ^3339sn޼>Oꅰqqg}B4Pdk̒Br58vءC-[W}z #k}& GޱcDz &_ȪN w>&&tUaPinId߻Pn%ۺZٷo>SY)4&[GGGGͤɤJEݻ7qD__ߥKjl ©armGԩ i;GJΝw=~#G9rɬ_*g=/PwFic119TߢFiޫu DL}z߷oVZW_E!|s鯿.\M~UNY2/+|ՓbUIZZZNNN```D1mٲ%..ǧcǎ7oNJJjaWJKKϟ??m433{{۷ooݺ#EGG'((ɓmedYrcn]l/>-T<7%9Oǡsɺ/;y$BӧOmwDǍF}&M_"""BCC֭[j;#I(+++33ST~W&Mvh!F|rϞ=5;ɒ|>[F*G]֘C=;AcDN)DbrDR0mAPT,U|G3.A5/VXPRLT8p mۏ4j F;}ӧ?<***>>>===77Dsp8]vcРA[nF/_$޵y2YGW>6 r VeRR!W@Kcǎ=yd͚:3-L<88888֭[|;jL BBBN:5`<+m._b!H}&!7㪲|Lԧ֎n^aIХuޖ5QVVh"wwhT87n(BHkLҾ}Mո@*)l=#6zBa;>`].Ze . &X-ܹsΟ??j(5Beh V*6**&X# ^,)o:t x^EƳrqnzST/z!,1x[@Q$Az^Y(7K'T%ɩyj[ɓg A%ds[j;۷;wnڴiQ˗Z8IbP@ܾ~?KiaG@ʗ]vm̘1>>>6l@9X-YXXXjj*kzTO֤Irrr֬Y#J[]\ƳtoW<u*_vܹaÆY[[>}`|t{T78bY_~A+ŋk;(ҦիW^999Y/S*V0`SttAc)ZdIyyMd~wv\!MK,9~xRR֭[>?/Z|ѣoccF ӄ V˔7#ȋ-211={v [>!jkȐ!<3g?+mPrӧ{յk׼~zu`Lg644\d==k׎7ѣFbl!uVVVgΜ|u͛pBOOπ|SBQRRŋbM6M2>f(+++%%eϗ.] !G=zHOO_###l"˵& 4h={פ~T{x[ KK˴P(K.u!'~ٲe˖-O>)..vPkdd$_0j\nfCtSWB5[n8p@Q B!x~Yfi; 0B!0LB!4 ,B!  !BH0B!0LB!4 ,B!  !BH0B!0LB!4 ,B!  !BH0B!0LB!4 ,B!  !BH0B!0LB!4 ,B!  !BH0B!0LB!4 ,B!  !BH0B!0LB!4 ,B!  !BH0B!0LB!4 ,B!  !BH0B!0LB!4ji$ɭ[D"QEE#;񬭭vB5`!r?<""`h;-`^t)N߽{7A zD$!)`& J(*w…Yf}WnwjĒ%KrUw}נRTt:ABQEDzupp#G>JmʕC]x;w@$I)n?PEPf5wܒǏlmTٳd ᎢR!B 5QM{=:o<: bdrL㱽!!ȔcFO\֭["""(8jF 5QM|~hhyKzn! Xv&H{I3?8p .-,P3 jX,Lӑ{ɓ'7B1]=xh}#O222Td2s,LPrKJJ8qBP;=)^_c6poVR4)k%^)G<$f"@zirX9H/=b>ӎ+R6x1%t!X,U׉}?:<3V,=+|mM#(Izb6j.0BMڎ?"##A};R۶R*{m{(Wϐ]ə,8ڡ_M;[@VP/̈́NP uW=ژ$+vq[@1ذ P$V.=YBLg}psb1mBH0BMTLn޼﯁vW_ nF%Ko%}Ѷr'>ekB4bvܚ^w}N]ߓz=_p R|5@~`J\t핰8o4*^@@@NNNvvv&Xf,DK$2mF^^^aa"xAT5/>z鮄$8Mu9،JS\IL('TB֐ E⻱r`wm>^6>?)))=2 /" LPecc䍜hTCc J,zW$b`jfu-jUQAV7R\,R@p8/b+-- 43B5LP k̃V0zƽ/Q) U̘O!@U$seޫ<mpyTHqnn&P~%_!a(GGGss3g4o޼ٱcǘJJΤ~"%(sR ;9ddŝd %샺VP%R0/6s:w@'Ȋ+;IDX,h5Μ9ciiioo[:݅tz4Ⱦ70#W{VDQ&m~[6n?]`T)u 7ƃ@ AYXX̜9S۱Iw$kNqӖ5`uV\y^cŇ$Id@@@@@Z" :u((>>ܜF >رcO#G@jj*Ie4Â;r$I f/T4ǁS2uM܇mU"I$2ѧ-km4e rT$0bә|U&C$9φbr|"qZ /fHI4M峘|>/V$)<ԟI$Uy1w20m\㩔Thy} X,~ϥ`xܹs9@ lJ+ p};v L>xt,fkЁ 'O޺u5۹'B=YH70Pe()fQ׬Y***sH "D(s5##PCCC (Ң㻭ܲcɖ!\ݽV7v@NQ!}`|k¦q|mځC:nOp :kVJ{cs:1AqwHs8@!kSLJͰC`Nv7 HOE Ⱦɤ" ߇Ic +B}º1tȟ Ɏٕ39P j(Jǎ;vǪؾ}5kT*,YwF8tcwۻW4Qb))wdK/^>.tK5<ȥ'dK%*KeG 3 ZoڨԜJh[Ld&N2w,Љ{}YL>@9]$HT"EaZ,̙33gׯ_XXWE*2ճ#?ݎ?Fu0Hg/T*`/;Λ&m欹/ Fw?w/xۦq|*I9"t;Bo$$$ڵkgΜ 5$2\bRBPݸ[{3cwo>(J%q7K>,"2.o% ۙPO˝v4fr4?Y![R{^/9/N_XUC19"tBodee=~x۶m3f̠R5P!Zu0$ d{aI!OcիӇO `Gl}Moå=V mmhE}?eE~]+I\AP\1o|a>D>2-q21щ?tv#F;laɫI]tӏҭUӵPӁ#X1`YfU]pWs"@Sݣtz8q4ھtC6ЃZvbτ1^}ޡ O[ ]YR`vr`;Nˀ*qcNh{ cK5]\;y|~gEFOkYUm]U0UYηlh$>lQ>xL7wrs6!Ҍ1)"ҪCO|t;~-]zUV;!Fv7eڎ!T9Bz葘s KJB ؘͷtngVzҗI*L||yG O$O3IK@okJNRF,QZ{`.6@&Zyv0 #cXX5RyŠ 'B}0BJC41"BsJHUIV\ ɪHr/f[c.R"'%"kb73Ʉ"ɇ-kXb(T* e2CäBZ^>|xB5wx֭O?4g&Scrf y"{Ru)HS O{!W/jĨlc6@M~]Nmky-鳈 EB0BVw޻w˗zJS}yHrrDM;IUz#:[B`YDEyrhP(HB 4\32oW!JI y1RYݽmR3lllNB&XNXXB믕JǷ%o,/^ { mOX"YQi87=dO)~BX.z+bYI Qn^)MGNi7g* r:z:6˨y=z(<;r VDTv|ʇ-Ot-N VD蘄B=g H$(5KGC'!=P'''ׯz_hޫ#vc <߫0rPm gkߞ$/,1mX^G2eJ>}6nэBӁ#XƍMq1cƔׯ3onCHJ`n_**jգG8qB_P]O?-[,..nϞ=>>>uƳj\t4i׾-222Nz={!B-ZtҥR__QF=|P5W^͙3ݻ틈 !> Bҭ[G-\̙3aaa UZ{rrr"""oii>bĈǏ?^q!P/]]ݵkΝ;w޽9s&x< D"(==,,,̙3ydkkkmBM&Xiy͛ٳ褤4PX\\FaÆ999`!g L0kkkAO\srB!daI JXR]H_@A MUT IDATշ|NDVbz'6mGtEEEQ(PmB}`!52pM!HJ!p]k;T;* p9B5A8IxaţI]-l=3q*< :[e!4YWH n?h昮Vlg O]m^v:,ߌOd>|6caSd@vM5`W_U5j>B`Z9d:CM^Q~ Y|:mCE꾩^!c~MLY4/ԡIP<ڰ1W6~4+=4|粞;&_LiXГy.,_=;qh߅WKMl^ӏtbU!gcU:Bڇ? oe7N!9ڃR_C?ؚ"@G.!ێJ?[Jه~E?VJ5ʎF5n˴:|A94{5PO^!<-L0o̽N-lRyl]#E_LVO=Sy#X!daIP*ՃAdaZzqPutX!x.KgO*,JUʀ8:&E@ PTX4 8zL RiAbsRd;b(^MJH{]Ril0)1STjK%| BLBI#B&_$T?+Zl$x|Q R6=@31ѿ<6R =tمm/](--6@B|$X@`»7egHo}Y0E`e@3;8ܹ/ %uD7#%T_KSt<6 EܩoGc&ΊAII `BM|ގ`1 vڷakf+彍鶎6ߢ"Ү}ϕ$O =f\+=H1+=`Q`ޓg흳᪉:G]ه`dTgڜG&%wQ&qT8&:.zfO=-B52jHĞ K/m] clOsw(ltnaB&P߈ڍ5&^+R^d4@_8d.)vUaZ3f> "H{.?r䦳'f0H(BUGZ> ҦMI&1ι9jko^VczWB OB׮]&N΂Xpի{@BUO՚5k:gϞ/^h;"T.]9rd߾}VZBU/~*-ZԡC%KL4 r\.Jt*}}}=b,))yRx .\xqNNBBME쀟-O~~B۷o䨨feefffՋ*`wqԨQ]tok_ 7W+8.fj0丸z;B!4`!bWie2L\-t7D (`B@ՓE.U.NlEeTfl 4mKcBu1ʊGZrzf^%PIL``O_BҤ6cH_uO (nD[6k1x\U/j8`!B'ZxZtiW1|KW7oVٽ[rP=rBzBAAjaS^ 2@zk吉{tY4Wx%*G],>wvӶ!"uKKinI'X~ ·g{G~Äg"W?S,Pj!Ic +35}8&'~Zpq"f.: |)@0&j>jötکfڍ{p ȉt* :r ]Ɵv܌$| ͽ]#E_LVO=!7C `G|5kpW*Wn2z-]ś/I':?~ngmmmmmm7,UY!(on5X>x^^>.tK})sp1<6ߦ5k{G da#I EZo>T|#a PӇ#X/>~诧/^<\Cl$x|Q R6Ke(J N`9B2Z-N]LJ F>t1A>}GS}Vv얅tG^  e*Yy| ̘#07{AYV*!Ҹ蛥,I1)H ۙP.?-wPz7`C5{`!2\#_6դ.G SGo?޽{PhjnAYBt`H8:?*¾ByWן@e1)16i߆#KG{Hߛ:~~ʊK=W<.!cZ| }dBZpeGcKd!9P AsE'=#00 j\.wҤI6mv H92rȆ>2cӂi[}kG5*55U ||kԬ޽[,k;yfS8B!a`!BiNrG}.,TQ P#X!B B!aB!a`!̨TwQTmپi^B!$^RJ*RD@哢 5*%H $R7m~l&&p_t>3!{g9TChLΞ=啒Rme˖۶m3JUP @c陟?sf V\yU777c!`4&۷oÇ fffX77bm@#3m4ooӧk4ȬYt:ݲeˌ[<ȈD+W^~}׮]Dt֭;wΚ5 ,Ƨ={ψh... `4JV*++#˗" @ԢEaÆСC]< Zz-[83v- gdggoB:,+))9sLBBBjjjaa\.j.YZZzzzw4V:ǫQ]!`Rܽ{mۢ3T9::H$crss o߮8 ~7Gammm9s\zG8pI&F) ,J|˗/={vTTTHHK3 Bp={L>}&M;wKh/_~޽{?TTfDF Gbcc۴i3uT__cǎݼyO>zaI$Yf]p!!!_~˗/uj5iҤ-ZL:UT>\z[֮]+`  m޼C{=vXTT A_``;Ο?0`]z]@C'֭[_G߿lٲAuݸs,Y2v.] 0ڶm{ܹwygʕÆ SƮ֭[>}>#gV( ,Vo^Č]ʿDsqPraPkdewUV}Fڿ1XaÆUVOo=/їͺuJٳgZgΜeyi h[)|دZNݜ,SX5ϰ?k֬!Cl޼%o1cƒ%K~%K+xzz aΜ9Ʈ3蕣:=xNkn +33smڴٲe >hܹoEΜ9cZ^#X/ HRNtR\bk?;ڌ<`;IMأԦj/z?iȒk? r?UɑRA &GInSOgŗ7 J,hc@V mB,2s ;gU|?6"i2uD,{Sw} (-B߹5DDn}`g3su*|V\:%tĊccg"X{&cumC2ӧ+]vbcP|W͚50a E;d+VkZjw>t;HsTWGl]+ʧG~q0a޴>}ۣ|;ǻZ]xZG.2{,w3wˇ^Spj!kB$e'IwW5 O1RƞXvZ4y25߭ˉ?ljB>jrêFl! }iƻǨϼ.8QcRy33?<)){ l„ ;v@z~1ch pfCOc[+Ä<7-?Y$.gL=ŕ/q1 [ SUu#$w(oQ|w Ƙ"aEw&j/u\ͽ%Bꘪ03Ν;wI*R1u܂@gΟjSkw*S2Lo61ƴk:8ῖ*Mt >b1)|A8ڱ}_/ֱʍ.LL4^*---2q]W[E|#"Τpę1t9pD٫; cLbPޜOOįl=o߾yMOfDnB)TMS 6Asꃬfr<,K%\ iM’0+ssssnj2u ^agp0yu!R溄O:'1oFX.ykե Yo͛7oܫ;Fmں45%+<  $"⛘'N`kjuϯ2tRj6$Bx'NhjjZkz[Po}7@L* i'V!"ť3UU\<""ոjF–a5E63gμsѣG]ȋ@;+]Fii/2rP;;-Zk)))ƮjWITy]Z8q1Dآ˾D-~#W=u!?ᶊǿByXHsE:""RNL%~Ӷmk78N3[>uƆ.b3>ncӎ7Jm|{ʹGa㻽Z5ID+>ܛ RŤFmG猳j""VezVMdwȕ'k ѷo_;w DYLfBXlY&M|!޽{>< ;;[?SàAnܸaJ=|#؟1ʾabbr}3x־~Nnw|Ś#HfĚ?F~{ ׮Kܫ ]Aؼ( "sE+9VTZ#"RklSU(DBY[F~ O L,N[Ա/T}}poĻ{iϒWsS՜_oK2au.O1‚WmvgT/D$+GyjrH$jw "~zSRR8cƌ+`TJOO߾}ʕ+W^=ec @`ImL9EW쎯d0lόOګ;^c{x횅#;wzY*ܲl[߱;.9g_oGʠݝxz4I;tiW@kP+cK3窓겷;dΪF*^Q&FW2g鯎6]Y6mLְ{D2s΅wʖoj)#yŽ98`JY&$ԋOĜgcUMĤ;+wt$ lצƙ'w_||BҞ1n|Vrnæs ߮_gڄ>dV)1-.?~⟉G /肦D$l3ܟ.)"ˮ+<(*(H3"U k%"""+++--Y6/,_N۷///_;u+**n޼KD͚5?~jjjNj0mYFQvNpi1*sUc[&EYv-3U5?pOPlټ󸯯*諼cTiod&Hm"}Ec1MVAES؄/\}.d#&LՕW;1#šX{HL\qmMD&NmG,|H NXI!N&B7?zg{{}|| Sz{*ܖC;8""wԏ*}xc|ߋϙۚeZxfݦR1mW:<}mҶB" jkWWd1<HiͅM=D?jK=jAשJ rsҾ'$M{ߴM: 3f̘1cwn'{8[!C2dgwMkk뀀{G۽{w .,..ftYfѲeˌZ8#UTC XONy/-Kߒr=ȨkA7=/sDj_|ŋhOZm_kc#d}6gjeo.Hf„"Q~($Q 31>3UriJ/nʻ{;/+H)i 8{OGij]ǔrda[ D!CL^a|Ƕmj˳9qU+x du7 twm. ,[@L+?qAŅ\W2nޏ*XY ?g1)ӂCR(ݺu3v!,t:ŋ;wܿ";vlbbbaÆeddHŋ?J<</޿؅4h'O&}&''W{V{.ج`_lj*yYE}vMrVU71GDl}_߭aB""t:f\]V'4xq"$"'qDēupKô[ZZHx<åpD'Ӷ:47WqD'4q_XE܊pKq|k;K #NËV*Ddɒg cT6mxxx`FܹsDsNӧxь1Jeee5vXco<|'|R^^ޯ_{+"""))iݺu111SN-..~҅9e]:OHs+ZL"/ufd?d(]P> |;㈈:4]:N^"bnd<>Lj2un=x'zt֍kfrm^J7Qآ_Ny׆sDaﭛ"$$'P=ǯ[zO|s)G$i5f'MJ fW> Y&UZZʕ++Wv=?4 z""Oh׮]eeee< K/~B*[KJJ %//oʔ)|>fݺu7GA[pddd{lmm5k]piӦOwŊDT-D'>>~ٲewߑd2Lfaaann.6滴<!!!ӦM϶njr˗/ϙ3U4PjZ.rZMDO>smӦ gDDZ6++멖MOO'"ggg"z¿%q 6\r%))Ν;r\.<:T*ˍ[g?CDeeebqm@juaa󑾴b  BWWWsssWWW??P|y0x<=Ij[sQ34 X/@jB+W._/\pΜ9^k:rSXXإK]ʕ+D$333|Y)E}shr cl۶mSRR-Zk޼yZZZii)EEE=bcǎDdoooffJ@/9ŋ۶mstt4vQ[T/5jԓ/8h V{>}<8=z>̹xXc2:,JEEE[nA1<0GGǯG:|'DgϞVy݊MZY';\\%e1CWr):z:>D"w~xs9rѣDuVx[lqwwWT ۷_O3EQNjŴ{[=Nx9SDkqXajRs kHL)aen۵jϼz;2ERodVBDv2EaQC9@!`d`nnNߑp_&L[o؜>}Z\U+ t\U!G ӻVfbI**V!S=;ۙ%"O,"Vv=q1U,5P4"jҤ 0&HgϞ9:::uj֭!!!U;::N6֭[ e˖}W3\^!JZPuFǎ"}=H8zzN\gLQ`RSB?^DZ>G$IѰ#DDL~ȡqEv~V)n{8<'J*a'$ɮ]\֮)N%u|G}TmUdK|:8:+)s.&sr"YtOqB1G7ah'viɺ8#16vY[MJ+¢t0Wt IkԩSaVʼnt=LYL~YWJOIHL+pn̜O|x@%rmk'jhnǧ/Ӊ-p2H]xΡ~V"k+[~VOy;::@>}N:ꫯ1bƌvvvvvv^SPPsŋ.^x5{@(v/'tOFڥTUWI"fr@@Pђ@ GHYSȬ,l8ݾ_T(sg2FGiLVкs3!`<]Ι3ݻ\Nj%mV֝ťcn[v2/W)H31>uqIvm"ۉǟz!ȈqmƜ#"LV`V&OqDMݺu*PHHHRRҲe>-[xxxo$+++99̙3K.[HHH+REQ_,Jndf*x6>#;ŷs~-厣$5v,ٙEv9"iScɂC""qBXVc^XOյ{_|̙3 8_ :X},$"=H8~9Sz*i6_T`R*ND;X/\U\Zq tq'nj`uq17XڧCC,vv2M]ĘF!>Lz?66][qȑ'OB_ r{蜕Wkw.?O@.S{k|`<~}Zg`'EFF:kvtV;X)ro=Pӣ~UJU:Xs5BmG"%|K[~Yi98n bo T!oWɯ%J ,s7|p0wVT< Xef꿲l|:FFT HdlLSPZ.Ϲ|̢̜bRRs4yr*sNV_^S553!bO/zXOmӦM111c9b!Uq|L^>P kT{/bӦMfͪ6;"ˌBDFFɓ'[ @c`ŋO2eڵѱ*N-E܄cy0k Q5M*Bg^:;;{{WkkyJcDZ?\lY޽w؁tPNq?ZWc`vZddҥKǏw^T( `<ӧGEE 4ƮKKK8qbPPǍ7 8P?ұcŋr4MTgIb<Do?<:T'YT".=c܆Me; Hsr|6ؑ"V~Pt6#6.WI"B:듽~`eO_=HC歋+'s}=ЁS:o}v5' \}oOpw ^F{i._qgqr7O:SpA,+ۭxv}?] ?OG;v3wpgܼU˜?.*g㝉9x Oo//,'ijJ傠.ʩ_wB~ʧ7R&hީse xNs]xD 3x2+g>ԗZ{DЪW~}{8Sƾ?&ky#2}֊Ǒ R?mƠ'P/V:XG;?~s@G|v<ήc@Wtn!ϷgOvٰ{ij]-˗o>ܽc7~TFJŞL- tqucy*.,n<_b089G|[ > stream xWKo7qy(6ֺ9䶱TE{!ڵ%B; g53\{Kk ePld^>\zt+WJkgċ'듎-Q&muL_V3ףX[ miTY@=䨲w"RdH)W) "H'.x.܄U} st8SfTJ/4&@ rġ7S⾂GT2y?P9e~M(jm(ow"81F &+"e-FV %in\TKuA%J#)(VHU&76;&[R5j} )3I<%d Ria^z/J[p3pkc92M%θN~Aj y6:%a|'E c+䔎X4G~\lx,U\4ч;ڕ DW_ښ%wu`6!;!V p* z6#4qPpƌif@[qQt)vCoP-'Bȥ齃1\Z tG831+UA:4 v]:IY'He7*\%,"٭h?s)_0=nh8hV[&n؂ H-2U+ $4|M6i}8dC遗ӢͲy#n؍{bD28^  ߆vΐAn_- naPAIM9{EQ :>ɝAMnǕCϩJ:w*э:ȟD5'fFEJ8.eKהe"?I793}dCpy̙ABNi>?99X3~d~ZKUF endstream endobj 5 0 obj 1329 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-1-0 7 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 8 0 obj << /Length 9 0 R /Filter /FlateDecode /Length1 3900 >> stream xW{@Te?wA<.X*23ZÀL&() a(Ĭ01rݬUs}V>GccϽ3ds8| 'Bhμ }uu^hz^9ɫrsK1||q?oAٚC.|1'Wxݼ"Hb@ !T0Ơ@943\zDH(!D+m#c}®$&mRT.xx2)f _`Q%z9<ޫc&sOx#Vo޼}ž'Rb%Xg:Yn$1O9p@`2N{%BD<?OvO]U+J;ՊWXv`M蟈NՊkϜ*6aFZcҘ#~NJguJc P4p ιO;بxS Iq,%}4OXm ZCd h%(<ᴪwyO>`!)nќgO j\lbMcѧo;彽|ݾvi>(ԇfwHQsQW@( 5 tHPV.d "5vk֓']}>cU|gO':=(8z37']xM>ᇣzKcʖ6.\KU3!fŒRo%KjZ&Xq'kU!`+4˭Vtz{c؟hq++dQ4寒B[326OIIOOںXf}X6ڴk~sΖѣ4eZcPz@ǂ *}g4n~Kgi<<6'Nr78s`7ѣ,1|n.a~"4c;$*DWF&?Dh{Kʶ$_%d"m ;Y܆:a/vi Ȁ`΁I |$k\BpŋGdݨd1$v k/]̮"±SX]9|xi > ;=Ւky|oZ#;Dl@2x B FFC@uTMGI[Yjq~yPG*ءm_e&mXw%ۂ>n̈́`τ_u̪qq qqmщSʹOC>Q;\JWRZQ4(%8h3s=W cM6-iL ^I}c14\;s( vN%^A-.h]wMP=Wٻܓc{v ZZڤ~U-QԸEi"=T@hq&bOha翸9;m[{CU JzZIJ0Jѳ` _*=UVbV.9omz܀_^PP-e'o ;V'|N=ᎁ| &c=Qx >\G^]:O> 0 jO${j ?ŵpEd*Z%K*薕|"F8yNT bH9]TJIb*]oC|ca WЃNg# + 4`Gz`[NԝYᥪ'469Hz }M5b=8QJ6ԁ}]8w9f>˟>_5G$ jEcSmLNJ!#kjX4YR݊QD@.3bv" M>IJ!҄W}ǐӥ/F7oN-`vc ,o pU0nxW#OlRF@jim  n7}$d}Grc-Rwݟ&|A.2PiZ(k(^o}<> stream x]Rn0 !cRtlN 48C.H6xX8̺xO?Ь!D<鎎CTJϷvRN؏it9])=(u!kw@p:Qu[gvzmO\>׉tW@x$ՔV7}Uÿ3SwTS%>cp`3yBo7c x%5jkU1|-yw¯wp7fěMF1ǁ2:&렗^\y-^&<xдi=Yߜ7N| w!BٵnKJy!>& ;;T; endstream endobj 11 0 obj 382 endobj 12 0 obj << /Type /FontDescriptor /FontName /GJLDIS+Roboto-Medium /FontFamily (Roboto Medium) /Flags 32 /FontBBox [ -907 -270 2051 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 8 0 R >> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /GJLDIS+Roboto-Medium /FirstChar 32 /LastChar 125 /FontDescriptor 12 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 279 0 568 568 568 568 568 568 0 0 0 0 0 0 0 559 0 0 0 0 0 652 653 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 541 562 523 564 536 354 566 555 255 0 521 255 870 556 569 562 0 351 516 333 555 0 743 0 486 0 335 0 335 ] /ToUnicode 10 0 R >> endobj 13 0 obj << /Length 14 0 R /Filter /FlateDecode /Length1 2944 >> stream xV{PTs]`AمES܅,a|İ,.(B7ctTƂVmLƷcSADms2SE[N dB߽Zm'ߞ;ߜ{^B`0`;:STR]e?ͨ~Omc %Si0R;tYUіJmIق~D҂*S;dH/M  "f$4f6dw0J=$3^橵rhDUy,܆P F҆ *"E+R(6??ҏ5-8Ba,R;K|:ˑp]$Uq9cY-8íl$vܷ-gtvy݇ՅipĨ?ͦZ~=.;=屶wu/'{\LȽ`!2R%9=T63:kcKvp_5VEϹޛ\7v=csXy |Wa!d=jk1X,jhC]qRN]$ʸN[ v$:b:5- N>lY`n8V !࡮֝_WgDn(۟/GFS t^Kx^qfQ]5r+ull<bns[cg4xWvBر #C""d1\<ޚ4Bذ簉VI@|=vɖ*T{o`-RZsH 3|) YYY4Ah'|'|m4S@*ggTšX^QhbBmQ¼YMu _jwe<N`|Aƻ]$_\%DV/iyɡ3&xѺzy>7đꖕ᪟OpћdLyȧW [-d:cJ46<GAͨǬ{Dkl\S|Gy^G;ۻsj*i BjQ?,8Ny17m隱#>,fKbso;h.OHPHP nQ^n 9/jIsd_F_[~k_OݴEKج7E啋:RGO>OO]ɓ"ynEĄג3EdD" >+AӏO>3激櫬YM33|'>t}ƨh}hH4߃FCq k.YgQNLwZ;E zǏ7ZN9UO球u|t!J/8+\cy@̓#خXOK)Vm}"#E+?q^o:> }ޗ#޴xw6Cz ubMQ3Vv)zJD!Q9.,D3q|^)Aֽ3]XAH wٞytY'гm{8^/]\J^_W`(cJq?-U-47X}FJ GCsct8Q\˧W4[ogLWӺ=vimxL]톏ΦS=P$\ X,na7bc{~7ļht  NvYвC k3}f~nQiSU㟆^2l7Ppe߮ȱ`p];ՕʣSmh% #DɺAgmڧ|RK//P>R dG: R>xd-0b׋:HCA $rkHh~_3M$}# z$+5AB\~ӿ)(IhDEI&iof=*x|`[ѕ endstream endobj 14 0 obj 1996 endobj 15 0 obj << /Length 16 0 R /Filter /FlateDecode >> stream x]Mo0 >v hi.HL4B?;:iƍ+$a6-0\k0=^FѬ6SUBv[V7JkH>hqY'; y .:jnT5X݄D񾱴>۞dGAZ2wC.t֠V쿵,I?.(4M)(]=F@|>62B\jrL8іQ+%{sYIbFad~؏U^ y))P߳Sp?a¦ endstream endobj 16 0 obj 336 endobj 17 0 obj << /Type /FontDescriptor /FontName /KYDOIW+Roboto-Bold /FontFamily (Roboto) /Flags 32 /FontBBox [ -913 -270 2060 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 13 0 R >> endobj 7 0 obj << /Type /Font /Subtype /TrueType /BaseFont /KYDOIW+Roboto-Bold /FirstChar 32 /LastChar 121 /FontDescriptor 17 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 673 0 0 0 562 0 0 0 0 0 635 541 0 0 0 0 0 0 614 618 0 0 0 0 0 0 0 0 0 0 0 0 536 0 521 563 540 0 571 0 265 0 0 265 865 560 565 562 0 365 514 337 560 0 0 509 502 ] /ToUnicode 15 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 18 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154042+02'00) >> endobj 19 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 20 0000000000 65535 f 0000009171 00000 n 0000001572 00000 n 0000001444 00000 n 0000000015 00000 n 0000001421 00000 n 0000005434 00000 n 0000008728 00000 n 0000001790 00000 n 0000004652 00000 n 0000004675 00000 n 0000005136 00000 n 0000005159 00000 n 0000005907 00000 n 0000007999 00000 n 0000008023 00000 n 0000008438 00000 n 0000008461 00000 n 0000009236 00000 n 0000009353 00000 n trailer << /Size 20 /Root 19 0 R /Info 18 0 R >> startxref 9406 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0013_Communication_Diagram.png000066400000000000000000000766461415120503000322200ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxw`2m*PJK ҁ  * 'uŅQP` e eXLg$\_X7>:>}$˲r4j4<[nU7 @3k,֭[)Xvڵi&S3۔111WV'p n֝;w ϙvT֮QR;qtɖR5l]~T vc*B\;64z(BKdo;`w)_?s]dҲL/:m:or !Dэƫ];y܃}MF_uRB}2$}Y,ICb[Fknw>[B` o/cK͗E1w/) >bu~>2TO|>|!J%±GBLލ2~&]-+n3ϕSw޼&0[[g═sR`ffok_yG[׶~9+\%C螽>'=WB2HMpT\,?-üYgxŵ[>OD_͚|%g͖ۧy6V͸[c~{ H\-t8Y^6P;_:tr_xOı/~`ŏ|裌ȇ_]-| )]}xgdŗg<*:FhKwfsJ%(Ұ ?}ߍKvCll^Wqtc⚔>wo]U/5xkVNSt N'UZR#<<ط87! ٞq0qllڗҜ\R\,KAƊchBsg) ꧯgt3cQ?g !G}F͚o[)jҿX "$$?Kx5>8@:Б[D}h-Wr>~Ԙ'v(k{Y|Tt咭eNYaJg?3쾧nmu~=P9i}e3We4k5ΜoӮTnwq oqSLټ.+**4hЎ;>#jڪU04<6v|Шd0kɃ>uKlռ4Bϸog,-/';5/t_3f|7j !_=}įzw򗓞5p?|xGHg>~Ȭ/MxsmнzGf8~0$$eάΞt:oiy~vW g&>v{+)3{^V'$Mj7ի?;S8K*U]*=r(q&:!DqvKYЮu͙mn=Aµko{S%㻷?>#023Ԡgymxӓ>>rzۯhW@۸zR ] VNNʕ+U״i֬Y3o޼;C,T߂}8/VK};k*F+000&&Fǿf]}*F E0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 (X `(0 tjiiiijkGzUWl۶Gj]6>>^zU111j@E[n8q)nڵN  FP @a,QFP*јG.rL%wi$x3.W&}2W>. g$lڕ?$5=QWOAY;RRO 4Qn:99nYssq.54r muj1\L0k$w(^契tCL7˖p, XԺ2!{r`ts(ݯr%p~AGOy<ӻxIsveh1EB! s.e2t·K.Ҫ9P7x 1苇*|6yIY! Gk$Iv"5P<혗m%WOS־}7LXӃ4KBh"{ڠq2?y~&VΜ;ޟ暌V-*GLͬ"кwN(:mlWq+bZjpO,˻tڮWJ7 o˳e! ,Y'KnmdTLgsyܴۛk]}2nS-'Ă\cB;=ղDi_N+ze˩7o9W#m|?ѡ2{hҝtOT֦c 3~޵iC_/X[zQE5Jt1U>d ޒ\zɪ[n,37𫽇PU<|탃5%7ѯ\^bԝw؂%_\+ye[/ oqe/TжiDٖq~-qh1mB/?y೻"F hޔR.$өNۮm[t|&! !iUs_jY># !4׏ޟ~E, n ׿G][_|)z Ƕ7>:(`VhVIc'xKVV9?ז-xBxu{~.@de6vcWpّvޢV9L[Yc8bN $ONHHB^Z4 ٺuzlٲ#w[e6t˯暵kN<@wf.Bx>9F-+hZ P  um۶ӧѣ'N8sL0m4FT`6gΜp8^~{'""BD%q!_|`0̞=[ Qoٲej()>>~Ϟ=j()""B}$ F !P PbBvDDDDD-(**R;@I,@MF!˲AJ`j$IvP P#X(XDx$ g^GKHpOq(yx$!/u]6a}m_T[fYxgF5ttҐڲ۝oϖrڙwŷу@µsJ=7dU' !sGno2Z _6&8%%rCL޷.d @CGBv|u)?}q=Ǿ;'޹u_pOլ1|_ No'gz})[Yq# 2G=?>/ wU}$?~^2Jqz_odYeO>}ZS˧oת>R;ѹ8MmDriK1iҤ bϽmZjqw:eY>$t•O=Deu͟d׶|tCe;$Àw;Y^11Bo9 IDATY+ zyʃ..ߍFw7%ʾ^B.+-[ߵ^ is]f[.0ڹmRGMN!(]6xrV?譵ZTU wx{TB`XoD闰JR`dTcɾm>Bn~ALֱ!y{B$uywn{NI"hEٳgϞ VfMU\"$!,WJ>q۫q8TNeo{{㟭vj Fo0e9:ϙda7;4_j&j>Iȥ{{7Қ3qƪbfK2Sr檟6 b_j>gH[g=n5&N{FMjw7ozyum_5[U\谀>},'>u/|}ҽ zꃶ2H%ɳŶ DcY6 kfT9g(#rW=<4tBCTsuw{QyZPKK'Jf?<ǚ}tkX'˲,W7ZϚX]u:]D2YeO4fqW[us+жt0jl l-:G _s{k}Y0̪IY{;7QIE^ހC覾^^!-˲䯯޵Ӹ wsaO+Jx+UrYYߺwXQokk乫?hQC;G~WdY9o@lAWNK%ڟ]yn{=LOsV}ǢmU|;6E:mْEzG֧Ӥծy]?S\Wq R}V?;wi/_U],;izg7N$1f@tF~f_^#c^t}A4'ǙV ":4AQc 'ܻFLvu"("ܱĩݻR|psĐ0o|z窡Я db-dB9]f-V+ʱy}I;ן_mӒKDorRh(Xl}ۗ2wMؐ[W7wf[ qjm˘ȧO8mҘ~{iK2)Wv|pjca ޥ%.;4)\-yiO m^ TSmڅ?O?%;˜ruw`T,6 .MPt&#EN-,./(,9M|{g/k 7`B7D̙x_kۿ`ƌF !Djی~>3y51mXZ PRM\0}+'3dν-XG.ߺ32kK\tFу!e_NznogLB-ʯ$$$!V^n*ݐkNҿq#X$M4矯`6p\{4>`Εìw.:i[ xLp9ZL<PC(C¥}ꩧ\30@?Ԋ _PK/X)SEB֭[vvv>}1o޼{=U@0Bl6Ss 80::Z1dQ/D~4hРANϑvx&Fm۶lSZ= әt:D<ָqVXv T˗/W;ZAbĈ4heM<+l,Ԋ]Rv޽`&LPy,$v#$z= hxL\%KBzkŇ7~x#_!!!0iӦM+GB|GsPcӧOW;< .No'O5jq,xN9X@0T yc0aKUϺ.NQD{{|t-9k浪;jlP$yuuq}zߦ+ǭ̕/nUΝ!&N8wxvc gϞfY 8Fj?v],IZM_]V#kҝowL4z/;EmZbk^WySIh0Ǻߏfr_vE6q^׀~|WZo8Nt7x#<<\#FP+t:fhu/ N,x09~r-WΜK[tNӿ}AxW5Ȥzvc_ٿҤsW|>{m'O60`Nj=z'OB" wƿxw+58W.^d]b5zpGyC7yO~&S@"} =iLB7GE_ظeo?fnf}н3w;c=7<ڝ_fŜ?ö0_OyN! 5r2Qٟs7}̪*_7^B٫_|y~B6o<...--mҥ'NԩS``=Tvx&pv{oϰG>ڱӤ!M;lO?t}w8I?E=۶}Bhm=5>)|̥nmk}W)QnlӂyNO|U9X??p¡CիQF6mڴiSu'''gNgNNY-%`Q?Y[FO#BWtVO:?~H6፵Bm4}^,FiݷsӪM[icG7sͪM%db͒mzlK9gVJTynw/$IB9sde//8zK$Iep郻=峵zwt'?(=JjBh#Ʈ:kB"YvsBh"{dKMLܬFwvfvU*" rǩ)c,Ԋ3fdddK\pOTXXX=_dBh|[}m}}rgbhp,=eǎr i$>~tqk֬m^өzuq:yS$ ӧgddz4͛iӦ֭[}ݝ;woq#(Xz=gΜ+V?_˫ᶝ:uJNN/333{=|CjZyqjEFF>b竆ɓ'ӧOBXVfXf`8⼽EM0aܸq%8.9r1LFZ_UVQQQ7.  "===))k׮[hnONN޵kׁvn?rBs졨H$ӹq'N\$,o޼ 3F#l6,nX,8pmgϞc__K8^^Vn;///;;۶m[tĉ}ݯ:>>6r 규;_~۷o]5fi檫;v+RSSEԵ)$$$11Qv P_w}m۶ڨQۗv.#::zŊBǫ~ >}zhhA(X@}%Iޱc͛7;j'Zh#,\x(X@}%IҒ%K~;u-vW\v`PDGG{{{h踋gϞfY @âhۧv`Vt:"(((;;[@C%B(@m`G`PJJ?oZBbZ)X5t:srrNA(XQL&SQQ)E$YN4t,Ԋ3fdddhp4  P "===)))==] @#IV;Q0,(`PHHHbbbHHA(X<3/c%ud,qt-qtǖtgӘ}[swmMBsAen5wvWD!;ϴ#Œ]{bu#=-yYKrrʈ$e$wv. 69PSe~RX6e6&Ȭa9Jd}^Ҥhjb{8D$[ >fnT-OhBhZIH~4 ,Ԋ={fggfb$KJXz3gܘ#S|LB9!ʫD6$!LM!8BJBtZr:eW%BѴC6]g'CI,j $0v{cZl6)pu1cD/?KϵK% مmʧK LѧK7ka*sYtO;R6n'YBZMMҠ9(XxQF]uUj@Znv-44tjǢ`kjGI͛7o޼YP#`~i!/v8? jEϞ=fAP Bl6S`(hRRRSRRD4DN3''t0 (X3fP;*`V'%%PFԴ IDAT4D!!!!!!jgI(44tjb @a,Q,Ԋ={fggf jNlj@\"P hNgNNT;< @a,QP+222f̘vT@BHOOOJJJOOW;*`(hBBBCBBē QhhN(X `(9X={6j@, NgN:D0 !JIIOIIQ;< 9Μөvx& (X `Vddd̘1###C ZvT@P $&&'ӧ,QFPsP+z왝m6 (X:fup@a,R%wsls`n(=x_tۂ9%Kn&Er)e>`der {0IIIOIIQ;< @=Tn æ"<6b Vq˴s—O|6v%%IfLE]wIzK֡Xtս0t8*apw_]9a7~}f k{Iqܫħ+(`7=[iB/$TKg7;OtIo!sGno2Z [.p!&[:οNb4Z[v٧/L7N%59s̻[LFs~wTwjÿBt#n!csuO_ls 7ï~ ;w>򖇇556mֆ\YIv7B,Hkzo>0;[iT,APK%51*|Xc5&5vS;bEEzmsAX@>tvv)[{c@{M|{< {x`!LcC*`|CNDJڢ%wo޽kBd<|fQM-ZxvJ8~ÜN$y|Rgy6< )]|W5#k˘M4.]A#Ql|̉HU=F orwה!OdmF;`Btk3Hu&gOFHeԞɜ4'#F!2""_۾[ }'qϴO~(To^σ_Gw'3<ڻoq;.bB:G^+w1JcCJwi>k_<'].s΃8\{ Oٜsn$ZPu\[_.o8V6*Gܩ4]2?NJ\qjL>sγRܸƜz2CZ979ܒX]*wz¤ID{hQcN=P 97ܘ g}]6erFz{FLW)8ω,bH g-nJ6vTzp˛p \twF2sߟ͓/F#ssjCC\ꚵ+Kl[.YIdv Ƶm3<WP %#nAȓg}B/es7Hc'; SP l< 9]'T(-ߌ~d(ҿR uj~{x]Җ4vUC*mߵ2ñaJmPo2 o(ѶaB[uZFm0)'nIp`V1z< KƉ=)鿤Ճ}{C=<<}Ŏᆊ<"CR!$ sY^s\|5׆N8uCʴ}̗Hił򕛛[hh gqnV>Lce/"sRUݸYaF5zEc>8DD̹j,""Ew]|ʱSaZ""Ѱk_RR iuZ5-բם'8W}ڬlqdYDT0s+3SJI)sk!7=^ {tb6v"!ev ziẇ6M|E*U5kVJ]L8o.eVh:j)""fۡOØ!VCo~5dT l%}EΩrtaa? |⼾i+=w-OVoȈG-8(ҺĈT+rHS{Tn3ݴRWB >e؇AA/nb-w+׍Q]MDMsvh{A9z5B |k1ZmSբitЩOL+lHj5֖t C7p{۴r C}z6JOK.Z_bcBn^YN%'S)NڹtA? _<{zVkUx߼S%?|KivDDBU$GEP{ y4R7?p۪].̎ZLi&nmt}ٻ?lƙ8+γn"J)d2c{mP5?. c'>p 7[Ӷdψ-NJsz6r+T~RirϞ=Dt1l^Jpppppx}[~%)0,A4K2 õ\Zq-O{GbkGƵ83NuHoYڦYJ]{4P0}o"'8c g?xGBDRmg rҁt7'iݓ?1?ϚyC,bNiÒ~ mjl*CjTq'߫',:|7 Jzuo&3kay5 V ;~U=I*jԢ}㙇vG$"҅o㆖˛>rhMoYp6,J/ulxSxֱ{D&aWpE篝;sܷ E]W#O_Oo>|@ϻ>vaɤn:|\rbb/ Y}]Z~ːjOJʶȝm^>ZV7%\ 9,M7$)ߪ}j@?vd\qU$^v}F$uk _s\;hŞmJpٿ'VdݻT ëTeTU1"ke$SRsubN&|ȁDH g?i|PWNDy'=Lդg9Q_.[V׮to +к?H(Ӣ]}1{Zܓy~KK={KYo{U&ܶGK6ޱ@sEΟBiqqYpG}E|ޭ IN"gMib0 \",R#1+ZY3Ƅdr"ՍHn_޶okݻO96K8״@!0XND{wG1YI(3[mwRUGߟ>4WVJ{q-y5xJĪW*lJys𑁴>)gvU"'RFqݓ 62N3dЖ~uqtLհBi_F/sB `A~IAG6 ^i||8f_/#)fKDrXj!,XPۆx.ޱ|.J I~gOuY޵j$"B (i5Qx\~ڱ_uoncHwpKG̵Cfv~(zH9!dDk`9=$~2u=$ +=;UoI R-\l7Dfr71*L>:kfrŹk?8h{Wg Uş;p6VwS<'l+|H ס,8Zs<,6`+wnݼۜ; D {'GCJ _ 9$ ^QvqnAo[[ڡD!hĀ.!%V VxK y7`=Q3X:|fmjUt4ܺLՠ66j !%GG,L=₦d 1"b~_HUl1yٯhB~`dKPnݖ-[73Hј|˯zH<,fr d?`({*63;;a ʼѢKeoX+[YlQ"h4Ba*J]ȋA (aJZR3>W֎l^ֵF)zU2. ڬ:rG/ܵRip3s>%a+J:]&l&&r# ='"UIʘ7Qm(tt[jjjTRQZZ y1!% *rZRy"{k'צFrh-C[]{@Vm='zoGU*g{s+34ߩ g?g|ť4qȅG:TaZ( H#0M!GJrX\H>p|z=QKIIQT 3J.mU `PExo67u/%'%2@uK?S1tx>:ӯfo\9sKo5Fkx'.ۓpm l: !]ZB="1%9U\DĹW&%9Vp23yyP/J4VV]][ KZR|bT=Wu8D;g⯈^ic?| Üj!e<~UT\olqV `)OiG} K/tEv8zRJTTk)Μ9_ 0܅1߿V* +Äəev2d 87H-aLw470@>X%sxsvI!vۧdɒכeU(nި#jɈQTlM+;ʉ[Ul5~udo.5k2dN_:ϟܹ]#$$}Ǐ߸q㋾7))iܸq~~~^Zخn{#$sz˼|]xgc. 3})GsBX(85qj#dB~'wx=( e9D=\L@Lx-C|kAqƍ]Q 3c%N_:u$H###]&)))((ׯhѢbYf/_~=Le" .-瞎q1m|WѶKk24{]ʈI+j! *MSx6\GCݘ4=)|J[j՜9s gN8\UqDQ7QVMMMMMMMNNNMMDTtǏ5*gx~jz߾}+VXp#r:88T*;;;Jem̼666r<>>>}U^344_}aBamhDS"VOjG*w[ 2kTtw9.oRVJEڲyKͽ?01&Ttrٲn^Af63 [YKTn._uחljq-F7IDAT߰C霓WF/=n~ݣ$s羴SNA [tvCy=UYm8#Nx|銈>|͝mIjJRT+Wc ߊ/I*2dȐ!o>{lTTT|||jjjZZZRRRjjjo㤤$"JOw( 111b:LP-q-;Ώy5j^;#Бաm'85UF/=עL(l5_;~?yh _c$gG;vO(j3ĺE?kN ۾7o/;p& c` 0%B(VsOnРA%\" %w}77?LeGg/0""&s|]728看y_HP7{!s5Jwސ CBhȹV||Mk goȞ)Z.\hňfOy/-U}ufma==b/UH|ٳr/ rFD?y ~jiÈmJ3 r)΋.[\"yڵk=ztnnn\]]-[vԩFpEt./UIH{tvV ׮];$O {&3|`HY.$\ݜ0vkDdz9K(ڡG3;So?prǞX)tRQVH&m0/,ڵ+W&MT*]id#F\vm4}(Sϴn=w,GyÊ+VXv@3327kYIz%߰rيAIDB/ Dz%eʕ1*o cuƴ--s?WPt B[8n,hV;^m&ȉܼ[Ky?94~=KAHZ9$#,Ğ>Y|UWL f=;F̾yv. t fC&p=;mLK8:!zP2ij$G  nœ(ׇGG Ж񴰯?]]A=:UغGkGFThqr ``%@0Qh kǴ}|zquMm6xYv3޻`P*,#ՠԠ.P'U8)&o'u g$ܞ_8,04 : DDL)ƈY}q I<{g_Gc"q/ʘ˯`>뷐8k01iJw&&9d´&*0c)rd4 4͟~0^\Z=zk0_e^\il(髠_ӽ&JEcڢ, \+VpUI1%*6|Xڡr-\Q}¦dzҒBےY{?#_kZuUHwHu$n{eUJm)3xoI1ߠi#>cO'Z:y{\Q˄O>8ڑͫQں2eZR&8ەDy{¦w`9|+9 >{UU8@7 ,4ɍm]X $̠# /4SϽήoň{%]p1"j>Zz9kF$J1q<O詌um1WN9NN9c1Aas9ݙ9"&w2"fWv܄^wߝ3oi|X\fSƷM[i9K猴U߲9bo?V*l]ڏzKs/?I=; XKz.&]:q%®\@~dwUWZviR>Ⱆs_ V`O¡rI\43~Ĕ? v)*5T`!g^^5Ҧl^CڸI\",0B+dec ״W˦^ǿy*%B1aխuY3g]+f"p{Q_t/ -.Zi RUDK|` o" Xm=yʍG_߿fyZ5'I>꛺rF̺W \{/ӀUD+ S\bޟN:9؀%m,X~4sְu<纑eLxg&ҳ3gG {A^uᴜ_GPwVN۪̚=Jnӝ|Ksn)+ln~,/N 9`KG6r$^_B[{J&bȠR#نvd̦cOμ/dFWBހU68y< XGң.%ȼo}T}Ԋٶ[+rւ, %CXN{wܜe]ZlWbT]7Ms`X ˉ2jm[Ԧ')ۯIk;X1bmWŋs.,kx2R3"IF= 0`K$_7.ȕz`Dey>[EݩWդ*gqγ#7L[Vg5=`a[ 9-g^ L/dW6% B'oy9˽ϔO}C"p{ւ$1icW{Aqm+b˒!`Yi%g7L>:kfrŹk?8h{<+D➘(-Q3NYWăt}fbTVG].df!㣺d=\ ν%Rn~m3MgJγ O=DDB`oɑ7u8;[䋑zzӟU"@nOoףbDU1QJQ%")䌈HP(ek5ZD #GIdg>]pF<[4I }˓46ZndaʅY;=w0vU-mߵwPm-q=A*7 Q#+?pmIdSO7˳nn ]N =m"!1DB1c#tN-^%S8!"FԘ N|VYG%UO?Ef_wɢM+\x7#$lզoؾgе v^Zp"bg bۧ7{P*γ rs?{Bj?K{Qs[z;^U/7^C.# mc bǿp\$oάo]2}oemvA,=W2ݒB &H&m;XU]l_'O1'_r,TXH|t4׿K1*U]ݍ[6jԨQw]*/gN=2*ea""ş/YDDsN ׵,7F,dk3%9qEGDdH.Xk1A2ƿO+}/PO'vnisyi'2=Vm Ǜ{hӴK + S!on+I66 IΕ & 8_S_ΈY=X?+FĤ6v2Fdm})<`iNy"砮h"Nb־n9O*U"̊I]JSM8c*5=X3V:]鵭$G,ZaŤvRIxξN\6Fdq}Ԃ``q_(|FL-0>jQ 87yq{>lMLf]}^{ssf@A-Iw~~8ȋ-<;QZ*l-Դj[ɳAp ,3ټʹZ GԒI*}+kG4q۔=OMPzО7ׇvSJ&rGcu,͉e,_wI*|9 _I)wk {dNϺ Mi߶D?Yńz9)e uƃ~ Udֿ|UBS/O|Y_, , "Wmޭ Ru ػ1izRx{#RSkn[mq>!zǼV\våָۜu7£ U\ZQQ׏O^~8 ё0Tnv"M\T2wU\""=p\bU~bՇz}w|]ģ7TU >_0ۍsjz^O;O7$>}J~jѓc͟z#_Yí] ?]w3[ۛNNVX9Ss4//[QPw쓯DJēn^׫(ܻ(YBDDbkrY._JR6_Qxx):^drg䂏se,0%Y5e2D$?_ssFț/}UUI`LLu᪲NpUv'ܵ8J˕Fߣ{')WN [/狼):.KIѨ\[+\K8Y3q#r.ى9tR57u" W  \bkIj _:DD$E8@3ҭvp5yV6ryʵZMW"דT*aDR z=7_BDHUt4^P~lo@F䥳Gr;*FY|C2w?/X%)DDB˜LR杛35J+D$-Wy(r& ^Y*,0Zy+.^ТL;nŽM];مrgzM|^C(Т4x6jk Ba, > ]41.I"-CJ,!^c)PZ,K`)3ܽs7TnJ&rfuUV3w P `)E> stream xXKo7q p $NP @C Kn )qIQkk%X{(81of8 +%VF ^ןUp (BK_!;WV⵰Q: >_4II%# 4d]sRM}ۮ7mhcڿmwUnLV.#ˮ^w].Ur1n ; ,?F,ب O%3Mֹ,εWPڟVP|Bԭm߳(1g^IL^{Qno/)AG&gR㶞~9:i]{IU$HY)sN$e's(a FTb]޸]߫_A:=a(Igt t2`1P[̔_]vn@kcF&:U1o8{e]}fQB<qټ|}ٰRapNM>d$(Hhe"+<Y\FƒBIH c{-XU9Ӿo9 e;=tCJuYJNY_e%.?pPl>zO m/a,)'HO ZE\) bK!?2CDF\u_+ endstream endobj 5 0 obj 1429 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-1-0 7 0 R /f-1-1 8 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 9 0 obj << /Length 10 0 R /Filter /FlateDecode /Length1 3880 >> stream xW{X?C]X4m*.ƈT  EMbUcXGC"&lK̮|?wg̝{ ` *Ylgd/)چm|YPRH gliappA&NB9Tӑ4zB@(!KI)=1B&2٭ϓ4Ն|3jy4?Pi=A6L!^fhz,6kvݻ3}>c|G_ڣ;@k@'O- P( z0=juަ0W8F#;q=IV|^4"5{B򡩥F an[09ήZce|0 p} a4TBP`joV5e_]awbfƒp%}d ft-mUW@zw ?0@mBګjAMAmvۺj\e^[d,;qK&B5h]n,[@yPh3FtjDWd7es|[A:=4UQGhD,5 (F= hĊ&oP_mYK'FL[0)!gBw8b[B- [rWN_{Y@OQhx*FzK%a=r<:\p:[ W,{@8ɉvyB$8"hV&ZJ4 f.h߾O?+=VL_GX>q[ԯ8{|Ep2D=ZC#)6֨(I 3DEA9& trh/7.4>TlCsrԛ[Oz9třOq!SjYg+Q87wD40G #f"v2TFYޝݹSƮ.Zڅ6qLay3(m1zRʒ|ީ}@K^/W7M'{P'#ű4K+Nup~c{FXeGIb;|Ty0 =DQ?q؝FUwxߢĬR֕=Eىs2_]<;{YxRcѡࠝǚe 9HEKVZdbl$j[밌)̑K`O;GN5^Dht uw.^2|]Rv!~^dx<öK({„\I9ꍘ@4}{7*`Ťq8z[g}jJi7N#܊v?uYetQE94{YM6&,˓1b>*?mxDMrmkv]~{[r+q uo~f'&&y>1vP#:^󢌧 7lIƟZNhtz蟟4o}7v#ҴaRPчG=3͓z  a&_VUuX<(gP7lς~5ҳnï*XŌχ P&d$z*t\(Cw_?!lF@RҎA(Qڤ=C"ytg _pC PLDَ,8KLw(guA^\[:L܏(io+31Rə endstream endobj 10 0 obj 2755 endobj 11 0 obj << /Length 12 0 R /Filter /FlateDecode >> stream x]Rn0+|R}8 ^R':nì8Ϻ|/ѱ8Un};*p=|ڇ~TMyU/ZosQ/vP4ìKj}{iĺާa.OyXBIn|ZDZ GVMYnu[#wUZ%iYE51㴨Ɩ%@ރE|+52 lxkxkp'd$Kr.!$IIГ-V+I4; 5@k`LR3K6cxx x#Alfݺ"mσĘF!a>8+?^ endstream endobj 12 0 obj 372 endobj 13 0 obj << /Type /FontDescriptor /FontName /QSAVJR+Roboto-Medium /FontFamily (Roboto Medium) /Flags 32 /FontBBox [ -907 -270 2051 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 9 0 R >> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /QSAVJR+Roboto-Medium /FirstChar 32 /LastChar 125 /FontDescriptor 13 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 568 568 0 568 568 568 0 568 568 568 0 0 0 559 0 0 0 0 0 652 653 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 541 0 523 564 536 0 566 555 255 0 0 255 870 556 569 562 0 351 516 333 555 495 743 0 486 0 335 0 335 ] /ToUnicode 11 0 R >> endobj 14 0 obj << /Length 15 0 R /Filter /FlateDecode /Length1 3264 >> stream xW{T;3kY%I jBX-b!+AC=5FAkEFHbh=GA.6Qk`=m꿝9wg^, X`0< FlF^~Y X pݜ> $PGIs %#œl (I |³R-` 0B(Ӥ&Ʉ>֠nAxx [}4YZ`jT 4vR5e:HgaZDbRDbZsrbӥ6c|+k )JG-OvhA;q']2 61Q` gȲ6@buŻdfH@ >f͞]66ބ^DyC#GH= X)AB f{>F7??'yZzLP12O3iMJ5a~7awXQ\\ʥZ~M,|xS)^ D 1(Nu,+V׃6Cv8@W6_CWSCgBq#{6e :/<@/^>E,YK P3O-@s9"!8,ocW:JVlo1Zj В`vV&Ȳ55$OΝ_ y,W6f7,'گL7P:\ ^ؘ9ֵsܟ>aN|*o>q'_lo~rqG>+ kR 6Nc|#$"v6Ң#))ӵ.KK76-/M8-YKP %-iDyGlˎ<~!yt W 3-%]uC6syU=\Ɂ "! B+Sg>~,X;1poab1h t!fF.vTf,7 #n8T%z;؇jU'ZgOzE>ADZO$g5N5Ha)?6EkswW SttىZ)>{|1z~m~vޠE(銓j;; 6V%%AD/[)blNs<83`hh1tn6Cf D 2T[Z 5m^'SrѦNYzg̒1/6~b %[k}7WPyM9m-h_BF$z(:V@7Nl,tn5+QQި݊[)Ez4>?|!ٸ[p+nn-e!~pT)KSeFbBk 1H+SnV. "h*f{/"3CG?mڳŕý%472}9}݇{;-4*ŵ *ާxnCIb99 Yz "'Г  !R@An^?9E-Z-H\&SۤS*?HߡvPլjW @c\3PĤ3v C:n¦́ؿ" endstream endobj 15 0 obj 2265 endobj 16 0 obj << /Length 17 0 R /Filter /FlateDecode >> stream x]n E|t4T/P~; }(0 W@v;Vyaр5r\Q~{ -9OIy8g9#Q8CE k jk2{zk 34 1kRC&7=k 9.~ endstream endobj 17 0 obj 346 endobj 18 0 obj << /Type /FontDescriptor /FontName /AXHBUI+Roboto-Bold /FontFamily (Roboto) /Flags 32 /FontBBox [ -913 -270 2060 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 14 0 R >> endobj 7 0 obj << /Type /Font /Subtype /TrueType /BaseFont /AXHBUI+Roboto-Bold /FirstChar 32 /LastChar 121 /FontDescriptor 18 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 673 638 654 0 0 0 0 0 0 0 0 0 0 0 0 645 0 0 614 618 0 0 875 0 0 0 0 0 0 0 0 0 536 0 521 563 540 358 571 560 265 0 0 265 865 560 565 562 0 365 0 337 560 0 734 509 502 ] /ToUnicode 16 0 R >> endobj 19 0 obj << /Length 20 0 R /Filter /FlateDecode /Length1 424 >> stream xc`d```cp``bPHϩLe;P$d&06/e``2sf@JFnIGC%_s''@&c M(`Pc;|Vf @;9x9YSQ F'LnZwS߸5<*11-& Ih8"Pi.u?t^Y}髌cN39ŻRe7>bR++m2Hr0@8^(Ha`cY5Pq`baHar7b3/10] endstream endobj 20 0 obj 367 endobj 21 0 obj << /Length 22 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> endobj 24 0 obj << /Type /Font /Subtype /CIDFontType2 /BaseFont /AZETLJ+Roboto-Bold /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 23 0 R /W [0 [ 443 608 ]] >> endobj 8 0 obj << /Type /Font /Subtype /Type0 /BaseFont /AZETLJ+Roboto-Bold /Encoding /Identity-H /DescendantFonts [ 24 0 R] /ToUnicode 21 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 25 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154042+02'00) >> endobj 26 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 27 0000000000 65535 f 0000011025 00000 n 0000001691 00000 n 0000001544 00000 n 0000000015 00000 n 0000001521 00000 n 0000005532 00000 n 0000009103 00000 n 0000010864 00000 n 0000001909 00000 n 0000004759 00000 n 0000004783 00000 n 0000005234 00000 n 0000005257 00000 n 0000006003 00000 n 0000008364 00000 n 0000008388 00000 n 0000008813 00000 n 0000008836 00000 n 0000009552 00000 n 0000010014 00000 n 0000010037 00000 n 0000010339 00000 n 0000010362 00000 n 0000010628 00000 n 0000011090 00000 n 0000011207 00000 n trailer << /Size 27 /Root 26 0 R /Info 25 0 R >> startxref 11260 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0014_Deployment_Diagram.png000066400000000000000000001065141415120503000315200ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxg@S$$P* "QWժUֶVZg8:U\* VVXBֽFIMɽ'I(r2AL3woqFgRʵڵkGFF҃8,(cϟ?y򤹫0GӔAkڵ8`={?u 7SĞ2fRH{'MU<'.y"hb  QOYBΥCGsZu= DREj5<icf$jZNRVB`O}{W}9t*ӵa? S? kc1'RTk7tLmSi+4gY] "BP$WUy9,k툈AUƩ"!k[ո ə|I-'ܸ\N]XͬTY,BQ6O:qx[lWe\iVws^۴%?]␙DRRl s 1g^9sf@^?u`{+mBd%+xe_#ZK%]%N]XB v߬iF%!څTE%1/!>hXo { m1i79e""992Qaq.%11KY","">-SU~+[Ua~>O"b#Ed4-DVV$+Ax]Q9#-岂`#}lbcF6fnW@$dZ:0^.SV]?47[5G%RҏRM-)\;N~UGͬ9KS"/\Ʃ:CC+{#6rZ~meJᛮ艞U٩V_ ni/{ﮠ3C ]o},C~(|p#lQj6n'P7#"bQEogA]mN;o,y͞;XrVTY*^a*)UvE /@+!=)o^O}B̡V`U$uEV~I0MvhՍ#Kb+|4w<9wcLZ~1|?TvKُ͛w=~ϸxbǓd6b2 `$X̞jywϹ|tө{WO^ 97:U>9"d6r&dO-7ܮUŤ >*j[ %"U`f&^7[5uӇO,<[f5߽bj+"Oܡ[1cvrG mummϲHTCH];DM:gqǴdǯSţXQ;mN8qئm]\COc87~JL-bɱ׌ՏY5"#C{Ybq2fM'%}=5H\`R^)8S1Z%$NɵM ""|{1vF0^jbFY_Sok*8eɶRyɘ쩖^_\VQ $[V1!PTZk{Oϻ'0[[kvZωD7SHDĉι9s'.',!#>`+o4 Ĉ@Dy?n&FG:OWM|gs?R YLWWz,.%>OM Ӟ;Tv+iZA*(W-u'ΩVvjriSz 1j!=٥sP+g""ggKtS|V|\8}ҕ{55nܸq:NR\AWPh$"2\:r<^jUbcuDD|KF@/11ݚ8]M_T;f_Z1؇ṳA ˓|<[HL[=%" ݻwҥK 2ҵrFAՃJ*,>J-prNg&rYGF#qzM񩫇D3|A}"4dd"? >.rkĨ*n|eۮ_0_IBJ)Dr{Vd4G({!?04W|,}=ELDykLO8:;-HWz4M'dKn[>pKN׶ΞHWΌ}WvE./Vhk9Gk_ȧ߬m^͘Ika6_!]â x%"ʊ6SI1c?ܵvV|||-X D"=Zj͙3njѱv< Xjyf,ƞE`.X&`bX&`bX&`bX&`bX&`bX&`bX&`bX&`bX&`bX&`bX&`bX&`bX&`bbs`Az}||xCTZUV1^߳gϭ[7Ē%Kl*~_LҰaCsPh4A"طo_u޼yF2w9تU"##/1m_n4{/ ]UV 8e˖V2w-fV,+Sym&J]sw)))9rdz=jʫ;wΚ5(]d2sc~ooھ}޽{h7w9[@@oo86l`oooZʱ̞={6 ꁷ7`iҤ(RSS1fB,[u@01,C01,C01,0ݞAE'X4psKxEX`^q"cBͭsMո.]+A՘p`05b&fźxX`DJڹ̬⣄|E[*e2 a}f칩'2&-WpS6_|'*86UEX` K;~FD|ݪň2!+9fW63+=0sڟI',NԓoN` ֑0$j386y~g{F_Y5!2)8yW83]y‚3Y/f|PYd.}#iOgso4ulՏh֬Y&uݕO?g =' h5tH̫ȮD⾿nLv7-L{бȭO=Dn,}d)$;ѓ5C2q.-+VrLæN•bH ._edjG5LjϼiԻ<gt _%V6o 9vtU7S'cBegt6.zHbM8O.$eXBISfBX`^bʾoU#:;1<>:\ws /{ QL֐%ݙ3yXP KxhyT]%ٻ,hfDD{Dls!lձB'lH1rߟy=SCmI{f8!X UewJ߆xO67uN7#רL^,C01,C01,C01,C01,C01,C01,C01,C01,C01,C01,C01,C01,C01 'i4oF՚BXTUʬ}[~岎ks@6Cץ_{eݦKxA8DO;b@J׏߽_th:FɕJ.+9fvg4Vh/CŠ D$9 ipt@CH{8ۊbEDD+?gek ӷR=U†9}< Μ2?Ï1X`S8/s*;{h:wӤi1k6t&33yuwW ~;;G<x̌,S;a)]=<==WTIdMo,gB?{c2KX-wg~.r-\zLff?)L,""jٚ{.5 S9"!/DC#""Ewk9!>6ȧq݊|VELDoUaԔSnK, 8 V o^ {JS1JK.?^`V6'1/}yv(%σ%F0"׌CƔ%͞9gEDDm'_2o4NV;xWҧN8ZUW([Sک8"㝸S7tg9x*CZ2>HOoi|ޞ6HfWskgOXh Ωͻ KgOIwuIN}W!·֬lɜ=}'H*}8cc]]QV2 }:Mv.}WeQv_տyPjS;1T/]C{9:S55oKbBxE"( ;;;JR\)Bzj^coV(f`Oܐ% 3ɑ'Ҫ`Ax8+g.뱧vr +q}4QN l=.dIvVRIe-..jqfB JNDDDH2̊D"FDݖ8,(w\ΨEW~Dשzɪ aUP(ȝ䌈]j y"F$h0'[Hx]Q9#8`UĹv\.+ 6PyU,(#N|BUaL"}B&*0\tWrMqaJVBRiブ 3XP!`Aa#^xSgTF$k@P~%VJ %#R{t?dڭ#d cRHb\|kep@DUf=;^a,(+L|I IDAT]IK7 jUEQ58v:z ~ѧAO-E8V=Y7t>#=[jW]VrJKK;vsjxetѦgP 2֬Y˗/رãk 3XP*Z*sůVO<5kVe3Xh4HW0#G"]@/޹sxݸqn߾k׮sI$Z}!sDD b֬YHW̬^zL L  LԩSu=uꔹ 0',0SN暻sB01,C01,C01,C01,C01,C01,C3^Q6CWYA)zmӚˀ .!` %R&S5=X@DBy}B2k` ۯxvjĿWzem'+ B!oC[ZI<; ooSwycɽ=NH;}zUR+[V&p]%45~>>/nOntSc"{Y wZcBHTţXQ;mN8qئm]\CR2&ke̚NJ"1%a 4\~CFo(UǯFs'3XovDDDK4$9`0jK4N1O3M&iF a &5n a=ߏ**α]>txشsVgK7/6>\QJ/҈Qv+<#+ߛ7{'{/Lth֩a*@ N\wF)tco|}ZGV5./~ =ls°O9{l{#Շ >@N{X`!``KuNFZ WWWLf*1Xr-[6x/|pȑsWAPZjչsgs򶋎޼y!`Zr!CZjm62͛7Ę( YrAZltev~i׮]ǏoZdX|HWAZ~X#Q  F-X`ܸqaaa-0wEo+VL<(]I$sτ ":pذa,>x#FԬYUΟ?9yd+ˇO}-[4wo={DFFD"sχE&`bX&`bX&`bXz (bqơZ+wQHe*Q:Ӗ `JXZ1ƉD"YN`px{3 />o :K0,xD5&(4 |$Tx!ĵG8d]]v(SXP6DJSFJH''"~]`eLjS;F"o.l*eLRkQn ?;#7(pUdsS_c^-j 8{RznvrJދO&ajjLְ\H;jX*L^ߒ 3[1&m8&jrUU2ʽU Ƨ{ڇl2UY.П1LxV9`o &K` "mM"Re%Ǭ毣mnHX11>2!w>dUC|*T(׭ZΌG"–JYջGl=퓻o.c8rBJZζINE^Unyx/hEksWc:鴝KZu;>wꁞTw]9{Y.HlkSw}UguP010\9uAJpwӤi1k6t&33yuwW ~;"6S;~6~a?1WӜ?ʪ qHdɻMe1<耢ht⩓N 27TB3~[ K9~_OHeM`#s_ĹU2AwtCI/XΫ2n)ݹp} o `EC* ֑L}?*<@@6vDT yq$/:SS=' h5tHyun^׍؝Y6b"XݖVT=0@ɈݪU!;+1b۩D$쫸Y|a~f""Qd2⃮VDZOX4&@Jf!`E8cX"1ƉeʊZ! iiu+?ܞ>r!+-(g"/jUM>3=wo@soWw;H!%ĊxMFQ ήhn}AD$}aBy1I`D~} Q)%t{l ejG5Hy_-wSD"{+1uJޡhQ]niSۉ4i:" sLOa 4X4"|CZ2>HOoB'1uhz2&Zv6Hwm㢭$jbvmB^0W"5A]\z+Vܵk x XI.ժ(ůtfu9yW d޽{o۶ŋE!`Y$ѧ'ھqal(W>sZݹsWeZBN>NV2{Acs"2TK"򤁈H{`yT@DM)Tʄܓɻm*:oJH?2OH5\p 8aէj-g*JKgPE yȭߪ5&JiP{I>t`\;|)C(뽑}^-~x6~N2[MWpEbxmnzݚ5k><:::;;E5%!kLjvC~n?~8S7Pѳv=:OQ7zrcҢۍ9vؤսv9an 集宊L`OݳjXO c P>զ} 텫+zSÐɃe#3;T.yb""ÕZOߥSwӷ|2qM=_Û @DԸqӧOO2eʕ-"";;;kkkD"b^H$?t:hyvDD֭[_+9t'*vW}_nBv-| fpm/QgF$X&ywx=Xr5c36Y6Qnw664[6K#{Y wZcB?px@x#ᜆoȈ eT5ʿM%"P~udL&"αʘ5Dkx1邳ZGU%HTCH];DM:gqǴdcm "TR˖-^zaNh4MSO*[A(JTݒVz^p ѝn8ϸzbۜypvS^ZȌyޙ0qE{No;Uq-\pر&M6s  YRAL$voq[v"ӎ.8iɎ3ye6e b #-WBDMLfߴ7z|^+ {ʔ˓|<[HXάdR&版t""H뉈yOM1Zxz8: h,d3|܋C*nX;M F:ap+j4jܸquJOw{hŊǏ_vm޽Jqܹy5j֬YfOWDT ~۩ϬmqwuUzە?b;u#Fʄ5_ttp\8&5Nݛt1r?$.'j,]y(Dn׍~Ο+7kȪQ>5VΜӫw6fՊF x ]Y=agEyy,tԞis$?\}ULn` c6w2&?^78G1~g{h!!!:u2w!nɒ%֓&M2w!|Gba?&įeD{35eՄȸ{l2c$+z~ە',0#K )]=J([ДAc_Ǝq?OvCKdc5kͥW-^y ͦj7u}0-iv|5n!_l}׭< ?ZujWx8*rGS+D71&,8( ܺuܹsݺu3w!ݻ7oV]CRVxǯz,>N WBV̞S:$HHgdJ"Aq_7QuP B&M4i"M(%%܅QOD7w!߉.0fΜi9BDw~nWZ<GTV޼8}!]Jľ_;KbwT RPȎj[[zeȏI=>:\ws /{ 1)L+}ӢJU-bInsv(  ,ZvvEe}̃'Ԯn5X+5`/G)f9#1*}T s1PZbenk{U LX ^1[v_\#E|Ɠ>p+5_` r( @<"n,=~Pk , [ fM`,, _[`xGhxE3X+E!C ,BË( X`!L  L  >CR -dANblˀ"("hb  Q?BȹthW%]*_jZQt i.&\In}""{ЩL׆~O'X)&)Ԙ)oH(h nNrOdgjSN_15v]=wŮBs5ACf‰ O8pDk.'.DDs`5HM>vZdY1'U5Mƹ "1@cϼr\Ͻ~?>WÆiJN eEO6BPUTRYUrQ4م%BSdD"McXIL8 ,""AS R5*Ϟ"":u[/1Yz5 1K`"!` XĈb d iS<;ge>ZR}{\.+ 6RLa/XDDN|BUaL"}B<ʘDsz}zŐTP9 g SߵXYٔUbco7pL!`Ux3ϣHϸx[gdn+2VpHN$޹t1׾XLA `$XDO\Î,N&gBkrB"]7XDDLT 5g*P)YZADDOfDNN'_X8+..b&SI/Tpʺm="Q 7 DBdJ2Fkn޺]QV\PPP(W*p|A(8F `߿;$E"IR׀J䭔.AJF~:[-O5GƤr1/1&JŌȐ~V #=[jW]VrŠ!(M h*\"iii7oNKK3w!Cȹsw~9so8,C01,7䗾IIg f'vX?tXo>&QT|YA)zmӚ.7. }5/c,dBN>NV2{Acs"2TK"򤁈H{`yT@DM)TʄCk;ʙۦNӏRM-)\;N~Ug*JKgPE yȭߪ5&JiP{I>t`\;|)C(뽑}^-~x6~N2[MWe&XK1ݐo 5O+txtvu6mIo7f݀'}7)wpVv_{u7 {M'F-Z|hvQ$L:~/Bf˞w j/&7 n>Õ̌#m߬MGYM K>5 !B ywx=Xr5c36Y6Qnw664[6K#{Y wZcB?pxpx#ᜆoȈ eT5ʿM%"P~udL&"αʘ5Dkx1邳ZGU%HTCH];DM:gqǴdc f,S_eTXugҾqiG{9[D\ GN~%A|*F"2\YI)KDd,+3sDDiΝl""b33F""6xU`qNer>^|†̝?!"lbqh"0]^שsΝ;u*<@݆3j.g_}6q~^fߚ,dH&Б~A9ߦDDNFt֥[mNe;^ʎIܴ젱bN>Rqmm>c\[z-^bӘlf&o]YƑ?!mDA߂]qyN26+-@d`Huʖ%K~7oӊSH2J}#fч"۶6g)+<ƬmQݦ/?zk &mQ w~2kΊ+ >!iL|DD9r4i͚5'Nrqq;KqȑÇWD{Dtat_`Ap>x ٮW0aFf  P  P  P  P  P  D|:ClPryN3'''w5 |*// K,; &(X5KNNNnnܸwl6gffZ,{,Pˠ` ݻwOOO߳gODDq굌HLVZZw})š"77[niiiwFWEOfj^ڷoF;JUq ;Vٵk:w\XXvڵk^믿fڷowPx䔖wzpݺuhW/`6mٳ')}EEEj=5q|Gxn(XP,+ jl@q :xeYaN|PF Fx 3XP`@f4% ) V=_%`CzkoܰkadqF*۽{@o|lMRgpϱ]2[;EZVR`/lM9"˭m_RшCP`#ğ79QAΎpw:TQT~)3]KeLY}yWWsFc׼CDH3;H ֭Cf/E]gBIfD8NKn%!&\띫W'A Vay3 zRʎn QXtܕ _FH57}+g/^F#gN=z4roͯϟOm+>r)S4{}^s =G~oƷ/J\/-֐ i S~*(拝EwN{юӉgT5YLL nݚ Пظ5LB/H{npӛ^c*"4ja +"fDH[ED8t5,Y.d>|rwDcg]1}ܸI q%q̉ n|'j]vT+q?&x{MCco-ߗj s/Jl_u#ѯ|޲?'\E}ku̓++,oZ͖Ymjݻwϙ3zvLj.͚{(EGmj,zBorYʖM? [6egD"ZO<[R̐Ai4=6?\RR]\\f̨Cö]e[ 0} C_6xKrڋ,ol^g!KB!IֳClVNĕAeX~_{w1jԨ۷;88XcÜ.vn>6gkc!wЍ+2^hf`PoC.Gšw>>;xၜGsy>M)ع;{ Ç ׶Nhn/iz༩"LEqLr?XgH5fۿoڧH6ᯤUm*Gd=3 ;p茜@7ۋMOtjG )+9VoWU~۷*--t:.77Jĉ̙Ӱu~S_|kM_rJqo iyyYik3=~p!K/vn59Ko͟(ߴ|+c\.?-_&zF_ݍ9?j[m+o|ܸ9 [WՓe椝u\UCϮE?Eh$^mRD>#v78rg}ogeZ05/W%$?K' ;~9pȠ 6qSۉ)mJdff^puP(wPZݠABR|||:t ?7;"1y4Kǜ<Ϩu_ˆ@ ,__jn%"ctꍿ3eIO4e6_KNCŌE}eImi=+no|]%4P~ Ps%^|lr%Ê˲|w`ÔH|o X<""b3qYۓQxmǚl˚o3 a:۔̙3gΜw ,(3XROX_5۝+k|`}fO|lX^|w=0#B,]׾ewݺ9ڋws9ծmeDDT.c^"T 21 Fi|9XP7Voޟm>QM86k;Hub#, 1FsZ=g$`+1ۗ ]8k@PЍuB'Uj@gpT8lW=OkP8?/Po[Ne2?0Ew!|aÌMz[ⷮڬyH>Q:nKovqmb>P V><8n/>:& }~zoΏ8htWԵε3Q)7J-bwSȐp(Vt2c ];F,+1bMÖAJ={M`Uxc5Yvo*ĐsڦsװV*:4=4" #!dXMjR 3SNRbO ˒/eqY/Ԕ5;Pp,Ga _L(k˹ǔS^fV˻EoZAXecEehWv%[عb+Xkc6L Ǣ_!TΤӕrwFYIIEJN-gؼC2M#k>ORrq%f3DBH$l,!+3aA^!I2)Иؖ8‘H.tFV߽ t(XPMnd|,Xc+l^HU,F,e)[}tΈ9ڵ&nF=}R;9GbCXllC-S(XPM .N6y`-H>qb=$B.cʉD>jrHDf#l!H1$gꘓ{S9ٳ6!]z0s\^k !KO+nԥ)X TFTrt*FVqIYvvENHDGN` ]\Nȯ85ETLMDBX`ሸ)23ڜkɹM;)"\/W*%8>օՆ0r I\||o_H<-wT+RgA%K O%ClHXH"""V*dT*b8]S̎!"e9Fze2 #SˮU(G4}ݤN#8vyHAàw7 u:|Ծ򆕑1m4{{ƍ?%#p6EPs PC`/A-*hFFFdddAA޽{ݫ=nj$Ryq7*??߾}!!! `< 77 %`<`ʔ)%%%hWo`K,NQV=tP rWzzzzz:Y>c+Pxt5S5$w+Ck:s挧ӧvc9#r@M0,Z(X`Mzxk\wCX%,z(X`M8\.?UQ*^~*({֞5Qd*OrDjdX3\p ?F"$. [`b\g\θFos%?ۼEGk[9ض[|RlX{7TbҺL f`5UfU9NϼQ>ٿ–k߼mc?Z8#Rptɐ?VrI;2Ϫe[]4\I4uw][ˣ;O\/S9w{}>l藗3XP=p&" kW7[ iRØ=OhP)CeM[9aD$t{*? ؖq߻O*!]iRvRi(LfV.}aIO4e6_j(,j kDd2<˿|)nBHDdk奬5a)8AR""AoaiB53H h0VZ[''9WU!^G=l9C[WݣZl6HZ(X`M t:A&`-+~ܗ{3lM0cKF.m5 (`F|eB}jHT8,,,pk.\/xA^ hhDW-6-0M0OWxx锩_&zu'l^=J*^Pa  *ƽnQJ]MeeLJ$nZvbmFhW4> oi3Fd8_/gs:Ƶw=jPz` V,k4~6'ܴs^w{OecV}0k}ػ[,BHM_0W|[~wY1eeǘU- CZFՊb\w0Vv SDM_\Ņ xz惃Bc޽%ZkY{熼m .y]+^7oy PǤzxx>`r~~~| ,""|xXZZZRRRDDAC+4hP(\|9Al2X}z}D,YdɒBT7LB x}d2jNr:,+C2,+C26^ IDAT,+C2,+C2,+C2,+C2,+C2,+C2,+C2ʭ\رc|"ˆ? PPO?V(|gﲲZ- @P}!C6m$O[paÆ j5Y,:/xwѮjv5vXOOOaU nB9o,PMP v%%+/@]3z 6!C^>}׬Y# @])JU*Ujj*Y֭[]C(XuPppɓ'NfggvP:M@ XE9P)Eufj,3X5 ~`((Xu`J|;PYH0v_9~~a$a_ggFrYUhI4D0bYOݠ;E #$b}6:NR@g$a|5.+8{Ȝp򬎈+JOcܡ.blcadQ'xJ%),xV:x +OK6 F+?w2HDKqLB|gPj,xV"d|Y KDd}T섄o* ɽd#d)z"Imn( &4{I)c;pTMR{N/١RfԲj-w6aE[NmmcQmgl?%eGk/w(}x/{{6F}|6?rӟ]h_՞|VU|Fs:ݹH{9HsMo4dK޲M9ٚcw_zU@g'jN- ظgu$5K?{2b\ڻ ~S_m?cQ^!6c` fU_O{U's0[l|:k$ -*,?I l,}V!Y7r䃇.9oyowT H\X}_ٵkuޝ pG] 48x?HoZD]::4*-<`NȃCDdL{ ,1YJ>6i , 8W\Im̄nDDd=+irYѲDF WWhHr\{a h-1ƍu皜:n呑͚5; ܁,xS^B2'n|$lC(lrBVmqC??  g_}Ֆ-[ bRy7(J)cs\5bۇx \6Zv š OZD*"aMѩ9/+ΛLYOtWbPeqvmQ,v 9|' Г. p.݌_eSďVLb)?ٿW:sТl5Ï݀!r_?(-|F+Z%CE,WS_KRZVJ_hh\D(X|:tЫZTTԷo{M6͛7WT2h%jiCⰥ) }/;|ٽO[~ߌ2d.q3wsKrYv/Twé/5? :OJ9l/N}r t#k[UbyPmPxsʕ4kĉ|ǩ_@dSl&9#=Nu NrͬYd2޽{Ѯ<-kQ$t 3Vr;Wm3Xܽ{ 5jwEwּ1n ?qև8BOI(XHMMbP`𣰰ٙP%PJ%)J`Cբ`U(X uWApS[+= ^߇SKpk) JuQz줮Ev} %>F^EtocnjR혽~;"#^wŔۥԾ_V.r5{<2W^7eYhJggڽocgD!+!ٵMaTquqEi{hDh3AFBJ!舠a`^QQQQQ=<R'g{42砈n 3/]/`J_)3j`8\_X ^xEo^H3ˍ\a\EbRʞGg7smtVc;;h3bkgM=bcBݥ!@m" .N6g-H>qb=$B.cʉD>jrHDf#l!H!""Vƾi CDA{S7sjmӊuivP`@mňJ^S$Z%ef8! }:E<0%tvur9F#FZ#SK35 rU Y%#Dj2n9y7UМ{KSz;Ddc+f+/˕J 3@=#`,޾xM)ع;{ cΑNBՐ_riq[L^C&jqi73W~)7{\6f "= jT#*srt}-<_1i/ )^x }L*~N(XPGpLN}%:_t ?o"}̆3{k82Ğ3w }QI4uwdNbE3oO/6GDm<3s &|vLX7,jq_ʘJS]9CPGX.iMG5utGMghk{xflsG:%e:őy˗r8-DDvV^J 1rBDD$SHh049~qZP(ndedY*MUO  IWb/,qրYQp'Cuҹk.8㱖f]z,# /2Vo}n ;ڛ:D7w. nnzgcxDJ3Dqא]f!"2^XK>Wsơtz_Ν;wYPT!pJ' z8͎61-U I:wk+~ګ@ԠwTӏ {trG[FŦ1jظ7[:j;Uѵ+wSrҽ&o]YƑW f~wY1eeǘU-  \Dz6{pJFvVV i ꏯ^~6'ܴs^w}o{ʶ=G*ɬ9+J27TZy|F`*DDDё#GMS֬Y3qĬ,@}0G}4|[ٮW0aFf  P  P  P  P  P  P  D|M2`0L(^Ϗ,P`,iiiEEE-Z;K}듓fF; 2(X5HzzznݴZ۵kwzիvvvhW"==bjhWhWfyɒ%|gZ 3X5Uq]TNGDJ P%Pj5B@]صbbD y:~_-Y@g/%ÚUV%, V97fc|Ĥzxs5F`zSgν8[/KTcbKR V Ti]ęOfؼL杖xd_BF2aL d+Y".moy3MT2m7>?m!"6ceaMpW|;m;W{[|zl("ƣaeOC$ #uLDd:NsH:,I6٬kߌt˔M_Y|0{,{0ؽ}.GDmam^W|*Ug02!"2DTrèSkʸ>9iwZ!>8UP;^tb&ai֎ P.~M\|&.3Е`=K>:>B5LO]DD$h:+9렖+?k_HB];wMV VfaFziYLۡb(z9=(&`Hb)] 9^0ݛ7u(%ۄN;刱3Į>nܤe Iwf}~V^l$~m0,Ro̾mG|hG0.""ơQ dɺp!}ڢ.wW0#weYذjxyy{w*5#IRLnkг]I0B GWyŚF Ba0%æurIiic%Y.M⼼rrׯ_~S- WVZL7 }c׳Sw|[{,釷iWc.,FF2#۴% T/aT\jzh*+? qY T/L?~џߦn߭i8V IDAT矟}}F銋u:]iii`6m#F5{`UO[6NL΢l6?^ݿCD$`H'HLD2$tţGB8swYBuاmaÔ'헱?{Mٕ.y]~`{MZJDDl~""55K݃,"i56mݰW \foɓ'O6B:+yXq啙I8vBPEp26 {siG,?Es8 ` P  P  P  Yx%K=}`IJ5 \ biQp]btWԵε3'+.ށMB"C^rlBXY<:•?刈 {ZGf^SXXpzFtv[6e~""CVBuk]Z48R8ЈfB"d>"2222"E:Y/Ԕ5;0Նc90 [xYH+{!)dc/7rJc6tV˻VoZAXe#fh##2,WTT9ucѯPp&\&33bJJ*RujO<[DDi∈Y~r='w3DD/؅+1I$2D",f3gyxd4ZJN1=2'2U,DReLyY9\M.vl6s$6-$#DT"bnqe\%pA]]U`A5aJ\)NbjUlg_dD$p Sk]\DLe/M4p.JT-dEWO\(kޡuCN٦ #>qzR)A.,6!WH{BhJ\1(<8$u*O<,(]Zy*"gk3GRj/GGZx_>s 4if06CUyyyU=P`Auad*{|s@PTEOɻ}'n>Oaz?iSAVj\VyJNN4iRÆ ݟATF"9So!E0P^eիݺu3hܸqg 3XPD*!Tիf `< ## %`<`ʔ) ?ꫯNQ˲G;b(X'x*HU)L^MOOob hz ZOnrb$7Ρ3Cglt^zЙ?Ru%_0[c' +\rexx_`dhL7L&sҥh4:99݈5vP2Eԙ)uU QWu}T*9UJ%!ĵkbuV> stream xZYo~_x1yl0g,If^|E6==Zydu}ãXwF+%N }+.^+C#*nMOBK'~=~ݽ|%TMAXD^UIiD΂/3Ɋ}wqQnݐ`u~(OÆaaC/ |3 8o.U;OFf;IgPQc|J2Bc,Lc7`dz bu~v&gxY|%mÛӫ>9Z׳Cy'{4& %b=ng :Rt0*2 mmwT SxaD k<何5$tmZf %(du7H`;H S$mH&뀲bfe#B6s!hpT`v;[3! 7&bЪϦnvq};88qs}ԥ"Mؚ)TJ*%Mʟ%T=\uwQd"RT4.\ϲ~`#T?3_/޿I::S 8+QWTS %w0t72\rHs !8)Yhd]NZ:utR.i C>fk}z qiNO@6l^9D6غk*8!Rw2YΖ V84&PoYIQQk95rmʄnҔ\ 'ճ}efeƵ 7 e\őwqyfs@=X}r|TsGߐ'y4m4oX]|ݞ? 8I[SY7,ٰ6ٹx;+ `7̀t` J'p``6AC4Aۮ*qf0 8eS4 ÃJVQ·]Ik "j|ֹ`B<~`X)*PiiCMӨ͕ JX3`$W8 lPZ'NRx,ZyȧBҍggı8Ԉ >y`5P EGw߲$`MpXGy>&e.4KZ Qb#xvSk`(-xf4-Ҷ"%>i BM&dd.Q<::J ֣Pŕ0a5`?.J DDJ`)IM&f[$N܃%B ҴHc %h#Ba ].2Q|"嘜UjUWKt%(pr,H _0pRT+"93WgтV>p0GWl%,jl)fWs \4fEmFT*NV $?Nod^ #oG,LVSFoa3>G d +w5ؖ0QV}5\N*+a[%@%M%HDoF|Xmnt!͖tzB 9`*iW_t%I~>ʏU|/DB?K(9H?RoPRI0= &%^ݑӐ5|):wv?OaʨU%/R5PҨɕ-BpH+g6o虋5dt4AH!]YIf.\Vu1n2-<;`2@ctj\#JBюo'I}E&` Xϸck%8m^TD'OD *6 찶Ɏv\s}Tꡂ@T 5咊e 99-hcΪtEY&bP!h/ 糤+d߇e*DǔF֕䲀`4Rtk\I:e3#݌Vꖫ cK\r [&߃z bRENШm!q~ᴠ9Fo[R~lp5$ |+S/ڐu n~!s we~Vw <*.it.$KSf6b)]kT9;Y<8H]Q2poƧd3ΐ+s)-)8J-_z=u_(/zx] щr]67s|_\jCGZ=Q>E$\D,~GrIL\X! [HZJMtn9fz?0Kl endstream endobj 5 0 obj 2456 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-1-0 7 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 8 0 obj << /Length 9 0 R /Filter /FlateDecode /Length1 4308 >> stream xX[W?LS !`"!IJ*Q("5 +Vu]UuZ/,U),B*VKlՐIP;3޹;(aPN˝5?t#@7΅gz{r{-8NҦ :wjQEs\?8P3AwJrQ *iI:=#n$V)"n-cB5^(1E\ 8ux"1lۄ3h@en>:^h< GNDMmXi_>ڷ}i~ Bb"Xkͬ>%.jcB?5^x&1'.m?Ovefsr3#ٙ{6VMեKUWfE1CJNe 7zK58OVzи^-ʂڴ^ ߙeF3,Y\yT!o_ք#hz(1y8zY*Co?'*Ce]Њ}9\r5|z{^sN)]|,)m61]k4UȨO1)PI.zJg4ѩdFЂq[o?qbhh`wޥۊODɞ PrFkgP>AT@rZog B5[ξa_r-mYR Rtd$D#aܠAHu&y6ΆB?>ЮWX`wO~G4}9eaʔ?_T& u=G>aHWG0 !_J& ; M/F8\ EƠO؁U#wgy4`?;2åYTT8O췖y?aZ刡K6chx~|} 1D n/*ӄ?GQ+N KCo*~c{H#^^g]?U^r vskP<ojJ*Zv31/if v+[ղfi@ :v%_]tA_xuA]('%Y)9%~wgL+͞panڵCwejl<+8O?7}ZQx%gҜYf3e*wr [mrVU#15hp&ʋ'x݌fl4H$vOl$!kKKX*.L2܌aJo-IxuXLMb*-Xyq=G2鐕kN!Bˊ i&¾nPlen oJgX:]U7*U?SASW>Cz8vJNcKp;K&*E-eAa1`4`sC m6Z!;w<;nr_,Vo9Kg翻LwcNY|Veɪ'b>1I&xaxq r7|JY HȢ !X|5ʫ:c o*/cֺ|+Sqi ⅎ|tttlltȸȱchr }O 8 A'yL%Ed!Ogۭȓ/DfǺ# fl"Yrםnv1cEF45pA٬^~k7nwq4:aEౖKh \+U&=$3φ-}/ݰgH\ K?9.^v3"K)s⮢Owxd;_ H"!̗"@1 gDF Q7H/AR狡HJqލHH#x0|E߀/`ܯõ+!VDCCqHTԂPuzNT$| =DM⑊YH)J|Vr+# wgHOR6tQHx sٍ<\+r^Az"BF{>[@PQ endstream endobj 9 0 obj 3065 endobj 10 0 obj << /Length 11 0 R /Filter /FlateDecode >> stream x]SAn0<@H (ҋI}D5%/c$@6Ghv^?qt+-(\kG9Qfݟʿ?E~˖n{XF$IO7]^밾 gU9xynاmݔ#%e!Du4eޏҺ΋껩dCƮ.8/Xjl =S #;b> H ]LF+z j7`0)q?!+OnQ{-2yێ=$߀wxG˻ ]g֛ 1ߏyה!/3隣||TD endstream endobj 11 0 obj 416 endobj 12 0 obj << /Type /FontDescriptor /FontName /EAMCKN+Roboto-Medium /FontFamily (Roboto Medium) /Flags 32 /FontBBox [ -907 -270 2051 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 8 0 R >> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /EAMCKN+Roboto-Medium /FirstChar 32 /LastChar 125 /FontDescriptor 12 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 395 568 568 568 568 568 568 0 568 568 0 265 0 0 559 0 0 0 0 0 652 653 0 549 0 0 282 0 0 0 0 710 0 639 0 0 0 607 0 0 0 0 0 0 0 0 0 0 451 0 541 0 523 564 536 0 566 0 255 0 521 255 870 556 569 562 567 351 516 333 555 495 0 0 486 0 335 0 335 ] /ToUnicode 10 0 R >> endobj 13 0 obj << /Length 14 0 R /Filter /FlateDecode /Length1 3508 >> stream xWWTw{ˇ%F]\bIJ`5 *9 "Qb1jhƨ15nR{ Qc=ȇ5s7[1itݝf;`01?7kť >`-)Y8V#i r~b@kǨCŹEߧV7Wf O/H`0B0d30 M %fzm'2@5&^{wZ2 L7vb-e К~fMzCy"okZڜ*I/!3wv*.ԃHgኖUT5jU-,VWt2|#xʒ۫ͯt;{*p/w~&ύr_>^ؼ]N=Rɮ~:2]*sZ&ձ).v~,%yc#?la1hJNP:bp`;kxKX帲GkOw' ,$&@ E ;xܡ0Zw&m?zs[Z>ڽZ삪QUc'vF?" <ZqE}<>WC6yPU0a6t ?׻cgdY 9*^*^'.Y'Ab} haT-'xooo}AiɂYڎd;ހqjձcUjEmo\ 1HN<ɝ4Ky2>-mϺ8q>Za3crx]ä˪#69'x삡#k$3d;" -\Xݧ5,CJzc^ۤe ~l'AK\VP7jm!)3ťq},PH66y0m1xt&ImV ~6)wkn|yK{:xC&Fׅ/w.(aae֙✾s/`C8(J)hrJzw|M5o.߬\UT¬ڿ~?F;_ɫ-Xeyx&9l. (S@ڮXdyZW#1xvݭGs @1yBOt|#a<?IhFU޼qz %X~rZC2R8X(3qk`~,fnNTX=~i)j8_Og_LK;:UM}__~TQ jU:.ބb!k=¦W=O|XQ&[/u_|>y'V>Co/ҕ$]e6Z x&o5uwԋ$뉦qG"a;^^EX}?L|Ms^ݔ}|6z.?BkғgJNNߒ0>=t 2FЋŸU ~f #e{1 }foH{\Ɲ wgoߧ>܌??LnQ(DI>Jꥯ /j VEI2 }ׇ; wfwϾ{W8̿tE{p:ѐR7~K![rTm0 #RX*! \vY)|LeTvS~3ddEy# C> stream x]Mo0 9v@4 !M݅>n?C! WCObΰI7ya]р2yQNf 2,>s"Vfxnq' ['әSk?0d.NZph2aco|#)>Ld k _@yֹNΪKFg(Z41V0_qB.PSFn 1diG^qwď̏a&}5$ƀ}N bͬyfK֗ɬϯh~}5U#G7oȇ>MaVɟ545+/*}CWcǦEܾ8}#9]_~*~Az endstream endobj 16 0 obj 364 endobj 17 0 obj << /Type /FontDescriptor /FontName /KWHNPR+Roboto-Bold /FontFamily (Roboto) /Flags 32 /FontBBox [ -913 -270 2060 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 13 0 R >> endobj 7 0 obj << /Type /Font /Subtype /TrueType /BaseFont /KWHNPR+Roboto-Bold /FirstChar 32 /LastChar 121 /FontDescriptor 17 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 282 0 0 0 0 0 0 0 638 654 650 562 0 0 0 291 0 635 541 0 0 0 645 0 638 614 618 0 0 875 0 0 0 0 0 0 0 0 0 536 562 0 563 540 0 571 0 265 0 0 0 865 560 565 562 0 365 514 337 0 505 734 0 502 ] /ToUnicode 15 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 18 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154042+02'00) >> endobj 19 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 20 0000000000 65535 f 0000011134 00000 n 0000002699 00000 n 0000002571 00000 n 0000000015 00000 n 0000002548 00000 n 0000006892 00000 n 0000010679 00000 n 0000002917 00000 n 0000006076 00000 n 0000006099 00000 n 0000006594 00000 n 0000006617 00000 n 0000007379 00000 n 0000009922 00000 n 0000009946 00000 n 0000010389 00000 n 0000010412 00000 n 0000011199 00000 n 0000011316 00000 n trailer << /Size 20 /Root 19 0 R /Info 18 0 R >> startxref 11369 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0015_Component_Diagram.png000066400000000000000000001401501415120503000313350ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxw@U9Ne2!EU.r̴rdugK͙L35LH Pq.`On4sIdrG3OW x^S:l]TzMʭQ-]mE%^7JVRCİ,Û;u5.,0Ea=8"~lԀf}6L[z״ڷT:G8ћ#~[:3Nެ? < 7r[iiy&٩GYfkPdS}#Hlmq8D"!82"+xzSѥ{ҍbF~~*#J 7ec[^ipRƾ󰑽sJ x2)\)}^[ثArWǏmbL  O9o?f@[_,ǿN.S=V~6-_KOUM*NU#y;n!g}6J"k>XwnȆr:{~2%}>Cٕz:gS;V3N?"o@s5)ẬA/0.. +mYa|BheGg?Ʃx{jm9}2'FꮸHetkiu* [6~^i:_o5Q}|7g-;QVעF%f'D7iS.ODd<X~}&]@1Ӷ4bMs>|!7:}kϦ0ϻ2̏ϷFY&x錽+?z m2|?lgV{j _02|.?~ګw¶M=_{wZ+$[:i\؃93cvC;uzKHDF'2M$GZʫ5_WP4pd\**}o-Rq=t{R޴[׾5YR)jJy$Zŧ],>ʞ0;diJkMU C*[4unKT^2FHˣ5g/iئyݍ\C|iVTJ]}?gLz>'9*o?2@JD$3!"b%EL&"FaÔ&e=mw GΧg޺1Ҳ ͚KFnFzƝ8Jl_9 gllif{w.%fRkΞaVh)+{2,AoțP0,Cfn"qr{ZY=0a&"CfbuN޲ CDFǦn~jGZy':{h`Ől XkCWt*lʚJ~=nIy"i?l&O Cd2# dw0KS]~R+VR$.m5_\Iny.m^z>S}#S.de:+kQF> ѯCG%>/<+w$u!';_j۰ۃźwn&*ke;]K\z-+f~.p\|=>ɪW/՚g"E#/ʍ5ub .4 m׮]v-JOwœbCD< >/vX󀮎;{H2xrfvbQ>뱅GuDDS<]IIٳg-]D+!besaW]ոka?w_aT#:[u{0P^O92l؅^7 J]0F5bT{f6_mF,8an0lKVb13RFvH(fKi&mؓm҉3 /{sLJ~ɨsW׽oHܨqCoYfw+xȓ8x;~>_髍_p9/kݾ_0*3g^>ڰ6%0k%"}/걇?Ull?[oY*Ĕq=&>ה>]7>=ݓoP]Ω$"{w)&<򀥚 j>1ZлbQw^ TfO7mB'tPcTÞ8g-9tѭ?7ϻ++x%Bx!]%¼B%A4s̽{^z X:t`)Ppt/{﫯`)P888hUT{KVoނ! 0,!`  @`XC 0,!`  @`XC 0,!`  @`XC 0,!`  @`XC 0,!`  @`XC 0,!`  @`XC 0,!`  @`XC 0,!`  @`XC 0,,]@q#FX ;k___KW@MZm4ɓ'-]r͛׹sgKWΝ;-]{ 0Q͙3D 0ݳg'w3Lf2ST',a0"|L&۽{͛_Κ5 ꃀ |ooﲘe2dggAD.\0 ., @ 8::?>!!8wwwKO1՗MDDdL_0yeۤG&Fx1_&J0{O:~װzsˉ E tB^kUD"̙3gΜФI3gN0Ee`ܩ;ZJ69tDD)-y)&bTm 0,2D&ص'myhHNk0dȐ333 ѧOVîUoԤ3F"\G$x2餁'_p\srMFJ&nڔrbf9Anݺu֨(KUc|ڴct1)%'G4f""Cϛ|=%妉AA,zL*Ժw{xmnMd =?1'Szu;Gw~CtS|&2,ޡR&>p+?޲JMo2D|]XFd1#.E`{D8fލrG˨7r֬Yӽ{ݻٳҵ `7Lx87L:e$ƺefb%=j¿RndL^z܏DrP 0r[>on""2jn]e/[4xoFqLawe>RƜpD3dGwÓ1xgCÛMgڷ#oͤ.?9XJDOʨ$ɖ-[lҠA-[|w,`[t=9Fz>)H{@B)3ii8 پ<7!Kc_g4yɼyykr/{݅}Pyw0R0XkICԧf9GOPj򟣛d03hrN-.fdа&"2>~t%fI#_BӕĤ[&FњMܲ4g_;ѹX#=r+eW_}W_U(ݻwttccccjJa{ "jJͦJLJ|䯄EJ~w@҉3FZ5`牵%.5Y"(X1U`TGT6y5s;6cԺ!cĄK1-lbУY먖g>x?@y mKa.+IRo} vkX؝DOHb+b=ʘK%s>u'ٖ}w|+0|7oVshhhUH[WKWe(0]Ponϙcn<0OfeDkW;-).yd+:ghMsA~ MͥO .uFx˩G7~x>/+kt;}q\tŜ˵Q.%#aoJڎ7l_p5jʲa~6|׻vѮo{w9+s9υ#FX0,$C6S׭;n\CB9o`FxgM$j҆kRI]22$)'+L*T'/H %^-gKa5#H\x `,cPFk[t8WDmZ*˲q?O]lx`ppkgt  0,!`  @`XC 0,!`  @`XC 0,!`  @`XC 0,!`Ldⴴ4KWOҸqckkkKW5ĉd!!!j_|ѢE KWKJJO,]Xϗ6mtUäRK 0,!`  @`XC;XVlmѪ凳(eE2S7n8Y x E #i3IaV0,q˚K.߶xxdݹBF ƙ_ѮW);?vL95F/I{z/JP%cϞ_.R1_YZ-r}&&ސ>Idjֽӽϣ:6c-qjs)^@!yłfVqArFsl 9GOPj򟣛Vs3nGj4R<ޟk/m2bDdmqnH6ǴUDr+o/j牵%.5Y"(X⇫zFr쒉Ab'Ӣw]l=ٳT`h9k$Fq`_9?*ȑ/zZaDD:v3G QBAV$s ÊdzA,ҟ_N|厤kExsA^'Fxtm/*LW׮Ζ70,2DlzITr;sT@o&bՕ*{aN>XՖH?mHI&cz1Aok1Uت87 J)f$.{LK_.oswΑ֕[e۵)UJȬ*5ೝBq̷={eq:wZ3Mo({YJ&_1K>Vځ}TO1̆!ÁS֝+%75|'VS/ IDATլ9gg3cyƮu]+:#s=GPس]U|k^'cߢ7Ӹqs~t<oxpTtຶj;^ˀSlu}9^ex3cʏ2>8Cuqd9?hbVkg)AiD/7R*=^o\ t϶ٱ=dܐ]8x&%@C%;׌hc/5|L(&bb1CD$gϓzvWy:wOZ=Ab3r|ySq-LL+?xwMR>U DIDyvСmرsU1BCC;V2ܳv]מj/NYj4cG{ zo׮]:uڿHHHUsWP OS 0sD. L2nI=x@w+?I_`cצ<gv9c{yej_~eݺuv߿oa*@I 333-]ETXXh@I 6l0KWOMCMرC1\BDgϮS#@H$DP(JBPT>>>rAuC7 ;` $j6NWRRrX,n۶[o5p@D*gԩSNv̲=ڵ {L&SAAA^^FpBbbۇp-[xyyY@؃ $juÆ {=cƌ;vdggw177Bu@r;w믿]6}tK :Ŋ:ҵ@C&}),,ܿ *PMBCC(!!҅@C&u={ *P}A@QT@Q*X/,T*-]T9,cee VB> 'n\7Z 0Y"5M Q1w^(8@WV\9sғS/fJ'of Hu&1b^v l(enLX̽KJ$,0U4s۩jV(W5uf~.3%ѹE*ͩ a/0\V o+e oT1aRGgo/߲Ny7>Im|CD(]3ݤWE`N\ڕ>2s?vP̭uTS\Ɣɉx퍳g xڈDd4y&D p W34VwNbԜK8Yж~ٜ_qn@+TX#V*ZM)OPk66y:#"'4,?s!IT3ׯi8ȗdYsjw=Y y\֞*2,'R\`}<!37`8J\IM:7 (NN=/,Q:5 hdԍ'$M<,13Ց ė\;YO:ED"Vfa `sle~ꕵ(\#]v;(FOK>OnoqQ eHX,p,x0jLN9/.;x.l0Oe":Y:%+0Xds XϋO2Uԯ_%@̀puu1c`U߾C-*\{O۝i^tbHO;L 9{oǦ4F5 e2,'S5>qÙ҇`7{j8>kFl0`/g2!f]~_#GL%W8s GK3j^7ּVODVch~6e{MUi7o%\ߛ}6wOVmTew}Ռ.4 Z>\ a#M-(qǘZyܿj,p&DVL3d0t>5MyjdHؘ߲zX{5s{O\0|ѐ3K;op7>{!jLcDdJV"|uXϦv-[~6-_KOUMT-:g./L>oZƚ ͌U٤ZLm3X&IJԘ}+(U'{f:_o5Q}|v 6|[Ө 1# ~Ä]K5SߢE k9қMfCo6uڬT8βֱu}dWrpooMFXǔ6D:_ӫJ""M2Noݽk2ge<;˞Fݍ:'_7N{ g<|ͺh'K^=m 6c O qw_B Is:)2sau,O #})Imvp(g5M Qݹ0^Z9Lz1$V:y7sUpD3)sb_`cG)h _7-'"bwh@e\(*c$vjs|9eVf!&F,e)>:tS7f鉩'3m: tuWKL̰ vMSjOg};KcY[fEw֭_+,&Z۸q#ϰXּy͛c^^ĉCCCkĺ0Dd6-]ȋxuǴSVs:ۢFtbAޓ}5$@<<&*g69Ԭ9UmeL׻Q_| c{ܭ#C{Og_ª6`߾C-*\{O۝izM$S'knХY=\ּ8/b<6X6rHm-˔a9A@Δ>|H=T69YjVˎZ_㴉SmnhcQž#:A6φ;b7+\2=}4\"6}ms O{f+bFyݙџ?4p LM7zܴI9ܣ¡k=p\yUw!>:Tch~6e{M &IY$ U`PEOv*7gDD[v 7rNN[b&<*@TKy-q䒍߽t3Gx5`LߍwZYWyGYi;o1,}{ӽͻo7^EwΑ&NG߸ ~cLC"l) UP̦eelR[KjPU`0U0D$S  ֎_@ K:.R\gTٌZBAoxϸvnorshΥ/Ru/⡖=qQODym%bWljgmE[PfjR*DoB^hM2'Ιk?cCONA*P:g./L>oZm;Br巳bL*6]z)uYnٶ K +e矌ٷ̌R|f:_o5Q}|v 6|[Ө 1# ~ÄCKe)((t!/4qȐa2mI}AsƾtY_75 ƨ%B^E~0,"6j#sDTń_ fs~}xf]F%6lIs.׮*2Ƶ,7巻8ZsD-?X~i? UCҜ>sʾfdn\EX9Q.,gyU޶dKI:glCDSb""ww .Xȵ˴߻L{ͦ{k?(pK}_@Ua2_Mөl/s'܆-^3m'kSںMu^)}ѹ=#]Yb:v#P|~>qP?B5`+2ARn| t'_U}0܃UVf-]TauZϋ 5-R-𿟶vn<É/^~[.裝'zME F*rz~Z)cυ=JBqgMVDT^vvvETbX$i>Tڼy3g8Eڧ 8[o-18ڣC]<x$n"DDåv^TSo?}MrȚE)^T7% bW[e72l؅^7 J]0F5bT{Cv֌6nw~5M:u)F.2T5ݻ ̙rJKPS6\7!J|`ɔIi-۱ ߼._wy?Z/3íxCiQaaT۾9mҏ'ޡ ~Hţ/6~­ݵ͛< ԫWoѫVZxkVL٢Vdd$ZgӦM{>tP6mhzƾ}nٲ]vn߾}-]lfoƴ_{lY۪L)}^&o|{vA}?~yuOSU)B Q(-[d4WW׌ A"hӦM+V5k;CDJUT* RV-]#@JVVVd2RT*U*'~ y*FthtGwXU(>>~y[js\;;;A :tȐ!)))iiiׯ_h4yyy/_%%%xd!fO;W^ΝGhjItO<-Zh1lذ1c̝;ŋB tѨQ ̷~U}Dl]YI[.x͚cˆ5Tˤ ^_nz|5?uòV&qt<SEMLy/Z&U{EMzlounns91cY۰Y _|A:u˸?M!`=EImmmw4mڴ{s-,,۷o SZ8N:.\`Ycƌ!qYĜk֪[sV0 VzIh{ Lll*XƳ_be9P߱{ ˂ lT;{w@_q ێf;퀵̲WbwnsO?/V%;v0 Uq* IDATӳgcǎY˗/d &XPF0LJJ yv7?P6iM%$Cy9lI"_6߹F}K`\#NxA-7QV򵟳 )ĜۈX|li7K[MؼYO`165ȹI%<s ?MUmjŋ{xx_e˖5"""&&"g*[[[/Y҅<;QC# 8ukެ4%ј<#XP(_02dܺ9Wy۶<ͬ8%霑R CDJebOϓ2_]ŒT}ˉxc*}^h֭PןץK,[T[[ێ;ܹ҅N2{`ϓ^ { D4ӿMEv69*6o&GoՍ'8XLD]Xĉ.sssKKK-]/44ҥK.#i+KY[qmOL>N܅&ڵk׮T(3>wֽi%̚{U0's:[\0|ƮqWQw傚qY\z-]) "***單Vϳg[gtY=뷓ׇ>h!4blĚkD_ofJ^tfPlܠr:4p*S!$ C$~ӻLccw7Yd~{9/6b)<*Y̚5룏>*--ddS|}}-[ ٳ>>>k׮߿kQ9i {V%"+"*eo2,]l[TQAACCz&8KWAtc..@Ѳe˿ XݻwO,YT6?'`,Kw?5`5j/\d蒒"ںu;udFYX}Rŵ]-I&7NEVކ曤h4D6wWKH~rysytvv^hxIXXXxxɓ' $ΝܴiI&ikkӝ:uZh,~kԋbJz5&p/g%mcorOgc?S'nXp{75x<ĘEhlRA4H`|TK,yeTT""22rС>>>nnn? Tm۶vƃj] W^뽹Rm#%~:?$} Q9X}/ԤN1+].sι}80&&.y֭ ={v`` Q|A_~̙3WX3y争ߚ1C8.~. N%xky`-ڹv5no9bЉE zs'*A zL(**ڵkȑ#߳Q([?>44GZhhhBBB 3LL+TÖ |Yb[Ɥ}g z,8;죞њd0rݯm~{h?~x LLL.]dmmGϟ?/_|Ȑ!AAA%XT//S#*BHBŬ!:h Qnr1Ed|,rU|\R恃/HkC+(6ﺭv1 ,>LkO-((8p`Eرzz̽m۶e0 .ܻwo]/ԩS)))e߿?gT*媨pAJ^ZMRϒy`(Txw=Oͽ* 5{P:``:::o|ݑ#G ;;1I"ׯ>}z;t萔ԤIjy2nZ򥷷7&X۸qcʏ1SƤ_~bD? 8roqBF♝ĥdyP ՞]"^~P4fG>^m+iӧׯ_>00pʕ%cƌT;X\d=/[TTdmm Q6{QN G BW8;wffMƃτl .h[[[ l/.]jll\j?~lkk{աCV7&M<{8_ï.P!jecftMW9qCOJņU5¹+"n9M[q~Uo+UTT*yFSUUOAAU8&&*lbbRH$y+PeSL8?tjg:jǟ=p2]=h=pm;/a=މg#R}||ϟZi\ooo.[X}9995  _>“=OvUO~uy)֋ǭ/ TE=HT@(8hj&4s,'3$9.o(mdh~L`t'g]7ZyFm߾-[5i$BY(mOIxT r?~7a6fFj/@rN:#8N%VF8&Ho+HgW2gB(D FU&P#C'rG6{p{zU02.9e~Tʭ5Fl}j,f5{~M2eѱׯnݺǏի{ AdggW5@P# oT6kwwԓ9" 3w1ή>ײe^ ıP-#sމїJ )󏾍bq@@@@@@ff˗/k1fT~vSnf3@70wݤ_ZeGm^L* E$˽3;2 7tV.^[_Qj>w[~G_~9sAMeRM|?iF:T7k?q\ǑAhv>S/;zV'sZ;>ъ3,sQdRXW;le:C(⪌c]3c#+0݅r %%zK Hn﨨iӦՓ#Q@wZp䥆nQrٳg_r%99YAAu֎2s*:sٳ=V7BΕ0{ vPЌVL(V#B"б܍=SvJHm!K6i }/&&&~beeլY8bf@II~UQwK(j?]EmoF27jwx"$9=(3}V\oYto"a; om=&ZΝ AR IfяKtxoVMv*Iq|gK-EKhD,e}E1VtB9oJ3b8pzɓWRCUoL wH$7o.qҥկXlu[=focC*(**h%FVSJh *<$Ÿ}5( SUU)S,QG]Cb| Eu6L+`Wik41ylĪvUX.WsSvQVV.vĊ5DwmMq<>f!y{\BidO=^¹AvK%kseAY;5)> /=BA#IX\X,BK<ﳅmK.C.a)l% Tv+K1{.w֬ gZltpD#IYcK&)e)@Ӛ+QzU5sԢ>5 jD5.fbไLHo4܀~QN. sۭ}Y-Dm-~*Լڪ⿉\8Vd(p[p:⩡H۴L@P\}~($IRu~ɄYRp埪KhO7\L0͒Ao>c ּ['|z[jpX\CiBg'8rيzmG/UQ/-<HP,6A-31Ĵ{'o<<0l\;N˷ liDߎ"Z9~Wɀ[ KNYi)osO T?heJs\ tp2|12~EvVUGucFf[΍:tl$B5-XrG5mЉ{s% _I>L{vŬ.:hʰaߝvVd%%?>./Hه"/ :k|Ӫ_q]LItm4Balĉ7<ͤzɜw2Qc+$2먇 Ut 2U>W+>?2zB'^oʡpzl@$e+<`A60U8AT]Ř*L|Zsp`{F682S}noO IDATL!iJ ZegIOeHsLО͓ӎ[ 6 ڇߓjSTd)J7C5j:abrSǎ;vt`rMB{gv1Tǁ}u(2.K/ -7Oc}Pѳ8*x8d/mݬj֢=*ήHAO zuP2iפDH?^OOOQީe[RV 6BQ+hm>?wφA(X]rVoc҉FE/7uQPێ^גQm5fH$Iɗ X+Nuh\Q$)MByL I)o#A7hb[\Kko12V2'pvx<(q}{:lZq)TIQde'MChaF냒66zt/zFQM]PέdO<품c ^yDŽm.M;~,[.n/PY\ 7}Jec·h:Oڊ[% ;ս* zuF=rJ(:hC w (Z76.Tܰ=T|ѣhֳ@H$Y hNSX;xriXZioL]"BleN=?B;m|+(32e;-9 -S`YkӨBՆ j455 (M{\T'+tC&X!۸QvB8BȶYӧW!5Lj(+e!T;=>\mλ+W7B1&BBBB!/|V !BaB!T0B!e`!B2LPC2{lyGB 5d߿t钼@!`Uι!B&X5}!yGBz ,BZ B!P- !Ba2MMMyGBŞQCqFyB1p8!B`DHHC@!TD9^|ZyO/^u, {? B!Cdv$cN͕eYdwrwoK6Afғ7_ tY+JT|U [[h0 [@͇_u]-U QvI $L}+[k֣Dn'KU싪ςBq54ت֖z UlMvt`,.92u[Ұkf[@EݳWv]iO3%2/+w !!RB $_?guT%R=|EQa H}5PY:z[GUjۢ!Ȃ?*i zg(T* %_W`!B?@ ssXl6-/^dq,2|y4! @qbH :V:dH4Ѩ Hq-"jV+1D?M0Zfrs> Ce``y2wV`yٹD=%A0\wdBJ,$o}*"HL,ҷ7`ekQ-'5l- HG2kQ1X!KB跧okKM)Z$/o_Q^b6I0,HާJH$"D"1h47\(,|)OrDtb}mŢl> dyZvvM1&֮]+@ByE$T2"CbFEɵT UCW7Vڴ/stthKYcZF֧rsV-tnKW51 @f@',*ⱹ\O`Dtt BU+/cbbҹs纉 { snEՕҍT&S5kcW$! cmg%TMZ>=jTD-d$L*AЙL0ʋ!aٚ7%`zU_aB=zs5:%XKY%CҮtRS{צ?zYWMw1|EˮGmG9Lz1),BuJIIٳguuuXPmng,-YOfrc8h B:E~E{iDS6jYVeXw 2LSS@Q jtBaƍF "ebq VMp\yGBrЯ_AAA"ĉ'Nɣ $_`Ć 6l (BNd%ϟq%(J˖-~@C@0B!T%?YɧOv_aK?] >>f_y(@Q8<)j :WV[ByDJJ D%Ix.VsW3iC0͒Ao>c ּ['|z[jpX\CiBg'8rيzmG/"z:t\j#:+;~_`U[aaaffA1̔}/%ݸiAg;~Dߓ_Iew=t?cS1V*%-_VItӁ[)^L d;Y\}{|HK&dVqZ<ёɰ_ =hI[=.פ} *rs6\&CQۂ3o&h<# fsCjÏ|̸ݡ*j7e\03B2?tWc6G%ӻiF3o +t 'u6Uc,NvNbaL:M(SVaUm/_cccy~LSS$$,f}8T}AS ,rPo%#,)qIE|AZ>aЉ]VOŤI5tJr&J>wj]{N=j\$WyNPt'c8NיKf>r_PyS"yXڋvsalC'X E@BgY *Q,N:6cVLvH_@RrdTAjϑ[&K?~W"hАI_/Ȭ}'}g9%(lݓ=jY8BՅc… A8;;;c7nw dRW8@JS&EBQII|~ƫ P@pXUlC3i@ ܼ\E(MvG,J= i Ϲ3c&:p(Zp*; b;mF2뙜4tY^&mzڇR~n0(0{L h5cWYGiۻOj+Ӥ{' ? Dn+s 6˅ٷ<l2vj&z[y 5 Xtz޽uuujԨMRϒy`Wľ+",f```eeխ[7---jPVVoTUPOo#)djY=fP=8 f]3c#+0݅r %%@ RV z)s\:470cG^i]F G۳ljhJ{hxUwOv&)Ӧ }'}ਐxA.kaL^t*ᘹC?w:"nGg80NC!WͧNʎtXϕ&Gnlӟ1N۞G&ƴKߋIeHQ#D$I......$B1X+yKXqjTYтo[$w7d΢3U9#!I$ s4Pd_y2DZB$Ixth>i9j4+Z _aGλ# I_Aan~'&ɼGaޭu8tN?MȢy&^gy;wս.FGJ6Pԭ\4͙ ?qb,MO{5q?_?S+,"HK2ԡ@ck^;g=d6]!;uTDDѣGoٲ[ϖ*t/zM5~0W,qmwgVtZ07)LPCcǎ۷b4B [hKܵpS׆$?$B&X!r m6k^;@4{ٿviE i4x{{O:UQ_HSS>~(@BI,=F݂gjj*(/dnn/^hժc_x<۷SSS\n۶mj( ` ju p8BJJJegg'%ɞK"tmM6߿7o8HQ,&?otznN8KZzOnnndȐ!~~~]txbrrG/_~֭m&$$+`haƞ`o֬Y-Zhl I7n(W~'O>ȑ#gϞ5553fQƈP1SSS\E5_&X5R؂- X&X5R؂-\5:Lj233Be" ͛75`!xYXX$&&;J.B4i!qwwx ,޼y#BEF`=z(--MQ $7[^pmڵkggggll!Pc]h Bhʕ.\8x𠃃yDž5ywfϦ(yJ_>Ādk3#@______gΜ)ߨPc&"1X跆-X322Սw 7"zgA x,}a ӏrs6ձx IDAT\&CQۂ3o&h<# fsvNbaL:M(Ab-t "TVC ͵V3~c̸ݡ*j7]yrz,j~mLf,NJ+GLr5Ucm^鍸(ߊN3qC?B!(T]EeRb5ҬY3.iflå42#b_$K{n>l3gmydVoiSJ! f1D_8qоی X13!}nWP51 .BjrrJcrn :9in ڏhfJ&Wvj{NMIч;Glfٯ*@: :qx ƊPU(8/'VA ~4tY^&)[cJmfc62(3WW .!4M:%mb*H,>L ,WXfs/X۞ !f 9h#jfPҨ[ܢE yG~[[.](D`g.Y9;xK=Y}1Euς m:{aEGCo7U >ȝŀv\KٰwPAϑ8i#}H'#6[yNస"U*# @ҞApRgS56Kͬҫg'8rيzmG/*+6(κG2E-)}o8fkQ&Q!mXK+4U~H!!3kZfp Go⊆nP(La]K5Nec_{ .\KL6(o݁y ㏰GN 6{jo!hٸ БM㩗wvu㭢(S*F1s8Ù}ӿзoСïUWJRRRzf͚ջwo{{u%0xutTݕkɒ%W\a1ׁCҽ{(yGQm˖-:l TjݧMV6oJ P=zLZ+4ng4K__`̝;W^,'N\z><4u뎶w^_ F˖-[y\<*d+b&`cic CfK`;eR1![!.(NnU>}z,=z( "5jKxEm۶֭}88X*nݺJ5.,/ᅬH$Ř&44[l9i$==JXP\\,H`o8p܇p_J\r%>>ҥKD7X[[{yy988T>88xٲeo:M64hѢE]I陟_I-ZiӦ܇Jӭ;wݻuU\\B {oݺ5..`{{{mW5NR >>$dV~[xq3g$_~ v3f̘1c^?KWWNLL.xj4`iRϬzֆ?/7<]uߏf행V`?-=`Em9np<\ gW={I&)))BP*޿n ^fJPo>"JMM _m۶mV򳭭vWV+LpKLQy+wIf.Tf#Nf`Xz[}ѷ~hѢ |5Z_*N\;rbw|7's9 9{LzZQqxMM٦\!$"EܲndO-`|BpҥD|rssCCÚY5u*Nuթ[[f̓흿^['hڌ'e"++'::ziiiw:u]u}G^Nz}+LUk+0 0 ˊ[[},IQ^a"cfv5N  ֞k֬+Vt0 7dmkۇfc#;?uKTFUCCC'OLDK, vQytw^P\\q7к;ws)2eF}W9ͰY9ִ۲]H""ZiӦM6&%%mڴi׮]o䕁54;U=p}f cA~e^bQG3Luy̞i=\u?}[IDTtmkP{[^Qx޽'DF\nÇ={v߭jfcj? XV]y`ðeWO7C5׫ ju`````ÇO*i{k9*w.>Ndk},Ι3'00ٳ-v?WL"--/,\IUrl:F7nH޽{CT޺uM8{j\xﳻnl0 KG8落SnUxa{39}rEqOTd=L/((زeK`` `fժUbxÆ wy՜j#Ar %*t{vrΠ)T{63숐qq\aaaV&Oj_ È h"4hMq tdrD1"/*Ivvg]7J9w X\Ǥ'cvSnkXrbLP*ѭi)jR'.kW~sc_(“ofԔ XcRIDp|W]$zoؕ͏I,u{tK^'SW|} GO*֘iN<;w^q_vM.W]/E𝧘a$^S7|QkCЮ?;CQ+S>VfrI˶+{G`ШȞv".+3V.\pBݽ8;Ϛ}t6F2?^JjDB_\[;<.˰~[8"C Vv uU;qbyW2bbb./FqĚntmڑ7G|rN*.dbI0Lc9#j9xPSAIO6vv2Q>3 wu1Dk9F~ӽ넟^KUJ\VbĶ{+)Dt䴰t [Õ+Y]7pGJ.=fW8|4 aF8pB_Jj$wF"2\\QZ-lP*ǔԢewWͅ;{' ?J+z}wCJFnOV+';K=pN*}DypZKQbȐc湗F46O]ϑNs,&KOۍnٟSwQnD7nQY1bUrumΪ%q%ޖS skKw~U#W?7ܧoݠA"JLLlժUOyfVvQQϹjZ.ݹs'&&fÆ GtRuo)3.0]AAAI,!+'?W0tJDDIMWlȦm4 ee{5yU=RQJ/hAi F`;L;:BljyrݝLR{9oCcؤ]'Pl/5ks-n:uX/ұM{qѳxΏgWoդ&Hؼvz) ]%k wwYr:|*vy!nzn'h7Ke_1hߠSgg3:u5"R9zh+fii/ 4/^\pau>|gϞսʔ)S֯_Bg غukUz`ªtr\LcGg ;ѐ U2ܫKqٷtgHs+:^}`{RyݻҖ];B"tcH!ppkf[ 6 D) MmL 3SA*9F^,Qõur2w ,11k`N}wg-IDAT^Ҩ)I<,Σwazd[ȈCXU22Kѳkk{#)'+#'IԪ_Fs I"H__Uy ɼec#59lpJʘ {Vft: gڱƦF,hrrAL5GI} C`dMfz,"֨OCq+ vpyiiE<Ӵs=5v,A񋃶^? /MbK-n?2CsHfE,O8q/lddd 6>n͚5#W(IOOo޼y=`ze~%KD_ʻ5JK*ԏhQ=K3v+/jţo++qT@ĐBim_| _vVsd:> 9;mҠj({+4xHvoNO r=*(F*9"^wsn|[GZ'˥ɩ9"Vw! =#dIérN¿M o01j@})Ţwܻ'$5˫7[˰>,P(8ưې^M]\Ε319*sL l2!d]H.?l⻿@MFe&& k3b .܂qkUuǐ7}S{+a5zQuan;,*g'G_2UNS ""ޖ=CD3.>yHlRŭn8Pm|s9 ^5""I_5Utv!˲-�MMMmmmիQc|%X~鵼d’Tsry%K(χ. MnWNy?k[Zi.|Ŀ ||]Rw1\ѱk +9ꛫ7722Y7jYbn%=7#gk[ {.<&Rg] ?{_CVsd{o'3ekDq2h2.ba9G+pO{X~\х^V?3ML j#"cc'!CʨF _0>6jD/ز#8ǠߴcyoHxVG#Fuggi=3+ز`S+e%[j\-~|{N{W)??VڴiSTTkimm}dZ'pqcǎ577]@@K<:8hFd3h=5q\i-d #511D~տۈS"9Lb"2(\q84ʔ%|8N;]D$tq4!C,]9؜4iG" K?%9Kإ_]M # ŏVqlGGF Օ""ה_WJ%ZΏS,n'<ڵ+}ִ^uڅ_nmg#yCeCۅ>6ay0{Y)z[~Wsa wKHc N8b]-$bSvC[,mM,]$FF~LTirvNio" efޣVLQ>}z ߼::MeMSu*`V%F"ظj׷K6lhbbRIU X\qM.23q/a:&-{|"NQy JHݺ^v$uљǀ ԭL$3k7s"" 㸂k'vq1u2}4cx͔uW=BcAs'q%_ԳX(ַr6g4=@cFQgoMf{4F}[|{ŎoL~1UY98ﬢ+Hװ,9}Rc|گCDLmTZXugSZq V`xJ5 "R* 4jnĭU3*! N|vHhJ5vB 켽ʛ TUnƥG hgo,w|N1yEN}5tA9/WQYo(qHͿ;0è#".'fn zΝF,=&"MZ_ ÈZ|`]tYےUOKnډ4Ksűzr͊u={ز< S"QqnV$I:;, c`hP_3uzN=Y_sVoԀnc~6vډ^ö2165w-&$E޾=RJuĈ_1|Bfp*)_-lػG, "eѓ㨪j'Zpj `1Vw^n|ӂM 4j Ө5\uxw-_Io^=:C ׌ӪSY6/^Yu #"b͆n8ym.~a) aC~jOܲcGC+-?X~sFdQQiٙŮ[g{,>>]w1G/ߣIޯcF;B+;jAW8q͸:Hc_͈^'g ,LCV `T7~V*YeIό;uU4cc}hOK ۰t\M{D蚙;F<,Σwazd[ȈCX ?ah"D\~? ~󞘈H^zHʉc j׷jtPT7/ۜhkvPCj!B x3,!`  gX8yv\f,k*Эܥxu[eײC}I+1:4Ͼmcw1.OS2 ]z 1B+JeCʅDKfrX6̤P}Tw(4oWo[Z43àj4sI 2TX/Fd@mi8bFyJ|rGɻwdG\K-2AZ99 :F s,!X%ՑfN-t LjRCİ,ij%xTC:61בHBV 0Tu\Id776umP^߽wbnrelr\bgR3W+%P][Ë SIe2K&$d4iX?=b&-Jڴi".s2sCDȬxXq* H(Z/.!R^::hagcDDʸR\THdҢbNW u'q5XܠUsc0g"ROWc.^4hϒsֿ9r%'zХ2+9rTֳ*ǥ%/F쳤hKGçB./;1k@_$L.&.:9r%BF$a%u,[;;fIt"alLk{+ 16vLJxK፩ 4p`}vEc# &#;XLܳ߀(ˋ "{##"!9٥s3&z?%Hm=}ˤLQa?q=ϤPH*#J&P^\BHLJBFzLA!G:*f|^ KB.7nEˎ6XMZT ,HϬ HAU^6O nX}@&.tr g)8.}xDz09VVBFjh$ y֣a#i9K4Y7"/:׼QJF)qQNTXPeblQZT[ =Z;J utE aPe5y2!X  jeH=]32SCQBDGYDRY˂N'hVM[:0DƎb/L۶p2f)ĤQ kNK:.:TxBw-" \k:L6kqJ#3sw11e_*CZIoZnYDeO9q~~̥..a$myбCOzQHjnh{Pֽ3 TuZ Fr^ Cڀ1nڃtEZr rhW0W5ىѱo}%m^\^!`A 4ka"Xv 0OP=XUՁU䤦j xQNNKxE* #vRpgV2p@moK.YXXh (_׮]]«HLL433vDmA-֭[*2.z&Lзo_mWv b.@-,--Ǎ*ҫW/moWWh KRXP%ƽ{vu 3,!`  gX> stream xWn7}߯px\ j%' {%V*"̜U3Sz(?[qr#<6 LJ'w;M@\Ha}9oIF;,_HEd4J4 f/^w_;CsnE7Ӫ}qx`Ml]woz-0i-qG}w%TiO84d҉@8BPsh0t7e~mȵjUjv>#+ACyr֊~[V51Jkm8tQ 6e`-|Et)Ґ2u{&#jc>6C* d00UH$Â*y[|:+#xlk5Q'ɏMed#Na:NZn85vItD8D FxC>sYGc*.wr8='/?_拿r\ 3y⼉KwNvc7w;Ւ=^kS/@+/K2 ml}8FeD޲Tf#ܣWSI`_@95hiSvٿ4}.zf><ʺdaCa>T34f/ηQ=Eb{8Dқ:d7VC:UČh%:d#b9x!W!QZKY㿿;6fN ۜuLKsQn4ˈGuGvd"VwAߧ2`|[zƽ\ 5;g2 UTkBj\G2kwM}<;g~>%yZ! 9'dЇ/Py-sUE(#eVFQdZmH:eF 2mp<OK=aidLL;}|EMG}I>D*?ǿ{KcRCdUɳ 2 VČ ҁ*ȴCuYg ?/cX$~> >> /Font << /f-0-0 6 0 R /f-1-0 7 0 R /f-1-1 8 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 9 0 obj << /Length 10 0 R /Filter /FlateDecode /Length1 3160 >> stream xW WT>{g0 q 00Bk<yeP:m0jJZKV5` S*(*di%2*pgԬ4?w^%yPuVpB}BMʲg)>{,źyid6Bܽ."+,e- V,gX9,gxHG$D"#Z"L<!FN5 T hvWF >` 2D ><QkFEMzO}Ƽ [SRfeu=h<1JJ.g#æԭwxy3'}QWǴgj~q :~ _j23QKb*r<9ىϭɊuxF,_9#6f%BcTA cs8~ ? G9U)HTc5x6St4 `A5= l_^iV=+o}7pu9nHsXQJ`v>`bSmyU>S/؅o<άXꓲ 3ը%*7ѩ0\a3 M}sgQ81sFli59 EΕviŗkHB11܀:ȘH[=e+z; N#pN0bdI|&dS=)JpS争pIUrJWet* ӷ,bO7s|šhsoh)XؤK->i<~0 }E?ҍ?puk!3WRGRP@긥^x9 g,?%2,j;٥5)/ޟq<xk]GF~lHv,L}!g mYω5zLNtI?Ԏrt gIY9qx a4ޫw+7PcYەwX {}Xp_ X!|4`3 4aip`Q;펃g{@s3y[m`Ona_6\rP7&o9ܵj0~u*.>x!*,\M<'+s3k0)LY#t%ծn;N b$ 2g q@oie] 9tA|v?MtgW'uq~#RmK %׿}p 8w1?/ӭoQ74Rkr^=e#oo%ϱjs^,/o)ohii(>R{XnuH!Zی6|ruT@ŃtoBJI i`ekZ6Dk9; R߮?}ߎ_=N)?^ߙ%*ܻ/@"]fB+m*|뷛(4'|2Ѣ$p4VxWѣz%+ꆒ;ת endstream endobj 10 0 obj 2202 endobj 11 0 obj << /Length 12 0 R /Filter /FlateDecode >> stream x]n0 yCV !M݅hlF=㪓v|IsU'a6-z `Px:dڎfLW ۲ԸaVU\ְݓ{|PZ-X ׹T{'tNU]kٽtP'xXmOeͣ -;sTUֺZ\J|wAUG)UA{ឹ.GL|2Hs͉"S_j k@A }D_>sO>A!Y~x)J}F'>8v*~4 endstream endobj 12 0 obj 336 endobj 13 0 obj << /Type /FontDescriptor /FontName /POSHGP+Roboto-Medium /FontFamily (Roboto Medium) /Flags 32 /FontBBox [ -907 -270 2051 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 9 0 R >> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /POSHGP+Roboto-Medium /FirstChar 32 /LastChar 125 /FontDescriptor 13 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 568 568 0 568 568 568 568 568 568 0 0 0 0 559 0 0 0 0 0 652 653 0 0 0 0 0 0 0 0 0 0 0 639 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 541 0 523 564 536 0 566 0 255 0 521 0 870 0 0 0 0 351 0 0 0 0 0 0 0 0 335 0 335 ] /ToUnicode 11 0 R >> endobj 14 0 obj << /Length 15 0 R /Filter /FlateDecode /Length1 3008 >> stream xVS?{ K4>{g/PD  j\ $6;t5U:A|錂j=0?;9zHss(3//;%VЊjZE9^t\4wԯ~TA\3_~AQIn@E9K!c @x]jt `7F&Q2 5)!P0I fH+,[V%VdlR$S2ʂ,ɂf&S^;X{U l8%|/N'^# hCpcBMplq9۵?aP@g~mõ4;'r7 yRaZӆ/X@XM:LouMp.ϥ{z AfSjIxvjlI33''df~,zT}BMZqeh03D6բ# <ƕާOz>e g6JV6ѷCbKNWYyBՙAR_#`$l֩:9I?;j1>U T믡|fOx_Mʃ|syْ4[[头9[t$w[6x~rtcTW2dd[$ |FSed%0 mt~^<*X!ۂQrђ@ Aœ9@S !ZUU.ZTBMtRTуhZw:S͉.CH:Ē~֐Sd#q%*caWy[cwtv 'G*TnHy=+~6]|_kJtKբ]1xb(=}{mYik}SYfᶪKQre`25hXRبEۢ({H1a&٢lNYP^Y~ vvco-,/x?[]☽5KpՏNHx-i^yn[ F<+yiBp}pjQD̈́FN/;m6ѺGwxC%=xS#)m. :G4Ժs;3Č3[?~GQs&(zcDy;wFNsMnKݼuj@f)Gs滋gb*TJ]._q/G1kx0#b5 :>lq΄[9?ٰ=W'OV7P[ΤVy4BV#M. w -Ǜoo/&~BEj_SC%'Ey֔R*kT禹dzuZ͍&$E}DQ6j~Ž5]qS.[癸]Y UmO߇WχqwnCsx /[TVaeҞƂ^yE^0QGt`L{m&jxQ`>KKO}78 ӆVGO+WBh?_/D'{wTW< [+傟X%l8V,D10 z(; Y )!HL%iT6 6J-A*mj[urdImG`teMD6nB%tPE5x5:KKv::rjZz֬ 2[mb endstream endobj 15 0 obj 2074 endobj 16 0 obj << /Length 17 0 R /Filter /FlateDecode >> stream x]n0 y Ca4F! /NNK GՀ+tepƋuPjF/(eũwfm g\\ְYg| O?8[!]M{8!dIu\붏#-YGatmw tZQlu X1 Z%!H\2ĬVVRp#3F.ؿ %ik5:rU8_q\s}C{s=7sڒ2 ɇjh|C0FJKBJ$͈c>= $ endstream endobj 17 0 obj 340 endobj 18 0 obj << /Type /FontDescriptor /FontName /VMIHGR+Roboto-Bold /FontFamily (Roboto) /Flags 32 /FontBBox [ -913 -270 2060 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 14 0 R >> endobj 7 0 obj << /Type /Font /Subtype /TrueType /BaseFont /VMIHGR+Roboto-Bold /FirstChar 32 /LastChar 121 /FontDescriptor 18 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 573 573 0 0 0 0 0 0 0 0 0 0 0 0 0 0 673 0 0 0 0 0 0 0 291 0 0 541 0 0 0 0 0 0 614 0 0 0 0 0 0 0 0 0 0 0 0 0 536 562 521 0 540 358 571 0 265 0 0 265 865 560 565 562 0 365 514 337 560 505 0 0 502 ] /ToUnicode 16 0 R >> endobj 19 0 obj << /Length 20 0 R /Filter /FlateDecode /Length1 424 >> stream xc`d```cp``bPHϩLe;P$d&06/e``2sf@JFnIGC%_s''@&c M(`Pc;|Vf @;9x9YSQ F'LnZwS߸5<*11-& Ih8"Pi.u?t^Y}髌cN39ŻRe7>bR++m2Hr0@8^(Ha`cY5Pq`baHar7b3/10] endstream endobj 20 0 obj 367 endobj 21 0 obj << /Length 22 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> endobj 24 0 obj << /Type /Font /Subtype /CIDFontType2 /BaseFont /AZETLJ+Roboto-Bold /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 23 0 R /W [0 [ 443 608 ]] >> endobj 8 0 obj << /Type /Font /Subtype /Type0 /BaseFont /AZETLJ+Roboto-Bold /Encoding /Identity-H /DescendantFonts [ 24 0 R] /ToUnicode 21 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 25 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154042+02'00) >> endobj 26 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 27 0000000000 65535 f 0000010012 00000 n 0000001486 00000 n 0000001339 00000 n 0000000015 00000 n 0000001316 00000 n 0000004738 00000 n 0000008094 00000 n 0000009851 00000 n 0000001704 00000 n 0000004001 00000 n 0000004025 00000 n 0000004440 00000 n 0000004463 00000 n 0000005191 00000 n 0000007361 00000 n 0000007385 00000 n 0000007804 00000 n 0000007827 00000 n 0000008539 00000 n 0000009001 00000 n 0000009024 00000 n 0000009326 00000 n 0000009349 00000 n 0000009615 00000 n 0000010077 00000 n 0000010194 00000 n trailer << /Size 27 /Root 26 0 R /Info 25 0 R >> startxref 10247 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0016_Package_Diagram.png000066400000000000000000000750071415120503000307370ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxw@s88@@%'ij4ffa6~mͦVZef(.ݱo}޿?b~.}>)>~x{{sN l5yg][ Z||~Jgg8p`Ν]gǯ[5}ݗqܬ`5su)Dd=uMSg/ {#iΘ;TmDΤ,^zxÖme#[#ʙLk2OňZx(-hMaK1%pGEщr+%6MtvrI)Aܔv;9p57"!Ժ& _P6R&(|?j dJm`l̵7/Ԍ[0n ^m6W{CHF Rw9 sqߙxHaB^Fvx%e6e3T̮k١}1QWm2W_" ,Y<Ī[|=N+v}&kǻJne+wAaB[8MĒI^OB^cw)GXˈ9yJHYEK|=BnpmݐNJQg> 0.^jF,!8u/FɈ9,k8i[m涏8[0y؋]zLzeh@V푠u9ciWUjQuɬ,wN1ڢ&""pߚ'윈Kma8VY]Q! \ƈr9p RIqRK\,H_{RfOɘF*-qO. 6Дf2Kf>-T'VVǗ9(Z i?쳭%D^8!z[YTj3ÿՠ7ꦑ>NDܲ{pڻqwW/,.*_sr˜*"KvRqA-|"|GɽRkTf;y<+9w zvlnOhxxv}:=!՘~)]OhTgm^ֶ#\*m-+==p88$\.ZrqL FzC~J"^{, !­o]ܿ[ vSB踾qr{_JMfߺ}u1gf[fNekk!'=l펪("⦵/=/{?O(pKԥ[6{v3~}Ym[ȱ{'+--^Z-dKl9my'0n*~ Wu>~|񇻼%w "5~IO('z=٩&]u劎|OǖQ> g~X=GDDݟ?Hxpֿ>cVۂ!:&P(۱1JDī+jf }bb:wܹs;"T{4M>|ʮ/Tîn)ЌY)֢bjy.x"<5>Vak_wrIqYo|HgN]RrǷ|"=z>c'?nB#⦽w;H~5!"E'Kܑoܷy}ᢋēf|6s}Lt*++ߺuq:Wq*(⹱Zn)y‹?L[?l1ZW,|ԔSTX=^q97~1~2sH91A Eig(Y)8Ex9Lsw%z>|N/!Dž]_HW #Y[}Ͽѐ>^بr\utp7)BvHWWtS&iժU.* ĉׯ_w=?\ڷo_=\X -LtpV\\'|Rm_y; `޽ K9wpXC$ 1,!`H  @bXC$ 1,!`H  @bXC$ 1,!`H  @bXC$ 1,!`H  @bXC$ 1,]]P^^޲e\]\hFUedd3UArK.wu@Df͚aÆ Cr~~~|||\]"w!`H  @bXC/~N`LknCz1u u]ƶ/2s i_6m+FS|}[ܔxrUey9%l߲tyqƦB_a]:W`LsF>M4~,7yI43>0}z@2i.m( |%s[YBk ,̛71E/N Ѩ'3a)R!#~bn!'"{ v4zԺ|/>ޭJ!4ieW<ȣw%ȺbL"/lS,c=Z{^QM\g'"gIJT=mj]hQdT^ͱtU;&x2G`L>'qKwiXVyG%h)y3nSCM8s9OIIIII K.%۷]bOH<{8s̝$"br}6 R3"eVtHkVxc=ZcDBs[&ň}"ڶ3b1miw{| ]z Q}^Fdjo1e? E5۴W1"l3>QX -~*ylJCyFă%"& rF4_Zq`֐GT;pE)`!y :H֤wj\?ΟbSڶ/GCel[W\ug7g1)1rK;tfoiK;wd|;yf1~܂{jH晟?yb7~^I)wfl9_|oOڱ?sf?om5z M M`|-j+ELߜL?Sh.)`j/6T{o2-yoe!`s YPI*}ɞ[]xyn$'b>/'+7mZfLmP%{:},W -fK/LU,hݵ^x D8dpmuN˚#G>_"^+L3}lXWNź9IٯGN%+̛ۭ/JĂW/)R}_uɮ$=B=2[Z۱%O; sMTX$ij'u7n?ۡ_zѴm'#y&lEa'r4Mv*+*%{J@]r7s~;-G/D ĩ>"3.2j0^H4وfM{x9wO8T?>e?jmg%k纜 D"pͿnz'?myu2 1O)?;~у'/n̴.VX9k+8ɣ=qv!390P 19-DD$yۃN Lmgn̪1^ZaZRԺ s*[f#ƗsO+?鸶 "ǡ,;,bLܡ6y=ƏU:u|NOJ\t%^*""m=uc!wjQ~~9/ݝe&WDO/m}ZSSShݺugIIIWX̛z{SgzeW2lǾG^vxWᒮq~]pCbFRX UGǤtppnɘN;[sfc&cZ^[Ewu,!`H  @bXC"t[zz"L;Y{nҤ!`'G-YҥK]]ݻ;tu@>]]8q%@-\ 1,!`H  @bXC$ 1,!`H  @bXC$ 1,!`HL9uuhZWW@Ů&M`\GX %*Ι2eرc]]͟?ѮӧO HoȐ!=zpm ƍsm 4i^wm k׮\[ 4bPTT{mԨkkFp@bXC$ 1,9X -[jPQQAD6mK^GjjjLLE.ƍ_#bc~w~'c3tW !`[r^8w˛%6bɲ9Kjpļ]U)}ytjF8 O]Uz 9s 9OxSS5g&xiOnXV I_-ȶF}+Dc~ab/2[J~h<;9OR2iTVB;&/kGs:X| C̶7o#Ĵ{EʈĢ{9<%%%%%+,]oB$`2h؎=Vr"y #9ㄓsι3wJ2H͈Yū1"UY/VV2"&kU urnMp#&h.WΈe}vA F$v1l~Gy٦W<urFĔ#('STho._ň ǥc "yC9#3g^{Spf̘ADǏv04<1 W|-GuҤIDd67c"Zd E0nȾ{ނ5/gZ+n3m)vmۗˣ2^u+3{֛3ۘoLKFE%Sq:7%`́;2VJ`?n=DhO˿ӼΩ1W?M$; 3 `ٯ~o >g;k̙enRk04/1w3o(#e\Q.TooɂzOR{Odܺms0 9~_O'w>!^iՅi4gnC*Iӧ}5NZ&kԢ?f*44 3+JJpE7m\3m'O2RG>4np#Z&BCxT}"b]2 s1?I}V'ϫ?uss`ٯo~4̛W/e ^fU n.699 zfnyl̃"۱%oۮ?0t5\a K MY`H,)*d1WqhW"o~#,p7s~;-G/D "3.2j0^H4وfM{x9wO8T?>e?jнZg%k; ND= U_&fX 0 IDATsĘ ;9q3U䖽-"َΛgHے+ZxwhnĄvC=,ܶ3mw_hߤL&cDbqASХG;5˧Ȭ [/'$5- ""e~g*>Sy8Ry5F¿^IxRS9~f;^AFc̨ŅK}ztMH]uYȷ W? 5~{\&Tθ11"ĽʉfD9#7Q!Op|~Q:)*†M'.ADß<'fVZA˜M8(""Dfh%J2whZyHU&32說 ii>/u uw9LըugK^Fڡs@>OG5ܸW>$8>xcVYKYobͻk֨CjԬHCīO>TVo:'9( x7 nHKi/kI `4TYyfu""s)X|h5ꐤ-5"Ӈ4ppR8N/̭|7z䛭\Q\\k[ e+ce ]:t:X ޚjsLŴ:q˫d2"|;֙d l(/P%(H:ЩfECE% W=<LѰS~>Ridī5JwxhpL`$Aѱ37m5 e*C[&Tܵ!KTzHfDV{m_0E\! 3e󲌌Eoh|XPLiFZ)șxfuzuNa#.g`mԦWM.5B_tnnֱWؙ亐!u{qEoO=s,cȄf&ESHJ1A$Jּu]ƶ/2koͶbt1E85nl"P;}s%?g/ݿeMibw[0fVMH>^PY]]ۓ-UT1YΆ#N1WΟ_+Q)=!`^U_*ɣWN#+4bCC%gnS<ļ]U)F:5D6Ͼr"ʥ#eLP0cKy'<)R{~uod֍uj4߲wT Lm'"*e"}Ά%;sSRRRRR8ҥKhs8a #tqC5-Zw%"& rF4_ZSRVy}Ӄ3tQܶP"tHkV(VV2"&kU u^:GDmY&ň}"ڶ3b1E)jFL{E"勇bv:_pf܌,fw3Q龹/JlO̮$""^6IG{ %%,TŦ3'e-sߒgYDˆU;m8jq')8@3{֛3ۘoLKFE%Sq6+pfoiK;wd|;yftT«6Xdʤ,n |Fc 5\vTQCg}伩ϘǶܬӟ_ì᳖u: '˚#@we9:` nS}uR\yjLk5YNRxW銛6MqmP%WOOwʏa ~;k$ 8_o:PYQyY%!NϮZfMZغvHxW=MMNNߨ%#c«lǖ_/K?Q8o'N>ǏU?On;dC6ae+S)BR^Xĉ9r[7+u FLsΓ_~)!jfO}\7讨: 2^H4وfM{x9y^]_H8p;?|.~-Yu){h?A,os̫ېA]{˽裚G.s9M{Wl9. _ώwtbdT_깷OwwG5UmZ,*Z ] ̧SjkekvAiӻ ʾ. m>[!´vK"u殝?"TsYl֢}:q(#6-o둬c$ CWվ@w8DJD֭sm5?O>۷oOJJru-7w袢O_r=p;)E.MČA֏I =!c2洓g㎣g-|%wM3X {;U\'$ 1,!`H ip?X,pO?SNV.|||t:ݕ###]][X,7o6ͮ.ƤIZܹ%n`H  @bXC$ 1,!`H  @bXC$ 1 榧szR\]  [|ѣ]]9Opu73,䯿28qkk ` -[lԨkkؾ}k E"w!`H Ab.FP(\]r@Jf`0sL2vXWW,ހ][CEEoKMM}g\[CQQ .rfnW^yӵ5߿^z%FJɓj l2Apye˖ 7RYYY^^#`nt?.6y{Uߥn2XC饧/\е5ў={\^IJJ su79,ٳgϞ*oU3g9U@z/C=*B]vuu,^@@@ll iZWpECnRiTu=?oUb/2[J~h<;ySSћ kM}3{Gv3hԺ#29OR2iTVB;&E @BX7#n^\y('-d'QU *57eo~]XRku){D/ιO%rcS_yYc~5[^;۶IO}FtTϖ19ynBYo sN1vUM2?E"1AGw,dKUum5fٵ@\lrrF !ӍH.,qr|45' i] . r\w&]w> T+yOEydCV.rWnAqQ~ޑc*Tѩ>w{&>U{v[ҿ{O:?*yGkO4e^CFkNд|}H<艶aIi$"27eǎDdWr:?M\wEqe7[ez5 qx ~h׶}<*e[Nj+ ͤ=撒 }bۣ*=8ϯȈdXb-Ͽ IDAT2Xթ^3tܗ%6'f<_ۖoɳ aeê6r\渓DTes~'?lբt-_vPWt1~ݬvtwp;\wX3=y{O_W{*yɉȧ}=~o޽I}H">%] ֦8={:}zagKm>sUQE ~>crVL~Z:cHDDD/ MID$Ir婵3ad9If]2:Ґ-Mr|Rfw&cZǞ99i7jh-N~VttBG3cNYr++4į>||' 8_o:oʊ SGYXeE`&׻f?>K,"+/qIwPgW^&-ln;W$+RF.LU޾UapnEH>?y!Ć/Gu{ND'X`DώUWݍ[/s7h"N$xu}YO/ݺ1]ەT;?s5W ۻ]"&#.}ݲ5ie^N59N6NeidXST5cRjJ (˽\/y~}sNt:|zp  :ec-FIg_ق1J⮓ /,nJ˴{y|{*$ 1r(_F˞[}mYi=&lN1pXW-_~cڸ㔗H0}Vd˯*OmҾU >%#ڪJkyZ;W twdݾs[z䦘Sƚe_[mj_dD$ƭ8.@DL5[jS/l=QGws?9"l7;tcՈ?$5b2Jƈ7(y7օQX5#"R$%QqmUkrA$"vC!]Щл?ɼ)g_4q$ &'޾ՏDʈY%x2{ Rn 3]54Irpm`^oUd+#dTHo-_WZ}֎ :YjC+Wr"fȘjw'9g͏~ZʉUaQ3a3T_""u/fho?R76vv9X3 a-wuM9' !S^`ժ3PNSܿl]NKì??w^x;oTXz( ;\?l#Y߹޻/@ٟ֤A7=t]~Cxavǽ^j`.zᄠ,^i0}{>SR$L(_y#N0ãVk"޳kW>i㵜k>ʱnۺvMG @tX=z߸9W*3=Π9 ~7D:s_{ O͛6DID|Mg}s7L%JFG/mpr{׌p%Q}7˧շZ|hd5;Q=swOeuZdK8CyOZ<}Q){K8Tڧ]ZmaI8OCwqE[dti[=cE𔰱=4+mX~VS7nZ4=GݷWgi;pt">7.222q"G+wnT FLyDۛ{N3K Aofo~s=WzKtAf0e2'ܬ̬ɧRMy#߇KƋ}q:@7d%,8k_!X68%L~fF2rXuD&o{ˢV OmҾU >-uyD@U[>攛ִLMJL|?Ox5貱?ɳ/l%qcp|:@7$O|ꭧuTٴhe^4zU!3/ed 0xcͪeZޝrU] O !fdJ%&KFtrU ,L?exi7X% )!`1QzS^9mϑV2}hn[FFyhKC `gBR"{ƣIyߩ1uX~:ix}ɑUH_n7'!\dGל*CŠW8*TEm/;- k%yGAa|B @4Lkmu0OWY\FD_̈&3X2Kqc AAr6U,naSсkz^ _kpttBg @DL`N)bbMܴYe\"Si> ZTXm[w%F1SĀpV{^"MB #Dbw^+^/gHbјņ\]wmpl3 *9q^ڡ #B7N馛nib.ۦj*׫ 3XajQ]PZO)aDzF7T <`M{pU>] \uR'ƚxɌy.Q]a m=dwqŅ^Z&p^ϵiryϔx-KQ:)*2G@YkRVN}p$$ywm 4 -!`Jn7H]Exkݵmu׆&1I]6k:t k[ݵ@|K,YrU@snBw8 =?7mШl*bMvmy^>LӳwoW/v6]m<讅bR*~U@#up6讅Nbj_|U@ZLnkÍ_0rRGI^I;t9hμ윈Hxcr/y=p.  fј4beWwđꂌ(=|*r3ۛ1>xPo_FLQ&O깩ջ:ɳ>#u\vvl޹wQ;nQs1;tMXwa*Km?]J~؇9up. 3XWCn7H]Exk   @d8EU̜9SH]\.C^``-"u/00P* HJJZfUh @dX"CD 2,!`  @dX"CD 2,!`  @dX"CD 2,!`  @dX"CD 2,!`  @dX"C\vOK]EJ]\gZw5tP^/u-׶* VWo&''K]ŵmݺu&M D 2,!` >RŘ{׎+n?zc JmN V5\.nvngh;=t![]!VwYVz ysW{Q_3X]'oI1հgB j!|z t[}hc.5L.x= j*g”gVny`Kqv3W=5i`OZrk[x`] ^p!sy'w|wØgv:j^Ictȝ"eœyw Ex&C?Na.r5[}4Ru}GIض-댋ŎHm﹍$nS>$A8v鬽humhSf2^/X<RmEC3X<}oqg´}PHeMk4Rq~kY ٕ"&u{r6=;@'g'2|}ɕc_ݶu/ٷ0%7HqÓ_n8]~+%"O/wxj-\@{v64zъ/^XFq**?#X~obAt)0SDt{G T^`ԼiCDDĚOwXKͽ,A}Dmګ̵1>Y7^hϞ6ִ-Nc$ ܻ&qT^ۍ[_G[CDg"^/)'Num9Q8o甍WgW=?Voڹd~Gf0eҲrܬ̬[JAM} z#Ry/~g}Utn~.;(>l pNK̛͟{vJMCxWL21"E>;52 >--N=?eVO%_XeaKwskAtgÅ~Z̿-9ȔK7lx~@K֭[nݺI&޽;99YZm8 i 3X"CD 2,!`  @dX"K]wJ]ŵf$\.]:|p!`uz^*mz>44T*$SYYk.*u!e書{WI5X"CD 2,!`  @dX"CD 2,!`  @dX"CD 2,!`  @dX"C\KT*\9t6|l6dK/_K]\w@|SN9r5־-,ߘ1c|Iik(++C`;D 2p|͢E 6f:\ii}ƍR077rI[@I>裐ikxw}Qik` 0ꫯ233%4hPxxUtsX UVZJ*>>@*{oΜ9RW!`ϟ?sLΞ=;~x. `/uМh  @d8EIV! L&m%]cL*@$ .˱lA*@$ .Wxe˖Z*A${ʁ˹\.,"}K,`]y ,_Wر<'- ngX.~ fΈ# HUaQ3a3T_x[oW}S^EDޢcT)? w 3j^ɳ7k36iԆaͨW'oI1E=n""O3ΆTÞNj 5ވIDATՆ|SKD'9g͏~Z|/|?y`OZ6'XM~=s!ɫ*8cCp5g+FU5 `Dm7N]c6U:Ng]:k*Q'9Jͭ)c][vaa-OV)&'*]u['ʠU#83O7 &+EOxr`D_쨱ã~tXH 8YVXk{Ϯ][s2kI?zs6[`΂{+d{=UŸwd@ n<}oqge^<"&u{r6=;@'goϿ[x7<冏krVJU@ܚ%ən]3•$ ܻOБuƽnzD#usgȸ ~3`9'ܗ gDڰށ2"nGof!#b~n7Z{a'ߧRWqsvU]sチ2=Ԩp_&$eXr` 48D{CcN98HӰ,0@Eފ op{iDDt6ɳx/Djߠ/-[ߝˁ3W=5i`OZrk[\ME^Z""w hպ[_Pn& YP/gEYSfXĹdB Ig^EY&vČ+ Hfr}FC?o^~ 7gv߾zaqʼnd}#\'_N>plj_ro_11>?i;TkԜ~*2W+ݯyx7.'>ۗ|ڸSđt)q}5'_sow-֜ZҌ,;/. $aKwskAtg"ҥ,޴qJ߾L 蘳'?J7?dXE95͝׏ KC^6w}8'E$|p٫w$jd$|=pmre+Ǿm;_41.:̳oajަ+,^dV_9Ͽ~fXs}¢62{-VQB]dAvf(XBdz׊~asѣGA }޽[BD`Z7ސhAQQ{Rr=Zr%:uJzÈLx|ou]z~fFn[jo{ã͏)/=zbyH|ps%'VNQ3"ٹiFL;yUsν%NP1k9fzSF$g:6 Q5b,fz+" !K6>.yl|/95_~/ЗJt/Uh9םxLOxdJQOSh1%%5G&c+2F{N3N)›{At0,kec-FIg_ق1J⮓ =ԴMRyݯ!#**99w>viɹfQ\;=h4q{ֽlcd7+vIU;R]U e)Sǧd^ VP69g/*Q0̽oإ$\`;/35<_IV/yK-SLfSmzO# t,kz'?7%wW?dbtY}mu2io1~*G{IR1BY%x2{ j3s.AHyg'Hc?}a0\1wCL3~wi `ܕ?m-Ǜiblo]o^;o;_heSDE:aw.%mij?y?>Fݷt=Xn'r1sM;'Do=xSo",x=moM4M `D 1 m/ YiK,MNIf==Ezgdwo?6L,rxJs2J]`A,}wzZ~Q Rp0]cwΙu󣟖^SYj]H­/m(5-hkeSޚYk^qw ]fZ4ZQx+wxeh ̐4fYF_ *,,f[iD  -r/3 Qp-{+<)Yr/ɂo!^|%Y-w-lV8%d6q$?0E NX -νZZZHyg'Hc?} u[ $ij?y?>Ƿ8?vB]fD 2,!`@s sW޲38JrNR@ⶣ9?Q c`%քI0p@G6[bјņ+?q:'0r~̂JNz,:P_%^+-\E /ZKba}d ʽD(so~aC)-z̨A,PI`[QuHkU'3畺F[|Ta m=dwqjMHiÒEvn;DJ S'uQ)=ƽWБqWeeZaT~y:/ϪWWJD-޼ʼn:tpjk,FD4AqIAD&\ƈryn"RIr*^_osNe Lܕ\斣2SDBboi4J'QsB j!`@:~F3p1`*[%2nTJ"1S"xCb +쵭' 8l/8\`v^1")y_b"gޚ0Gg W'/> o-ՉG1fJs%2$F9t(,H-(3T ^ji@ Rq*(6^CMτyE>M`\-uX~ R"^_rp9.BnVna[pFܫJ)g^Ù54U'z$ UQquh @4wKymG~_gȀGI[e2GŇgܽi{$Ң[kY`U@sRx$b*Kэn.BVoVBefYĄ "tKAf͚5k,΃ *tKE :,!/++뫯 hBX UVZJ*$b999RWm  $B@bX 2,!`  @dXWm/=tK]GGI^I[29tfqjШÅ#vTF8(XӜٹKk< }P:pF עb윈Hxcr/zѱ&M8Omݻ,v6[>̢1i|ؕAD8^O.,0َaCS*r3ۛ1>xPo_FL̽aa~:FDJ:@q/'1oEA!urjW؟W5Nn9RYHrE'odvCbЪ5A#EzlOtFυīN(ED 0"g,,:Fèt^U7,w[y1u8e]=X4i⒂xMr2|tzOݒVELJ^#rVfHHm1F]WY>*  NeQnj2\ XV贌UsBŨ {|ˆ+:ZSUg( r{2cDRxƁCEC5pݶBP(ZX3!|{^OLQdNQ%ӨY]mח9\evsRL|̽zre9YSe c 0yյDU=G\' h@{1^q:dyŧ|}ˬ.#"/fDj,%r`@yձ 9Sgmk]iR0ym!%nmɵÁ Okz%w)XF^~1`2(&ܴ?aPj.ROݷ-ϫK3"SĀ[H@sT|x[GLB/-cڿ-#&0x W] @1.(-s'0 MJ TуS*cis,уG7y MH M̮2Q#au-*@1STbV^"EpS(\e Ր Rq*(6^H"CNv۶m;sU5,??_<b޼yR@ȑ#ӥK.@'&&J]D 2,!`  @dX"CD 2,!`  @dX"CD 2,!`  @dX"CD 2,!`  @dX"CD 2,!`  @dX"CD&T*eff&$$4|3 K[ @75X"2LyIENDB`crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0017_Class_Diagram.pdf000066400000000000000000000225661415120503000304410ustar00rootroot00000000000000%PDF-1.5 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream xWKo7qY@ g.KӢhfAW]H*7)"ߐ\IJBrfypoAxEkzc %͍zA8m +u]'E&@pNYc@V~x`۾ ~΁Bⷤ DÁSzaJ-f7A/-BeNFi\w7˝NرD'j4r(YsVP,M8aIjzQ[cU 伟[vA~ac >3\4R:R5_b d}>_?:Pu!xF[ĮU^w]h\ K.lKRN",ms^sSMd!T2 - RdYZ+.y"V۵'əb|u>~sY{OoAVjtkrVyDXٗ`~CHi{zZ4u;zj}P 9a~<,lTk Tُ R))frGXY:jIV-rM՜Õ jP03Ҕw{d[(ćR{խm֨5Wu@E `2ASo"&gS<nZ *61BE ۉ#$C]_T9ϠW56Ih9mfgUa "-I ӽN?{ RV:U@<{,h;]z065gJ6<W4 #cJq;$)q ?zӯ;q‘ =l \J6c+\ endstream endobj 5 0 obj 1125 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-1-0 7 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 8 0 obj << /Length 9 0 R /Filter /FlateDecode /Length1 4420 >> stream xXyXTfA LC" F+2 Au APP0LQHKԘJC wFk nQ\z\K}oüswι!)IʜZт B$6%#]FŒٗΞ ^c2BZ; H|װ2hve;I3nE) _e4dnH@7DD [d2[a Ü'`܎喝ؾpO-$oY 8%#ќC8^NnHwb_.V.Qr?wWAjGXV::o=['_A87H _RH÷L#Ë gP\_ˇZ/Dytz?Q_묒)]TzJr$n9ɭu S:n{bf|ޏ yEѯ-n~V>]{Cbi2ziAGcժtvqvV)Ect΀i.xHusb[1q~sV""q6acuI1eekڊ#&\|ggtr=u 8~HسSB%-_O_ ma=^&L0(v ibHD&i&NrFh"FS*z=lAK 2+ xzrF _77o~?ͮ2P6xp%/ܙ:l\Esq` \bY }`r;NA@hK^?E%S? !bI|W>6u#Ӱuppq5C#'UZ_Ip6iN]GCgo?hN}#MiNJBzAKDh % XFyk+)8 j5zED `gRR֟I99zmavAy IFؖ0R2{9^{=L'5׀}~j"lyms#G5N_ T\ěRLo10/ pwq_8+vޝZ.5_:6pSo*vñqDoXb]ݭ}bda/Thg/=9d@;/76Fql ZX!2(Tu7wy\oR*wO>@,1FW9NMsj9A+sl>|ҠI^ J1UJq҉"Bs-^antқgs,![|g6>khQhŠp.?f`~@w^C54;23{ɜno/\lhjjȯ3ٳGw#g Kf5P4ZqybG<vC̩,3#HJsFE^L;';~n☢.('Ěɋ+RL&ѥ kEǠG\Nxd|DsMяk3%|Ђ{[-cXq=PiYD9?+c$(( }ݝkVҟfN2sV5RQ=BK\2\".}yYFJ«5zU/S+WyZ^a'u QO=zS ^i<ҕ CJԙ = y[R<K]ew)\Nkˉ*tŗЫ6~ģ/eIkI#OepPQҚHKMUUq.AޮRʲu+RNk8DЀca#F5*lnyU h{⪔C6_XpBj>?8G<>ٙY\IaoYlOd%c>J7+}T7xuSޟs 'm3iƻ/^$,rv=u䝁'^z5Η$=q^噋;Pw3WgdæY-s+iޣ~ DC~ւGC@ OQH,Da`{;ǎ$M ?bD:l$0|z'*!ۋmRzO>)׷1N+@t -Qz\Vpn3@tr“?X刽i=;o9Їi؍ް3lb"*\#,$r{G*XvOjvDh$+5ؠ7u.\ :kѢ[m|:pzZ_\#L ҩglqѮ;wNӲ"Dx4=~[A஌UgΔV]v@lg5TA\-{|&rъAZA oݞXurk.R"Ea^ZN\!<W >F5x+8؊1+QsʒIaa၁G<  DP~:uq rB~|#q"0t :Zzo':'`\{<-w79X@/ïH@dy dـRddm/74gÚo>wdXEW% x8!zF>~?ݞyx/-mXƳ|u jp_sJ JQ{TG8M\Bk/C42IF(72]]C| #?E@;]Ȇ4Hy("@T-|x !藂APJRÎ Rk@$K Nǃ$~J@.Z)KAM-la-V"ddg]06` UHN @=Dԇi9{ endstream endobj 9 0 obj 3208 endobj 10 0 obj << /Length 11 0 R /Filter /FlateDecode >> stream x]RN0+|Jj6HQ%x8DN䦇=ƓnqE7e{Z0T4K$ajetVfհy9-taR]7<-墯ӵZ7/%QA_}k%[YV^#^A?F$Cχ,?- ;c\ W]WQcݟY\ xP endstream endobj 11 0 obj 407 endobj 12 0 obj << /Type /FontDescriptor /FontName /MJBKEW+Roboto-Medium /FontFamily (Roboto Medium) /Flags 32 /FontBBox [ -907 -270 2051 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 8 0 R >> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /MJBKEW+Roboto-Medium /FirstChar 32 /LastChar 187 /FontDescriptor 12 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 349 353 442 0 0 0 0 0 568 568 568 568 0 568 568 568 568 568 265 0 0 559 0 0 0 0 0 652 653 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 451 0 541 0 523 564 536 354 566 555 255 0 0 255 870 556 569 0 0 351 516 333 555 495 0 0 0 503 335 0 335 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 485 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 485 ] /ToUnicode 10 0 R >> endobj 13 0 obj << /Length 14 0 R /Filter /FlateDecode /Length1 2116 >> stream xUkLW>.EfImUfR" L!T>]_[WAJ@-T[HFӈ/mИ lL)>?|4 U[۔fٵ&GLΜ{=yݳ`t`Իp~*,^?{b,QKk%E^=BZR-}E2!*w~l9ֵfRnUI$GUm[2:>]~۝v_SU)~tJ ݦ"Q֠1h:Y{ۗo]V翱?I{ YsnBg%Һ1\ơT[qEJwܽ;w07y3 0 }pR|˲گv9sՂ66QLXfʓQZ)̚9J?*olWVr"Skw%/f'F$\.'8#AKn2%I|砬D{bӶ#ks}&jۄ_bG0UPW͢j}嚟eM3$Vxء%Խ?Y8gƧ홠azlwX Rb\G"T/v[ 5?9eg1F马,202->`rrm55|,Bc_+](lik"un ׯހv*5v jT^U,$\^9ˣC?gyH&ң͊Mˁ:E fZ8.E/Vf.-E'DFmڜj|\CIo q?)tsiJBؿ/d I 2! R(刧?=|3ymӜx.D[*?{Oȗ͵!7JyFsS#|4(B ; a]k`q1rP{rh&q1&.!M|>$n0$>F/~ye O\| endstream endobj 14 0 obj 1363 endobj 15 0 obj << /Length 16 0 R /Filter /FlateDecode >> stream x]j0 ~ Cǒ >XHm5,qC~U:ϒB281N\kP'<['Uʷ'/ qYP|Rpaݳ^N xug}GvWpF} {4#Y4m$oY%朚.3:\MĆ$;{#>u>}/>7u FgdTd endstream endobj 16 0 obj 296 endobj 17 0 obj << /Type /FontDescriptor /FontName /AFHTBS+Roboto-Bold /FontFamily (Roboto) /Flags 32 /FontBBox [ -913 -270 2060 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 13 0 R >> endobj 7 0 obj << /Type /Font /Subtype /TrueType /BaseFont /AFHTBS+Roboto-Bold /FirstChar 32 /LastChar 117 /FontDescriptor 17 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 291 0 0 541 0 0 0 0 0 0 614 618 0 0 0 0 0 0 0 0 0 0 0 0 536 0 0 0 540 358 0 0 265 0 0 0 0 560 565 0 0 365 514 337 560 ] /ToUnicode 15 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 18 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154042+02'00) >> endobj 19 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 20 0000000000 65535 f 0000008869 00000 n 0000001368 00000 n 0000001240 00000 n 0000000015 00000 n 0000001217 00000 n 0000005695 00000 n 0000008452 00000 n 0000001586 00000 n 0000004888 00000 n 0000004911 00000 n 0000005397 00000 n 0000005420 00000 n 0000006304 00000 n 0000007763 00000 n 0000007787 00000 n 0000008162 00000 n 0000008185 00000 n 0000008934 00000 n 0000009051 00000 n trailer << /Size 20 /Root 19 0 R /Info 18 0 R >> startxref 9104 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0017_Class_Diagram.png000066400000000000000000000715771415120503000304620ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxw`M}3n6"LBHIn.hE,*gP[3bFHb;dHq/?s{&7ߜp1/ ?Æ paKUVm޼yօ BW\9s挡OSWKUn@tyP_{$p(+ ] ɟ\!h_&ތ{Fw)µI$^:|:^8شTJMV-|iJ?1i௡m4jxs5cwh>|?v|u̷~X{WM e+8%(#0q&ŸtFI.O5w3ʝ^ۻOwdg3FRZar*\+Zy-'\BQ{^㌌K,uLZ5qjagJHRrWxh[K.DD| R+ޱvyX< <ǝM^x+N(IsR% Œ]{(yg^9 _fRڭTYyO3#3sSK٤,S/0 ,iKW{&&?!qt'nN¼+X?]o)0,QA!>s~ܢY6wI9 w2cDD,'+[uʺqㆡ(&ջ-'>$p'9hzu hyK]؝k=+a ]{5JQA!US,Y@̔*ɬWz9q77yp,ͬH< _:S-K}|뿇K_w9JMJ:={{-4[Uz "[%YVVV֭cccWZeZG`ef"^V,zl,ϧ|(gtޡ]X]w7^]ޣB^1i״#mz'</'A[6N2w\sh۔&JLNߦ󿇎]GBW뚔c6T[}|ᔹ4 g:^R妫UVu|i8lOE)O*h+ ? uK:+!#H}enǺ{\Ԥv.HW&돐S'zױmWHW`t_e':`:tȀG5}cǎ^[n :`]tI&,>*>tiX^^^KںZj:`YXX4.wx@  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @  @.sվ}HCWzm߾U!`d@кukC]v%'' (ޟE ]|^jc5XzgXzgX`x,uOKОTfR lWp 8CxLc̸Aȡ@op 4ؿԨT7 F([үT"8  pJ,ݾ 9,tf ]oii\cuml""R=7L"1sd8 cwycy&C{Hq~Z Oqk!z,'wm|^oa~:Y}Mum~U6e̓ʷ{mv;X?3ݱ#oz?k7k:`S$"q@ɆSohn/]ZSFYv}T-%תOI#"չ%L ޳r>i'@""C9 Q{5m%oϳxh[{U2jj!ɧ>}=k=燊_}bU2\ԿߕPb!`}4 26A;o)!xi""N,pFRc/SSXL}~>?ᑚLbGDKS㭉3.=r 3oRӕODdlG/ѴZ"V]w؀uvqvĻ GRvR坂+rOZ&Np®qR;O׾r㟾(ZSxg\\~ae{ӌ{JB Yvbv]n3eqWgQ~xde3""ң-OyNVzׯ_Xd :8늕Js/.&"R߭usTW_ Z>l騍Ƭ[S?8*rԺu 5z[ xnT} /l粊H;W5m.]eM6 4Ux"|Ÿjzf[MWy! mbވWP!`u`ÁDDsNyټykN9mƮvy<"[q#9=xľVSz/x"zoݒ3dʙ7lkt+tN7{ n>DD5";̼v횡70666t@D1ƈߟ [gcJ; (cnBF'⿅U^=CWok*^?q Q_۱|Am}d;>57 ^Z5CW]pa„ ^Cm9i 5Ξ6g7+ ]vӦM ]& ]ZK7e_ ]g i3,=C3, =A.A{RGX!\,R6| ૃN(-_V&xC-J]Z3CNfO7o>GvibBw8п ㄕǟWzI~vF@YS#}?2e C! LZnQ{q9쓌1oC=x' \A #m])'9H7G$>n@TbmgLqsXƿF]ɉ[үT"8 oͮ+ҸƘZ֜~U2PnC14r1I,_9zob{o{DbX_LXOM%]vx.)?|`LNc3o,dϊ)k L2`IVmС5MG Isw6>7d0?I?;vi׻o۱jo;um][*9gp⧎OȉH7c)G'r6AOIЯM Kߓ$>x(|pCD {Q;}]|!(_ҨM=@P_#+4tPr';[m2=Z~{(C9 Q{5mƥk">]պe 1,`g𞕣=I;x}񬻮8VFD"'rhݪ\SѢ{->~o|裮gѨN1\*NUsS~W4*XdFnnuK53c#8r ED\|*fxMn.c#ʯZ/EO,rL!W:LRc/SSXL}Ox&k"⌭V˙W<8~h>'es4d!W{~fޤfyf .?"|e S3?i>}7Dݻ#_,X1;T0Qʨ.ewg_QC6q]daa[/[v e݄ SOX)GOV'n8aFy8]~vP߭V: ڙOy"lo}/QIX_9oRA‘̞Cf؛vk.U >|W@&' ^9i6SwM=|_7QDYzT)oɪT~W\L£3?[R[uJT)ֺÌNP]]8|)7h6rpB忣U;`L߶\˖yݕ,C_=0 J2q_WNq8jeަ"wV\En#}8%t 9 dΌam\@TJ#o> ;y]l{kBv<ŐUmBGb7:Ř{g ߿aP#*cȸAȡz, @:0@"q\䮕INy R-Ab_ӂޣBoiUm?o鋮܋W-9Cƭ9z϶FBt++N9Q?lWg1cPl_+#xvNY襜]8"q可 63j0=V$h.&&gh#V0_6mda39N4gmPB"6jcKܬBEatܔU̍ 9໌R0+vj؛e*qGnREFFQXX -ˆ(22Ѕ|!7i$L:nx*߹}VkպqÑeB";{8Rc^wj_W&d/t=HwYsΝ;w\@@̓:ٕ0~ҐfY7m>|9pcu=wXwD8iᙗy𨩣[XpDw?o٠fƸRr~4hM3uQg7"< Q/Tڗ_W~gjj 3W&#gʠ!Rσ\igcWw4}+4 ]=DB߁os*/mZ!gY5=*9 $j%+R;圛,+K%"sMuZ~zk|sÙ\Y73\" J$'qQ}-'#ⲙ&_.]߭yW+2r˦!WZVvEs4!=p1"'pVo!DEEիW/,,iӦ ;p@```ddkz`5X٘S_qo@<}=tP53C1i4%8i"XڰaƏvZgg琐Shgru2#*#t$"biVҢDl\ʭaYGH @qB~S;JGTK:xPf©VѱfMbM*I$&~ Au+Pr.UtiCW\ %IHH?0nܸI&mذaԩ:u2t]E,=TXYUS͜G$gTƗd[z$jjwb%"0ENe-Uݍ9mjt5gEtFL%&[CǵoPJ|+?֭[ \ڵAAAElٲUVEc0͛~Ν;Ν;xCTqsﲭV' ۲iس O%of9Kx]w^/-kĦzom>韉mݬmt)c_ 5kMtȿVZ( IDAT.dozQ[˿oߝ5cjگj GdAz-2tzꫯlRt@ ^` x_\um֬իW_vo)Qr1cKD9yD,k܀ųi6EDD4xǹDĔ)RNfrH,393 )GcHw/L~H" B( 1K`Pc,44488ӧݻw9sf2e~C`鉉ٌH'^/eefi]qFMZÌ e)jF<˲͖_Ʈ44ϓ5eEPӧի׳grEFF]L2.88c3#5랚~蛢T9~{Ӯ5koYX[8$?ywſg"~VXQN'O[+zsDg*""o&)p3ek[4g'_3Ƀ: p7g:Y4hRS±K26-PM׀Gp.BJ &5еE%*O1_mM=:j)JJaÞ}ۆ欪UwS*Ț ^l֥#KO5'+IX!y ?m p!|w}ݴi ]H1]ϛy6h$1G$:|4Ḁ&M\CH ,c|o?yVu= Ypv,}NZV7oF5/i ='1@=dh\3GgXz_ zzu7܎z?gR ĈodlĩS=tv͍S \2x|!ο;n՝c/y4S[|éE˯RG ݽoޕ2͝wmNe[FC*rEB0?\.ZoV6+8#l/WSk#X!isQ*' n$8 PK;_CgKDfq'R_ƪo{Qmo?e%/yv7 R*t63C{N~wܷVRUV>gDyt>Auq)EEXR|IŏXK*2_ZGD$42>:o2N<""G @Zv5[yu! 25]ڭW3.VZ.IWNbT`RUmQ^<a;Vb-{uNܪGmdYT`p|]a*K;b{zS4Jw):e\[՛R ՄD{G;.Ν$FFs?ᑚݺWbBD$8""X"B(F+Njj* "9+ч"%i?I&>tVog:L8RSJN{,{9*lv3THpR#:S#cMO[⺛f4؈dHh4s1u8Lݑ|[v]z̻{x n^,ts2,$"IUz:}Ky HPĉN5˦ΕbJWӖ^D3OVjq5 4wj|L~Ŷe N sLRr10JEX( ,od]v(3bDĽ:Qi=e;F{U+6@ɧJHQVR~OݐVt4 `遅G^1r""{3gQіy'Rׯ_F,sq2(7~7DxлLm"cY""EV֓ojM>;r1R^s3:\X+d[8R6bGqiҒSߦ5xβY-m–GUe/;.K ""o*WuWgfMg(ԙ9LtEPԛ1i#ig/ng+n=vpN\O$O~G_M3K)w/D 2_={\|#"vi|@XgoœwSOxa?U@DB߁os*/mZ!gYuRK+c.QS}w*yu;CT`ҎN[euG+:ΗժZUGd-C;x*j%Mqz_<jٓ;Nrh ;z)""θrE*+Wy'jt2n|ĹulDY5 ݵ8זeyD$4_uNӯQy}QiŌ?~'#?ry*k,'55Gh#zVQ;*'ewb.^c^4v=X*9tRiXq R9zu2刈:$t5q"k{9¨$Q>l^3)si7v~޲^ɻLvuD$n4tR9'uE x<3߯q+yb L!L)W:d8iو[#F-˽˅ExpOUS7{N۲ozC#R?b{; gȸMi?wnC}8:Kw QGN\[$ -9fL8qv-mqiLBUke}2̝0Ҧ{Z"i8N|b\B:#Ҥ?+t\kJć|;7gScYr%IKľli9ZL]Ir/4k}P_1 Sb1c~~~~~~ ?He>;DfB @#sG$k<_d9CS?xp\=h^܈u7&fľ Ƙ}Ǯ,(wĩSWy'r_jR<('_aaaD _܎u n#߹ I ?IufLe٢gOo kjiy+侅gU-E f֥SZLNnK9/8=ڃ׼OydʯMں6eh)yKg_zK91rEIcw~]G5O;ˈc}yD*>?XTp:{rsҲ6kt=mmq+dq"zͪ'԰r7C'xb-#լP}UxpeAּCJy5zˠԵm{my[&RZFo'3_1*txi=Fd^"-ϙ07FFƹD|"şf,㈳pş qbӶĨ\egE\J6P 1q<īeYP&|s VWǯ04"1\I{9u/-] LԹ<3<ا[M ^ϬӦTXޥx߮xQOrufUX:c%$) (": mP^mi6=rnӣ+ˊ__ߤb3fZU7o쾺:ƨnΪ#$ f<m2f5SW;B|~~x|Q9OckMyGE+Wko ?t/rgL| OEn1Ӌ\N~KX@Jrx#W41ű! *vNc9C*.(u-5&i};Te2aN|fiQÝQ91 'k&_9Qϔ;Sx9vXqs~R'(c)/LYHSht@5dJzzzzҡ!"1+c,cSG#NTomu7v88\c;sKhKYJ™|=G.,: ~u,Ɣw/^~]BVΣ+(^$]zƙW<8~h>'es4d!WUv֯fyּOw{DScMD^(/HępDĉ%bSޭ{>̜>V|?`PXz뷿^hU-nWt{S;-,lB,c}sߵA@xp-υGg}ɷ0#^uoa}XG|76EW |D8Bg GfIz`ɊjfT1t,OAtX̿Oޱb}ko"+}}ڏAoL0,=x ~I[?V/r/^NƵ&l^;%j=kM_EN} }|6}`e,uOKОWd7Jے7'GgbOԚqMMDy )ϢO>}aha|/ci_ou&5]<""Rd|ې9w̍8SӲSMrҤ?8yycc\ǙJeD[9cu夥evfFvfԴ-K)*in2#bD"q|>#xRxʷ1{w0gPڵ^Wbo4ϻ^kId0qn[UNj[ǣ* |H ZbE) uƽ3G>~^3fsp-ܝ-8"N*dxϞN"rks͓}$v""չ%L ޳r>i'|ygpo}}-kIuFǪ8pF8Lv"s&Ik^Juzּcno4<4dc|PֽOe[\[՛R ՄD{G;.Ν$FFw9a~"j/=ظT~79#Z|vWӻU,qKkO}.={޶\=tFD~am'qIJs2|p 9={|%}aqdM>;rLϔJ{xs3:\X+duL;˾_]mjU&\P24Iib%7|1ZB9+[ID]qx]u4}<[ڔF,b"ҕ[o%gEѱ- eԽS׻سJ 7*v2"Jc}mx"E6YtzfU"Cwa) q,xv?~ W7>,X'Ż)W&;#"" s1M’cE]^۩eM^(+xjߌ'$E nW-eSP\<3Fh8io״+]<^5{x=c_*QE+H$^95|?Q WʫqכFh)ON"1UlcYQNJKkttVh ÇҥKM41t3t Q `;--U3TbJ4F3p/?(֮]dɒk@KOO;v,;6==|jXSN}ŋ>}:m4C!`ݹsg޼yz ٳ9sn޼i>),гÇD)S%Ipp@97֖J.=f̘;v8pХ|:x;Z̼rXvBQrePxE/Œ%Kbcc&Nyٲe;z}6O G@?RRR\]]* SRR?qUL4k@?,,,?^:z(=z4  XzgXzgXzgXzgXzgXzgXzK[FI;m&b{]2CWC""N(-_V& ] O`#cqSqC?A9_2 M+KJUi?ap#ihXڹ%:[J%2{=:nH}܀KېrOikv]Хm5^Q14r1I,_^D`ӅY:Jo9ND9P RsӲVӬ3WZfZYmfYmVthyxa ZEA||urefm+Te{]y+ %;xk{2!q"9ō€`k<źGqyhQD]".?]G<NdQL"%"jqV~>{߶v䣈Lf:Oۇj6$8PPn,H y}l_˹ ߛ#/]]r cm. X^pPgvbJ~b|O.)&m rԺ63Oe$>2ӿΞ1ѹQO$\> -Y이wf֪8Ǹp)AqteVn*\ܽu={)d -绽}ǍIL-mldܯg8Oh9빤pƿg.ݔ`H%aZW}9O|׭=_f"bLP‰`ȼ;ً|km9Q- }S>jsjoF<<$~,CT{|. ۽xc8>Ƈin7;? GMzg6bu:}<ϧ-67z+OnOm9 ]>ѳhzLc]:|POU3\^d]x.#~pbxmmm엞I6k@peRTUTYbwz8(h< "ǿ'vТffI{{.ͬXw˗/@wjMq;fe-#'Zs?eQn?uU{> Y?\_g\,}@},7L~pwz{ pIp @c,X#4F`h1 @c,X#4F`h1 @c.-[N>e˖/0x{Oiiiޞ ͛7{{ MNV\b۶m}8իW'%%y{ [f̘ѹsgoO6m{{ [ڵk)Pn+ "1 @c,X#@vW웦noKtvd1}ۄ̶uTbWϏ>"햇l)hppUl:r kּF!:E1J|ow=t.AKĥ{ 8Wˋ 7N|!i9Ƽ8|Ƨ]"4P18Ǔml5&~)ܗS,-ZPjűC\[:DgF vg5T-X?gMmfsPd!?˩eZwQ5ϙr[lq[Y"Rďyʇ Cg´bm.8WFEDҪWj G_v1ɬ\c(0EtQ:6mSTlS-8<5xsfsɠ-X0Q]ZyRGƴڲ uh?㩷D {ѱ/oFMlRv`ͼ#fns\իWȲeν}ٽ u"6vS咿sWNԋGU?:.u:UU`E#wWEŚ2}KG uMT93G_a]ܓ`)""18f|o7V;k˃۷ObCU[&'Dt!wYYӄ5WV( iAz}aòeDdp:UoF4+X }u|⟲?_LX*nj9f؄!Mswؿݔzw&5seF'!EDz326/y((Ys"bP mQ[DD<%%E> \0E{oi+5GL)Q~ԢB*ᖪ}& u"yQ,^ל^SRpEkձ)wif n(򾥕UO=g}Tb.Uz?޳v[^\=kF;oSBtx =y%}c]pH:::":G6w|kWn=+cCpKe`WKO6)s6aَpqܻg M}xi~oroQEDX^)Av1+esvBıW?>CLE m;wOG/L]Sq.($XWj޺;:co;.ԫOOx-XW.g ?Uu=e&'Ktuɏ;C7u1>*>ڠsF.=EO{΢pdž!a?<1 j%C_~c< ?.iytA)b~RGHNE-xD||f "T/g@uRUtI1ydP _./O|+7)"owhdы>WyiߤϺPD2iӟ/sSs=OwCA]m*/O gԧON"G|?4kBgkWVRLx-)HjjX»\֬YӣGe˖۳^:))۳Sk+X#4F`h1 Ѐ9v옷GZK.SL)/ q x{ェ\,b?smڴYt飏>}?xM6:thn֮]^C`lҥmڴ4iRjjۧO/"]tYz… <أGaÆ9r Ç۝;w~wEQ v7O:u֬YydddBBnݺs~;paJJJD$11166mvڠAٳKKK ?1zhE)B,X --m…111=ᨶAvvnVسgϞ={JJJ*++8mvرiii^K.L``333{9iҤv}U7>ڵ۰aìY_mwq-7nƌ7owpiXň]t_|( GGGϞ={ܸq999<^?A}Y:gΜ33!w 7dee+WLKK֭[ff̙3gzNeF`h|衇~oo||޶m\~xhA^{Ex߯Do"ojٲݻۃD`("8~ oX,"RQQAZ"o roxS,  &9vW4 &% RUۃD`D`@D`D`@D`D`@D`npnytHvցe8SU`y̤԰",ڷ}ޣ]SZ)gYu5U.@VWZ,A۴jw\`?eq)Iml;2ٶ_m={ BO +VؘS1ș(>aʢrE p գNQ<{i*H-;usv7P5;o5*,@'ѱE;K*n ob5[m?,T}X v &9oUʩglbC_. SfEʓ+E=m(e~SQ]R[TT0""X['].1˥s,cr}PT-gn#b(-u~&> p,x/[~5XjYqڶIR%%GUNQ&E}g^}ZQ]NǣJqۺ}FBKFDuknp?xW ״Cb%-N]=;d<VoYuym,fB"VyWYphA\.*F-Aџb4Sfg/WVFD-_ְc p,xbZ-l*% Ȧf:\_dW" z,}X㰝;r5jPgޒpbvzAXё[CPmM]G ~YW}Q+**-V.@)Q, kutU+-!6cբ{$SOdncަcU j%scP (gF/޺函*EQ,շǣ*: pQ,hޛJؿQJ@DbjĹv3vI=}'4{":$Gt86΂S`K3|%(cK ^G>_ -;), [dC*3`1`-S:Wn4hGUWDFFN>Sl"##=@`7NKK@@c,X#4F`h1 @c,X#4F`h1 @c,X#4F`h1 @c,X#4F`h1 @c}E0SJz{@=F`SKy0_spT}on-;YGOmhm'"Yۺ;g5>&دnQK6~orTlm85HQncHmU~|.ͬ&v'}p9XԢ%o=?՘0ٮyL^eǖgoz%&`|U;Զ."ڻ=7{g5S<ɉtD^{XNŵ f#3+=dwZ#?t2(&YuBC-""jqV~>{nvն{-cTSa݆My󑗮.u 6\@B]7gH|di=c DD바׶^ŔĒ\R,Mm5^yXIl_.~oɲe綠3kƐVW?Q7X{ܘtϤےFOpI o+۰r]DD,P϶^*\ܽu={)d ն{-cTɷ%vX)\/j3ٹK7e-phɢey)`3Fŷ4|Ok__ܪR}9O|׭=_f"W?lҘRN|wCmݙ^\<|E vZ)+g?:9\G,IDATa7,_o⍥JX۹.TuQ9:};؞f]]WUU~\Jd K ȉ+v`G&G}cKG=ak|+Cچ}B~XRay9PpjM)HjjX«\ǡ DWZ٬5iqa/ѽP'2e%:>8xW,Cypˈ_YtԿǤp,\qw?7eSo}bqi3}a\^Dj[|Xr&?8{4h1 @c,X#4F`h1 @c,X#4F`h1 @c,X#4F`h1 @coRYnݱcǼ=jՠAݻ{{ [O<7|)P}{{ g #=K3??DoOy{/r1 @c,X#?YZ~jH{z~T>&n<`KG7M8 #D,5Qt:ED :rAKĥ{ 8WˋU#Btbs'Rk69^jk"|pr\.g+}|Dt¢+ 6]{{;:=5l|Ԟo=6+\)6+..c^UD`؆z%ETNSR\R6}E*}5_Qgl-_>Mڴn{L){Lj.N;xosO7gdl^`kGQ^QpE<' GheJU ?ftE1& iW>SD`^( 'SUOY^^*eջ͛7o޻+q'u{{;* GOXtqb]Y}4oie q(Э.qjEߨIC0߯z#/"H]jTD|߭k}ζݭ[A*o{ksǷ1Zv3a2<Tv|dy}SSxk]cC/GSXt+.t@N}$csC<%?9OYWĹfcwW'r>y?w\oO;QP]̊z|ٜ7qՏӻws~XLQ { 5Ͻ]& T\k 84nOD rthքF׮l~iߤϺPD2iӟ/sS paNdOMM+Vxw*d瞗^zI#k֬㒒ӽ=͜ZS\jy{ ,ˬVkIIhjz{ ,˂ =@Ke-[-Xk׮%Kx{f,ˢRRRf͚{  {=z7{{,u`uEEE7/aʢrE ,QE(½?4wMmغ9;hqq7آ%NXRb7-ᶟTgO`oUʩ%%&V?E?C_W @=:KK+"'W{oP$"~!*"#T-aEDDN Q\b0A/nKuW_q:7.qC"&Y?aW]N*\QZPLyA PWs\/*m*jI)]p\RrZXѤH9zէVAbcu!Ҝ۶6e湛֦4[T3Q?nݚܽI N"CM;$>X2U+G]7⬺ܼk6RQ^!bQ+,u .K諯(fMM>%Yخ媄7ƥy+vEe ;RVBMC^Dt!q=ROksGξF[nP̶@Ӯ_7+:Rc1װ)y5)tF*"%Gv:#@TTTZVzI)Q, kutU+-!6cբ{$SOdncަcU j%scP (g$DfXb6WQK_+[+"z<#>R̶@޼|WBV"S#ε)4Kj>qĝuE1vI9m?|)8 KL-pUsKJPLǖJA|.=@ZvSFWS[dC*3|e @c\3u1oO\|3PX@}qƆ z{ Ԭo߾B`)Pf͚y{ [ pE#4F`h1 @c,X#4F`h1 @c,X#4F`h1 @c,X#4F`h1 @c,X#4F`h1 @c,X#4F`h1 @c,X#4F`h1 @c,X#4F`h1 @c,X#4F`h1 @c,X#4F`h1 @c,X#4F`h1 @c,X#4F`h1 @c,X#4F`h1 @c,X#4F`hИHMM$W:Tp:t{P)zwz`h{ $DIENDB`crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0018_Requirements.pdf000066400000000000000000000276611415120503000304350ustar00rootroot00000000000000%PDF-1.5 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream xWMo7qyM @hbܠPe)M+ىc-rWd9C!hR{E#4>#GZLͧ\-nxE݂뙘 -$o9'1Z ONx|/}9nSn?+㜷 (/H4ϛv&GdO2r}{ͳ]JK~y#G&d2 ,f:q1YFӝ 18CHRun/z6ֹB0cݾ33T5ek|+e.nZE/xԓBșѻl(C>ף5Z `ݎ$%>}xLl(}\Cqbzs;Yg܈l>ך8:/_7' [L4Sw3iD5\ >p֨TM.rɤ3Qv¡H*d4=deŋ3/67>8x*O&%1 r9i}Iaٿ`7 0|!XzK2ȫ,q\V$띑}dd9U(4;>id Apcfp]~ Y- qQEPl0*0X uJMT&0PP){ u8E(;В#"Jn+ͻk,%JO¡FmD%*8(œgaY%CO&Xn;PA (u"mι}|֡hAa-wMEo0q^aiޠyjԆd*G};A:FyB(JwJޖz# E%™+݂}hw] RhT `enDp)\@;*5ܔUJk8ݍEfw>")??4GuU=8{ٰ~Ӄ4ЋpUXEI^U?YTP^U-AcN8G≨OY}3\BJQf#樠zIT +vxb[Jv!K.WȏI$N?JSE;.=%,8\I]/G^4DR|0mrM#wG 0gx7K }W 'MEm* endstream endobj 5 0 obj 1259 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-1-0 7 0 R /f-0-1 8 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 9 0 obj << /Length 10 0 R /Filter /FlateDecode /Length1 3640 >> stream xW}XTUϹ23\t>`ȶV`f@'K،0# @ YǏP5ȴ5pd]ˏXD%E3*֠\}4{{  §rg}/`{Elg1$#Gc[p C h !ѣB "Zi' v.i͒ł_@0uJY4 ݆H0Ƥ1bJMD8lNv5Hahs_4F:!8[h],lMA*ם1 m*6[0Xbh Jm\yCnm|-qYze ksiI0mqKNLgV-foRpRX!(Dm6OB l2D:jޓAlŠ*x{H%{It5q7j P>zy;h1CQ٦hh8j7O/Xr,tiFG7.R-qPL0#$ 3&$%M@0Јx26Υ{10q%,S#oN침ݕIceR8owqZPoʅL<0?pRc//w^WxyO&ɳg%D̽6L~:Psu2}r^bWμE>bfH Arq XyaHtD@oWl_CΟfߐ2rwru~m-rg?EƸ\s/S!Kݕm#3N'Bq,r~mJIH@,E} OxkYit[4{]gf}_7O?½-!FB%W6+(€' !@՞/":\snAÙ&)vC|wyiZE8xϑ]~"vvM]$0x&o@9ū+^;>P^fط!Z"4פ>SGw%O?t"'}tu}*^>e3$QƐTŗLA1p;9ʧ01RvȤGfs6`s9Zɕ[*XwzdB05m{}?=ބtnq?".L^֢EBZ(Nahoh7Vs_}.?/Ȕ"$ ܟ/L3 pobc8ǒ%u^S4Egb|G 8x{*ǽ^Me2,zX#r5NՈϜX)fE- ALJBXKsy$ #U,]K*up@t ѳ7z{7K\dYd<1oFR"IHf}ޮ`Čwí$`{_v!NI-wL_l@p;Q:r~.-hÌwS ~܅_a4MGߤO.";zqaI?-~ݥ-N[?;J& Y |pHvKUA?d~@pӓV/} x#Lu0_c\P-qNCۉV}Dіeq`&| `=/GKó+3ޑ͉\ N!U"ۊ<;G 8FЉwfpTx=P[Ѱ<ú<Ƕ?bo@k"_H?ט* endstream endobj 10 0 obj 2599 endobj 11 0 obj << /Length 12 0 R /Filter /FlateDecode >> stream x]Rn0+|LI$ J/Pi?KTeȁRxf^guʳ0V>X[0{ nGwo&Yݶ0nR<6{sOs at>wDu7`5 0pڿ xq<"T-,^]> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /ZTJKGW+Roboto-Medium /FirstChar 32 /LastChar 187 /FontDescriptor 13 0 R /Encoding /WinAnsiEncoding /Widths [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 568 568 0 0 0 568 568 568 568 568 0 0 0 559 0 0 0 0 0 652 653 0 0 0 0 0 0 0 0 0 0 0 0 0 624 0 0 0 0 0 0 0 0 0 0 0 0 451 0 541 0 523 564 536 0 0 0 255 0 0 0 870 556 569 0 567 351 516 333 555 0 0 0 0 0 335 0 335 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 485 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 485 ] /ToUnicode 11 0 R >> endobj 14 0 obj << /Length 15 0 R /Filter /FlateDecode /Length1 420 >> stream xc`d```cp``bPHϩLP@JFnI C-_s''?@~M(`Pc[|Vf @;9x9YSQ F'LnZwS߸5<*11-"& IYMMM̌ԔDELmW?/]5W'}fnSܾEe\cb Rx~  pC<}$NǾW8\N ${?A~Ȃ#sC ^} Y endstream endobj 15 0 obj 363 endobj 16 0 obj << /Length 17 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> endobj 19 0 obj << /Type /Font /Subtype /CIDFontType2 /BaseFont /THFUQT+Roboto-Medium /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 18 0 R /W [0 [ 443 582 ]] >> endobj 8 0 obj << /Type /Font /Subtype /Type0 /BaseFont /THFUQT+Roboto-Medium /Encoding /Identity-H /DescendantFonts [ 19 0 R] /ToUnicode 16 0 R >> endobj 20 0 obj << /Length 21 0 R /Filter /FlateDecode /Length1 3920 >> stream xWWT>az3CaSBJ@E(W-mٲ|n"CQ+7+ޔ*0~hZ3k}ۿ9!jM(?QȖB=J+\dOJ닅ND.|f_4z΃Ul}g!<7st%$@"'!}B ሊxoGU+j=)ZA NzHj .@96$zLvl)[<4BʦL_@f'J ZC0{:˗URtYh[>K;K,En `4QrdckªG* ?`9hm"AO՜ä2F%d? seY6mjz}K;qj!)`9c|ƾȤq~B~W t;A. D.=/+^(F -Yf o,9wG>d,EC&5j|8~.а܂E|.]b{i@!uIO^~dh ]\b!AL!YTԽu[Ps%d D^1h4y)b\y;G9x*j,,/ݸ\vmj}""؁CYNߵÓ :Vfx u[U*bӚmZ fa麠4snq߾c~iT c;dI1@#`R˞`p ieݠLnQ\XGֽîP}<4Փn$f C ш8R6" x隔lqS.;ܖ* :8KNA*1܏a q7n*Έ\#\lC0b~?l*+7R^ago} A>>X^Zh?eﺿ091~mm̞~1!i.^TWcݥNT|Kw*vNj|6=;qM $G.]3cvRdpj mYm.Ʃxa"'r:HESwEet45#|FGb1#mێ8+.`*~+*f&;ehњنB/E# kw}C2?|0I)YKVN_8tt5܀Чh-B5{K୒E;EA)u.ce/JOHHnafLZZLtZ7Pnlqh%ugL>r+\)/50ͯ?I { 0DV߿Pw+?N/{{1Np(<G׋f:wZ.]: ?(Y[|B(w8ND>]Y4@X́Zv8c'5vAO- kًas@%@T3װHǷdnY.? L!=COOeMmܑ3,N>ffqC_@8}y9U)Z6~NP*5l̠p+)h`XqV1u@3ͲTwl?bDrh*s*\>@C:p#7)II'g'4wߍI&\9rvȱ9ƬB5vsvjl,Zp&?49ڲ*vL `+[Ae=tDZ7|,v NLJ AeX\8h:,ZU[R -D-\^uxێ1ȹjlg*rK)}g<`8ʾb3N't kg7y3,m!Om.>1}YV֠=w9z^ew\(|d}=rZZ2;TZDy_=aUc`$=ڟ/cA 1d[LTDjohNE]G\NJ AMMؓ顟pkKT0߱_3U7:k41l߸hh ;+;F"Gl: f)èG-GbI-,~s08yil5U3S'vlZt)2s}{ +Z]b}_o2nmFbbzzbb1;joS샱j/*{]񁑁͢ ;"3!/s w a3l60~Q|;y.\O{;uXi+7bpЛ&he-{ bu/FaFkGy_/٫Z3ourC}[ΰ~-xZOާ.d_4W=Шq? 0+Hr#H1‘KcI L{)$O ST l߅yă&$&Ej Y|)Vc~)ϢH=Y =TRD"0:=4Ժhхzא <] L\]DNu85Bكp`T:X{~VqD@ٞ9Qν^+ogbͥ endstream endobj 21 0 obj 2750 endobj 22 0 obj << /Length 23 0 R /Filter /FlateDecode >> stream x]n0~ Cďi$J/}1ȐC޾^OJ=,;3yCq{V9ZK${:^t]ooi,(>^έ&425\M==)eџpDx:_e.{hv/ڝIfIm]>mu|^gez/0-sg)tDla/ȻTI?.*ckC4JX/P/".q> endobj 7 0 obj << /Type /Font /Subtype /TrueType /BaseFont /KACZEG+Roboto-Bold /FirstChar 32 /LastChar 121 /FontDescriptor 24 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 388 0 0 573 573 573 573 573 0 0 0 0 0 282 0 0 0 0 0 0 673 0 654 650 562 0 0 0 0 0 0 0 875 706 0 645 690 638 614 0 0 0 0 0 0 0 0 0 0 0 0 0 536 562 521 563 540 0 0 560 265 0 534 265 865 560 565 562 0 365 0 337 560 0 0 0 502 ] /ToUnicode 22 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 25 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154042+02'00) >> endobj 26 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 27 0000000000 65535 f 0000011347 00000 n 0000001521 00000 n 0000001374 00000 n 0000000015 00000 n 0000001351 00000 n 0000005191 00000 n 0000010882 00000 n 0000007097 00000 n 0000001739 00000 n 0000004433 00000 n 0000004457 00000 n 0000004893 00000 n 0000004916 00000 n 0000005778 00000 n 0000006236 00000 n 0000006259 00000 n 0000006561 00000 n 0000006584 00000 n 0000006859 00000 n 0000007260 00000 n 0000010106 00000 n 0000010130 00000 n 0000010592 00000 n 0000010615 00000 n 0000011412 00000 n 0000011529 00000 n trailer << /Size 27 /Root 26 0 R /Info 25 0 R >> startxref 11582 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0018_Requirements.png000066400000000000000000001147501415120503000304440ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxw@18!C@VT\8J2-s|헸sh̕-\(@TBd("Ce>?PC|Q@aYxx\7k֬8nKh:tf7|$&&;w*iJpCTkԨQ r@#+Ly*% ץQenJ;/'4tKVub޳G1.==wS[r䙒6(^cȋ?Y2|ym] U\tP+T8v3-vr0DlEvě:E+>JpUY//Ckq{q&o)2{Y_\-&;#VRid66Rӏa  @/Dlѵt/ȯ5/RjԨS2oVoc(HKϾo`D6rMJSKw]||?mݜZ8G^mM k`0´JY"CiCO%>nl/Hͭ[u(*aYMqq^nbao'ת50&Nhv/*1|'K% 1{ ?ߝOd=s-{RߚЈ1ɑ ,0 a[URH ihd 1EDDcoVDDıkDf"My: |H ^cDj\X[F^<|Hhۡ!"T.)Ѳbw`l 73o->qb/WKD֪ӈGrkU$81I.5 =i&KofxKRF5>uUmx+>]&k63>B*lS{1ȜzNߓVE*OH3},K!jCZZ߯a~yEj2J"6otuEfv^\u-GsFF܅ýWĖJk{{sEuYz{'<<ȡ0Cqzj/CVz]e bd.^|hΊÍF97 ʒ!o +۟,p!@>I[Lhv_1z #:Yeox׼+_33㼵> ^?i#"%;{k&-ya?*d$=󮿐3E4}>ܰA_z~.V:i@OP RNG#k+KKSt,N'@,뇅>v*aǟ7ޚteΫvQUBo3-? -DDV}9N6,?3mR+]{̵\7^6:b9oUC[BU쓂]t{ZZ)\?i[s_ٺbҜW>W(=mQQQ1lذK.Trg_9E#zxlחƿ?C~?} >g[mUVlW; M~>]+Wt{䋎O^0.3_+;W46wU+hn݋Cߛ0vdz6t?;z" 鿺s6¹x NLSXi, ]' q9.OZu @7`9rR.,_ĉ[n3f ׵4pX >tP XW :t ߀P(a)ME`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF`dXF&h***222nݺUXXXTTTXXxb@D*eY"***""BAD XXXǓ喖 NNN&&&>h ̬̌D!I*D"SSS X\3*UTTTVVQyyVʪdZY[[;888888999::zzzz{{;;;xƧR._TQQQ}HP8888::TRyo;-//7Y=FD&&&^^^>>>;v޽\.7k @'$$DEEEEEEGG'''W988x{{O<:xyy]155555upphqqqRRRBBB#""~'"xݻwuT!4L7 "h\233Ï=ZXXHDݻw+;wnȃCűՉ0::DdiiٿGe5ZLSgc0"##d"rppxW׺uk |Zr_~cZZZTTԱcCD^^^|l Fੰ,{̙={ݻ7;;Ĥw:#KLL ?qZ1bĨQ:hj),x7ر#++K*xFqtt;vlHH#ץ@Of0֯_ѐ!C^Cs]JJJW^:u0uLSh4k׮mӦ͐!CΝ;hѢ}=y+"dcƌٿZZ… cbb wUoPK|nnn3fP*w\xqV.ptt\dIFFƮ]Zl9}t77k"f@MX@D֮];︹?~<22rȑB"H4jԨSN;veƌ֭\ ӧ;weʔ3g4}95qe˖777!`4/iii }D"ẢI"lذ_~ٳgzz:@BhF{RG igV ):@DDD #X[ck=lbS֝_'Pa$5?~2^ǏT* 4>X˗{i0N:ս{w#ݕax|>E39ÅϝH-<2w{knzIa;w~nF߾}@PTT4|pPmߋt:V[B$mM< ˎ~1sO*,~l@[֙UpPOdd@ >|JwXM`x7~7/;=V%GeE}=LbbS!ɜ[Y%" zô[%"¹ۈHg.WW~-##cԨQ9@h>裃_ϯ.a$R1CDTck-&t_x$vXF>SߝF}9㛋^NgLU2~>KUS(5ru.)B)K<+=G~WS"?& mO]nѮfK_ V\Ӈ~~~k׮ _xq @矿[&L~t%,Y{BKwEy{ #|Uq~ܲ@)jbG~xoM\z/?w[*H4ܖѦm{3Sbc.'|?Tưڄg |4RE*,L>RSj_Qhd(,(bx +Eo|ͥOyշӋ+%txQ;ػ봶.?=DDo7n/_SXMܼy ŪUK: arak.TqԲ~Ǝx6=L2ҒG 2eNќ!IqU)GeVO-2 Ww[>cՊGd(VW (f1̷ߞP-Mu^1{-+tp0d(/,OCV^mnnGg@:{ÇW^P(' Hd-ݺ;)AJC֠/+ԳijTI[(P_,k(SDvn9 #X҂|Cqo+-/bDM?l[,ո^ahmm`t֭>.` )[~\.4iRZxLQW妞;AJ.a C[wsnxVv"bL2!C$u>{}?Q^]:2dȏr/.~ZrqR^t}{։SdkPYfZJ}F_GmjjZυ=9a6lJ('Ҧכzߓ=:潟:94끱2 #|Yˎ\/*I?{uij<0/*2ẽ/6rh_߻woeeZvժUfͪ+Nww}]vxSNUTT :k{<-Nʪhkec>>4 l=v;jg?f=-yY[[|emxShL$^-VڗKY:tv0l<=۵qYUڪKZÆ +++;}Ç8Ю]w}xP4@ㅀX ?ȑ#bxСtRbcc G3p<gRI;cݜliQ[ >$cȈuq4L;0#Q;F;D~`O+*YN!.RrUօ@abcck6^r_?,he(((N>zkҥD4a„Gfffr] ԢUVܲe T+V|W ,={H$z@V\QRRRZZZRR2e쁷QTTԏ?xݻdɒ uaa^ߴiSu8ҥKZZڌ3ϙ0a{߰0ɽ`:rN:=|zЀ;v?z`/p ٢),,ܹsgz=,PXUUsBS}>)Oر+'''88^>}z˖- 0EЀ$%%7nVVVR޼ysѢE;vP*˖-;v,0oƅ RRRxx&]vݹs'߿wIOO[gggkgϞ}QTe˖#Gr]4554 ^^^Ν[dȑ#uڢEǧ+ZrJOOϽ{Ο??99yܸq SFFމUUUedd RCMLL\bEDD… 8-i KIIԩouEД!`4byTWVV>BhZT`#F|瞞۷oaruu=t萏ϔ)S,`0|駖'OܿJ}eСC\TsA׷ooW_ Z/H*.]׵@Xx;wgϞ`kkO?sax,رgϞ666Э[SN|>kkؒ˶ƔgToРA/D"1ЈxW#QFq]K#ώwٴt{䜶}`SnVCeokSv#ĔS{؛InCFl^a^6f2^sd$H-ώ P8vȑ#GE"g}?QL6mxb'i'/:{J^˴ח {Fˈ-mRϹi<<%lBE9V+\=~/ }ʔgڛu c%%%o"jDcǎӧϜ9sx߿ѣӜB_"|6_m{M%h&hpG9n]r227evۇv+75M1 c-dB^4#X0Ν;_z%JUw >t֭\8Xv_4kx;񚺖ԍ&ytRQ)Mk7;A/9[h*&( I9_@5,i"";;ݻw3Fi_P+^offfo\8H:_nVO1-̼zoa IDATR=[Uv+~$+h؝=wb}or|Sӣ r-?9u7RP cĤ{ XvmHHocǎ{ązjG}͛7уrI! }F_9ɶUV |mS/[QA;|m=hY?^?cd۵&\͠7"8|AМYDҥK롯u͘1c{TDTQQꫯ^z\:y ۱cGk&"h@ZnmeeU?}M:u }vtڜ0ȑ#[nEjh4MZZZ]. SKII&L`nn>~;ܹ- ǎ{7KKKCCCu9MzE`4;#Fׯ… X]reppٳg&a|:yyyEEE3fʕ/^亢~~~ .?~۵kuEP;`ABhLMMm۶s];\ոTӧw=++k[l; 2`ABhFz^J K˸O["##bQ=z𨱞6bʼj 'N6[bHmkNxX'hG)TN]*MԮG=zo_3F"^{_b5*Fd#UH}̓ "̎=tf ms<}۪R̥A>Y'{- jDzDli 6ǰl!`1 W_EFF޽?سgS"y04lUIZ"2ӢNN.yx'g[Sx .\HOO'6V^xw3z_J"L# |tVwez*"J%-k*@πݻw֭KKK;r׮]j*@йsgooqr$=[*a21vuuI 5D"ѣā=+N89j)>la59MZ"2<,.^Wy)x2Gg/fZ9CX\\\BBBBBB***Nj")ɽRjf&NcII 0[-plo.(Pd"s<5UdvtŅѣGݻwh8P(?1114hРAH'$$DEEEEE=zqrrrvvvtttppprrrttT*w1t7ofeegeeeee]OϞŞnN]2 MQʶMIg1PFizwKA鵔b;;#[SrnZm$Auڽ!"bDR)Sr+RuڋbjT&5DVj  c׮]c۷o߾IHק]|9)))!!!%%%666//-ZP(5+-,,H TczF!RNGDEEEZo߾bccتKg>C_oͫȌ;xRg%bGʶbO&D2;2HB|tDPP .?ַΝvE$H۵ y#4nL/sAAADm5ꌌ̬{٨gL&eʪe˖dCeR-J:qQk@nG^t}8ѧOǏWj)`@}J:AӕQYYYUU "xrD")?$#h%f~e !$r IBG TK34Wn'b;/_k_  #RT*.&L@sqF& #X9rdhh(U1!`p,44\WƄ`dXF`dXF ؒ˶Ɣ\Uttktt4ׅ@ӄ m˷ XOKO\\\@x j:--MVs]4MXOώwٴt{䜶}`SnVCeokSv#ĔS{؛InCFl^a^6f2^sd$H-ώo.v̙39|`tXO(puܔQ~ b iNyq%w FڷzY;ۉj[aH8mnB9Aw!شv!R[~`"/>[KVoH:_nVO1-̼zP}PVRgn;cm'zC컯`Mpjzw!w^_'6fr4YxBDzr˓m߫'M^s'<{˥lamx3{%U_>JTbf O/[y#0B*6q=auD޽yQdW!aā_=YԯfV;2vEMwܧr8 Ho`LX|>jrSNZF/i:&CĖ]{%M!ݥwyN_l/ *lly :ﳹ{QԲ-vmֺւGVN GgSKt~cWTcI/ yȋb+c#ΖHSׅ%[Ŀׂg?Y]v̙3 3g/]w K^=z./,]y!vעm;֮~cZxRDTt귉$y |gӲe~]<@B[ }j*WN/ݻ3d;wUajFs~K{}_l<"C^y Hlm-x?VUTTVܺu֭ =KjK|,tW3AGso?-yg4|{[! q{ `'#ʞtŐ7[ lYZQ?=fyApy <;6ܿ@*Swl=Z2ҮIp蜖7'9;ύOd}vʕ[N>uιmG/=WG|`"*Y+v1 0Wmn3|V9ѭxOXu,`_'xzk;?%bUHZ͚ƍݹ.&FO|VݹB3DEG[<.ȫX( /gֈ єh\.Ȫ d|RA5 TqՇb?T}߸wh4RtŊ ,0LSxa&xs) r<*++H(>LhD=FyƮ\WlL&0&@b"\Ƅ"BBttktt4ׅ@ӄ%Nu!͎ZNKKSO>!`p饗^JMMmѢׅ1!`Vc igI 4P0tv1d#fݤG=b羘 @jc.؝cຎ2Dܼy322*n!`5b,PCFa btDDUF}eJUğ/>B*9t\jczVH%r6^,?cc"1ʧa7q[gо\"6mkstobQ;q 'sHec?&=dڴi/+ ҥ\.oժСCu:]= P*!!!JBi£r)S@^gZwy{.f9Wo9^!h*RfԶm;/#""C_kVLe"Cy?:YL\/}a}T|L+JܾT,v6x>c9rG=L0;;;--ãK.<~ƍ,|o~>ZɫJ^7*j\H>.Ab5CJ'iT4jwp^[X薡D{;OoڹTr*+0 ܧ|5?}2b{˞wy"E !:]KȈ4ZXӼ/'ܷ'q3d(b/D+ԓ>_ Wvӌ3k-OmΫC+!`5f?M{~E~- ii!oȲ羽^v Kӫ3i){,8/k#}/6- VX ]E_J?RDEkgw}'ZyQp+~ض~螹>"Iy"w,x--4s5auXG]zu!41,QPPEDDp[Msv̙`k8\ѧOǏWj)`!`!`4GJ2$$DTr]4Mx!4G7n h0`dXF`dX035,uTMQ hVub޳G1.==%WN)i3_eڂyzν}[Gs>Qe^K Bo'O1`օl[0}Zi.$(՛zvl$Y* .^Rwxv Q42ޔyDDٗ.{Uqi%,EY' ּK[x 8pbk ^Unrm^m+R.gUF)R55hd!` ,POBV)Kd(8vGy|{wWsSYK7wGSW&vrXSK B_o`#`+K δ8HGx k@h]]].&LتD*eHsE\$4O)""2;%"b$]Ej +2DDλ[ӑ@g>u:V`^ngfYR t-L+Y]%T*QhYSS@Vj5ׅ@ӄܻw!GS~/`ƺ Z"Yzre#3T>]e µTM#"]~Mo ѽ{%עfSN"b !^sA-$iy:ߎ[V;v r|ebkA7=z}ߟ* ɂ ڵkuK.\*_X up"02,#C02,#C02,#CzҒ $2;Ϟo|r)[}X^G^IDDR.ٸ:BSVdy=?꬐Mm{OX꣏34w x<Ֆ妜ڵ̡'k'z{?{PU{/^e "2 qL4KUJM3ge_44ˑB-Qqː .OpsrmƷy3͉L VEHH8m떬 vO~Mx\7OzPi"gwbV#A/8v##3n6L}iAw f,0 pl?y|73FbwJ=,{_uԚ#|,{/8OČ}+7]{Ƕ,v9> #6bBdD$=?QSJJv0e?' *[IeǀMjC`@ܨn #'9 Tot}Ǵg̣z2621=OLNL[;#[; %f$/wPޙIw94Jf&D< w%gsqw@EwakyIO;zffjrH$aoWbEbPCBե&z!Qk8Qk*[vsXOTMX>LjlnNja"%*9cHL_VӢC{?s{ #oֆ6TX_zp(9t0yBDŽ1s|Z %&'+1]'bRHq޽KW 㒢X|J^$"2R+ P!Lrts ײ5ȟrcŻ67%j4/Ji')I)Eפ$gvvB{*0U3Z bڮ r+jmmĀrus.5.Xv>ߵawq7LܿlXp]DRFBu `&rn%n`Yu^~|(W0XUt922еJ)E/!ǀGN:Ʒ_tUkc64te,JP*@%CdXpŋ[hnB^zXp߽{ݻ߾}\ߋuq26غ|g>٠x/Ƥu>9lkk#'H3j^}2]M3f_ /1,]v ,===LSyלGׅHv% ɉ{Z ):WcӁNƃ>-_ |7?4Ul|s,904Se+<\ [6p""1ywbWZ˾Vr ::z˖-YYYx_@,[F/[ѓvvvhQƍ7xիW/]6O$<:󚵔Hԯ'l%8qMHDꐑE/-ۘ0ѰYQy]q9EZ_Nh !"vl+V0pZ$YmL`׽n9O5ua'&Qi?0٣q_ٲ阚K]48s&}ݩ|`ˈH}R䅅-BsQ=c?N?c$u2Por~fuQ#[&D1kcqʩi_Οة9j :]tJ233+Y3iiiNztFA㒍ݛ6mz˗/>}aÆ6{r̼UۦʿD} C7u=HCxg˯i3wݹ3C*aKz%JJȈ;g2Eo%Yн$V 7On+:]X7-4o1z S>횜 lQ:RށS9c?Yx{Ð7JXtZe F~ٹS`t>IfBF_7mzs۶m۶m[P߹sUTZvժU666RtĈ)))H" ~^ʳo\+޹{#wZ$rιFD$uޟG_{, 9˹}kJJ^᭦>>M{,p>=[J$XSX|fZ~l'gDR12Eγw d]ѕWstHRw\xao1sH>阖s5Jd-c g4 ^s[]dݵml\Y@LhF3DsLS/=z 2ЅTslҤȑ#}||VY>`1gĆkCk`/zlf/ L?6"s2TL̩k2R2jב2a&n5D)#4T1":u%D<+#ȍ[Hеg =MWݴJxWtL; KIO涏~!' 93&f(=ջ U4VZujի=zرFٽ{sX 2Vy=1O_`?kRsRR 8nĦu֭[nz"Isskͬj;UXxNDMѓ`۹rboS29[y](>SvfH$X{9)zNUMe@$>iP!`Kcʕmڴ޽ nݺ6k֬gVyH}77Cr"n?@Js~?]x[vsyg1el3I$u5f 5Gs"ݥ͛Njt0T*HLN-cۿ/R`$'ݻͦONL+,,x9ܺu+66O>.:ر;wfϞ-l,k _ݶx=>LH]HI$F$%`(XQsI\=ݤg6p3,Ƃn6ƺGvl&Zg5g)Yۇzz6W{a5'Zْצ,NZ#uŴ?2g}ch~  ƳC>0ūJ }YQye\CphޘFJypb;k['mL5CՂ/W gŬsbǂݛյjޫY#%%Xoc{$f&e)|&>qr<'Cm?tIpf2Vw<5N2j5af2"sO0(y?jk+5m{{m έc:Գ2"uVyjZkVNf=nV'.c`}EgܩS'Ct922еJ)`a `K%<,JP*@%CdXrؼyof*w#]#VJo;|2ALܲ}Cb8PvbDU%J$,BU[  N_97i]S{=Lu2 N?w\\VYѥD<'i@QkM7kʈIR&5/Y-1t^!`Tg.)ZxY[ѧbSJ Wy6%>EL S7KYZ.R͍J+w #[R iIz{o[),LL)&UdP.P( o$fy?AD$=t*^ˉ©y@}BU2""tԁt$JT*!N_U|;Apla%V<Yz{;KR(p9 ,x9xuݍ9hc `lf̘q 9&"ߕ,&3ʯଏ> o%jbDD<;.5^w1V99GG߶jUG^/*@j5nv8NGɭ"]ܪv-նIsf]6NHWU@LRfp9O15MPs  ~`Ilk^wþ4YR0_NϬaed^OQ"3ͷqW]P̼y*ߥet1#^PPT0>X5!`T D `׽S#+eE%rc{56;{dxhrhUň,]9>{,,NfYR "]xw gy;x,y4mH/ WU@EBq=%Uݤ}3N&qoF#V="ӱguo޶ęiYr V*,5qai*.:5\*UzE< w6t PD_x9 ',x9^gB^u W^5tPZBBK `S:tKx `@eias _vjdbAqFCWqww'pYUyo_y}y&[;"]UK666 0tiѢE&M2tP= T@p,8:%%zߑu]M[:[\:?v[?3m%zģ}wfZvVMD<%!c% N"ëeΝ'O޹s  ʥv#|xE5KV`~mw&EMmo8W; seiKRI2nQw^N{gے࿥h "0aZ6t9P !`@y:a`QED$qػ}3QI׾רψ?%e$}jm,3D%n9xfSNv3{￿rʤI]?<6Mo6m|ZAz^mmBAaaZ{u(}ebK_RUxxhhhhhsϟ߫W sܹ. ,(;b>u+.7K.[?#>tGLC﬍èz;SN-((Xh}fƌ. ,(ⵙ!ACێٵw׃,Z6l/̷]ſKJRЕ=ZߵSw+DGGoذ>+Zuرׯ?q℡KjqΉ( [ նm+W`NNGݺu#""Z})LSWEPPPxx #"""""ΝeC:U_2t:]FFN#C޼yM6,xU8::Ν; a^AAAAAA ^W&~ !`Н)y:{FZܓ4|8,Lr젒>BBvsrruCSK??ڹY)VfL!^u]9+jxC&򗍱M[6ޣOhZO-l%'}bk5늦ZIj;ʈt#~`꘹GCY#F<"iWE ߆2""Ξ-^h"'"jK\=A=2#" AxՉ7V6aOeS8 z7b5^^uSaGreMy׷xF3R4:NDĬm(đZ""}^n#]L̺#԰9[f턥/7>iAM1zU8 ѳgϝ;wnе@5,Wɤ_蕶?DnVwjvq.Jo:Iu0ܐ-8ѣ'ٺ{WLpo[, 0+LOԢ2Ndf Scs"  0VՙzGA%G-vZS{aaaڵ -x~%8CWqss3666t/3ߔ{J, "ׯߋ( r!`U111~~~k*^fB իW$3g (̙3s1t@Z:ud*4SSSC/L-Wɓ ]TOWK``j =X  a^.I !`UO#%>A*Tmz!ښ %ߡ&"]_iߠRajڪ ҟq͝-r[C%t.1ۏw0SȍbNU1A`D\t9b}OldT%#Gu1;"~*~ظ;{fO96$mЬd =AOF*Yf\/9`/O;&UW4$QL) >z6ϯ Q՘:N ?3#.ޗ[Fߒ4'2+<>Xy#-#̶[?5qX?sBީY1 ݢbBdD$=?QSJJv0e?' *˳/eլާz3kvz"1^HD-C,-=lU)o:t:]FFN)᫃3=T‘ٜZ*7 ucڳGNQ=UIӘ'&'&DMQ7(^bHZ}ַN'j"!"А+r  nlNR6NZ.{M6;iiGLMN$5JnJjHtTO5j 'bP|4jME{Y!9dTV޺aoOW_~.bX '5ۀI͕I-LDߞ#קմG=%W x?{/aIV}돦~׆*aՄ/ j](r8d%%mZ@kk-Pt$r}rRIml-"}~ƽ{,YZ^3%EzHDdW>sb,>'s~&OfˏsX#U&WcoL7YBbu;+N֠e33Fbo}VGLܔHiӜ^+@$$]_!SY%"1pΪ{zeP%@2@ՆV՟]-1ma6b@] _[9r9iUx, ?1ozRڰ;QO긍qlBY^"MσߗLܻqH=-&ٰpẈsiNNN.'z>7ob<ů[(%%ϴS[ZK?kYKebRܵO?~P~`G}Q"w]k FIr*ګ8#;WDY?2e_7 .Q1D%00Ѕ@Jy?I 3cK҃y윋Y=p쏹2\DFyمx} aۦiV[Q1u`ρo'ddj9q]^ڽR՜HU%ЃU񴰯ԳT(- ,& /59'" 3l5(??N:\iQ2ˏ N ܹsddkyujr޽.*KxچuX-< >,@UT2MAcڈkѷ_tUѣG^^c))եjٺй=lMUNԶ؝ilM.i&0ֲj")aٝ{0,./Xpt*U <fژ鯯5Ƚ3G%!"gc͡үmu<ǭu]sQSz W; seiKRI2nQw^N{gے*AY v}nUDD׎7=ty{^R\\vIRۧ2;#KԞ;\떃g;d9J_!`emFNخ&5yZW|hC,SΞ\JWYJ0,xM'}󩃯-\qZ1҆ơ폻ylO7ݩ҇\Yw aT{6IDDUDDӿ Q9)^DDC񔨢?d'<e@h"kt:]x6X_bw |@(""/gDD$.C( K`ƌ6l0tO Yg7N}u7[SĦko~SdK>M{ c vn=4%C=1Ƙs OifA;yo޼iBVLl7(pkyM~{ڡȿgcΫql^ab-/DLM;jTW111{]q ] Br~93̼;.Y7-lW7{(G29u{܃N7퉭ۮ><_?h/~SKW3AAA^fDQܹsxR^e[t[O,_𖧌Mzد_uhoӎ9{_QʚN ;: :mu;^6>Ɗ!#e&_Zdu' [HI9w7"6&Ll4lVkwhdo^f<{wG\NѩuW9"Rٲ^Z1ڭf}5˨2ESl#R L+ ڱcGR~CghjHD/mll>I&Y[[?y899M<Ѕ@U .?ImHVQ3i|.KI{/I\7nD>)Wt6+>EВĺ>ng.Dov"jgv$j_fO;v9"zH%L}vIv3DR qL桨=7l-[OGJ[v˼{t\í&JuK?m`JMOO~z2 TZoѣG4qƂvx!\\\q;"0sy۶m۶mp"##(88OCH9帶 ?ǧi%1էgxK!{ FD̬ӊZŴ=Ü%Dq^{#wZ$rι҂2"cZ9D+!$5Ws#7gr9WoM 1ACo7CJR'^S`F-3"zdů 5^Cupբ{488"##T9\{|ThfV=u i Vg1TL̩k2R2jב24qvu1u!>ԩgF.ؾ9^-x GB²81Su xDƜ-k?1_ٷTwe֓-UelD]Zrŏc*~8;/k/=YꊛnyPYW} ?5v? v[ٞ%IqeLfʖ_}@%aaQ}WLy=-]ל.gm94T5'Z8cs_wJyq#ˈ\=ݤ,EszfSelnOd|i5M>Hp`_L ?Yer 5~ νM[_PdRɻmH6b颾0l1YW:u]ɽ[8 %3ZokkX?Yu^L/sŦРx1GCY#F}!)Ա˜UKJT-m.xxVt}CGpz)ni-˦222t'dOP ;+hʻ ݝd3Bx~nHD/WYP#DDG0ގ,""11qCzt<ݖ9n{zY\=]-5;'3dպznqico8ܲsҾug-h7dPuKT}ko)Yc۬7-=7f\i)}u" +$>Э:ۏˆKw^}T1JŠK(,,̰ռʢ;udZΝ;GFFWzGAignٵzNvڅ}sݢu=ko:?W#UV-v>oti9ω;rZmk!/s"NW:fll ofrK},J"'11wr8sTX56ԦħH]mLTnN&B-/R͍-5YelaT&$9IzڶRwoqS)E b ""*""Ѕ@,0<.P( o$fy?AD$=t*^ˉ©y@}BU2""tԁt$JT*!N_U|;Apla%鲳brL|k&u%LTdgk]XՒN0^,01m,l:3n!gD$XydrFާ[xadZU:QX6}JYxtmVu2ՁWqӴñw\!45C%D$X{<ԃ%i{b Ҝkg98HB~91>mFRy=E[H̼s7^QtA;itIzgc"^PPT0> &0EF^N86mȍMl$ᱢʡAW#tm|챰8eo7K#[tuv5/o33?im%#(r& ^3A*)-SRuM:m1sjP3ƽyl͝-r[C%to^_Zi$7? /mIDAT0篸Ky5 ĺnVKBԻY)KOҠz:XqMn?Qg׽숴A?߻+bzLO96$mЬdh =AOF*Yf\/9`.vۭOD2է^9C1oXI:#F ]?߿a*<#`sԟvPbbfrhp6s[Dq"oe$6uKV~'&<Kss~^4?]t1+or~Y7렻bE{|{(M8JZffo;Z0}囯(7Ay1C^Z9񇳺j  * S8<#1;}+QkVupp,?3X#qlMaÿ*=#&DFH5aS sRћ# ^أK{7 z/U$"Ζ!^6ݪhS;glqm{c+?S\atngƟqDo|LODDY uT1XP1#Qcc GNdsl;tk,(쑓ye'm9;|Bͅ.8~nFRmsFpzg@1af]!i"3jW/'Lr礻05ټ2kOj.+DJT u1"1}ZMS fdY59;5>1vԎ=gY0"}돦.Ro1{_o%#RQR̎Sck2Rrjבyjbw<;l'LۯO]t?cD"Hƈ!9DŽIŒ"Hk[kHLN*9KI'bRHq䴼 F%EzHDdW>yKqSn5M`'l:Fr\4smKOYݳ626a#&mnJ$4T͋iNM_~`WN SRII), ~۸qӟ֪v nDIի$^Sf$ŝص|l@M#t1 3ӅGe;YvF-Y]L5^ZXP9Tj)if/˭EJʑOg `ed?g||[ד>~׆݉zRmp03esʊjO1h> IK2D,jR1"lXp]DS,ӹfq@/{j;a|BJ"`&rn%Fn`;K׺Q{>I;Tu;{>aFfyl'OkJdjұdDbE -7g$9.8D@Daaa(??N: \iQ2ˏ-PHuʪNOqdHHHΝ###}}}_XyPi 4@ՠ6³Iv+xFP?aSu$hdӤ+`母|UcגI- 7iE˙BUPX Jd*`;@%CdX  !`T2,xn<^c:zUصޝGY w&d%!e $1dUzեnPQܮZ)놭 TۂJh%KI $3b~?3?>]])ǰV?96)&~}V,[v?41[l掙cJy*_*s{s?"ynz+A~cJy_jZ[2E~vN]Td7\w핃|5g"Ү~XsƠ˧1pt /8rFuN}S4&.[2.=2Pyw~M?}ms6XH_evqN;?(z̘1cƌENNdeeo}l=徬7'5]a֡3DShZwD } ɝ QHoP"Rp5^%pV>80R(㍴+H*zXDݟ|ΐ~JD9y"/b?V"7']/d:Nuΰ.%b7 Z?5g(돲+xhMDc{gW=qyhB#ڽǡDE~hiǘiSoZaVVXid4)vaom ILdl5_y{[['Bf=Qi'ͪy8bKŐfyi)9rEi}K#_qC83dY]Vw.;{ijhfGuC0("WBS"G,I dϙ1Ξ2nɪ"o]3͒z XρRN~CYw_OxO)b=t[ק;yZĈ9?͚r]t%aϮS&<J1fWwy;㧗=ϵ0ovNNq.T=ꄎ@E`N.לakPJB17'hx|^C$7wz1XSx.vNE+5~KY/@~{c'z1(_ʙƶ- ~jEape;M{h,~inxua)Æ&7aTe>Ʒ"@ѻ뒯l*&q䱩v+_xWGo󦐈{&< 8w_Jv歟h41o\?!.%"*"0R]_4]Q>0ZEXŴtQN1JDEaVwƻmkNeMDD)s4|2ܾN;n!ks0gE\LdU}iLH߻Ss]uZW}>]`榆cL]-paG] 3g-kn4/ ޟ?9M'!s҃3xq浯}ûª{fzπŌI7I {ztiguR=/V7㖋tdB1W;t颻$ 4߸MĕqK=.ztpccuꄾqR}c=N!*+hu1&gf3+?;^) uPZkŋjֲeF5a„^f9š[>x)TvvĉsrrFkռ`1@3\Twg{?&`X`1 b,X#8qPނmP{/GŃFhv]Q﹁V:Ji]eU}NmeE+9$dc+)\]y}{Nz$bڬջÍS(WartݷltHmʠ{>-Jykz Ze9w6|}سb.U[S+ czG DBazDDD+}2ªՈھQݨ *q+k4掊{uѥu&"F\;X}`\%hW.YgWe#"bVY)%WGtmm88?1XIJLXHLoM%8oA32n3WY`:pbn26g!)-Rz{ .c4^. dI J:sJˤ>> stream xYmowQ; hmhc_ pO'qeiZrݕN',ɝy8/H(lRb{hِ%~hxFTeN\g_^t' W_ %jHW'$+~u ۾lJ9߿d3Kt2<ިRW}ѦK33PYmMԾB{C{达rT. ^PP()=|!27Gv(X;q4voYA DR_+38vj}ϋ=un/w{ͩC㵈Azr VheRwڵ|vZ0~ǟv3mExJɄm2Q.씓Ngɓ6ZOF{ :) IA1mc3<{Ca@"E;`r'@FI8hy2D &6R!z;f Pb{9!¥.1 ?1F 5` Sy|>4IN%lL$ƿvn UP9v$A拾h/#˞CA !a, Qhsq(;d`>KsƀuNk-kπkU51AS#Ƿ-~##7ﶷ/wϯwJiBx!^~v|J (s57[B!z alw>E6{|o)'}\v؃4tz\;<N-2*-8<-AtaTt/8ƄV6SUk5""k?&Jit$0Ox1ZR=g Ugn+3ñx3hHhR)f:iX I;>AX+Og$ YZ@`I;.pJΉ$RJOl29腤zNmr8S@j^%fp0?,z8yikDbdeΝEuJQBqAbk~j}dPnsh:;ciJ{9 сd*QGW~ӑQb&mqLU&ShNB+#s66`68b;(pa4̰K(W}g7: t4>ǧZƃ_ON^G[L)kX3N95yia4i; zΌ".~;y$6t`SX}/+Eۉb^1)EVlP7qX)'A*j7w^tA-%VAUBg:4蘚* )J0HkdXۋ>R cWM7L3P 3O+[Wz hs~U, 1'smb^ĬX7-1_P:f+~Z?e ְM+cA&$/5 t>T 3e_x<0yo`tA8TkpIk3$M 4>ȎfH27+8̈́v%cRiCpM9YǂIuɾeq>&W y(%q9#{h Y;Ľh18=|ЛLXߙNI[X@CD^%0slMlKRNbuژz pPG:$O ˑd6CdT.Z;l&G&JiD00 W5#Y; "e#{-blk>AlzKr{tz_=ߔؼqqz@ endstream endobj 5 0 obj 2333 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-1-0 7 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 8 0 obj << /Length 9 0 R /Filter /FlateDecode /Length1 5332 >> stream xX_N4MZT4VZ-.D!lTP!labqudȶ6Yn-ך<)~;}ޟ3#D|򴔛{w@5!3˜93}ax#u3%OC"' 2nk7+]+\W?0[ Weh[P8$C ꊐ^w" r̩q9'naz6%RwX1V]Z]IKbڄxvAB؍ת@^&spwr}`!Ht`~76pbNdXLީTE.G}Ys~MCP`b\+Nj2 Qd[?@[C" i5Hrsg@,;5=NYe %o(Tx=רj%؄P5 82VCB1 ʝzpKGp1~Y_CnMYdg]RcH/7b5Ɯ!j>4U)t VH:Xc2W;!7\Z LMx?fV9{PDWGiڀVw.!gʠ`0 jtd6&VaQZ›76z1 A>z*CŜgz8^]ܮK2uY͏ˏ-㳺/}G_؈ 3&ιx8.$?0.hInw0 @it~Fw;ί0QnLȴAk3&?p|S8 ci^.qJ!M8`zAp9dhEa;v0 ;`0AG}|WvVT/ rDOޔ u,Xed YݤKnspЈi%_7u)옏fY0oJ]>vbxPr*#*f؟пB{ 6zXeQ  -g͚☨1bÌ2fmi+ӿyEڵrz~o"~Go(6*봔e^Hz "/(=N&'pjwJm`=}MpF{ApΞ^npe%ikXSM_`Yu R?4%5H4ɸ+nhͣG\ʎpUV{/ "n +ضtqv#Zk{59Gƞ B;n , '\cZ?59k>8hNWwW'/S>$ 8qf^Wi|Ab$HD[ځn1e@ݷ |Loļ!Vk]C6'JaXrqp*\{t iC!>a^i׾"bSrs^Kͱɭg϶΍5S>;읛4gѢl,X3UUg% 32īs-y0ЧTyˎz$mlڌVLj~CO#n^v=G[V=>»O?BG}GT;OoNiBi%&Hw+Eo[Ss Ӗ7|A}[eq)iR<@pbJrJ 62q Wc.'d[bj>j`5 `QצAS~WcJZMXoV;yj p?2U<7ㇳ$g!sǡC?Ϳ3ed!@_wN[ZG!ҷ9Rc@R' Uh;ýR{$u _}5nѓ[5q3.(wC`_9ZI$K'j\dD(k³_Nl)#u0r*%>k8>K=CupP@!RGtHAs-䣗~#g{y%~dbPK+a6D!ï|*lM70rJi?њn.MUt#Mf_փMfj/d,,AX΂Ga>oՒ$@Q’ qggzJL])fp&EhPt8 F?Ȋ:pk3OUfsn[n-۞6;i7˖9CEїGJe;f2=\q?6J>뚓oMe2)( eHʦOCc6WIvp:taU 15´Tn+z ֩cL[Z ;4anOpdgILQMnA_W*dZ=Εi6t\KPٮǴ u7=M9+hIB_⎍GޛeۈP21?[1u䗏@YP̹x#BF3A*FkL`#HhĄPr4~,wm8.&/7nRdwj@~l+i)Ucմk/>%ӄny~H⧣_{t]OG5qt@a i;3D\-5@f#kD'fElޏy*>u?}#wv C6%xQ#a4wos: _Iur;O[syKm;kGKƘ4#=thxСB""BB>.CēBp ZGxp!)!u:ooj tNA-ϕ< ovl<>e몀Wgw̔Qf^C-pcst|iYσb29·qVsH WΨOԏ h֏MHuSQ}QAkIl8Z~3D\P>E@}S$ݷd~""{,/PfB @" @@Ár!AZk> e"4# G{kh45 >w荢Fl m!{<@MB?|*"P^]{nmb9E5S,2X/ wX! ؋:Npi>i@ ggX ]` xFuaq@]A̮)@EwH tru<1!u endstream endobj 9 0 obj 3873 endobj 10 0 obj << /Length 11 0 R /Filter /FlateDecode >> stream x]SAn0 Cm:HQrCn&H@0_+J{j._yL3.Q73NszYqPi]m4l__=(Sv|ǥh[SJ-sXz/14Ny92t맞uLU&޺;)s!i=߷UMw4,A/k7hmUM;BߞҏGՉZUi)f8- #%=qp]ey" xGbIXXWrx@ 4-9˺u---Z|G#9`c3um7ozbZĒ1s%vtS_?TA/B}7o}99 8BN? 8|Fݡw77O=]ػwp ϸGy ׄaqWg{Ƙ:_<Ϙi;.+ɬD endstream endobj 11 0 obj 452 endobj 12 0 obj << /Type /FontDescriptor /FontName /NOWHII+Roboto-Medium /FontFamily (Roboto Medium) /Flags 32 /FontBBox [ -907 -270 2051 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 8 0 R >> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /NOWHII+Roboto-Medium /FirstChar 32 /LastChar 125 /FontDescriptor 12 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 557 0 0 0 0 568 568 568 568 568 568 568 568 568 568 265 0 0 559 0 0 895 0 631 652 653 0 0 0 710 282 0 0 541 0 0 0 639 0 624 604 0 0 647 0 0 0 0 0 0 0 0 451 0 541 562 523 564 536 0 566 555 255 0 521 255 870 556 569 562 0 351 516 333 555 495 743 0 486 503 335 0 335 ] /ToUnicode 10 0 R >> endobj 13 0 obj << /Length 14 0 R /Filter /FlateDecode /Length1 3308 >> stream xWST?OaewEG 첈FXh+DD%ȇQ?EIFS5~V;ET`ˆ댂 QSqJQb?w羻ws~ "%)n/_ 1-L_YTzjҔT,|.ڏ=D./vzyVf-I(~) '*@-A x7:&Nҡ`TV/Axc} _%$9I.ܽ{,_NbI#+$ @0$oxG&h6'}o3 hp8g0Ɛ`'Z4nf&ۛ.|DݚutWǭŐ[A]Λ; 3J (8/,rHCJH8o@)KgE$,Al UghqPBdc{~ڭ[[[Rs9J_g7 ^1+j66d- IS@ҍIfdxފxB!5Oր|}y.ʈw(lM)u Z-(~ҍiS-K .-\ 8_h' h(;sPR[¸\H_`41p"a;,Rɢ^TyN.sa,%oS:zN-:a._*xFH~}_GyEN&a8!=/zßXaMJG;ofG&$DF$$A WƐ40}f[&d1]tFaxpA&#oFmJ]2c^sl ?n\|m¸S;;yҊ/ϝ㡉9#u#jR~;{ zB7D6ҝfgSy܉%99%ɜq^pMNufU F 6)U<)6> /|? -ĜβS1ЍYP0mUɪ3U^M1 WV+ y0Xb@,3Z FlMTLiֈ?46b۷5?=47U;Iwg Y7,2B#y&fcGB(u 8Ag݃CQƒH`d tCEmE`m;š'.6މiM]m%yYXaWkOkN]4jZLk:iV eO0+ΝhF|?ҕC|x2O>Iҙ<-Xf>DkoG bxo;.#_b*gb\Ѫ#<(h rR%8/GnX/wCڡ+^Mj9e7f0cœFE_Jņ%|RD{_YjqOǓ Rvse !u&31fΛ1w2{?ސh=~=40몦J?֓/t#>Q@/ T7KJ5oV14m|s.xdOzI= kun+9yIdmmR0R؛^,,2Ert?S%?Rq#DBQb,Cď Fاn+J)'0QR4O F&R?*U۩NBZfNEF ѷUU;*Hkg|4w5Up6-4  endstream endobj 14 0 obj 2283 endobj 15 0 obj << /Length 16 0 R /Filter /FlateDecode >> stream x]Rn0+|LH$T}:A*2wRxܾn\ef*Le rDK3=^$(euvu-O\ְݳxR=cyUiv'I[Qyy\g\ ,zwQi#kkˏ,Aԅ4 겈bX#҈1 dH21 V쩢q8gϜ< EgmIZe`@\ONZ ˁsʩ8"q1{YYU8GI_1{[ endstream endobj 16 0 obj 354 endobj 17 0 obj << /Type /FontDescriptor /FontName /ZRAVXW+Roboto-Bold /FontFamily (Roboto) /Flags 32 /FontBBox [ -913 -270 2060 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 13 0 R >> endobj 7 0 obj << /Type /Font /Subtype /TrueType /BaseFont /ZRAVXW+Roboto-Bold /FirstChar 32 /LastChar 121 /FontDescriptor 17 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 654 650 0 0 0 0 291 0 0 0 875 706 0 645 0 0 614 618 658 0 0 0 0 0 0 0 0 0 0 0 536 0 521 563 540 0 571 560 265 0 534 265 865 560 565 562 0 365 514 337 0 0 734 0 502 ] /ToUnicode 15 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 18 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154042+02'00) >> endobj 19 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 20 0000000000 65535 f 0000011695 00000 n 0000002576 00000 n 0000002448 00000 n 0000000015 00000 n 0000002425 00000 n 0000007613 00000 n 0000011244 00000 n 0000002794 00000 n 0000006761 00000 n 0000006784 00000 n 0000007315 00000 n 0000007338 00000 n 0000008118 00000 n 0000010497 00000 n 0000010521 00000 n 0000010954 00000 n 0000010977 00000 n 0000011760 00000 n 0000011877 00000 n trailer << /Size 20 /Root 19 0 R /Info 18 0 R >> startxref 11930 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0019_Block_Diagram.png000066400000000000000000001660001415120503000304330ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxw@g]vp{]W:[GZ=ꬳU@QT\(Z\ {eGPَ7͓~ 1k &OZݺuWXAG>Co߾z()ֺu"0޽{GEEujܝ|'W;1cRH]m {yn{I.%FƵqjdQfRv4x&D]Sp OdbXӽ!"EBIJ}mOW+SD L|(.˺g1Ce=~qFjQ^&47Ӟ#aVR=})0 0,O$fkQ.FsO{PyUq=s&j4d##:8Q}\NJJJbfVѻa hԣ2Ņ]qr^~^l|dlK#^$٨߉z!ħMV,ZZsSrH=ū?a%®kFOEc] m&O{paO]xρ<ֱ_F-8-G,hWЯF؝TO%&RGwgǧ9T*dRV~7>5j7l餎=_ҳRӴfeF aBAcY5RS>e Hͬ^]ӭM0YeL~6机s0iJKK$ (޹,$1J26!tGDĈ4s330'3SK<|CHVs-DR8uE1=6Tpj#D"NKSrFIpYX[Q4/,h&21=R?>6G%X,KhR%X[3Yt#e25%8;.ɥX?Eu+Pl^g3WWT"}s*MBS̍/)zr]75q0H̝L?x~VR̾٘== <L\KOIc,+V4-Lu5J#gӷ}*!Fll{zDHt>C7n) .J~"\Xwk&&}yg0\:jI@Ӝf l.#/Mw ;o󭇴3T)bfR.6l+Goy)so3&tv6Ds6$,uΆAuk>>c5Z/1u|*͉OCҾ|6ץY+ӕb#)K<>j5GVk3Z@`QYmZ:Hf#xxT[ڇUaslóqaRue튳.-Wg5mXqpWkٱ;74ؙ+.D%cagѾU]*%22R# %gd{YAk vs1*ؿ[PӬ?8Ov`wO}=eߍ!ۺʈ܉WF {v[C*vЂXP/o,@d2INJ6GɁ11swQLLV-jˀ7{Vfq2+2)C"DDgCju\*Ԩiäݼ!"Rڿs!9D_ѭ#;q V*baﯦvwq0wϘUw_ "r<˺w wĘ9{Te^&*,/s]=}n֒ѤǞcSq\g1kĸf&G;GcEy.Bf-6 Yh5ת}P'ڍ5\H5hH5sCeAorUeYVVVΝ###7olZ _P[n"^(<6G4ǖΘ>cشBi2v?^_=sc9>τHP{꾽3|T'O&ܲ/G6{S>ڰs}EQG+4?tw ~}EG/XJ|)VЏzj&bӇq "=|HǴM[9a gN^VUpp͛ `r8zu{B0G/mmDq+N*yqjB:t ]| yn\"wSwpնLt%1I^ /o5y}g'JFJƳfC7.CJ͛|)… Ϟ=e˖rMhݺK!]7vK.5`)QYZZ֭[U|,33VZ"3,=C3,=C3,=C3,=C3,=C3,=C3,=C3,=C3,=C3,=C3,=C3,=C3,=C3,=C3,=C3,=C3,=C3,=C3,=C3,=C3 ((,,uֆ>'N_ȧ,Zܹsg{{{CeZ\\j ),#G (h;?52+e7:e:XP,j8axn᱌+04` ؝Vj*nU !:ے|\jo:ԩ$]||ݻiW51fiKIJJ==2/Um&5k.6L,6vD^X5fNUbܡɰMYU-;88______ t=zЅ>YRDD.^ǔ%bx!b$uffr\ΡrHn m4q+DD ߴjFb1iJ"eYX&"b$MF9.t)C21jC'hs"bf5a-ba꒪رcDjB8.b!)d )II[{ٱ-9̽W7Ƥk"CW U>%ofbJjbM% sdH+³HꋔuaY#]Q.&j/T5(Gp;_NTXcō_%g,~펺ۻukBDDC5[>zgOžVu1D՛֯MNJ~rjǘ=Ä!r8.ÿG룛Y5:V`)MU|ԧqioPn `q Ͽig2hfa3mzjWyFENINHpĚJtO*Ta)^*N[B'GeHCM4OWw7ճ' Z"Vn&/ ː6WҼxBKĚ[+]ĻM3cTWMecx{vRoOՒGijoЮd֬u1e_.*Hpohܼ}[w!`/)~s` K ks2 u/klkae:P-`1˭$\Jd +KA{j(|w!` 3S{4ts c'!KU_~X|ҎTdds;G9J\“'V kjdidUp̚.%_XxW qDGD._uQC_ilGk[:# CCC ]K4,=C3\ "31a @  @  @  @  @  @  @  @  @  @  @  @  @  @  @o=ddd|׆РA1c "g޽ߺ =@lݺеiO<@2"""b֭.LS(Ϟ=۷/X9s :VZ.hPh*ʮPoooCW78 @  @  @  @>K+aeƖ;%(NOL{*E(4eF1tWj.ȈjN#|N;֭$NM/ z&ןm+{t':H}mFM~>Z*g ð±~.'j߷TՅU #l(Z;X3ay,Jzvd7m[qi.^{2?F u`+30u֤_w}WZ ٰM p|FGYYU…?Λ:N%}[G͆{meXV0#|'L*3qӃ9՜q%G|v}FrJ{d [wuJ(?8/lfsN]?5qiS<퓃[%uZs9zpF]MNdv`O6mڌ<2e;|̽V)w}Y]@9kZ3ƣŌ%iS}1t z{9ZH"W?+Ưj.bA~ӆU3e<{.zVk{yyu*BCÀ!. kan?m,΍2Adbk/Iqv4MtqR׹vMBS̍/ ob/Wl8dcdvnJEHz&D \"6wi?'E`͍#[T |Α pK+K [;'#0sGK8e"m~$<3]E|jI/^H6b&6sSܹ֢׵a\3q;!R.:Db?#2Wx;sujE6ͫcjvB_wPkx3'skZlZuyO_г̈́l՞}E rDGypP*j"oUڍ;d5[͝A$^ V=dV,ݡNVA2^llḽ~ =صugNUgD ۱%SaD-kfyDbJhj!KA2Ƚ\^%baŃ%juIM1rf'"VZoZiXm7s9Dĩ22+󙈜̤$1]t`ZСVA_heA[9 tg[u)q׶}̙|\x"QT{1F""ݘD2m. "I⾐"!CDĊS*cS} 2K%3EDFe|VE:Oiu| a]U?]$=Z4ГkԮl+t.V{ChYfm=4˓}s`r'{0Ln$+bֵ֒`XP$%F6wd^ْMKIlޒ>G&""R=x0JMWq ;x{7u+{ɹ߇Yyuճ' Z"Vn&e_-sZC3}Doeud/-|_-2 5j0i7haN+2)C"DDgCju\l܋lw?HXXR*""MfFλ x5 '?Qd]kزY54mڴizV" %Y:fhQ?n8|-rKɓCێw6#5:`Ҕ%NzPƼV=ztܶI ˢx_[K\Jƫ1-4#'';+#yÿe3mʋ8 !Bf? 3w WR&fE&ssMҨC':zt/NC..\-J\4IKM4Tswz9 uRNXUj$FLN) T_N= u IDATzv GqD^3ePp ,WVፍbv^Mc\]!3|Uky<ߢ1ui]y-R_GWuC0OƼ Ddډbڏs-t&|4l( *66Sk_Px.ce[ҡSgzVu՟{_۽6J;cȀ18|z|1HOTh e4[p6.=yNlRaR.k[׵PGqreKѣ.,JHH +W3RfE0|e'dsh!Bqv~ٳ/ZV=l8MJ?!kaԎ5-%Bc; )8;Ʒq$5;Ne\}E0g|8}iq{2+߂ HPkaﷶ_ ͟] JZI~UE&9yn[OwB/^HD?)|֎;FD.)O Xo\YV~|*!t^F$&&RhŲlnݪTbaa  .++kӦMpR;Ͻ'u֭_^7dj~@i9X/^tqq;vlrrlr̙{%$$9;;ѬY>|8{l\βlϞ=\b?&`Qywr[*߹a/YڴiSR/6n|b,,,̙3f̘KZ꯿z! š PZ܈ո6N "߬նK{bsv"&Szl]W1)oD>HR k{Z-\Өju2\FwR9""ֺN6f7bd>50&o#G455={kTYZZ.\pҤIǏ3\2K:3Iܣ,UČk._XLVg{Š<ډ2߸~ߴIʽERXk?7Ԃ-fIo?Wk")ҭX BeР1C _gV)9,엗ׯ_potӣ 4֯_?::ӧ)kef쥋X.$""F5/,#aIo+nWÌKt#NJj*Qr"Q%ǎcYW^.j* 0HtRLJܱBSe%rr[OIlju%Hq:쉊#"bUfp+ CDHlkzqj5ln6alիic0Uvqa--Di7nY7*Uq09wF=6s]CWi߾}އ<ؽ{w޽BCkn7k XR]OۜV&ȑe೹.ŤpH"ftw rGߌIP'ZL~2[nWBfQN2#Fd^Ĭbe+AVfG\Zt*HWzPB7M|OuUu}##:8Iïaͅ  #$9ٯ7K|4=+51YmE&~MZYi>HJ{}?TIJVBD¤,-;4F"2ڔ?LL|Kⲳs$2+--M.z5Tk`2[Ǫ2>y-e5BC!-ѫжz¢·H,]#O$'ٹ{dFD];wG+ٺyT1Dfj9\+0dSֵvCkձk\!IjSne)CcXlJT䘘fsN]7p 儁"pXs]wXbKt=zЅE DrJMF^u&>\{!H͠ӷ4ݻwnЊʃa6I}9i/T,2yǩgO8SbE-W?r?:[݊&"J+.Ԫ#yNLn.vtBUʶb8]gf&9>1?{ Gxl=z/-_G`"*/kŋ(00E'رcDjB8.iZF7HR]F\spjd3g$*_RUg\Pt7{yt_#n[@zw|Ѳ׳GK"w\ԫ䕥N$ `>pK;v.9᳈H}oaC&#QI[&CϕU3W% wol(lw&FkU u \҃oL>J}.YN0<DpJ-?tD" o67 =a>Ҩ+cwֱ6<̬{S8H=tYKu8~?Im6W>_g[c:W|7l!SLR鋩?R?aa2 j*"zEdd$˲| 3O8:ԫWeBҍkرuK֍Ube߽i^_#{HhdqXe4OiYU.}G~͞2 K;cPf=x4仌oe&_/s|Q:g/[W* %6uz/->QL|nܸakk;qsy{{gdd((+$u뇬U/M.؋qѩ^?^?*a^޾f]W~ꁰ*0݋%"F\sxb B| %k׈G=- 8{l哘X|={lzJs,tpGu}0##]vƍիFcccCA" *ŠBDM41\Q|;.ȈjN#tWg$`$±4"ʺx"$C*0ť=m)m9v)Aug@/~gbsM՞MqZ"Mo;L&4g.a"xE53@, y[1{HWxi=xOk`T)bTAy~wVLXj޲gw,Ρ@uVt|yOR]X(ctOO;cgsO,j.@Kמt"ZPO(i{_**fwQ û_p[ ./Tƶ:N7g\_U)[yWp /$6RVfSVYy/\+'ˬmgg3/ͺ[ 6 [ܾٱgmVEakLuyӬGMYt}z+kWt}ߒi_~g )I*'Ʀ}ѠdNs?-_E`FJţ;ԩj޻zeO{O˴QI>_.۴rT'{'r<;i^k"T}tZq7.M6HDx=nCRE7ڥ'Sݦ4͍OJKml?DDeߍ!ۺ/^y+2x!}Uv AS⏫({횿ܳ3!IL퐯+'#XĘ#7ޡиGDi4bD>vv(7&`~ߦ}f75B7[;w }eM|,Ód:Àaf܋}""1g8]fdxQqPa}zJ Sy3 &ww1bE_k4O#KKI{ 5]gSK~?Ӕ؞;]ig9"XpqWPEy%{gkܵmXXR*""MfFʵ-UIӦM6g%99+2)C"DDgCju?ڈSCfóUſ+hzĀ~F=%4eSJj41DLq{wZ~>9WO~i~kG>R3y ~vBSd+CDX\rQ Gaknii>M4ND}c??&b)#~n5b\ W#ڱ"H5Aq w/\J ,kWd/D(ڻk]ǙOFͽwN mfZnWOD5lS1j6iceG_`h+vIgڛ7i,xKCێ'..%#SKDR/\nk[\kMǞ١2j ʿt n+5g}WZ>?NA n""⹌{v/N)԰?=vGԦ.Ϳݽ?/y1b3[K9UvFzzBSMcKg{]\+Vн)#WcKgYUk{њ9[WI'T?o_X6z݂Ta*}@)>ua,<|` @Zޝiz^Z۲|kU~\zOڽy#1Q ]:#T\Ӿ[φ76y5su1wTǂۼc07Mؒ iϿa;'SWy88______ t=zЅ% 5+}LD˗/XE§ ::vaB'u^BzU2Jl^~)Eqi^_#{HhdqXūinΩיsSqsjT%oe[2t>NbԱٰuS 9LQQ  g뮧i9NUBw7yh+^UbS{)+#9v˟V)4ױyˉiUNd$""F\sZ5ygfz$j{|3옍'r,bfDD$`eDD-fXu?ʤe@;3_}ֵ[m*(>'KWoܼ6ƪq|>KsȊO4vrCP:0`%++]^͚k>N]eF  @p޽EDZ655[,'d2L&ܬ [o|m733311%(% "---===o{~F-ɊJ6{/U*UΝgΜہ6ti)RRRRRR߿~3f_",(ٿO?5idǎ+V4t9@D0c˖-'Mtڵ޽{o*U2tD[lqvv>r@YV~Ǐgee͚5е} prr:t; ] `@|~N ]=z(`CXsI IDATPJ* x' 4x7n0t!%PKw%cbb ] `@0|iLJJ2t%J.ރL&IeMPX,6t!r9VYE "DbB=`@FB  Ht`BqGD,a {@ o]vΝǏ%''<(02L&T\յ~8s,VYEjD0 -\ѣٺgu&&&bX&x `v/^X~;v ]&&&;v gg͛ !B(oӦ}j׮H$:yd˖- ]'IT.]U|ZlٰaCCW!`@I,,,p1rF*EFFOB1c-Y >wr%Kݽg\>޶\ʑqmMS...aaaZiѢEǏ7t KKKCWQJ$4ll;L;iF u`+㗘x<0R4t  J{~J9u]:dԏ] "~?Gٷ^&1pWׂn٢T(63|t'Wt8]"_QtRw0{4Q=3G6w2] zzRǀE#Xz4 7-4%t:T\Fm1zٚV8* ~ћo `ͦ󭷠noYΡ@uVt|ŗTONKKK/ೆCP4JED|>umƎ=<hw""b]90Uƨbn:CY]yo;ZT7M%Wyв' ]FF%qmzujB #XP4Lwcɴ'ug3SLfnugc"!CDĊS*S=qC o_}<`'W/+խY~nHwndh e '%\ ""dfҍ",84Cմ.@3_@볘6C5[jk:d,{Pw>I$iwOfeԍ;Ys ?x iM*ac:vږ*! F%DTΣ}s{[6U`dՍ;A 7ۜXp'6YP2:LBjݺA!  ztxg!Me%ӴX$Qt W)A (Rcgs:?~N.}e {,,z6Qn-7S4: # P]HKKvŸqڴi#(P%⽼Ӷ6)yGuXskFϼڿd-藣=|\ f^}" \;&g1Ў9h٪lPtp3xvbomg;E~ĕ9r-'@{๨8"{\t~ 8biG'{ⅉ@A At6WӨmM$+-SL).IlAIfz&ͪw['2mgn?rsTQtNDB @=,/1t&X!-x滯UBIU$@>Kh*JlS#o"r.{9 xĤrGVtBegt"l^Ӓ7塟BC(wk&cOIu܂.~:4PKWm!p;cp B*?<)daB"pV*;ZCEMxU4cN4piA^N 0,:)dQk QcTUԕUMo:gW NPaB*k^sw6U%ybn3+ ;yh=zY3@ޱ,4NlKWrrF C B!~ΏU!;ymV /K_&::8wt"'-Ό0lB!a`!B0LjtClX,YU}f I+4+dȪ7{eϻ{ `I:1 NC9yE!T`PBe^t8fȗAAFJ3;MXjB i4$%Y)m0j&jBՄ YŦ Ų"*dCE7Pq *~=*ZҐI ~$__C'zڱ@k~H$ `€g[bER!LPAB0Zz~{= ~]}$U t 0Ub2N'AHwиCV̲g%|~D 1#P4 $ H@~aH\ H;V%S-\}>"4+ lD } lB~z\\v~yLvk:\SNUEg NhdNsіci }ŋ5 lcWL.7;eH)&(spg,םO<6ӱ"GFՠ3po >6LFOq2R氕{-LUɟEEJ*J>4Q3M/">n h:mh!/ D?%:e^` ,*=hEN^;0|S1ō njۂ^=uo4߀ ctLuO67؎]qZ:Tz(|.Du z)KfY9EWMi3e}HjwtfA0E]w {Kr.ӏ.j  pc]wzN\r8h &;"N{Mꎛ:s-{D릆"Zӑkf80`H']өɌgh%FIgGM73,|Xa9Y:_#7sF;6)E3w& ?x\|&Ձ]q$&5JH@$'3Է%)) Ig0hA\M=F{6 @UCPcF#L6kۅ(&FV//=ewq,T:BaJTƋtPlggȰ͇;('v5q&3paX@hױ ^&}(D(+ݹW R=vK7]WU8 %ZL  YlA H$ 6VHG(WŬhb4ZIlQD^QQaA^Ǥsg9j^ \: H}yL ,@QA'J>[¨6j0B`0'77 ~ةĴ,16'v(-gD,2们? 8ݯf_7NֵS΄fʖoUgSI\֦9% Kv?זm;e ٹbߣL2bO5Z)>v qdgWʸ0ŲVo7LRvL`z,wkf+wt7ʣ T]-e5g U_yono˦ lq>@f  iasuڍtc([%[Av|בTRîӚٗILdͿ+O A5xţccUȎx*}?P=33}ZN]܃}ߝ=F%(,2Nd6/3RFDn"7;sc}eƷ-Bӱ͇:Q._W21$sªWɟ:`)J ]ڭT0$uXlfA[.LQe3ت6A)bBn(1ʪ@=0XPαөbF iJ uڎ꭬h\}NHNI;sK h6QwL)^\QT)=m^dQRRW/~?&](dYIvYY2ɞ%[%rQgvns<5]znj#VE \1?S4wb};cFwuht/U2bqܘd?#-ZjS=*3&zޭx[q6> E CftS3`➷bJ$Qzo7GA@WUkƎ%l:E#FmzRuS}I>;oF_YQѷ=m˵C#d'aYhı#:jҀ.i8z{WngDd>`]G"Gϼ0[v'G -l4~ŭwJ#v&<$~W_.A oMU~8qco vI쬬5Q E iٙIh7/mKQ:J",gGj͛)V}G6DXn͞r:~,%w'tf 5nnΐ3s<@ n}}bMAS&u\4%tBΜw]{*}׶R%`X/ڟ>iс>Mzvm,<4x'R`M=x* Zyvj$!CL}W>;`iƱs)VZ9Ǿ%X3O? 0?+-OYGNgf $ 5hh`BOCT~T^X!EpLkDhwh׌8+7r( 1[fO$sQi@|Z3Ks. gITNVNaXU]0B}Y&lλcJwTpᨯz}W]U' -޴{'J(g5ynVN*PypUg,Òk[wqNRGS/Z%=v}:u"P|AC[=qj)AE J Rί^ңwy[+h,r٣($1I/TnZZ! ~{lPt̍vh")))??_Zέ?dܶDA{fO7 h4l]?{:h蚩Bu*/ M aJR^t&u> Q&=Z3pEVS;{ߝYոU~)@#}}NC*p1s5niJ#LPŜBahhzQ]Kת[܅yoReFl<4+P@3<Ser.6:Q|TZd3>E;X9}H_'Tu| * G{/ 7u#@xoT~ҩySW0[t~Fir LP:uԤI͛7NK/3B Jngvx_K]CJi}1_2|\{5G*RuxG6@*[9*Vsri: %Vuh:4Ȼ/%>dQk QcTUԕUMo:gWOL M(jN8Q)Ac2^^^ׯ__l#P5Mw!H#z~? gu7UԏfaWTu3$b3cm ؖ-tm@f:'$dikЌ<Ѐ& r/JupppppHxAEQ&MN:eeeI;,!!>,@p>WÇ !!Aځ4HsnܸQځ|!x@УLEQX߮J$,M?<[w%:Yl "DUٵkW||| B˕%%%iYYZZSQ4F?|reϲX,yyy.[S!T3CϠ+6QN+%cJ0B?0qqݿ?,,ӧ</++|5,wޢE_^^^SN=z4ͮIJ\m٫ϤKtQ Fv ޾}޽+(df(x</77㥤>>ǎСCōo`4uVM,UօlNfrlU>+t+F9iq{.g &li8i-n0v%< &_PJOOvA2y:tD| #%Ν&?4 LkV\2ɖkˈ)%$o:~s$} 6prIiT%{;RecJ}Gup콤it}s3ƴyRwU32hť}q VX=rsss%O~ /6?#?,IO7{J~?NӀԐڎ $-zN4aAo$]JU &Z/ ~oݶ߼0ŀ@seJRlɫ*tXVrn|PgDܲ˯yK$<.+XP»H-o_3N' ]͙0X` BѮC3] KD3{-' zb^[H\:-1q \12B';{ IDATpxl2`R_Mvm_Krrbӄ ┗4c#2N_ڵt{ Dđ[fjn:*ܒ/){γÕyjzbп.7VݖA ˎ`sLAT^^v좈 )C/G vQ&@FN5ywmA@{xG-'-_9Arm¿b@u!IfF@*(q incI?#eRR/>i6e_dӑO[-i-uw<**,&UOoߋGWyqp+: ^*Hсv,]hoO^* խ\zhҀ޴]>mHqX]!,_ϭ |XvNũ%ȵ~3 q_g-CErN`?rC $I(~-7nVfHn{.b_w3lvw'Xl6A USLyty6@wN܍N]|;v/b]<E yߥ5Q`s R][-2e}A!3Rа7?s.ȓsvL@I+>?cmA>#36E$꠴4ڛb-}_LOfArG?PRV$ ]]ꏇ UaT~0` BRCo>j˱Ah3d}=$|3K]jC;rEmKMzUTR bT)~ṥ r$0؜EqR֮]EyKltt x%ŭwn>xOEc!엯ᛰ[ 9,+G$@1kusd]k ʧ/8I勗C#e T 0i髷o]="W.ލ_@SYI2&1!lBaJI%Q̊vJJ*F35;i !![p6i݆a/d2FO=r/3Q1TTIDB1]+N~ɉ+wSVAR]d1PYq^Ϟ?Mht;N^@$o>@*TmaD?ˡMZ*d?}|zHlo2%@vp`@E Of8=W +njΠ]].vh$KBQVvQ gB؂~4>2g\a" \-v"$urK;:ݧ.:Be ˝;Ǐp1W=:oP[7Ȗx?ݩjyqN~pnSSͰ:J6syڣ&WWSڻ՗" BVl H>ҏMwEM'"#>ſQpl,C^:>u˵^tc`RPi !{+mH "RYq B;ƛ>%$~ $M=80l,x߅Tvso]zF#$ JR-M؂~euCv>]ڭү{ _~82,َdjT~հimwY6~+@(uvveG6\7_M}iͧ ^Ge>ޛN sEss3o\Trؓ **X߬v߹T6,-kO%b( +>$Cq5ݚ63V[po[nXΕujt@p8BOP`_Fh~#pN62 Mi[E_Qnܸ!h޽{:tx񢋋cAƼxdԩҎdzVel⽎hfE{"iRW ?&$j(H 7Τ >xbj ].Ǧv,;h;imϜDŽW2S8&2%(A(F ,8|#~9sf111VVVYU=92!!Xڱ4<\.wƍϗv, Lmu/_vqqСCMJgSEPvJFԱwDn)`B`Pׯ=Tᛘ(^Nf;/Y e>E54|4JۧL&?Qg\4,ڣ22-4ozКʘo.$"Q̲"/KʨJӲ{ZiҞIkc!u&!,ꒆ=T!-m^3C2U!P wD*ںt=CC4k&Uj =!:69#C]S1B{X 5-eIJ1'D !W2KB-Lj` Uuoo@ٯE=480q[2}._iӦ300jY&3sXxsB &,,  Ϗ>}zPjnt4o߾r劍 Y@/^xg@3JxwB> g nݺu힞oPS7mڴM݋WYWW/^EMB5!P]t)***111,,L,oݺI;_lٲ@iB5,$>ؿGΚ5ڵkҎnذ@ڱ .B۷67>,kѢE3g˓H$+W,rrrj Q8##c֭'Isrr֭'O~~~y:뛗Alذaԩ2221cH;:QNt#߼ ?>2ShtF{IARRRTվ},k…3g櫒25rd|կ_4b^xgkШpjĘ$mN\}V{Y{q.y6T|1eli+O%%g Jz6j,=TrD ŦfV-eM񭇙ڶfJ1fV_L Ѿ]'Mvw-] 455jjj>lkk[XX8o<`2 TPEE\=5MmXqѯD֝Yyb?zة|JJf$uǖ9(eznh뤒$ICBI(TUS(J.dCZ f/ZhݥYfu:33 2DQQt6JBIW9)Qc>O(rcihMɓ gd,HH1rr\& 2l‹79Ew{i$d8l6Ih4OyAZQfqIw I"?0aB˖-)( ۀP%H(RPP===(BG yB6C@ї=ϟgq[t4O I غm[0 ( 8Z-l<t@@,Q{PlfsC^i42Ҿ&XPC,iGQ3tuZeܼ"AQBIEfU&2"x@*u6,-F ?m_HrR2E'%gkg&&6f|-KpuoĤ*wP@`Pp<|xx SS:맵nۻdS(t֭SN%;q:B?MF79LJ-.H୰^;6QXP>HUna$GH$!N{CF )/O~#$" ܿ/ӹ 5%W^y:|/ ,%x<^\\ҥK/.,,,qvv^pBA#\.(/9!@=>WN.=OT1XiRf Mz˄W9ZZtJ.[]-cS9=L}SU#8MX Ge1@? ObZZ6aTNae6a`!B $@B$X210v8GEQƒ);mns ڐK(ҏw#gaD-S"n TP!CZ?Ŕjgљr1RE,Zl`X,{,/L6T4|!g&*fۖ B6T&Cv(s.^RӂEbv/ddr.[Ed-O/iZy7~M[:Bܛ:h)Dݗΐo5z!LC5G_s,~o_[|)toy o,u3ާ7ǂ"߂NY9a۹yxYf*u0k $&cWn]kvŋ/J; M,LQTxxxxxxɞ-ZT]֭[nݪ$#z;wY:Aԁq?ӥŕZ<%CA or\ى[|Ŝgѧ׍?9pŰCe"G剞,oJ)#PUM^^8p VU,Is-)߿?~sv ++IU|v,Q`pͣ88jӍ=5*& ^v@޾mY#U=$lQG6DXn͞ :/6/:Q(}FtV2$Trv`u=~3 rsы7߈(qJϬ/H)&#:~,%w't.} rU!/#-otGll *uSGΆZxooҭp"͛7=}KP(` 9&tۗd>YWR٘w< G&=Ez> #y/1Lm/MdgXM?7VMϲ7}JyshE@ྫ*| rrr*{HC&Z+B KBBOBxOG,bt\tQTiVoIKK311q!j)^WiӦlFGGرcٲe:::%;-,ͥ>}޽{W]eaPYE eeTc![TT99|Hb+B H.]Jo*++رc%Iu((/J;PpႴUE˕ˏhNވEQOiR+> հSNGHݹtDDDH;*M~Џ?~f;88H;_b0a¸u}o,Bm__yn ԢNǩh.K/,ɓ'7ncU:d ظy[]5^\d/\tuo袈 2@mc7NC=zPQQv, #~~/w \.%塙)o`!dggǟ:ujҥmڴqvv QWWvtC #z|1@7j/WWTг“/;HVFQ#"##>|իO>x\WPݍoҐ+J6b1+]Nkܸql6D&BkgK7.^<]S5?He㐠Äbm]?C>fRs0BHVVիwYq\.Mk|J'''r\itBkgC& ˸|Xu`G9^uJA" ZT_YgAe]{#(|{aKm'z,4jhS0B˗/{葚:tP77;U !j՞rN.<su?<'_۷{ij/$XϋhXq `Y6gD V 5 `РA<Ν;m۶v8!T9B=μ/T$t•K,lQ^ּ_ѓxBKV xExo 5 =}H;BNTq\>YTȿ@+pI T|?XAj"=B=jvQD?~'bJPDd044v !T/.ܚt;S<-5 Q/L6T4|!.w Z7U`-.>,N%ӧ8|iJ75KE^ydefa ueL_Ke-m[aVZܶn+e֌TRH*=2wA$SAQ nVbi골|ann.f2UHe{Ti$:׼FCȵ4綀'/LE-Jk+xlqƎ\BhtվЗypYkHcgW=JZӑkf80`H']snϿ|b]Hh~h1k_[ QreOgMoF,Th:c}wq` gRk[[ SStǟoqjܓlRwԙm#Z75sv:R{]U=dz/yGYE( _J8aPKvCA!$u؂ꇂ%mu&TyNC}<=m;:N{m۶m۶{oS߷vƄy[ݻp65V(PUnfgW{m6~RG}JOL@j+Gv/>>WRfǎR;,jXEU,%%EVVVQ`hhX J999I'j۱cDzeˤBֈ,eeeyyC A|[}ݺu޽+p\UU:Oj.Bc .+|BժFԂ>_2yf^^B!(`LҎ!P# YW]ԴnA!a@SNv!5B!T0jT _]\? %f~,ImIf hZ j~B>.CӼt $Id$?OT778)?!BՃ-XFM%Zύ>^n΂mNK;Iju !m`5TO< ݤ*t d,^p1m =z#y8*sܦ6nB?|IpGlfɪw!×ʸ0ŲVo7LR'/L#Hz{_*K"gMʊLypr[t$|:?u,J͢ vGv{>B5H؂hLg5Bx iec? J!m} 26D}-0B9h٪lPtt`6Y},QRx¦ϺO]]܊N^8z۸v(n{4!'Vt@U^!5Vm3;Bl!hDX#w?p߶-;L}~%cw_9\!oEC{Ç/aØ#ӝ,..7H'*'cJj v;y4]\hs_Ew]3* D!DX_|9=^>_hRNj[1\c*@*(k*Y|; $ɳ'x5~ Mp9O{ ڽq!{^U@lBi Ir>BѠ >M̙-q9IƓk>Pr~@g= {E)`hu۽{.'c 輸s%JԈЗvAVk"Uw?׈ YV|-u&!TP6>L !Z72(RiRGVDtAZS 55`9gJGN)'ǶPUQWVmnvQbvuvak&m hZ$}ʹSˎzLȺbWB l= Bo2S$e]-J⑪- "4vpprbv mAA+:]V?P];u`_EǔK-Wmʠ2o./NRi5QBN)J6N !vǔ81w39n``!BuDnn.c26 !~ő)ݴeT kS ,sO ?+x_ku+mX,å  n[B)))***Ҏ`B?&X0]ftϼqtF%}M^yO_&`q؜,kwaWVœ[$v~)FVkE4l;(?/۬Y3iG9X!C»GЭ\N5ay=@{n!]~mκ'^6d3謊&5g|[辗<WljXO-U^nX,~IW ־}8<ݻw:uPՈ=ePhn|}ߧ )P'&Ӟ>@+4- wNJ+LHpppnnA*rvvvTcGUj=pE3deODH"YFCCҎԫ۷x*ٳgʕҎ*pA Qv,[Ṭ8tU!< @/+Z璓g̘~i (RQQv|s-6~lKF1< #`6cyڪԶ׼?Hh,QU4q]}2|#2NϞcdkB:ƂDUûBG8VM5u揄שLEvi~λjƥ%c-  +lߋ(>MW .R@VJq7m:封MKzƗYDn T} Ο?ԳgO##ƍ\%]]%&&fڴi/_9sW}SZBq[wo쾒k7ȃGJ(n_o&+T3s>]_QM7}Eαc-Z[jղeK 222orJJJxqvG E:x!Buծ]͏?niiY.Bu@=J.BBAll… |||0QwEP{n <==1QwEPؿ555i !9)))ݻwv  !9o޼CCCi,LB7v 5"-9H;W_']'h9TNkF[*?$n)3/LTv8yiKT#KuWptX 1nkr9d/A>98RO7v 5AXEeo/(u+&={XVVM5_B}/''OpWൃ4:j ]vy?[ k43 zqe}sc;t{tNkL5νnCTD@d=18k//]9CR^ԯY ^& H~%c /77`+,kD}L"_,\`.3bsأK{]idɚ ~7s{·#/mbTרې9{n,gn&y=MW=v⭾^-iJy@n& Ztii:J~u\FgFIoyUCfӴ0-ׯ\$!G4M Uͫ*x/ t~R૗޸,)qf._z޳O47Qu5E`=6HՔja7DS+i2=Zخ:J&3&ѕ\Ŋ!ex%@e%O^}L|y1ˬѰBgVވ ==\[+۰4%6ʸB:P wܲ$1{xsf_c&JM:v5ieguھkPm(CDH 5WhPz7b  mo<{%?}yDiLᢼO}*=O\MU5?*p/$ 3}yӰV \V1;K/N9 C|STQs )QPtoAW,sl"7;zy[]?J{o܈B:ǎ'3H̋$fV\onB*Ɩ=L1>>OBaFlQCIY^^,f[Q5G?gEA8MZvy{ӰKʘ77= "B2iDE<+v2fcߙgڹ&ug `oL|;ni@Vc8b*RWpUldcߕ[~) W{[ Vu?dW*)wUEWu$1yh3/Zzbq؜,kwaW֏w\G^v1J:5yσ!0[lz~8͞3 WtZ(O>ݷ7*;;"ddevc, م:!HKxW"snqZ6m m&lje՜I,.fNUtF%}M^yO_&p*(dBH-cn LY1N7gcV7qGL}R?27e/Z$^r[lR˙[68T=8~ehb$mY؅ RNYp1ـ.s-ޡ^\$ @$Qޅb1Y!ƣ61l&%grgt% j|u?]̪-DWraAyȇYV2 ~zV99}ѮmrnPa#C=(/I~I67}{[dʟ\"Cw^~Ő,:+Bp~U4Z5$1gɎS>W9}NrP=erPo쉛V_Goɀ; dgO0lX\D 5ǣ~jH ~bPLRYMaܰ7i4hVҩyk:!` rnYx}ɽTj$@iJBѿ:@=ܻ2L xjD[ bÏ+Ň u onJ' =7ҐO. Nbo9$bH֘>׌wܻ3n-k?v߿49_N茐ŶM\aÎ mѲ% UGzpl0蜨K/`K?6'S:_O T4MI'7 ￉KJ8Ҙ@664`܉~K 7СvG~/(̧@I p̀ \QdZުLq>k@=^O' ǭZ?,A8يoſ;|)9"D~RYoN=|2TcN1Q3*whO$h6-U]sG}(Oށ$:,ID|Ek/yyZ1s zSAAwj0x[op yX7exUDX!R/G+7hDRiiU6n37ƚ0_<ظ͈ ˤsdI}Mt2  +*+~_M'C <;aO sC]L4'^"Ssr&A^8 |)k+X}}K ܨTWYxˡ]%v 7_^  ^F9 7*?\J !xI@}*GS\W.Y^Ao߾I(/~x8T.nz훐@ \d0 --"zvUKGf(6n(W)Nxظ)fWQ4Md:-,(_ߍHy]FjFmOԧLvM8Bv'z}?+ Mܲ5P6lAb[v޽{8|=m*mfojFp, !< @/.}wkU h0glj$ٞ}v~-X%&:7=wJL tFMw GtAVԇ?r4MCכ`+2,^o35gȀcA&7'-,(D"]v#'O?kw¼;iCcue(l -QGܞPM!Òdv`dsg'ogϱU!{g%үTt72C:sX]g̷82?̧#$O}I+eZAy3G[ʙ0ݼw_1E`='Rzc *횫2$Ed? TߕMff w,&a^`0hB]+X-q_c)@jY2 o4ឨg՝_T`b6qzyTq5zOC.H:'zn_gΕWw~7ML |rUS+Yr& 5]ӮR?4MӴ] DDD˗̭[@vvvy=^j$F2,R3)+G aM9<63(3pkO4MGyp٪#hZ.ŦSѷQ6UPafo$TƝUVd[.jv#U>!5]FȀ2Y\\9iJd {ÿ* @:oz%:(Ǟ l] Dr>{cBa?-L lg.eټmEd~Us!Ò0z\RyܢeH'ҨB? 89em5lV8vKC{niѫV|fɽaLPeeJ 5\O(M(!%]7J;bϟ(iG8q^z%@;v+"XlRz2?ʕ+^]`7{)j [j/pe}cAMaҋ'o3mڽV3Lj&XRTo,ql RMԑͦx{YχK٦ Eg?VO$q<yŪ .3(Tw\Ѣc@?B}MNׅ7=?kfSm޷n4!O]]Uo+Ba9 /,YvI{L\Q=J=z$##vVyZ:ӈn] guY%?$( C{ge A2[Ymjՙ+xQ B!T7Oq곱<ifi`G`X`[u.d"BU -p;p`FE+K>qzI6R9\\S[B!`!BD")@,`>N !X\HMM-7b0hР T`BY:u,JJJxP  !ڷolٲ G=|: ;#Pcoo+@ !6fBu&XStiGu߽  \3o/S)\=XDž N>-(...mڴv-22irssXΖ-[N8QMARv5,̣6Crr҉_CI[>a#ֶ)ю{/r1{⅏OͥHVXX &] VXXإKF"j &Xz@lU{xIn={l^3ft,r2㖌T'>}W޵kWiG;@]]xzz4xxx̞=[Q4_rmlW%W^[!lb.} MVgp{}4ʸB:P YJY'lYmyjUCI @@ر Öh=pɅ?EO_L#\NBQ}lJHHx@RVVV F#Ir/MV}Fɬ3⣋캲 Y\ͨ"ukc7e0z LZqgǚ-#[GڵuMT#\5OBM}L.SAtvg6u5᧖N]L*Togē/w؁~˦S/;OztBHgMO=;}csq1Hʵ`Ivoˠ]}&Mݺ]nu۰fm6'o@Z'_lp2U.Tf}l]GՂ>F|&=<쩎m[y}```޼ySQ"׮]xҎ2N>{货O?Њ#-9dcsKƝDZ 0qmL0Mؿp{/=zYۏJu,Ka5:ڶl!!pz{ZV{u1#iwmzcJ&qLUk6oٵE`祓/>`MDUQ,Fϰ` {MjF }\IJ%X{+je0Dy═d*[ ɸ{Za(/`giB-88X$U=^jLMK*Fm"C u`),Dw[};CЙy0?_LJZ~ZÍI:':=d rMn02XP"),sR"1\&rr.R+Hy1zY~.ўyv9ϬeQknBEDGÝm6Vgڔ e:>, \ x6G3a!YuUq#IN9"/: [ jf#l4pSM_?o/n_̒O=^f}_hx'QᢵrK)&Vl5UI<ز3tVM x:JA$TAƻ;]~2VW-XZ?&Xj%Xu؎KGkg8:> +mK]PE-]b0ũYPrΧ P[hҤIGsP֭; cs,*: %F)/ =pt ?YIl@F ű[?E"դ K_ͨz|xހYuq[B>I@xsF#i Yz eQa|'Xd$V `tW @=&˕S70Z^dn<2y@a d6rMMfuo8l hQL@eXQa=vFTmj WI2?{Q[ h)aapf l&V \yٖr!1bDAAA&<{LIIADZݺ0ģήw+xjdWȈ =xBeC3v,Tia֣\NJ{$Wo ~&U1s.{WKgą =+a0K]>_t[z+kx]k.Cb"x?W%K+]x=`UЂgߖʰQgbd6t{&EEֲ+ԭ[n߾Pdn:))c|||@@@QNlnn.(Xy&)3퉠8:wkh&((53==0Mf< ::%SYK&_>|/Iqο{v$1quĊ?8df7!?IɉiBij<0zqޱ"Fa^gt/gѤcM"*D=+16~_-]g,2()z{&l6:6N/t(k&,,,+QHիWWZ%@jRu]Kݲ`]kh Q;H:1&a虛5b<?rԒ)<.}t錈c;7seT ,8&J ,1u޻ʡCS.WAŭݕt5ݼysϟ?v R4}t==#FH;oxe ;dߎ$:'5|;}"˯?yW>A%d2lAӋ{,뉵exyj_()!^|%o- ^]w;㵤>% # )@{'=T%v W^mӦMJRSSwillbբw%XE/qLn q/w<'UwIgϊ&dM-:r@FAjBWREk&D@'.)IB*J~9l^}}{=0Ks s3vdT]?_1P KuMO_@; $p_sHZH<=Il]8;ra֫l$.8Me>iZSx>sZ(^BiE<طKXC0OTR`@*rv|c2`qTZ) IDATIW ڰu[F(1---7o޼c__3gۯXBEE=z'+@˘zi`` (z/ppLO;{o/@^>frgsw9i}`>7/Lw;4a RRЀZ7k޿f~te{xzlgN f;rz%4"U.o/h~7RUA?G+1I{3<. *_h8l/0'0twn(!M{fs2y-5'۷tڑ du5kx_^>HӮksYy ɰTFzFZ?.J BB6_UZBBBM+JH(__G/ŒoذaGݿmJ; `I-XyY#^'ްX;oOmqa2;?-fh5zL"Uh0 ̺k20Zdˬa Ƽ@NZ7P-Oo87pU$srDdT`atq1l[+fz2SJc;ƪz~WTQQgyÇ޸S;d\Ly=GmZQUx:3-CBRĩ=koRWE JNiTRQ$Csʎ*BS* ̠=je] J-t59pΝ;w܂XteJJJxKc+,hoyfZʹ.ʛo~ѲU{#%f]_~:IyUncll澾WfaoҊz|A=?:' 0YsѲ֎/9J)"qf! Nx6]RmE]DE]XOS)oTU*=euVAxŋ+((^zΜ9 P`5mڴ}a0 ->%.瓍]HWf!o 朎SfГoSnݝ;/l2+D0!wbW r˫"걲zD5N}Esz#:7osh~oAMI*~/Ͳ-sBN_ *#lqQ}A,@XE@ʪ8ϡ=΢@0:wE%?Q`Ex] r2΋;7n_a~VZݻ+VeWHdee 77Wځ J`1c7.@*sRUo?&d1*j*۞~NcZVONZ75μl@EM`_SEȵ*jjR)RrΔUtqhfɱ-TUԕUۻ?n_֭[cjU !0kC-dRu~UVG(|~(+fቐS+)7\>*-7:r^[e- "4vppr:eq:_ =خ!3-(hE{`` bX_?6mT_E.&X߃}~\{>J|t4:mV'//_/"Fxm+p}oYݶNj@FsUo4iҤ###o޼`6kLL?lB`!$MfIdmv͕+WK+$TDAA}Aځ Jx!*@~LLA W_ODgjjziXd!k !*6hРsI;,u˖--ZR3K_`&Ȫ8kݔ)o+ !*FSSS;w|ܹ?Tw:=٢؍g"| ={VSkӛ&sm ʭcBU8,,lԨQvvv-[lڴ<ϗ:1Ñ)=O{1Ʋv<%:?|1s:SEjdI[A?{… C yՖ-[M6jԨAYZZv(uֺeb8 f7 6TbV1d$!zoF|.WN|k"l&U*p &ίrm+p9㶄|*i%&*4n7\dNצ6d-',**ÊC6ͱԒ6_Tʭo VHHHߚI]llC@ IbqZZZNNNVVVfffvvX,lƶm"/?ʡTj{ m]Or w1*\y92#.݋?Ϻhjaٯk ڝ"0+?#m6Vd Ofą]:XR'4-xwl&S[L9Cϗ1X6ƈix"$dCz݅g/b?UݻW^ - C522z]v@jjon*]rDῪt6UΠ lBӧw-(4&Θn,Ou_;Ս #T5hE], *~V j @>ejAH&=Fkxy$66pBl@XLMLMMm$vH:%eEPYԷ0/;_DlYt FqyFF HHҿSrM'QTNjj v;d~^^FZRQ]S4Lĩ=*2*uVnBHX-:%r?קAtRURRћ,TRU" ғ? FJR>P Y>`x')uCKMYAEtv³'[K& 7B 5 zs9"Q-.b@Y2(%ܠ>QL}++:1#@tdlwn4D Ͳ-sBN_ *#lqQQ T1QQMXn$ cȣSo݌f+p L:l_gHnͣ3o87PQS5DtƸ:^W  ۓc[+6w;x(Uut]5MmODz?1- ]C=&G+LbtFUGaG`@Ljz}*X5-ZhCgIՔԙ&*;μ4UWQo$\*%úqj:Lw N`0l8{&vQrدT8M>98RO7v {ÿU$]6k_HnZ"-9H;  5צ -m2`#_sP˖u?dz:i+99= ۂVt`oGՎ:|F['BNM&7}v y `+; +>B骱4 O\_cZEpm=0ڽI Ou|wwXcta1 ˍȽqϕwrh3 r !—um\]{sӻkhW\k:ɺb?$CUkn&,_iJטP6yE xB=o$>LcVM_sm+ܤF1.p}ߩ율4:iWj6<=(="~Ӳ"aW]5[Cʹn[-'456_Vc֘>؅[\8y[_(Ҋ²5]nY܅zM=5LZYzH׆/nu4MTr5B!j͗7Q̶9Vh0u,їJ 3͵ ICkOkS ,sO ?+Slv؄ai$1{xsf_c&JM:v5iDA}<&R D$(OWIGH$ɛg1 pڶ7bc><4pQ^ȂVZ>X&O\MU5?*⫴,};qݴyK,n&kOnWNd{do鬇^uy\~c**Go𔡭e;TR5B=>QQC 'HUI]MQ#L(t%C%Y4|R#f:6#-]ؕEi4j}1lqty'Ǐ:cZ;tjy]C'a0]wEyJ=M|OڵgNCH*;;"dde`ز,fg 6 -M\%7'lqsssss2HI0ZY5g$*D⌀Jh1c-cnW9}NRR=erPo쉛o:=?oNVB- R@PZtۙ팶sti^m?vMӊKZYdTYXҦM*?ÓV{ޜ`e,UKUGOҩ2T쳊7ݹS?iz3߲mkSo3O'>_×Mߟ༂52-po{Gȉ.RTOե&|=sWx!'X(KHyP0i!]IĎ>HF=O #zhGí1QWo'iwY'/‡9NDt92عO}vׯ~ ñ.Z}?xؒzGhF_4!'6?t[\>'!rRdDdr~a6CIV7yԕoxZh5Fc1[dAj0'U&~ze3>s5r{c=QށLTV&_xeұ?`r׾pүS}\9f|~TOKoos}aT_?}q+(;j sNTЮ.w/8lUwWzkuy+>-{1ϺwWeCDx>Lq6Y6}8`k4\]/<mɷCO} LWgsU?$s~ܱK? l>x 奏yUٳǗ~boZ䒥3.\%{gmą%V3MKRD)s2-[ǘ,:+?YXTdΛfTBocQ5fVV^QuA㻡moQ7d䜌Hx'dbGBnZ=˖-*G ~+VXlJg'5״OOC nܸqn,\}ڵk/^_q egg|45vOFFFӹ;=np^yq~k}i79Vn|^m=qȑN+tz%jCR$#ruԖVhcҲ2vjEk,jy$!)Aܖ#JJuZ~GizfgS~Hɦ=uKL{$XX˗/F(\@m[|W+Q/2?&P h|g O~ٝ{WLyrqi:ICjb$x;2[nUQ'Zl1`coH1Z-Abdwt4t+bƒ9""yŭ3[nذ _juc "5 >˙5yҽe!y*&!& bwEøTmxEX&ϙUݾ4=s}I aIDATˉ U1"b O{d]D$e1/^ga^/Ƣm e RlRkIM$W3O$ )j-V卟21BܽbVTjRN-HچWTKⓧUS#Yc"N K7W?HոZ> E+t,-p(nrz| xJDʄ$K$6KmM])Rq"N$)rqH9dV%L |D2Xon?HӋxX0&1#^/Y&5RWخH,(h\,rRfoym5TmH͌W3"mؒ] mLZVDԊ!9ͲFn }""qԋ2T-UEj}#Dq!BtXMyOoQx(3YAd$jӏN옅cXwd4c 1x[촸DC98}@qF frM:No9lj#T iGL%eb^l SVK/Gxkˡ\1Xc '%[KK6R!%kk}#KlnЛ- r΍ TƌƌfAx\ܹ'}B5+l ੧wGn 5+lkʔ)SLwpw?8E"lw ?PKKW_.Z}}[,VXXd*//w#d2)Jwqn#""H3Lb؊c-Zh"w?5kP1,C1,C1,C1,C1,Cyl͕mN} p8h3ý`4czljIÎ^m=qHn+tz%jCR$#ruԖVhcҲ2vjEk,jy$!)Al#i)# T mLjJT0;#\m%ȌYkUY] I.Ȟ jhGƪ6q|8m_C0i^XeFmTX0Hո[ nڸyGQBJ׫ I`-8m6 2h6Ɖ8DRqab"@W8EvCP0rXg$:+w[o[L:B`DDLae z<9F$sx $_I3zOنB!wB,' Fv]n ,jgaTAL1;tܙ@b3٧cХNN T4%>mͺُ{z?%,YtFy{M-tr 9͵9:eMNWaZ::JjZۺNKHjQ0dGꫫDLwm b&ׄj[6&Q>BEP0v{zQ!p*ji $,1ER)HqPdɂ&"'eWVKՆx5#O-)U Ƥ%hEN,{ k$)1mxBQ1&DI˜1PQ gz,,iZAТ4̔=t 2ROi=a2 0M̌cNW\i(a NGMA2CJ{8+~i|,@OZ,w-,@֪Up+==]/x G.`򤤤3o|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |L> stream xXn7+x> N@6 F H>>Fr,ٱWl͌A0Zji\_/$/7w$=l>煡o%)/||+->1;Q±Ϗ9e'^s‚7Kqp+ _Нi/}+W+^{7ddHrBJHb U[j-321Z-\wگ~^; )OlX P WVC.AC_:t2ՑB9H&lN)$Eݫݻ_޾(!@%"\w•. 0Ӯs)cV'Rr*OWBG{k\@l7u!z}.{㻛to 4-oy^ |ɲEPTQ3nOQH_[qCdTϖĉGNl^r2JX=zš!<;/Bqv*P6LΒ%w*̰d˕|S$Y/1 ~ L[-.(= ëL4|l݌2(D\+A[彟1F-GD9@+Ő#Ъ<*1.SAƶE G 8e0 MyiL-gs AC\&bdYͬ*CptX(])`ȁSbiP>kp oq ȟ( R>I5F]-PAdQ-ґaE \ piOʜpaӥRPK&MyeUsŷL^ρ1G:c #CIh7;& 1XZ5(SQȹనI'~2!.+g+#/Bo9 2'ǰ QH{]z TncSM@=XiiҺ{hGk 4֣sf/SM`irgj+P4>0C<*,FPvoxm0#O~hF8YţaBh3k]bNUzvOEm[,LXu:42[/{rGZN2A+/TεUr}]vpE먌dm~\(&% wQhyv!Ǒ^0rK8,ϱ endstream endobj 5 0 obj 1469 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-1-0 7 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 8 0 obj << /Length 9 0 R /Filter /FlateDecode /Length1 3940 >> stream xW[TU?{gpeTfDVր P@&GA,(4J׬ͅEV}@PW M%&S>a{v /{98#h&"/5gqEsBo?_EHKiՐ9wLxUv,3sV*#߁dg0>7srQ8Ahl{!!Lj$h rBU1rNN#'`܃]}ة0t$OrNC.'$0;be_N - Zo})5ZZtspwWVsscgh?xv.\Rmjo9?TCjk~u7f?=c}{A_'vRH$5]UT |Z"UZf0ß?jV(tmL3V.>?uy F _CH\Z"h2g5rDWG  kE]YƖIWZ,wWGgzzex5kb>;o]Q6;_7<[2wX#rEH kr|tkqd5je| v>o _f䅑~1eX!%}ONRn)Ȝv̂Ut$vӭaP=gc@a ;voĝx5~f565sNcꤷ">idUw Jy$Uc`BOҫnkv ZpWnzF+6}hO~N\YkE_/;XUz6?֘W|\d ,r0GO%GW$?$X9~lؙy(xeU6usʇ\`w 7?VL}B~}}q3N>Lʫc:/3G(*U pZ3qq*mctN|'^A7-qQ w3Z-*K*銫ʗWm)/'={׭蔥X0o[e% U! S*+߬.M+[ %EB (9'\]`髷W@d,LtHHzBCciOf%G1 Ib\>TA14$ki>ğI+'F󟢜{`vdp5XP0Ƴtz7kJácsB/$?yDH {Ώ2M,wzo_-K- ⪼7V+Jw,cz<b|WLou˜Y9LլI{cTF^ -aF],(]`+B{ر,d&ǟ%ɟ8O_C9?"k# e 7?ܛ5-aʊ$oT'G^׫-'' #qZ״R?C~g$=FH0M躝K}r7cQ!/؄*H^~^FOU_~+`>o_xtx G;;*^N 8Mɡ+t=8!W߾܁'R!KsB L@XԀL]O_o?iO76zn}Bw$iϻd9P6NMrrPKJÔ4)Nwd"]\3'3m+;9Y 7> stream x]Rn0+|HV^8~@bohƉL8zz ;N! ,䎴~>yDGĦ~p-?΢Hx$G:> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /DFITTA+Roboto-Medium /FirstChar 32 /LastChar 125 /FontDescriptor 12 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 568 568 568 0 568 0 0 568 568 568 0 0 0 559 0 0 0 0 0 652 653 0 0 0 0 0 0 0 0 0 0 0 0 0 0 604 0 0 0 0 0 0 0 0 0 0 0 0 0 541 0 523 564 536 0 566 555 255 0 0 255 870 556 569 0 567 351 516 333 555 495 743 503 486 0 335 0 335 ] /ToUnicode 10 0 R >> endobj 13 0 obj << /Length 14 0 R /Filter /FlateDecode /Length1 2892 >> stream xVST?}h+KhaQ` H qE@mAQ$)LaTԤd a01 jv&df 3c4)uD .=$_s߻{~sH 7Ww| tu=9/hQƥoX| K T-g]KH/*xHTkwbLOzH~.u! '+4&,((aԣaڎ!W5nP-T #U Y!ΩaS)`lFb›_=pAK]]98dJkcc+h6,Kc;qf۬Sb6" 6ݩ0;ǯ}]vCU獻^pqWf;|飶#/r߫Kr>lk}M>|CElhA逸0I_VC@q_E;jvhs[EFO(̞؍q$/W, s^JZ֘A5"XhOng[OA嶹9YpTbҾ-fN K "D[N#(Q`Qv[l2*.IB3Wnhx畗#LU.96bc7E a9sRd<t;)N b *,LzxNJ?i3p>`slR|b(1:lᢎe='.~y3r[M-XZ&'| a0"+dHaCM͚K!̈m)<8b6V7%6,] æ1bƁOwvyA_A}WZSL"J9rs~9Gh0t|NT 3A]~[laaaLæaB* tLiI#a]%" 5 {qH^7^[(A֡>ɫuG (~v=z^Qn[&X,hMLc ~ykc2׽Ƈ?;;f6ߤo5l=yaکo]zCOzzxye1_Ư$,<=-;K_̇04h|p)QE155u3mdcP~Fy40[\4m|3VVo˦'Ѡ.Vݔj{HN^gm}uR)I<طY ZWlNFKheNTOKV-(|kzo<*~󻬼?_p)_Y2]}unK45Hi`WOoS;IL6ss_ӧ\<z%c0W/i%G%aL4*T ; EňFoM\,.3󼌎Apٕf?ϣR.qqٞDRyj纺uf! ,$Pf>SX{,c({¨:5'0>?ݐQl?}\BdzJ$?xNbHӢz=XoΏlZtw|{SQ/\FjkEύ 54(ޟP +{]G ?i"xSqajfTlT/@jF1hL|% $Eȉ @%{$!rI$t'eTOaV+t/]OZCRK3"fubZ1{4/ endstream endobj 14 0 obj 1965 endobj 15 0 obj << /Length 16 0 R /Filter /FlateDecode >> stream x]n0 Ew}tJ0 8eAv}I1H6{Ώ+dq6=Fo#.%Gh(4.+Nwj>hrY6Ov>-Z?Krն`Q!B^dS|^Bƅl0?jƹVJ,'gyNA5ujuʗ/wub s!\^5{NEYc\G02˺׭Lb ĢX_9q)\2k~-~:Q1]vKԒR/ { s`W~H$ endstream endobj 16 0 obj 332 endobj 17 0 obj << /Type /FontDescriptor /FontName /BHEXJS+Roboto-Bold /FontFamily (Roboto) /Flags 32 /FontBBox [ -913 -270 2060 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 13 0 R >> endobj 7 0 obj << /Type /Font /Subtype /TrueType /BaseFont /BHEXJS+Roboto-Bold /FirstChar 32 /LastChar 117 /FontDescriptor 17 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 573 573 0 0 0 0 0 0 0 0 0 0 509 0 0 0 0 673 0 0 0 0 0 681 0 291 0 0 0 875 0 0 0 0 0 0 0 658 0 0 0 0 0 0 0 0 0 0 0 536 0 521 563 540 0 571 560 265 0 0 0 865 560 565 0 0 365 514 337 560 ] /ToUnicode 15 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 18 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154043+02'00) >> endobj 19 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 20 0000000000 65535 f 0000009299 00000 n 0000001712 00000 n 0000001584 00000 n 0000000015 00000 n 0000001561 00000 n 0000005607 00000 n 0000008866 00000 n 0000001930 00000 n 0000004827 00000 n 0000004850 00000 n 0000005309 00000 n 0000005332 00000 n 0000006080 00000 n 0000008141 00000 n 0000008165 00000 n 0000008576 00000 n 0000008599 00000 n 0000009364 00000 n 0000009481 00000 n trailer << /Size 20 /Root 19 0 R /Info 18 0 R >> startxref 9534 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0020_Sequence.png000066400000000000000000000776741415120503000275370ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxy@,(}7GjiW+Ӳ$M3HKӼRPDEsA7f 3M #063uӧO [ @ּy ӧg?~\*R)͛۷Oq^|D?46-)C.tIun^i*""2IS!.V'VޢNb)hԵ9|V4r[89"e%%\K5^NrjsF^PH7r5 @Msګ$wVgS+V~'X5+/U99)5^AOÒ7ܹCH}J;yr#by/36mRr#$}հ.-8v}*D禞IL/dD|ᕓvluM:%) i0VTnj+;7>_[Z~7Jh0 |8WUwil?ny#Gdxѣ3Eݶ[WYP#1CAAB>#))Oո}mvbl5#"-#4mAfc++-*Il4D"$1Ffzx\||9W$d(qJ@Ϭ5Ԫ:Xܛ9""[cׯo1Ɔ+z?ܝɗ_^j3Cfk+M4ϼ,8n$",Vt`mǔ87T& NJ_,ƫ{!JP{hn]=}꺢~'^+/=Xp|Pm 2&~޿ܽ,|G__FqknFn#@s\WWXWX[H,hdDF$ WnȘ?ܚ7"bi ]BB<_T"{)ͼ7}q_yg~8OIƓ}K4mA҇jqWOY3:O}Gl;G,vj^P E^ 1M5#TI=`8J,/at;Sq5KQhccb"9) I3t'9v22u#(7J'"i&(KʯCTRwʪ2 >nNc#oO+Jl4̻XaNI%ʈ8LV˯x;&!"˞HrLgdv][6XOQo @H# X$sq2AZZ6([Y=MȐXn3 l8"4>l_T+v1Xy$->g$"b:])+U鋋eJSY@pgN]0O~5~6Rϟ?/`iҐ= UHC C(Ue^kgaCz6Qް/}]8i o8uAMLk?b_gmۏÆQ-MXvD͉Hռa[c53/_DDDmU%%Iۍy%_ -~Wq1_=\BB? LՄDn{cw0cLٱ˦SHe=&}2/[ztB*kqSڲʼn?i[Ft 0[=4#cP-X_v Hžo3Ƙn',4cpe4sT^F.>[FQTT)WZ%P DOScܞzKx|Fv_XwPmTֻڷo?0l0G?Mq@ͅU!]h5'> Cݻw X ߿rʡC ] <{+>>k׮eb1@v/`e7o.tD>"&L%t܆ bccZٳU<ʽht"`)Ν;׮]:ljD慿[pl|F3~[niȼUs(.b'6W:Xɴx2%?Il>S6s&GgkojMgN>o<+(aDD1;c߉sݮ__I;vŋ|C<~I12q T#!s}ᨡCo>݁L׮>c!4">w[̖ ˔I+I<Hr}5m;!Ww6>1zNXň:MU _w!Bjʔz*.'ΦuwGڿ}ٟ@AfL8=dz>ͧdJt~3??]8}3:cgPc!`Yܺu2jeVP]fR+%[':|CWM^JǬh$[Z>f1߫>={"8nc_THݬSK,㥌>[O!f={-j&,ˊKLLa ?YFMs Y{$Vp~OsRNߵI+,[Ins\VqVphm;R`"3Omr݉R{ 1By4v""V#"i/Rp: =r)ZEVoL7ȩ{rnϿ$>K_D.GrMDnʲ6,맟~dͻtґ#Gh+/U99)5^AO1H8jto!]:F,be&MQzBJ._!3)g\I/f"f]{t޽{n|lNv"4/t q"b%GvVgVI8">'+N7P1 vg<q"Wv3"5O ,RU"">f4G|nۗV3ݼ~';dXd2~g}vر666111O6D禞IL/dD|ᕓvluM}%!ǐu-Kdkr6XVSy<|miX[k=TݬYyFT* g\;I8c'^{fpٷj'!VsOtku<|ךtR[;&/f5IuTzCݻwgff:ںO>k׮=mf(((Q(:Wu]Q^+0sR;9"";Z7{aѨlS7_=s<ImWnZի*l*OoqqiJm5c?\NNʱ3=}O"TDd=Gb-&k`İ69Х6UH?pS1}]EV1?Lld/#ls[iuᏅxڊMK&Al>޵sGjn㌓`YJQQK/r"ڵkLLL߾}=^МIچ>xC>'e^:*\Iq fO.ok#hd$5M$H8#DR]ˊwڶ:ͬjZg3q rKHGOSZs6Y=`N E 8{bAu3qo mVdVzТ݃]8wwִI&}U"lj%,Kٸq[ZOX§W's$vrw:w6kcWITSׯ;;ejeF F 7=rDD|~bG?WXIIR+*@M۷;2j(ZqM)# X$sq2AZZ6([Y=M7 )Onѯe߃2G6=©z<0"qn֥}6dkv HXO'WCQHC.'\[C Ci<t%;X-tw&AS6nغu\ *eq7n܈5 BU j W\q"eW1nVS)q' qXLj;få1nݯIUU a6p|ݯjJjr_c78Nsy֝w]Wq>1ZAଽ֮OtGndxx=pis,zbf BݪSJLIq[hV(ǮH(~,"1S8[+lܚ3wh 'rmףS+~a#>뺉ŝ' ;wJ j^bCuF"kK3I[K.qĹis/ 6unHI_ő Y/MŲ~c׻KITiά՗MOs^^gBAa\5-쿋,7&|?iLbBM+1[x߯g^|}0#);O|FDR6kݹOˈ}5e̘ n."bNs:(ժ^+K (:0G/,: (eY|ځ|&VT&G*kL~VI$ÊM_|'eW-72r /o9˷vxxoFgyZ#Na[͋fe0"C7.*.*Fj%t z&<-ۏ\c"29lD+.* *L{4y0cplgD$767bo;Kz_,p&9ZSk>{{M<{^} E`=Φ9̩du7 _T&?u'/kjIE]BP`fXf`fXm6^UV@-[+//OB `!`!`!`!`!`T{FmZ⹌R&tetI WFK.I._K1&쉕,(8HA-L'^*2IUn~͚xڊtYq rRWph+?Š3OZhr i+H;{Mk l䮴.5V;U]v9To4?TxzXsADH8jto!]:F,be&MQzBJ.3 IDAT_!3)g\I/f礞͐Ԯ8㟔l9:KK{M]v98OO=zr D禞9haWN&ezp!Zأl|iK LTnj+M}>][ʬ%^ࡲn֗bX$+ DaWk yٔ A( JJ%GGIIylc'lXVRʔNJS5u#bFHD"&L\̜|"3Lkg0n6"KJEIAY˟5л\;!IA̓P]=}¿+/xZqN޿]+r򭀲N+ѝr%#k㵗SrUmΝJ|⪡l«U [+).!RɅ}m$2F$ '~xHرk##cY.XۊYINNڳJfNS4i ]B:z⣮6z#ʍ0rP `TkTR0j,ZFMvH>vٔK]%SnnN'_씗)*!"f4j3/$ߴloqF+q>fqJJJ* kj%w9`.5@5lj8O;8xA--˭j/woRx@/S8"OSSH5^qFXcG+4 G$u ;s$ڣi37'g]%.W.5@)vԬlcpHwײ[M;{pPߦG8XG8+nA 9Z]C>j)wr#&u9N(!&?RePÐFc] Zƍ+t!PcIݫw[`T2gXwƍX t!PEpsRjj%!oDX59v (Xɚ5k֬Y#tPWܼyyBWVZ鄮ZoĉV??ǯ (,׫W/K:$$$$$$D*$wxѢEBuڵk7m$t5@ jNza bBWP `!`!`!`nq upp"X,tPup   '`֓'OnڴЅ@]1h +++,.===11122R& ] 6*jѢEBWu믿.t 5Zܖ-[zꕗ't!PE      qFYrЅ@]ѵkׁ ]@ ``KQrJ.,4vSI8Kp{dݧFcP:Xu}LsCeҠakTzͲ#ƫ{!JP{h.3|V&}[;k"=0{BU/3y""bqww)}^YWXIu`Ur[g~IODm:ꇲWm{ɈerxֽY6wҀǍDDcŊ.H~GS*uЯ tR:.T ȘyK1w DO`H3n FD?6\;=d7S]s^<)',lxuHGIJM7csiYK!9A Κ7rg׭_mm ΃a}{:y17އS;:0jƁ[Y?zFdo)CZ=ؒq6V ܸqCѬ\RBڵ!B "q .~|~}Bb.k,W/HLBMGo+ďH8dWOb6hӃ$=:fѯFDo )w^reSGE#_4b3|6xJO~WF&yM{6o?T<۩](:ll"7i9]7M3;>ϺސLRomy+z EƀԵ%Nl|\ay>??_ ] >8?ٳBWQGi4W^y T.㈈Drcz>O&ڲȦ2L)J'_6uhِXa<5%l+9źb4:=^wOX.=23H}9tiyώ{\w˕r6_evC"BDDza~ /4`H,&""B!!ֆ#"Ns@˫Qu XP]vBWQGqg2^}UK?<oz1Dュc&2\H-nܾC:<$Wzrޒ{yvMY__6iArЫ}ljmmiɿkwjɻ>V[G>8˪eouҤӟ7_', jLv>}L =L]dɒ &dff] 6ׯ_www7nе@кuk{{m۶ ]H6tXUz/iӦzĉfi ,ѣ\WAj>s=7iҤoGm۶ ]l 4Xhh@&[B  ftSN ٳgXX5ݻ7o\RRҥK޽{_xQaix|sl^[zkrk'Q_nz52.PݻG~ٳ.tEP#?}ʘIZY@/#"0F%O9׶{&--Ez=clҤIU͛_hy5kŋ+V G;V$BC*~%C/5^2wcI=b_\I_^__<tƍʖ߿رcf X5'd>ӱ݆D$}po8|(HbFvH?^l'}q'9I콁- UVþ=ﳡmh WQ2""Õ??xMLn1ό3v= BW`(;DXRR2iҤ7|+w6m?٧7}_\)fH|͉ȔP~u<űDb'x?ru?gf4 q~Փ~rFM<!.!ޣF[Z;㴨Sy{}Vi*M6nغu\ ? :ujXXعs-Z)Ʉ [[[3~3dŭxtWh]_V/G3Nψ7u-gSI'; B1sgέ*bƋ_.m=u`ߖGt`r- :XwƍX\"ٳI&w"n 'y /qh{a?CYG]BD m8҉6k∬)iz CGL%ϼiW :X5\.ONN^pa\\OW;I!/دsЫ[<`!D]4D _AQshVXu {{O-e-˖-lҤIe0Ɩ.]:gΜA͟?^zPXXU~gÑXuV\>zTs_rNO_+<ܧh4Ul;7;߾P> 93>_s v{γI̛M_cpQffЅ@-ADѕ`4_xᅻ_z:K.+cel_zFh4SLy)tj3X?XYYYF&Z7|Y֭+?޾ V+Ϝ9F2jP+q1" "/,Y2a„Lkƍ{)))3g\~G}4`j֭[o۶MBjCƞ?^BaÇ_pM?M$w:wݺu{Q*ҥKBBw@C:w|ԩE:ug믿vB[$ɓ/\0cƌ:]@턓"9s]@eq upp"`Ys֭ҽ^y/wn<»c֙#| U?zܒgH1V6SXWbj bY?|>^v/o_n K,מ}sgjM3 .|=Uj)>d~/fyؐz?t AW;NO $j(tcJLڨJFfl:;=*K5+[6LaʲBFħ~U- _xDT{bCZvA۳bޛ.&&hH&RcRb(8-2N'^rW{6F-O([5ӞnlRݙh|V"ne0"|r O^$>Y{>i鐷G*9dܴ |IQ8aAg'/C:5ٛ!ß}Ǎo]qš,W{ yڪl]낳M7csiYK!9A Κ߀9~*r Md7S]s^`b"Sݺ;޳sU j0kkɓ'7mTB4hU>zC>Z0!\JE9/7Rnp:oDƑ~*{%G\6u5}/}wb)i/>zo\&U6c %/QmC1d$W$}*%]DDƓ}K4mA҇jI\TúpMd+,KOOOLLdBJZhU@ ]Bt$Q($pDrobk֔ѧJyʎvQ_9- ~T)XDt3FH,* ]|uҳ)3;dr_&HVV '_6uh+5=D,WC܀okmnD4_mٲW^yyyB5)zH76zFzޟUJVNI7(UDVQYIV+˂8wOJ|H𠘇W.L&a8x_^ zT۽Z ܿBt'%myKIJ~{ݺnWV'XbߦOiΜH0HH*ܿxm҂W? +^ӎ{1ϑ=k "2*eDD}@p!q:t\m@P\v ݅W8DPI}J~;Yw~ FFtknz-|3z؞)Op9zǦUo x=YإK/ۄWqz9.v'Sx~>^ፗŐAa+O3Q"FSW)v#I^ "9j@ն-E^B$!Ө1|4·^TE͞>oJ3y~xrE[ite ZE}1f\CQo_;vQ^[=zɆaאn٘[;aa#Z>IYmFnx̯˟_fVQVj=/”"Udq1" } [Mdɒ &dff] oСϟGlzэLuSup§{:XPR/80  FqFYrЅ@]ѵkׁ ]@L[~+>~j0u'q6SPP #Y茒h,3C03,3C03,3C03,ѣ\F5.gbqQQQQQQBWU,3C03,3C03,3ïj0WW\kkkX! IDAT b ]@ mܸuֹBqF& ]666BWP `Y܍7bcc Ѕ@AbԦ%(eBQFpEkĦqT !.V'Vޢ}#pW0Mx)$U5ki+&e%%\K5^Nr(Zڕb疡 n9p2׽mD{x^ ԘT V_rrRj=SFϞN-`.&^f^m"4' S>v37ϿtNì,N.˷@G  8M=^Ȉ+'ؾٛJB!ZZim*5RVrP[yRYyɆ]>wéx]8[%`˖-lҤе@vZBѧO  JJ%GGIIylc'lXVRʔNJS5u#bFHD"&Hd%{t*]FO+_JEIAY{,LN:5:: Ƃ \=}¿nbc[+ɹ" ae9*~V+>/\(Z_YS,Nm{ ..;)S*ks0)]/]$>qF«U [+).!RɅ}m$2F$ !RzQwdEy\~+H\ӬjpRJY_vl5jt-&;OD$ro@Ktl%Ʈ‹ɩZ77 Pɓ_wvԍI\#Me="kC)/,7*U*oPUqijdn7N&:tPKr+Ir&!E'$2[P#4>l_T[E8\)!"b+?YOXP%8Nm Z6birG~txMz4xhPݥYlܮa ii4ruJ90ٯ2J`@ՑBq-0BF ~:88]T!55U*a-+++33322R׫ubIJJR; &p"v+W8p`~~A@ `(0 (X\jT3VjG $ӃKPQxx;vvZTwg ?NR; ڴiSSF`N,77jΟ?_ 7{=v+r\rRQQQqqqj pbT 7Qi'=.z^&Wˁ6hN3>9b4z4xdw]m]ȅ?dt:}}C!\wj7z5 }fKS7wX zw^dfB_8!秎ӭGL~;|/o-BSK"^NxZnzHb#%V !)tȀ<3ivOMٔUشokv~C␈:OJnǜQʓ7'1Xja3?LӋL[?<#sww_VbzcՖBh<[|um'셶:Q֥ 1ƣeO H͏}gnvM;͖ I=S|Ӛqx{[۳6]i5_&v3GovqZ>}>stWiA|jIɯ=Tc >:c͖^0·Bh FI.+-s\`uw BG>xVw֠I!lݬ3~H:k[Zw!eBō ̾7;`Sz}V$Rc#R7Y ?z8W\L8#{> nV!h . !$ E7yu83 9#fۅd}%uF_n3,9Nyd}]G;z~g@;$=]pY lKM&fKW}V[x]gc|%qNBIL:E7TիW>>>jg]@ERmIE !D/-%׌ n)?zM^zյ<,NeO`v-\弍;HۿɊ]5[{'.Wtlҩv?O#$vK;d !#{:܀$ ŗ8vg>wy5jԩSR% \zfsz-xI'yGFK!4?o}쒕C|x„ wٽ{vڈcד$iݺu*ٳg6L +X+..NJJT;*UJJk> jg6jH pb ۶mS;ꋙ3g&''ȡCZjvڈvuO~~uvڈFyyycǎԩkv(lѢEv=&&F XpIG+J:s{}w6b 7vyذa۷߳gG}԰aCCAafyܹjX(ĉSLIIIiڴy,IR#KKK{P*$|ҥW~,$$云4 7N!eY尰0?BuٳgjA}q=DGGbynWǍw&]BpG#Cy.CqoDL}UiK_+ۏ]"vܰA&W~/.Z7t5ZD:'6)>!۔ 6T<8]|Ӧ'9ֽNk:`. )K{Nu)gG08p}2TI|Ӛqx{[۳6]i5_&v3GovqZ> x\ĽM S;OJ~[+mgF ,PP) x$a~(Q!$(B!lݬ3~f%YFnXw~2zqqF|$A!4-;j݂%4ZBѨ]BHAJKo/,\v Cq[bݪێz>+sBBH/O39E|P{HVK[ !\R|UB+6={իW׆K $*ʘ,Ua:tǻɻ]R-eB޺Gk-*7 Io4Hr+!(+.U5yo@*Ka;$c=]}ACcİ==@Ξ2狂aiow7ݤ-sQ>u4VM򎎍04DLBt5'g=ꚹhֆc*mҩxՎ^}[脤m9f'楾1y ^r7g.ٚ<+\hX!dȠvږcLgKWx.e[kչ"'&.Mܠ@iNT.HKKS7 ?_~衇zvŔy xɭ@Ay\]]Gv6ܦEX233###zYPX,$S({C{`],^!iWń Ԏ8vV+W80??_ 3жz2qO^4u&rɘ+5pb`UB'|ew}cƌji  yyy ۷_vYCԡCޓ'Op&"7lؠv AΝ+W\fMhhhllѣUL8 9g5f}w[l`8ѣGϞ=GQ; ꚾ}ٳ׿_:uj\\ܒ%KT 8 GAANZjgA]0cƌ\K. p ,@\]]{ɓ'L&NBllW_}v)QUxՎ810 (X `UhvPC8ȽĨVFP @a,QYsssS;Kv U-[vA$YV^vf]`UrR&jPPFP SԺ;' !DZB'zi5OY~캧ONB5M>+ۏ]"vܰA&W~/.Z7t5ZDBȅ?dt:}}_:'BT$~mӊۿr:d@C\NOlJyq۟vbnˣo&= C"]Z wL'}v9_ Kx^ '$yGFK!*~i[]2q9/MN\]㹔Uo}kWN[6qEm1KW'=6/Sd◻Ѯ܄$˲"<<\n:iΜ9GiԨYPdgg'''5J,BBBV^v6ܦXP 8Ubcc{ooo5jtjW^^P{+V0a`/''gםصuV%jN7bĈcǎ_ |ϟq0ɲ,rXXXXX ={VѤIn2a fh4UPMq,U\kΜ9?|nn?zw_%IqW\ |QQQ 6:X@*)vNmܸq:tѣ<;曥BWWW3L&tc0}QWW*]VVի:b$%%C>mڴ<_4MIDATjB5an V[rzEK,YjUPPYb!P 8PP0 (X `(8\:|S;8pbʢ@ (**~+X `(0 (X `(U A@ r&.&&&&&F氂0 (X `(0"o^^AP__^$SNjlٲ<$jz0j榧 (X S ۷gff*2UݳuV!Ă ,Y5l6?j )XK,IJJRdS;Q'.gfK-Z+رA}Ç|]z5%%G-[T; UV }9$fl?=zIri59V[ތ77n tpo$ 䢃w\x`e M 8>:c>}:&:K4J;;1è7ZJ(ntcAd!Jo:FYkg<ֳEC7#ӽ8x8'=h16/"ɯ; '%O{@#WLV}܌~cw$U?op 1<7ޘ]~?5~g͎0HKoOh?y,Ǻi5=tK|+mBB8ooQ-FO'6P,˲,V~z !rrrRٽ 4BIa6h$!.yVwF$$Wn魓sԚIEvsxxA|k7vL+$s4$IM!:mm޸EIhI+ !$Swj%6zwk$8;F!OYzre,rC=5BHZM' !:NkM>! a宖 \$!$h0Cc7II$ ѳosKR <#s /ؿ5W3>x'5_&tI޽IvYu(#}|5M^ynljϦW,,ao =壏X,"!zrh._֓WZ6 ! +6igĨ>B!EM(UI,ۋ ,%qaBl]_)v??6?yvYhLh}7҈,Gޅ|٢`HPQ'i,sʮmCs鞒NoR_ 5HUK^ZI8 9t}8sV(ɯ/顕\s%7$>4锽ҁs"+ߪOmOے I8rr^W>BYmi@,I=Z\ G;|-Je>fqF\S$V+ xwW\.|i؄#t|NZN9!=;H soW9z'+]1ԣ_owIo5勣W[61oK9OnOCoxewFI6+BJ૟B"" nBݤk?bjWnmL~'wA:I.jxppwtx~K,\^V. m\'=t얃mrǛy7w=68InJ| ܡO!8XR4~썗{{J_<ѺWVC-S^ZfO6I.0s# Z[zr3uVx:ْZk4:= (O[1nf]j:ө~E6?-.w8k].B؎8\.3ފk MJ$yw ]:ܢta;u?Xؾ I=P+" !㤕[N'C_<--ɓ5@e .&&&&&FCK=γGP0|j^/! $9N?d'U/w4*S~4kh-.FǏY%k{"۲9:mnܰb9AqH채(X\|ο~l]CsRŎ3/ryQU$_^Uv|K B8*-w_-M MBH&6]/lBJBtZaلp|TgOFF{d2^-**ݪ\8 |\"'~9Ql1⚨ۓmlׂ%_*(klvdOT$xڬhbݰO G^ rןD7{ګ[[]Gu :upVaVY9r\Q+~` %ƾZrӢu~8~v!_:_G&nxzիJ a?C1k Mq1/nڽO7]g Ǚ X@{gIb#%V !)tȀ*ga;i7!u4;(ݎ9&';N~pg_ au>8T,_1X'>vxw#]-;d !?]}JiޟqQrYǚ/#7͸Of-wDGYikv%[ndBCHDwc/ߴfkq\=6^42ǖv3tC3G{5ħvSM5)3;Vlٻ N^ muK.?3bl _< $]0c3627?%A!$٬BwAJ32Ȟ;BR{&aw:2ߙSѭxݕ~T[fl kw\'C!}f5Zm 2uBr7KB`4HriiiS6[ƌnVl lYo!^`* kO]tNsu& !$tC=:t`Wۺ~gXXϓvvݪԵz>+|fv!BM{[u 76;f#m'+v?Sꂵ*K:4 vl(BG-?]ulƐ_|u="} /whxKa:tǻjJO \|C!ʊmUǬ*Wpk?MmzիW Afe[\͵ZW;ꋨ8SN/븑diP>/^~/vI-=*Gt5'g=ꚹhֆc?iݢ4:_!ƪaJM=i8_s+-it-[4i56(gͧK cİ==@Ξ2狂aiow77L=T /t:>8 kҔ!K |A#|ZhUH!%+x%=KYVY!4Ã6ݩ¥ˀ(?kD/KHѱ!dȠΝa=81qmjouj[Y:ɶyoL&y֒dYB !MS'͙3g9995R; lQFBHHիF+X `cŊ:uQ;P۷/<<$)//O8@y7~+33s֬YvjӦڡ8۶޼yW\ygzxx T V$i޽k׮֭[vvȑ#:D*Pf((($իh- 9j# Vt/°aæM駟LiӦ=SZ&p3R;z??>hǎ͚55jTHH֭[ tu . }DzGQ$=Gy7曢"q/BY,UM,z^t$Ijj#EX-[rEiW$IZ+Ln榧 (X `(0 Ċ233"%%ej pb ۶mS;ꋙ3g&''p,QFP @a,QFPNu_lll.]jv(0 (X w7}jA}v P]VVVfffdd^W; Œv #&LP;EXV\9p|BP @a,QFP pbVujA}v p,9R(**~+X `(0 (X `(U A@ r&.&&&&&F氂0 (X `(0"o^^AP__^$SNjlٲ<$jz0j榧 (X `(0 Ċ233"%%ej pb ۶mS;ꋙ3g&''p,QFP @a,QFPNu_lll.]jv(0 (X w7}jA}v P]VVVfffdd^W; Œv #&LP;EXV\9p|BP @a,QFP pbVujA}v p,9R(**~+X HkРA\\\:ťCjA}ѢE SN@eY.HKKS7 ܦE0 (X `(0 (X `(0 (X `(0 (X `(L^'o߾N:U'tB%ɲn:cy48m=IENDB`crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0021_Timing.pdf000066400000000000000000000254451415120503000271710ustar00rootroot00000000000000%PDF-1.5 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream xYn7}c78]0yl 9Ud3H0"YUdFim Qk3E7Փs^GֵN]B}{ҳVW?zFWgwхx" 8uv5.LAaR̍-|wq\b]: SV1eş0E e6nO 7w:Dv::D,8,(UG(p`H%l:\C;"*OEixJC5;TRXQ`VdJ[x9o9yc\L(O&*D6 ]>b8zhAyƖnhjWUZ84MbVbvQp00-d4JPoǂ(:DѲipkGC(V}XL-Ĝ.b'QuDB+\IZ-&ۤ^T 5.2} OGu- f10<@d=v誥6J#y802(>?d-q[k)(I-6Rjۄ6y3a쎹u;9m4;I qy7$Yvk~yhq[/E5\oqu=f$IVm`<81tEĝ &ﻌ-h $oNU%F5';^bG4W5S[eN"K)ϙkժ9=Vr^ƈ19=ƣi5)N@MWCDcC`꒱=[t,lN%k]htZjN͉h)|~}C9PN.xƤcJE= dWrݳ쿟nOmDYz:l (+*hF5nzD0ԜqL+4;Oڡ䇧'QFՠ-NѾ~uQׇ9 'KQ "8P #51}i@e4 ]x4`1+*$爘mŁJr*K8s+ =ԝptYoc+tiJu9)ۊfS9}`R]j[&5Ҫ[Ռ[u{o ux r ls # endstream endobj 5 0 obj 1855 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-1-0 7 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 8 0 obj << /Length 9 0 R /Filter /FlateDecode /Length1 4676 >> stream xXCTU?{gW \a@&KY+ELP@bBB Pfٮ&=02BL+H=w?w{#h<"((5gvnWF#Ba 0!73N/[G6 ˄E?3gUa|۲_JH5BE0ϙmE80EJC!#@Ƞ*+8cqV[k7P#H$ N,&$0_<ZVS|O[[|jI$B !L`%*22&6aƘ1@?&ZY?`'c&q^G2njwo<%G¶mo<- ΛʧE'9-N ͱ ]dU L=Ql=NKxwm6Wl`7i"s@WbiF# P`a`!$hs4x Wލ^|IcWFK3ϹKc.7|xִe>gLS̸a%Ϙ0_!5'^gdrC½d2 [ 7O/^oKH\((sJlBB̠Cqmnt RFKm[X[i 3hy(CHxI 6q.ٻiٖe\xǎe헐}('OiuЄ5Z##\2Щ0o-``nRIE Ҫ `!JHo8Ara._F/i%߃hkdr1i,.abRy+7NN+[SXI:>cl!4E5EG$0Q`ώ0;6 C@瓓 :6} Gڜ@QeOY6= X楳#AqTJm VaX^ܼw?x6% Iob4xW O)  a2 JM~v* =H/Xhs yׯ-V2|ur 8FW^h4~v ?B%q?'$h%adV G;vF$ի-/ G1y)"^< =o{5;,2̂?mi7ܑsanqE kg;b *F&(p1L⧛,ZT `-LḎl`|*. +>|jkܬ ,+O6:vo;AeS0+q&%-( 9 D[o̫c[q¦bȚ%3˼٣F,Kz^cז)OzNh-W+bPF$_i/ls!*]/b1z;[WқKr Qj.e'u4oj ٔL0lDQlp Җ޼Sz@A+7|ș@YPd5F `t*e!L~~6cF/WF⌢ȐI{^4qܸ'~gy^cz7 ߖ[PCL7BvhSʲZ62h-}^qOEp-lX z :PG<EhJ銫~ml)/';~s?[cRb}T7*˛[jƥƆ{^]3Y +00/!V֨s}m~V!kWӖ"%>$4MY;7#'z _'#qUu_&< ]fx 񬌸G^ޖ9 ks|!y94B*Pݗ$Tc]z?t\ 7}d.,ws/d}P[1`{pe2$6tVH(BS`T{; GMIs9}I|EՋA3N0Q]3hj;9!/A W=sOb/^179;2b=ǟGvzrԿ[/;Xd AiEݼz`ס Xq.P[ ߆K*c-=+cZa7ڈ㨭4{#o8Mx!]ED sU҃$UN;^v\qmL'o}X`Yb2z(Y<, Һ Ay'Ne\#=wê8:Vi%}6qv^#W,RJ]!DJX-V*Ik&p\LPu 4^5,MجY"U ؀, W9` AWa06&݆c3ϊ{lM[@(<et~ эb:O=;r?cbXQ;"pȰ @Ūko\Tʱ9~i\+bGMt*'h:ug4L"'FQKIH;"L7 llƯB|A&mZA<0[U=~aхZ~9~-;IXvAWR؅:88ݷʝeX?\| 34é.? t A|i?`x2b%~,oy+7ЃNsDhI,'}A+Ϧ#YG*wQYdGE Kv1|9P`Bk*4h:V-DtxN20w!GSfD~!Z)|407灜Rb Wr4\E~ hP2N7a^f>}R΃5|@1 #t` x`|,"ApyNJ(hl |>C|!Υ><I}$o?.ge 6j@ endstream endobj 9 0 obj 3383 endobj 10 0 obj << /Length 11 0 R /Filter /FlateDecode >> stream x]SN0+|Jj'6HQ%xDN䦇=ޝH;jS=m7i\tEc);ڏIcX.;yC?BM&u(%cvt[Ǵ7_O[P<ЁҢk^HC{@&q9_y&mdB0E:}ܧ=׺5)u]չe)8GL=/qcm7k0^Z/Z d͂ߊ 2v}n@΁B Ixzch ~ޣy{cl^lj^yIjZ[A}Yx0.#³|pʹ OژO*y~Cuu endstream endobj 11 0 obj 410 endobj 12 0 obj << /Type /FontDescriptor /FontName /GPWRLL+Roboto-Medium /FontFamily (Roboto Medium) /Flags 32 /FontBBox [ -907 -270 2051 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 8 0 R >> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /GPWRLL+Roboto-Medium /FirstChar 32 /LastChar 125 /FontDescriptor 12 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 349 353 0 0 220 0 0 0 568 568 568 568 568 568 568 0 568 568 0 0 0 559 0 0 0 0 0 652 653 0 549 0 0 0 0 0 0 0 0 690 0 0 0 604 607 0 0 0 0 0 0 0 0 0 0 0 0 541 0 523 564 536 0 566 555 255 0 0 255 870 556 569 562 0 351 516 333 555 495 743 503 486 0 335 0 335 ] /ToUnicode 10 0 R >> endobj 13 0 obj << /Length 14 0 R /Filter /FlateDecode /Length1 2892 >> stream xVSTι.ݵ%Nlb. 0BWZdS䕤(@4c4jDiiЩAMLfFkK[gQQݻkNг^ `P[sek8WTn=W4ᘽlG 2ǜe89bRY řb;˰_z _Uyj $DM~< 16 zGO* %:Ukc#|ar)EJ= J- 0m%Î,%¬$h%hm6/^JwqO5bB FH? 'Ձ@qF[Ӆ/W 67t\Jjak c- >qie8dzL >(0&." 2oxy9rL'Wgoיqټ82 q)tR9|6ql Iq`14;.軃$ݿw%e+-k\壱R?IfR?"nB1 լ1*`N@_d3Pb?VAw(e2*o/_fdwn-3"|5;7Nr ,cAt9ďdd  T EbZp} F7{*91?.fbs*bpY@cyJjj\Tc4v&jmh>³eɜZIb}TTKCD;  dM $2JH4SPcc^x欼Xϣs_ %VzLk򴴶m}13sm_?ΜN✇6GmBBQA"vd qnqЇ$b¢c~}&'QyܩP~.܄(ǩUddB, xfx4ԅE;*,dءòsژzHL_`ELyw;G+9HYF,$scv?Đ5bbLƐA-ݳ+׿:`QF!2ř,n:ӵsFėRwZwx2Jc y  8^=a OQ E~ŢzK&j ]z zn7o]u%_]("*s*Z7Ԯ3ohsב~i$r(׷HxAM7tE)USBt)C zH)*X}~ɍɌk_TX9~1xcq b|9,qn#u{3XO+Q(Yjѣ2]Ӆ""Ԫ"KDd)*אnAgʢ^?m VO5ӑ'r' r>"ҹ e!=\̛ZSkPLj }*Y\-gevIWCy&<[VC~S ''pE-6A8n۬kꢟ*[O[m p9jLxG ܻq4i YGX7gx.t\ a$=h珆>}xTYiz.r]5[+:ؿq{"sl|NhqX#^@`=iòydDo\RC&C.&.fcHP9hk zVţQ|PxfĤ܃k' Q5&y/l9Ø<82[p[G0or DlT> stream x]n0 Ew}tJ0  eAv}E1H6.0W0| aċu(A[F&EmYqꝙEB'5l{1Xwy`4\ :hb_儐}]}Ls|nLシf tmw t\YqhԷ hD<&C䊹"~b~̓!z { y7s4%x ~`~ k_#k$OŞxü!ͼN\ď̏yjNCu*>cEgx1Хn|[Cu:?{J/ȡl endstream endobj 16 0 obj 330 endobj 17 0 obj << /Type /FontDescriptor /FontName /ASKZFP+Roboto-Bold /FontFamily (Roboto) /Flags 32 /FontBBox [ -913 -270 2060 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 13 0 R >> endobj 7 0 obj << /Type /Font /Subtype /TrueType /BaseFont /ASKZFP+Roboto-Bold /FirstChar 32 /LastChar 122 /FontDescriptor 17 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 573 0 0 0 0 0 0 0 0 0 509 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 536 0 521 563 540 358 571 560 265 0 0 265 865 560 565 562 0 365 514 337 560 0 734 0 502 509 ] /ToUnicode 15 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 18 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154043+02'00) >> endobj 19 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 20 0000000000 65535 f 0000010323 00000 n 0000002098 00000 n 0000001970 00000 n 0000000015 00000 n 0000001947 00000 n 0000006603 00000 n 0000009880 00000 n 0000002316 00000 n 0000005793 00000 n 0000005816 00000 n 0000006305 00000 n 0000006328 00000 n 0000007092 00000 n 0000009157 00000 n 0000009181 00000 n 0000009590 00000 n 0000009613 00000 n 0000010388 00000 n 0000010505 00000 n trailer << /Size 20 /Root 19 0 R /Info 18 0 R >> startxref 10558 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0021_Timing.png000066400000000000000000001447101415120503000272010ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxg@SW@,KnV{:Z{Uuu ^ FPPY 3Ж5'_s!B!tw!BU &ORB!*u_]€U>|xm}WB!+֭[7,,L?U{yF!J8fť] <~*tOSbϘwA!ɳ8[i̅[)d=|-˹u}+F}4n% ,j{x9q(>P9TMΫGY*˒OQ妽NLH̳hg˥&ƚ+τ%istQZp;HNv4r}JR;gnBJ$ܜgl^ˠkX,-Z4Ļ^<%k,n\NДl!Ib3^&ظ4 Wbed+5@ELLK,N݁K5Rh^*?vr;kTG-̲M#B#4Ei2^m(v7& w*F<ᖾ# ]zeʖJBZ">g)z$~q͜j4ڄ,Goװ*:h"m=Xݧy(vn4hƬ3G!P%GYY\EǙBfn[w_+ ŵm 4.PjRɠLU*.NW) S&@TkxRB}WQR66^x$[Eժ%L m4FF>Urp OJ1twhݛ FF&ʋmT/ /߲jc݂&EN۴eAkͣg(1ǡU]~ܼ~gƙ1+o(~9T1s&w`.6B!*~$i@P'W߻صl׀OJET*50LD Jރ˺>ּRJ|]׶D6"dXi@t %dr{q(tiLT}mer z$&6woy?V7傪#q^!B_b <$C ElCôL9amLX@b}8oVe9y)$ڞ"Iky)[̥%Z,%^ñ*`2J,/ 쒟| hF}L. P$K((+4Ohq(K,Bh 4߀lKWwcDLEF/erG`a_^mC ߋ2v2*B^?OΓgV65K# hm[hzCfBU Wd}m[E`'Nw%f[~yG-Ek7mW(Ӥ#mO=6z[M:VD̬O B}4sɧB^b5<{ z5cE lXO^^^Νcbbvޭ2BJ)黈q,KWUWX:uhrfEp UXXݻ"B!TQ(B|x=a{ uBz ;K&=ܥ>bt-r ! *{7>0}o !B"dY=.0]!BS]F);.LBj뿀yy=R,[,<<|Ϟ= w-!P֭[뱔*``B!5kXJcffVn]}WPغuk||@@ڵG*҃qVX B8xիW AߴlBa] B _*G/^w& Pu !PyiԨ5 O,BCCCbСCۧr8B#Xz€B|aB,B3n0`!P !P X!Kkp9|S]&. |B&n}OhĻxNh~;wԯ_d{~~Z:tyv*0,u/sw>SPfm|{7ŭ~c'c2b¢Oh XJ7BՖ*+FQK@ vkФMӔM69n!.&>|FQ{tq9.W]JQ-͜ 8\uN<)C٢E WBՏ*-MGMx\έx5PB:b^ծۺ'*S6 r#.^ś?5裯5F ,jfP zweZt=pQφI І F, 9Qw_TJآ=ݜ[* Sj _>(&Au_3/a˺u_u'8hѹ J+~ԮLxܦg7ųl|~u川W 푗'IT,9mv-n~:L "DUK.<2YSh8x5 ȏwmla]Xv~i'v-y}C7>VS"!`讀G$5M$+1~rHVش tB:aY;y? _trXv!loandd&9ǯЙbQ&}#ոQG/l`LgɈ3{4LS5g,ʤo4eyo?!B!  ,,L *XLŋ] VX1c }ׂnNSB!cB!t B!aB!1 X!B: !BH0`!B,B!ÀZhvMzꌩBUæf¨X{CUgB:@[G͘!w} 5 %!T^Hu6qV>]W:nu6˩&J$YǴp5糹&Gfb}/ffV(Ό`p[mI&$ʾ leWݭ#Mx\_o4!tBH䙯^Hx){wvK&+zu}9`kՋǞ;ugRhdN0vw[V ysl+Ocv,hm1/gC&~G߶3bђɁs{ەX !x!ʨ-<ʃl]29U3c4mY B MH)jj2yT'<жCNڄۯqjݭkI=g5˓ ?鍶[5l^B,0]oXՒ ]$=:1'b嘨gF@JtB\L͟0,*!=O.Ӏ\Qz >}m+ -Z^CHEjXCMҦNS+\d_.p !T>.\3W#k:Щb`طq{zO7\5:W2mO 2}Ŋ}O=zu-8-ɬ3ȡG 8~cap.!f9E;T)@9lHNv4r}JB>qTgX ㇫f!,WڙG )%`o)dV_6Q:"]cF1 JRFE)S)fJ WB_eTM'd$`w,W͔3uRZ9("ud + ^rXWM,zYr )!ڝibPCu]^5q(^$`#A`Ci;R(jf'j8tgL3l$ʾ le9[bHV1-\lcw`s"{/f{VqfjK2)m(Q3aP77L>~|2}_LTfjRi9Z}6V*;"B BA```PPP#mRud*f/ (}CwuS 7_lko0t6}| EU=[՘Iq6MlA3lF#}N&ޝ}өde)])c5"~V,ږMx*ecɾ\#E! !$P ໝo4,>ӃEu4dJG': D{O35pݫ܆K/):QY2؎]l޹aRptYFlOK:떒BGӜ_kJ 7m:7/)iz.:!_*77VXA9u֟P7o,#n\XVVVbbbv"D}̀G ;wu:0lF<rzu?:Kܺs]Z{mogľBYZr;ʺ~u' ҵ++wDʸmO_޹K\n-wgkqtܯ9^ysk_ω:1恄2v&~s0j_D- q݄)_{w" I^w*L]?-}S -{֎ dA':|_Pi[B;*BD(7%ܖ/_^7Ǐ4hPN֬YTr/B:G&PBHb_T򥍍~؊HJVC4Q65[R^@H)]>xCZ7pf Hڮ/`eܶGK gnպx5j?}Fmz|>URL^#O_B@VOiD\L͟0,*!=O.Ӏ\yL81>{w&P`Hr(%g3gč`  lܸAOƍ˸#*oBAV X}ūF&@K0vlތ2i׽sBk]}l}: O\f|QS9w]}&-!o?<^ݾϞvYJ -6lX˖-=z$]B_B>4%ݒV>{Ѭy͛3%QWoي.SWG *gj :X,R&z,vѤkKQL]\@rC%:7GVIƥ5'}9' w&(ݰ9glboRiz)6C\ "/OUhON]YR(7v߾}_޶mkA/315dg,U\)Vq?ۈ>^CHEj)& F]w_c3jP >-[WMG۱`͐~97h{J ъ(͆ ع|M>~];U3֞Gdjb,EDṇWY#9u+5)UZOz;1%6Ҹ;HJ}+RQ "hܸq&M:4uT}ׂ"D}wB"7{rfHU1K|YEosc7& !8rY#ݓjvz1fl^ nH4#,+ey]| l]!nfhJݸ=t]Y@q7Tj{G61d- Z8](^cibLţ(B# og-X}s.m2-[t/3Z:lQ1S1PSw;!iz> ~w"رc꯸}i"X,0=P ixnUǭn1aO5g몮2N]^^+f̘Zҍi B!1 X!B:# i]ESзWB!t B!aB!1 X!SdžYnoʸty8؟&n,ŧGļn".G`i_ #Tz-^XU XKkg-\߅Q޵{.87܊=E*]T]B{nGc80NS}'~6ף!TM6t WB_^^ٷ6qԯ)giɥ4@"ijgsMFm.ӎ r2qM\[t]$AMk+.s+@qvTM'd$`wXDzwGWh /E w`2k9+%zB.WdxgRz(g{G5 k53&a]ݸ= )˔vij U4Mk4}WE|EIrUC hne1K|Y@qی_2+b8O$Y2؎]l޹aRptYF[S,e-߷LjnJ3^Sz:vl~uE4pȿԀEqg>q;/7ew|~>BQ jB䑋qV|!-EC1iOy+Nlm˦̓QCi=ˮ`Qn]/ щG7}q1玢HV6SiA'>}m+ -Z(c@=|n0lA2]<ڳ*40jԋOGoÿ!TED">>GSQPHܸϟ?޼ym۶;wn]BA;:<|&&2<-|):(߀iӦo2dHA_,믿nܸ?88xjomoSd-wX{*H9qyGΟ?˗/tUlllΝtҿɓ. !+`ڵ]vw]xA9 x9sܿ޾K.6lwE!*ZN](S[n;vl9cիW?i$B1m4}WϟϚ5KUJ "/[nw =cǎǎcX:}9tg̘ammݧO}W @m6}*7ccc.**:X/_2dHz:J_ ƞ={GZj҉']B}t| ѣ !x}6}7|pB!Pe?Ϟ=RC/ގq=-yyE}O 2)~g*)g[awY O?/}OժU^~BY",Ym̘1mqN1?|KJ4Eqn{KHփkw\LTl) W^HHZؑBU\Ri'3f0R6Ѽ~ڬ)Y۱u5xh>k!2>0)'E͞=ӧOؑBUozyyiGP} ޽{kX!&Po3a?/oȦ([*nM ;~G5)Uwqt=4~JZ Zv6I MAby5Jh z.~aHLc-r ,\.ȐIb;u %[oc-ⲹ 'P\WqO]4g;b`qkSɴ-zַq"f#w}2ܹž}ʴ5BJFOOO&M̛7N,<\s$Dyt~^k: _w%׀ʌuf nª1Cxbd(uh53-Եcsli6H)7, 6uoŨQ~6ō6DBZ"NsujP2\VX,VnN>g BJZn]VV֏? iiiAtww;vt>}TE׵:ڝ @[t]sɹ?)mb>ErN\'Φk(v>=] +͋]sG0pwIm]kP{l5%h1ɝѱdž3HM[+^4BF-WKddˊΏyuhðj׍蓓_FV:zu\q[1faU߯jNTH[M>rE ~6ڤ'wn=IHEkiR]hB*FFF~|#yxx=_~)hٰaÓ'O֮]K#/^z:#(.Z (u!4,Ɖ34iڅdF-# ΃&b  RLʤU4}qle(0iĈqKN$'Ǽ]y;xLnT)L;&܌ /KmƎ.5QmGS@#H/&~l#,Y"L!!!:uj׮tϟNzʬcv'g?Np㵚fS8& 55kՠ!I*mljDC&[]j>P+6v"NO3'u8g2ء߇/ڵkX2mB166^`Ioݺzj}UfK*lCCۍϸ+2n߿ywtjʰE.T ̌i 4o޾_QKyML2u0(v^ɛ[Q[Gx(йFZ/6{c0"H"|>!*qyxxdee=yd„ ...M:B# ~u7QiexPU.5i" %jӷyѰAnHΙ-bs/|AAvKDI5? 05thߐs< qc̑$-/W W b0&]j璔6->>\~^!* &n:Zϟr!>gQ(\dfb$h4/",uam]LK;PG$057s|$Yê=pD'DI%M,MFjhxҨZ7TZsOȒ{LֳgRDzl[gr@ %`891)P[gTs զm>:\P/AM6:u'] ?cZ:jiJ2m:@DmީomΝ]?:4K[X|bY)[Z |{.X'gɈ3{4LS5g,$vE߰~b}Ic%i1!MByaÆ ~aC,@XXؗ2y_5##Cw}>f9꟧[|ΙIMҦNT5GNں>HK888ٳG߅ BUV4+ EB[^9\ӧOmll].NS"wBURfԩW_Q5k,}WT0`!B"l۶ݻ C<}BqУ -V&&5J@qm=23QTd2(&jDž7ANjptPJQX2RN`ŊU-B!T ,`q8iӦM2̙3U cuH$2%SĈCem4,š \}*hVvwM 'GG7%\L4il)Q\r%44444,!]>}ܸqnnnǏaza]R$-"+G'W߻LB(KyrYL&T*RdR%ZX۶i,< DzuJ|]׶lJ&;~ Btlmnjnb N"PTj@e<]SLy͛|~B!JS/^EXXXzv1w +!B EQsνth۶mVΝ;Wu-!w!((H&>}:$$׮B!=)UViƦK.AAALf^/_Ɔxb'Nx!=)S7:p={6mTH$…/@H$b޽;F+BQAkHw޽{V*=ήCCCCCC;;;??? !TI:հaÆ V!B!B,B!ÀB!cB!t B!aB!1 X!B: !BH0`!B,B!ÀB!p| IDATcB!t B!aB!*"O ,嶄BQݞby/hG#ѧt46zy|E\ʻg9i5%ƈLx\M+iWXJW#luTH uX0]BoΖC.u;vGߵT6KhYRȤ/գNJȻ6cկL\uӊ=n.e7o)K(ڤ HƉGW46{q䞍 @ҮӰm=r]ˈ^,qTE!ʂBQ_ rί[e❞5)=y#d}ShW'өӾ?RjH߻% <1%Wz79l s3]:s֯{̞"tXy)BH}9lC:g/K%ٚL@Q̥E[Ut 9؝}LDzwGWh V7a{Lވ3qn33ڻB;_(ԤЛr}[83҂m%c\O?+C_7K^#YǴp5糹&GfPdžY r2qM\[t]jf'j8tgL~u:uĠҘR+eR£x=vCeAl[ԎyyU>reOO#@.no^bˍ1Mjޔ}~{ψEK&j-9lWvT/ /߲jc݂&EN۴eAkͣg(YӰHakwmȴ3d= Ntv˪A6Ov EaǡU]~ܼ~gƙ1+o(7>9K.\L*"qՋǞ;ug OS?ߤ3pY#3 {L4 sPhܶ@6%]8;Ȳl 7,j Xʒ֮ef>jJ[P LϦ y/2U"DO@B;ahnz֎ ͧ]8yI:ͥWe-ۙhJlY[; xdݰsP޺s]\wztu92xC\b7!t^}Dqtׁ+4i"Pc#؍ĞbG{&*Bl W!(ۙy3G9;;ct@>tEn/&6ֻm}Z{g@qi~"w.%]4QXlqMޯ7'> ko[X}xTe( ˇ{wuwqVx'jTWf4jpkXǏ(Xs B}]:aiKdz[6zjmCMB;{щ+!Hc43NZk82'LNa @ @( TP6ѿ0fG /46 R3F4-OQCgx~nGRԦ= 6Mjv᧡;u{u9 @@ptr,ğ1G9l-K`x!SnI=H\vl~.FDǕ6hfx_TP .hո?m~m[ZuFM~SjxQ$CwtA?fKTZFwdѦX*ah^N-_jH%FGGAOZ,KF\y\ES^]~.m+Y0y~LG[G$|м\-2/h@KWRAdY7F^Cx8>p&1vv6kTܜ9}5䕰Hk hfX5lkjÙm~+U7fGuNkecs.4c7Y+{}ǻk]5Xӕ98Hú̸gݡ- [lqpoF$uyud,N:YrdmZ6>tlr 8r)#Gg hNBsCí|IW:B΄}{'57_9B :Io I)W ٭ rJ8wbEO=|?R6~0a?o5VYӦ +?.t-{Uϛi~B$$h8_z^6g%a ){9@0B5Q?콯&&gBCESfl{T҃뻛 Vum'/n;3#ˍ:ک]{5[!+AAA^ Xʿ'm}=Mb/?\ϫ`*43 .~N&o[{*E~5?mϱʹټ ֭ݻw+78ͦY>B_#K~xӮ2U5[֥Jn~|$IVoe7b6̚z諭_}_#_o$vF!TH M<*mo>~'6=}s $ޓv4aɊ?d힩>Ŏ-BB賢I'EEYdyϟ)̭ ][!z85-*;ѳf"D!b&X!B, !Be`!B ,B!aB!2LB!X B!*QB$rF>S HRXlmm-}"BP%Xyyy:uTdd'OZmuE"4mڴUV:uŕB!ިӧ-ڶm[vvv56m HjJPdee=y$&&̙3۷oo'MP!B9s,YҳgBʵʕ+[lٶmo6rYfjB!Tq;wի`oѣG7ou֭{WXu !+:~xƍϝ;yf++r233_"##Z+;"B*СC:urwwyfPPPytJԸq7n4lذ{;vpBj+22{?w\5XoԩSAAA?sLeBUG,'XݻwUѣGqueDpsso={V B ȑ#gddn裈}2cA!6sݻ~d򥸾ش2ie.ggٳg;vȑ# B!T`͚5z„ ,YX?ca >%!z:ߍ2'-&Vw#\\\fΜI="BUk ֍7.^8~x@V,jgĴ37n;kb*_\.w7o޼pBeǂBU#%X۶mDaaazznv"@lwѹjaVz![)sQ*i޶nM/4memfBx w,V]qrRpۙ!Af֯% ~6ƔctkB .Ƹ1+.7ݺuJ۶m@Bjm۶J,{qr3]K7nغ 7I킧_g\6حi&2k9lul8Ϯ17SYoW1^ґ+oFmoYh:u0 fMۙaaN$uѣx!0$X-Z`5խ+)‹GO^>17Fs=xslN1wjw&!'sq׮ƜRKO﹤|Dz휃Wb7{K1ׯލPeŨ~Lxx`cE'-[LMM@Bꂝ,Ν;P~}VZtļȅa2 +{@9# Tcdm%w r޺cLCN؈eG 8 s0f@̒_D|Ɔ oC{Φb 4huԩXBjxpvvf5vݓgVO.pĎ<+Z'6an;HA0ny/5yFXY?U;88p!B+##d2VZٴwGl^0 }vq~`=.?Y5t `?b2)|dx$##A! v\}}}V/on* 7ii@UO%ip8MKIUMqOA8h]7sWč?˪r gQ?M,gggWv!PuNE)eH8t/NP'}N+ :cp\T7Q{ճG?W:N֞#3c=95LfhdGB S!Pa]`jqnDŽURY1 ˆطo0FJ èatڵk׮{ Cee`U xZmcbb(zxP+MU=X#}d !¶Rfbd1&B#mڴ֭[fff...۶mzjeGGUߍ2'-&VPg"leM=}t???Xnaa1zh|'BT\fm'wtT6Be֬Y)))˗/.;o޼+W!*@Mh놷[S* mvv0@9>sϾЖ;''ػTɧs25ڏu7YlICyGoSVРs@U!Af֯% ~6kPE瞫+j=zh_~aI>}5j4yʍ !TMQJ)S=𓫿Oqkn#kX1 9UA|•ka!$D8NUGpo)oL6> \}X@c$Vtke#[VU>͎GG(q ; T_oOH::ȑ}utx^F zc6Ǜ.R236t2#[~ u΃W^B2bk+)‹GO^>17Fs=.b!!r3f077/Z޻wCUgU,7FUfYpɝgR}[ .֦/߸LCIЌ󷔔HŖP#x>Ub±iFk -&N}FuȚg%u/ ٌ2;cڬ,R^H"2ӮeUAH$׮]jKxdӦMe< ! !Ŀ>2̮ %zb涃> T@fg ̴ FVô0gblݐ^N cneh_g_C)c;x3 di8bG\^靕V%BU 0\n $ !TYIXԷ}7 {:sՋgZFj(}R>*DF2mf›T};:11Ӧ!C@՛6Mʋ-cd,+My'>t[g~ '~XN[!v,CCCJFc4J=%wmEVlՈfEG҂ɮ_kcӨ%G>?jfD5@8ЦG6m@HhΩubs{L\fltN&~ysS$hMOHIvOkz(144d-B; #dz1g%4~u='F((U)Uf94ٍ-MM]N2Ҡу +b8gwӗz;[-VzsK%9Gf;+bYGD3ώ6365q\˳=w=U}i2`i%ZtxZvrrb-B; '\v3lҒ^}-U~svc'[z=k#GWu`VvbUVϢn ;gwCd8/e.G,Ο8`p5!rľIϟ_ױFi7Z}v1'O^I5luYTaRNOBO˞ƦAg)iWp6|V2~Ih 7S7uy^;oYRLK$5WÓX8%(R܊yx HKX9;%ε5*ZXXIdVRefVAmK]K IDAT^\khi%7JP}&MMB>)TOPGv߾}{3B2b0ˆ -ZhРAw c=b~ J.D ޔ(߿!qsMsƳDXA;?LE,},hZ \.pШT~ DBxjЂwS|zu D|\IvdF?WٚB}Ϝ9UVK,2e Vn|!ti*}`L91*90F.MhaEx: Sa Z:$]|:Y`  FY1<4sI-[[|mJ;M֮]{޽)!PEb3jٲe.]̙ӡCڵkrūq?9ޥhi6>H6 $?/@@ ^>|mhZS5r [VNjJS9T* Lj<~2<)1̻ieW ?cpppNؚBW^-JCCC333mD"*DĆR켬 $#74N}nc^X"TC& -䛸6w)H]p6^6E Ti2{2… 7n @!*r6RhhY]?bmO^+>\xN2zz]tiǎB!:|cǎ.] C ye9uTR[OwUL SSSGV/\УG !BE7o;vofoo?t+W_w͛7GmggvڡCFGGVvP!P /^pӧ#""vU~񬬬[nݹsgLV B荊H I$0~INNN^އ?GňD"[[[TZٱ B`%===+kBVB!'LB!X B!0B!b&X!B, !Be`!B ,B!aB!2LB!X B!0B!b&XWPSq2}LZq Pq`we("kCkS\y<j6*6+\dž89[Byw7f_)vBʧ3$]4'zwAF"ĺARg=]JD!`T:q Obagok!ᒏNQ[5dZlв-C94aGn{h:eڀiGft:^@ӏy)3֗ұZ,:߰8 Ab?!EVvUrJPto:UrZ ?c)5$rW<||^?|H$4rjZ6S/.Z"X |IaG h"n(t1ipF*C yn 4Xt_w&]woȪ91wMP(r:-SeѽNߚ.6{pں?ųk+@Ri#  ET*h/8ԭSߏ}U^¹rfTL$2rj=PmL#~'Niv$ b!J)400000"]QJW52B/ọMXpi ~JiIñt"Kg;3\Ϫiݞ?ۯ2Nw?NKlG׷VxO Ξ6';GKDzzof^pÀQ* [sI- " -aަ@*/s @ @( TPrtI6GÉ!LP)(}WP]x m}k1^_ZC=ǜw}|wwL}G{l?Oj5 N4Ia#\.PZ]$olZWfQVc3[\sK% -LT"U^5NZ +G(BS`t!V$;JȈ=NsxMLmlk{ d^v(>&M?dȥj-]o?J#-Z̑Se~@ҕT;8Y2ЭGߌ(o]٩8u~k:9{oQZT@3Чj?5j5-DZH, 1*+WWyTJڬL153BUӀtt彺k\~V4rtGc~=wLyz4TRSi}7&i6JK$- ~1~krb,%"#c}RĹS~ߩխlk_l]6(Pxkh>r7xM8}I߁ڞs.hzV8m?%vkF $EH;ֵ4%6M;][Tg53\=S`9dSI,<Ե 3TȎ]o`:UwC$DWZJo>g~|L&wPe)MJ)@xxxf{}v4 'p? #mWDW݇&o {zܼ͛v]!T!T0a &8ϚzU:SBU  ]k|/M{*WYq񗛬3GBB&we/\~8&&ŋ>t萅.*;:B+=XQQQ^^^F?zhRRҺuw^vm̮ >jժ'O9s￯Sιs*;:B+ ,((8vXxxxv8NuWm1 ӲeӧO_ ôjjƌʎ !%h4}ɓCCCo߾W_G/=-Zyf߾}޽{Tʎ!eرcׯ_?iҤBʣ T"==M6yzz;Vܹa$B`-X`ժU?Ü9sXoѣ ŤIgϞ] B ֥KM֣G̮*ĉ͛ЪU!^ؼT*\V׳,4+Vpuu2dH~~~eǂBU/l&X֭[zX,f(/hf)6?/0@H/$&&.[\bC!%XJrAAAm۶}X?ca >%!z:ߍ2'-&VRX`@@@HHȲerss!B:ѣxsPŲAbsaDŽͻ8}Glia\II B裱c++֭[kPE瞫YlICyGnxۺ5Bжai ɫ y3:F,tŲXuI=n;lg|BǯZT( W_^܎ѭ]k ,̚ˎK~GMZ]+KPhP9ɪ";ypH(:7 K4֔ 5)a.t sNhB}RH?JH$CҜ \0vmY a)Qy[+حiFȱ~gc.µr2SK5IMo\b Aս xkP[  zsbTgok @,.!G Jvo=@8BTKaTxWf_8ыd ሤ\@Du^-6 Iac'Nyyy"quu޽{eGfS` P:g/~sݝm4#ר=ޘ} qh"<}B~>wj̙)uTtKʷms,9x%αy_Pyp_KU^zh@Ԉ8|oTx@8ZJffZ܆NfDxԕ+ժ_[;zee3FdŢ ۺZ2w,>NGqt[!kKVP(^+B!> ;{85$1/raب-:^7FUfYpɝӐ:6*\*dv ȵYYkQwTؐmhٔ)VfDV@ͰbgTI~p\Ҁ+}[ .֦/߸8Fx@qkP9W! 0?޽{e!B; ӧOw?ngVO9fY]ģ&tu Y8tVrJ5, "fk(0FZw/f e fgLIͧ"wn,rA^n^I`keP(|vBO-B\.My'>t[g~#_wi>~.d2)|[zC M ,iR^h#cJY$<X)r+Vb}Ð?0@BT* BI B!h77Ljf|4@8Ц^D4b훹>[č?˪r gQ?*>1lڪМS6(N͚N͊]OǦQC{M O@swK)Kry POO///#ZD!Iq_9-N`-&VuH<8:r nN?4g%4~u='F((U)U%fZU/Öj&@NL_378 3fmflj﹖g{(77Si߳[:eA7X?fb\ĥ˲[zKUR}!'X܎ = ^]=yJa]ΐq]E;Q]!-%wQy1&%T/kLĤ㚓[Gt1h5zn|xkB0Z\FbߤOίX vc'[z=k#@Xwшih+ ǀ~KN^W@Bz`!BU겂 QJry/fF,/W*K4eu#777<}B!T.~З`ժUJ@noۮnMP_9 l&n& 1hь ld"ĺajlg(Jm[+WPJMM={vvڶm[X.\aÆʍ !Py(+gnܰu3nŭOϱD@h^ ‘YwTrȵi3/ `ݚ6o,cwth6`*>H6]W @}wU75 9\92Ns9IW9Q#۴irs6 IDATs,YRSN[6mZZZZeB`n3^I^ ?z6L~lͿttv xslN1wjwM}܈LXt353==a[WK&ΚŇ3ެLq7߸v Zuݹ}oO9CՏ.\Hd}"88xΜ9.../Y_~C!c,NMG{!I̋\6*kˀNƢcϖߟ:$?{8<-6Ŏ]˧ó(0[+G ͹}%m (8u=$@Μ/iVFYxFEm/c B }Wy`{nSvs #. 6d_gkk*٩@OM6mڴig?WƽUZZ6aT*.E!*; Ann.}l;G6/҆>v`U5@ ~΄Ѧ_c 1hޣ){T#"k҂`D%z !B偝Lվx77Ljf| %qo;3TPP"mݣ)MU!ڴT5ITQ˧ }%dc ;;[.Wv !PuNU{޽{й0;-rZ@ZL8$\됎 l ٚW=2"Rp\T7Q0VOk*#'02q9b@uVRU~Yrf)wX#B`իW\t Z}v1'O^I5lu7  `Lh-- *v2q#aG#vLfg( -9ujz}vŢ4Y1g/>*eQ '?ױ`LK~̉'N.HʹO|/UAK,yc":qԅOEV>{ |#C[ڏIDD4hk"B蓰ghРNjЅ- 8b[}r'^ڦU}YS[ĩ(Sbo\Uz׶<iI~5V1W 6zD8pk"z~fFM_[=QrDM 3FHKӦMETƏa\^ف bY944ʕ+ \C3vw73t Te+MMOo:y&2.E㶡*Y*T/1wt)Pт,J'*3 hZCK+~Vj&{!27# C#Xxٳa*B!qXKzV\Y5pF5 ޸wOU~菪|H"3$~~uI6_'O:ynT_X,}\kAV!\.4j5-Vij2'WA* P}2-!* Fݻƍ'L`mm]E_wV7_]J L91*90F.M Ϧ ' P]EO K&}_} Բ_u+FPQ^K.eB!6iӦBƎbEArrֻ)yg6 o\ϤD |/DǧZj\.)V3vkڪMVNЗ9Os叢NBէʓͼk-'Ϛ5)A!PYy'Ouְ0[x' 2)ɩPJ?{m`:CA914ݜ, .Je/e0xŗ: K(Vd_OLzAF @_E$ֵ_ He[x@B!TX~}ʄ Μ93l0___vX!o,[!2 9=wW޹wb_K,j{;HCۛwOx:2@P/' D\CO h0eK иqӧ6%!*,avrivۯ8D( V{z)<kP5s w &.]J/!RV36fJ{% ?a}W2l߾}<ǃ!B܃UԩSb8((㬷_Q=I{*'N{o'}cΝkڴ):uʪ"BC!лO.**)$$d񹹹KJm=-˰bT!nҖ ~֭[[XXDEEVXp!*\,t×.]yfw;vxxx̛7/,,ի666B!T}WBpժU5j0`ĉOyc1*N\ztppݻs6mڤWG!x,or/I&׮];yuVXh"777{{{T*">rݓ\.M6Vj߾=N&B!T{U(888888===<<<"""..֭[r\PTL_>/Hlll7onbbRA!B*(*dddԹsΝ;Wd!B`!BUO`!B ,B!aB!2LB!X B!0B!b&X!B, !Be`!B ,B!aB!2LB!X 2̫kfx8mZ&8BU+eֱ{u|6C ίfT7@:G?{q^@])Nv\~#mNቈ o<㒐a|4wmӺvXQ*ƋKFL _neӧ^7>ZZIJv:|E"/V^+>.[~Ѱq5_Hjx1Ƹ?寯1C#\I>vdpUU"imorD9~iƊe?l2{.:1t{Ȕvb%-;nsͶ~ر 14 _nk?>S,E_9r]w92,Jp1-Z#wm=T2k]S|a g)`)3pV*=^/UfZWeͺNZ6vhY)UۦpܤȤn=!}_|ꟿ-68v86ˑ{'Htĺ]{~RPyӷHt͖uJmhHԘwXD rT*;|y;7S)!c\5wDDze;XP `U/Su5&D|ٷ eoeƣ7գzO?#"O [u^n9N)k w{||ȦY>9r53ڈ+Irp^חF8SLi{G{uǶ+naĚzf\t(vnbqK%cIȩnS[LSf;pб?SN"qysO|^^>ϩT%C̤VtLgoY1okƾ/_7y銏KN,1e[_-`""Iuѱg t/*<"V+(/[ˉkdܪEӂz Z`p/5gpKcGB}k:mӖYR<}Sk݈-fB^S^skl\{)5Mɱ9GFz$54r1]нk 9G+ƞj"+4VTXĸfRO*{C'NY?ϝvofP>kkC}(äMt`&F"՟ώN{c.&#$W0rxRx`:;117ep?9^h06:ѤFu֝ݹIR""J(G4WwI2H$WH9Ԕxfe7W:~LG3U)p*3NJ K?䋋ttFIcV䅛7|2~6 *c‹X,"*})#N$s/S̘Dgna'W91Ne|jƈ}W_MyN0Uk#OLu_?'?|܇y6n]ȿpLsn"Fao~Eݙ@$1LF8,4j+*(,9MWXh$F-,cF8T+Z:q6>N\ΉC1z"">&LԱiSz{XKM𰥜S.Lڲ1BW,k1c\j:U;NǮmqk]8"b=ḥ*M6ʂ]Kǔybo3PAG .^Z iYNc5k4]>u6XKRG+;Ff0]][P` V1.dE^燅6-ڧw;,ɫ玜ᛳ{&1ɂlzZ*Dt-ڊT&՝\7m7<4ƌZl[zUvOD v3>nxF;zFg5qsl׿&/zۚWyp*HK#jTW|9oq0ϻ)]-N~uɽW+_;F osUOXk1XXXXXX*b1fJ?8V̬w)$c[1Jrh1w"0X7Z1LhÃ1vT61t;ډdKM}Zw_sDi>۳yeUWwvvɓۼ W:M=c<9QAssdZ?n|ofr<-gPPMټf|ޫc8_EB tmJSGN;Yo1(6jA  0,!`  @`XCX^XXxÇ'$$ܸq#''d2Ug/Hdii٠A//Pssn UMȑ#˗/_RZ^$ P(w>rȈn !`;wnĉQQQփٳgPPJW @;v,22r[l \`AVj/ڮ ` )Sl2!!a)))˖-k߾=ҕP EDDĢERRR/_8n8NWӭjU233Ν;tЄc"WU\>rȋ/7nҥAAA5@U%!!![n]bFQ! .ܾ}˗^ZR;޾}{ݽ{>ꣿov](Ӭmt+UT\cW+#"uÆeb_GvdϥL-ILtW^-[T8/aV~~ӧ;w,HYw.quSsLwhH=?>hADҗ&lݵaDߙ2w No}JCNKKKK}fQkq-eU7c/i"UiRs[ulSNiii0P̙3F7\=ꊉ8ˆ6"">7'kMz&:w3;K8 Θ1[o2Qkf_=,SGc S}6V":hTKBCCc'O X.]"ƍ RݝAb6I_}fߖ* :.whK~\ S~Veg*͔kbĩ,wJۖ@5&`D"GGGAUctYmQK~C啉=g X> tVfO0R#奥VnYFVF5X*J$WGX,;Ƈ>b]1"|̬wvDaN V`턦'ƢUc/9H+UEju~~~D"(J)%(#ُ-Qzug% r j^C:F zCIpkGyqwj1Cq2}1ٺu^kTӋRP.?{朄%vhnJ1-4f<qlNrEZHb* "fJ羌w ζDzǾi#M}/%Ri*ƕ, /y7sTTU0a† kA뮯ZYa좞aHC\аJnFBCC׭[W@L|˕,ѱcݻW_6@/F={d1caaaaaai?/ְaA1Ʈ_^74hPnWȚ5kVxaXvm+qرya@hm0m{ڣNSVduV%H$_2++Elll~gцVLNNŻwvss6J@hm Lfoo_ɚNSM2%i)/{i823l5QأS<ł}`ѪDdnn޺u={tGPJ),r@ IDATxϗ_~٩S'"޽޽{㏚n ,`|or~ǂjt)SQv'L{!]bǿتZ0+%/ZfwNxo=Br =$-4BqRawPx@,mZ*6^na,\M1'vGOD{HD<\E%M6>Xr׽ŷF!7:hT|w̙~D$.\tҚn e׽?j-DH$+j#"N4ne'vkF'i8bgLKe)'t7t'Qi,䢒H\]'%GҀ9 FfOJęuY3wITw_O4A{~^+5VfSN;VXEAAAuͽz*[1֥K ԚnjF4`q͌`|W^믿:vq+((Fgŕ;1'_?YWcr\Hdm_W^Ci@?$=Ų6>i_c&q i zX~FF1#2'=S_S6a-d8||o.ݺvtȅ/DAa$O4gQK9"YMњn/o'袪Q\\T*wLKVr2Kc]1"|̬wv|gCB,oꍉ:s?.(Ϲq#[թUm)R ?X bΑiXa/{ܚR#͵Qj+aV ^$ΦK.n̽trҏI]D?F7o5h῟=BD$vعT!Dh8"ZqO8iC,9Աu}wPU7<...9(@m&Ljܸ1RIZu^6t'9Mzq-DK Qkw,غ zFRa;&bƑ98Ecw+EunCqXKKk| )66Zx ¼h4Z[[4hɒ%VXg^mӏ^[k.<޾cyo.IQh<|Xt^K}\#v 7M^~j1roub_6zT,X ++ 2?vZF֭[7hРj"H$۷oyg?6'GSZ97mdVJnǞjtlTs!j#}%:sn޺(%6)/!-!.]RݢK)E:Kp_ 'hsOȠ +j#FoFrr-TxF"㳮KgD|3Qv9|!]_A1d;yY<թ4*K'>'W[_[9:l;fd^oY8/8new2ψ̭휢A&b-S)9""N߁$9"DL&>Br`b'6>>. T*̬!/ }B,B1iҤɓ'۷]vB)7Ϧ*cP|1cy睢%g^ڔ#ґwOa\i.O0X"!ȈFI$"M;sWBLɭ׫ro'-*,bkPtF4yd TK.\211qرTVj,J2o/֕|3(<Le%^N)ʽ+X*9BDhތnVт#>򑨳s 3Ӳ*sGXTe|>{|7XP̈́ XD1}5k̙3GՎqijgdr:ɤ%G,WJT21Z6sUsY6sODof%*˻r&GDžK>u g*3NTx7,Ywڵkx_ T'hVNfܲ kٲeƍٳܹs{2N,"8n͚5:uСCZpV~;'wj2P#?G2ƍ7f̘=zbqy{@>`T*ݸq׮]K/=5LqiXj!whbw=zUVK.4i֭[ E5UI"">ݻwmv=#A/Ǐ;vꫯ0wP_UZvbcc 3""Yfgdrt͸Ȅkk3gN4 qUHTN:uܸq?M-[6|"xhZ"^>}(3V J5pjSN]xƍ999FzxbKK xyyTPM>BRTZPk!`  @`XC 0,!`  @`XC9/c,Ӆus*UX|C>~q.kFY+-= =?{q^A!fY;t}fjA+ $no}UhG /,F |`EgV%L_)_^~'b++$=l "{fPWkB]ϿizYJe>RDD]/[)yӷLWb}_.=42ײZ.3whuoTQDd׌ s7>ňHڼWO;qKbXrԹ:o-Xd筭+Ȕ]&oM~{Ƭ _UowQwbFsǣ~R⯭3}Μ5!I$*Wwl4C l]DD|^^>ϩT%effRiK_2ڈ+Irp^\0UԶ1޽?[&?H40@]tBtPޘhL(8x]ݕzLOm2nբi[C"|{NH1G<#h:T3VmTd[DWSzϋ_;K7D7ƛxV)96>G`C(T$Lm݊ӆ37mFZ$W0rlZVK򉨾_]+I,ɉDB=c5?Zo1YǏ&3}ŮcO&rCl8shnm5^u8嶉l3URM&)__sJ)+ED1Dbq$;,/˝{?&kMm3/ħ1-DD杖߾12Sq|A^>Ob(1dbqĈ%4 oMs蝺ekΙ sL&o޵JGI$bƒP%ШEuFk |&?lߵ)/C_Wv4ݝ+h4'J0}ڌ鋵&""#3lj9q(FODħ>t٤uUD"y7tnWǭcG/~&4j 2$^-j\brDD"c)9Աn͚(MOeD;: * .5c}ngml7?[ED␖ܬ&kvB n9,Lqn|۪BVM\4u~X*nӢ}z{pD/IҵA$ӹc_QJAD$ =1lMC;Kb^6|sΠy/vnkn<̪K[sؿXK#jTqarwSZa{~ǩmu'9>?uxͧ8G/۠rn8toZp໥guX*#bI9c,,,,,,AaLZ*dʺ[xLM{'`iM7JƧtCU:>eUWwvvѵk5jnݺAUS *WɴiO>iM3GRMټf/:X7?NWTp"ZJ6~rMwQ'M6pɶ*YDDD6:ed `sNlSϡR9:ểP8 0,!`  @`XCjf'wx֭>~[zZ~7{=gg8`i/bܹ&o߾C U:h#G֮]jժwߝ>}YMPU" .hb֬Y{NLL۵kt%,Hf͚+W 0`ܹ~~~5@VUkϞ=Zܹsƍ說999^:**800022;$`]vuww?w\b(Whhs|}}{O?t;}ݿlmm''S XǻϜ9] X4iBYM JLrԩt/`k bРAB,aJ 8甓FK>bf 4 %hؚ"">eiMޘ:\`K\'w}wyFE~IjJe=oXOWkNjOFdKO}M1}wg~Icⶽ"fǖ<lRjOr+&"ˆ6"ssr> \\$Dd:Y2;eEѣ,8"zcYʥ}04I|&%t\Z3s:7G<-9o i@KݱQDs%"mDN0Ȯh%#ȊN^p8uao7V)}#ZډT  {{{W aVbb"yzz Riݝ*YRD|~,##S]YY桁H>{kGem}7fLҀ;n޴pEEeFe\quuH$%GP yD%H,-- "C Hgg%JGW)=5'YXڄ%tёR"ndY5pf#~}eLF-"s3LV|$ "Vaa "R[jDD3zs8Wb{pt.Ok3'sVC۷Tp`׊o Z행$".(Ϲq#[թUm)R );sd8hb"V^#B9byWoL{~J\O¢j@@,ƘH${Gc-5uZ}t9k ^ ?6S}z z6|s8? #$QLDbHHJ#"OhG$rKxmƶ6um={/ugߝ3'K Nct++V3 vD$* pPZ"!L~v2bʆ?Xn׊l^;G2_ٿm&&bEyry&uF_ѣGD$ H?)Yw 1HRr?^.3w 2׮[U'\c ,&n3:y'dIxxx8EEE=] &lذYç,m66h?|獕\QF֭F^4׮]kԨѺub;3?A0`=kD׍.z1T$77wŕ|x%kd˰0Əoeeԇܴ 5IDATCUkذAcׯ_ 4(+_d͚5e+0muСxF@hm0m{ڣNS/!Eh2)jy8+w{3XwDW{@hmgN{i kX+pߋ 6@/X[C 0aL&jryMwP[,,,F @pyyy5@m!LWco jQXXؠAn&`yyyQ|| ՞下(KK4s%/Bf'w???Bqnݺ Rr%;)o⩹5?˻|h{w-$U;xz72.Z9{ɹGXnTu|b""C W185Y[%C[=a*@e 3P(w!HghvvJ+禍yQytc^5:6 lɹ}5˾w9oPŗsĐ }nѥ"FĊSO%zinq2[;6;g㏖-[ZYY=tۦ_~.]:~Pk8Ϻz>.%7Dڹt}!ǐq+Cjgawh`f67WvpҨ,4\m#|Qno6`m$Vp w_j$q"'W.\8}믿oT`O>VVV_}Pk3+gMՕ>#fοJ1m)J.Md4D"$1FVɕ ʻc:f4)/P§G߳k&"JEq^^E|333{79h¬"" 1c̞=-ZlM}6UH[rqN*Yʹ<"Y{2FDqR9GEZ6ɧN+I%d4y^l﮿v.b}+s璭[;WnO .lڴi̘1r'ɓ'ۏ=^smJJ{`)ґwOa\i.O0X"!ȈFI$"M;sWB̉bSK+z‚""|=_ʥ+GV?C TKV/^ԩSӧOljR[\|?`qVyv~Qnfl> stream xWn7}߯A4gx/\S 4A*BSŹErXm%gᙋHh|&:'Z\}FUa=")'>c߿oVZH_Vagӎqj"k^dt՝,&zatѽ_IP4m[wp?BNdӿ+*ei_ɰYfqAfgp+A)et)X{c4o h j, b!kwa'Zۿɮc '6.ss-O,eۉ*xoӷw=ڕe[ Hx4N)8 CIXՑu6{ٜo/%SR?_I|AU\GɺϲyֆѮo$XxrZf/[q/Z{է3qv&=?`S5/B:V앢#/D iﰏKU>eupH 0q@`=-S #V b R_n_ uI;,2&Fv[+/. V%xxZT1@[KڦI.4Z!ҫ Pd󨘫)5~n%6 }<Z}@0H$eql#Rl+Ũ?  ]UbC0Zn$!I=sFlsxS94h7+]R@K0L 2 H*ƚ1Em6GNAn3*8Trw:nܙf?fqerW9ﲏ*[mu'#0jU!\ dʫ:lĠ&ޝ#(¾ f^tu5VS endstream endobj 5 0 obj 1330 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-1-0 7 0 R /f-1-1 8 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 9 0 obj << /Length 10 0 R /Filter /FlateDecode /Length1 3888 >> stream xW[Te?{S.؊00h+0 d*agn(H*%kci߂@hbce{͞}/{3w~wF̹ &n M_i]&w,Ҩ  ><';wAqDon7_̜p9_1~5wVq$Qq Y`Ѐ;xAΨsI:"I=l Wvv*^ƙ"([i,ܼ}hA3lX ^5=@:Hc6t]WΑ7JKߠoꩃ>0v)#}~ ۓi ;*߇zG`AEZ3M[\U0%d-SD[{wiJpMDhIuQڵo?cގÎ9:r؞[mފg$lR<> i(_w׋6Վ߁hp[*6Djz9ׂ73ߓd/I|{T{kip琯`>`4y-MBI>{ܻi$j9,}*Ď"'wvk)jWĝǪZ6?B\\ff˳*:y}ډs<ڔ=S8FUV,M*"q!F.% goj/dzcb5Ϗ#,6[sroh6>7q.xMl2=js?(j0p{=~WC9> _D8ƍ P"Y-#-nG6Zzf\:qM;yA;Bc@]H~J~\!&)0K4U2Œ   &t2]UK۞=mU"/Q$$&ATKHKyK8l2ѣ;b!>-uYζ"8Zr/1.?_PgL>Z:"7y*܈w䴭6tlJ۽MlĥmX4Ag7{ f)C DBkz|7{"-ط<^Dldhyu(na?؉5}X1`J0m's&% g@/Ÿdb$FjV:/7rNͱ~S/ŘQIj ^R_+Ϧydn|mI%jM '/ _e_m&ҺdA>X̚VQx1.JQ mCpQ6 q|'[0ȑCMc%a1qGw=N-N0\ߓ'^MfC5Aѣcn>}cPQ#ږkSOXЄvH8 ­*KM^4r &VFmDlU1+PI# 5UM!l~k5Fn{ 9Asz{1 g^k&~TTUテĨ{u}x8)yTxHʹ%6(6f3ޔ_?bQ?K5*VC%~Mo]Έ pL!!C^9;T'B 8~׃LC^w,~wF?#nj[3w+} {y ѻ„JȒa83` z{$l1 HKJ9( A6DID)B)EHX%BxK0b)QG%Z~:*l7grAE)@م,bh-HqkQRW} 6G֌> stream x]Rn0+|LHJ/91!}(zƳxyEga^0z<]eqjSh7*ɇyj}z䦞:{ z;:\OՎhͯ݉u{庎i̺Hd'繳:dyah{*j*y 7 ǠS$Cx'DSBS LqBKˤ7 M-B]Bo$hhJ-.aYHjQ \ ,$Rm@CcDS f7ivɿg'> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /CRBXVH+Roboto-Medium /FirstChar 32 /LastChar 125 /FontDescriptor 13 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 568 568 568 0 568 568 568 568 0 0 265 0 0 559 0 0 0 0 0 652 653 0 0 0 0 0 0 0 0 0 0 0 639 0 0 0 0 0 0 0 0 0 0 0 0 0 0 451 0 541 562 523 564 536 354 566 0 255 0 0 255 870 556 569 562 0 351 0 333 555 495 0 503 486 0 335 0 335 ] /ToUnicode 11 0 R >> endobj 14 0 obj << /Length 15 0 R /Filter /FlateDecode /Length1 3092 >> stream xVWTw{첼ŏhxjԲ,bB QEUPQ $!zbQњkD4#Shm,9A<zb9iOΜyͼ{@`0|ޒelo]`iiF1Mjɚkh,&g-YQw@ggXr멿lIF2q懁n%A/0@äz1M ݬVݍ hha*;S',]MW%?C,@d*$͌64[[x@^[p֙[ّ:ѥsi%6Q'N #t:q8vUV3"B,򠨘XͪC,2>jxdԏxS-z'9Ӓh=nxbU/N0Sx̬H5$Q]@ /g~;t8/yz_]ƫ߫0E2'k @`v*>R AeZeAQ+Gɏ1jkzʍu7z#:i<9*JN.s\c2$ʮ/$/5 #VFtj˙Ff-3@i"a!/z6›40r_ +g~ϫ2t8fl a6KK0t[2U>SQLaמ;qړӽ ^8d+qO&zy؇^B^zH]L SCЮ]ؓ7Wı8rnK{U]ǿfwx9;N3d״ȉM:r! ͩePe+*V%M̧ׄ յ!ͽwHᄐ'*> stream x]RMo0 W*(J]8Cc8Q/{/N>n\!{p;:pA# x8`FV鯧ދ,mYqjR}e <- qzr4`F޿BqQ&PEp BUe1D~0#// aJJJҖGH>},ad%cI5\CMyyMy>J2_<0/G&5^+$ao/HOLpۖ&:5:ϔ= Ǖa endstream endobj 17 0 obj 347 endobj 18 0 obj << /Type /FontDescriptor /FontName /TXCQUE+Roboto-Bold /FontFamily (Roboto) /Flags 32 /FontBBox [ -913 -270 2060 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 14 0 R >> endobj 7 0 obj << /Type /Font /Subtype /TrueType /BaseFont /TXCQUE+Roboto-Bold /FirstChar 32 /LastChar 120 /FontDescriptor 18 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 654 0 0 0 0 707 291 0 0 0 875 0 690 645 0 0 614 618 0 653 0 0 0 0 0 0 0 0 0 0 536 0 0 0 540 358 571 0 0 0 0 265 865 560 565 562 0 365 514 337 560 505 734 509 ] /ToUnicode 16 0 R >> endobj 19 0 obj << /Length 20 0 R /Filter /FlateDecode /Length1 424 >> stream xc`d```cp``bPHϩLe;P$d&06/e``2sf@JFnIGC%_s''@&c M(`Pc;|Vf @;9x9YSQ F'LnZwS߸5<*11-& Ih8"Pi.u?t^Y}髌cN39ŻRe7>bR++m2Hr0@8^(Ha`cY5Pq`baHar7b3/10] endstream endobj 20 0 obj 367 endobj 21 0 obj << /Length 22 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> endobj 24 0 obj << /Type /Font /Subtype /CIDFontType2 /BaseFont /AZETLJ+Roboto-Bold /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 23 0 R /W [0 [ 443 608 ]] >> endobj 8 0 obj << /Type /Font /Subtype /Type0 /BaseFont /AZETLJ+Roboto-Bold /Encoding /Identity-H /DescendantFonts [ 24 0 R] /ToUnicode 21 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 25 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154043+02'00) >> endobj 26 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 27 0000000000 65535 f 0000010820 00000 n 0000001592 00000 n 0000001445 00000 n 0000000015 00000 n 0000001422 00000 n 0000005454 00000 n 0000008902 00000 n 0000010659 00000 n 0000001810 00000 n 0000004668 00000 n 0000004692 00000 n 0000005156 00000 n 0000005179 00000 n 0000005929 00000 n 0000008162 00000 n 0000008186 00000 n 0000008612 00000 n 0000008635 00000 n 0000009347 00000 n 0000009809 00000 n 0000009832 00000 n 0000010134 00000 n 0000010157 00000 n 0000010423 00000 n 0000010885 00000 n 0000011002 00000 n trailer << /Size 27 /Root 26 0 R /Info 25 0 R >> startxref 11055 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0022_Parametric_Diagram.png000066400000000000000000001010521415120503000314560ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxw@Ue9w3.[(KPp/9@]jZYZʑ#3W]*9QQqy G/s=s.{cFǏ2o+Z -ZDV๺xm.iJhA^p u\[!"˱Z_745]*w.XyF́ӊF}l,{xWFN2NRn=GGDW\K8)'G[1Q2 2~\,Q Gũ|ힸ-%JoLt%5Pv,}{J/G- /[;2_uILQ;9|Y~ KڠmV5(9]p5 iV*<9n{!M]uHZ|҅d#F1E`Ijt?2ȑoXweܫye^[R}]jvwQKKݠF#[d^;{ Ԓ< xR_R6 cY7Ν@oa1e;JJEz%tgdh.l,*؛fQtTJG:VdWebOLŻ2[BDƁuP+i1{1fg˴ӣdNi n败2)|*STi FtI/붬c|t zFD)k6+TAne-$1H*pDR3!DD[wtUSy:f(ٌז._5<>NrGЈ6<{go(ͼBjnR{uoS:Y(n?ؔ'"bg~aRW vhXUhΘSٔ!pkJ[ߜH-gj6=v=`> "mRVeQ޳ƴUIы{*[Qg(kxtLαZ5k z$Q^x%EGݱuQ5ݭ;-ZŜ5$O8K>ՉZWV ya[zh^fϨoقA|ѫ͸IK =[Rpm[FoH?9ヅ}*o0jqe&Ѿc0,lA;ŵxmkkI,YUo袹y3f_R8\d\[YY:O #2$J'F qgviP`#,3zVՀOe?EMIL{?>WZ`:jNGۥ'_7$"^e\*~3I?jT׼=`Ҳ u6nz VM.0dek% T)،Q˗oɺ_>Ш@cӡ{EYX8{<'kPrù$lO@%j&=QAlIYVViZ&!"eGo8vFV{r| ǑʝUfmsģ ^"EG$,/ORO|7t{}޺Z8ΧゆFHjr ,UeSfK?)U*YY[qD) eji1 mx3;H$7T|߻̶Cc/ U%&=`YNv.㬬C1Gc7Tq GK Tfϑ,;shF?(QXX<$>܁;u kYqDdS2;7O;#,դ\-"I5Sdc 07u!E,׀p2^ :ʉH'FN^} }KIF8EЬ8qj~e=|(~cv?M!I|I&^s;7}]iʰUqHMXq` Xiii7c+Ҙ7oÇ3/`EGGwKC" ]쿀_xi8::6h]ή}flO  @dX"CD 2,!`  @dX"CD 2,!`  @dX"CD 2,!`  @dX"CD 2,!`  @dX"CD 2,!`  @dX"CD 2,!`  @dX"CD 2,!`  @dX"CD 2,!`  @dX"CD 2,!`  @dX"CD 2,!`  @dX"CD 2,!`  @dX"CD 2,!`  @dX"CD 2,!`  @dRs7/VpႹ_j՜9!`B5jd.>c sw`NX?088]`0]+' {^N:-T@dX"CD 2,t{G8K8NVoYãAvNJ㔯Jfo?T\aѴΦ o>x `+HkqN?3t޴ԕ{oexҦ\;ˡCJ^&Xudw\&3F36&wTr,# ]WQ*,x ZpNA b)RRso6x j~JeDڽ9i'}մQ*m[_KDD~֯Y-\a]N]\JUw'"6 ;.Z3c@c3xڵkHh^'}|FhPCG)| 04DDecg)8U'rӞ oj'lA'ޞtݹok"x.ؼK8"ƿ~?wOx[h4y4l[Eqsc ,:r^A];5tUp)_~<1ƲN8Rmc!8ǰc!J}ҳ NQxx0i +XPP=;W5vtm_y-ܞf[틃>okRfۆcBvdMD7{u%M(3Cm(3zݴށ]|;Oo+j.9;8$b;v3y@BªrI<)Y%CW%"bJn*po_4SNݱ+mѼ* TB7y[#m-}wHH5ǯ[>|?c? 46_]@e15}J:2ήSh[mC)ֽTS_k4?)3NvZvۭcj3 |LJRIl(A!ޒ8Cy r6>oTھқ:bl{I:/7-2_mE^;s+EDD,=&ڡ1fT{!#¥$Ӯ~ ڻcnd ,(%FD*'ڲ_8y//O^4Z5wrǾ]۫"m93WRDDd4Sa0T4ψ9pZѨwe9աn ejjZKٹqRp 9ɷo$ViXSɑmH3C|m턣AvCPϿ~*2ZGD$9kWK&W*8#rs U8"be홈ٲNӢ`}s[<6HD;x"5U㊙Owm<${vuKW68:.>.!nVZjIt~DӤkNN*;7?jM9`pm*MŨLF,̭YHZ͘TXVɣ1S mHHzdIK(+jVTdzEY\Xk̸RIlIBY9v%\:%\?~E zԩ-?yP?}+oHb؈K`;g*1:wȘq%b߷ 499rr&d\p%!+7u1íwplkymbEfƻr]'kV%}^*i u;]`:atR^D^QF<!ʱn_Q5igRryyD*"{%˾TJ`0Tjꛁ6Wndr@O[5KU5uMKIK<|QEꤼ8ZҤ1*T |;)*9M$D; DI\.]\YuJBS*ܹ^)nK On#SK/_cyZ-X= IDAT6~Fپ}S7֭EHs$G.>\8rJp}#/Cy~6TDCpB%%")R8 ,~=uׯ~$V 9ĺf`HͧpnѧYۢ,j\mЩ*S3M,ٳk[~/(gPdm i)T; O(  8;;׭[KNz@I66no :D 2\"| 4hS^^NX{{3f<97g)1FD!!!Daά 3/lUw_*i fקO?sۼy!CtTe 嫯"+Wя?h0ϟo*,(5jL0a߾}D?MT,&s $swQ )))ׯ_OIIζPT .wppQjKKڵkT*sP `AQǏ?>|yDD999 k ̅Zjuܹ{[OZO?W_*f͚7ǧJ*J򫯾:}`1ƾѣGs\C7nn@zEDD,Yd„ *jժ_>..>2w/+h4=vb5~^II+ND CڨM,Q\JquEGe#G~w111v/ <땳y/nٲETi)SjVA_gG/V)yVTynQ::5{$ 4מ|#D#,l :#œ9s֮];gΜM6=c)+gѢEuٳgR(Fqɒ%NodD/Jy~pUn^x4v{#[7n 1GUeVA`<\S*t#L׫>G FG5:Dµ#vKLLY3Vc`/K._-B̭x"If?3^G$kEGE9؉'N+&[=ujjɫ;&coCD׆\JQ3St7l>j(tܡ*/;)<Ãk)O2I) '_M)l~5.1큑E;7\XF$rJcjIdMwYgrqm0&H^/=gEF_׮]8?RQ4j?>qIII^JjwzwQ/[ȉ81!Nf1t ҄As~A-OIT6vRS՟q"ayHѩh.2wma =}wNjQqRPk_͒#uҶvæ\gjE}i3TιVqR{FqZIם_Ο WF ZxDFöٲg`5o޼y梔t^]]vvH}D$o0Ȅ?tHRcA-ӟ/%5wIfL{}M_W q6 rĵ?N^w'iv+0Ƙ9_3fmG$s0]`,s`gHl~іKRv sIі _?Q:ƴggKx4=y)oC(1~as9]O`̙R4++KG4{^-ϟo׮ sֻr߾;\֊'A} 7)IM |y|~F åK7nl^ wmoooQN<7$ܿ{_ x'{ aMؿ?s",WO/>{p2q!ݷ{ѩhֆ'2ލ:#!3?Y7Ű"" %k׊UPH?IK"!K|ۭߵUrDD91ȋd'wUq ?pNk}jUj9GDM%q2=1'}>< ]V>Ltnw^c%GDJs=vc^le#^MZEPyNSXlZ{Am|r[`:nGjz7WpD2^=.(Ovjhw _jdmE6pVIHbmcɕq]'LnJzt 2՗7dc;qĻfm$#2\7ѹǴS2}Ʉ&%\6JF1ƈ($$""" c sNSXp~`.,a ==]^2,(Ѓͱc^L3ĉMd4ǎl\\\Fe%N@@tX"%Bٙ3g:tPʍjZQF:u%smB RnSL|nm;-j٩֮{vMGDe:6^El_#а_{,m120<^TW @Wd^ctU:Nv)]|,jlJ?e_Ϟ#z[6 h$m1!mUU^=kL[}}_( 6*pkJ[ߜHNo$FDoCM):o{Y7w`P㏏q}vΡ`.n ws~_Hgſ;%uvvx1}ׯ;{6/v~$ F^3Sq2Vi>3>Xi !u-[0/z0iɲY7uK*+y[zh?yAߝZ?c|Wٶ55=-]__sߟROd0,lASO啴/4`kF~χǺIc1Rúb 2X޶wnY =K.`٘&mcë{MJ?=G*}mV|'t;w{̦_G3Js)**8__Rm]XʅBDYf͛7/%%%raťcم,t}U[wFJU7)ew55>9>G"VS^V޲L &ˌ=r<ӫC#WSR/\{c]׫i-!>r.ZNfXI3$N[q`M%G&aG_`DD|WM>zIkWݹs[n]p|gǤŋ7.%%^IJ+jܹ9sm6p@sR"Yi[wc( V:t{キo߾MZ^߾}{@@@ʕ-p֭DN'Q"޷[{M+-ܘh= 7NNu n^DDbmq׍47V#LEijL&eH.d"S*<ʪ^̟?ʕ+}Usw±ݻd)Uz5`$*}3{o4T54n9r6H2L&'2$[ځ0SiUZ"^6'qRf֥sM2k׮mڴ)هPVEk\rԨQM4 u9S89iti9 ՙ~#nˈHp l]s+Wg?s!K.37yzJW:?Bia15qO\vu=RLvIiΜ={T Ji8U1VXٱc .غ`#18OJ wGegʻN{O:1buk+(Vgq5ؕw$$;TcE3xe2z}+VTZU }˖--ZhѢŦMBCmp. IwMa/BGWb*F'*|tN^Y}_n**s`'1z^T^A5\m0>󐐐oذwy X]jvؑ;СC} '3fLvڷooJ#\P(&Lзoӧ/]tѢEum۶m&M*URӉd2 %zqyݺus_L&"JOOUG@r󤤤/&$$۷o7 ˗/uu ܽ{_~Yn޽{srrl]uoW_K e rww6lذazӧSSSSSS ޽{f}v||<UT)ozӦMU*Ʀ/((zX`JWSiii{U-?bEPls9ŋ̙cJ,(۷oϜ9_j...ݻw1cƍ7l]@)VtۺBI\رcu:̙3s_Κ5d2?^rs)/ÇXϝRfQFXPe>7R}x5\4qva ;Oˡ/g/:NF\ɉ _u9D;k&n-҇m_^MOD<=ZکjxO!wCbýH]Umur־ᴓfK]xBӑC xmfa#Fxxx;6'}ݿ) XncA^–23UDk7D 2%ٟDkj.䯐Rb<-HDd6Y.ЎX H[mT/ﯿfF'1u;>~ } ׶(pPug]?f|^͆~Oˏc>jiam!v~[)j.>7nlB,,110@ `e)))1777[P `eiii2օ=X`YFF(2$c@DQ|=J[PLE\P2X```@a !``@a !``@a ue  d$ 1,!`-mEZ )TA* 8祶5xLXs*݇k^EnS;xF=joHU[gCԼf-֒k;a{`e~t<뗗5v~Oz@Vv-D++ɝ'powxyrWXD~]o8RGtPC&""2u%7cY^)H ,""2]%&m[ a\2Ac~KS+AC,z3߽cn= z?̼g֧n_ѲnݦMnȠC0[]f /~wWޭ#>}kѪJ8)q{[s-|'ѱnΠ'~f#WXg5-/b8󨨨(^jU9Yz1e9͜scǡry[׭v*]v )"f6qy֡~r01j^JRf}~qι@<[ג)\6[S~3eSc*w{=wrz6 H e>?0i;[fqD@6u_pv~ZƣTK ,y؇?,|-(y xٿZqpdߜw8i|sקg5m׮_+{#>y9H{ɼg $ o1f_ĊsZt1⌵j^5#Yf!!"U ^dVV~=;U|mvc 'jx9qlG r.쭱tP(a'hƖk_qKV,e/oy$!|nv౷ݞ8Eѣ)]tqgB[pÓZk)8猕bo|hYĺ#S叽(r~Ǯ u`[q?ibWO W*B^hp+?F 0y *pE/`Uâkh<~9Z^*Nk NDjۏɖzwƯh cL(4ݾ˟%^m^xv,`=tz&KSy-4[7xxzlEXGvTaΊU[(t|vSS&xsո{3n-w9[72:^3E:^s:㳞RGeUdz\v^F%b8fF3uƍ?ĉ5jTcǎ|AEDU7竑QJzYkOM+==Lq_OzȘƆ%?""YWŽzd۵S O;pN{ |뇮NDƝ#?nﳛI}'Y?c?"!owokݴGE xy;ϚHYfo۫2 lեs=9QՂ/*|えHϝ;WR))۳o6d0`CVyVZջw\SVyር\X)tES4?rdUޖ-UlK|A/RMRNu!xBvp-ZhCg(V.\kW2q]v/q 2o3vXNQ۫t> sZu@D$ܽ+lW?vJ5GGG"̴u!VQ42*?o/?ڻ?~tVt*{3t' v7\W'LTV4?0I__|%$k/HiWI̳cl_sP+EA[~;j^H?j6%7F|ZVO8a{Yɓ'srr$- ʡ*UTTI֜(==]K-?wԮ~C>3݌1?Fk%U[cW,z0C6:5-|ςWÞ[ "/GjEWǻ9l>rGM.>X5oJ՟@F+g1_|kM6mRvƍoܸCRgϞ:u؋wN]!;O;= Lw2]<]eD[8_[y*R]aJ\1b_F.l'&&U3?MV3jԨG&fgg.ZjժϦ.(L&SݥmŅRRRm65k|GRd:[]I]1 ۼū]Y%&&ۺ xN*.]<21##Úe[j r`0HަL&;-?ry(e7kw 5td0Wi_O_z=OwAI毿0aL7KRIfHHɓ'ظq//_oHR)7lӿKOICI\IAC]LL?Pe;t1nܸrq΃{aq痕tB>쳥KZ|$R~ LB'_|EΝ O,.u?UP!`Bٳg˽a9R)? IDATr!`FYj(w}wΝ޽{/Yo߾QQQ5k֔n˖-0aBxx[oe6uP!`@e˖ŋϝ;DR*Uhf͚?~<jҗ*xCw~\۪7Y胃T\\܈#ӠAFyzzJS/}1ƵjP.?ؿ;bK;œȠ{˹?tњǮfpGM:=nҠ8 >\!տ؆Ǫ,d2Wl$"USOI-<n/FY['$97~>/TbW`>3z.TW$߽}lAnrAEDD\p믿>xFyaLd2AsR/mX08:j?)o|M`L7}->3/޸hhLAn CK}UkNOX}~h8ɓ,y}jڵFDwNGD &8HoLR`jo~s^zU*{π~i&"ꗭT) qF>.S׾:tnMkj>M:>؁ѾZکjx촭7E0uD:Bi6]p"߃*+k4dL8栉ȸgT-9cƟ1Zj2 /W$zwь]JFO_[N~wujπg}HDQ5drljs63HvHÚ?5M\˫"QGiv㓩}kʙl`0̜9300pŊcƌILL8p <{u&dH;[ ҝZ2zyT h*9<*****CHD?cѳ $:bp-NJ0ry!e:H8s؁k6 p3b6WGHVwG;0b/|}li1*"Rcƃi#"]"&87_Y$"brW FZ(=#bcRA:^jF[>i\1MC^1Hp j%'LS3)0rιa{5eD l,? l?jJ~ٳof9=.̎1NΈҷ$~=WFA*FĔ 9à5ۤuW:v"e+f.j2F-[U-[fj6$C&O2_[ZID֋9|gϗڄx9T-_Ha9Q6y=TsR|h8މ SW}֐Ӿ.'ª kК[e h$bqraDg(XN$xUK$Ē-eE4U#`MwiMfn\L't W/ 'ʉ768bʆ7Ɉ#z Ta%^Յ3HK?sK)1slE# [<`ض4 oTM>O4͹s1yc2"Y;Old'(?2"Uo/*`=l92|Ϸ"yX8F)j $.ZI ;1^[}iU]5M)r9|tJF̮G{Rp9OMM}|5|%]^EDH[K_0RDrF⽔=1'se;e>o|/LY {{:'栏_0!n)\fkyˉʵj80"YzuO2"1m^/x dw~ϓ<:KC*;ײnT᎙iDE(xڮ4ru8)-%܊BEק>kڏ1N9|vqN͉V1.x#V,p;.:d ٶg\]97]u垼v .KK;;1n8s]SK.l535fZjꥵo=?Vlzb#|ʰHD#l^1(oʉWϖ9yժ쀍&X wE5WK0&O?;!]$ş"̧qo /L&1"1NHprq̷HL?#ns7{xxd[.f5&7!g<7k׮_-]zNč#&MْFwg-^8g%|s$T;cbKfAnZso9>mQ{$Qp1M"om?9#I.ڠg1j3Z[x®SK𤭓rR*k6WT3 |ߞ:mV=ߚkӆͱTQM*jkv_v+Vdf#b˩B_kܾv骑4"Tofr)7xt<RїVQǮt3S~o~y?:/w|o2wX?Y/F"y_Y##=#Y*kj{ElmRvmzd5v [Cl+""=o@Lmwv/T+S%ϧ8_ZamT.(~ "PIe-[xˈHVrk١3#"Ehd3W&CE9dC$(i#9g*o,aʍ~?c|kۊ )&ιutNW E,R iƴiӈH/0 15@LPeͷ+y)ouqa$6看I+80?91cGjr{@ԛs4Z?:EM7HwDι'FZ>ӈv5 {pq7Tjܥ?AސQF1;6w>c+ x`e/F_NpXV;-7gQ/ 8XxXwҥo-/G9#b!%E,TA `A]co3ߣ'oyBvI/6S32_E4c۹ش: \tzӦsi5" nzu"|`ɻUuV+ծ5"zLsG1dL8栉ȸgT-9cƟ1OO{UuV="&2,(H3RtWE"2=c 3:9uȮ۴v#7+/z{ޟn,ܮc:?CG0αQv۸'Ӊ?7]4٩g+]>vc+˿cu~gvK̬Ii))Vr.>Yv £rQRhM۸%&66թg=ɂFDx/5)K[GΎTV5tN>~D)NSϴ_ aAUygK ft1ea]wZ"UGmțhbN F2X,{\!`̭}l'&&awU})x]9Fݞ[X>r%88 D[ qW $wW}KӬ]KFƽ|6;\}P `%L>s(Y=[5䌧fu~Kω`,gdL񌿇ֺ8{6+[B3&ta?u1w.7)@Y1c۹0"X;UdFWn)7tHg6Ɵ3n~lAUÖ8xFνmz,,fH>wŤ{fW@:eD3.>=TW._l^]MR> stream xXKo7q 74E@AFEA,9)$'qEoH.w%ŵkÐ3!P$/XO <'JxETeZl2C~$?7oJu+aHRɲ#+ut|=Ihv:u'Z((toWÂR B{maHŰ_E.KЍ+ zx|=_N*W-1 hMJϰS1~DZ:ci ƱVgP?Yzl9hmٟ^eXݼٮ4;oxOIWio$Ii4vnо<] Zǎ7$a #Xe q#6&42uEY;dFǑ!'^ae4紓n^^B%Ωpǀr =b`y@x&q&┫"5 $Wꃩ?EחO/ģG՗rוxYo6JiX<~,<{=c}$N{1,b ', -ƁwNkiBsdN7-m5u&wCCiJJ82(iG:Cy6dÛ끸=edv6r()1JDlppk䃒uJ@h,f M귯jVWQTlҤ8iIM>=L3gV gZ]PhU}Wg+O- V⽍ܔt/Y)ϹrRT!{>ǣb ?J.Y~1ݴo86ŧկݿW endstream endobj 5 0 obj 1555 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-1-0 7 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 8 0 obj << /Length 9 0 R /Filter /FlateDecode /Length1 3644 >> stream xW_W?LJ}P  AIJH}}!H#Q"b-k]KQVZJUEWtuѨH|T\$E{89P(Qڰ}tc]ŝob>m33‘\|ηpmIyUq  g `  ?: {^`IC9T !YPBډZ&~mc=BmW`T1U,|MLfL *lvk9;{OJ5E"؋2ұqvG>=ʗݼ=1`A2H}zH 0 7UI֠ 4EFEM0/TWyȧ"W|Nߩ#JN%C{Oq~(f?"ZmH|+!fjz9ɳ'_][2}0֘eWBzCB y`7܍gcGҩudV|?3*4I鼮xޞ4,FrY%b0oЯKqrn71{ 5QF^5Dyl Ca6 վC?HzMۼ`Qlz)9nw52sk%tUT5}W;]7GϢUXėQjdd0ʬL mBO}Wѱd!sFMNWȨ muKB]7ځT 硯2GI'm∋P0yD\ye_CIRiQ%@!}~7{H|/{x6{X(/sP&yuFb!D[uLvxvvS$MYǙ(*Py0ճ$Iė߉vl=Ǿ`d!I# -c'3F(1˵> B Ĥplly6"}q'4ǯ}.ުϝ> o>UW;hi,'zxBrB(yh4w䤬?qr=1ϴ6i#KvNSCg6ͩ5tm b'$1B0'Up}{޸3%6giҬA&.+*XFbڇd|: y+屧Jup-COBq-\R˷߲'NີYL-}@#g.@ YZZ+[ݽSB-+c_DZY9Nxg,I$\*9!D'z&^la?EE"t ߵ/,(qnё$<ŮrMe|e^/PX9L*:7A$|%r60EҝKG)_i|usK{YWW> G QCMAj6y"3mՎW2J:p ./`|ɮ޷.e3ZgLݦ!WO7z#y%y[*<ڃ3r >>? Q|nĩ-^uYVI6dȶl `G1&y'$y¤x""' [4wǭas#d qmOvo[A.c?yyYYGG5#rg 㽏qxIV1mmi^O{xH%Ty>R'UZmTG~? ȢvdzHA"Hj9ds H=|)$v,YHq.XlW#"9x!/D~-Rm2R~%FlR+TCx/,"Htg`6W{ E¾} -C@3#md:"}26R7 <* endstream endobj 9 0 obj 2567 endobj 10 0 obj << /Length 11 0 R /Filter /FlateDecode >> stream x]Rn0+|LJR^8~KTe!]oJ=c0uvj[?m2{`]uD rEQJ7vP] ֏0Ffn*wOnAH) N,w_7F{k?̒x:\e;>d dk-ޟA> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /TUINSJ+Roboto-Medium /FirstChar 32 /LastChar 125 /FontDescriptor 12 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 568 568 568 568 0 0 0 0 568 568 0 0 0 559 0 0 0 0 0 652 653 0 0 0 0 282 0 0 0 0 0 690 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 541 0 523 564 536 354 0 555 255 0 0 255 870 556 569 0 0 351 516 333 555 495 743 0 0 0 335 0 335 ] /ToUnicode 10 0 R >> endobj 13 0 obj << /Length 14 0 R /Filter /FlateDecode /Length1 3352 >> stream xWyTT 303Ak`U,P AQdQ5 ۉTkq_z4-Z hꩈ[5`RrS"Fx͘`?_;w}~wy@P27-^*Х9_wV<8g >Y%럹*HP2 8.M+ɇp8pev@n/`NF9#IC(!p(Q / i*\JZ"Tcit/?"YH< G{sqN,AZZnex"79&&Y$bb;ͼM /._+H\pl2.j(ډҽb@ӑX{`֑̥gႤ=詜R0QjGTzŻl& ^_gK,m;<ye8lbyLPheUd1bj6E:Y kx\]foQEơ+]]_-:̓ȅ55k't'K m$[3@l­tҼfI D!:`yk`==ՓI{Yo+wm(HfDuxY1@.bdF͢5:t*W3!b5oI>mMul=7=2V7NչT^mh`@UKx@}ڏ-Ѩp7E/z!Se01D7Y?ݙ3!1\^7!<3YƉ> t5ƁY #т _M0U3e}eH=ۤ~+U0~D1M z L!x6@ѯ*+]l}:tPv[͚Mٳ5R>H1Mo Qř/g4#*ĽV= LyB(oɺ\<[]Gթ$wLaM}(uʶҭ2Pc/qvVU ws(&cQIFZguZdL&nWns-)w>'gd_̊ 6SkyhG5Μ:0։0%zk4+]tfw5#5rv)%݋c֓eWRtmRdniidmR"ηNCNbA='| =})6$Aተ̎V ONGr@4wyo68[?&_ܺ/.djwgmJ}\~dʁ<'+B¾:_@hJY2zI͌crRP1{F>b~}gYlѻ5! 9ӫ;UV u[va\rROmN3J>V\!Jʄ^ ^^Alͤ'cYk,A"w7+t簲~$kG3gg;KDI>q!{~:f/˸OZ_171U5o~>S! ++_IK*}}24[_o3pSYZ{'K{qjp95SoB2X(@= vo y9P̏>ŰeKT ?Xxx2!wA4 ")ᔍ7AEꖅ%3݋ n2v$h< a}MA:sjN# s90+\oq9#u_ȁ" endstream endobj 14 0 obj 2301 endobj 15 0 obj << /Length 16 0 R /Filter /FlateDecode >> stream x]Rn0+|Loo*!*pCM^HXzQ*;ٱݸ=343^F'RQUzi"ͧmYqꝝE#n.kg|R- NVm{0R7q\}lS|neGҳ.(> endobj 7 0 obj << /Type /Font /Subtype /TrueType /BaseFont /JAUUJC+Roboto-Bold /FirstChar 32 /LastChar 121 /FontDescriptor 17 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 498 0 0 0 0 0 562 0 0 0 291 0 0 0 0 0 0 0 0 0 614 618 658 0 875 0 0 0 0 0 0 0 0 0 536 0 521 563 540 358 571 560 265 0 0 0 865 560 565 562 564 365 514 337 560 505 734 0 502 ] /ToUnicode 15 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 18 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154043+02'00) >> endobj 19 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 20 0000000000 65535 f 0000009508 00000 n 0000001798 00000 n 0000001670 00000 n 0000000015 00000 n 0000001647 00000 n 0000005445 00000 n 0000009057 00000 n 0000002016 00000 n 0000004677 00000 n 0000004700 00000 n 0000005147 00000 n 0000005170 00000 n 0000005912 00000 n 0000008309 00000 n 0000008333 00000 n 0000008767 00000 n 0000008790 00000 n 0000009573 00000 n 0000009690 00000 n trailer << /Size 20 /Root 19 0 R /Info 18 0 R >> startxref 9743 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0023_Interaction_Overview.png000066400000000000000000001044051415120503000321160ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxy@TUߝ}YXeQAQeS+67ꩬ43[z[JrLqeQQqAQfYg9"^' >sϜ1#0wMNjRk ,[#XXА233>l*xS=Mn 5OE<ǎ_9xK"/_ggR"/dFuNTsƅiNd}iwv QLYLw2.Qצw'gmLi`PphNQEbk`_{)w/ bUKvNAs+%&e@')!29 :ݶb0 j 5<|iOI!=kGwl+hʕrk7?ڏa{Ԋ'%0"VtXs \H.4}]8VlCpX5+9y>(g܌3&Nbg*/ҔaؾEY9X.PnNݝGk,Kl`:??qܓ|<4boL^x,1Lg*m뎄̫qJdrG;/cZmEevqRUjw!&tPȌzl/T& B!G 3t!c3,fL SfwdD< ^ߪU6cu2\Cm*;TDDdO۝gDD̵su$V IyIDBH$``;E O/""C˕޶"""V~H|JK2YJ6`{l2v]e;ڎTή?+i9F.S <&{=5Ns2LtbO{ 3|ҔapqˇTd* mUC|2""b}=*Z.S8wWd2^ '""ξQmyh0rOU4A?_exujn/~J61cNGosMDeo$4'r15U[ktBe 8𛺶Q?xѧGX٥V~~NR"".zuicq #┮+))zfG[ C>vDm'~~/S:9Y5kZf}25´c<㙛̦?O{=3,ZqW~:WWPADc_ 6{7c|.6䵬?~ꌧyv[뮶'S{E|'==O8mki+aE٧}R#Ogxu{>7.Yt"+9r MOg*nۣaTr ՠtkhZ;_=Tpb_crEqqB@B #2$43;vh)X6/Ok˭Z:Zi4|Nq W՚oj'xj]1+- ~ rg2X{w6\*<$b㣿kwd{e9ư։K; `cױ[2*#?v -~sBdvv PS[~q-,~B )ҒR;Ն[J$S {1ZBmm2$.A 6[֪m%ϹLJFu.8R)/ה1))U,+Rյ &$"OHϪ]9N|Q_Q~rVF8R'.jU'+|NKEzA N )rR++++G9K,*H 9VYq4IO1*XϹyL(pHvDYxig)cSVȺص̌<ݹȪߒKDD5 .2 AR""AHoa\z)C{UYXZpk0VTeq׶å.wJ{34[jjhˑSx/ܺ_Ӯݶ: xxpLV"ߕc r[PjaqhRv]J;zXqDd=9`l-Z@ܝGXiK,3~{&\: rk׶8==~Inc'$2Lڨ'FlN/+]f: ;d}4>7a [,fU͌2NVrjO/{q6ii.N6БڽVwwI>2Og.|O)FQd*L5C@P_Ǫ# H6paOHO1V*n/[״i刈۳sO)m۽G=zt*wšfmn#6ίm Nw42iшCƗWmwmiƧU.'ğ4ZЦ6!Tnۖ|VV_<*#"Φ(y8"@'A_]Mmo?{~d]Beu]rܪ l#ۛ9Xgrq"W~}ØȰfkӷbg}ԧ-hd8/Ǽ_̈~M-=%~B&L8`s|qO)Cj0MwBD?:|;3&>m9?8~CN<󤳀jjl{[G٣gGq"_o'ȿ_W]FUVT_JKK>sLs=m'N~{|i1`?uRl%3$zXc[_H"72JS kg+ؽN3_<6V&=^!Ykbpj~X>5F)ߍd!p4z6#csoHg+D:fBӝ2XFakJcJ*leW0vjog*<>m[XJVϼgdrnݫec uuc;_i)Xz)))իP(\r_41yUUllO?4rHsi="& ,hHWЬ `AC濯ܹӌ@S5wܽ{#F0w- ῀ֻwo3MP(Df忀_h]@/`Y[[?f,i$w!`  gX3wP/0d>|vyel>b*` )߱c_>}kƌ#Gf{.Fx3,!`  j맟~""LfB;,?pΜ9cǎ:tkh>Ï?xرK.{`֬YHW 4e=z?ƍj  )sss{WJ5~x+Ch\\\f̘a*gX⩢.''gذaMpStA@ٮo~gYnsu'0a„j" =<<žy晁b9F C]x)S5#jժ  ,P.^13_X2tY!-T K%vb#!O>}k*++ZF)..>wܱc6nO?YۻaZBGձcUV=w毨eΝSL|'-Zg n7[W('۾eO?ՊdX,n}յK"/_gYc:Yj9qĴi_j3Wyʞ_l|/x*⭝qWcz;>ݻwڶm#sΝ;wu˖-uV=M5Ox\,]6KLW4RݴI;n,;kӻsM_,N;v6(V:ywhUHI?[X)v r %rϟ;_9UQ װKR2s_ڔrJg(nk0/^}zFF/0/m۶gܹ<5rŲcXғ{D4gtXc9-$2Cp!=D8@BzӍuL%gKL^U^)f#֬Ysԩ_fЯVJwBйÀW[Ϧ1 fԨQ?._RiӦAeffM6w531p.~֬\JRVB-ds.]<.:-3V[trQYN­K//ÅqWnܫkl@,d2 ' 9"8fjK..5^]FjѢ߁] ѺuϞ={Odɓ'S(u2\֕m*;TDDdO۝gDD̵sd[IY99""N6؉]7H$rD"DB41]p6);[YsD$tJf)mR#77J?lْqUv߿zr15'Lu+`bk碰ZH`Y7ljoi"ڌ>ݸƤ.T'g8Y 6!nZ`&{1w,Jzаe`pA|mkGo_ATpbߑ32.Q ++-#'mzYDd0 #<=Ix5e Tl*;Y[ sEMR5( ,h,8R)/ה@r kʽTleu H`=,쳎mEŧO:98J-=q9W`_԰C HrNwFsU]$rRXXIP R sDXИpLV"ߕc r[Սu!R GJҎ2INAJڳ{rl[W,pw]9=?6KriIBd4'@F)NCh$d*L5C@Pߪt8kpVͺLj9}B$v>!=}#ǽ,9U[HH_pM+UnO7H_nBg&5WpPqZiTW߳d2w!p>:16}rH +:yY紵Q!`4&xDMRcy)9bѢoP7^w^[`@SdyYǮZtآDƅRV;/a A&K.3"Sm[w$d^Gȩy^atv4UI⤪hg֥WTGW@Tՙ],E"w^ Xh< $(@cp^R z##Q=I 4Ay9q;d R+9#K#;/4#X}%nc`,?-BHİ@39Xа*|嬰N f@y2Nabr/jU-&qCH5G{g{cn륺S'hj%\M67O+Q]0\{؉-a%fc+8Y%ܿ;g#y R1[͝n8Yk%ƪdYB"ܸGb3ꪝ8kϚZKw\t&$3:{XqDİ@3GPk&{@n2 v9MM }%T>K F&?~6V.*ZFr.O\Ȉ*Op{'"VpwhId]wv9’()lj^=%M!~ns o;{~idWgDTjJ_KSఏfqۘU},Ӧ-U2w{.k(g=A󃝗0' }:ƭ10hm|â^s~݃;yT:w;X" M9|WQ՛!}D$r -:YƬ`$J YHrpԌ8 ʕJAQvjv'rB!R]-R's j):U$=?;FV IDATg-sv3?AWoWADSm[9ИXݙxz_g}XO?Ysg*;{gjjxyk.ɢ5EE9yjy]]x {Ofv}"vߛ4|4A–^e\Ni'E?oGT'-l;i}$"b6D\ZyIaa+O""G7Uj\?gkot9ti-\mcV)DDDz,ChPXM}N|cKپ8y˰s|D[.-ߒ{PmJO\1銴FFEq3eex1 67Dbb"i#էOsI twrbZuJ{7 sq޶k'n-?O4N Jȑ^WεT)U3'ݦ Ÿqzi*<<<|<Cg%ft8Lq[N7 jZYSEkѪ'޷;?;)v xl׷ ~,7iC-CYzwlDYIgl.~5a.$G̘₄G D+9Q'tKđ>`ME۾M+5>jyÜ//Y!-6C:XLĉbgIW]Ŋ*cܶN7c"##(66ּ@sc8'`-d% xkFة[믡C=z4 mM49X`>,1 DjV6ƫ $(w4b~z~Vxgܢ~6܃4bs5^tx3,!`  gXj z"2]X%8q˳D)d>kx ?φx%RE 1w_5bƴ?1CKLj>zoo1',xh ݂$gdLW8mo)43R3 YvN\:w߶2n#g6ma%oXT# VWdBۨDUǞ"9=WR+ʎAQsfe/{Q(rJf{zֺÅ]DrVeDDi_<̒+ʎ_9c`l[uo!`@]{l;ui#$É)mT~$1tv4f{?9owC;i/bsW}(pͳ*Hqm+'̐sxWN r!< RKI1U ZpgV&s8vv):U$=?g-sv3?a vus55?9_SX2YPnƺnHo/3_=e"4i݋|C:Y 2SRґ|@XDxIduܡԣY' $tԹ@(>i1}IQuVn".HZ绳+A ͨ>ͅv'!"?C~ –^e\Ni'E?oGTW}e$HY4%"*, bSdӣc5cIC?(JwQƱpωUJ' Qe?Nhji9+/428;ݘD/tti! k&5O#=wX%[#ʋb¯k%(-)5r~'Xn8YbH0cm/Y=^{3G}e,_N**HAL$EJt&t]H,@ )"_AQ>{P(LWgֻc׷}ñʜ5k$Q(x:wqdHS d(Li,C:W"ďſ%!?w}¬8'.xSeD$iC'`愀ث2cX!Ab8i "Tڋ8Yp""6c?c|}۷i0=1}7D%HAq즊[9nrVP [{;.#Lz;+pdb]9FN3czȊ o1hooDYLsSsug/Myu {}DxK=d,ξsO!|{t爈nB"uH2k}|m|$dڂɝDYwG:ʅ$T,Q>w/JtFe>ް!~ik>x!ܷDV~#?w:ʉH:jUo rh]?cג:OCXqQWx̗۶}IW/H"5o5P[l0`CBB] 6,\C3fL\\ܙ3g]HP=Ma geeED%%%.h{JZ   ౧RHә cA3ثjTyCxj\~sr'd,h{;33܅ ', 444!!ArG~~~t 2V  )2dN[fMm..((3f_]L(^_{{{34AXMA>}O^X))){6mu‡X3_r <;wM6SN5wEM@SqܯZZZڥK׷ifڵ;vJѽ{Ȩ"8V[pŜ86SN 4wz~ӦM;v7wQM6DžG=nܸ^{-$$UP(JRiiiybL&˭-[vڥK>-RWdUƊ2e a/h&OiӦEGGDG*JZT*BklZc{ݺuy//Ww%%%"/K8,gp|ng1$o?ֱR*U<1ő" 3^hm-*\yx{A=cU&!$wDjpU6ѣG{xx\z?zKKK??C.Z… .T=Ma JN4N3 w\۶mۏ?hl2{{z-h4˗.];wnpp5<դ;xfK\J{行p//{t*;OݣNw[ݔ'$$K7oVcǎ*--%NW\\\TTs??~e2klݝ8x`HHue pG0rH"={.qK`3 LWWVrD>F8Eos 6.$O+gYV]ज़G֭?&''Qppp\\\M'M$***Ҧzjʁ%77wԨQ!!!.\XbŁV2111ٳ{コtY{zqjO[Iњnttq6Oo6nXXX>hР;\h駟̦ )((??'O5,7<((U Lf2hР?p5p’ @hvlmm.\5k, #sMD֧,,,f͚p{5~xF۰5XQLLLV^ hBDg[on]TU"c^jJ2iMv!' 9"S;7ZݻK҄,@zpcW'ݜl}_ޘo",q n6jC_@%HAq&,'T啕eBKXP_ɠnor&=Y: ox Ivꪟ&jc#!&Β7o6z_yt\HBʲg=rss]cIDx |iteפX-=ƌw̙5SRR0UKF ;JtⱄB"C<ҳ MĊ$ZX񄮆#w$v"McQk ]ULg*m뎄̫9|Rji,׳rB䢲P8*5rYuG]GjhE@1!<^+8Ry)+HٶڱCEDDIzFD\;G3#"NmuD"!G$ h0YH$nN%V\.+*jPp15'Lu+`bk碰ZH`Ylj>׺>l)]q))mBܤu tuY}n92w䢾̭KB.JˈDwb9-\   FXkTZŲr/[Y]+`B"tmKhl<3c[GQgNN"NRKO\8i%6<߫++++<4/,x{حE'+I*qA$scGL#lv06[lUE[M&   ~8J-;ױ58Aͤvޝ#o?( ssLX @"s@D{7.\8ze˖D$H~WZ=o}o9]U|Ñ#Giiiṹ!@ `yTm|ԩM6 >ne˖ .TW 33}ݻw=zj Ç#"" Clllhhh}ܢSNqqq"(***11>npXРӫW/BP7O>۶m  Ά  z->>M6^vm},h +W6lX@@޽{-ZسgO.]^xl  … njq-Z޶m[>}&L0o޼54[XPcf͚:u>e++bƍF9s)S-47lh4?ĉͻH$駟,Xh/_^_TVV9rڵ3f]q_;::Μ9Sծ^Z&(hEIIɐ!C֭[7Ɛn1cŋ7m4`bsM𯨨O>;vXt[oer믯X">>W^׮]3w9!`򢢢9zqƙ1⯿JOOx TsvvM fr6 IDATgРA[lxb՞.,Mfff= vj[蒒pl |8<>}.;88g֭.,xTvV4w9uQUϐ!C֬YcrేdŊÇܹsBBBm\^|  n޼y111}ݶmJ2w9j̓8q̙3]<.c3f̘9s?~z\n!J׭[3o=Ӑq M,3@Ͷ(]TT|.q+1_g|â/g_t{m߾WXcД `@ _|[nwvppoC[S%>CΙq;W$|zgkHk~r0{e,/6ݘ[%w@2H$! DAPqur#:JiԅV)G"p/qeq?-`_䒼Db潻YqWriICJDVS߄8<<}ԨQAAA ޺uk94drYݿС#/DG\SU 'fbgXtaDT#bsc^S'"#[ek24d_ehho߾aÆM:~U(-,˲3gΜ7oްa֬Y# a'|icq~ӧwSoED\9zN mˉI)`b ~r^~^kW2_B9"h֭ƍ [hQ5Xi*A9 Rƍ7o_|~IWo3A(cwX!+l޿=1˄ 뢻j?GKU`qoW\9mڴ%K|*늠4 1  ",*..2dʕ+ *k=g@1?6ǁO$Ő!o6, bn6m &-930ϟ3gΆ _PPP +i ;vhB9M}6b n#Yxo/bMi'"^bĨlԤ wuŅwmd'`Hyg::{ꕝ]޻ +,.##[n6mZe5iX""^ݧ Kدo'[L@k9Qdh:j~X%n\Z֑/T_P??kBTa }ѣG*XRRR=nܸqs]NZYY=;;[*r]KbBr\\\ܹo>+ MJJrqqq!ׅ@PC]|%###<+777..\ Ϝ9Ӯ]; j  cYv#FرcD"ẢE$mٲe̘1'N. 6,ˮ[o߾hnX~mVPPЫW/ j  Scǎ?ĉ׮][-_uy t.aOogs HOblݺۮvWX1}kȑJ[={SN~AYC}NNNe!TgEEEÇ߱c7|?퀣ѨYaOO0f<ݶQ]YЧ댘 ygw.]S0s555 ںuS=駟V\YN˗;'_p?? `Xqqq^^5( "߿xx… LmID\/Ѳn &.^H^ui9,b#O}{7,U+L6qDOO={dož~v&999YYYGIHHhٲ%5BƲ,˲nnnnnn,WX1~xf͚Y[[+J򅸨HVwؑz.""ِtz 1V=Ѱ,fm`-~G$h<׭B,uGce^X=W2YCD>VZrᄏr ٳgj׮u-y jic4hK&?לG[?iw,I?֚OķUd]_#xF]]e٢Yؔy6joyr0Yz*R|||ݺuO8|R\|@ 7n\rr23XbIT*?c@p̙_~q\WZsww?v cgXW)fs4ްd #0cR1:G-;wY,1EO;${ gq&[=t~73ߞ9sU=zڵk~~~VjԨѢEF@P 7oz+6lu-%ըQZju=44rގ1Sdo_5䡚wگQ<H09%R?'88888j"6?/%""̓c_z.""K.r<::Yf?xѢEϟwrr2eJ푱.?rm۶yzzr]HXYYEGG;88g˖-\6s)O}5cyh79)hxrc #!s]tW$.zz ;ӈɫKxp͚5 ߹sСC@ՅPR,FFFv޽\*X*jՊrqq>|˹.-]cXF} ج1Y*qŁt ڶŐ!o6, bn6mOĈDWnf-JDDk׮8p`֭cbb,,,J~M6 PR>~*p{Kb _OD<^zdقS7713k'EÓOZTw߻1;G665el]k~]q:Y;jҠA75Gaaar9g˜@C( ׅH$ڶmۨQ'O̲,Jܶ!/],HINgqHb Xٜ"C;Q~錕A3RcGu9cY? `СvB HJJvUFFF .XjUşX|^)eMX&33+ˉ y׺0ҦCl.@I!tPq &X?D G""a,XPvmmS-[b"6cFcwHbxw} #Fضm[eh *&"Lu!dɒ}yzzj_Ϩd`a-_;q]Ol߾}޼yHW5fJ*''hN̍/hԨQ]t 155ARmzm3#E9L222N>rѣGs]p3X%]fgUw˩?~~["]pX%h*.nޡ>ԩ͛7.s王KBB¾}u91,.jP-/suuwqq府'>>SNڵ+ r XoKKZ$yxxp]NUri777B/p  !5jt KK=zp]Np.]H$ڼy1c'NXEB,;}􀀀#F3|8"WXP(͛m - .jqVZ5qE3|8,aΝkjjm u֪2 TTT4|;v3*msss}||vܹpB+!,Х &lذJNOO֭ۑ#GVZ5ej tlС!!!ׯ_wuuMLL亜7{葛ۥKvgq]T7X{]t OIIi߾˗.Uׯ_o߾zu9P !`@h۶mdd$:ursyWWע#GtԉrzBP(vu9DDQQQ;wH$QQQ-[DGG7h{Νo߾={ZXXs[ ToXPm j*eiiUPC `@S(ҥرc,XP_#GرÇMMM+i"dk׮uɓ'Ue#46 "\[“UTN{cl$itz&SN{"jӦMdd$sww?yd9wkqq#G:v J WB%fcڙ|/., R}&/GGݻwu׮]ݺu+###{mll| S%,lJC[ד ͛y{8oHS|"Rn'MZM,h05FIYH1to!D""R=R&˭}DӣxD"1iˑ׏`-|N1Q~ֿ_Un%^1Bj(m[h;;;;v{~ORe%^-z|-^Vh@%Mŀz|?D:d6ۉΞ$̓UEŽdTtdʨ O Z^?l:T}!i>7?aHu{ۚXa&4K?NK}^ӷ%73)A^_G]4]>z[XbԩSȑ#Z(ɈO\M)bXU^ʽg%>oݢgܾp3Tub\|&g&j/v-kG ӧ ='R c¢X:%j^(yZzr^ʧmz{$"eԊeg-gw|sVrtA}"~,Fx)m[3E=4$5reov v`=>-D/߄ P(<8`__ߌӧK,1T@D$4AlڥKXN"""=?/.&T{8p3:00pҤI>>>x""b5,FpHsѰC1WrP0_Lj cg_@]d duFuřY,oզG?RKa5%TS®8YS!5fg"=^qs.[S.˱Y|'D6nJ[heN0r۷3.K^ ѵk&;6 9K!ZGXhH̛87Gj>C$IRe~I IDAT^,F"dg-@!\wʽg|,}g}X +nAxveףݽ I3quor ,KDĘ6nRɾx]B2/iboh _|ҥKGT*U*ѣ5k%==$WO<`9ٌiݺR}!";tp}mCFɅ pV"LN=>'i\{d3 uJhQyZ=6~o0KgVjpW0a+KV{+iA#h|]/t}LAJa9s昛O:U2dݳfK5eKk8oiҮ;@UGDI773HR$TT6;nNm'TA۶}oFٴtb"pqoďmxD Xŧ x<^g@ V Xŧ ^ku2KDc9_&%6‘lԢEov)~eYͅF_Q⋻.{Īok'l8O;ZI$ ;fLfbĭ J""6r_W[cXf/0z2L,[dщtͅ/'t=%bc^?NfcB6wSEhl+L] V@Ii4|pa7t 9MDFJ\yin5kcf2Ń8ܒAyN6|βڦ19ie?tZ:G:rh/6/S4~8zU+KuyMN3~; S]Ҡ~lK'2b-[gt>mvF}l/0Uf8 ENNNJJT* x<,E wG~Б4K?Zs" NDAu|2h7.%]ƒo9~nBEi_4%l3;.V pPs6~0zR+Uu9YvtȑcXXDį邿QIھ.gzr^ʧmz{$"-" ^WF<1^&@)h[Z$'']v544d2а[nK,INNu5~AAgFc@ag~(ԯWJtkIDDijtuTx<>bC!CDH,bآKwUK)RԤG`S?f[7\UPDb!$+TBD~(|P(`:O:7w6m8==޽{&Mg̘W_p]oeggd2d2Yvvq ڿ낎_xa(^/j{fw}I]?E5WOma2^-˹JBuΝ>}\|yfjԨ돹vڬY~۷ٳںԁ,,dg<$#~^};O>-[ܶm˲]v=u@ ݻwzz:Zrr U\&&&*wcs!#jRIƷu_`?K )0c?_BO+{(nm \ W-dg{~fq߷{e!Pas۾qU#e_5BX^"< c %yU[E>m}^zQQڝӻvqy$U4|˲,˺1x`DriessswڀrssY=qX,>|8嗎Zꫯ.ڻw/8qBjcǎQXXX&h3ϬөJVwgME 1sowUXXX;vLO0AcVc/)`A9sf֭[VՃ ڹs;cǎ~Tv͘1cƍΝ{.Z,Q~Q}X,*._3#:643-}o+Z^Ͻ2z=sĠArrrXK~={6˲٦C yEEEAAARt֭_ $''s]Hּymr]EusND R]!ɛ“.8ՈG%r!b$-9Dz;{*xD21aHfε gR,LkR}@YD@a۪uZ"kkd1#axKTT3X?#0ۋi  ʢP*,VDe2Yzz:˲ǏdEEEg"NHH&oߖdÆ 㺐nٲeDTybwO>au]VѼxo,-aLs9!"bƍ6hkϨ˼,[tw >1ҋ}( X|5\!{R}@Y<>XV!u_Xycn{CZV)bUO< lPWtk"uɜooo"ڽ{wNNN =';;ԩS/{՞={[.=zt޽ڤŭ]͙3ZjѣGw> V1Jnݺ֭;ydz>vڝnT# 1۷4y߸xڭ־615i23b\(fi[Vo/_I N:եKF3o؜ %OK-^qGS9G6p_zwZ|o^E7kl~̋{RTgeePj]^?- ྲྀnJD,N2ToiӦ,GDH:ԴiS"ڵk\\g X͛ڿ 6|~UAI; *)Ꞟzn^?ņ9]v=cccǏˢ~ǦM8p`֬Yqqq 1Ƹ3~B,b4v>kݓ -?(2s5?,쇏ijzovLʸɽ>27a. x~dj>;(|OCHYBgsd(k^YP}aYVT:88ָqcRɲO ^Ty/ʥOƏ_/¤f*+ծ];ɓ'[a4K]U 0:0hРܸqC x/x @pڵA|?y-Nx఩gϵhʊg[g# }PQBR{WFK,|zk[T "8z|nfTbeeմiӳgϮXVZ\P!`AM>]"QϞ=>eΜ9ݻw'3gN>BDaظnۖ-:AŝOPYQy%6!%6廬U;v6q5:|^%^o޹}4 gj&/,V螃CxxׅTyXPFfff]h̙֭o|ц f̘AD ,ػwY^jX1&=9,&޹ab$%(SۚI du laVV̼\ߨ83ethU;-A=]zga5WUw`U=LW_}uӧdѣG'zZdɮ]\T*Bc߾}'NS3gXnf $qAvv1k bYfMNNΘ1c.\믿̚5k֬Y,fff1d7,]sժUϷ? |E<`9ٌiӺR}51D3vjj#1K7Ĉdu?ڍY}kiԅ Jh8DD__߾}ӧO~7o0 Bnܸ1{l;;˗Ϝ9s޽o\ݲyY/Gs&O2")/ ""7SHRD*}`?R %u 23Xbvrt,P|>ܹ#F[++뛙$&&޻wa={Ι3yodYS F>14L(bD3q [w4#ȹ}=!\FI3ke<ғ7*rlEOsB؂BLP*X-Z y={N<ÄcccWWXZZo ǐ}Hܡsc%&rv#_lȢSޥgidN2HaSGo V%e 6ɉHL[: @,--dF,7';"ƄԾLu~uSFߦCOoȭZvzneZjȨA&9XPy0N ԢJ.BQj5pjX 0TY>, =w/KG0@n+iqAdg@ m5Ѩ}VӢ\ϦQdzvMmݺtNJZ(3oѴOTrBܝbªs#3C*/aZ׷hr^}-K 7e%r¯}^n5aPtj~ YS6GoD^ܶ VljȶXV*5h5Q!{pjѯmkGDJ{T\D@ĢD[Rla""B  =,[:E__^o5qR{تY [&vZMKjHy||S{KV.h5Q9,ڜ6z #t?KǦ50^j] PA& 91RM}('?+5C ġS1gfa~xNzn~XDvF%[i-L;oNNJJZMTrX21tKxFܡ"rLTVZz|ҶbF=em5(lY3׬&^>~鉆Xp}8n5v} d0U)yp;HZgs#tH8hd2i_m]kqIDATG~[;t:B+M?6FI#π=^_rϻ5ņ]G~(o'&|o>P1)OδK5Dlj/}#l9mF~~T_.˭;{ߙ&tyzqۙt6=w{DoOv-K*L~hOxSţ!4vވG5yO]{n~t$hG=]n_IVlƭxKsk#b4iI}P]5[|&4"%sYIGWGB'LZ|ԕSνF- ͛XT#yFBˀBqvYu#!{6R|w153+5N-<{(:_x'mk) [Mn|ʅ!KONG&a7A$sLrffڕ'f%.MzbC*"6Xhdd5#i2<+.]?{: _:ZITV ķk f8O| Ƌ׮x< wQLM)=}CEaw1%ēhm}')C#.U^?񰁫K]>{㈰sJUK^c+IҵӘ(lk#[&+34/^ǭnZqYL`TWݹs%X5Q;5ûS@P:tB E)-rDMԭÏGjc`9&Dyvx2#9q#ϥjbf|>CIKNQQm!cܦ`\7{}n[xșKܰe9v  =h;퇗x'LٰzRzJl<^2DƷǠu$|K \7hdR:-xVwg~`oFL^Z֠ðwY֧CD$tv eoѣ^. :X U=;ݝ=m5Uԋi :cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:cX:&xSll;wTa-[4`= eвe灊aYjc<IENDB`crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0024_Classifiers_II.pdf000066400000000000000000000305621415120503000305710ustar00rootroot00000000000000%PDF-1.5 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream xYMocO,~pd !k݌E%Û$@=Hٚ5Xf4|],VE6g57o'z~qb|U=K|~^2k7/f7{|U'r$O>{zEy 2d;_OOQWe93n؜Q^>nL䯰rrz귋ӧﶟ>_/i~zuyuu!?=j3|g懟^썼1fvpi7g,p>cgñev6w3\T!%Y"g@!=Ggf2h;6370/o|h |boW~^,?YES F|Y=hoǣyGC4z<53HGÿ_>o^w<ۣntsW@QMu#/mUL"$PLR)Xi㔊vh&B #N)]ec2'J4ҖQ vCY/JŻ_>[F VzaRRɌ]ۃap >ao 2v*Dɶ 8l~ҚfoSypA!k]Ӷ<[I!V;)oL*{ dBQͥ2w]MJSlg%\pſ"W B`DpB Hr8(uY h6)5NCP(aW[EʬAhm@wj A3D#\Bhwi#A9NM0VLYI5DT J "惑jK/ZCt2G8j-Tx MZW;X+L4ΉiȠfWјܴqCÒ@#͎ٹ sXλ,HEh Ey/]|B'G, 1tKa\\sۥ*zf T+F-Z%UѴDRF{eM$+` !!qkLwC@8A'3 Mboטm;\ YP|KZ$b(h`l.hE: |hddjwB8 wyM|4Q,z6(uYS7^4?exuLe|xyN>Un9}$la|% c5߃4ڌvUs>0l.wr"Ёf(h~n9OCu\;Q)o핏+L0(I+.; WEJ"hV@#Q!vyO|qWHY` Cu382Xd..#;.kl,f0`r(#B KX'~=Q}m HǨ';.N;ip AdW6!Aj4McaS--Y BTA&@VE 1Z=|=h64} _la "Nm\Y-rX}\ [%Eꎑ~|ꡘBWb5Ui9ud%z5e`~ou0_d͙/Ro6 endstream endobj 5 0 obj 2309 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R /f-0-1 7 0 R /f-1-0 8 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 800 600 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 9 0 obj << /Length 10 0 R /Filter /FlateDecode /Length1 3824 >> stream xW\TUff6Bffd2$` MG Q`a fhʖ!5R4tKAs?vϙs|9!)Ԭ싶rYȼtsD1Bn RJ{!ps0~YK V} #0.7P\qEVJA6a|~Ci1ruA< w% 93*FNڷbqwcn0+$D{11I $!:;AT~7z 'oVQK /A381Þkݽ᮳{&O{ި=]? :*o3J JpXavE"$Zk 7~MpAT^ފ}HQR2m›;0qKRZg=TF"z}q L.!W5eCD<l͠7Ztz4N^JoR%cP*=j+[~%'Pv}#6y x|ucSUx^]Tr琻5S<X""͞5ۡ&$;b*#!#ɠ)*ѸPHUF nٟ۬vT&6p|0?~y虘Q=.^ 4ۄ."G #9EMxfpAۙ\]K?rgsWCO'5(1+a8/1 6t^\QΫE˳s  <^oƆnz131%xr7ߐM"l㸫`NNFq kK݄]ˎbϮtp-7Arl AFtp~ ̅Fz?H O<P; qB/x@-3BGg¼?BAz( w=ĮQ*L5UG(g `K¸hU(Cc.J,!Jc4JDf Ē)r-KЪwTβVېUt?4ku:c05^4-plS`VP!"c5lo` Mc5jtT(|Y B{WNZh.Y_Z8WʊYYx}KggKݙ;:g ei/ϚW6/Xn!`l 7ّvh rK)%kn՜5Z5sNi%Y{ʼn{moas3-Ź"VXAc\P1B_A0g0Gt׬_>yVœvZ#ҁկZ.~Xf@TiPh=UR6?r*$,{/9xٮߘؒW/+19^s׿j?(-ܛi;uLԩBE΋^VS{w'W|}sffMyd(??/qVN.QHtY&"FCz[7uk,"S\Ǔ +m>UU A\\VE7Jk8>2XpQuW걔wE^v:hFJoR댰qɝ#|l}s!?Q<ɽQS|ws4 Nev۩/צǾw O Z?rԿkgh2:g[y0^b[ցE/t2*gn 2ۦ&lWU"H׏Ž^eq?[ Sjx5om$egS-Hwe81܂lcB #1 F&ldKvGl+'SE1nCMN$=Kfyh%rq .+pi"~Z@?*!awY8-#r; :V Woȯ ~)wo| `'%x@˨׮e?㇀ V88 4Nj`s=*ް:-i̤_Cv{lpgs.B7p|f φ=3G;LJB*8Q \[h4ALA3ԢjJ΄6hL#y7H"4 XR<{Œ" "fb%(Ğ ÷dwFd d)6kOg @I M]@"$fxs 0>] s7]̘ |3 " endstream endobj 10 0 obj 2721 endobj 11 0 obj << /Length 12 0 R /Filter /FlateDecode >> stream x]n0 yC@V U !=㪓vhQNd\u?xp2xuȴzvlgPq-+'UU:e =Nނ0}I5ySu:i=ٽk;Nbvt>۞ی:NZAUIW}Rݿ3)zU@4F@|>ј9J\Dgid /Mǵ"S `` HZg a~~d{ .wR9o}^2V-xid~(y$.ħ>җ?Ux`!*%;?x<\j endstream endobj 12 0 obj 378 endobj 13 0 obj << /Type /FontDescriptor /FontName /EMBYCX+Roboto-Medium /FontFamily (Roboto Medium) /Flags 32 /FontBBox [ -907 -270 2051 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 9 0 R >> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /EMBYCX+Roboto-Medium /FirstChar 32 /LastChar 125 /FontDescriptor 13 0 R /Encoding /WinAnsiEncoding /Widths [ 249 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 568 568 568 568 568 568 568 568 568 568 0 0 0 559 0 0 0 0 0 652 653 0 0 0 0 282 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 451 0 541 562 523 564 536 0 0 0 255 250 0 255 0 556 569 562 0 351 516 333 555 0 0 0 0 0 335 0 335 ] /ToUnicode 11 0 R >> endobj 14 0 obj << /Length 15 0 R /Filter /FlateDecode /Length1 420 >> stream xc`d```cp``bPHϩLP@JFnI C-_s''?@~M(`Pc[|Vf @;9x9YSQ F'LnZwS߸5<*11-"& IYMMM̌ԔDELmW?/]5W'}fnSܾEe\cb Rx~  pC<}$NǾW8\N ${?A~Ȃ#sC ^} Y endstream endobj 15 0 obj 363 endobj 16 0 obj << /Length 17 0 R /Filter /FlateDecode >> stream x]j0 ~ Cqslrfhd8d7t0-$}?Yڿ2Ov >c\a)j.{Uo;öd{Q- ^\@C4:> endobj 19 0 obj << /Type /Font /Subtype /CIDFontType2 /BaseFont /THFUQT+Roboto-Medium /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 18 0 R /W [0 [ 443 582 ]] >> endobj 7 0 obj << /Type /Font /Subtype /Type0 /BaseFont /THFUQT+Roboto-Medium /Encoding /Identity-H /DescendantFonts [ 19 0 R] /ToUnicode 16 0 R >> endobj 20 0 obj << /Length 21 0 R /Filter /FlateDecode /Length1 3176 >> stream xVST?߹"e%Q\0b"+ (N1ƌQ8vHGSB4hVE$ZQUQݻ?ͽw.BDJ .W qi!./i eR&$H!'8S4ÙL4w_(V?JCU2^^ۈ!bg2#!4b,os 3.~[.)zk0lGPrBPF">ߠǯ0ʺu-+IVdǬZO獬֒ +vlMOϷ&J6e㪕}I)eŶbCH-GXlo+rQ?NL&ah6EjGt7Yߦjk}$4I3~ch;gڷOO2ye-kvY=U9e4 ylؽ#G­{=vH^ pJ0*}, Pl=H#:@fG'/oe}9_0c=p~^k(-Y>4S*Ld}ի aK#=|U:Qx|ܕCӹ_bG9(8 Clp#C~LWgN֮ZT2#Y%kh"8X %.o`>; r"9: Tdmv0|)w::8jx]\RD⟩hѤX$cչ9ʤ'O=2SLH s_?>oc9c&7XKͬ&8@-BD)<4n+X. tj[;9,ھ04iAUќWt融NW,l0D}T |h")+=@n=74ȬMO¨meO{ xB;"8uPhHW^9}lt {e[aӼMR_T1޿)xh\W (l]+eΆP֝s$!1%!krϏ)w&q]A~N .nĜ r8pkKeM~5atcbQ5ʽP*\vXCc56]#!#;i"br70̇,(_o7<{$X:ܟ+vB=>{O;> xt vgC 甫-9FzIqsCxѐQEޭES]}%3,MMK ф_ ipʹt6;%|%Y#V2K!|'&5$!1F-d~"H 淓H ;PEye$"l䋑kKC"!pDڄ}!!T|>Dz F}Uj1zHD*^"7I}V_6e endstream endobj 21 0 obj 2190 endobj 22 0 obj << /Length 23 0 R /Filter /FlateDecode >> stream x]n E|tq#YtEaHjߗaTF ٹx5ƍu:\>:V\[fѳ,}`YX#n[I/<0y4.uhiz3q/gY {c{eTZ4~TFwy[c:N+kLF}MykuC'' +Ԃ@OA51%2k:Ƴuĩ####<=.Ǥڊ+Vm$&CYTO?˼^+/u !*=#upG~J/jB endstream endobj 23 0 obj 341 endobj 24 0 obj << /Type /FontDescriptor /FontName /IVDBPR+Roboto-Bold /FontFamily (Roboto) /Flags 32 /FontBBox [ -913 -270 2060 1056 ] /ItalicAngle 0 /Ascent 927 /Descent -244 /CapHeight 1056 /StemV 80 /StemH 80 /FontFile2 20 0 R >> endobj 8 0 obj << /Type /Font /Subtype /TrueType /BaseFont /IVDBPR+Roboto-Bold /FirstChar 32 /LastChar 118 /FontDescriptor 24 0 R /Encoding /WinAnsiEncoding /Widths [ 0 0 0 0 0 0 0 0 0 0 453 0 0 0 0 0 0 573 573 0 0 0 0 0 0 0 0 0 0 0 0 498 0 673 0 0 0 0 548 0 707 0 558 0 0 0 0 0 0 0 638 614 0 0 0 0 0 0 0 0 0 0 0 0 0 536 0 521 563 540 0 571 0 265 0 534 0 865 560 565 0 0 365 514 337 560 505 ] /ToUnicode 22 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 25 0 obj << /Producer (cairo 1.16.0 (https://cairographics.org)) /CreationDate (D:20210829154042+02'00) >> endobj 26 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 27 0000000000 65535 f 0000011796 00000 n 0000002571 00000 n 0000002424 00000 n 0000000015 00000 n 0000002401 00000 n 0000006384 00000 n 0000008174 00000 n 0000011357 00000 n 0000002789 00000 n 0000005605 00000 n 0000005629 00000 n 0000006086 00000 n 0000006109 00000 n 0000006855 00000 n 0000007313 00000 n 0000007336 00000 n 0000007638 00000 n 0000007661 00000 n 0000007936 00000 n 0000008337 00000 n 0000010623 00000 n 0000010647 00000 n 0000011067 00000 n 0000011090 00000 n 0000011861 00000 n 0000011978 00000 n trailer << /Size 27 /Root 26 0 R /Info 25 0 R >> startxref 12031 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/2_feature_gallery_export/D0024_Classifiers_II.png000066400000000000000000001337611415120503000306110ustar00rootroot00000000000000PNG  IHDR X'bKGD IDATxg@3ۗK(E7%%FҬ)S&yUɵ%hb,F%IDcEPiKej, N90;3gf8]@K#g֬Y -Y󋈈gZӧO g˝iJp{ߡCS/ -,'-_(] eo۟ iaZ^eIOJY<ȱr{&?b_lʥCGW1GD%B˶^b!ʫI GKS_?lc`o +K]\EY}=䮻vfٿVm%cj 9mNڬms:rGswI͙O;mgVo0,T(2[[e[o': ׿ =]ňXiVr6k3 /7)DwV{!Tֱ_p/^~rfN?/"+-OV,U(Hz"CYyݱNߌ˝eSC.\ڷs 8"^n,{kfM"<&c8]ɥޖJٴBITpd|kyvoz~}ݿo{u_:hV.osRYn/L~)/A[vw$R87{\UEEԄG|4 #h$i]tZ]έ*:guS0V]a,ƻDȔ55{^~,[5'邂<&֥vZU]5gř{?ՑG<ǮG7eGo~929;#ڀClӈx6iHs}(@2Tat3Ipr_afVTb|"Y{ vտㄷ2VRVVe*d.>r#8 OʶZH.$ aʂsWhx|oLQN(2lxK$U~'h3/,+*e,UDo0An İO},xeU S$%fk4/{Z~yk%"LmlD>'8ұD&JB@䮳I:"R/[Ō#"KN%<)lf#!:/+ZRb`{H'sP,pǫQ,s{g6%􃪏<',hk^{٫|UW^٨@;kO?}Ϟs6G|ҏqkGj[W,9=^ uFhlDn!TXbbЉx!7XdsÆ}޵Y#""uqQآ}]O=mk7xXGA?NtxTzhW {9wl7;XgMϻ_/miS\qV^qq߀bR |+߀_x666~~~Ʈo4hKh``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X``X&0vh֭[GDSLM`@S?}ӧ"G@ŋV*QQQ111:n!!!.\0vuMQeeexxxN $%%;vРA O S(ƮXдtH77EfeeK$B0,,,++w]j+Zqk4! 8qٳg###zŊIIIݺu5kVNv<4 999&L0`@IIɦM8Iw޽}vJsύ1"++qx8,0pOOm۶-X ##c„ s#FFDD9r;,,A x$,0V .;vlffV'ИM ɓ'3qDggGFFF? mllVXq)YfuÆ `@c͝0aB^^iӦ'NP38| Epp#.]d4}1m#F٘U^^n<4֭[;tpB}[zxxT*m%RSS'Mwyyy[Y8:uO>vvvqqqQQQ΍hGGǵkמ:uuԩݻwmE  իW'LгgϜM63w܊ #-vO>dذa.\Xd""JsIMM?~Y:u@Kt~9r$**]v.^NNNk׮=qℋԩS{gEA˛:ujϞ=/_vړ'OE=Lnbcc CCC]XjjjV?ٳҦL5Ǝx]v*++]4{:̝;7((Hnennn1k̘1˖-򊌌d.h ={_~#G:rHttzr[&L(((0vQФ!`@VW>}zVVVXXX k?7a„oݺ=<<\T.h;ۭr2>}cVzz/矣1  :tБ#G]vEGG922VVV'N߿BB n*.. ԩӧ#""j좈HufIGsۮ)d+9a2HjծۋlMd?wܦMҺt2a„k׮:hjuSjRl8ɐu+p̵⤸BIfԠw۝t8"̟K_$ۍY͋rssCc ]@3rȋ/Qtt[#2hРcWt/1QnЧIyÉ s!q>3xE[9yqfaffg-[;[ff#}\3xΝϿ~Y֭;wLSXzVqq̙3UDDZ~yJqD\qD<"sOM8"/M'r}+Pw3 qK.ݼ[9"N勄+^ xBƯ#`?aKy~yK喦v]1JWrxNSx6/{j7mԪU+7~k׮=mJN,|GgϞ^Wʘ1c*** 4&MV+ cWLkvڵ666`ʔ)O9CM^bx^pY4wNqL5ڬR8YВs:Vh;qN0ij!WØFHG$)wL?:V]#G[pijJT?:򉓏VҕG߬78^RZZ:gXlaadRs46,tӦM#ѣGBo$Jl2@{ϘLShro*.]4k,wwwHdaa!HrJb h߾}SN󋏏'%+;_8NDVC?]vocN{O+g>dڻI'|ɉ9KW;>gj#ҕ)*=Tƈ3Sů {ivXe™4~ S.L}!ӭ"}JLL ;wnNn3gXxx?wm۶9::VWWXo߾B,/_Dg޽{wvvQp1,c}+VdJ:zhXXǑ#G]#4{Ç Q111;v4ČTˈgVk;Lב+-,2Y9:H#xD{oһhc?>Feׯ{UKĪ=zYC>Y4pߋQQQ111b844tРAIII;<3vܹhѢ~{:tc֬YGUTD233#""-Z8p/{g1&O^[[[W^ 0h1JKKΝ{ر%K$%% >pV|t"0+I>p>j%YX8ҕ\ҏQpCGijxSDur7SLWdk8_=Pv] 4H0111 `ԩ7n0Rh4}w}GDvo=sgްaC|||V Det|ͦM>Nmmq222$h14ͺu<==I&ϙ3G$t!UBUҕ- ̲_H7 *Y\ET۪?$p߿þ{8>ojB#^K8SKݼl(=Gc|Uen`;[s)\T0Gw7nZtӖ-[/^,ƍV>ƍ#""O>?~T w- 빥Fmz-E&&&6tŻqqDHfc!qDV#~eW\qB]u) ;4{8"Mޮɽ 5wpD Mf"qܭy$, 78ľN/c9"$M+ciii?<yxxDGG7 MϻGO&oa;wH$½SMMO?TQQQϑW6h=2dddT}uԩY ]_b.:t9{_&y☽oʵ_[5Z=2mJIJP?{)rz_wy{ݭDĤ.>OHI:#v1YE-p{zsNA}Z[ߊ;v숉 #F yHvg\uuGEDyyy;v7o&QFٳ:ݟф,cׯc@@0hРӧO) cu ԩ?`c(hrڴiq\ZZ>ִCFvvRtvvnW_!Wg|>%]){H9BaXXXVVֻᄏj*W7r 4!:.22mѢEYYYu50|M=[[[h"ҥg* IDAT='8W^!۷ѐ!C ]3W^_3%KƘb|֫WYS88x1~*31""^!ԨQ.\xEwwŋ^ܹ3c,22{ b)yeEko?GUׂ~i͚5y(mf9rdݟ1BJ-x;As4~}z) ҬlֶgpO^nRfXE扸%OľoϮs!C 2ւ'+KMoը^H.u˅y:EVZؽ{˼AWZ#Gə0a€JJJ6mtg&]5V6m-;;f55m4SS>^x3fgۿ(u BPȯ(oc+ xpbcc׮]_ggg񂂂.\طo߇L5[m6ii}̋O S3""N-FɤR:tp b |H V!2ua=|Sw+qRc5L\݈4W j[yX HvݮXRSw2C_bѢUVmٲe޼y3f 6ofί%GDisV  g̘1cƌLBagg׭[VZ=rګ $wV(l::pB̕ʳw+*PQ#G0e&;̹mG]csĄ3>b"Mŋ5Hko}~ksX bŊ'fڴi_ܚpN<vݻ={4vEFcm<$cruoWtG\տ~\*jkDLy-#ª@@Pђ@PVu5Gaf5+ɮRk͡Q\vvvߖxk>|{G VS\\#wnc-;3i j|Kϧ?&;u f9cQpp0:tȸak5𯾑{Aԡ>ҥKuWWWKYngΚ5+... ""q1N5kǻuѻwocWdxżX,~YBuue2u'h(w)j8Kw)yEVאTE߽'Oא,7G.]bccgΜ8|+WdBիW?͛7;::v+HS7Y011y]1 fʕ_~F9sg}fnnn좚o/t(0;TˊtR9sRSSǏ|r//u "֭[;t' 6… K,A;!`֮]{ISv=..E5O۷ohh#GڵkgAu5666**(000447 1v]Q[[b //7Θ1Cn=+p̵⤸B<6ICz:RjU}dK"SS1c,\ã4fEGG{yy͚5+(((55uŊx#q~96—{XKEbs;IkjLs2N}xLMD:KDv_W)_5xc[NHGGDb#p⽹j{~|BsdʤoX9 Y̻EjӦMdd[n=qĞ={?~E=s9СCOƤ{v[MRI[]q^ Y.yǤjcތ?߹\"6m8q-iYɕzXH^nL}+51XPPPPP旒yD<)L88LSDذK8[6qT|Zڅ {MH8Vm 8UnQ=|Mhic4vi%̇L{ߜ#/9:}}럕D}6` v@7f⋟ySn̊5kV``J.&{ǝ8KW;>gj#ҕ)*cęWִE xD2L͋~ujEљSxXoX nʏ^'o4csʃjwvk#31jenJR`jK%ZF<+G~HWRTS+jFL}Dnrvv?wܦMҺt2a„k׮ⰰ0__ӧOGDD$%% :Ը%5%3M~W}wjTbѓ8SLWdk _=Px2GS(z`hPڋl-,lWU <_S_9"]B *ƙX4=tDOw8~!$ܳf]rQmoӒQx֯~?(CǛ0aBffy󢢢ÕJeWVWXzӧgeeV];o7Δ9;vQKS${<5i8R5D*scٚrV{z]E<'mY`@+FXz1ۊqo(14{8"MޮTSgG7߾g?eּ܈?fs+8#.^{H,}q\1XFFرc-**1MD JNNnE7/5CyDD'`=d.BGkc6}>ګBM²@ q|+[ #N;t!Zq.BS qhro$hro<< l=ݻOZ䈈6%bYO|s)'禙8皨3 4Iiu>Gkx{ WU¿<8:Ł.o{TTMLLBCC p^hZZs=v mSo.ФUASW;,XS4$?yΘ䬢Te8={w>l"^ #&t6k9/+`8ѡC[ x:nͳg.**zח/_nggg𥔔|L&?0;`@7fϞ=;**kҥ*S֏Z^no=0]irSM7յ+ehh ,,,,Y2wN:mݺgo>Sǯ]3LeY#ew,Vqx\-.f?M*ur{2".+b):?,0X:hР'UzzCBBjutttLLLǎ1 S*JԲS}UI.i+R.3bY٬m.ܤqI97J*jr/$: O,܄ә56{t8\Yh*g!` 4H)11K.SNqF'/--;wcǖ,Y4|Mtx+t>9*=gwL\ʍua^!TflUL%spX89keJƙ>g_Lbjof"hjʫ=d>q<tW@ 2eJzz~qF}cVm#hV_I̙#)./HOK+uӧe}w>x1eIMqR^DhH sD _$3su7HSreUݍ1\%"N*Ԕ?(@M1wƬ;v֩Sk~Ue5+ɮw[9,hn7f%$$Tۭ:uo?pBL8sK9+˯.+* ȳtSOw Dڼ%._*cb'[ eyDr Ig kg795-#Znquk%ZS3"VSd"<Ó SLyϟ?DP(~ >ps$M'98"KN%<)lVYu^V~M!"S_"6R:xW@RRҺuhʔ)OvA.4p|w__&rH}#1?C] ;`@3ЩSos,ۧZ9uQѩ;@ 0E&v5v `C                              L`Z"D;wo+3矯P@(e<#eHR>}sdV믿6nܸgZMDNNNfffB3DV={vÆ D$ 2iҤQF|cW2q1" &C1?gffiW_4hPϞ=͍]<***N8/\z#<bYOީ""9C_}ki[  z'L"1k8a\5iӖtqGkvuK$v}1H+Сs=?t8;\lll^^ĉ]@'8"R%~=$]SKL9IƤ)y[uϰ yojfوvΪ={+INWw0' ?~|nnn\\ i\LL@ tUW~?9݈Ze,.?W()Ɍ u$j{↥]ՒIOc Vt~4"dAOP(S֍j/mty~ Ϝj+Bk< 6L ߿؅4cx;qD@@^2P _t~q9YV}MHTs|2F<3UʰHY#b gcjIL%ȱgyb{O+g>dڻ/-^@,\\yT+S[u277;v옱 ipɥ f~K$py?"uy?dFxSj6u'ow<#9Mڲ+U0"ո-ׯ_~ثZ"V]UU^Zeɜ̹Μh!|{';_b gӡC4cWь!`=!V{ڵmʼn-۴wmgo(ȑRk;qBKv2,ݼdv|l_@GDęeBH"[_=B爕_V0YX8ҕ\~M{gem_''Ү]|?1'TUUk9==f/|߹}aY`$fG/>TID$=Gc|Uen`;[sdޣOg!jL9ڼc'4u͕M±=k%Wf<- o/9'"t:]evrW0"vC%<ڷ]Y뀗v/] ^o-Hm{_qڞ)&/qY,mWDB18I^8`DTy!& nVRsoNKk=ŜVhxNgi.<ƺKs?īnֆO{YXZ1[xo~^')Sc|e3g db1:@zh/zE/ }#7>?{y/ @ *ŁuU[֢Ujպ:ֽVVp[AQ +a%!b#|{'w{I >36H/zM#KҞY4dD-:zKSvL92}AL#هХxahص7Nr|~tƐAbM@{"P=`]2N\uͯx.eˡW;Jgvp &b4&(h~{p4k5"!3GW캟3'toaAf]\|ը.|ۘk$ZM)9Nvn6D^־~b_wkP҉DZUQJڮEE`|Jw8CRZp+S=U[}{ TSJQk{1@4安0E3KR 'o)>[2n|q@&&<{kƣMWQOjNf[?^4/nQ~!:ZmU/x3`a6_>wAC!׉wT폻Wn?tÁ_0lꢁ7u_0/"im+zȪq? *KVk8n5)[{6ShݜgN}[u_BU7`hCo۽횊Ӥ-{A!*h.Z{Uߴ$BU~opt#'oc?jB؃B!c؃*PP݆D ryzzzƍ9[؃UI~~~!!!lšݻwK.o!Pͳ~;;, W؃UI bZ)zuɂ K|h޽[ B!TS`Bںćžך5k`ǎc(BM,X ==222 BÀtǧ.+Bҍ  !€t租 B!}wddd<|P&֭[pISSӢ%_|ELLLLLLe2ѣG+򼦦G"##ٮ%OOz]EJJJr U >>>lW,Ǐ?ydhhhrr{WƣC}|| 0Êʞ={6nv/h[;X[[?~< Bj/zxx]B괴umٲE&Y[[o^z"H \.OKK+{|>QF喑˗/:th֭ B**Դ#]<}}}kwp8??3g]k._>>{^p8={1b޼yK.eTXܬY3v!|##m۶]{{Aǎ]wӧO;88]Q"""̙s=zdee]BU3iF#333 Wx_vÇ \tulS>.?o~ιbEw>>>Z={h^:{n؃UٓrEHW 88pZf c!Tk`+Zȑ#N>ݼysyo={ܹs狦GŒPصkWPP۶mv-4bĈǯ\&ZPP-Nds0aB9Mt1CoOysefnDk֬VzSAU{ v /Mo%Ġ[aƪsK Xbޑ{9=Ve'7T`6oޜn:BH-PM_VlScBT~܌R}/,Yʕ+:0BETu7kWpTL̀2ckzx SXFprSn}UЪ<V%QJJ%ۅOl޼O>mڴ)^,ڴ*B,v7 *#Fhذ ta ή[e,{Pܒw73*k;ϽPgu5!VR'&$$/7*vd222$Ɏ;.|gϞMNN. hfnmI#a> ZU斆|a~3~ :MQ߽@WgBP} RJ/oQKsg]n@  &]'쾛_fF ~i/Zcρ̹@DMy֘Q#hkOnIbs/!)(L3:sSSмE'ύ45ccZgECP9 \`Ԏ> a RSc8wZPS֓{m߾'yƚGs'Fl#{gqE\@ Ɵj1;̮]'+> U];w`߾}:;777w:fUg!`ĮWO/ f\@^ɣe5Ow`pEbc>St"7.]dll~5Z.KVz [/ot^eRie^"dJ*&ǵ)={.^XO~ ]*]>y3Ma$= X{@Cՙ\Nө  J)U?3cٞJ~qk{?%s[R9(Mh1Z!҂;>ᵚ(Nb$wrxzQj7^˩ؾ}TqGj4ߝoyW?<w&VnaaKGӬ J{}3͘4'7?{p|0 fv8`ΜV-WF !nnnϟ8q"变8p`.a|;ov_,Ry/,o x/*v7((H J=)8П~VR3gRBE+g6/aXg]-TsaU*UEf u1_W?AUvFcjeX?fI35h ~z ֭[%>}z@@˫6īiN>p`sw݊7[ϝZi$ ݚ/}fȳeZFRCŒU B!TR`tb@sRi4Ե>LN;{6Ȧ )g6grK] 38ȽDR^CYS]}D| #f!KL9{<1;rCŒ!L}KMZJ}\&ixK?3tÆ f%J~~~5khg{{{ч)cgo;]@WnMxs4[MDlhu1o@O?-[Ewf56Į)ZbX!aY9 J_XE@ o_z蒂\~)IWѾB5Z.??D"QhƩ2/y!ԏ\RJzIjf/ͭ=OmFۣGmzrx5m}Z]6m7ڵ޽{={@ -1uh+0"q*u N Zٝ6fҘtq^3Fqr\aqN+}w7 OZ}6S֓V>B5YaY"eŋٳe7K4x&BmځOM c=t6߉X XXCFBxzcN(޾P~aV1^1.BK*J)UOk.r_/999wjLDү_w_rl2VJ87mB91p҂۫ϺuBi/XlΰwcgO‚5&ͺ|xV)ޗٳO|˹G+>AO̅*`*Rl֬FrѣG`V6M~~,}=X`!T;,Z(22ȑ#PXX8wVZ9P~,j, X*Ço׮ݜ9sJ֭[VZM0c!T3aBV!\ɓ'+VXdI{vQjaB€Pmӽ{>},\0##cʕlf,j XD133lP f̘ݻwo׮۵jҥK[>|pСlR2O?t)˩|||mfddv! *333ٮ8p.\ЬY3As177ߴi۵T9**jԨQ}aZŅ*`!TDEE8p`Ĉ\.wlӧOwئM˩ZV?av0-j(|k"T̜9dӦM uS۳]NZjլY vA=dUBBBϟ/HfϞmeeU4BԲdE?]mwyKLWL=Z36m:i$0227o^hhӧ+6͎ט@Fʢo&S{:lĜFJ郫O#URΓ>v+e~& ?^OKX@b}A\aB€Pq+V%~~~NNN3fP lЬSwR4 j6ݼNSYƝ;5eݍ͉~71-3(.тgLZzxwn$GǧkE ,,ŊңV`B&ÀP-P(͛>dȐW \ҥKcbbWC63N yz+4(}? IDATL4U)!P\i`gilhRP( Lib@,2m`-VewigkC-P[Z@P-櫒`BUM.'$$h4]`\?? )!@zoÆ ˗/8[n+cuZ(몒ccLvmUe=iˠTQBâڹm +ШrZ 10xkN"gg_ߐ:3)Eeem-i-" ]݅ Ueee]€UI bcrMZPPP$;8@HCTh)?;S{S.#J=[-jժt)))֭+c I#R_,-' |Hxcs{ه$GN1rr旸1mb"22QY! j9X /U{L6kbm­XL&322+-drHǎrҶаM[kųg#۝aڌB/t5.P@ R5U>'- jrKXq/׺MBPZT$--A8{-gkkp=zTj JiMhlDś$$$lٲ<<@si\jrrr=O"""F=nܸ!>|ԩSKKW@ZzOX;:ɢS^QE"""6-ěC/ߓٙ fvkWk7+4C?JW  <B[ZTa牾0]}>Шگ[nǏj5xMβoH5N8atjk&;?u6'-( ذhX;oyd9,fwC (qSMftHT3zF9Y 7{5v\ҮU'>JʡꇡPZz`q߭Z{"[]ƥW3c񉉉gϮX Tma/z{?O|oաhsގIy.n-E%B6<2ө LWj:;w_i ۸ρF گw!f9r3arW]|l\o?y̍kF79wxVx^6c{и\41U^W$͍zY>6}`l>~vܗ_ ,#_Wŗ-]<%i4jo}ߊhݍ|_EիW:5wkF2ҕ5 h\gIoOU?.u6W%U:s <K0۷s3{ 8[]=X_~LMMwٷEE=iBHUwS5Ÿ;:γd б~{3hRu-j`a# [1#S#+jwWLyp[01S4>a*۷K.8K&bxo 1W>+- UTP:E}Y3`d#SRSv d j.j^=¾EF"м_L}ڵkRh[ɌHȮ´j+ Xu9/\S5{k}n&="hbD_BH} Gloߔ]LֹwˣD_*MYԬEF /Ԕ_FbY3iLEKߐ?O12ň&&͗:&j#+WظtFgL{aS쇭(Xyx/l.h;gתd忄%K9wb7"Tb}!GZ&b.2nu$qvi\!gt0`|`ҹ') W V29oE &wjp!%=,K {@X;:U][9w] ͛qht= RJE&J`ƍlRq!v-\\\={J_:8M SQzq{׺q㆕͓'OƚAqcEglR[h3RJ9y3MFձc˗/W[#_n;shMg&6:tK5@#Fmy1w`ZS}o܍ZzFܤz/8kikIoʗn(B!Ɋ?>@z}BfŇ7~+R0wPT>~…ڵc$D=|>gƍuld-#x1BJ5O7 |R^U _Ԕc}\JO :~SHxkicZ͋Tփ"V]_of{Tŋk ;;(ҽ7NӀn ,ΎOOOQ*e{nKK\._~}>}\]E9CCC###+++GGGPXWR&6\߬%Y&@Ըi}RYJpcuxP042^Lr3&G~;x;8Ɔ=zD"hذa,,,.j=z(//o֬YlR#ٳUVlW,inݺuV'Otvv^hQ&&&_~cǎ]TZ͑J (&)<`2yYL Fbc2r73mfz5abV߿lWQ٭X*>8}(V;o޼7̞=;//o.]b:MxsÓ7$oneafx/IKI0j]!0`U4++܋hu0- ^rmN8{=CiRu"È@s+yM43 1ܠۣTOo}|M[*\j-;!!!~~~l0`URFFD"ٱcۅ ,ػw//l_8v- #5?d%)7íèZ^˾uYyvw*Bb*S3n C{m߾]P]€t?NMMԅ ]~6 +}{DLsFco0\~&x-,H\cҬ˗l`E=ݛK iIuUB-R n5z$==rƍSLaָ8;;=z_ޱcGx"$&&6nx׮]8!ΦMRiULS؃tݽO>W!NӀtfɒ%rG_!ByE``T*e(Be +2BW0`;tP~~~m쪧B*D!&!BH0`!B,B!ÀB!cB!t V%Bۅ Bm6### W8MC%gff]B!T%\\\\\\خBaB!aB!1 X!B: !BH0`!B,B+...==*۳gϬYخ!P%F$+(uQ}*SWn//mAu {ڵkr9ۅ  hv\dLv7R?x3YSj{:lĜFJ郫O#URΓ>v+Vl O~.Dv-!԰M[kųg#y+Ci3\ ոlJB)/H}p'NZ.j5P5Vj^=?jn&*O|S͖_W??D":$xC͘1СCcǎfB <"LE4yrQzr1wmG.2~9$ȬD 6?Hyme*37TU*dq mmABhbbPǍ:}-؃ >;`\A!=X֎Nf;Wq8|ȰHdMK$d.nv&]&$ZF*]M叮G<شmԈj)a*>北b 44jשS>Ӯ]?~\,]BGb.D֫hQ+L ur.7d\|㏫Z4=X'\r3..rBU?bܭHW֔3[rÇuvʕb X:3tSN%''kѣlBqM\m*ۅ [ 5j/T!BHpB* !BH0`!B,B!ÀB!cB!t B!aB!1 X!B: !BH0`!B,B!ÀB!cB!t B!aB!1 X!B: !BH0`!B,B!ÀB!cB!tvz,''ŋ111 yyyYYYlB%ņ]tH$lPm2~Ǐ|GGG;;;SSSKC'O\pa͚5<w~~~1!0`iӦ]xb}YΝu!P7n8q}uss[v7u!T*,,5k{\\ܦMWLW!=r;w|'O۷O&7.??U0`UHFFϪUƏ3ydPvQ!Ty\.wȑsٷoӧO. VRRR<<<"""9uVXvE!Bpٲe)))]ve"j XݻwRRRpp!C.!tŋZW^IIIlPm,QF;v[nlBUd.,,dlٲĉk֬޽;۵ Pjݺݻ]pBkAHa*Ujjܹs{5ekAz ZJD|CKgҲ]B%8p1cV^v-7 XZbE~~ƍ.5U~$S3x|ؚ3C)sA/hzUҪUD".!d;vꫯ7ov-H],$]X^}--_'=%nqg*z!۵ 0`SNehA s`;s.Qs~5f/Nn 7(쿿\4t¢ IDAT}Z7 fM;^:MInIbs/!)ЇԫWgϞGe(WӇBvbGضSkNͷZx;ϙQhڶo\{fN+.U?%4iG, DH33a 6>cիW\\Pa*;w E.].|;o^]jbۺݘC %4q?v['9YFy+(#eSǏfI` @soߌUWBܸqBW\ N>~*YK}{gP'~6N &<`ቆIݠJ_D"D"):"*V rss9H$bC#i£d|@u'r130@8fI@Wb{OY2yh?G7i .==^^?A>.r@H_a*Zr)۴_Cޭ -;:eׁ̼\ۚ{Reަ].?ǴhѪy#יaJ @ Umd||)Q?}qc{(k j·P%aB* 7-M͸J*5|;q8__5M}!8bCbi}la=@nla3 ;8k{1R{Y4=헍Bu7[M 1wܵk* A!8::o> Bo)B!1 X!B: !BH0`!B,B!ÀB!cB!t B!aB!1 X!B: !BH0`!B,B!ÀB!cB!t B!aB!1 X!B: !BH0`!B,B!ÀB!cB!t B!aB!1 X!B: !BHǸlt////22R4;;:Z b{{-[6mڴ:!90`RСCG~zaaaBCC)@WGѥK)!!0`ϟ?_|] E۶mnݺhѢQF\nunݺC۷o5WB~nذa*jԨQSNuvvf$D>qCZ_~-[lmm-!8]eff~'ӦM򊉉ٶmFFF&LY~}xx۩S. !r===CBBnzɚ<--rB*KܸqcSLخ >߳] B!T%0`险SZ[[/[XysefޘˬY]B> rʼy󌍍囩w#Z]lp̙,$EB]d˖-VVVG.VK[n LxD}!P-=XzC&6 NX:ջqg]W^ތKAǕT+ wub@ܤw4?Y?7Ru =[X ^\˜9,FE)=tP9Ba.\P(emW9 SnZ_#~1|F4d樶<t;)B!TLhJr; 6~f_W~ݎumzm9/hsRV_YڌCKjKT&%%hz B()))ճ`(PzHG3 I4i9j;; vVPaa={i<O?3fL5T ._'O&''ٹǏ{{Bz)b9hfL%iqsO&+rرYfM4M6666\.7))'N2e?xcV|L3f8qB,L*&$$]v͚5~~~/633c^P͂ aۺOg C)]hѢE\\\92dȐm-[vYf?̙3wƮ*BVX8;}իW_>00ά;$L A ʪjUk֭?pViUY۶2`! `0QH|^sOr{s!Z'nB&OW_͟?ƍӕZϞ=ϝ;~СC򖬳8|!C/^o&&&Νyf ׉j0`!}k֬ٷo_xxƍt:61b?qDV>ݻw/%%eĉMb֭[kSNaaat:pȐ!'NG?!V; g18v};w|}}>|޶$++mj0`T*gϞ`dd4v، ?~׮]{q3Ly,%Oґ<,;!o5~Ez);qo'C.G߲e'%E݌ݦ37T1D˽Xϛ \.4 i.m^hN:=`fffRJ<!f;ޝ,sg_X^Ad13]R~y۬wZ 9,]ϱ_ϕ>1 j-?WC/\f͚swyʕ+Æ KHHسg ՍI9C?- O阽_&2%1'?Z(s~?=txAu.VWHèc~y=ߒ3:tиjz L0Ac3sssH$JfÇ ̧I=> ӦM߿C_i4[vP3 5Kژw;GMrlC*^ȹ_W|zϧ )r ˋv'ڑoO*;y K~xxsZenCo^kM!~  2119}tppp޽ nj64ǩێNs tPǃ^pWf6y_B;Mq58׹l:̷L&L3R *FLÇug75>|x߾}k׮gbfk> <5kժU|>_7ۧW^oÖbAԋjհ-O>v4GNXG]fZB6x=ϚA6P\܄>֝yJڿK=Dq* ?W} w'**rwեɤyb!M݀f?:=0Ͽhe\Nq&Ͷg Zu^nBb'Л @tפ(( ҲH㪠FYQQ>YZZdϚ5Q6l ^A@hKK˷X%BHG`j 9# yzYY1^:(s]OI~rҨ-UME>ҋ1U(=Yy|Nмi]tdD^~ᆪYYYَƪ;&YxDnıkWwOy?'QCBիW_BBB׮]v^lsU݌_X23?.d_Nެ}Nsݿ(u0g[IiiP&۹sΝ;%*HmM`DDD >ҥKvZhQll,EQ+WJGV7]XxvFFCH]U@Uxz ѳwiE.'$&Rܻvy6gRZn'>|xuuӧ_o۷o>REU~zf5?JWzE?~6'?~<((H__R<W{k#o]YmIQ>%K`tEʷ~}(I'O\~n? Jx;*燅:u*>>N>-~ᇱcѻw̐!|ȏw*^TzwY_h 뱓ޟ4i7x3.a)io++uֽzzz'$\aUڙgv"u9(sy*t|4٨SQg.fQԔ˼p=QfPUH7Ti%HmqQ\H/%22T%T^-:>~6;v,;;{ĉ cx:22:.X s,j0`ʜM&?U x_WE)URK 2B^=k{AN ~1p}ӣ¦esHMхcf*xG̝;?WTk׮ݼy?믿D=zܹqKw-]OryqTw]dv.;Fo=&` qΟeuuRߐD?[;xW]6̑?%X*11СC 8h"H$r m\/yTVt[a7M(r[LT%{wVHr/%?ԫOѤ #R/O'Zqzn To3vg䖩(PZ)j-8/b .]ãQͬ6;ұ@H{$"tR6*fjj:k,v40t^]"(nâ(3~R*Ġ(ɣ+;KU6&.%߀gdjQ@=*÷s5++oV*"BѫW/@^"J#""]ְYNNNDDÇտYYY988H$F/;yX,I:{BER|ڹȘ 1)4 /y&\I!d;"/ܩS"w)21FE2YȋwTUܜj!*QVl䵢z8sH'ŜI/W,IJ̭V5G6OINN}6333""&*jܸqt:ܹs^KB%<yDI:71JՎĉ_C}k-L{vo{zDE]*55n3?50cS8/s.B>vl܁P{ᦹݙ촬gp {i'$JWvƏƍK.@DDDAA%K\t:ѣ JJJ6ҭ[BBB!8pD"9q℞^f^,pOzKYYW??3֣KI"բe"._ŵpqB `0T(,VmOD˜AgG#M*3t7(.S'u$44t񡡡7o r~bddx\.O6|) 6rB%Eֱ@HAK!=X W\ ;wsrr6駟u6yd+WױT5> 7ίq\Puu@oBA %0sL!IʨjͥH]yyвRXWV^KJ̼mtr:zC9::Ν;766V|2𰦦ѣ&L֭[NNΡCVZhX0] 4p@@tйc,Z SNEGG-^844[[[B,7n(@QBUT,+:ЌM-M3o1w5gHoWYX0(Ѐ]R$`Zy%ѰG"-IKG zFg\JDlb$z(V, H]+t+VL4iʕ˖-[Lt ^Zu?'!OPޱ@HGaBu4hРA ###߿P(hoo?x`^Q"OjIDATpryp==1k,d<^ wMj,K`m/ =R/2 m= 5wڢZsVz[8{VȼZyt`(U*Btngg{m۶$''>}XYY9%λ|1Ll}|:Q@tX s0`!Y[[駯%pn)<4ıGc,NOu|Cjpc*AgM.:9y*z :n tB xwdF1YY9tӥcP=X9 QAplU[  ChkSMIB( X:COOZU43DB> X:̬HU4B033v!!Ps€3O,n-OlJW:/難B!uFnvܙgoYtSv {?'\ .[jG^~FX8vuѧJTș>Φl%´b)vvQ@5eEk;P,#CUbrUNJLLttt|<!, QQQ@"T`j5us6ⴤ KnB͔b2/.ػ -BRW^)pا8=LD{)1-a^T(bT*SvM3ÜNQL/t;q( Jjv滞Jnk v.㏍,txHLXY/?4}F~65\BSSJ\\,ϴ6veWk}P  UbC\pd S4kНۻ*go["gVYZ; (}QTe0`!7.[|… G=`綬ѭwT *>^c3MˡjDzVABAP(`P(D9I}IjDWbFszL&7o_ch^Ӿe+i؎'Cf 6F&ܕ7I;kW(xt~SBm,3gΜݻfMsR?>(}C!**UhN~PM4fsWs$/v %EX. K$-ݾ A6e:)W `䵫[nEGG/Eƚn5ڮzuԟ+n/c&/=wM{W*F,O7sxuF0?節|~mTebXp0t6WXt`[{Rc/dTy ( =˱:z8Ҟ]Bjkee7bN>t部T)e׮][lY`Ci#(FostKz*,vA ,MVAR|gT=oB `g#M6拯9£N8y!ĉwa>>>}QPPP(c@ Y&N^owUPN;=mЙt 8rȧ~:hРy u>O;~҃ЛzO]@A<֗\n/O"0vxyW!IԤsW}u 1gΜr???77ɓ'KGVV49MƏ߫WÇ3?!Xԥ4 4#wW!,]\:iҤW򈈈UV={~5l Y=:z{rܷ_B-@kʐQbȽӺ]B,6jԨ23g|j36OHUu1,Kvq!,V]]g9;;?6$$ܹsg[ .:t"۰aCWC$zDQSre8>B,!Jq- ^dI$D"ѭ[233Rѣ͛b5;ZH͈x1ce|e^7߼B: >,;>w=L&~<BtXN === @c^zǷl]!P{u֭[5tҕ+WF!B,ݶf͚7o~'Oe>cǎ3gVm!PuСC׬YbŊٳg{zzlݺfļ`B! X:oٲeK.}Yd2GaccB V[0lذaÆx<mB_{{{{{ eF!P A!B B!P3ÀB!0`!B53 XU\u.!B NΥO<&k[!B XBK@! XZG? v28F3~N49S?FsyhY"(`,<-9~٭4H]anF|πM !BMe䜡ņmt/׃Iq-9g/SË9kғҠ/̈_ͬo)nu$a }!BI8n;:10Y@;z]e?' :x;g+2{֝5i"ʹLÙhngcwnE4f2qgžQ !BM,-NFwlf(0@r_> |ޝ9ިy&x<^#obmB!u;&YxDnıkWwOy#tlF#='W!B%YVdc/V3}?^򾯻S/ŏT~ nki/:'4%wԾB!4eL{Όg#fvlY$zkḑ [Chk)3$%3s_SΎBVc^jGM !BM, Lf}}}t0ClR~r헛ϛNď*y_v&nt2G\Q\THC:l?f}N/Bm\.g2Vb^jZׇVWW|m ٱ&cnXA?杞ea!Ԍ?͛7ktF45gggm ߒcS]ۣbB5#DRYYieeBU4P窌h<v!UY gKR@v?V_''"4OLL3fkA"IU:J;sݽEķ/ nIװ<75Ni)pnOf'ݩ3 m=}MEMYQ=|l80-%X` ݼ-8w0űhJLb/w\\EQ{~Ov ,ib?hN!RH*05ںX_KVt[a7M(r[LT%{wVHr/%?ԫ'#u~}:ъsT44hРlST(I_SN!5 XM0!''ŋ.!CToHJrzltԿ7ʟrKJV| _)'Ҫ*J3EURBl{F688ۛ&Fe} (:d2tI}yGSEQD*???>>~oY al̘16lv!!A:J^U)p0cC4tTZԹrBuR7>XT(S  j4;)PT;X?^[0fш˩4۸q#N2e|w8K3}}ٳg]699[ t@aJR ǩzĔ>"lJ 4#'_{,{dSPī8Ԕ=??J% ԑM`coߞcǎI&ؼ!M-ZԡCYf) BBZPP8Qbʳ=r)GD(6CϾSZt P(`}zĈ1bDAA+BV kxN-\< /hQVV6}?gϞ -VBm>ygϺ,_TE!H$NNN[r3g]BmEQԜ9s222{;3f߾}%%%. !^Vyy#GLbiilٲ>}|Wt$"^r۷o?߿&&&]t@ۥ!$//O7qf̘j;) XORݸq#>>>33ݻ"HPh(ҀF8;;۷{ϝ!)h47>H!BO1X!B B!P3ÀB!0`!B53 X!B B!P3ÀB!0`!B53 X!B B!P3ÀB!0`!B53 X!B B!P3ÀB!0`!B53 X!B B!P3ÀB!0`!B53 X!B B!P3ÀB!0`!B53 X!B B!P3ÀB!0`!B53 X!B B!P3ÀB!0`!B53 X!B B!P3c<)%%%00P{ B鰔///ϏB!kz(BvA!jcp B!P3AOmHIENDB`crystal-facet-uml-1.34.1/user_doc/doc/3_gui.xml000066400000000000000000000551331415120503000212320ustar00rootroot00000000000000
GUI / Usage Manual
Window Area Overview If started in graphical mode, crystal-facet-uml shows a window with toolbar on top, drawing area in the center, element configuration widgets to the right and an optional notification bar at the bottom.
Tool Bar
Create/Use DB Opens an existing database file or creates a new database file
Export Exports all diagrams to the selected folder (supported formats are png, pdf, ps, svg, txt. xhtml, docbook, xmi)
New Window Opens another window on the same database. This new window allows you to work reliably with multiple windows on the same database.
Search Find diagrams that contain the searched elements (see )
Navigate Navigate to parent or child diagrams Create a new diagram (see )
Edit Modify elements in the diagram (see )
Create Create elements in the diagram (see )
Cut Cut all selected (pink-cornered) elements to the clipboard (features of classifiers are copied if the classifier is selected)
Copy Copy all selected (pink-cornered) elements to the clipboard (features of classifiers are copied if the classifier is selected)
Paste If the clipboard contains a diagram, this diagram is pasted below the current diagram. All other elements are pasted into the new diagram. If the clipboard does not contain diagrams, classifiers and relationships from the clipboard are copied into the current diagram. If the name of a classifier is identical to an existing one, an instance of the existing classifier is pasted to the diagram. Otherwise a new classifier is created.
Delete Deletes all selected (pink-cornered) elements. This operation may fail if a selected diagram contains non-selected elements.
Instantiate Toggles the selected (pink-cornered) classifiers between classes, named instances and anonymous instances. No effect on relationships and features.
Highlight Toggles the selected (pink-cornered) classifiers between yellow-marked, greyed-out and normal. (Does not work for relationships and features)
Reset Selection Resets the (pink-cornered) selection
Undo Un-does the last operation (Opening a database and exporting files cannot be undone)
Redo Re-does the last un-done operation
About Shows version, license and copyrights
Drawing Area Diagrams are layouted automatically. You can influence the locations of classifiers only. When adding too many classifiers or relations, auto layouting may not achieve the expected results. In many cases, splitting the diagram into two or more diagrams solves the layouting issues and at the same time improves understandability by focusing on one aspect/topic per diagram.
Navigate To navigate to parent, sibling or children diagrams, click on the diagram. To create a new diagram, click on the icon, or the smaller icon for a new child-diagram. To restructure the diagram tree, drag a diagram name to the new location.
Edit To focus the diagram or a classifier or a feature or a relationship (yellow corners), click on this object. To select an element (pink corners), click on these objects twice. To move classifiers within the diagram, 1.) press, 2.) drag and 3.) release the mouse button. Note: When moving a classifier, this is moved in all diagrams where it appears. Order and locations of things stay consistent between different views.
Create To create a classifier, click at an empty space in the diagram. To create a child classifier, click into the white space of a classifier. (Alternatively, create a classifier (see 1) and a containment relationship (see 4).) To create a feature, click onto a classifier (name or border). To create a relationship, press on the source classifier and drag it to the destination classifier.
Element Configuration Area Edit the properties of the focused (yellow-cornered) object. name of the focused object stereotype/valuetype of the focused object. Stereotype names may consist of characters that are valid XML tokens (Nmtoken). This field is deactivated for diagrams and relationships. For classifiers, multiple stereotypes shall be separated by comma. type of the focused object description of the focused object. For xhtml and DocBook export, use a double linebreak to create a new paragraph, start lines with *, + or - to format a list, use D0001#id and D0001#name to create a link to the diagram D0001 (showing either the id or the name).
Commit Stores the latest changes to the database immediately. This feature is optional, it is not necessary to explicitly save the file.
Notification Bar
Information Informs on success of an operation, e.g. an export
Warning Informs on a possible problem, e.g. a read-only database file
Error Informs on an error, e.g. invalid data pasted from clipboard
crystal-facet-uml-1.34.1/user_doc/doc/3_main_window_sketch_1.pdf000066400000000000000000000025611415120503000245100ustar00rootroot00000000000000%PDF-1.5 % 3 0 obj << /Length 4 0 R /Filter /FlateDecode >> stream x}S=1 +0v^DqP( BAljU-0v x~ab4Yw HX q kR_3J\idBFsi@.}ݽ0/چ>cXi&5z7<&%1B_V,/|ڑ/\eJ5* $8cNI8r &*D2K-r~FXObɿ-ɺǒ58YFff:IDkR|{{.L5Y!E%ZA]Ycx?/ni!׻M%qQ^JQF؇k釨.dqG鑩Mӕ[L 5)ե|E .#.ʦz[aq2xKPż9vƓP0O΀QR>YsYsߌw endstream endobj 4 0 obj 493 endobj 2 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> >> endobj 5 0 obj << /Type /Page /Parent 1 0 R /MediaBox [ 0 0 115.199997 115.199997 ] /Contents 3 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 2 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 5 0 R ] /Count 1 >> endobj 6 0 obj << /Creator (cairo 1.15.2 (http://cairographics.org)) /Producer (cairo 1.15.2 (http://cairographics.org)) >> endobj 7 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 8 0000000000 65535 f 0000000907 00000 n 0000000607 00000 n 0000000015 00000 n 0000000585 00000 n 0000000679 00000 n 0000000972 00000 n 0000001099 00000 n trailer << /Size 8 /Root 7 0 R /Info 6 0 R >> startxref 1151 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/3_main_window_sketch_1.png000066400000000000000000000032761415120503000245270ustar00rootroot00000000000000PNG  IHDRFsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<;IDATxol]uv[uzaȀ: &:'DA'?Fфdb ]f@f&8ē% (52XvPNJn9zs)H$ ,]8xqzcYT`wU휻 ^xx6sdB`?@mArtwN2Q 18}cęFM=od>6ȮIX!3srW))))))))))et:;靤hJ:tu(՞LJZ(Mom[G_48]6?5A:mfC:8P/iv%^*I$etުL^D+Wz`> Npr%@G G{mXҢEMGW:\)k] Jѓq=)gٮv4mZx-\K͡x:H 25/}|gz X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X -@d,d{µ4l8@[i5ٖ7y1>n:Xo-YUsSy/͉x!xI[i\ G`6k^?$IU~ R_|k"=jD.m|_Dʌm"#CGdeFy?EuG.ȟ^۾w|Aʌbۗ#o|w#9G*3Ƕ#?ȷD~2"x3]ysG-Sb~e3_K1m\YA`08Giy<oſݱ3qs1c ̊ Z1ayY3w(|Ќ33[F&2EFڙLK&Vx*N<F(Ff+u2-y$bSXDNاg'c!2Oal~hY +Cm)djrOA[gsCy:'q\7ŇqG̘3bF3fWf3134cFl+vI3>?9S|x&xj77ӑVfۖDgoȟneƾȿ|W"oȇ+3zc#!O"ȋ"WߍmFc䵑ȗD(N("ț#/FeFl0So|GG"_ʌVTy:yS+"AMF^-IENDB`crystal-facet-uml-1.34.1/user_doc/doc/3_main_window_sketch_1.svg000066400000000000000000000065121415120503000245360ustar00rootroot00000000000000 image/svg+xml crystal-facet-uml-1.34.1/user_doc/doc/3_main_window_sketch_2.pdf000066400000000000000000000025671415120503000245170ustar00rootroot00000000000000%PDF-1.5 % 3 0 obj << /Length 4 0 R /Filter /FlateDecode >> stream x}S=1 +0v^DqP( BAljU-'o g/߁gހgƇ0d_ R!aW=#L9;(fΙȄ*;%큆%]{9<`R _ }-*9>C MkQno©@+l Hj>11cT|ZjGJp)KԤZ6(܇f9JR&mhH8h PcZ,–aq? j*&2ɺǒ5`YFffNDR|{{.yO5Y!E%ZAYcx?/ni!׻gI\T`k{ZD! kzdjt%z(aJu9_i-H=ipnq9d1rݱ$̓3`t\yez endstream endobj 4 0 obj 499 endobj 2 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> >> endobj 5 0 obj << /Type /Page /Parent 1 0 R /MediaBox [ 0 0 115.199997 115.199997 ] /Contents 3 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 2 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 5 0 R ] /Count 1 >> endobj 6 0 obj << /Creator (cairo 1.15.2 (http://cairographics.org)) /Producer (cairo 1.15.2 (http://cairographics.org)) >> endobj 7 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 8 0000000000 65535 f 0000000913 00000 n 0000000613 00000 n 0000000015 00000 n 0000000591 00000 n 0000000685 00000 n 0000000978 00000 n 0000001105 00000 n trailer << /Size 8 /Root 7 0 R /Info 6 0 R >> startxref 1157 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/3_main_window_sketch_2.png000066400000000000000000000033071415120503000245230ustar00rootroot00000000000000PNG  IHDRFsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<DIDATxiswmwgv릤n4[P H73ndƶn<ܳ=U8k9%GK h&3ox4]ퟐk.޶c5j_p5Ok>o733333^M?gt~{/Q^[iW*?|+]2YQ>G廔'+/PޯdF'*?LycɌ_g)_%3~׾c_TAZW"bL FP; @z7.j/PZ<ЯthZ}m;;2czyy}]=f4'iѤp@ift~I$ۚ+p5^odVZ Ȭf>zkVI'lhoteV`t1D^b(/Ё-o$v(: q0 t=u˱F3XQ Me&ƅr!]v9IokoֹO{u^ø*3r1R38dFqf=faYs1+N3F6̱OqvtF%|҇U=P~\˕U>@dR;Ei۔*|+DgoV<_p垒j/(ߤ|kK_Ҿc_R|W(^p\koT~Q8%36hR ?(DʛӔoU~Fd033>$tIIENDB`crystal-facet-uml-1.34.1/user_doc/doc/3_main_window_sketch_2.svg000066400000000000000000000065321415120503000245410ustar00rootroot00000000000000 image/svg+xml crystal-facet-uml-1.34.1/user_doc/doc/3_main_window_sketch_2_create.pdf000066400000000000000000000136141415120503000260350ustar00rootroot00000000000000%PDF-1.5 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream xWn\7+Ds_rpCjrD)qbY[67ygk1;7¸O&ؠ9JlO^҂qQqLDy)?ₑ >ŊEZsXK<yo&<6 6Ge ^Ls+28jn(վd$l%$[{lE~~w5"DZrQ|k%IbzOYDFPl=׭n n[`=6 ˓4Wh'zrf o{k\krAI#Uo4W*A0 : Ys7nwR\j.8n'gېAY<>gz<c Bj]m rk}sȳkǃy=p_:nW?7ExyJ|yJ)> r+ R-JgަҙZ1)K Lu0ϮȅTMH h[X3j:g)l}’/}q ,^3v#0d[aq4pųkL3V|k}Wx8Ԇ,Off[)1ݭطdƄĈKHhO8s%޶V%e)RZWiȒ>X!v91`ꄊW'$VS1 9i\̔w*I%0;Dž(do \F yTl &m%F=«$S˜@43C u}WJ8Xh'MznB|LՎD*IjeE%&.h!ZgxrA5e^[iMʃXhj> jD62AŅj~ի̗oV6-('.'˚GQ;r զM/z*6+xamlgy ^#;j큵&N{1p)3[~ݻp5Q ٪h״m7ՠoe6 6yDfRNx A##nM0{ ^ED^N5N|T/j_m( NJ̭A8Okq 2Ð+v(dUB瓆F 5xJ?!V$4ovEtIyg!,e![)-d*_ {=\~^0;y.T> xOeMB=nx7k` 2БevSU OR?> endstream endobj 5 0 obj 1429 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> /Font << /f-0-0 6 0 R >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 108 81 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 7 0 obj << /Length 8 0 R /Filter /FlateDecode /Length1 3924 >> stream xV}XU?wށEďADj$]T G2WVJM̩lJ3CםuM1H>-m[S6*sMۉgyߞ}w|sDATY^g+^D]rIDrF9S˜M_q*DX4erjq(?La9,1}ÔYoFkvL>4'ge*}i'BtU6HN!*O[8Z3uDߓ{&j:9ڏ־T+ՖZS[5+9K3M=HwlaO\旋K19@)b4g`I66ܧ}9dh]+IlW-5.U|oRWll⯝8f^ZLɊK;Ԥ8|y-K":;lR'z ߾V'FF&" @\QA hBA^4cF%l1ِ_"0lr}>^7/9+: z=Q:f.ՉKhy’.K8ѶD[)nʹIdOOj2g$zd6XvkXU~Ki.kU>9j/޼Ū$EG6իw؈)˝8?|wK[kz4nsxG,HwSM=Bi/!\nesƧ_Wx½)NoN"YԮݲƕ!m n^Y.L<2hGsM*|}fOEcpZ%`?[VUܐ|o"/y FVZIVX ,fX."#a # v krm U\V7c(~{,TԞI#"EۭE-`r1E*l܆4[j6LJ*[Dj;ƶm/uT 1"IF3 DBj\ǵigssGjлL~1N< 6M]Em 5N gz#z^W, ˭rC(TMsd5}Etl8Xb:-jq9"i,o.m^KMq+EBn,?¶m qގ$dʖy߲*-ݜ^B*V:S 4}>eeTǶ7Θ*|5!\Lz^VܭcD&1 ˰# Iќl\˨#v.ʄR^S'7gsX]F TŹ&;~MR&hQހglhIjf"1|gC{b* HGJ;c3 ;>eØWXl! 9 HF8W2&ʤPP;S-upz֨LZs*UQz286:Z!;:ŋx㵑ΰPx/PW53( w=Nޠ-.|UD[ sR _*Vʇ/}h \g q\<9VV8k~I$EKRhz?Q6)UxG >8,O(OnS8&;V<)TxS  Px] )WxՆ}]rBAaRw?.{J=_qa|إ[ovz(;^#P9藃ئVcEa Qr/Dy/9MFM Fb3 rl03 `<*TYuQXǃXf\Tُ5\u1V+> stream x]n {bMU*d)4.r(N ŀ0.Xm7s<:G&L`7G0b8hͪZe 4cKx"ЏR<[[u״+ h49݋ rEU|ut/]kIy[ t ˜|M1-#}#+'3k2}ֹe,j=> endobj 6 0 obj << /Type /Font /Subtype /TrueType /BaseFont /UZKCJP+DejaVuSans /FirstChar 32 /LastChar 52 /FontDescriptor 11 0 R /Encoding /WinAnsiEncoding /Widths [ 317 0 0 0 0 0 0 0 0 0 0 0 0 0 317 0 0 636 636 636 636 ] /ToUnicode 9 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 12 0 obj << /Producer (cairo 1.15.10 (http://cairographics.org)) /CreationDate (D:20190310111354+01'00) >> endobj 13 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 14 0000000000 65535 f 0000005427 00000 n 0000001653 00000 n 0000001544 00000 n 0000000015 00000 n 0000001521 00000 n 0000005161 00000 n 0000001870 00000 n 0000004517 00000 n 0000004540 00000 n 0000004867 00000 n 0000004890 00000 n 0000005492 00000 n 0000005609 00000 n trailer << /Size 14 /Root 13 0 R /Info 12 0 R >> startxref 5662 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/3_main_window_sketch_2_create.png000066400000000000000000000257361415120503000260600ustar00rootroot00000000000000PNG  IHDR K5>@sBIT|d pHYs^tEXtSoftwarewww.inkscape.org< IDATxy|T3@H" hY2+ZjUĊ[7ZZMqD[7ܰ+` jV|\p#wjBHB23ǝ-mf~>̽wy2I{Y0 !d at:#OaImF'"1<H: {{^3O@~ Vl/pن b_iCȝ:"Yz @Lg[(Oi2$7k)ݪț@?^3j1 (i&ȫ$=X* EB{YZKC2b$ wiBAJhD! {*|tYQ ݖf`A2_tLFl}=(1 ˙T 9,vBJt%{阌3 ȍW rO o@t4kvrKED.Z@ a[b`,coLr $ Β{X*} z<TNDayC;wwA1S'^Bx&ʸg콕Obn+,_-lU{[U` rs;ҏz 8 7NE!F%\^йMgAVSM5VMz=aKE@ r " }_U ⟃=YfI@#t杣Q:xA|3twN6 &X/d\Ǿm  Bf*kY~~JԤ]:S  Cx hd6- \n|[T {@OՃ{QgUt"r/" R$;MFpLr KJ2R\06WmGh~\S4kOPA.dD|Lr.п$Ip-n3B r@aɋqm^pdE_zv3؅I@qO_{ +`<FZ[N#GBNIOVmެlp:$ lih7ـZ/sLnW ;=kYU׳!Ov2)'e}i? G s@>[ C15Cé_<=TAcFqr\i"IzP ͦʑBz%%\_ACx'O[F0C1l7G Ceِ|7 c/V! ȭķ x/{f0R΃0Z$ Wdg|Hjِ;-Ado# #.ct Fi ntV`盃7dF4% s fcL2 1& pI@a8$ 0ca1D @z֛(t ȇeTd$7qĠ$ # {yhchWb)RN`7([tx0W/rnAP:x5@|0/8`AđGJv=uR`AP20HA`&:D 9@ޏQ](8 bP$ ;wЉd|(%bTW<K'K@9He>8SKߝ*y+ ik·:qY..0SQ݊=@ak4B`c eB$ H[mPR.)rd*1u.eќ)m_/i-=_G}]H."iw$ȅkI@rTU$,oTC輻͑p& ,v ^z E-~6@t=N#I}8 g (ķ9,1ρʄL-, b.ߓNe8ǁKen7s8w{T>I&ٳy,߁< i2Gk f.NC^Tn3j-AKܞ" $)`;PD2d=bdz3g? ,i8EWUmwOZdYj 7#2>8 NG~[98]^ _=%ok A fnDNLbҮ UtRMoSfn EwmO$#S3:6 ?kÈ??lk_RuȻ@?G;R>&x^JpErO@FcZÀT3dx=P&'[@~VlۘFhz7Dƚ67BT<тn1W(r `hG44BC2fx)EX "4IB=;b%Hi? A|Jr ]P:5DT?'i2uwFL#6'#^iX !lx^RA.@>DE(p1P2Z=$] BכּZ(+y-4@"/EؙZz_Η#Qzg@2s@\KB KAU`0 K$-Id<7U|D{F5ˁKk3 sXwZdH{B|[E!;9R~r 0л_1 >Y3`a7OMsf'07Bz@Nܫ[~t=lfj鱠A|39YdfDlޅZ>dk6]:N竅2:Ì>4`P#yA.?oZSxsxH gg{A&jSQs$!=$b,w9P~OUR7oĪp' e6dQ%'—SSv|N]rȾ( 7BҚO'\Ҋ1r5seo;ANzqDl8smg76יmjiF-$@_ni暇7s\$#\cH]w5:@t0Bb6ƨ)~ S=|5 N"` +@h_ޥei *TX0ĝO?Xaai{xcx`Vh9Uߥ66"sIAS!bGU0+ut6+(z0*藓ESu'-s_GC"2nm.ZP_uoَv#^/dְ~' e72m~ylʼO"9J ėENN>\3MF:10}:.&;}^ܷ].=t]|e Coz0iYݖANG A CT G[\ۅ42]ķ- @l{= ?>b 0$*b7|&}H4G#tE-itVʱo ?7+Y}~״=#5DP&s>`t"<``9ګ˰QaX- I>FKL}.L'Fg@ dNg'}BZCWtDʱ{v:SP+5 Yo6g@"z0Deڀ pI@a8$ 0ca1 0 ǘdcL2 1&XtDDta+Yk:@YA-͡φ6q}>NcP>sd(:*ś^t9gha1X-p: 98:ٽe:]t3"~<\~7Vgg@7B<5aQqHˆ_% @:- Ӂ3 w1tEeJKNp.# }N]6`%@<~_.8шV2;="470vB2ax@!3}9ۇ#<' 靛 ,x.w6ňV|:+V!HPHJnߡ[m#q+hO:)V2y} :*3"$dARw5@lZգ >w[^fO흒4=I?:W$ EĥhBB:0H ķ#qA&~bWoԽv2Gj ՏG \SYy|=ӛ7S`nws'>ږRno{` 2"--0]62"rB0^yL 8("%wXu!p 8>HM Q:Ky9eg"ޔ/GEh-78qu[ 2`jI%X7BPoxAX ~ #62!@%pN^tLbBz`"s@]Bf{z,̈uiܘ*y+دPg#2-wԸzTA| yS@W Pˆ1ԧ9E<ߓ]=x̭N.ڀv#|UtM?PZ۝SQDr`$ TB&XGq[Hff;ѕFKkp#wO# k ;)o^ $|hKh;+f`=AG ]FtkkB'AATqzo2۪{37B׏$ Tէ{x`B$;6to#ZS9 ^0i4{gZ3nɻO&wW"! ((7CY铕DylʚoI.p8|axd:;]: G"a Z?3` p|$#pN{`OhUo1ˁ%${16/GHw*DnD ?kk =8b/-;1$l*׈o6Bb/Hh~yD?TB ֑ kð=+1ww7L bm2|Dqf%pp>{Xz,vq9zw`~ O^Eo*EpX&BJd\Gg)̞A澺[]Q1) v4v̀I R`w݁o HU`I@F|}<Lg]/P cg&QBn]0#j4Œd̛Nc{ҹ9 0 Ȉ"٢xϻL|o$rNb$b-;ܸ$ 0b)K00ca1 0 ǘdcL2 1& pL{&Ѵ&+ms:zNN:pvD>ޭ6|6ߗ>>:"vt:vwFZ Զ. ňL s:7iQ5m;6c΀ܦ lia΀%QbPUt^3 #><<'M:tTa z!c@_Pug -Q@Wb/A#ce%jME?v:~]5:nȀQ?I$ =X =Chp 0נ0_|PbcpT7rwz?b N};,' FX8c\S3DaYg;I@B bзAC|'g$Ax#xQD'C}.`Ӂ8"ni)_8\|H #Eu2#$BREև2jElEPI2=HҜB]נ nzl ּ 9@GW=Mti*U9K?nF> @:t)/_Th@"=w _uu_I OIDAT48dH>8e|'џ;pDZ@-b_{4- t42H K Z_`5,߀](//hR]Z/COtk8kᘭH 0Fa H M@E"vFf8b -ɶǘq\1qA_T[Xl}wA`Zzp8 D$5d Vl/t%"r@ Q:F@C . h8}^9oalj[5ZkS@f#/j]pKdlKuFB&lϛLjR¢ҁ^ӕ|U.@^sK4fhaBύ_/cW*89C$ֻ֞Q /ϙ:J;o~?? \x}{ ?=OF9GjH*s_NT>>(iB. Hzoůn흒ؗK`- %#ۓ%9 STAϒVUךd5ᣡ+F;w&I_'_d' $;Ej*uN40`-XA]p$ieU}$2Tgx=Qqg8i|#g&RU:d*<}֝?UE|ýL]T6eYь PDRhq!O# )!</{A7$X0!U7<oގ'4W,- QCE S |C-2бxW<@P"< ΋ڀO'k+~R$4B;dߢ,R Q_JN g &3 (քAbOz+ "oFcir c (r?{aBJ}1? |l *P{e2 0`PIaՑtXAU\~壍$ 't cqk`'2 ÈsJ I5a,wa̬.j0IENDB`crystal-facet-uml-1.34.1/user_doc/doc/3_main_window_sketch_2_create.svg000066400000000000000000000424201415120503000260600ustar00rootroot00000000000000 image/svg+xml 1. 2. 3. 4. crystal-facet-uml-1.34.1/user_doc/doc/3_main_window_sketch_3.pdf000066400000000000000000000025651415120503000245160ustar00rootroot00000000000000%PDF-1.5 % 3 0 obj << /Length 4 0 R /Filter /FlateDecode >> stream x}S=1 +0q^DqP( BADZU-DOG׿!i?9,;D3o@a.DḆ6bE̥8&Ή̄׍; T@ǚ.FcݽTi>NcXá4C1x ?ލ EΜ;%+)A*_5},|60fZJ$Ս28!wMv\UR>\ :6R(liPS4J6u^aRe\ UwR\x9IhXn|=;=+7I9:@eb!3w{#0/e'~rJn'u(\/@x{#XnC;|! endstream endobj 4 0 obj 497 endobj 2 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> >> endobj 5 0 obj << /Type /Page /Parent 1 0 R /MediaBox [ 0 0 115.199997 115.199997 ] /Contents 3 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 2 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 5 0 R ] /Count 1 >> endobj 6 0 obj << /Creator (cairo 1.15.2 (http://cairographics.org)) /Producer (cairo 1.15.2 (http://cairographics.org)) >> endobj 7 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 8 0000000000 65535 f 0000000911 00000 n 0000000611 00000 n 0000000015 00000 n 0000000589 00000 n 0000000683 00000 n 0000000976 00000 n 0000001103 00000 n trailer << /Size 8 /Root 7 0 R /Info 6 0 R >> startxref 1155 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/3_main_window_sketch_3.png000066400000000000000000000033241415120503000245230ustar00rootroot00000000000000PNG  IHDRFsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<QIDATx{lunM34V Qt/Y x F 8/D60I4aBtF Fl)"5Es]iמ:}=}8J,_O?;y $I8usm?p z`0@vP`v۫Z3QK/l)FVudB))))))))))@mjec\_t96Rz)v3mҏuVV[ֶ$It K[TE pd/J t.U`-s7< l9㓧S-fiI}} x+x?pW[L.wffv~~s6ծD=3{[`yD t'e׷Ȝ|4o?/gW}\o:L98QI`ռ=}3xg m6 _Lt屜6۽X٥@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@J@Ji.пᓱEf8rOoo#ծ tp~+ZnghCjWIwVަvOTEacSӏppe.y1S_6CZ7RvlX7fF3&I$x(ύ}_|mF7:޹#'uȿ9؃ȿ҆9ꟓ|NoE&%F~yنyg?ȧEn image/svg+xml crystal-facet-uml-1.34.1/user_doc/doc/3_main_window_sketch_4.pdf000066400000000000000000000025641415120503000245160ustar00rootroot00000000000000%PDF-1.5 % 3 0 obj << /Length 4 0 R /Filter /FlateDecode >> stream x}S=1 +0v^DqP( BAljU-'o g/߁gހgƇ0d_ R!aW=#L9;(fΙȄ*;%큆%]{9<`R _ }-*9>C MkQno:6Du|(Ybƨ bi} Ԏx*SIlTQ< dsZLѐk045TY&Xj-5~;M%Kdf '^QJ VE}&~3|fW3GhIpv:cg-7Yfp!\咽r ßWؗXqE%|*FzڱL[> >> >> endobj 5 0 obj << /Type /Page /Parent 1 0 R /MediaBox [ 0 0 115.199997 115.199997 ] /Contents 3 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 2 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 5 0 R ] /Count 1 >> endobj 6 0 obj << /Creator (cairo 1.15.2 (http://cairographics.org)) /Producer (cairo 1.15.2 (http://cairographics.org)) >> endobj 7 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 8 0000000000 65535 f 0000000910 00000 n 0000000610 00000 n 0000000015 00000 n 0000000588 00000 n 0000000682 00000 n 0000000975 00000 n 0000001102 00000 n trailer << /Size 8 /Root 7 0 R /Info 6 0 R >> startxref 1154 %%EOF crystal-facet-uml-1.34.1/user_doc/doc/3_main_window_sketch_4.png000066400000000000000000000042021415120503000245200ustar00rootroot00000000000000PNG  IHDRFsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATx{u6ÊH*5]HE11&X3gϤu4k(~$o8cUGGbK񈈈I6H D=PwHT?y*ZNf0W*opk&M=>MC Fdb񯌦9u:M:`{kS8KM~b3PYbgٟ6 Z!~Y}3H( $ H( $ H( $ H( $ H( $ H( $ H( $ H( $ H( $ H( $ H( $ H( $ H( $ H( $ H( $ H( $ H( $ H( $ H( $ H( $ HPP~*d*$:4Βj8138Orm70!`Wc7'Q)~ 7-SF.~58؂t5$'a*zfSO򵉈[MiJ^';Wc.qƔsf? 8=?kwU\eib.bc1s=kl!·1.{s_cqY`.Gѵ㫘(= \ć0iE|?+X"ECE1sү1q?U/c.FV5Jb.bWn\ĭ37\D{#'w&X}rE\X] y9kƺ{b.b6c.b/a.bwHiccX\4%E P]99PZ==ש(X [QYlh5J!'ٕ5 g,I=?ˊԭQfPVY'_,`=4l1ʋZr/ 6k:^>x$9ӹkżi'Peai%iK2D}TNx;}@u[(PVTY$M\߀bQߔ$+&N18?oXBY)J2U߀&\ZG-?6-Leؔ;hlILAb1xYӾ5@g w?1+q7C{>$,^Ρ=>] bSYqX̿/IvC~W$~mq My_CHh?W[Gj˅4n5zzRnvv!kiCtmY% X>w">8 և97ևm+[7C~?Oa.⶙ȳ[Pzs 0nW {1ܜ7>k.o}ys~_0%?5 [~pQb_b.և1o}Xt?`߇x 0f_ s0Ǝ|s~{`71q{ۈYW%vc.bw-K\Ĩ֙0q[c0Fek;}H!* V5IENDB`crystal-facet-uml-1.34.1/user_doc/doc/3_main_window_sketch_4.svg000066400000000000000000000065771415120503000245540ustar00rootroot00000000000000 image/svg+xml crystal-facet-uml-1.34.1/user_doc/doc/4_diagrams_and_elements_spec.xml000066400000000000000000002305751415120503000257730ustar00rootroot00000000000000
Diagrams and Elements Spec This program creates diagrams that strive for compatibility to UML 2.5 SysML 1.5 MOF 1.4.1 In some cases, it deviates from these standards for several reasons: Reduce complexity to be able to handle such models in a small open source project Reduce feature-set to improve understandability of diagrams even to non-software-architects Reduce feature-set to enhance usability of the program This section gives an overview on standards and implementation-status of crystal-facet-uml. It may be incomplete.
Classifiers Classifiers are the nodes in the model-graph. The table shows the classifier types introduced by different specifications, if they filter/hide their features and a comment stating how this is implemented in crystal-facet-uml. Spec Diagram Context and Filter Comment Block SysML * / - Limitations: Compartment Order is "properties, operations" instead of "constraints, operations, receptions, parts, (bound) references, values, properties, stereotype-tagged-values, behavior, namespace, structure" Limitations: No labeled compartments Limitations: no Multiplicities of Block-Instances. Constraint Block SysML Parametric / - Limitations: Only the rounded-rect symbol is supported. Node UML Deployment / - Subsystem/Boundary UML Use Case / unconditional features A subsystem is a component with stereotype subsystem Component UML * / - Part UML * / - Interface UML * / - Package UML, SysML * / - Class UML * / - Limitations: No active classes Object UML * / - Artifact UML * / - Comment UML, SysML * / unconditional features Requirement SysML * / - Actor UML, SysML Use Case, Sequence / unconditional features Use Case UML, SysML Use Case / - Limitations: No SysML extension points Interaction Diagram Reference (Interaction Use) UML Interaction Overview / unconditional features Hint: To easily find the referenced diagram, name the reference identical to the diagram. XMI-Export: For xmi export, this object may only occur in scenario/interaction diagrams. Activity/Action UML 2.5 (ch15.2) Activity / - Interruptable Region UML Activity / unconditional features XMI-Export: For xmi export, all regions belonging to the same set of activities need an outer, enclosing activity. Fork UML, SysML Activity / unconditional features XMI-Export: For xmi export, all activity-nodes belonging to the same set of activities need an outer, enclosing activity. Join UML, SysML Activity / unconditional features XMI-Export: For xmi export, all activity-nodes belonging to the same set of activities need an outer, enclosing activity. Accept Event UML, SysML Activity / unconditional features XMI-Export: For xmi export, all activity-nodes belonging to the same set of activities need an outer, enclosing activity. Accept Time Event UML, SysML Activity / unconditional features XMI-Export: For xmi export, all activity-nodes belonging to the same set of activities need an outer, enclosing activity. Send Signal UML, SysML Activity / unconditional features XMI-Export: For xmi export, all activity-nodes belonging to the same set of activities need an outer, enclosing activity. Decision/Choice UML 2.5 (ch14.2.4,15.3), SysML Activity, State / unconditional features In activity diagrams, this is called decision, in statesmachines it is called choice. XMI-Export/State-context: For xmi export, all states belonging to the same statemachine need an outer, enclosing state. XMI-Export/Activity-context: For xmi export, all activity-nodes belonging to the same set of activities need an outer, enclosing activity. Initial Node UML 2.5 (ch14.2.4), SysML Activity, State / unconditional features Limitations: There is no distinction in ActivityInitial and FlowInitial. Limitations: There is no separate entryPoint state-type. XMI-Export/State-context: For xmi export, all states belonging to the same statemachine need an outer, enclosing state. XMI-Export/Activity-context: For xmi export, all activity-nodes belonging to the same set of activities need an outer, enclosing activity. Final Node UML 2.5 (ch14.2.4), SysML Activity, State / unconditional features Limitations: There is no distinction in ActivityFinal and FlowFinal. Limitations: There is no separate exitPoint and terminate state-type. XMI-Export/State-context: For xmi export, all states belonging to the same statemachine need an outer, enclosing state. XMI-Export/Activity-context: For xmi export, all activity-nodes belonging to the same set of activities need an outer, enclosing activity. State UML 2.5 (ch14.2), SysML State, Timing / - Limitations: No symbol for hidden decompositions, no regions (swimlanes) in composite states. Limitations: entry/exit/do list. Limitations: entryPoint and exitPoint states cannot be drawn on parent state border line. XMI-Export: For xmi export, all states belonging to the same statemachine need an outer, enclosing state. Shallow History UML 2.5 (ch14.2.4), SysML State / unconditional features XMI-Export: For xmi export, all states belonging to the same statemachine need an outer, enclosing state. Deep History UML 2.5 (ch14.2.4), SysML State / unconditional features XMI-Export: For xmi export, all states belonging to the same statemachine need an outer, enclosing state. Value Type SysML - / - not supported. Limitations: Compartment Order of Classifiers is "properties, operations" instead of "operations, properties, stereotype-tagged-values" Enumeration UML, SysML - / - not supported.Note: Use a class instead. ActivityParameterNode SysML - / - not supported. MergeNode/Junction UML 2.5 (ch15.3), SysML Activity, State / unconditional features In activity diagrams, it is called merge, in state diagrams junction node. This is not supported. Note: You may directly connect the arrows to the target activity/state. ActivityPartition UML, SysML Activity / unconditional features not supported.Note: Use a parent activity instead. Legend Filter Defines which elements related to a classifier are not visible An InstanceSpecification (UML) denotes an instantiation of a classifier. crystal-facet-uml allows any classifier to appear in different diagrams as classifier, as anonymous InstanceSpecification or as named InstanceSpecification. (Rationale: If a classifier is an instance may depend on the context: An M1-class may be an instance if shown in an M2-meta-class diagram, an XML-parser-class may be an instance if shown in the context of stream processors.)
Features Features are elements attached to one classifier. The table shows the feature types introduced by different specifications, if they are visible in any diagram or just once, and a comment stating how this is implemented in crystal-facet-uml. Spec Scope Comment Property UML, SysML unconditional Limitations: no SysML Flow-Properties refinement. Operation UML, SysML unconditional Provided Interface UML, SysML unconditional Required Interface UML, SysML unconditional Port UML, SysML unconditional Limitations: no SysML-compartment Notation supported. Limitations: no SysML-nested-ports, SysML-proxy-port, SysML full-ports supported. Limitations: no flow property, no compartment notation, no port-compartments. Limitations: no UML behavior ports. Input Port/Pin UML, SysML unconditional Exists since version 1.27.0; cannot be used in version 1.26.1 and older. Output Port/Pin UML, SysML unconditional Exists since version 1.27.0; cannot be used in version 1.26.1 and older. State Entry UML, SysML unconditional Exists since version 1.27.0; cannot be used in version 1.26.1 and older. State Exit UML, SysML unconditional Exists since version 1.27.0; cannot be used in version 1.26.1 and older. Lifeline UML 2.5 (ch17.2), SysML interaction scenario, 1 per diagram Limitations: One lifeline is visible only in one diagram. Limitations: Lifelines start and end only at diagram border. Limitations: ExecutionSpecification (ActivityBar) are not supported. Legend Scope scope is unconditional if a feature belongs to a classifier unconditionally, scenario if only applicable in 1 interaction diagram
Relationships Relationships are the edges of the model-graph. The table shows the relationship types introduced by different specifications, a classification in which diagram type to use them preferably, and a comment stating how this is implemented in crystal-facet-uml. Spec Diagram Context Comment Dependency UML, SysML any Containment UML, SysML Deployment, Package, Internal Block, Composite Structure, Activity, State Deploy UML Deployment Manifest UML Deployment Communication Path UML, SysML Component, Composite Structure, Block, Internal Block Association UML, SysML Class, Use Case Note: SysML calls this ReferenceAssociation Limitations: no AssociationClass(SysML: ParticipantProperty) exists. Limitations: no AssociationEnd Classes exist, no multiplicities, no roles, no ownership (dot notation). Limitations: no ternary associations (only two ends supported). Limitations: no non-navigateable ends (crosses) suported yet - see todo.txt. Aggregation UML, SysML Class Note: SysML calls this SharedAssociation Composition UML, SysML Class Note: SysML calls this PartAssociation Generalization UML, SysML Class, Use Case(?) Limitations: no Generalization-Sets supported Realization UML Class Trace SysML Requirement Refine SysML Requirement Extend UML, SysML Use Case Limitations: no SysML-condition-notes can be attched to this relationship Include UML, SysML Use Case Control Flow/Transition UML, SysML Activity, State In activity diagrams, this is called control flow, in statesmachines it is called transition. Object Flow UML, SysML Activity Async. Call UML, SysML (?) for sequence, timing, communication and interaction overview diagrams Sync. Call UML, SysML (?) for sequence, timing, communication and interaction overview diagrams Return Call UML, SysML (?) for sequence, timing, communication and interaction overview diagrams Connector UML, SysML Internal Block not supported. Limitations: No Bi-directional ConnectorsNote: SysML calls this BindingConnector Note: Use a Communication Path instead. Item Flow SysML Block Definition not supported. Note: Use an Object Flow instead. Exception Flow UML 2.5 (ch15.5) Block Definition not yet supported, see todo.txt.
Diagrams Diagrams are views on the model-graph. They select classifiers and may filter their features and relationships. The table shows the diagram types introduced by different specifications, if they filter/hide their features and/or relationships and a comment stating how this is implemented in crystal-facet-uml. Spec Filter Comment List Diagram - any feature, any relationship This is an overview diagram showing only classifiers without features and without relationships Box Diagram - any feature, any relationship This is an overview diagram showing only classifiers without features and without relationships Block Definition Diagram SysML lifelines Internal Block Diagram SysML lifelines Parametric Diagram SysML lifelines Deployment Diagram UML lifelines Component Diagram UML lifelines Composite Structure Diagram UML lifelines Package Diagram UML, SysML lifelines Class Diagram UML lifelines Profile Diagram UML lifelines not supported Requirements Diagram SysML lifelines Use Case Diagram UML, SysML lifelines Interaction Overview Diagram UML unconditional relationships (non-scenario), unconditional feature Limitations: There is no link from Diagram-References to referenced Diagrams Containments cannot be shown in this diagram type Activity Diagram UML 2.5 (ch15.2), SysML lifelines Limitations: Swimlanes not supported State Machine Diagram UML, SysML lifelines Communication Diagram UML unconditional relationships (non-scenario), unconditional features Containments cannot be shown in this diagram type Sequence Diagram UML, SysML unconditional relationships (non-scenario), unconditional features Timing Diagram UML unconditional relationships (non-scenario), unconditional features Legend Filter Defines which elements are not visible in the diagram Scenario Interaction diagrams show only relationships associated with a lifeline of a visible classifier.
Maximum stringlengths All strings (names, descriptions, stereotypes) have a maximum length. Ascii characters require one, most other characters two bytes. Current sizes in bytes are: Classifiers: DATA_CLASSIFIER_MAX_NAME_LENGTH = 47, DATA_CLASSIFIER_MAX_STEREOTYPE_LENGTH = 47, DATA_CLASSIFIER_MAX_DESCRIPTION_LENGTH = 4095, Features: DATA_FEATURE_MAX_KEY_LENGTH = 47, (name) DATA_FEATURE_MAX_VALUE_LENGTH = 255, (type) DATA_FEATURE_MAX_DESCRIPTION_LENGTH = 1023, Relationships: DATA_RELATIONSHIP_MAX_NAME_LENGTH = 47, DATA_RELATIONSHIP_MAX_DESCRIPTION_LENGTH = 1023, Diagrams: DATA_DIAGRAM_MAX_NAME_LENGTH = 47, DATA_DIAGRAM_MAX_DESCRIPTION_LENGTH = 8191,
crystal-facet-uml-1.34.1/user_doc/doc/5_modeling_guidelines.xml000066400000000000000000000115711415120503000244540ustar00rootroot00000000000000
Modeling Guidelines This page lists remarks on creating a software architecture and design document in general and it lists hints on efficiently using the tool crystal-facet-uml.
crystal-facet-uml Hints
Tree Structure Diagrams are organized as a tree. Start the root of the tree explaining the document structure. At the second level of the tree, list the main areas to be shown, for example based on the arc42 template : In case you show several layers of abstraction, each building block may contain its sub-blocks, sub-blocks may again show sub-sub-blocks. In this case, structure the specification of the sub-blocks in the same way: apply the proposed folder structure recursively, omitting possibly empty or superfluous folders.
Focus Put only few elements into each diagram. This increases understandability of the main purpuse of the diagram. Put further aspects of a topic into a separate diagram. Do not hesitate to copy an element from one diagram to the next. This is what crystal-facet-uml is good at: it keeps the model in sync.
Namespaces Put a prefix to all your elements denoting its namespace. You can then distinguish a GLOBAL_START_STATE from an AUDIO_START_STATE. Or global::start from audio::start. To achieve a more compact layout of an element, one may insert space characters into names. (In case names get long, the space allows for a linebreak).
Attic/Storage room If you are not sure if you really want to delete elements, 1) copy them to an attic-diagram and then 2) delete them from the original diagram.
General Hints on Architecture Documentation
Problem vs. Solution Distinguish things that are given constraints (problem space), decisions, rejected alternatives and the selected solution
Names Names of things are crucial: If the reader gets a wrong understanding by the name of an element, a hundred correct sentences of describing text cannot set this straight again.
Description Every design element needs a description, maybe a list of responsibilities: What shall this element do, what is it for? Names alone cannot explain a system part.
Precise sentences Be precise: Write in active form, e.g. The persistence component shall store and retrieve binary data records identified by string-based keys.
Distinguish similar things Things that are similar but not the same shall be different entities when modelling. E.g. The process in which an example application runs may be different from the storage location and may be different from the software-component. These are three things: Example_App_Process (Type: Node), Example_App_ObjectFile (Type:Artifact) and Example_App_SWComponent (Type:Component).
crystal-facet-uml-1.34.1/user_doc/doc/5_modeling_hint_on_structure.png000066400000000000000000000415011415120503000260620ustar00rootroot00000000000000PNG  IHDR1 pHYs+tIME ;0iTXtCommentCreated with GIMPd.e IDATxy T33]+ʖe MRJ"h&FD[nPIv$-TR)]֙9Ǡ1fΜYsoc}3{|@yyy~&\x^…%.&سJ7$ φ'WDDWߚޱPvdttɻ&vig6nHp U'|fdsuET $><.h_<|_фY pcNDh]//L1kv-i|$~GȰ'T2Y!u/q}ᚌ(1딉e#6 Py^:pɆ+S-HׯwFZE^W2t-#7 ]tV%[7lÙ"eħ~Qq;w8ah' K pEE!o`>2H k.Nodmm*~Y 7ZI#r7*<+ZካGϼAIZ mϦ;XZ}1zk_(-#1t@Owc3쳣Ӧԅr3}\#)}=L -7 ţoڽOXXh22U&i  lg3 Q=?$md=A= 4xVUAP:v IXJtBTc^>KSx3]U+O guy닾i'!iQY}SmF)ˁJ\Zxmv׉LUZ霔 2va؈a"=$}s,j7"@ivSPPM(/4UlnlfÓSү]:cĄ$dgDY9iXM 4HVaʂEw %G @1.w6=~k~ i8yk-2u.@C ^WO% *.PD4*kk)ITB 3 'AEG.iWW* SwX۵4yF,=ŋՉ{m=Ԥ6))ABZ!@sii RD__HBvGk?<{8LŖ@9hbFǒ>$eeҪeL;u !#M"6@pB?(;v5~".;uƬjK[xL웯N(uYu#HÃduFXBiU#\qSڠDq`Kk;]KAHHXiokg;r|RXNEˍ,RR/q-!}o-!JNs)1mUiZAD7/:8x:IplDikD|Z0$)n=6$ Qh6*Чf #<嗰1Z1[p w+Qq'mGyccry uuu]~ۥ{a0 GxE6 #m%nsPtr]JZU? I~͛TUUYZth wb.澪ʌ6/GFX%Lǥf{0obӎAѸh&ɪMvYaE%<~jAYˆxV~'xƏ.tEH)n'Hӛ,(j2`Nid϶Jp[pN-<#T&Eߦ;zYɗ@r̕tP4JR&n}Rw| 2%C 5jSwSVܡS5*Z{Lz=/$i߾}ZZZ>>>666=nPW5.[wpHEDsVmI-U[p1v*6@$k"sdIǕA*&.*'Z4Lڍ !f(t(nNyi&r(!yg^ҥ!$${}9z2 j,d75n$xV7Sn,psfI&yVrt.Z|9ʱDHcee 6LGZ[ڨ" ~qnjEZy]t… vvv~~~˖-c{t.Q?HR@GêVV;\jz3%ewN{udiN&|K3s;mlL*a iqDd۶mObss .Q?$Cl9@MP#A~<’b5x/;kݵGj3{'QF?W}(_vl0w=W0 CS;/k^666N6<>>^^^M_k3HijlBXs@$MN뙕*sÃB``84 tD s9o1c?+Fƕ 7%,KʋDž-$m+S"kdl6 7%C~ÇIKK~ET6 z3z wwӥ%57?"T3 0)ᆸ0^/!)bw"8N.AfpC\%[RHs{N,Y;>E6T FA:0y|ӧ8[^0M57zzY8#5M0"3Շt~z7x_y6HcyiٟLllN.qݿL%|;4T!.)6vށDͫw'Х6M60ŞqE:v_t?3 q1_q'… K\x^_:}vKKK6oP˟_<Bۀ0|[McgOƚ}eKa  cΈuIq) $$m /{smCwlET0l){~\Z( :tb$X]<(P>P#B۴ϩn 9l9ccμng}(l)kF*a`C'H"m9՝xLWӗ,YcGH8|[ٛwFLMX)˪(T߼pT))VܞV5K:W+9uifBV4\(l=XӀH =>wU0V_EAՄ'$JIR@P*g$;-FÄzJNB6r|wj^DsCO?mj*ZM]C; ʃNy.@;zFE$v\dݻ{Ѕꦞ.J͡'Aj}[]tՂ@y /{䀘. G8 K\zcOHH0333f 8\h!+6cd ݴy}  ?W;4heЄ,)@yɖi4aW۝~U?XKwwwu^:BR+ܺlD32awͬ~'dIǮ L2!ohˆn'J(5210000txJeQB-:41,QbRg2~te3wީ-6.Tߦ 4ɂlb1y ; M &.045S=r2j#߳':+SVY$|$TtĞ$I /u!Mi{}zgl,_Uc~ٻ*8S|ʝ5ۖQQs\>p\c"Dn5MS*Iюu{T'z{ @rQnxG w+H<'nI(8xI^{RRRZ\ '_`!5iB<+~|[Lu?GT"6><JNoHyϮ=#bNԚW>>I:~@:m~倚݈=+Zm鷑HCv=C~/>* W^\ibС fnG`;6#~T"5):`^/9E 祣 Ѝ.t+4˺p^P< Ao0 ƲԳ[| JF;%}&kno&};'~-v!(@P33X ژv|'be)9 x({t8}$M,Lϩqv+qۈ"X u$"%)% X>3W9TǗx#3*:ea5;;OX^^|w.+g IDATGzCQ3{ #UUP@g ^A" #OKGqU|睑ɪp ~nȸrDwDY}Xva͗v|Og?eLϳ$@{{kd# p)e-jE~tW)J<{8A@x||||aFGxU"ΔEVtƲcL" Mllvˌ0oƵB:{F$uǂyOmf :BʿyKcut: zF\6Ŝșˆ:J;S/'eG0uQBBPdqxט"KYД%AAOOJV7*zIHظ^/衄_aJQ8E5Bv'Ael"'X(j(vaQo\{0=뫄j 9>.uj};XwQZtHK4AZ dfyS\ :XF\9J#M_ }XvOxpp+Q?+rv)k dš"%\}*cF n/P?($Aj rs@ m]Jݬ0JJӗÅcFjK'&x0/r#Bދնd89wK;2@ʃ~{Pgec$cfo&v<+GOD̝7KL-~[O Z ,m_D ɍP7﹨sA+ٍ\8J3E_}~"uxovatur%a {5+e-z厤~Ë_d//87Tx?kj@qz`hb1yM1Y%+2/A' 0mwV~&wu@O)cm ܐ>dgm@K}}'O}v ='gfnnn9eyh덫[l{Nx|z':YK,%aXu9_=/;>{Yʮ.6ff6ӽ¯lGkt3k{L2p^47WV|#e1 :IpE#ʕ+WR=ƜLq{]a[.-(,"h{ݚ]a! UˀO_|//;XZ^[_X#lb\̣B _g(0Vo{6m9ǒ[fPEOq{Kjqie]v읫Vx%i'I+'ju0JYTWgTn pb/K(-4ܱ^{,Ι)E ID؏ DӨ`,\δǁ,>Xl&Kj) ܿ8Pq.Kq}o[S`dd6Q<9^r/_OYk1s POUV%_S%O_Eyvp W3 ׄ*17}k9↊yxKMk#([8Y5NQ 4eQݼ?o"Uy'5P_Wzpqc([ mY9Uss~"⌇Hϝ BAFo:2neٳgʔ)˗/R7opBXXX#r6m˶|@ۂrWMl}V+T;vI?e:^[z) MoO3UHzʀPI?.pm+W&L X1cEҗI87N؟̏KY+ZxF/&;\}UEm2/M_chx=*<>Ub wC"ELe;"-a?$eT g>{<=zMa nˎ}f9w<Y9\Rƕ"}ZZZ>>>666qa IT)pMƁ#\"D"IJTw[^{4>8Chg6nHp U'|f `:طO]Ѫ?x$hxFP}6\W>J apW@YDDxYL,@ɻ&B3ŧܹQSmT"-A Hk39qMQZ¾9 locKHz4enx⌬l*}c )Y]9ub=YI>L7u1nCR(ዅevWWKtRLku@PDˋLdfc3w˒7,iK5T& TM^'$F~΂tZ6e%|;4雼_w QjI:t 1DExmM`FRBҿi)\pREM3"?}gruZ9 VwMnk `M % L:~ƚ}u\<>x%.: uoqW?K@].L7q_ # )@BTW=DqSҳa^؛b 4$$w;פ8˖_IP̾/\L8 :\vҞd!J;)}cQn㉂K}b9K5F> - )n=6d4@+ ;ӅtEigHy=\M?lvs/d_"u9 RNVLQ! u29h cłD QNP\VN'(8mulCHt&/پ4um4CK<ف }?>q/qC@ .Pm>`R[&"UowŭC]F Ǒǎ7iUg%=yUĹlJ\v)D?c;wNNߴwq7,8A㤇[.P7J:JX}~s ?=KVҕ2Qӕ'g(KvEh僛(%9dXu9Vtرc5]QwsOq42*'^)c/[2?%(Y>j66EVФlݰyRi%:J6;(KDsVm&:i΍ZRO.VM\2?ecNDh]//L1kv-i|$~GȰ'E1])R`yI+=*#!oVP9\d^9>Fe;KLFJ[ss3i-Ό/z'H쟓iUV&m[BQ,q;^M3^HP`l+s%9;ev)Kln!AE%șE-w8mlˎsU'ؑsie9+CR3ĉşgRۥ`Kv l|/THn %șEQ4;v]kaGϥ _5LO Ry9^4#57,a#$*A J@wHBQq,69N i)"\YS3p]M= :)/.XKhFDfV0|(9p0ی><y,A.m+[~*;k%.풮rn2=Z];^_z[,\]|/b6%{Vu">r01NlWD\dSѳW]K;,1 8S"xB6 %ݩ+v\:Os.YR/H=Ef8Pg7pO@36m5ϟIw></A>>4*_Jk%G qynMʪ.q8ǗlNreOr+'+Ӟ|`K !92KwsǑVxĜn:IԘ}Ǿlו4Օ<8%eݴ$<1 S% co[  Ѵ92\Y 7{ ::ύ︠/ dȤWN^y\yOfNW6ffٞ⧺rIdӒsuN_voF7#"l\L7 fQZq&3V7<7lՖt!Rc^oǜ8؟}L•7 9qI`2tþ)IlAF&qG}{oe8D,Hp ?M#q* 3^T-oS}mvit*l,x-ٺ쪙y…UVmܸښaUfѳwLPNm9l?^s`Q1?HzP?}"/sOޖ5QhT I3 tFh(V]j53*jgb sÌ9ƤMhY<> fZPO)2Yt\ Q=6 ^Tf!}uvְ' TF EvZ O/12N# C乘4D7Grv4XRNa"If.PKفodIrS6oH,i0G_>Ncw3r )1A̬(y^[OQ͜VW˞b YnCzc; {R\Sw,Q~-ҵp֜U2SDWN[ vixpQj/{&#ȸDž[y0o<"?ޓt2XQARI / n6aN߀?ѕ~EEIOۨ@3Wf2FA{d45!#R-tV֭>R/IH,\[ņjX-Xp")S@?ӕЫoUfm5?W&KWK ڗWzu -'Ow2LqL l)6n(3+)ɒj?|y>$q_1sw z)/Q{Dml9.zy%? &W-7+uJpk1ũP[-پf0Y͇G&6^v|?M0nfh71a2Cf%]=/ cJ DDP[-RK*zd8],wDm-:d#zykv(΋3{T #W?KABBB`Hj(h d$L}c«my놆F\۞kۖ3y0pa{E絻N$K:wtnoq\%D,MIDAT#SRIY<#WQ/ tD s9o1c?zhgφgffffff{xxIqp/~xxdϞ=-BKkjj޽;c www___f/%%%!!aɒ%gΜR𠖖(..puu}ܹsgΜ$%%|駎---.\:hKKKDDɓ'~555kkk={QZZ︗o]dɹs( @444x{{WWWj''Fmm{O9L{ڟL95~Js lK⢣s…Zso,lP5ؠEAT˯^ Xf v(??~BBg}<,,ӧ\]]}CCC/^R}ZAFFFN8qݻwӧO722jhhTWW/[ٳgfff.̒5HRUU9k`5ܭ!:hcee%qϦM&%7]]QIG >}~遉*hÇ@rJI|QQQYYƯjgg;7nܸq=o 077p8MMMs-,,ljjt;U~Q';ς63m755t mmmXAD;pP(Wr,u 1cLTO Q_ԊK= ;>r;ccc:;;xBPl6{ѢEp$'K漲ĉ|>_RC kG#'Id9TTThiim߾n۶رc555v0s^^^BBBpp^>N]]][z|/// 5kDDD#yee%t\%oA!>a?OR$Лᔗ:tmaۤqPAOBO555:::!" ѣGZZZ֭[x1,~zWWϟ?l\zѱjjjCCCwdSL9s{7 nI k׮qܦ&"(?1U~:)tppյ399ᔖZXXܹ6'EĈ{ z?~ĉ4#ǏcQ`L:RTi1֑xRRRnnngg X~=J#( 0mڴǏGf}7p<~sN%ۧ/Bڦ9sիUUUR񴵵oAnܸǝZZZ555(SX JkY1Ebbb?N6dVȾMKKqNN:u~;''M>}ƍ RݎDnGtP$&fddܻwfIL nJ*JA|PW%Lf>ҫ|Q UEB!TOTED<|0NZ Urt:}G$I/UEĪuBZtP* 8vS|Pb_UHUuDUE(`AhQQQmm-EU)*z*;;V1a/?yJ**v J'C!|PTU.UE::$TUF_c҂¡d||)SpEikk[WWv%K@/$("B>3r u*)) x8dʜ GAX,ܹse,\.WUQrP*:s *JAO^>|cRA(uP:zA'8*nGbBC]%uQقJK.]|$>>v#'N=rȘ"BpY5iOA"A[nE...T*x@N;881̀K*鶶vvvXhPp k.okkꫯ򆇇q0"I(,,xNNN\.;ёWVVB}P ԩS;v[",n޼ ^r{L&͉c8 XNH_,$my}=o޼^\\, .\|A?3E-**jii"##y<tPzAI]Ç!omT|PQϟ? GP&عx{84c͚5螑{*:89wJZ(Mw߽w{|=S7|PH˂flWdY4G-頲)OAŶǯ>}eA"{(dUpߺs{s;o)OAqxu>ꚛQݓ'O\\\V X!Gk*>G@<ë냮^999/o),(1 oGU욣c< :;;Ԭ_~ҥ׮]:u*͆'˂Ν;;v1c~r/X%?a`sv䃊BNOOrT',(1Ï;vG8˨9JAILhl&nAQU$HL%!#ƇD!jkkK%lذ”΄EK;\!5(bj9Ȏ@: L9,W L1T~j1!@&/gC s,3\P2|d/y CCChIqTEI /I;.Čdff:88X"..]r9555֮iagzL1tz Q/,]vB2#MMMgΜ xeeeLLofmm]PP&Ėot}{{ϟʼn:DIIӧ p"ʤ:.~,K8 Qрbhȣkww3%1#>XN̡LJJO[ZZ/\YDDDhjj-++pɴvB'qHX5ER$bˉ9)'$$paaaO>7oʤ:*ICj444vB'!` ]a912ִ% T \RR,6\.799Y.+d>:RiX(KWr,p(g̘"4}||f͚pc*‘=bhL&s``W 7%S ؄WPLb(NeA8gXe lEHN̹؝eł5ףh-ǂCm۶cǎUJ:>-ݻ*r8S^^nddt!d2{zz6mDQT>fhh8ZBBB444]vZDr, Ғ_~`Jcc㘘v%PfD+ ʂ P1TRq]v!<ظq#vM 届V @̍[l166EWĤO3M TWW.]tܹL7 g ph4/AĤwЌ &!AbIN`Po߾f,ذa!!!_~¢onM:bby:0innfEW\'x:84 )snM:b ;wٻw޽{###WZZmpss%,)C[07t:ZKܵ߿#55&((]N lBq-D)b!Љk?~bff6sL@뛕eee_YYV%C)Wm8FB(,RR!%P"Rk砐 T*uBn^zlg}&_;vxdȡ:x;"""IaftBGDKDtб,|P\#Z\\ 766}6W>s(qPR8d3 [P$H%/ry*IENDB`crystal-facet-uml-1.34.1/user_doc/doc/8_appendix.xml000066400000000000000000000113241415120503000222550ustar00rootroot00000000000000
Download and Install This appendix shows where to get further documentation and how to install the software.
Documentation User documentation is available here:
Debian/Ubuntu Linux You may install crystal-facet-uml by the following command: sudo apt install crystal-facet-uml If you instead manually download the .deb archive, you may e.g. invoke sudo dpkg --install <filename.deb> . Find the latest executable version of crystal-facet-uml at:
SuSE Linux To install, type on the command line: sudo zypper addrepo https://download.opensuse.org/repositories/devel:/tools/openSUSE_Leap_15.3 devel_tools_15.3 sudo zypper refresh sudo zypper install crystal-facet-uml If you instead manually download the .rpm archive, you may e.g. invoke sudo zypper install <filename.rpm> . Check for rpm packages at:
Windows/Wine Find the latest executable version of crystal-facet-uml at one of the following addresses: Unpack the zip archive. On windows, doubleclick on crystal-facet-uml.bat, or using the wine emulation, call cd bin && wine crystal-facet-uml.exe to start.
Build from Source Find the latest source version of crystal-facet-uml at one of the following addresses: Follow the instructions in /readme.markdown.
Further Links Static code analysis results are available here: Test coverage report is available here: Validate your XMI exports at:
License License of crystal-facet-uml is Apache-2.0. Copyright 2016-2021 Andreas Warnke; Email-contact: cfu-at-andreaswarnke-dot-de
crystal-facet-uml-1.34.1/user_doc/doc/crystal-facet-uml_documentation.xml000066400000000000000000000022421415120503000265020ustar00rootroot00000000000000
crystal-facet-uml documentation Andreas Warnke 2021-11-28
crystal-facet-uml-1.34.1/user_doc/doc/html.css000066400000000000000000000003121415120503000211450ustar00rootroot00000000000000body { background-color: rgb(255,255,255); font-family: Helvetica,Arial,sans-serif; } .navheader { background-color:rgb(216,255,240); } .navfooter { background-color:rgb(216,255,240); } crystal-facet-uml-1.34.1/user_doc/doc/manpage.xml000066400000000000000000000143051415120503000216300ustar00rootroot00000000000000 ]> &dhtitle; &dhpackage; &dhfirstname; &dhsurname; wrote this manpage for Unix and Linux systems.
&dhemail;
2018-2021 &dhusername; This manual page was written for Unix and Linux systems. Permission is granted to copy, distribute and/or modify this document under the terms of the Apache-2.0 License.
&dhucpackage; &dhsection; &dhpackage; creates a set of uml diagrams. &dhpackage; ensures consistency of relationships and uml element names between different diagrams. &dhpackage; exports diagrams in various vector and pixel-based image formats. &dhpackage; &dhpackage; databasefile &dhpackage; &dhpackage; DESCRIPTION OPTIONS Without options, the program starts in graphical mode. See crystal-facet-uml_documentation.pdf for graphical mode usage. Starts in graphical mode and opens the databasefile immediately. Tests the consistency of a databasefile. Tests the consistency of a databasefile and repairs found issues. Show summary of options. Show version Exports all diagrams of a databasefile in file_format to the export_directory. Valid formats are: docbook, json, pdf, png, ps, svg, txt, xhtml, xmi. DIAGNOSTICS The following diagnostics may be issued on syslog: EVT : ... An event occurred. ANOM: ... Something unexpected happened that was handled. WARN: ... Something unexpected happened that may cause a failure. ERR : ... Something unexpected happened that has caused a failure. journalctl -f allows one to read the syslog. BUGS The upstreams BTS can be found at .
crystal-facet-uml-1.34.1/user_doc/doc/screenshot_1.png000066400000000000000000004376171415120503000226200ustar00rootroot00000000000000PNG  IHDR`v3cB pHYs  tIME %:g}{}:{ @ @  l@ @ @ @ @:+T*0,($)#K@ iA "2L# ( 86&ՆN@ p.v~H&YGX, H$F/@ h AJ~Mvf^ @ HJkA07 KR`@ @ G}UP:qnāj}trss~VWWUQQ5r,sޖht7I/R kJJIȨ،1jVpzbL&3)99^|^~~yyyEE zzzlF}Y("]&J}rss+*PVPv?~8Q`A ȿ ŋ`c9(૪҂󅄄`CA y@&Sn߹MiikMLLXXԤ/0(CxŚ9cFZ.g(:];n$ݻwO<֭CyˇD3c+|hdh>yA(--̼s7V˖,[S[(:<ʐݷbbtbaaGii۷obc?L:5 7%]gld4ͭ{7G޶5PGGNȟh`m:}͌ob͵byn%%%%%%YYYщ\!HIK,511133#HuysssFFӧO?|pĉíK: wUqn\:~~}|~6P"_ AU>HGRضƍ32>x HHHȹs*++i魁b5:<<Օ/[zu׽\tF0) W]nݛׯD'p:Jm c|T޹}:B>~[yy˖e˖uZ >>cO2ht!SYFJJի+W<~쨓 9nشiӊ+y]W^]t큣mmk Np-[,))34w7v% LY[a-Tj ӧOߺy㷬ʞq+Vb˗/?q؄ s?ydŅ>b00` ST g4Ot͢h ~􇜜\m \~=2򔄄Dpv]]o-;G«1J-X3p5$^zzF"cÕ{t)3&k֭[v*..= /^bEn?h+X+MӦyՏ+5HP$a4}L&ŋן<Ў{ȑ#{Ԅ,+ٳ&...&F7)h֖W~T$++{aìUTUyRgYXX_ML p <}};vw<[WW=<v(\W&e Q6wm{ѣ+ 32}, Eg۽o$%tŋ6mzu\\\nݼaffoЛ7c~!ϟ}>ϗHMMM]uoXTTOr~y܎RD{dn9g<))/-_.++c``ӧ8</!!xJFF$Hmhh~sc_Pe;QnM7K"v(UZ]lE!Mr ϝd0ucőzEDDL6)MMӧO;VPPť?짞djZ&kxU?|0>>W;{GR(IDך5k\ $WRnns;>yyyo޼yǢƆFJC#00imm=xv]vS~Z)✹wWKOO744yf,N9ϯ41A"*aR>mlloN$ {)^ѣ-ZYE% ab"x###''ŋX2֭޷[xa;; *m y׶ؠAmTU}N)I@I&..qg֭[ۿi y~XNN%Kܾǁf..!""o߾74h4Zyyy7ݔw[7o1>]dYP.CQ}g 8p d:HLLOft:5֯_IImm8K#Ƿ:#,7*u'| H v!j5a30T haA0X5N_ݶ9W[@F\4P"/?|b---4fXp8Cx5 Cx΁`? gL;gJNRzy3A$xۃz,[JUF*reבl][ڽHM8t4 `D#t<ڥgϞy*dff666""Yq @]-򱢶ԙӻu܏:s={Bz#b]xw޲yKJ >>cmmm'OrwwTB܎g `aaŴjjiNˠqh߉d6UTTێ<el&/$K`V|?? ]C#@GJJ9`Ç، ߹Ag|"/2oߜ9nF> Ep8$J]}K33s_?#BRL&B<Af ` AQ` EEE簝`]MثljõTFHO'//{f짺chZҥK-Zuꔼq'&&6jԨh鵮=Y/tuu;.7.iB(( Dɦkce:jl\5 I~BM|||2u\J-IHHbr_ U~ RXSYá ɵE:l}*5DLLA?;qr999@ڱeo@o9{bn! -z6P򢰩kkb[w63B}j:mBBB|'Ɵ.{,)i-@" <ןM;M6uIII< <[iii3g***2031s&vNVlQy 6ܼySMMm׮]7ź'x ;侻{?~8㵕j XX~&Й4UidW< v/>d)/Rܖxƍ}O"\43>l>W,_.,,xgN=(**2pF6~{{{HO&uZA "E #8412V\p^YS}?IL2:̀T[[;a71^Ѧz$ok+j^+6 A7?_DDxV*$VW`'Oܻ-!!!=k޽&J T\Md@ %MMM***__n6푬ח,^8""(ki0> tq4lpo~𮸸8..ӧOC]pMZ̊KJxq&b-:( $!6ĄX" y,77]Oo Z9Ғ{>>Ga3Zѻq0~z)#x<^><1sfMM}H$rs332o(*҇.vK{[\\便Fha0BD^ؒtxѣ{6b%gN6P=1e}{zbC}U_2Eq;ϑq8@2yvl4(cFW0hN+$q1')/D`ϟ?3fLKK6)9r锔LOOWVGhHQQQZOz wrLHHHHHʲ"k0<~E[=? y%sd8kp\vrl%`A?LVBE;R\˩8K[fjKFG%ԩ3?KO bz457+*vA7a,^`ZBƎ"ςUUU ۷3gN8ۻpݺu޽4dD}ыI i-߾hii;v,''CW(U"H" ,Xyyy-d2Q i9‚Ar $|VTTf}TVVvߕ~mY@4߃4,>vyI/H$H~OOx ;;{BBĦb 8#!VI "EEn< ߿KJJfk9Ȉ8PV$I "l|SNWuV T1 oow![ _|PA6$oL IDAT4c 1i^}\ GD% {2u%XRRRll GΝ;ٳ~LLL,3#]} A~jյk׈D"SR+//SYYPYYDP(?JK;^@ \x\AZ4sN@$+!$H30gCr"EQѯCLUǶD^b -ƥX2sν}6YmQ 0+]]c#DbCCݻ.]ӧa9"~RĄ^~ˏ?~!CCC%EޕAu<.%%Eofkȣ^ bB3Ąn%%H$lۼe˗/ C wkߥٵsgݻ>_inj*..QSU32ϳ(e $q ̬BA=#mm^L;u4"Ee0@g2 Й{$Ra̒юfϝK|ճWMMȼJ|nje)2\f5쓗:fVneevڗ/_` ǺLX;Dؒx꿁TY$~`uuWh4UPNNСZH5m:Qcy}4*ZKtDp q哊=07mҖ=x{ĉc: kρXlt!P^~*`YYY ***킨sޕ6Y EZqK-i>aömۖ9k֬޼Pwuyn!`THzޠ$æomuu3f*V#݋SBB^{?L&ŴfP8DCCCihh---\R ) `!p3mX0h`Dr4aoE![C(bƪԋ{Eo%K[ +qZAYxKKKO?,pqafVV tbh333{iuu5gܾw1U$ 붬LdHyF)D޽{ghCA 6N,R12 -GvskΠmWPyu `r7ONL9<?卍,s } z)7n?R^E8`mm{475t;; 6̟?1==6f]`qw*|8|>򥍍ڵk###333~ݱG^^u]]ݖo@Ht&Iq?d.^pϟ??iҤr`"[1 ,ܹk+\MU,@Ά)b!H1i@M< _\Y ft`(`x̋ݘHL2"?_ӓo>O=:]A"r~p3Kta`%*}F=FK^pB <,{/jI)2 0eʔ߽{f.:+qS  Hp!555ÇξsBN滵Wv5H0X+ý?~@T02|ʵ6bf3x?,l[rrr'>NE9}zE>>3f̼yO.[rĈtc(8vwR+jjj7g&D]]*"jYlr>$W2 jf|+3şgP{y Jh+<ȓ)Uƻ 6t1L8 qP t,rBA*ˤeu] *,/m $:|B+rPGFNy8Й#˩333/&''% ;%h999< 6DC=##CMM͛{֭e˖͟?ܹE6ozc}iP} 3gΜ>}ZAAam+)\OWݻwGxJKOMwDY/5lJMMY0-))oiAh7&Y[>{bIikjjf/Yl@UC2fT~mo־c}Õ>hss9sjkkG~M2etz+""i:.+K|f sTO8A2y qGWss3Nt Ɍ61|GA+1#t( ǁ ;0Kh9$)x9*`qQ$Y<?rVň㴵99 eeeNNNm}||?.''SUU}xXN֏Ka5Tʶ-Ie1Qf^^!4 .q"' "Gs󎠧?g-t =zrti}2E 񢣷b}e][Hv|\.re4a„r< ߿~cQW^}GiDDD[?~<ږw}v;o-䄄ccc}}o'߶J0$$DMMĤ6>>siΝ;x׳':߹sSF [W2XYZV?}{=|'L{n+h[/\ñXǏ1}+pL דٵ?,5ý]G>`P?>zn*OxR>17-4LJe;X;\(Mpp@WFw퐘d,a457s7<oaa߽{won&'>{O"% Fdl@ga?1e{6ߤ52L&꺻#R(|y:U ګ8PQQ)$,qEQF1/n}…#x{޻w/8h{?\ѣǦ&Y ,+뚨)D1M!rA5p|WTT()+!NVBJJ}Q>stYYyL_>?tТ rssC-*LtuuLLLtut111&]. *2ٞW`k*"ʠcBOҊ%zMꪥuvLVUU쾘 Dp8/pᠨ5: PTƶ.X+fff7Îz4%ti79Bj08 ;y1@"[C_r%pͮdk  !$ . POFɠ*% FZgCCh//.MݰQpEJe: \_W/u333kk됐]vuUʕ+w޵>t/ĉbbb KLMCBBv_zY TU^:88wp+b[ ,^33Ç޽;88<|lyw=%jڻuǴiӺr9{0qľ7nH+$$D\'M:ٳvܵmVA_@RBcc)/~?TXXxmRDg"2[&=wfzL(iEEEXlEeNGLGs>1&&:|x sM?}'%%yFEʱ'JJJjkMϧgI/gQFEeM&H$RRRyjhhhS(n>JJJjjj:vэ`ٔ2@'Q?rF %.`0''}뫥 |6Ꮑd``޺VWWy& M XNL\L\\\JBrň]+-,,q0ےnllߠknnԏJNwoײ߻wO]Cѭ. 6_eckhhؕիW/^m۶Yfu_˗/w#n s,,,z͛NEk׌ҩC`YPY^)R:ȓ'"]ͻj1331+kN9}mڸa~>\d1wN\| gϞ}3g ΥK{αaؑiL ?#wJqк̵'W FLL`v4q8\e:߽}P(-:{܎rws]~}Uvv;vˮ5}I}Ѣcǎ=yɔ+6k  QP@巧 .^^^cƌ‚GG}ur|.k %Juq[B#z͹YF̯.ґ~\Ul'"rJ땔@c [^n]222.....l~IOtIZZٳ;*DcӮ=z$--njbl^vue&l6[CCםRXXu:j9痐`bbs=!;T"H~!CL:YEY9|YauL AJr]ZqƱcǒ+Չݕi1ŦLr*ꔶV?@*u`yyǏ4mmxP/eeϓ7mW_ vlH^<֘/++g0B,[YU'RttyyyVVև ?2L RYY3c={[X/YX\\xih{`֝ygZHšC,Xxɲ=GEW;tX*0:G6=+%`=dرGBEAN7~YqLu iS:tyŗ{_~nnm1k׮h Zׯ_Oz?)Y##Ǐ9rӳk׮yxxܾ}{ر$toPv{;;> 3T{Ǐ?yO#11{%# p;)0#(@ٵk׉'bno~ ##'NLtZ enZlA۷9?n8fG&4hœQ$hjn;1qx|>Hxv{: LnBkDAr.]_SS7kş$$${ uěvcǎ3gFDDhkk :`(|򈈈v_]D|%2rR Lb&._qO9·CYoĮ4  $'Ors.7os;F@@U_'..NV nF_BQ|7mRUUƝ=gǏ{gwzzz```-d2Ϟ=N?`nGF~+Vnٲ ߻g9OzlihPY[è7_8,6JR_~]jUii䤾8nܸػwNJKKۼys0XΖ]qs B( "` _Gecc3իײ{AUWWlLJJ zXwwv8իWl٢>ߺׇDZ;u{ݶ}y[s IDATn VNI[-CS԰S֭['%%u' xcXp7ӧO/\`ݺ딚 ϟ?ߺuk۸y0*nmڴISsHxX?lX &z#r coߓG =Z5;qqM\*c#edfjNҲ] =R#l7o޼{vK ?|Jeϟ%n&QdF -&R tWoQ8BIcاd c;-/'fl2Cş,oq칵 ҂Hׇ0O b>|GD}}}ss3GGG,Sv$,,LP6lX?{"޶}wƍ377oҺ*##ɓ'ׯ_WVV -oH\ >~"' V$.g.QثQUZaUs$ێG=+o{Ѻr ?:.((c.%%%wMNN~$&& HSS A_fԤIz/ݫYRrҋOUU$0mllVWS9Vq/I`x60̤{y+((9;O5j@^Eߏ?77D"a؆-- NN':oMh @k_|]%`{9C{%LNy*߃Ǩw3P؝EL6oUM9 ? Q30u˔) cN@؏(F҇ @ zC0sقDa/@ h AIY&ٗ+~LSA @0DQ,ZI(l6N DH"p@ 'pd 75UWQi3 `, @ @@ @ N.v@  $@ @ t .ClKdd$l 2J9_v »@ 7,Y'@@ 2p+I`AK#g$@ @ @ @ @@ @ 4@ Tjw4 d֬Y}*((|捴4ihhpqqTSS@`0~򥾾AJJ ߿GP^^bddχJx BR%%% ܥP(&** [ @ 4 ~8OUTT@ 477ԴTVV 0 UU՚iiiWEEE(6ӛljADDwctJ@:IOOc# EQO_~ZZZ s8 өV233I$#bbb`;@ q 6 A?.'!K ޮ3f N@ 20 v@ (@ @~W @  OF-'+=¼me RP>m8zKLd2O;)N03ݰzwK9\A@ @  FO=ww }=u7G;{}}e+=y%x)ݟ"ɛ9IRdԙii;"VTT.]EQW @ ȟjkhkkkjncg s`% }5u ? I{)("J'\ XeV G}Z**B|yԂE}ssι{2/stu^ys =d55&: ?H$:}v71Aھrrv}jcccggWSS#~ >Śqpp5kw}wu,"`III[^#ǯ#MG_~8?nONד'-=d ]Feݻ} QԌK)鲲l6{ueXXFxUUUnڴiرcA?СC5 4to=<@_!T[[CV:DbQq."''_SS$gg猌 !?&M4yѢE񡡡 \. O< /P>& 5fP(liiųDbsKKY]I&'N8>!<|E4o+1cFYYӧOYYYT*l:>a„חY[l/bŊl2<<|ʔ)ƍ>}zHH~m888ɉNWzxx٥q8PLL̔)Srrr,YBcbbzm,:>wׯ P[_?DO!D$Z[Z,6# UTTzM!G[o)\QQajj;vZ ε 2<==}ȑt2,^k֬ٳgO{{{BBӧ{=M6qPuu?!|}}"""fsrr B,+222883̰0GGদh@`jj /OQSSS^^'JYY<}|҄ 6MC՛q** MC.)*(l? \2uyREEEgf̘qȑWWWu8mmCIII!ƌvĉОϜ?}t˖-&,7 r|| BhرIIIQQQ}Y,Ωb<110**H$" aÆ)))AW P r˾_^Q1ktø7n.=y떭lYztxǜϊN={ǎ^\.x\.ju#!**E%%Q1 of3E4k֬Yfb%%%:^TT4c VP&VZZڗILLLNNh|>?%%ܹsxI@ߖB{J ArD"AYYً/F [[[}}ccT* S^ÉSgD=MRf@̡XoC olocsVm]7saey-Fez^UEqaḄ66h~}B3g  ӧORPP % "szFm޼!TZZz…hjj?H$zxx̝;۷)Jw-r"BXҢ 4Xo466UTTx<' 08-ZsabcǍ΅C !ĉ544$(yVVիjUUUnnnXmm7o ,˗ZZZ 6l?sii ڵk?x9''gѢE}58`aawTQQ+]]]xM !mt~bƌг (JdddwV ;wn{{#GTŋɓ''&&zyyGEEHPYY1uT"B֭;wfss365kkƃ޼y-{ܱcp^=\܊+V^$?0o޼Ç# _|I"\\\oݺER,XP^^M@"~w*/cEEE///waa!@5jTzz:3\A\A#_,E(O[޹@ =A$W$>=X\GGQDq #|XWjjO͛>y3uK7&&fʔ) vvvrl6a۶mc?4B[w.Z  h4Pի~鯿:{l; :}a{ 3g޺uΝ;YYYg̙蕴t'&tyUHֆض֭[/{{^wtwwJ>l>訤t%)==]KKz:sy| ǃrzJJJ!>=ܲex+V૸0H,++ÃNϝ;Y{a#.]JRRR gffb̛7ƍCz%q.}||t ֯__VV&[\\aggg:~ر.+퓒$d{Īӧc7K^qqqppN mll gϞ_{.1%%%|Z,w0ǹ^LLz`²߅5NLܑj$@!///|[GG`&&&&FEEa#z .]]a.yf333… /^x,@JHH011J/XC\ⴵ:M6f77'N"u+|x-g6}Xt3mjiO>S&#V.Krs|uu5y'~/B+)++#-ݾk7 n>_B[7*`fY c OܹsH$=sL``#G?}"K,w{^^D|.AN^^$O uwuT(3~[* -7 E hkkSPPEEE "5Ww444'644sO'GTMMMwٳgݺuaaawaNfggw˗_vm񊊊]VH$=<<Νe=ʹϟ?fffjjj1cp100hllx<O(b @۰.wϊ757z Ṷ{~3m*-1bDؚ`iHgӈ1{ŲJEE{]UUH/_`aaTTTz}ϓ@ ߸qO)))yuk8B177ϫ*??}BXYY]rfwW n<̙3+++>4cƌ.P(/+߿H666ϟ?y󦅅|u䘙My`MMML&|9z}U+֝;vvg`̘/(RU]SU] @?y!7mjjAݻ UUUccX!Cٳ'>>>%%EWWf׮]G~HHHX~^PPЉ'zbùg0$:(( ?㣣\Y:W2zM6ٳL&w.#--r…S0o'OLLLd0,KEEeȑ#@LNN!Mmw-K"EJJꧤD >XbMP.v|&]gt>󥩫sss_h.]]]kB7oZZZv>sذa}o^ffe'744_bl6'NN>, yyySN˟MhhhKH H$ׅB!DߩTj]]׎;TjSSwaa!@5jTzz:B֭[Xւ ;::o&sqq)//#HxbwI###\}Cx<2%%%yNP((D"@D!ǃ x<H*!vO݁Mu<zOBQVUW+H>>>۷o0aBԽ{K.0{Νu! ?XLLLFFƵkԒ?~mxy[.:2QDVwQMw< HwmP_[pLGY)|x܎We 5ā (ΨTjFFxJzz 5C« !:FH46Hdmm_RRҹxbI& ^sww?y$z BtgBq]]]ڵkƍ[lYir3f(++{"YYYT*QXqqqppNϗݰa3Nwww?vxnYY٪URRR3gٳgݻb111SL_t)N7))I52<<|ʔ)ƍ>}zHH͆bG""##-,,6ng 2<==}ȑt;|}}"""]>}|r==͛b|_awwwOO7nDEEt,zuqq&>vϓ}Y,־}BBB ]&i&.^WWx}e<  q@k?{ԩS}}}%\]][[[ݻ3f\d2!D$ &//oԩx 2n8l@ WUU_///:tRЫW}T*a}q=4D"9r$%%B`6PWD"Ѷmێ?;lذtzzzzQQь3$r[[[|~JJʹsD@MbBFwGBp%`0ϟ =zlss_GG^Xb2=111QQQ4^j|Rkkٳ+++=]3g ӧwxxx̝;GJJږ` b ?@6oތ*--p455]\\ 7 CBCCccc{B'N\`DByr\ÉD"dee} Æ [~=Bv|D  5̈ܰaC֭xbNNNff&`0XڵkY,ҥK痢ٳ׶{{_~f_pҥKv5'555;;;''g׮]|>^jc׮]fffӦM{Aϻkjhh>y򤽽@Oqx>O<`0X,ȑ#w\.W[[{֬Y}6""b޽r߾}'`hhxjdddW_K C~'ŋx&00ѣGG166nhhwzϻ$%%ݸqѣGD"QUU_^^Й|& .]]]7o޴TQQdZZ{}ׯ_wttvttPԞGꨆG999W#^ o1@XjcY|>_AA!++ [}:| ˗CǑ}'ŋVVVǏd2mmmǎ[\\mPT-~3|o BPXTTe$ wuZGGC 2dʕGA:u|ҤI؊޺ukQQQGGGjj*}͙3'66!rUUUsrrCCC/^X^^yfooo숶k֬9qDNN'O~ܹww(999x]'`cƌsNKK]eeP(x<߀NB,Ydׯǖsy .1L"BBB,Y vZe˖9sdee PNNNGGGzz:V۝;w(N|||IIIhhoQQ~еkzyyݹs޾}&px {jsuurL&6lؽ{wqqիW[> ֲe |K.Ŷ;VQQm۶ŋ>~ʕ%%%B+`ggӞ$iӦ]z>++d2&&&׮]!N>}ݺIddd"H4vX!kkkg@<==8ٳ˗w9lذb 榦[EEg h,իwﮨ BjjjXJz >>sذax5|ƍ7n8))~iʕG B+Bm6l(//7771cƥK̙SUU:,}ժUÇ7o^wU)))D^'zΝ پ}DcbK+\.BqwwoX]]]-ZtܹSyϗ@ K"VvhyyK.iiiijj/Ͽ~IIѣGtuu߿d,7!!A^^_ cȐ!_F»w?!֮]^wΜ9s/^4iBh6loo#L&~߾}X]xqٲe0BH]]ڵk˖-ۻw}W\\rMMM*..NHHp8ZZZ|Ͳe BFedddddܹ366mƍúQF455566&%%=zACC믿V-JvnTVVV:tdbK?رR+22EEE4m ,wʊ]jU=|={NJJ |z=ii 6?@( @IH 7:;;Yl6UpXLQQQDD\ZZrrȑ#BO>]|^HHF{Mqq1BhҥK)))XXm,+22288ĄJ\JJJ^^PWWEYYرcϟ? i&.^WWv9Xeeeڷo_HHkע t:RXXcpppSSStt@ 055+''۷/_qqqba[x… drbb"~amɓ'ceB!KaRR#?3rI<ٹdeWv*1b޽{KKKy~H$:::aߞ<==;_莔uYP~@ L2LgϞ|rUU>W̫W𠥇6{2H$#Gl[[%z,*EG==*H$z%K/IgSٳdGśgw/ }8Hm۶ǏvonnM|>?%%ܹsx"6 Bb ByzPΝ;deeuuuզ G-++ї6bbbh4gbK% ,liir' ON_pae\ ֝?>rbG|^礲RIIIVVAUUKD***l6BRTP(\@DЁ@ԋյΞ=ѣ{]yxx̝;\))~Դs`Faa4Fm޼!TZZz…hjjױ)JKKxbKK?Á{_!njq޴3;i$;;˗/*++߹sgƌϟokkkmm566.))~֮%eee ~~~ЍtMZZL&s8**ttt޼yC$D""HUSS͛7Ё|9GPyyB ::: ˵rgvcP[D"#fdee5uذaׯP(r, @@իWKJJJCC ޱqz__;w>}t&&&~-źwͮuVuuoVV6ݿ*@ kA"FQUU%++{%EII [nCH$Rxx7|Cl[oܹO>EY!vZ??Kzyyijj"\3gFMPLLLzms=𰷷_Əyҥ^h|DDԩS Dbff&ϷcVXzy544l߾]ZZ]ecc>|6]VSS###3dȐ$|~uuSN9::VVVBHIIYYY5Ǫ|MZ#~K-Nj"MG LMME"bkk+<7y f^*3|'O&&&2 - 255MNNrڳf²ݏ=Ңk{"""+,--ݜMMMM544<{luu5D222_JK<صkW||#G455{ 󥧧7m42M >c| ,j2../񼽽e˖}骪?ݰoQOdZU>+Vt{MKKK^KA߷gc:ѣGNNNȫW~>YjճgɌUUU[l}ӧrXG%>yٷI /> -iii9p>~3@ꗋQ$|06+2v)|Ҹ2K#*ʊ >uYƿ0޽{'NxE[[ȑ#̙y.]t)99JﹹO0mgϞd++ ###жm۰PBؽgΜAOѢ/^|QKKKٳgzҤG544hhh|N111;w-..vss۸q#B8...//嚚uH$/;֌(#9H$d[;;QFN2e F(y5kٳ=!!֭:t(K. H$Bnn. JKKs1L"4...ǎ{yRRlbbrBEEEFFFrrriii#G I{ j qGqPHHHCCCLLLLL F9s&>s\\CBcƌqss;qDhhBHCCCGG+///O$d._\(yxxlYYY&iff&++rpppppv1bĢEJJJD.jkk`0eddBcǎLJJ]mmmkk+J(˗===YYYk˖y}$q.3g IDATRRRrrr\.t깫2+LW@.ʒ$E:~꿗=/>¥K)ΜHnEK}}{8OTgG n - XUgx(@̃'xh4ڑ#G>|xƍK.,[.^BZZZVVVyyy}oÇ\nYYYkk%K t:ɜ={6V={UUUl6K| IIIY[[x<&9|,:BDGGǴ4x  Օ_zE B|KK DRRRjllR|>bX,eD" --nooGihh?\JJ 6eee>_SSfd2BiiirXI>/\.Lp8I$BgdjjJpWC%eammnice%%,k?㰬 u]`@@BZD]]cÿ5f4>3H$K[F":Bz1)1nÇG577ǻ|P]&© \.Çϟ?711QUUd2ZZZ *qѣG677utJJJ⿎s@(k`0lذڇ >bl#%%U__OP^zennc,K$t9PTZl?T__ʹTWW`jj3X[[5OgϰRRR&&&EEEC-))?|X8p/^<5zBHUEeUT\""F .%%5z;w6p5HRSS::k i?a&%%3fzԔH$K|*L_+++> gkkI&njX`}aaabc<<<Ν /PmmmGG@xH$RRR PH ttt^~gX,P___{bK#޼y}5DKb`b1,..P(jjjLH( EWob?]L@Kwϒ\.7hҍpy\׬^OYb<W >ݵ{{J {Ʀfѣ7 Ҕ8Ыob8}6_gײMufiiC45Euw,PGcF^.NϜym?u^}Cc;k4-6errYYA=)|rrFwG3 wm#H#F )2w1fx/*s*B177Zz5&wssX +++x fAwrrrT*!$8WVVV'EPlllN,*f8~kOѤ@,+qhm@=]J&Ma>="1.($$ ݺs}xݾ{oiQ.^ZΤw!|*xw?1;;?p8xB۷'Mtz@]]}cHP!|H}>v`G3PS#Iz0 3OewY>>>NqFzz͛ &`ګV yfFFիTŋ;=s̓'OD[['Op8ʕ{{_~f_p@g֭xbNNNff&`00H`X0"cEbx;{.0@fSȺ͛6>+]?ν{]kimtJ eeeMo[w+||fNj<̈JvW#a M-w̖8X;[>BPsKKƲ溻0PW_௪yFDY[ ,Gξ? ?J]]iS>y]snY>.@OzTMMM/_͛Ν%Wr FbbbDDD (NNNGmii@/dffMSM}-<@BEDDݻW XZZ۷׷3>|ɓ' 6{ȑ0`sP__ڊmST ܌md]]AS\8/.nm7^~#|W9g2׋X_ `x%뜎 Wm.>@}cXx|~fcwZU5C>mjkܺ7Ӧ\Cw%D">׶@ x^T4āBٹŋ͛XmgϗzЪFEE۷;a,Y UCћ22> (RL&t%{cWExKHăf 3' ZͦP(ͮnoo1_mddH~s7w&MjfV}Cy?&$jiҾ=D(\'B鲤 )Q6hG4l:L&Op:ЏFYF;z(sngOH&kUGyHmSd-M6BHMM-ߜg>().EbX^Y]ca߳gGG]=C!am%ПR8y򤃃<_&52ꬬa%D"ӿp8;Àx$5BOgR|!O4-\OIN#6}[*F]Mu]HJnXp|†@06fodBLt  ǧZK0;xL&ww7o+8lN\0OjEqGX} س-kWسo uӦJIz>~?#PUu L0r۷O0snjj޽{ߵDruu?A(77ɓ'K.wOPbbb+PXXx2lhh0w\| W@HKKC?| ֦&"/uttD"QEEJ{{P({ T*]:::|>6Rgش***}?'''kWJ.^@رĸaa%C֮<āBCH_~{_`ѝO%%72%l*BixGl[MM-fO"|&޼60<=,?xm\%Eys>3``$f$#Ν;͛}vlQm4;^^^@H]fq\Xby<^yy7odreeѣB؏EEEx.J}WH$kkkcXoH CԳ7g͘Opt VWWvڸq-[VZZ]1`nnf[ZM{R\\D}||geeyxxsfee[ڲe fŊ!!!vRRK111SLYd NGphlϟt777n Ο??{TWW.]Ֆe߿?99bL>!TYY>eʔqM>=$$fw3gٳgݻb堝=<'NP(<==>>>t:}„ ׯ/++hӧ Gq.(bji7,/_"^zU]]-[MMMkkkcc#UŋMMMohhE־x񢢢V$FMM ϯr;ﰦ$HZW (Um.XFqn T[! "CHIަ!yxx=='95^ ﮹A$cӧϟ? QcccAAH$jjjOѣG lll|%Hlooϟ?lmm(C^^JtÇ>Y,~kk+,F&\.N%ri4vNŃ-)uЈ^[3I$RddQ֬Y$X}}2|W^^khhnjj (**Znݔ)SBCC[ZZa֛p"##WZ5b>k~z ?~|ݺu {`^[p8ѡ111Ǐ_tP(|pT\rrrAQQ`D"/^K±,qGa2Jupp A\\1o=#!K>gb1LAT.~gӊW޹gVVVppڵkL".xyy͙3UTT4w\|;HtttΆ϶.Y™ 2Y[[3e2P(qc555555|4445* ^CCTQI$҈#RRR:::lmmşg/644Kuu5 )ۅ ⏫QFZiUO8?_tzIIֶ*..5;;ְV !>\.L&s\uuuP(//.h4&ӆD")))Y%%%]͠hI@tJ4+nO7kt7TWWxB @M HKK r8::~:3/Q>RKSRK]LkkQH;B >ny}e~H ðM6߿?>>o[jkk>|ѣӦMkkkǏK Bܜf|="5 @ BQQQgd\ח$H$XW*111 [|N\\ɓ'---Y,:s+4MQQ^\KMM\xɓp-8n4(5Ϝ9# ad2Y« W >Ikq{BkkWp{S^KK@WWWWW`:ǿy+W;ܬbhhh``aXwk]|>ҎO E` R[[ٳSSS0&&&Ћ_|;ydwLP0 Ev{{}2OO])o5 uÆ ӧO޽[KKY؅ <==d@l#666njkkD1cwgD W)M|ǂIA2ħ FozBFs7޽#Z!@  LR+VXvmvvyllln߾bŊ~ ¨Q~7???{qMMСCa_|MRUU7"7WOSk 'kW\yĉJ  0'G8jҷ;>>>׮]۾}֭[~ M)((HblB``+Μ9v丸8fjj/Tپ}{bbիVZu CFDD$&&fff0}XFoimɮl6[SSرcYYY/_$H111cǎ^1<<<**W(3&::׷s` ȑ#ǏonnP(C9sb%''H$kkk&uP& IDAT>}0mmSiY@ M!}# P(xWErrtq1cƨZ2;;mu677߿o_߿*++d@|2<~z# }&7G133KHHVE > %@ HAB @  8p9%_:@ |MTTQjkk,Y(uM6/\|KޝHCw|>jjjjjjbX, @]B6m"HAzOx{{޽;))I$u=vؒ%K*++͛e˖`vՁ 6 )Hlnnkmm:;;l6jkkp8B ݻw1 BS@|L ;wժU#FPTT!%Ѽ!B}4(777<<|QQQÇ 6l/?b 99L&[YY1LCCC{…={3 OOOOOO[__wޢ6zh˖- G ƅ `;[npqqYfMeeeZZ555'LH`iiif.bܹ{wR{hQwRvv6w1h zzz[nuwwد\Q(DSS_M1@$D5jTPPК5kVVV=պymll"""\nRR#G':::44 777&&F__kA~ƍ]]]K. Ν̄RDFFW/ЂT__쬪Z[[o߾4r$ ._&@  ut;v+**1 zu`իWÃŋݼy)HĀV fffd2ٳgPhooёQ>!!a{&ѣGddd|>Æ fff//g?^ <~xƍP4H$J 5[[[<[YY9r޼yO<122.gOb(++Kt'C0@ |>ŋ򺺺# %%%EEExQgg'G?_~ɓ4]@W׮];eʔ>~ 𴵵2T*%==D1bDJJJGG-'䬭SAVVŋj RObHP0@ #<oŊcǎ%zPĒ?8o߾ m۶f͚{ωo@p8;;;WWWcccw5a6mڿ||<h4%%jD" D JTbܤccccbb wO}H<6N<liib:;;V!FwH0ӣ0Js\@o\.0---|_f% |ƧJAAA{߀(**jjjR5D[[ٳSSSųlmmoܸfnCD"I{n---gg>}OOO///xZRR&? @|qdr{{;UWW 򝝝#>MBBB"h߾}/ڵf'%% yZv- Z ѣ Eܥ8@;uĉΝ;׿F$]3nܸOx<4\:{G 7n$_G-YÇC Oiii?^a"% ~ΝkffvÇh4ss(....999<O"ĉՖrrr׮]|7^`2hOAKS rfl߾h~Aj-"~h.!UQQ~K2Đ]O!Nxbffĉªnܸf7:L$\N ׻^xW~waد:l0%k׮~o^x<_~zz:RǛ8@ EAB -ѣWYf{KU(ʄ O`}}իWG ximmmDDݻ'LMMw*++_|yǎ-Oyyyjjj'OԼzzmm̙39NIIӧݛ]]M8ĉT*uNz ć@ 5/^trr쬮~ʕ+=yѣGϟollHaNNN]]ɓ'E"QAA+W6cccoݺeiiyׯ_߼yΝ;}999Bɓl8*%%MMM/^<}4L~䉏OkkkjjjCCí[^|a4Ipy>z}޼yx[V^wqq)**Yt_xekk+ x?| ҁ~k@w:ߞ9sF^^~C^^СC666IIIhDY!Ctvv&''4q֭ΰbAAAffÆ \]]qP(jrƙˍ7-Z4qD:9ðׯh4HaoXXBsrrfΜdɒ+WHUVh.]p…$+11,HAAaȑO>3gg .Yd͓&MZϞ=koo0553gΧ-00BÇ߹sUII? _-Z-6@ oFMM3gZ[[^|Iӡbƌ~իO5k?^PP%!ڄBkײ1 c0VܴiԎ͛?ƦzxxH8`YzիhGR)VTTO񔔔V1cH$P(!!!_|ŦM`nUUZ*88X(Bx.tI#[b{!Μ9|r 6m4gΜk׮}бcǖ,YRYY9o޼-[hWwfoEȷ@)aaaӧOroCL$ҡ%B*85k،7n߾}{pٳg{yyFGG^_"G>F23ZNNpC"HMMMnjm6 Du)G@|n|0' [n ݼyC ><11HK[pJ111'O.^X @ :::7oR!a{.a-7L6{ӧo۶ SA 䒙|"4/DW&@ 3hРŋGEE >s8ccc\;III<O[[{֬Y/Yɥd2ʊd;bcc/\?WUUyyy/:HHH(..&&&L&HDiiionnԜ0aB`` F(22rϞ= XWW/c8@&7l؀kGq秽Y$;w ѓCjzwͧ;,ZH(krmr 겯fAGc}).~'|K 7|~'BnI$RddQ֬YXXXꫯ DǏ/]TOO/44`TTT7o._&""&%%9rֶk׮M6 6~PPPA}}} ÕMMM]__쬪Z[[o߾4É 500͍?~<hݺuVjmmݵkP(411:?VVV2\:$YtP(x/^˻}vLL j)~ " ={ֶFM]i ґY;zBMCs@533#Ϟ=p+7n̙3{ mmmvw^ho=zKFFZz`ُ?NNNvqqSUUMLL{{{t[YY9r޼yO<122{~6l033xyy={6''*H111Dߓoޮ#czrO(++h4"(޾I9r$ܽ{`p[Mkѝ/OwjSRRrww#wW^^kii.ZZZf| @єpϧrOHmI 3f̸~u@|;@ 8|pԧtƒ 7_o޼%N# 544F  mmmgϮOMMUWWQREEeƌ%%%&&&rrr0 t:H$655'655A-T[lGSSssssww.\%%%}2Bi@l6NZƍl6[6 evibbRVVvQ| gܹ_~%K>ٓ NT܉ D ),,Fw׎H8eeeuuu bee/láP(B444ܹsZXnn.~3h  bccsm]r x>D"_~֬YRsttt\7rrr&MXbߢEϟU[[[^^}3L&rSRRT޲Bbb"Á^\~z.$$]KKb=~|JݩS&Nwܹ}ٲe͛7oa244tΝ͛1cN[[[aaa~~]2dGZZZR(#FȞÇߺu+11QYYd޾};<<ݛBxoSȖ-[lق&!?mrMOsvF@ w$ƈr˗/?~իWaȐ! ,&&&鉉v%''H$kkk&; RTTTtttEEjHH+266>p@rrr\\QSS355iYxxxTTP(3fLttoncc}Ĕ-- Ps533;|Ç[[[i4yTTte0ydWWT6yPVVh"+++L޾}]֭[׽)tk!E h5߇ܾsǭϝ<e?QSŗ!>he^ee%?ݯ$33XNNÇ޲ ?~Xj7Bv#qqqpi{^EEEQQ_Zbx< p6JԬSVV&?STTڵk###{jA^^^MM ȑ#fff c ׆ot(D >b;3@ vyy6M&2VH$r8TWW؈aF-~XW|#YNJ}oreӡ߇0MML|>?!5?]'.].O!o߼ ]QĻ@ P__]577,˗<˗?jlldX mmmqg Bn3 D"arrr^x@x4C}I$}}s(cf\'s3eX1&6UFJϟ'š2"Ň 8p}v>r@~ATUU_z A 16cW(++cF MMͶ6/<<ߊa?V <11W.\EruuŽ~Epct"T?/?B.`0 ]?I IDAT;[xYqӎ?*-[4Fw•7f}3 )HA憇/^8**j0KC$''d+++&)u;ƍ<,[NܹsΝGą $z ܳgOyy9:LÑ*l|֭...k֬LKK~ss ^j#b>obbd2ǎ TWW ￯^a9΁ @ }]mmG!%KF9@#{L&Or QRgZ܎)d\_c--+<0s3S@X $D5jTPPК5kCn޼|r.{ȑ>FG,]T(;w.33H k/':::44 777&&F__1p8V1b:;;۷,--F}}} ÕӡSTT~z''իWx<ĉá0555)@ tttttt< >S& [;9!uSӨQ {v×K.8HCgT^6R^#OVAgϞX1nܸ3gB !!a{{^G⒑i4Hk/|>Æ fff//gHUd '1|~XX-F9o޼'OIm$..NUU511ONKK$%%1gddDkFFʕ+NRTT݂@ llF:TD"M _iDI"s䲔]"K'++kڴiV) #%%ȑ#˗/755t钿}PRR2uT#Uqq[/PTA&c8=!''gmm-"><|ggC =***rrr£DGGǻw0 {4 >~/¦Ξ=;}"P=@|Шw_zսسgϞ>}kUUUVVVVUUH{GzzCZ0 ۴i H8d2]]]H$p444*++ߢ`mmm+#FEEEbR\\ɓ'---Y,_gggO ǏBFc|>_µɓ'̙sҥ9s[@ \.W c#vuuUWWC*Ԭ466vttdBR;;; P(dXwEUU 6WY"t:&H BH$UNE?o'vyo$0~O~`m0̘1ĄH$655hjji)t:Wtz{ySćciiZ.\%%%2 wnnns)xx@ssk-77e˖=|ɓU(((455)))x< 0lĈOrHq{ǫf/jJ#no*@ >j#4 p={& NP`ņ;wtb/_ dKKKUU‚Bdy^zEpd!U| P(666o^bEwҥK~~~0ɓ'ϟ?_egee5|𸸸͛7;@ 5 Nvtt Ikk+ s-<"H$*ZSS<-- W;:USS_֊WAڑ'5a6VW<.W$JHnjxOY\(t! j4ite,H$if͒䤣roܸ3i$===?d2\.7%%Jtogԩojj*GZZZR(#F{/"{8`vvvN8qv^^޹s to$$$]KKb=~|rw}b444$EFF*++O:6Nka.D__*E9|* j:Wou<%''/ n[ˡGP `T? $G+W^|^"C X`̵KNN'HL&SCFDD$&&fffp@rrr\\QSS355Wl۶-))iʕzzzL&3##Cb_~9sL@ &"aۑg^@/Xفarحfc0L|c@#-ݣR EEEhN>s^~8o<<̙3?Ӊ' >lB|Aee<ρǏ[ޔPSCCC 9\6 jjjﮋ#G%$$H]쯩. DhjG&ϑPTT1c}ً/'Na#@AX,6-:v@|`mG DzY,uTT<::b"b //oI;PD G@DFA:p!> eΝ=/hx3I$K;~u(|m_s|vɒ%7o4iRcǎEEEc"8hР1c 2/߿ի P(7{…\VZuݜ _}M< `Ld8lܸQF-[dXy{{޽tҥR=[`D>x ++K;555C}Hv9s+W]$fΜ@ CCC@PUUe``GzEyjj^dKQnyfeeA訢r9 zީW7қ,2?k"UŋGEE >@ 7n:x ^`ٲet:H,???11NWW_3D9&s۳O[5WS\QD@ރ*Tyb)HYYYk׮2ex֭[1 {ѣGSRRNʗ=|p…CQFTJGkhhӶ fgg߽{wEEERW@|֗,+ᆆ_D7GUlmlP_ 7iz) XD"QN<K$ u͔WU?w t4Ͽzɓ.:;;O>3X" c'6[ӏ@A0lӦMwl_L6-55uf|MMMDSq$$Jv/cikkD#dqձcZXXo?w\``)ԩSkkkǏB!mnkkݻWVV6buu1cikk777ؠ @  eܻMDB99Ҳe=zÄ"~INn~2_OJWIQT_s/ʧφsX -CBaՕ獂W_34z}y.Iتtwuk^Ii?詅>̹fL{ehs9Ι= =ڊbZӧϜ<_SO8~|X R[[ٳSSS{U0tB􄲲2BaZZ=,L؂XӉDbSSxbSSh4\cccOhuر7Cu`7ŋK.͝8qFD777www~yyyZZZd2y)@ ψ-DÇGdn\ޯXP 031yQ[ wxwvuӖĴ!"x׼իttt>W"t RUU%0jԨJXRSW0P$joo;>pgysG[+)QMu66 3*+\-f]mS }ߋZmm-1e}{;%EK1^4l+'e0&SeLrʑa߇5CKO.~bq;w~}wz})((Wg;vFFFe:thDDDbbbffɓ'{f퉉)))ZZZ ,蟂dccm۶+W1̌ KdE;;pdmmd2o~'&&ڵ<_F,--ߋ2ܽӧM&c18; :ҕ+W$@|v`oR`nEǥeS& h4 K ^H PT%^.P(a Hr$yy*'MHwS&c"Lv/n@MG\[2eС6EBH$turYbyشBG9fh hV6[@G{DRRPacbJZDnfifϖޮVB#pWg ($-:QdkGprr_ǾxTcԩS̙3Gj-ݾ}W_}W_ӧOMֿHHhooooo/CcٵKJn -,,qF$1008Æ cA@ ga},Ix<ޔxʍ[uu3O6X8gs% 0-,Bc 0k1V=s݇)TtЫ<do  "G={jdZq )d9y WFF2u~wXTeWA4b/`$`~#MĨ%Q(V.#4˲l{w,EA3gw9{μ3f IDAToL<6s[CF(Hihx(HHrzpY7Ur<|6$I@ O_p87U/s;gU"g39/|~qIiaQ ا_~B=i *J5u"N͝q䷒֣Q'lƍCù8OI 9,>Rijip87:ŊrCʽe \Jq77豢⒖ Cw9ߚ;k&߳oqiYcN5fOy(btmގC"}c?rW-Y܇~&>JzeDbCCÁh4mxxF@ ,z<  E2lܗy5*)- 5JO*r >˖X&8?yCS+˓Q"Bz,w bw7o:уvڔ)[wS$?5gFCN$])=&-re~׊S8m,Lm\p&8:؃HmㆣQwKgϜd?tF|WA';^kjl~+K30%Adk -EϟoxW&ɦFF>C]%ĉH}bcc'O7Ґ111 _k׮-..s};9 (**277 |.S(I ŋ-,,?.w|G[H~-ӧY[Y oR_?[L!S sGK"SH$ E]]@!It"B$|n57ڟ>h<E2 jB )T6)>bJBQhx>><<|&:::g%K+W!O>{Ǐ?j{nݚ,6=k֬3fݻ@ @~ m}(˗Փ6%UH vty|nˆ8HY艝 JEE&6b29Aj}ĒX.HfwHVdžwbRuHH_oHITFF3u[,H$nhNFMgf?sRr3h*vއ...j#{ΝZZZ?}tgg֭[/ c$UUUCCÏX77G=ykXA4j@ HH={ٳ}+DJ]LB푁Qaz}n~+1M--Nc+  k+--;5ԅ#$[[/Yd۶mSRR|Ξ=$Yp… ?vco߾-& %&&W&@K'9FSSQCwuťe>`wq)_µ45/\6wVU 5UJ (*S&Ox rHII0aªU**,--lv{{; wo֬Ym6ȑ#fzʕ+'N.:t̙3,n޼y>} > W^]`EmݺeĉW~&Hٳg?{ ͝7o ˗/۷vvvO>w6@ ?4^TUd;{*mܾ챒h*3XNԃ\y`K@lkP _C̷DUl6NKK ;-=rweaa ['N/06_p:f̘ٳg'''_v X knnVSSC$22REEĉ 8::z{{>}:""Bjdd9';;_(zxxűlmaa!/@ O̮]!)/C8@?\|yÆ ;v:u*6h"93R@:˙L&;8GVUUUUUkll H}}^t)aNNN ezرoTUUܹS2Z9o\.͛7L&sŊ yyy'N^`! xP(1P() D{={6** X߯r…K.YZZΙ3GlOD"W3v` +/a=H$A@nL&h@ Bܹsn߾H&gΜ)ǜ\n~~~IIڸq㲳utt @ ȧJs:X4E 䳆AU d2,XPWWw)&b7a„%K9rŅJd1-rO@(xb9hii988ܹs?%%Yv<9dee)55U[[D";TUU1L {EcciZcCF@8B郆 HAAAQQQAvL*iӦ;v$$$xyyꦧ JGGGBd2w,6d;;M6m׮][kkkrp666/^BPVVVT*9DQQH$D"HrI$Fp88N(***8N3L*{@d2d2&t:`hMMP(@dpdlq8ܰaäs"(+KgpE%6dH!Xmu5oh# ڴiG>̙3cbb|||"""qK.Y[[dSSb~~~~~~/nkk+**Bdƍ%:u*Nx񢚚ĉ}XXǰN @ gD}}*FԴа\ 5b"N蔗#YAAD$Y,+lffV\\MMM 5$wU,A #ꠝAZ~},pM6ݼy#44ĉqqqzzz~~~W^3 :u]SS3))?5jTlllLLLdd$x|ָP(3f̸qƜ9sd,/38hdaaAsz<@ eee>`0X,xwމD"lyB!L!UUUGQQá$G$^ho߾Kt%5E%H c}[CS 4C]@ C /k{zz9 }}}Ԩl:::㱶p ".>}&@Ēr### /EvhLP{ *57M]V%L3t/^8~ԫ= " D*@># Kɓ''OUmmmMOO/))GJ*IFĤp8D2+R+L+@ųgϮ_~>}bBCCA"s\WWWgll,F뀃H@4ܻwG*]vΰ\X.,W;yd###@ d˖-SLٱcЯjIII||={AB۷|>$1I3>LI˅rspիW۷oʔ)Wg*6z9sL6m@DO>}Ǐ.O+WJuּd1l6{֬Y3fػwgd7L>?8Od!!EUUUAraWR1'AS>|pqqm;wjiixGر_CVVV|||wۣGǎ[__tvvՑH$`ROAAA(JF \vL& L& EAA/?~ A"D"L&JJJ>|(Ν+VթϷ~; *j<A ?|8DVVVVVVCr83f0X Z~/"sfffaaMiiQHHNOHH8s *0_u޽ UPPXhX/^ظq]hhhgggttŋuuuBBBПYVV/YdŊΝ;ׯ_=gϞh Xn۶mȑ)))'Noߎ=&3nnn)))K,!III"Hy(5133c0YYY.ʢP(l!7ܼyB8pӧJJJ ?vttĆᄒ555+J Çꊉprrڿ3@Œɓ'ڵk…W^Bh )?Xqx<8G$Jp8T/\ x}C:;;h4IVTThB@\PB,,,H$ReehLJTQQ9qXwqtt>}tDD*o߾}̘1,X(&&]L@?~c@رcϝ;.\xܹ-[h4A]FfϞ Ҳ_@={vrrk#,,Xa.k. A<==oݺ{b}^BY`ƾe5o<<<{,%%mIMM}ⅽJ7Ͽs@B}… s郬_YY9~!kr7˗7lذcǎSʎ F xK)>899%$$`E &\rv;(RMnn.7ߜ/U^6---@1Zwޖ( D㻋/ _zOsL(c2 lxaa!Oeee:CC秦Jj63Yl^FMNev|!|>޽{$ۛl;;;ȼ<3AL N:%AǏdsss<=<</^,#ka0x< Ԅ9<<<֬YWZ[[MR+Oܹ,tU5111QQQ*))"Sjj6D;v,|A 5 U&.)H"gʕ]NڰϢjhmmpA#`#ə DNXSp8n  [ZZlllP(8cժ*0!H}-ϩTECCCvdK0tuuDxVVVHːUdPYYy[Ep"ӧpPZZJ$ϟ?}T*f,..۠ HAAAQQQrZrJffxvlڴIFJJ Hrr12liin:P/_qlll###sssF H.nۮ]~1{ yEee%N @QH* IDAT@ bN<)krF$$(cNSSemll@VT*NK깸d<] 11qذayFr>>I&L{'Op[[[/'  i^ dff1ܼM__@ ;~ѽi=ޑ,BQSS333 6mS8jԨؘHjnnUSPP?x`YY͛zJ?~|dddLLLHHH  >}zXX[Xa,\ԩS횚b~ϲ3fܸqcΜ92z 8hdaa4a#x ,,|5k(555'''""B( °0WAP/FXITUUݼy HHp|>BH$p`( A섵c5l.۫cK`b4h8BRFBWW߼y#wI'Oj#w;WH/Muuuuu}EEFGGǍ7Ə?vج/_QWWG bccq8ܜ9sV())ioooooՕݻw\.BcX|~ZZW_}bi4Z]]0>|0### ɖ,Yȑ#8 #չs$}}}}}}ѯTwwQ^Lڼy͛!n~3f A K憍ッ{ݻw޽&:CCC}|F>JKKQF---gQ}}}KKKyyyqq1+ԋ7͛7#44v2d=Z)@l6ĄD"G /_@ <g8p$eeeips`鹺^vfL<Acy FYAA|{ggݻwjy=ZQQS/p!x<˗g͚EP]wJ⽛[yy_|iiilٲ|555t o/^[tiv !%wޝ8qjC gѵkװ~Ϣh@lٲ{"z1s 7 *2Ptttc 8g#Smmm%okkk6MMM) t=x^jll|Yccȑ#׬Y"VrrrrrT^IyK$B!0)5Ç뜜OcO6߿ﭬ# `]AAaĉB>|m1Eѝ1 ~ܸqC,T?P@3o2(>._k&aAdWF׋]zkkkhH Xg="CFI3b Rwi[ϟ?dwMև ݻgii 999IMm1OGϞ=KKK;p@ !zR(~?555 T[AJJJRRR444FᒓdrsssoRCuuu+Æ άbcc'OlddXs|^`w{5}#r-I{;WV N5777???9H5?hoAooÇK޵#GeXYYYAAAn?t$UUUCCÏQgo@ OwsP=)O0oEkjj[hvvveԴ}˃JӌD"N:N苢΀Or:.6AO vK,ٶm۾}^pqq_ЛoYjTQg…Rm@ lPruu"@zk̺55I`QhhhZ*<<ibccI$Ү]DvA#GUVV#gddH$@T鰮رcL&x駟tEGGr8Z AݻwWUU?ؚ5k ơC:t%修O.Um ;zhiiֲe˖-[f][[v+W#GHg&zIw.?~<77嚙'h?CTTTUU ݕ$6"4mԩb!NYYF577 mmmGYY,`q\*E$|q0 ˅rrhN$¬֯_MĬ,&DX,VXX֭[MMMڋ/6nhgg{Euǎ\.7((HCCÇϟ?݅o۶MKK ۷oŁQTm9xmFa``|dggO6m;1~Ek"CJKK}}}BBBtzBBB@@3gA&믿ݻ޽{ -.9s@ 2P(L&xVRpSSgXD"VYY<=455aBt˅rfC$Ds􎎎94V㺺ǎ'cǎuww?w\PP/**ڽ{7z |.AG2SUIIIQQc/"ٖ]vYXX y֭d DGG&&&-1)~E=DFDFF8q\rtt>}tDDo-X(&&]$GP! Lf"DBP$F!8\7o=-@ ._aÆ;vL:UTkԏ._}"B$MMMO >~wKKKؓD{={lTT:VTTFPVVھc2BP̻zEE|ȑ3gDDDhiiy{{{{{wbB1' \.WGwf@zHFMdtqqqXwk3NcE)++#(ՠ؈9\@ 2H.nrssͱ!G HL&suuuN?]~O 755a\A--]v!RQQqƍÇkkkϘ1Cj3@xԲd@ ttt0"%%%]ܬ(5~뱋d]9ŋkJOw؈\xQQQ@0"+@p)((#**JҺ=z~jA|>z_LhLKK[nHR__Kwww[lrJEE'XMrr5k$-ꦧnTUUJ&^XfYZZ޿};-M.ڽuLٴi c)))_50"/_nnn"'s΅ׯ_'&&z;v!@ _D$ϟ/m::l0&믿vڵk/^yI*|rABBB̙c``SSS|Cwlڴoʕ>>>555̙3cbb|||"""錌\Kddw߭[.((ݽydtQ͛7-^X[[A7 'N`XݣG&9b#" @3gCH$ڿ?8oe 8vC!H~i}.]… .\hmmUTT }T!~3-8pD" Yj@@Pz Jw3 alo6~xsh4WWW38,tVRd,lH$`bwd23Ϩo$)$$Dv?'=%3ɩf L&t( }~Ćh4[[pyA !X QHKKroܸx^M QTg,\. !11ښ@ +++uttLf}}bNNꫯkWXXҢlee5ZB<~i>"jjjJJJNZZZƣFemsGE >|XL  >aWW߫˫$ƍrnoos#J500VX' \pVZ%jnnrիW$ TSSz}M2EF~ƍ^^^|9r$)))%%EӧO={V*((Xre8YI|||xx8z=zΜ9ӦM뿅"l/'\rz;`euuuP@j_EPg̘v3gϟ+++O6-,,,'''""ɓ'>|;wnFFFkk+@WWWONNnkkx֭[fxBUUfWTTp8'OTWW?{_C>#^xQXXbcc3FBa^^޳g>|t*JPD"hkkkkk+++KNN666_UUL&##zooo55%KDEE=}Txy{{>|_ꮮ4.i&IwI*z#fee4PY;wjiixGر_3K@>*333]]]s"_!;|*sڵoeeeԄ׷ %㏩W^|ZMMMvv?9T7nx(Ν;2" Hbg Ǔdyag+W?***N^YY)L2nܸ|riDL[rrrgxAMLLtuuD"Qkk+b*--;vܹs6 22ή?xnʊRRRΝ;gaa1k,555OOϊFSSٳgkhh'y9///mmmRrr2Jnx}}ZK& ߿ɒ%۶m۷ogzzzGGǤI>}3''r/\:=tslmmG >{yy]r%44422r<44{GQZZ~_I&ѐ!֭[G`ooOPܹA"˝e===Q%jWWok<==srr3b.G=H$-mы/z!)){ Nj塾fff%}}}W>3F>>|D|Gә3gƎ;c I+;wQUU>}EwN,q8zq~~~cc?4>$МĆ?|TGGACCC[[ۻwVTTΜ9[vqqqMMMׯ.] x<bh4 P(Re  UVc޾}[IIi޽nnnX ߿?**KEGGr8Z M͛ׯ_khh,[lٲe U ;tХKPIZKK ,*++;~xnn.533 R ݻΟ?]f d4JF=q 6Y\]]ݱcDzL&zO?h41bdcc>AcŽ=ZZZld2YSSsԩb) CR ѣ߼y\.D׭[ ^lٿ/pli[l![n6lMLL>Jg%d] IDAT ]^>%Ĵj\tAl֫j̙E>|x K@lGQUU7xq8> ܥ]]].\p8wST'''KKˋ/^~ eaEHΏYXX̜97o߿ ȨQx|?uvv?}Fxŋ׭['흝׮]+--_pBP+ ;"fee~u.,KaXaaa[n555mۦU]]]VVp8۷o_p#"" &N@ }v\\ FFF!!!t:=!!! ̙32 UH6Jvr윙YXXhccӷH.<yƍBCC;;;}}}/^eXܶmȑ#SRR#ҥK Hi@eW~A.f:;;t:t-Zwwuu d29++kiii@II S~zVTT}iݺu} ʕ+L\ZZjkk,X`iiQ;rȹsbu@FF1bGwG˗...>| Ba]]Z@\Spmm+V---)))EEEՒ䡱Jف)cccÒ1c`{… ޽322zm^^^ll,,$ IJJ ᏛݻwSSS`](=z(*޶mۤI}رc:;;A:B+ckkJӧOy:f`(;::6o,~nbE'''aK.Q#ؓicƌyaKKeiilll>|_ ]6lرcԩSDkkkAƏ-Vk LFp8I}}}uxK.ENNN ڇa6Jv# A9D"ɓl6^ӊ._]jѱRbZ`Do2ܹs?ݣG%:XLMMMrr2rwwWVVp坝Փ&Mz䉃&X2Ƀ<(B@ 1&A 18}tT"E'j-((A#F@ad2v^ He"k%H. ( ;qP~Ik.޹sk6cYTTjCAA̬W.@{E"۷oQW3њ/_Ç D"޽{Ϟ=gyfŊL&L:5>>۷]eee\bB}C60L>5"c}1`+)t@5ȑ#111gΜXd2B!0ah4܅6:>f *C ^9pӧO]]]QsdAAA,~׮]{eXyyy/^444ܸqӧ|~AVXe˖9s455͚5맟~bX٨3l A`8@C ѣ{ Ht:H&U@ jjj91%FWWW]]ݛ7o444t:Lnii HF'됵k$>|xMoY` 0Ɍ~ӖBwH(jhhVg1::K޽{k֬A'ȃNrr2@խNLLGBauu54j`0Z[[d2,XPWWw)1XoFܹsΝ -"@v {xxH5Bd=!7)ty1L677---PQQqƍÇkkkϘ1`0xN#ss󆆆Lggg333555`WIId2666|>ɓ/,QF={믿͐P(|1l>cƌު7D$ϟc}TFu'!ۜUTT*++[[[)ʨQf444lviiϏ?NPH$҂ jkkHD"188x?~ֶe1E/999yڴiʕ+}||kjjJKKQrbddr/]dmmM&MMM7o77.T23gDEE455EDDxNvRɩb?~ay2BBB5<Īvŋwvv[Xew"E@D"ԨAbǧ(Q!"=FXb &v(U˲}{w߲KQϽs93ܽΜss), bwVEEEׯ_ľ귁AxxxbbرcJӧI 石'GG>}8::j(" Q.ݻѣGݺud|>_GGN8q/~iUUsbGAhl RSSY,y93|;v6 8p 11qǎʪ~gffv%#G$%% آцUuy֭'N OIIyG nñ?y7otclll}ɽzOJJ龾/報 a mhVӒȃz4@vbF. H͛#F3f1c C^ $G@ٳ ) " C^3,++h m:vxKBBBCu.ԍOڼԢ¯`ڴil6~BӶ5557ٗ@NO2%==ƍL&̌b* X߾}[\\+labb2vX{{t׮]^F9rH|_d7oN4jG\.1o߾uqqiܹs>}ɓf3##x@ ())ÇWq~4;Ԧleˈ* oٲ8 T*uڵ*Z6SÇkImZ'3iҤI&3[CHf7f?@$Bw@I#RRR|0V\"y10bĈ!0Ě!%7o58os5v0""t%߽{tȐ!T*U&~К]\\N6Bٳg322矷o>}ӧR~~~h-2&rtt 9uzRB:::*={ 5++4G >t4#2ѯ_?ynK)ٓ'On޼ikkCfb 95IX3nr?766l !}ǹVWW+={bF'ʊDi|b~\6yO %6|,[###ZLQ;r6lX*zzz)}q#G'bCΝ;v}¥w7o(]0`Ŋqd$͛7cǎ 6ݻf֭a,AjUA"ҧ a'(.B( No]]SQ̙qA5'##رc?  ={vk)ɇyqzzӧOg͚ռjܹs/_ՙt5$$ tT|\.uVjjرcꫠ ¥Xyy9ᅌhƌqqq4ipDFP3۷K&&&!섊3`K. h]qkYYYb8//*8Iw w֭={˕yyyDΘ@1?LAnc^$PhhΝ;_x1w܆h?Ν;===.\hddsɴD[>NOO矛 ]p믿Y`.))sIhSOgr訸Z !MD./dddwa BTɿ ,,,""K.ڨI?˲;wM2M"ұcLj5CKKG"t:^>>FLMM/+iqܹ8#mjjzڵ>}̞=;//H?rN_f yevԩ/^믿pONp޼y8//oڵcƌ۷oPPжmp$''0!w8p@ 5áT .\6@ RY #CYre@@@߾}$. 6Çf۷qN8A\M\3g۷/v'Js޽9swРA˗/'.]vذa}5jTddP(ht셌음*t{*aX,oXfZ`hGiƍ_={ BGGGbqr+W??t:Casp<'@ #\~_똘OOψUV(t L```RRC&00аYYY/XX馦gΜy ӉS2ݺuߏ;6l0sssϟ?;wmddyaaaNN̙ 8pk׮}H{{k׮v ;yg7ALL̊+q 82ג%KnZ__7?~Gt]zD"255{nZ#f}f=> j GSEIrLxx8BhĈ)sPt$˗/Buuuuuu 8.N߿|:u\ Nr\.ͦR(^|9n{YEJYUUgnn޳g1c۩wp<ܓ#a&&&K{ MNN$ɺuBSLx+Wnb [{챲ڽ{7"޽q>%ɞ?~z ''˄˕ ɓ-Zz!CBQ6d'O^|իz?~}._"J/^8j(ۗ}޽ƍgϖH$ JҌ/DR p"ֶLnh4___]H$Ϟ=1cacmii㓙휝' we,'֊D"zl(HLX,cۃ۷oW(&mݻwn::: .tLITnذСC 7fXjKJJJekjOIIYhŪ MIcc 7nTWWh/^Cne2ى'N:E$)^"?r즁AC'D ĄhbbB؃%%%8p 66<44444f@j#LfMMMΝBT*U T @ H$jk0oզ]6`͵5 ڭY~}+=]h  *--ݿ?!DPݻȮBiii!b*?_tiSLϞ=kN0a޼yO&FGG1SNT*2@===# |CS|>YYYw$(((PтϻwbƍР~' EDD,0c 77cǎx<Ν;:wu'N؄Wm&˽o>^ uUw&A^㓒tŋocoo7otGG=z e4rǢynnn|>ĤnÆ ;vP(jtttTl}|ӧO?~|ҥYf}v?VV4kG={7o_JKK B( {}x֭ aaa"A>Rk׮]vܺu !?3 KXjnooje˖-[FN!͆eUݻڸRl6[Uo}addm6鵍SXXxq6NR`ԨQxǵݏ_UZZbŊ$WW˗/Ӊ=%77WR>}[bOUKHOO{s׏-.m \\\`P 4(Mo߾=33[n^y #޽{ӓ P(._޻w~ؐ߾}Ϗ C fgg7OA~JaP#Gѱ ~Y?yHJOqtt矛PK:`[R ydL#du޽ƶ}KO>MRCBB ERR;# 5ƣG ӆNڝ;wӲ2##fwdvڕ8h Ν#T(˗/i|* B(44tΝ/^;wdk֬177qFrrr}}+%###C&Cnڴn̙~⑕Jeeeի{cǎR4)(H@@OO/TWWc!DP{䚄Wmm-'Rz衫Kccc})m󨩩pq~|ڴiΝ#` T*uСiLL9aK,BhԩO޺uk||;cr@ƍYYY<O__ѢEǏ[˥Rc a޼y!\ތ ׵Ovuu֭[<|>Ĉ-鯡ʻ$5^v-::z۶m#P(Q(&ݻwgdd|AoiF… 7o7o^XXE򒓓=zTUUeff֯_ :x'[LL̮]'OL򑖖XRRbcc3f'''gϞ=m0D999{Dcǎ={6q5??۶mO<155%ߘVX%T&Lpƍ3g,Z[;nddԫW/r ۷oܹSYYs޷ WIIX,3332d>"BΝ;8\&?~{uuu*~,,,Z熆ؐ/**laC,IOOψUV)--rիWK$(SSӊwJR<ڳgڵk, 444,..>x`VVVrr2A l߾=22ڵk:u۷/B(##c͚5 XbEMM͎;r stt?s… 8>|ܹ慅999DYHr7noLm<7k❒i*g|||T:cǎqƙR4--{ݣJ2;;{„ Br,K(rPȘ1cBo8rʕ+ cȑٳg=zDyͬYT"CDMxbr\.kaa*M6L(:::/_$'D"P( ݻpL&{ JER*}ٳgoߎ!A}||\]]NۥK(H֭[rN2ŋW\FRR}ll,~MԩSSC_&&&!zڵk9x  h>|Hܘ&wJm ;㔔LbL&ٳ'nƦ>33MWW`P(BV( " :RUUUE֊D"zD`0$ B4 ukxhs>zѣNNNÆ 4iH$n rxDk1tPM&xRP*Moofgg('O\hի BN6mqP(]t7hn❒i* jÎS(Ν;?899 flT*RښRWW󫫫y}&M7x`rguByyyϟ߹sE`` nݺlٲ5k|"d.]4y)SgϞi5.`0T)y}T"xyy1L###xDXKY(&&&66h4J?~Et:]݉x8t Xr$ѣGtLN]vرZpuu=z  Ciiitt#:uDR_-eEEEEmݺEӫWg8멩wp޼y ,8pI6n𑧙e˖O8¢KϚ5kڴiQQQ8F5B k,m>4vX2RFjXV.S( ;m6Æ ;*PѤ p¥K^p;q&I۟>^ xM377$&&رC"XYY};FhdB~-BHWW-&&& xt`J8HL&w9 ڵ+ܤ?qDCCçO *jdd4l0xAm䙬,XOOOwK3T!ǫmjmFo:4R{.j-ifdd6K:3_xAXѣG~*T5999R b4lL֊.Ǐwww߳gګq;whR'X0A'B+z$lA[  37VS K $;;XXXT* ?~\PP JsrrB"(// qV9ҿp&իW V"x<:^SS#˱eyyy]]ammRH$:::W,֒ ]]]33-//o,^}}}II F333k\AmwB[[ۊ b 5TX__,jkkL&BB̌`{} >++^&Q7o8::|\ zaLcϙ3gƍ j,ϳgώ?ê*{{O8&'':t͛0@F,;;;?}H(r\{ h*++ܰ윝+]]] p "J\NR)6 nnnF/p<\>/b16NJL&TQcLMMjjj kbX$hJ:sJrT*x<@>Н;wݻWP4?Ϛ5++++$$dƍV駟V\ c|Z?T*B100dk <Ha08~aaamm-V<&YXX(5UVVWUU|kbΎL(3DDboo/qA!N;uDP-^ɱF B P(X,ׯbqeeD"Q[K.؟@K>__M6M4)22rƍ88ѣG7o&Ȏ3f….\hSH$+8d^AUN!8F300  J8WsssS\\A|Ja`0LLL0 U &//+ɐW{KRXADx !kh8!1 !LMM]={m۶>`0 pBCCVu޽/^,^0p*--ݽ{wFFфXz^^^rrGpBwҥM6%$$7gϞ+W˥ORn׋ }=KlQD&˗/BuuuB6B8Syٳjٽ{q>|8**J&=|83>h,!ԿcWWשSǰZO@ppÇ/_={b >| ׮!dldйS61ko),,rwu%6&Ih&ɓ'-Zz!C JJP8p@իd5ٳg3f 'YZZdff"t}B?X:֝Nڲ&&?$uJ s3Bh{.r !t̹̜AGP:תkjV.]lii2xЀ?n~YP`kcr^5Ѻ -7d@AjJrÆ JHH T6 lL&s˗/T O<|tXssPlXz|||JJʢEX,VmmmxxX,&*700h-; %%%$$ƍ!!!0AGGgw1B/_V~:hſ͎ KK$_oٺgŋB77622|#C٪r>U[[fU;iXVGGtU N獵oѵk';ۥ  [~ƃM_3?Yya1W,373;po8O:::f&&::t (H-߿3с{ IDATP(~~~ Jz{{#p8*ZYYIN4_ssu!Ο?sN /]4y)SϞ=Ӧ;&L7oޓ'ORRR4x2ЁY̷?8c)%N Zν{14`H+gN"gڸI$c?k3BhxP_LcGϟwPX,>q:e_BB֎13\¹Ϝ+*.vZah./lvBBY;̘1C"lٲE.ᑖFd.++{.8 0]TD"4m GɽQQطv6+׬;wl<<_~]T*Gb/~&!T\Z&H\󥵱?>E#K!E%JXsڵ+lzzzL&S(:gN]vرjz{{/_|ΝFJ nwh/^xĉd2g̘*--1bDNTe2YϞ=KP(z:{---_e&Lr?3XiãJtռШT.SV*;Ֆ EsG ?8Nvz$\.W*[,0'@Aj"""÷Ƙ2eJnݎ?~ԩ*ѹs1cL0^z'%%EGGt__ŋc?xɓo޼鎎=zjB۶m ۷o ӦSC3f !wiv'}~ K7o:AqE֬i~6Vzzz޹;vrAkk\"+˝_QKԖ}US[x4q,cgkT*yGw/\.bb0Lfe˖Ʈ޽{?ꫯOGoݺA/[lٲej ޺u ! TqssS mwwwWWƮo7_?GG{?8r"Cmmmy>w^X/2hN~؛dia+'7WPzw562߷ﶝjQÿ|zhWmY㺺3. Wƃܜ<߭.fWUVUMÇذnC}|44mgCGGS˗EEEBcV(NtX.uy Bd{vA͙9]oMMgL!;vύX,\89wq>vHò"K:xh=|{#2O?L 6t"׳r\-{mnٛ  @ǀB^… 333uyfsssH+B"3c7|7Ο@CQ 1hGԨ$JRic 0绤utnK"74{V(z# @;Vr9UDLvWu9Qcw| @Vzꥥ!6m2=tܿn="'(HG*jF¯NMAzwލ>|KYnkaS5֪f С$p1>!:v&@{vgw/@Aj1nnnnnn~֬Y0|tL&  !Э[`h 9/vr|۶m: &J  %a8P ; *Cٳgs\|\UUellRrFJ$Q]]mhhHP)qS]}233FgoΝ%:V+XLb!XP>E\)l2( e=bs6l0ӦMC 6MNwrr"#FP[UQQg>ɴot\š맒Ҙpڣ>` IKd#-XM6_yy9yݸL'XP#J$1QgF3fԢo"4Tn6uT(*oNm*U%ڭDCTnm_UmMf`@Av-F('R>߮%CX,VxO3m^n] ( \& Fhrm$JR===|/DLP(tuuutt}vɔ)S(B K۷ioS!b1Bkv ƄD4K^ҭ['O~Ai<[{\AH$UUU)u9+hG5o(**b0^dbdWVVJz@rBaee%LPRimm-B111dL& CCCqe1cƴF5t`,Yfw>*,cϫ ݻw۷gΜBd07I;Q#֮Yx ]vmL>ԩBHWWܜnaaR)H ok:T*G04 Bb @Rk׮ma-j{/[슊?+Pϟd2BỸ}qۼ+ЎJ &-/aپZP__O Enp q _ ҉۵k>r势~.]֬YR\&]$<}͛vJHHXbٳ8bŊ˗l[> 0qDDBZUU5~9s;wYf͕+WΟ?_ ubbbnnnTTTXXXvv6ugddPԜҥKMv֭~i!믿۷/77ש_Vy BXnϜ9o/00P&a_~Wr-+++wwwB–.]*Jׯ_"""rJkkk˷lB }i(GGǸ۷ocGv_~>|D"իׯro6''իǏд++`aÆ 3f OB#GJ۷oYYӧOnjӰfIjEQP[X,|||BSNrfbO Sn ]n؊63 )H=zPkRIB|>h4:t<C8*Y#F;>qY,@ 'vuȐ!cƌ :t(j~~\.YEEo߾]QQ+ YVOO5_efffMꋊrss ~Gq8={><((hȑW^իWZZ?quggk׮%$$h;G!;;[TKR" #88… }x1cRh#phƦA}}fG3r{he-g~SynGcxghhXQQSYYɓǏz([bRWWi>Aħ<q~DB$r@'C.^:JJR(rP(<hdW*ʠ7nH$kkkD뗗tYf:uJOO/ gffn޼ƍ\.dvvvyyyuuuSN=x𠯯oEEň#>|XRRN|Çk)rUtttd<ٳgUrklPegoUZXC@ `)rah4 www|LBL6M姍\J%0q_6V-Bh 4Æ 322?MLL\.wƌ?v옽}|||jkk3a„ׯ?x2s83gj. 3g/;fkkqF[[[q8W111!kkk''o6..Nˆ~Dz2Ә}ʕ+:u4p[PՋFM8qѢEFF*M/66!o߾w 4??_KFmbر .駟,,,~CAcr<(Mc @{?>|?|h/=|x$ICB\N!uuubqåߣI&臘&%%%**㹺>}Z%|ryr֬Y]tQ5&&wttt``aÈKwet:W Ve2/_L\ / ;1cر8}gC񇳳Ib-ZVVVQQQ* BhԩwꫯJӱsqww={6ҪA/3gΓ'O~& _CZdI~Rw ©Ai{o ^FFA#Drm ֪JxlB޼y/!௤AAAj:99؞b``@D A5GlvÇ@;@A1 }}}ԴB*~:BP(;wvtt$Rӻw^ZZZWW~M___B/18:a WctMooo&Y^^NөT*~z{{?ydىD"&يG;GUvʩ;p@ŋYYY.++[v/ MF__i }YZZ ŧŋ7otoVTTߡqt gg޽{~0> 277x<^yyׯ_?Ν;V?pfVSSAi;###իWRѣGC}ĉSRR:w{tuu]БټyԩSmmm,X0o< MJ* d|wÆ  [%,)Vg۶m1& ~zrp=cS(v!GlC~~~{I޽߿rp8ZRId2L&D B,KRS\O%H$"vhbq8*fi4p8FFF\.à2e}h킾}{յ53a Hj"D\KkD׫kIh0&bOD4&&cFD4P@HQ`0 ~sNch ~묽9kjLhhٳgM/-2D"UWWk 'J$%ZKEEŢES` /(*bQT*Jd.BA4NL.d2Z-JM1Ơ]?~+#†z׮]yi'77pH?ŋ/2 EN6\|rdd$ſGFFO8****//MIIIprrz Fo߾@6={Z æO~ r~8j(&)}lmm5RRܲe= Ǘ-[)GFF~QQQoFejΝ;lmm̙Hy]-ZrJ|wϞ= ,0"vddS⬬^- .%%ĉ033Owm;v=yD"wwv?믿?{ 3` EDVVVăL&|u{4dbaLh .y< ( sssC?bx(>NccsrjL&hNC7/ZN}֒f4) IDAT[Zh4˱c\jժ(???CR]vڵa7o|,kk={ް4)) ߽rѣGvܹpZz՟`ŕ! ukYx;#w0 Z~1 [n뫷- ?_|&6T͟IL"͛Ϟ={oݺ5,,lFl31}o0`hU@T*U.2Ɔw MJNg坝L&rd!@ :,楥STDwPC r Ş/퍍ħ舉!HqqqK;whlll\\\g?rYlmmmmmQ_x~HHH8ydcc#n߾>pL&ۻw͛7njaؒ%Kt+ڰaXbEzz_eeFFFqq17.H:3zh þǏkݧzȑ[oDO:TYY_憄`v)OOϋ/X僃u}W şѣxCbK>cdl`VSS-z:6Rȑ#+**pPavx??SN)lJg0D "ʪRPH$:!JCBBRŒH$=#2`7J%HQ4_fkkKRU*56F{饗 E|||L)/DDDxyy/6# RI4 EiidD2v؁C@*//?+xxxhMիWO6MǦǏ?~XL0ȫF"DDD9s&77VUU2ښr;;; ÌԮRp0X[b2"JVƏ_VVL/oGgkLL̅ Lfqq^ğ{Cm Rݝmɓ-Z4gΜo}+Kg0~i0`0j(|mQ o#a":i W7tb]T__occP(r9!!!BpN"nO@@qshM/'1 3ez/9hUd2]]$Iss3HC rڵ쌌 ƞ?^o1&immhl6,d~D $%%%$$"ڵk]Cra95ٯu *˫V_BPy &LPPPwڵqF /^v={?>11ш&ETcv3/VU/:K/Z $5&yrH$#Hr`d2 B&R)谰RhIP`fffvJZ677 CVt:WըRoooooo4jhh0aBaa!MLL믝(L&1öD@bBܹsH@0eʔ)S544bI [lfX.\XbroooRYPP`(@s~~~{{{ZZb1ovGk[Də:u[t:^WWgdZcԨQj:77([Έ؎+F6-*++ `:/{ݷo_rrilllzX,z- a8X,Ft-U((ZFǿ`GqsET>wVP%BPtG_}1HNNnkk{^aHSL!|" ʚ1c[X,c__#G_FmذaӦM/RaaZrrr={;99eggO60bĈΣGW^-**z7)6]SSK$ ]vyxxneeo'%%effzyy>fXXX]]=,[,11133mǎnnnzCP.\k6-D"!չ>}Rת5 A kXRXbƍ)))dž C u'۷RkRCO_-20D"T*__߰@gg琐dI(V( –f.с BN/<^Ө}ٳ%%%/_KJJΝ;wy<@nn.omkk#M'5VhC>ܹ1c?4}7޽{7;;}ۺukJJJrrŋ>| gddL8/К+߻wmϟ??c |w^|Џ̬߸q#o.]dCǣHDuDll׍qqqs D^dɒ;wF6-n͚5nnnF#ժsrrt:vˈH$Ϟ={ƍv}!7ӧ~FZd # Z+׭[ BF uJR*ZXX-0]`+<0 \GIFH$&!jTo# b0+V$^5PZZG~'O8;;#DFϟ:;;[[[_~jRIQx~pt[677c]YY) ÷lrر;wh4&VVVtfb~W,StNdddRRҪU*CBB"!!رckkk aXCCv` sD"Y[[KRFѠAA]6U)<f͚eaaPf)..nmmEi1g/LcxqbFÉB7ߘP FLS6332ihÌjL_wkoozҁ~ܹs'55Ec0F $0oSKP rFi yѢE0`RR!G*n=n߾=vX::kkkc$իuuuݎ}p\333[8h֚1|IALSSSc$`0Ak y.uUd2Y 辗`9%H0 MA흜]g$;VZZL233y< Ejjj{{{rr2 ۠V322}DWWWGGD" 5jT^^L&koohllDa+**<==1 khhϷ( hBĸkZH $Nݠϴ\.u;u'@21Bff&w#i& CCCQu-Zh  +Df0 7nq ןM&AD0`ؒ{kמ={͑#GzGƌp`!}5D]]L&S6 _A|߫Ѓg@annnzt?Kn߾_bRR[[+H^~劊)S G۷(P!??_߿U uEYXX?0ԉ:uΝ;(_q~?c޽2?|uxxΝ;ǎkTbnBԁ_iȮ]^:nJ냁MOKR3Yay}]])aiad2#D"@bp^Rv*0W4  y_r`"mxڵ_|V^aXrrrqq_ܹ GyE$s6 я3Hmmmd2B(JZD^;qͽxaz}hstrDl2̞(??l…J233ڵk'N0)00pp:A`9q*))h4!!!aaammmFTRRJGH[[>iVXXىh4hąw@gii)Lnmm})^C$ ]C.]t>;;L&KIIprrzO?4**"""-Zhʕ{Y`aӧO?p~S⬬ Z޹s9sjkkTܹ322r„ /͛r{!yJJʉ'8`ff'`vHyf-?~|ٲe4MVǏhD_YZZꕇÞj ʈ'NBr~8j(&)v߾}l6{HC:׫C,]tٲeEtdM3w0MH`|> Wtz =Zz@*//rѣ[[[+KKKCBBBCCFYQQQXX C]n߾{+V}'{0 {۷Sowa agϞ0?ρN񒓓^􂴂cCC 888)JWWWvqwwBSXf )((ϯ c\rѣ555'O^p\._xodee7nݺ7|h 555++'qqqJP׿몪qoyyyuuu1#?UV[NPx_r%9<j!7lٲ{oZŌF;vjӦMVMݻw9sӅ/Fv\ #$$$\x ."Z2")}wδ477t:O嶴8::lC؉b2|ƍ/x<7f\TT4zhB~WWׄ Lfii)J2kkkh|qռy{ކbu;:tm&h:8pl6; wIMM]`x...nnn"a۶m/BNg<ɓh}~x뭷ƌaا~zСW_}UP111͏=B㏗/_%ɗ_~SNyzz^xqܹz@aK|MO>o7l؀~b֯_{^H Q.Ϛ5VGݻw_~yٳgwhw3.*"99ۿŋᇤ 6+VHOO믿d2޽{o޼ZdI:Ő03gT(wޝ4iR{{{^^^VV1" mnSmyqiikFjkkQ43Ht޽H|,(P `*8rHLVQQT*5Ju4TWWn߾L&㉏,,,EEEQQQ_|1~x#G888455yxxlٲ%00ǝ%pU+Fh4bxH?VFNǃda^pCĤ$8Jf„ 0nB,dD"`_5&&… zN0 |JV㑇,--Ǐ_VVeEUh >_LO%:ziӦi[ZZ eŋ/{c̙sرDEcDժL&Ġ".{̙\.[UU~jjj$Vhuޭ0s̹p¤I.^8uTKKK#-# ^;=H:K.R4**.--7NƎ[XX^Lj:,,L뵈Isszu.A"Hx|#Q ð[`k9!ɽn(MKKÇ߿R7xӳ$55cD48&//bxYxڵksyݑޏt*JVi4ިͦ|w{!ڵk ,=<ݎaXGGÉP(NJLL4zGU}`$??tmλ&!!aƍ{Bo `AZ` X¿Z ޾1''͠I]]WGGGMM!Ы?))ãNKR.{A G~t D8::R/?o@@@?Mn5kh4z4T?fX.\Xbvttlii)ɲf̘akk{-eooO,F]]]ޜ9sBBBL۷Kȣ욚tĉ틌0믿+1c[5fDTĎ;|}}9" _'Otvv=z7޸zjQQћoaٳ);;{ڴi,ː׬YT*#hs_>&&0EF7\.'VVVF:n7R` @7#+++lmm}嗍0wEFx AuqC[]мːdRIR?3bO3_H$n= v ֭[Lfrrr]]݈#6msɒ%D?Lp7Ι3GT+.]z.Y?5jTBBG}tܹM6 ~Iˇ-66|RϪ E@@ѣG}>XreIIӧ۷rʠ WW+V~Dy(֘qQ1 >}ƍi4޽{mG͘1/vډ'*peHZi&!!!>>oE|>_ohin"zof2rno0s$/,`W_=n:EJ(Dx7 >|jDcE(dn766j|9)RGJJJBBBwرgr⊊O"Lf[[#jT*JEƒZ(`T*hBVrGGGooo6-ɄB!ND(b@ 077d2d a1`V/HJeIp>>  EyѢE $0@ `Py+VXYYv{{ 333tҒFr&H( F#A(d5$NFJ0 e·{X0`aee?qܹH;; ?~\PL0iٿۓ'Oll6L&CX񬬬b1RH$ BPjkkLPaÝ;wf͚URR2wO㊕}T?XWWGPFZRRBƍXRd2\JЀnkeeaXAAz9ZR@ :u*~!j]"{X0`aثaX[[[KK+NO`&D":URRxxxCUN 8p|M|{ܸq9RapB-,,:;;q"N'N0,44TԸq2A CX0`p$S?0tB033JZ^Lmmm<oh}96diy ]FPZ K ?G cUb@!W jhh0aBaa!MLLWjmm  N'---LCͲ.qر#ƍCQ cNNNxx%h4mmm$ p8* Лð66ЀB!\"@` A\nOy<DBH$7S/*j۶m$i;v H[n} K}}}{{)jkkkjjF]__999d2AAAJrӦM|>֎׮]KKK駪*///+4vRP5H` G/,//e";;{׮]3l1c|`%(J+$$]'JU(mi 'H(,$&7o*`kk;k, ͛7o^aaahh(L֊f% $J5qeq@ H᝝%%%b))J%BhMMMfffB޽{xyDe2ٸqX,V%~KK Q T*i4&gИRKr RRipps{^{.9@FnxDZ0D߿ߍMARUTT?Fþqӛ tIlll {ߍ;;af\RPP|~lCj777%7|WW2P---NNNxHVn{{=3 ,D~~n|jrpܗ^z C1I$RkkcS(bzY|$wQ 5 Օx[tlPAĀ3 ʕ+fܹW\A싋I$@ 8qbuuܹs/_FTl6V(Ν;7++̚5̜9\ `@9NVV֚5kBBB@` h!x6ڵkI$Ҙ1c1 ;}tmmCZRRHPK/vmoo{۫fΜG0gΜ1$%4󫯾 hĀBM@gO@@@@@ڞ3g 0h{̙hwܸqD⭖.]Jdĉij!!!M0B"==8쎎Zljlٲdǎxt~f„ ݚ%AAA})((pttw^cc9>J0544ߝ8q"z[n#O>ӦM믿&L=y]r9AZr L f=rHF/.0Lhla CRyzzzxx2777KKK.m2gɩEuuuϾJ ++FbD1uԯɉB,XܹsL&cɒ%Ν377}oܸ!NrO>XвB\]]+++˵`2W~.'iݹsGiii\\\QQڵkj0lȑmCb0et뺺xZd2*RnPx~AxffҥK###VZ5M&*^c #HPzޕuE3111SNݹsg%M뗆  *<<`1 BV߻wֈ2>~(:Л!0*ZQQà SvvvjL&QFtyhHDD,@k)ZQP&,, ':xh;) D)\`زe (/A FJyΝzk۶mׯ_j*0ELOO_|yttttt5kLvر-[dff._/P999h Mk?y ~}k P˗/GH$RnnnMMMMMͣG8Ϙs?xҥKΝqF~~~VV֥KP177'Ol޼_~}6E9w^Q[[D&._?oHHhܹs<@gΜ0ƍ.]:{lVVVIIIvv3gP^[hb c  F˵vZ͛7,,,"""n߾`JJ{Յ_|922bn޼xa}ᇣFb2NOEFF:u*..ի 0Re///{{իW ###'NheeZsN???[[9sbte˖e>sPE3^ O?j'N8pO>1r9B|O[V/*U*7ob_uu5aӧO?po߾@6={l-1 xbPPU\\Ǐأ.d!v 6IIIuuux242qwwwvv~@qrrz:$G\1 ֭[u;[l6۔˗/ .™3g/_~رYfs8Вյdɒpܙ3g?>44RH$&B!?2 <,^vÇ{xxܹs…4m͚5B@*.[l˖-x߿EpkYoa4رcW\YjUTTbݺu߿?za7o~zVV={F.|pĈ{ͭ[~O=ɓ'<OoaCbDDD|o}ٲe&J"䠏R`TUUj?%%%)) E Hsss#""Яɓ'gΜxI&766j `smwy7x\+X-Kln53c C;}ud27oOEx2{ >.d!$n / Z7@ 9t##^FQUUpq\r$Iwhͭ ծJ"HH$SRJDFV"HcSTB<1H$H`\P(PpFVVVHHɓ/rcƌxb@@'ObFHdgg' .\ؿ hn]̰X,&)?~h 9bǯ^zڴi*L9s&77VUUAUMMJ3f 2BLUUUj_gii"sΝ;wΜ9.\4iŋNjccȐ`Ԣ zwy[V/*5H!9bnn>iҤ2#ib2z.H0pZ(їu++&M| (?,---W`4îeLbBKѨjAb5ȅCkܹsx^LP"""LMG42w{|NFC7nɓ'Q؀A… M f@x6xm PZ[[k4< ڵk ,=8"(**jIII~~~ jVr\RT*E^H|oTRj5ўF!Є7ݻ7++ m"CR&kɬP(?,a(r0F2777T]PC` `dZVz 15hY"M F2Jd2닑HŎ>hV^ nbb"wp\.GC܃oEkii!.Hc0 >G< }ۛb]paŊgL2eʔ1 oooOKKCFFLJD"c*v{!1}^^VQFܗ^z 0Ry}~W^y뭷Pp'NȐ`bBѣְ)2w"RYPP`Sh4ݛ={MBe꺮`  %77H-qqqLȼ 6Y&<|\nȫQT|>_ߩVF&UTTfꊯi |>ӳˋ8R2ښd2YFʆJ...peFꫯΟ?Op8fp83g,//Gηt:deeY{  IDAT9E]6hr] |Æ 6mx饗 juTTʚ1c[X,Fy7xիEEEof XYYIII^^^\c__#GBfh4e˖%&&fffر `hs_>&&u0T!pbwwӧO777[ZZr9!n5lf-[fa1 srr={;99eggO6MK/2"">ST333[cEE]PC_ $_lmm{Ytl%2e `rr!% QkTi%]TWW2޵\.7##ȑ#uuuVZr;w'njSYYr-,,LJf{Xozj6&b8p.]6kĉgCBBL'(((C ZZZò!֭[Lfrrr]]݈#6mϝ;i&@O?!k\oaV{ݶmG}g<[avСh˗nF.>}ƍќ|rʒӧO>|xƍsQ*ʥKn%4$Zf͚?cԨQ 'Nrְ)9x zX*ugu222֮];qDB5?P(d=S(VVV#FU;-ᑁD OOPzd@/\ ~\,w1L~^S}ԒT*!D=bbB jjjZ[[$_~ijjruuп cff&JDž[qk׮a]YY) ÷lقf 4 +++ ^^v}PZt_򁃆bBE#VVV.cX {utB\>xobmhJ%*R߿oěG"ru3Vl/Ƃuduk׮%K{. $;j|gA!h. t:0ooZ1xԐJL@```pppEPTcǎ5RmCCC8k]T*ccc+**/_~Ǐ;88|KAZZ;v488ͼeffVWWx+ .455ݻ͛|/LP]/ꊋ\nggOGGɓoܸ!]\\ryee@ 8qbuuܹs\T* G9LPl}t+J GAV2e}he !A^^^E,&Lw $g }ZȁbtttWq@յhјNbo"T^^>IuFC{"!GR\CדHI&i9sbu֞~)y#H6m0044-yھ}; ?f… 3fgPzbA&1+q"˩T))d\K $X@_vQ" b@\.7F3f t:Pv?#"EFF=ۆ0 {nTT1^)hħ 1y* _@(T*Ó/ <]VVRߥP(b<@珑Dx@3]YDcGȻi;a„#G&Fp1sSC#~n:p'ϒ7nXZZjʪMLLBB,X󞞞]]](@`$=њ@F֖Jݭ1'Ѣ'((O|Ȇa'W\yQoT*---uOs0 o"Ŏ>'0 dz0"۵d2Y"d{d "E wL:uΝ޵kWjj*vww^~Vk޽{wȑ6lXx)N:f͚_!5͞={N8뛚?f!:tH+*immF"hD"{zz|r촵ƌ󁁁GRa۶mz!?7cΞ=mDFF(sW^9r$1/JI&SN XYY^sZs{!wuk H$Qjc䒧V@L$>>Gv/Rjjj.^8{͛7o߾mmm4iҲeӯ_l2>:srr"w 駟.]G0`hޞfJJJZZZ?;*}ܖrS/ jB&İAE " ("]~ .i )$-<̝9s{Ow޶~O?hѢ슊 B~uTƒׯATZFH4oՐBcƌSf޽sΕH$Ǐr^_jUdddii'|e˖uݽ{7**jݺu.[7+{Eу4.\bVP( ^vգF****++q'V'LPPP񢢢rrrv`عjB;K.\D9~ګWܤ$жmVX{$wryXX؅ tBzWz뭷K.mgy~/P( Qƌx$CX/r]'mJ;v-fCnqx/40ڵkS(//S3,j>T*`^FGGc;jbbbZA]D)0TR| 8z_\\|r̙3[nuVLL?!vG}sκ_>**jҤIf7~:IҜ7",K@@/6lXVVٳB6vfѩ_5.QPPSG?^ZP;f7b̙3g0F8!!!jժF``uK:fߺu+<<]X,*8rjo8FKbC򆶍B7nի*++oܸ122rٲeeee\.wѢE'Nطoϟ7oСCo߾3uT<~|a ]x1,,r18v.J}5z+e"*++<r… Gѿok׮)= ͛7'$$;vlڴix SNm۶-,,{jj;s!՚`m۶!fΜjW4y ]&3(H4#>>>RymmSJ2s+pï]vEr]mv}Ν[lA۷5ünݺ]o̙3'Ol6[՚L!C;w֭[ؙʕ+7o\ddx_YY?!stSOn݊ d~Vuҥ:urb:t($$DTN0d2IRɔzȑN:edd;v$IfZѣ]&FAπwUL߻wÇ?x˼JhSԖX,CӦM˗oذk׮k֬t6cڵ+**ÇX,N_|yIIILḺcƍG9i$\ùcï^rח:ԩS'&)=rm>}y睥K?^*b-K\E~~>>:eʔu]|R&N>ï:???<<!4gΜ>;v쨪,Yꫯ |xY&=]xVq2ѵ_1vׯw-66+!64**!sR/u[/4++rKNNNNNt xcRut;zR/\Aށl 0xत_}Ȑ!mB@ tݳTX,۷۷nj3rcǎ>>K,9rի/_ ƪUB*j͛aaa.BӥgggϘ1#661-SHrJ˧@AVfԨQ=\O4@qXpX,JäRIOWDkAg< wwNdxґA|>!d`dpxځN:#a6]СC}`=NPTBz;WVV֧OFcǎӧӝmb^|EyNLFϠA 4o޼ݻWVVSbbbvK{9^zT_rAlzQFy{ߧj7eff_3go߾!C79c4q^}?!4wܹs>iB\'8xI׮]BLS$&f0{ƪݻ6lذj*HVf۽9>l9]3i`[wcpnuVL& RR+Vh0}z4nM/q*P.vjkqxc$Ko6k,άxַ=x2FQs\XLVDP8p^?P(tx7faӧOoRҥKR)ֈbA/^rJPxxxtt׬Y|lzn?|ȑ#+Wܾ};|7l2{wypժUl6Lx[%Mf͚|g/RV?^zĉ7nܘ8qxGFF>sׯ_X%{7ybZzˠٳ"b gϞ3gN^w=l0χ*++g~㐐}-Zhʔ)uuu'OrСC遂^xb@0k֬򰰰c x]8Hݹ}ԩX,V*(I<\6m0-8]ݍ 9I^B Z,n |\.r5$v=x5g&>pmjjjf3IHH@L&6mX4 `"cw!W\̀|>ׯw>eʔ)tK.]ԛ>)N8}{|w=z8}"""\T ڼyPrvwY<>Ç?zo3L=*Phjkke27-N׷oH$tPq;TwlF{>jTݐjn˖-aaa֭{nTTԺuccc`.1j݌dj2,44GPx߭Z :|>d2?"f3b0 OXOtF@EKP# L&MIIB8ڡϏd,S2:X,cfsp8 .IL&ml2j _4k_}޽v|$Ibk e48IśL$pKaa5LS 0XrݻI"H._~b}GmK CvKҸ\L&sR[[.$ mh)ɼyfsg6}iI$h x L_d tŊ~ 0_N$ `ٍ i-\nIIjŕw_Tq)۷oflٲ h7@;+\) & hns;8 ml6X:(BΝRǏeuZntͶ v= h-ܽB7nܰX,l6;((HP$i4FbݻwqqjeX*J%%%D"7oތsvCҩS'(HЌiC IDAT0L8& h>n߾:a x<C$ܝM!TJ853 ԉ/O?h"Ih4| ζ(Hd<~j=m޽{]tr|ŋj5Nذa% =l6ʐEW|}}ۈ^PPCrEohΙ -fPt^dh4 BHVp8Vdx(H=B+8S)}D!)8`ɡ=v'$f ]A$i4JDB*V}ybwv:w [tФ"|&{QCCCo޼IK_2jZ$aۍFcHHH]]@  7[zz:  o9U*l` 6%H9tka I^$!^Fۂ Cxm$I7 @+hܹϩ .4 Ȑ6+&,>=H0 A @e֭ 8&$P@A $P@A sذa^66&}vf_hQˌaHM~閹&1{lD֭&L#1 x#MVm~[$}geee%''ʐ-sM>l;ܾ}ӧo޼d2\2xZ@Ah,\it#Ò԰0mphiҖ/_.zuEym߾}ڵ?;Ϝ9~ذak׮GMKK ݺu[`]5͋ y7z=OUFUVV<$vebccG]VVm6-M:bŊl]IƏlЙ3gE$/xO駟~gϞ!Dr9|bڮ]{ %t>*Ͷp.]~]9b̝;7&&F ڵ˥La$VرcT*]lYnnnYYŇ>SFSt7FFF:G)qƭ^://h4ү̙3Zj2&OpB裏 v|yDrH-:qľ}|yzm664-_v;D8p`Μ9uy999SN%b/f7nD]x1,,,11y<[ld;vwn̞={իW֭۰aüoӡC,XpԩX³d͛7'$$;vlڴi鱱 0ߚ &MݻwppkjjJJJ<6mZjjUUU%33?999--ޣ bǎ֭H$;w^dɁBfyʕ۶mݻT*0a@ 00Ѹf͚[&''GGGڵK.>|aTXVt}ثW//s=ݎBbo߾o3fLcnrȑǎKOO?yM O8sqlJr<|>I%vbZ,N`XX,}bw07RJR x}n!qʤC<~Z;Sx^JbABF2tt:]zzzvv3bcc-w0?@A&חr2޽{wfsUUfcXΝ;3fϞ=山EEEs</##갶dzj; Bk07p8  ѣ%%%|>_~<~8ǫr!..ݺuF 6R|f  @TN0d޽{7""F${QRRR^^n5MK"x<^gӱT*&%Iǧ# ѓ2hРA͛7{Ѯ] ƒN2ެk׮6_۷7C.]zB6իgn[B(++/_GU"W@G(򦒌qGtt4p_oWH r'|B- 6Bwpw&o @yW<řsssT***ZTE#JJ FSFZzd,+ĉsrrxSv۵O#F1b}or`tyݏ?ޘ% Ł^x @Gy<^~~###{ׯQF}]HHٳg " SN'O>}7|#J.]*J=;͜9fmٲn!brssg͚/:~>BH,4h+WDGGG/_sxLq`V¡J۶mkdp;^3fotnݺz$,,LV/҉'nܸ >Iu7 wh| 3nŹqNeۮ%ٖۑZH ̙3ϝ;3~۷^R̟?_ݻtŋYϟ_}o=`ڳgϞ={ BCڸq;zh6|#Gx\.OHHh[L0a/vكǯON-V^yxZjԩSLqvRxwlذaΜ9YYY\.^^a$+W?{ :t歷ޚ:ujQQݻun$Ia6ٺukk]zx. `۬`o߾9i!I211s+O`8XBzׯ߂ F `AF/SاOҧOK.>|…={`$ D"'^r%,,L*C=@℄Lf0|CF3 ޽۴>Q D"˿B(%%!TVV&fQwܾ}ȑ# o \~I B'm.\~z@hϟYJ@\IZ>>?C^$IeeD"1x,T`0`]vO;r\$xPhZz}\\͛7guuRtw4""ϯ.kjjlΚ5r'p> +Bm|JOvlJ^p8̊UAiii<[V)AAj( .1tx h$F`0?!Vo8jfBHO?͚5륗^裏Lsϭ^ҥKK,o]vҥ/rmA>/^t >o׿p͛7/\pر}ܭ[;o޼Ȑ7xPomҖ-[&}٫WY&))oر2ӗ/_.zuE@K.=gذak׮u'Wc 0xۡNLv\țC-LAA Y,990r'L@wܧOf5t,mOF#P(ƍz꼼Jш/Zĉ:t۷l+v؁i4jSNl>|ƍB/^ 9o7oޜpرiӦfϞzիWw !4sLV믿Lɓ'/\ZcmͩSm=55w9tj[`m<~ر?\*.[,77O? ĝlq8)ٸqcdd$?斝%Pr\_1S?l6ۥt:Ao.XԩSs w6IM89fS(dR65=ՁP=9FIoI%wA%&&*J&R(W7Vo߾c:kPMŕ+W9Y={dffRq@SUUeX2332Fq͚5.]¿ v튊:|.ÇX,N_|yIIILḺcƍ)S[b>x(mǎUUUx,YW_mPo'D~_3gG}T&Mݻ7Bh6l())IJJW3m4 %72qIaνuuÆ .\ѣBh͚5[l !9=᥻D"qNFA5v^ гT*___lbBs]Yg`P(A$d2I?0]Bdyy٬|W6m*//ӦM:u*>t]m6>34駟 Ϟ?rcǎULo]pQ{_:$*WE;wJR455RJr~8ݎ;ON//[XXXVV&FgXHBaDD!t9b9|6|7 MCrr2,&}gáx1w7#djdKtϞ :.MaF rϚ5O=Լ`eSSS^TUeZqqwuQQPe1:ZXXDF-lzzQQBϯRRI$Պ-~t !6b*=\XX>#"" _YYY>}4MFFU_O$333E"V@e4/;38ˈ`OF=H%'WcIM{K};wrzr=*=점;;yRA;@Ap>䰟Vq;.OO-l5r`uuu>&ԧ(FDFe0$Iz׋7m7a„@Fp\L&KNN~׮]}|| EPPQ( ry``x,b֭[[yֳvTFWa$\] e2I_BZm[$G(왘6<&&r>իF.eNp v#I bDeþLxTݻLwh4ZzG/ KEP~_X5Zm/yyyy!Dˍ;]捻@!D"l%IZJ*2$SNk5 [=z4%cc6we-PpVH<7`0 AAA]28V㑑+<^v{p03i2^r\T*#f3Am*tF#ŢgP(Xo1L&l6=TwDYTF[zV m*nqqqnn.˥2;P[[+ɚor<--㕗GEE97xb@{E $IGx&X#wKF___\jf˶a@@BC%H֭\.Z?rǀD"LfZt:]II jAAAgh4&H$X,K;psT*ոq ۷jumm?_ZZj|||fϞ|ػwܹs%_{5x \`+6$B8ŢTqm:.vX뫪zRG)Jտ+fZؿ1$$ahh(p8Β h4b`xtږYdIbb#\Yv-)^GNVLFNL]-X>|D$e0 @c1$I Bߔf(M ͆Wz TIY r5$-K6"lgE"ɤRT*z6 / ؓ 鳩J2we ^o(gKFӭ[7(u….]HRʫ~C8tҘ9C[j]No@KQMq߱pDRd2U*TJK@@/ FK>>V !!!8!S5QL_tUUUUԚ//%IW/,,1Lt3Bhoknܸi077ðyqQ%+ @ ž={{ر?dAohZ-&&BڈI$GBB!~5L^^^^^BsXO;vlgy!ԥKAyyydd$uuu8 Zv?.&搌$ILAz$Dit^z9d-V9ӽ^g ы*A;3gիW{nIm $?oZ94%ppʏ7_~ v (HX rrrٓPQQT*?/~wAYև[L&d2DGGO>xD}rss=*VK^'fcXJR 0LF#H `pB>}Add$r [+**l?;w :BP_~]*+V$xx(шH`pl6[hhhMMd 6LDa@hg2?~ܥKP!K~1LRjCCCJ%rJR"h4j  [WW};uT[[۩S'f2d2Nh4:.((a6V% u L,JA;~)Sܹ^p85.ιx;,(g_8i7@G jqРA{juuuxáq͡:O!FA߉7*V[nB` !.#~Ǔ'OꈈBaٺw1Νu]̶sV'͢ÓXrv9DmQ6+,sWbc\.홾X)ޒ&?R>>.ӚWUUy84!t32'₳p!C fsmmD"(xQ>~-.!JU* ruP@A)(9꒓^h[]vMDDĽ{c.DZ/ÀG픢[SLEm[3g!x"oP@$H"  eI"1ۋewK"i*R䰹~lƪԎYO S$xqwKs;=߿MLLl>=5.'9AL&`'j;zJ zV*W mTH@kA=fZhƕi22 iP?3 f$?!7E(@EcWeXq/|u^S$xzMaaL&#I~~~Bd2SBGƁ=z$ɑ#G={?OBB1bTYY%%%8H婨hp@`ϺCĤ j VS#I$sz,A*RKL&S^aaa8}_pp0V[@AR*.\HKKxT 6к0>!c&Yüϵ0cp M١3\dÔ ZCapWN Pq 4huGͷ|}vN\ud=MukzFsFsfL&&f- ñvX,@ʂtP:nCW\n)stAX]]-J-۷9D=8ۢ{Ν;W"?0F\\ܴW>ٰq y`JzR_fcE.|ٞK ߝZSS ht [SSc49NTTZl6`rfD"FCUCjܹs!T*LJJ;wVT$IGDDt:О={𲲲`Je4+**|}}lvmmm.]Ouuu.]jkkF[\3T$… _}O>!׿_Q/ab #R.7{{Ȑ!۹sɓaJAٳgpp0}D:~{'" rt+T>z)L_}UppMriӦNsfPw?RrȨ7BtvEVt:O? @q}ڵk.67~=|2o9Ƭ.K0 "<<(H Pmm-^X,De4Ij#8á~HdAAATh;f{99G7?S ގw}6LX`A߾}ccc/_>zhÆ:Ê ~X>}Sj-[VX1raÆ AA!Ν;gZccc,KΝq"}1̬~ ۹s端G%$$2d޽CT* ng\.{|RUU%M&5efQ]]d2`hó`tT>CX~Ʉ=2bkAsUR9eʔk׾kݻwׯ_lll``>'\ƍˇ 2uoFTҽaJO/TmDv }1gΜ9s$ ر Olx#88f;Px]Xb.+HUYY (-[;!^~Pv  ޽oѣGN޽{7o^`$͛7B))) `QveeeiiiPaGG$ͦ2Rm`0t:\E X,?v!Ԧ1̰0qk-3ϸK h `-hL6BaFFFFF7'9rk׮) @䧟~rʝ;w^|}5 $$$it(")( 6lg9;vAwYNCE_AT^)s@B}>wa33,}{}aAA!JUVVuuuG$1LǕdddlvYYFԬx3UPPPRRzÑC555 !:%y***8󡼼|dHI&m۶mnnn&i&??ݻQQQϞ=l} H0gΜs璯333-,,h4ZffiϞ=!>F]]]x"9[BSSY]E"kv0o )6[^WWqk\.fz 0%t:~5BHd溚љ0 GYYbыdee)F |/|A׷yf{{{ BBBȓ=zѣZ֭{Epp0 HxbIDAT!Kh6[eee!r (~OXL|RIצjoo߮*pGG/}8,®Bѫ锔Zq"t-fhh(|,!ONܹԴq~QZZڝ;wRSS /z`H|;6>}˛@.r:B⮵koԁN+prrʚ>}ӧL$YYYSSӕ+WVVV455:u ķ1$ 3fHLLP(l6{ϟHMM޽{~~СCsssLf^^B ={ "2$UWWȇuߟ\ Ȩ4JMMZII DBg1cBU|(y xdH"==!j*kkk׎;|8BNkjjc!p9?? ! ]@kG)**fdd$$$_N4YYY>|acc#l3%%b #'֭a\jMMM<^G8b >VyL{3gL6 !DP<<<<<CVV""b3QW 8cFrqvhQaL556@0!AQiT þvkx|ă8|ש2QHLL|N5q8L$HEIEq]T A,,y9Eg9j*} j*d)*)=HJ5tF%1r$&g`BR)z !  pq r!D.BRT*F$tEѨT0AtJR(  ȑȏVHZǯ RgT^^~+ɷ޾*a0TF]KyQƻ766@-G"S#G.@JB0]RXXثWt7|azյ7 ]3hkaG:C:'m:}y!ѱG3f]~ ry{vdz>kqp߹w|_t澴R;T||f;xr0t9G1A,V_tmCcdd[TXFM\<<>y;6A;+6m151v'b.Z0 yORn͌m]$HBqqI^\A! m;Eѱ7CF`cg9h2-wؗSMM HG<8yΐF-m(}}ajZQw2񣂮̈́޻o.Y:cR<`7nO6cs$.)%ePbrባܘ OVX\hdhlY.YZVfm5 rY?svZZiYztW16KHY}Ӻ'.bve_Z6zeAnx>WJJ#!#ᮭ[tuZmhY'ledN?ݲa]C, NҟW5_\~liiY޽.Y]_OB#`Zn!ye8Ҍ.k6O4`lnkQy62AjgFn2gX4[@ EG)--;vP|̡GBuu#Wut֍?p*M-oL 8BpQScs!BRs9y¼%KBѱGSomٰ>>J >~瞽ΣeؽJز).wcbBt:f/ [pt[ ZE]MMMUV;ز/&B|ɢϜof-G>|?6m?|BliԻp'ܺ4jDCSyaQ#e֮9IB#FEYgffjv$(x Erϟv̬.nŸ.K(\[WgհeeeM nA{ FF䩆6kaaqiw]IJX.2e~}TUSs_%\HOWgͪ;wfbjbd2f.{+.131ZҎ:ڻ1.NcLMUUTf奣]_oGv# ++6[qNT-,taF;(Mawz0SQQ7;+. Z-vmOrB/_bgۮfWx'OXֳQ5HG[;rR }S\#G"{6p8˗l Gk=Ej Ҍ.0Į#ZIޢ]hֿ{9xǛB̙ [޲0a3fK~۱l&eᢢb f}S 465! --g ?m4B-ƌjur6[bTyߢW 035%˳X}z.(,t:!$+h6~ffvMpj?il$_$%doMMͫ%!jH"9f,dr8ZWNpvNZ҆ c2/ oV6YM<^3S m2Eё0L/e ki(Yn0@'N,|,*,>Oŕ׵0+WƎ *9*w̬ˉWWDuOmz?tupeF2e<0 S[e 'o3qq*ݧ?yc(}i9w㰡&ﮯf&2bAqm# AүKh3z{͙}3۬YutAtqH  &>olki( i .0lг[PW@AwEu]rr2+a[V4+{M+:źvw,ryn)+/VAQщSgΛ=jPC}㧹FzzAd=W8rLLND.JuuuBt R{7MOrkjB͵`fSV"Aˈ}Nŵ)Nr 0>ٳy lo+ng`47'9O5"y$hii1/L-ammSQQgXB c1~foܸE9Cf*=]87!RWo`0|<D!r>}$!T[Ww)jYyySSìlխ[7auqpV_^{sJl;iձ8Ç)((9;mپin^eUՎ={54ԛ]'~?AEeeccɹ9;mٱINNUUuvyN iHCMM?{j_B[wEE߲feZg\ BRG=j ͊미2~%8;i.H;[ܼq>lF m߼u-(hsl! $e\xQؖOmFhupƽRce-WzBvg~"yNtԙ6!fOܱkh? P]]ݍ'^ktjSp= \q==!Yfѓ>z]t:!8t@HYƨ[m5էܳOBaZdE_`BH_5 "JA1qS|nݾmc3P\_޾+}e FL\V',4\\!DRZm\hq5*ǣGf%WZP!L=sZr@+VO+*.KFFFB#m_MMM-7[Q C7i(tcBo4'Wy0@nvsZ>Æ'kfEEŸɞ(`|`~fah`m0i.מ]&b$ޫ" : Z ~gzڲ Ɨm+5 C $H޾.&i2\`x\pIrr)P4! S9bAۥzeyeXSH_YZ AJ˰䍍?:l6BI8iSlo{ǝ8I&LtEJ̀{:Z J\h|fy666~mzxm''F? @{,vm$pLB!_epCǥɈ7f}dMunԞZ{hʕ,{z)1bہG)--;vP|̡GB>ޘ@p6ḣ&\\.c,YZ__=z;mˆ1TJHX?s^gk:/mǤ;דg[;B@ٶiñh&)Zu555Uf]WXNeaKNq˶чgۦ QWZ[.PeaN2}Fwvls1ں呫Ǻ^:wvƟF8 H3r[E`:]8ϟ]<ޞZ˪3jXhF`[ظ$%G, V2iblvy*J)׹\/V.]bldfUDuM흻A3gsq151f2RʥKLL|aiEЅH(,sbdh8' n-o3SSUYAxyhkwכ鑝!T^^+**Z@{%vIWWܯ'OƚyCA$~x_[߄Bt,)c؇Y>4<>=~!]oUQQ1AO AcSڲŘQ##VXf]ja޷k LM,V޽ A2ڻo`8̌\N) $%doMMͫ%\)Vl[meeePKilDX[Zzbg7~ ++{1x=.㔚ȏ م a:?}s*?9=~d3!K^A }2-aeLqiT*Sq1 #Bybe '88ci s8M3w6t҄"׬dRH\ PJ&{wm̺xuEjk[7_\b<=]jBTE{uӵkMRX,J摡o ;źv[EE'NY8oFOs z>=0,7/D@uuuBُVԄ̛k=RͦP-:RH\ beǕcuNYy9 ?@p6kw ^JO88び <OF@ y~=˳w^{V?z':63b07g-w>ͫڱg45?lllvy997g-;v>ɩ;~RX}뮨}EPXHMM?{.,T[Ww)jYyySSìlխ[fx<.!y+B|K_XwybM5ϮU?9SWNDfOeصmi)[M{yާ~=4z{NA/ 4z@!AFWTk~p.ršEGDbf;hP-VćYS||G9\յ#-w`ɊH8W}=wz+,d?nPL\X66? !h4ѣBIhAuuu7n:it߼~,!ڝrɞdaO_?Е IPUEF2ݢp! 7o:oܬ({a$F*SUWQȐu1mly@ncUTT_d%ɇNJpt]Z|=]mȎ ;UPTTTTl=`Lԩ@Nǝ8I&Lt1@g||IENDB`crystal-facet-uml-1.34.1/user_doc/doc/screenshot_2.png000066400000000000000000002530531415120503000226070ustar00rootroot00000000000000PNG  IHDR`v3cB pHYs  tIME #9;׺] IDATxu\SlCTJ1@0b+vab &H(e R" ^~GN{9 FE"@$H 4E@=jMuEi1N@UPHJz ߷l*J$ px\6%NiŠ!DR""beG! CD","JR5p^ AT15j& Wy n@gaߨKDdip^ /:WG.cf߯I/R]]}/_VTT $%% 䤨 " JJJpWVV8jH>>k#6؜⒒R uXZHExo8rН]b~74OF<.%pF MMMM U5پbbbPP֎AT;SRRhuu766655<N P/pLx-GJ3CB;}u۶{Giff%++}Ǐ}`?REEgϞ'%%ݽ͛CnXЯ_vʇIb⿴KYYQ2v Bo߾{Nffhǹ3d-'32mK p,KHHMvK SoHٖh$c*{n~ä`T Ο̌BO<É;iXVg R1cΚc9&{m.\\`%K[٘F?~|׮]c6m(''yBѶnvy-^ת=~ݻG;:nٲY^^$|}}}/_^Zt:}Kdrƥ{ 0{?MjGԕ%,.;gB9zT;;jI`x<޲+ i㬿!!qtuU}6vQQaa @0 ҫW';wnȑ|Yf]xQ щv~BHt#bGv͚5kMx_e)\h'?>󄉞fff=zhvQTTDR說M6ݹs+Q_~u`dd{={q/~`nݺ~ag$Hee勖}"Ћ/2þ ~|WXw`%j%&TYYŠ JJJn8ׂI$D"8NoזEeeezzzUUIjX=&9s'5615''+,pիW'%'EFDb}g SSSMX۷E dɒ7;й{ZbҰ˗yJTTw?':}L<5lq~(}}}ԛ7qk׭믿G}`h0qҥrrrW\YhѱG[^ޫW^pa;vr功cGG-㧬̝;/ ~a^^ύaK+m-VlTڴiSHp6AǏϙ;/GA-ݞ8|RBT!55zOѕM FZZڇ/|ޣGM76k'Ol޴QOOKrB{Ξ5`o[E'e>V]NjI1y[߾}k<͛۶mӓ~=a[pan.7z5'zV3x'SD"e|yr# .:y`ʼnˍ >k׮0]Ht̙Ȩpر.mڧTj54ڷ\;qKؙ\011oPVVF3bĈFjk(B"¨=~"Ϟ:=~o:99ݼq\PE7|3g6Xgg7 *A*++<50pOGYy݀op/7)Y/iMr…UW.9Rn)1AÆ=~o-jԡN_8`?E.M|ۭ/<9ùsns{דxRRRG;֊$?1~Ljv$-JkY?nɉ>zș19ԸԪiΪjn>ƽg?O0AZZzNNNשּׁ;w޻w]_t gl7t]ˆ?~XDDD~^F~sBBaÆ KJL$Erf~ k󰇇ɓ'g͚iԸ{xXYZZxzy<H .pY|eGi) +CT qRc+ҿ~O,|||?}@%[oAԬkV}6Qbz҃s4}dlhi://^秨`hhӧp!!!eeeEEEҪZٶK[熤BHA3t$At/ֽzW9YEBx`LgOXaZsuu 8qbU:::NJMM1bsW.=/)/K{|<]w&8+22y_ wvv>rF;V):-JtW@@3f4~ykiUDI\ZRBZJZF°`kk^z5ի|#K0lBBэ7dLg&!ET1,@D %\ ?ƍEEE:*UC;wnk}&d墨 Ms-[߿y.Zt͎ڵlll̙C9;;Λ??Zj7_IeE$) Y PU/--ݴg׆ N:3r9MrHHH ݾ}gW``wb0l '//*"6 /5捛! *zK[tS6σ! ۿر666 :eqRRR?}255c2Ó?nggg !󯪬|*֠dJedo ,,le1˧:B1Y<ڕ;Np8Ls("ivxy''qW뮮]Vh6F:;0LI>.Wph?#ƿ+w?X/ۑ/ h'_H"* @$&%`֔Gl߻pYƦ:#9 l6Q^[^AKߥ||(wBi]6ק :bOkHFJqx^?[b IG\⇌WC/ɚԾw'"gM|r۷=zt]~ڨ`f5 Хx߿,["~hӧ~̼'A+V9sYLP[ێIIIfUHF\,OMPBlM^qCRmaMMM'ձ-%ȳOOW4HJJ*((~fР]y{6akK6olcg'a6ҪcId),9 '-=21Y̡Ç8vFHK8^TT_'H231A '0B-I9;ef.yRD}Z2ɱ0B<,TQqR뗴t*JUD჌L$$1|Pq6---fz t^i`~\!r{$p}P!ojelj!999 FFFPC RC%%%LVQkBkZA0cEK;qգi- -hhc"##[ڬ`p\xw=Bhnnn !daaea%k 4TWWoiv qqfwF$?X5P[Q22/^077p8!"ta!C~ƹ;ש3'|뛚:}R E+)ˑB<~I$dk*o;X!˗Ht:ͦhT< %!BEAFH!6 %]XB,ھ6싛KGHj|锔xM Tq߬g`s+))AU٦eڄ[+Q[uoS .\(wr޽F eQ%aXݡOMwQGŠC 4eʼ#ܚϜ9kݺ!đbUy芥+v?o޼6|l~ޖgz!BÃVGow`/_ji<O_tb_nڦ?P(EEeeeCMLuttCJJrZMLvh߷W^{G4qx$@6BWDB8n?+&`qR!Cl jdG!sssGGիWoJwFoB{쉌o>YUo?SFFfF ;;}~VWWUV\c" ~Į!~N.d6EJJE=_=~bۡ i˺o"}?<-퇹i̱39!;aC#mC#BCCDb}fVOiUyv߷󫪪\ƺ.]DLLۢsJH(GN^! `]lʪv?&& p 5hPݿ\SL6431Df5ܘ}$V\y MMm۶5 "݁=78߿9 Q))G81$F1QfhsTe[JBƍy\%V o˖ڍq~s'$o}آXKϛ7Sw/uv";7q:wz =y;)Ȁ-P $$qQt&Ozhga*]P7΀T^^>i>JZ'oˋʙ#Lϓ:04ťy_BBٳg»6]+=L+WtW`'Nص.۷oag]4"`XUCEq[3cRSSƣ톽OIhI; WTU㛯>13mdDr6TTZR>o>|l0-u"3#$f\Lyk}MB&Lt)<tיs?}8sؙ{R}L'<2+mcwa|&H$2<~855?ݳggZRbl{Z!ÏDO=}e%سgφ VWWptÇ:uŋ:uGvv{!$%%?Z1dkk>d2b hN;Ax$Z0 =NA"xKO&歽FQ/YXzlc:Hd!m2^O;'}ABO y4vJ][!8#CTMmJk-FA8?owB#F),,)Sƌ啕|rYYwމF U:go tuu=۷}^P ݁4[bl6'Z3!bH\p$" x+UTTRb͚5sJ٢;Zd̄?% cǏEEF̞=GLL67/W[[r%AVF&;+[EE۶n13p{755ypEnO tRrrB Z{}JKKhr9ޣU@Uj(Ӛ>cOO3f̰ñegQ|ˍ8\|ATXo/%''GEE> ƼwyÖ yI e 6n<N:#?87Iߑ#d4{ S!k+0{֟ vtҚ~=/393cMxiiiyyI^#`f>IRM!f̞6C|fٲe'OLJJѣoأHtzzzu_,i5,0L#??_sPKr5a$/ )ޑ)GGǷqEEEVǻ3̔l6[0kkk[waXKCMv$oĘK͕nS"%T 7B>6:q Vrcuʴacp֯NO}PsQ+?/vP.(VRRKgw'qb<gs΍;λ%@##n LII)-l%elMՇ_!Bi5%4AROII)b|t+>iaO6*/./CS!zHUqH@c4wB*l=2,t>z)-7| ~r}$**V.o^hf8.7^o#GwOϟo4ցZ|AA陞>a„Ǐ5ݻ\.!t)̱'QB60ClߡxNNN>>>ӧO0dVVV;DʰBK{+Oԣ%Jyk_^6?B$ Rzz{G6sc%ֶS18SΛ5y7n"6O<믿,-- ddd$D$ލHK8n:/AzunJZTik%` Y z <#: ܭztzϷ̏o\=}2:nD0P~ ft0%*0|FQzpwoi?See}IIIll,蝑#G޽{ԨQGutSW!r>֖5WxIII%t`{ &: 12"`H餱m72ߚ'w$HL6\BTAONtӇSG$%%999$+#3KKKÒ\?gʞs7l뗘I"͜9͛{믿|}}g̘>}\451"??ӧNRVV={OÊZZ޽:thUzo2aj-ށ(mP\\z/AX=YYYKƸ1;70ED"f#ʦ͟dH'{ivnР*qv ~p0=RL$bJ֕cmB {,:<*mf8z?>>O<).. ov߰w8;0+ ME99liqJ}Z׫ ;+¼3JeO(bqKJMJKL?٫tGbSΙ$7 xyyymm---m۶rkWèeee]`2!..kVVV-l"߻]w[޾}[WW'##aXX4HwHZnU`XYYݸq#-U=JJJttz.يiNJC':uNʊj5Kks jU"h0zСÇ 7Ik׮_fMK^ZCC#00{+ELgcPY֯_sM۲o7)8"$/|qnayUlb'&*F#NOL'^KGTTQHD$KArHD,Dg:6q?²2B ->ӻo2Q7ۧnhh̙3[ʕ+ܷoĉz؈ikcTTT ϝ;7cƌV67n\p,%!F޽{ΝMO;ꋍ4nh{ѣGHN*AJ&Mv?E0j8[8[\tl/ mۡ%vUU?~*$$daaQ߽{7|xZjӧ/^\p~Ȑ\& lT0Ⳳg ?έS H$"{\7@4T*UOO ðKb$T"tߠ**=BEEbM8>dAvK;~Р^^ii۷oϟ 6wR X:..N灩nEoӫq Aq+z8jVJMMqFFOf>x𠩩YlNF=FSQbb" v']ѝ#.~le'm6@wVcg 'H;6l,?HB7aAOE1ťk^ii)G8\I|| !ufO/oOOFh7YZZjdd\͛:>d^ޓDB8rŊ͛6v0y}]=w#F8qde3ul'1d2YDTDLVPP齧?Da߿/'Lݻw7 vR`W_$Q5"a]]X[؜]iMCgfTk'JW$Hn^qNAAٹ=]NnnC f*2Pttt&LhbF1 da:ozTG|pWEBk!I +JJJ>c2}RSS{,v! È͔̊M& YlVJ!H,.))4099CffTTTЁYYY,6J+..ׯ1;w4\?<''ڵk1ϞveVTTtJnԿǎ:;;>|ã᪫W߾}{ĈLM6 6Ǐxqv}<'MiÆ 2TP8z0h999Yh΅۸9AD`4\ucǎ9~p6GD% {{SNH$.{28dD4@!Գg 'B TS[6 Hg2>AR { r,Ǐ>_t)##O>SL)((ȼmB}-[L2%((O>=z۷/JKKq/(((.XF =},9;'  w(sz :#;%H'd2}\KN˽1!ڍЋ8N4i5]YӦOOQޙ镐P 3gΐH'N4#ڷo߁hȑawNvڶ6lGkI]K-^x1XE+"9t:/_.\+Cx,hs:8ɀœ}|>|8x͐W^+**q6 :X[2I =ݯ)YSS]SXXfq?r!2\RR.v4ک644444D[K~HOO!CAUUGvbڅΑ#Grrr233 ZsB_ $D240~ɸqn &c͢ӟhjT5F̝+B:̌Mjkk>F8:~x}6xHZS]QZBgx\^@ DEe!; 4H$h6f(O<+/@k|)  tq)"s@A$ AH50H2P$B7(_( AH$ A_ ~#7n]]]4r4IU H©>^볣F<f7vCSkjk[_UM[W1?ED8;9򳣆 As ZZ[\RڳgBew'잩qu55 ;3cs<$oZS[+-%ZWSS#&.VBꚚVV/p8"\\2Y,*r^G͜6@-P("""ͮ%5cx<VV/yGA?¢'8VVRrq8*H 4{ c! 1 STo};w]F&NQ^^Wg_]rH alv`46T\LU_{:٩ ~SgIi B g@<̻hZZy_=L$EED,m-M*{'$=ybɢZY:{"1εkRS p\W̏GO;KMM3f v v/22"avN.6znUY99Ad~P5gҐAji3#`A^(+;{#?~RTT8rB$H?@$Ҋp(V8;;C!$H|4 qqq(FQ((#FT*Hq ݻMLLFv!C@Qb (dذaPR^IkDFF^ o++++--EԼ~yMK;hť0L򼼼7o1fTWWz)))qqq^'H:݀0 0Lwx&-RHo$B)p (R""zE(Eѫp,^P){ll7 ! &̜=sygΜz&Nh^^^Õɹs+SZZZtzFFư0577[ZZ"}}},Ǜ0а0;;J53/pbbrgCuRs̙<]]]ׯa )Jf8D"|VM_xuꔓᥚ>]~ڵkvvv|Bرc&L8uTUUջ#w}wҥɓ'ϛ7}ժU7o,]D"۷t+[ϴ+VHzf̘q]\޽VkjjB7oތ= dgg+J6m8Q.x<?BJ/K^@`h4V9=Rzz7D577tiӦggg봶/ Bٵ}'O 4Ǟ^rKWub 6͘;o-%~kg΍}=OV;hO) |7ܽة0W_%HB0!!|`_|~GGGPh"GGǧzF^:''Gӕ$&&9rbϞ=ϟr_r !.ZAOzƏO.+J 'r8kZR}}=˥R|>!$-,,B`@ܡBk )PCCäIi=c>gGzLh"~̪qMm17-=c664'hjn9zk<'>kii='O|QSSs-B@;CF}}W^yt…'/%~;;;%>lNP(1 ßį!ӧ_zDGG߸qEGG{xx\rL&㗩`0x6;;࿃PrD"{.a,!d2mllܹC"ڪhjkkuCCCjjV8q"ZGA\s)aW,[X0w΅/,ttO3{+Bh^b2HzfS"2߯\<{n~ᶭ/"v v'L5@¹;vlŋ-rij@mmm\K>X M޺u9rg͚5DGG>>~)B(00Gb~X[[ K=<zѣG!: k뵫V~)[P(?_όԴrԫ?teK}y*ϯLǼ<BÖN|{_O>>&&,X4ΟD=믿.M^OHHxwz-( ?@rwwwrr2+VXn# =s F]]] Bk$0vP( BRi4Je|>!NC`)FfX4FX!`K$*ATǻBF [;45&F[DBKk0dof2AAAT*c>(P(ڬV*' ( LF(|0233#""lmm!:Ś0aԩS% 9Bt .nVpjmmdЕ0\.յNFC34j5ł8`juGGcNRC9b1LT E$0twwl(1.!!uNRݺuիyyyØ7q8\3`8i4:0ƹrj5eʔY͛7---FjPA0N#׍,{{{5YmffU0 T* d2c`t: @2eeeUUUZFM8ʕ+SNںpP||qt:c0!FFG&wttljjRvvvR444ҚiӦ%$$xyyYZZ1KPb@*_KKFaXx~YYYd2O"Ԩj6n8<+˳d;3RLJJ R* !RRRR@L>@BQ((K*VTTDFF2LJhONP srrBBBB,+::ðR<}KKKxx8~FRO4>P(RSSt>-,,Bdeey{{.a+M2dݻw 撯o{{;t{LSAA5qNH#]{cD"zD"t 8;;a 5\.oooR4ͭ0=~`zBvvvɆL&d 庸ΏD"?vvvL&!$D"X,xxxrH$J0eʔz hcff[VV! >lt:D")JRy&F7nܸrzKKKpdCTtf#ƿL&?Ɗ BA"j&uJ$66@"d ~P(666 z\^QQaoo?-h4$ 1% 3 xH$///LP(͡LXpʕo VZtR|Vٲe Zr |xHQ([[[Extk׮]~!ܜaeee޽{ׯ_jĠ Pbb+W޽O,1nܸV[[s ¤I_~bA133?~|RRҭ[*** G\g{qW^-,,}񲴴x$M,o[n]]]ŋ/^zꩧ޽R~W<}rr2>(BΎj!/\299yԩgիǏ6mO?=_}UYYĉ'MTSSs{N/vڵ~v1Rlll3.]$˹\n\\̙3B!xry[[dKp,Xgw|=(.yyy+ KK{L&ᇙnnn;w0죏>'K!!!k֬y /=ӧOGd2<ƍׯ_zfff= rbZGGz|TӧO4n۶mժUYfƾCv;I$^ݍjBaXgjrR41t:aa0 8OOhoo{ bΝ{иcǎ]~ڵkG}jnf~^P}w)))mmmeee<*@h4MMM;y`X0z|W'|>ޞntknnJ@ T*Tk-ŲI\\͛7O} DGfff!!!SLdcPggO?$ xSO=UYYIۏmll4_SSSSSso|򉅅׬Y\]]GzYݻŋgφ..;;oܸqPjhhζ 2C޾}[RM4 +`h4靝|>m#V\i:#Ů>447;;;6}"OOO3aj:"" }h4ZhhhfffZZZDD<[h ܹc ܽcvkjj*))7 ␐H$?ɼwPzewt:]nn^555J0oo899S(D0dkk;a„|++RiEEE``9>FCBB***ܠ@ ]yy^F!>f\ނ 4ѽnnnuuueeeFѮ{48p,d1L77GGGx,!h4F~9H 11ФILWj[Ô)SF>@P]\\f[[[#""5UUU^^^P!dûpkk몪*J|||x<D"q\'''GGGP}}}ff&Bh֬Y bC޽{E g555]]]!sssWWWkkk B[[ۊYfdgg#Onff5ڊxmcc3i$PHbqQQb?46$ֶ8 Úsop9`5ͽ{l=ˆrwWsЃVmoo988y>I$>NqgggrrZB#޽ZQQ}r]]]666T*UՊbsss[$)J'~7 ;;p NhooX,+++d2Baaao7Q>~~[`04FtIIIz<00xf`ڴiaԩS̊+* DjV;CjĽ06~n| j=tԔ6tB@ ̬H&u:hG-,,h4FJ:B:ƍڊaXggH$WRVuuu-//oooOVT*ojjOA oeT*RI\eDx# r)#M" \PfCT{NDDg0 2nl2FE1sr\&T*oܸD...C..G X\z~ x6x2mtFG0%jFXvl#ϧa'◕p{2"J&]lllZZZ@`]Jîm1\Z |1 Dd29;;[Ϡ2L b/cXd2YPaP(S06X 2mڴꎎ\..v͜=f.xs4m_`Y]QF Ӊj*JBK 4 L68e2D"x x?=>'H9P($HUUUQT'j5yb% YT/!닟rÔ7 E7djc0LH3lB{ y\a?2 XNj?򪪪r, Jjjj¿E~9p)n5 *..Ɵ(((PTD[[[GGǦ&BP( g *@?`i4D"z`XYYM8qWsF}#66.]\.7..31͝3g(VE:HŹ:;;ss ɓcVMMMqqYL"111]]]g}pT+& .T*o@$0\zpP&j ?\vḹn|nDwJB$`2r_ʎ]AT 䙳_Q_._>ߟ~.v+cfDHB賷Haeoxm8{Tgx>;f1_yqHaHnXF$}vxvn^1fbʬQE@F\@8Nw?!$;1~JJ0NP|IPed&HOz^auuxd~ !ׯYnjZ}q#AQGEFak7lZdo_-(,`?B'/^?yWutJ^{yu/P(oޅg2>k7l;{V܍N;^9q"B~߅?e3>֭;NΎ؉ojim\z} ¿}wB[o#ExA};{`hyO<9ZZVf8̟͛l?[!ɡZZZO}__DO?'bB[d) z _ykYox~[L&.~e[-,,[lbr 1wúusNpa2KR;?n[;%Ҕwz|QVWHE#Ⳟ^R$zyfw=~raXVvNpP( MHNF;wRgFEV,[$ ̝39pE zm_=#ɳcf̎\z퍷vmužM0l?Gj `07WW|:+ZiS&ߺrNpP g_o~rUYUѪ=݉b/^ui9:çK$$I}C` M!vwr1 ;y81~)jN0xJ3c'lܐPd&O @EOgMM7cݭ\qKԴO.ttw^b/a"zP#ƚA VaXn?p K0naٹy:d„=!^QY9u 1]%'>wv'W} [HLJL5uE%ŝ,E"75XLD:--$P(}?n&V457_?O3X.+ :bc_j ~V~)\'fӢqGǁ> E!6=bϏF䩤[_<խ莞>\eŗ~SӅh_ڶk7146nrH_x?|Fj݆ #}|/%898lٸķ'I'O"f-}j{=oy{5,Eعs(j[:[jjnh)66.]\.7..n̙F9s@0XqqqƖ\B1yd#ƬYfDncbb8΂ Ls9|}CòU^g~ 䂅 dۍ}8jޠX{♛/}jh"z.vc ӧE-70&5x?l=$aaX{ksg{F6}--Ĕ_|!TaE=<.4:B ZZC0[JDZ_/l!ZU]Q*nm.vìS &Fg8u[!@YYYz@FVCtɡ$<#B! Z1ð .|III:NP"##7nOH$((#]п7o4++kΜ9]v*Jx/x0,!!oyW%oY uvvR'N8wM61Grro 9kooeϟ`aT*s–,Yzj& ;a?ceΝ;~z[[ۧ~:,,͍㙙YXX |%uuuw>sLllC&L0\ً6ZH$2L*޻w~8|M^y8ri&(..^ٻw] //fjZTVXXx۷8p_~aٰ @s|7JJJZjΝ;y*u({iwwG}~gg_uܹcjgxxgB//'|ǁvn:8(..޶mdɒW:88@ 9*ɓ׬Ye˖͟?@4=dk{{S]\\,--RiUUDզom!N7~x[[f_+1ðR<==|>*DpB bҤIoFll}xVVVllR

 ;g˒Hދ777j澾\F O;;;Jecc)Sۋ{OH$j:44T&8eeeDNKKST ch[[[r!ի_{5@0kAM<0z^x!//oz ~}r[t˗ucG䏱 |>$aggg-c^'ATaXFFFzzziii?UF;::B!BH(bjh4*2ǰ fL25p8>DGP 4-;;;--p<޵0~xH #x%466wFxxg^b#j U JܹK `̙ H 7o‚6l=QT8hllp8?NOO7LP(z;'',{Drssûh=~H$,2 yU@RTjyyyiicooo^_WWG:1;tM8q=&fgg+ar4xJу!RzF477tiӦuwwgddDDD455 OX[[gffz{{[YY ZZZLP 4‚BTkʪDh=~khh TCH$첳om~]Ҙ@Ο?!:}tLTj>XV~IWWWkkrggg ;ϯDb|SBuGǐJbM"dgg &M233Z)(cf 9*tr{\z<܈|$ZSa UKbPTFc2oIƐg/>h=zfgg>Kz~|>Ν;$ IdbmmАj'Nrwwv]ooo:V}rڄN[o-tGG;wz///b}˭ZGgD6BiE :;; ) L6|qUx 6 .LJJZlYYYY?Ο?xvvv`@@@`aaѣ熋K?SH$RPPPk#IBI&JmC-8::x ~rR)z<!f[ث@(FDDXc333iL /?yOO͛7 _ƻ kh4&t ٴjJWe *B@i[nq0w IDATݺukIIIVVVcc#B. #>6afT1F$pH+F}H݉!KH)aPz`\KE a 0 `$ ~s<>(hŋ;v(--Mǣ u@@LhTq0l:|>DbrF 3Q0-jFC0R5HTtTSQZB^;pÿJbf1K`i%nm)ҨPZ DV j&  6tH$ q6>>>**J(2 ;;3g&&&"Ξ=K"H$Rss3B'HR$i'O)𹽧`vر@f'MW_y G9991)Sdff!@t:<7nD}ǁ"FYXX̘1=2uȑt;;>(IӧO\`+'hg3f%11Q.N6 @2%bx NNN7n\rrrAABhƌįmmmee^OIIA͜9s_K/mٲ%++R oذaǎi>B_m)UUUGE-^~ ,rmfkk/E޽koo~رݻw*gϞ%HKK#9qℕX,H$]]]'OV*ϟ'(g._\ՒH;w^ϣ]zI()JPCCa &,_!DR+===tU1Όf$LJdN6a¦J\FnAb/ܹS\\wѣyyy B'|rbbD"AEFFhA}qϷ Ʒh4Cvo>^1cڵkLud2Yqoooo333eBU"XTڙ,tm˜;vm߆Jڻ?yH2 (;\rr֭۷osd2aGrAAA׮]Ccccccckjj={Vtg"(Jpp0<ʅ n~~~C6Fnbxw}\200P&$o=jt:]ddiUM "3ٙB`T* @01LpXlqB1zO8q ?O|>?000==sT*522ȑ#]]]?+BH*9y˖-G矝z}}}=BW_%r;zh@@@kkX, :qG}d&88ĉQ԰k׮!d{ɒ%?eMMMjjjkk {sν{s< !ӪZEhg[FG`? ~fFGܾCI)fFM?_ʋ6;sm;Cꋓ'9P(<v>g\tI.sܸj:rsss̙3:J?,,,55u7oބ}:{{ϴk3...11ٳF\B?ytZ! mp8 ,3ͅ22vFRs\H҅K\.wM{rBz~٪˗.9#z¿]y/Ft5R}oBe(AӧM|떿O;ADdOM]]MM-a7nkZR eHcQ]nܸcU%`bfL?rĖSbeLbvqHߝ;w7(4~@3А>zkbKN|/*~v${[xsiL;EP5F+6=bϏq}~K;z4bc_ +-+1o/OGiW^ H-&:jۮ`߸!G}A֬b0~" V/[|s1$)$(p;#J:pbxhxGJ2ꙿz=x d(G,!)980A$aXo,7,F" @x #)Ga H  taXL֪T(z]|q{S]{S1B%Pz~arWuuܨ[;D" d99t:C$޺}7&zz9f2_ڼ 3rZs?bDzlfn~ ϭ%V;9$c}ΞSZZOL }ү]7^ysz4Z}3)qftdd2L!2f3z^/aOIY0 #Cbꎗ\u2|"c&ug%!e2E \n^C@R_ By t:ݍ+Jb0pv.~S}.]U+^|eЧ/އL&e|w&| ekk)[;w]1=;Cew+!^])lۺ !ܦ##oUVU9ۿu7o7N3$X굫VIk(S?? D9^hhTzm ӵ 0L %`L|/X:yV?Vqtp{@"==aF۩iQӦ}\Br#3,,۷nUlk+/k4jZM"d 'f^ǟ}J}gŲCD&&D;w3Od~rꛓiYd~zw< L&Kx6_}i4줣 ϭ_~Ms7>U+4(v#ajId@R)dV;q S1LOQ*9ќˎETjz\VnlB&tB ambqeeU= r 0uJ%EE>+;'wsT.|];lw)RRS4<1ّɤmڰ^QP? FOV];=j9oHd6L>4͏2Q$ 0j:!)%$(HT*[wRUj BYR;;9: ôZM$R[wRBRLBB&Oq]Н{!Y,&BZոN09o0Qcz=B򪭭u:|=2d*=F%M_1 ϭ_z@F $ =1ŎJ괺,hTS޹{O.{iar?vhJj!1b0ѠOBam]muu"_3aO{mb tω=/pD#__dRa6Am⊪̬;ӳs0p8{ r}}B:xS𔆙'ejeK*BhjrP3HF! >33d'S()S%%͚|F"#">h]}CwwwTRс?!9sơ#_DL 5=%HQGb2499#C;w';:*AF+ZvʵWՃN9 11"!+ /#LP,4iؠoPz{LH,))7ΞNHVXlaY`^ қ `Gkk5ĨXnذwQUz+KYw( ,_|-93?bUQqkO/:et[w~ڎB6m}GPV^nkcE"ў/¾Çĉ>yRDߚ@Q/0rؽp8$"IH҂@Hk)))i|~d2YKKs޼yvc%aΚ`!A5U16ϧ*|L&#D lvH(TV/D"qm~yƦŴ wot!d4ڀL&{w`FVP$ڵ/w$ H$B][බV@0lѻ 6ɑH$"DB?B<8$Zğ;H$0m>#As3 :\ vuqRX/[/;l:X-lii$ P`0G)ttt̜.ᱱ8uP(QFYYYyxxxyyt 0DR/WpwW#pGHyf @ QԩS{IIѣ]\\tȴFcccnnיL >UVu Ç\.RUUDP]C Pd2+**^|yI ~;;;09eoOS>ɛ`Ο?w߉D-[X @ rʆ ~Ǐϙ3 JKK:tʕI&o~~~jjj`|f͚o-haRlTKs!C89P[[;s̽{~Gu4eʔ .绹~g {{7oĬYpBMMmձ/^HIIy1c$A3Q$)P7RzzkMMMFFƱcǠ$cc?}֭[s̩?rʬe˖peƌk֬Yx/0 CFBI&ݸqCUU4̝;7>>~z7z̿{nڴ 1"~@;;?D"ܹlDQ >^Z"8Rss qƅL8qƍW\W~QgϞSN:i|g`햖 A[[itVj7lPGΝ;n:|%`q =UUU˗/On lٲeÆ Vju@ uZ#5}ŋuuuw͍@ xyyIHwCw(g=ѣZZZO2<'ѣGђ0t@ILd2@l{L++Fϝ;ހW_]pɓ~-3y //?z*BeٳgO?D" b//۷[[[ "GQVW1 BH $:}Hك6X7D}JR|[zq3D---8 ,+66Ν;s1g"/^`0 Ɯ9sB n$ ZjBD"%%%%%%} R[T y敗;VR__ر 9H` Z i\޶;~xCCr+++MMM3fرɉHMMmnn޿c"""pFM8w: 6w>177#O"ĿUUU=ں#,-- |<:: '{7|SRRKUq IDATڊ^܌uaa!SPP󪮮 :::P9ijxGn{{{WWWcǎaW\wˬZ 99M_%\ ̟?_{kߐ}Ư^D")++OUU4\ 9rd.@ ޿OR544Bʯ_>||||nnnTTTTTTVV۷qOٳYYY=B=}422d"<=={ ;$!ľ>v@odd4o<`=?{Nxm\\\O0uu+VDGGsQF͝;8Orr2BS?BH[[޾ٳѣG?777qƁRSS]vstR޽gϞǏd2W\I&m-, eݺu}Lvvv xO>=~?o߾%Λ6mOU.]tÆ >,)))))GI$۷g͚uÇwѣΝsvvqsswƍǏ?s J)d {Q03f̒%KTTT^4>bzwykk-!)<}oٲJ^re{%Fq8I&M>ǏwYBw;x!D {GV@XVoeCh4mpcqu]|YQQQ__?$$f.a2x MkkXS(':tO?h@|6D];555:~ѣG l6v"q2115ko:P433{ 3g쐀J:99/^444i^+ϙ3œ&M2djhh.dGts`0Db-H}ot <ie&(H?AP⋄+o߂@3 eǎK.ݻw]ϟ`aaq/^ܹ7jrȥKjիWk<o޼yj)))  ={{P(trr,B4|;H >.<7jhhx5&  egHԔ9̩%\.ɩPnn jkkmmm{>nVSScggחuA@@@gQ^^~&2rCUUU .8̪Cb00ݠ;$000ϱ0y0rbrr 1c4551 {{{|'%%Iؘffffpd!".D!BmmmLA;;?|>fnfSRRD@ z:uc(uuuϞ=^ϊ?SYYG2H$JHHPPPKPDPSSѹuVuu؞y #<<\B8 j߈HT*-88xuՖ8㥧O4JDF6]YYQWWa۷'NlߏIJJp8=u*0xyy577O21D['EEE),,~{:%$$455M>+0YbP(zh``` D"cvvvx 䥟zzzU"ZZZ!---O1xkCCBzzH$7nF mʒXPPxb1SSSggׯ@xa@ PUU'Et '''ׯ_?T@x<&:v[VP+`!V\yo߾}Pnf+((tXYY]|>͘1c:x<,n:`orx+nnn6m!.ۣyǎsss/eƍvo2B9++b_S֩ҥK'Og uxܜ嶶v8$É ;YjPyO>-))h pI{nݺuG(t6g(drjwy<P|:D饦JS '|'N:zCuBtwwlMO[#G}'X!`S(~u$rʾ\ҾK]J.ER/ٽ{ov၏^ u -,, MMMū544BG0cǎş544qhqEE[\Ν a4ad~r 6:z:%''_x1((h]E%r8u@ I N?{]\\VZ5+((tXL͛.=;88nƨQ ^FR;UUU bll/ _;-[ _+.]hѢD1Z< lmm{:UUU-Zwٲe@a?{@ K,9tІ LLLN:Y訪vA;,n3f̘1c$Tظl "㊓'O^|N 7µk<<<-Z<::iiiuV_ҷN͋/VSSzj\$:TXX8k֬ .HWVt+򀍍4|]Ξ=믿@iӦ?~CSQQɌa *-@|}֭[} V=lϟ={˗?~qF0 &&&M8Ν;`D"ݻw'MD7OСCw޽{?,v?illrޫWV\kG5 l@+-߱cǑ#G׭[wڵ7opܑ6477'%%9sٳg/_NJJjEEQFM>/^(++ i^xqkkk///==A c#***o޼>b!TP,suB:::޷oPd>̼zǏGNUU#i`H  qZ`cc3[nفeH͛7o񊊊 FSS4@133322gP0ĉ'N`2yyyUUUl62RzzzVVVصfH$c 9x<^ddd~~>3666 >jjj&L;G$Fee5k mBիcǎUTT|M~~Mh4 䝃?~ʕ` rǎ򋡡!XT `*ΑTUUeee]reXje˖ ϟ3gV qbZ(MQ=t + h¬D(G]$4rΝG@`$///%%%%%%?ĭYxx )S|p۶my^ d2JW;PhhqUU˝2e HήA[[[***;vrDtu+KKJJ޽{Ӧ`d3l2%%%x(Ìr8wAy5?~|~ ¬Y*** Fjjj_vF544#}H)BHO"00]Z$!"I,3x;^.4}tHc(+++{xxPׯ_a3III::: 8𜡡aNN6eeeFFF`gJ۷p?\36o,B?nmm]b U7Vԗ/qvvf0I4Ui$ِD[o`QƆX͙3D"!Ǝ究v}}=Nonnnii>c _3fLw!W 3EI(W˄ &DEEbH$ ...h?uDw7ao <@ E BN+))4PٙVJ-]!^ rss|P(5BEEe…D"144֭[MMM_[__ڵX2wf舳۷o###|N733RTTTQQi/x\]]322JKK)a}}qAA9x7 F՝Vjgq~uuu4i$.ǏIrpXP"@23$O?)}dVVV[CTTTݻf B"긃!vf2EEEӦMи~qqqw{ѣ322222ttttttTTT+PjjjBD"999͘1CEEE  F:2\,X]]{ ‘#G999!H^|k $%K|||sss+GAV=V IDAT\8۷oʴd@V$=\QQL A4Я}GcǎUSSC9994664|4O6mڴibaNT*UII O+ LcHL0\EEEggg}}}gA Ν ȜƑr zެC% )򚚚|}}񟮮111)))ѣ{H0(++xG&8CP c4(fEEEEEE#)))cǎYZZ&''{zz¯0$,(((((ěh@IzDErw F" yyy|>lу[Η 0ѱcccccc $Y444d0zzz`L#dnn奮Ķ60 $PT'''@0 Xb#MMMwww$10ÙzPncccbbfǏx_=`K+F$x">>BhjjĒDŋHajEGG3f@ |>{]d0}1Fͥw?ydOOOEEE\𤤤/_FFFN>}<""",, !D"zZL؃5t:=55522/_u޽eb 3gbu"nnn&&&[9::DDDzG  /deeu>D"&O/IHH|˗/3f۷oAtZZZòX!H$Rdd$ϟ5k$!P(LJJJNN/J$?]hll,..ՕKtuu)J B4:::;;^|cXpǹsX `;wO4snHTZZ3l2Y~eBB@ @,[ !}ΝG߿#9;;Atuu;E;V/133|0--`[NSSs d2B!DRPP`bEE~R666xI$zJMMd;G(JNC T@#9sB"h 䗤sN4IBϟ'%%M0A&ZZZ{bA=eʔGKJJZZZJK.555˗]v`B=>|XVJ@ \v-,, sKHH(--k׮~0YcKu^#8$$'sssNNN@*((5jF3557<"C?oo޼144TSS%%>#\^R___\\ҋ촵WZ˺:'jjj BUŅ},,,\\\bbb,,,h4Zhhls!Y,VRRR~~ǔ)S[:j| `Ш{I|||{Ⅶ+zr}˗/]GiP 111mmmxbXYYYXX~:,,,>>[P3|>_ !4{ǏST `gA$UUU?h(wwT{{ϕ}PAEEEDw I&;p)ƍݵQQQ.ikk_tiݺu޼yYBBvݻo&Hnnn!!!o޼1cLP(K. >F@[$C,X?x 99yܹWHBaLL H7o^@)hkk/M=\.fw y>^---?~]C]O/lhhKzzz=zUTTz8Nddd||}b<<<Dׯ_kii?.ҧ'HW^]zHFssYL!88XCCK{vvvhh #M|o߾ӧڵrHLmmmiii!!!߻w={vf_ijj:qĩSu9993o߿ˋ{ټyƏرf!"lٲ丸~d]\\ovqq),, x XXL]~zRAA|$Iy \vX؋KAaaayyxq @zjFF i#H صkǯY&&&`%%%;;;;;իW]p_O>|r0T ڹs'H<~'|BR&C]]]]])S|EEE:u˗;a„ }+}^˗//++wRVV GH$ mPAAFD")g<"H ҿKR;M--]l900h-[2-- ҥXڱc|+Vddd|s}~/oaɘ1c^{7N8޽{ +++9rG(ʖ-[LLL:ʠ ???+++i˵^iiieeeC?`X****Eqqq$NKYׅfxn޼9{ :O??Xvr.]zܹ;w;v 122rƌ>>>;h4YWW)^)޽{7gϞ u` x?㯾kHI@@; 0{ tvvkTk ֬YcjjڗW:" h:WWתW^b,kܸqӦM={6B0Д-Zh…}XGL4ҥK}?}Iw\x<u4 Ǐu8:믿S5w+ 233Bqlllƌ3+ٳ{׶h 0ٳG[[?6u͍@ xyy @^K.ݻwmz1Z?ٹsÇ.\8<߃? <()):t̙3H0q…osK`8!PhhOdd$B(((G'F Px%2++ |D$00̌B‚@ ,Z Wٳ***SN}4t钅J70[rDΝsrrRRRRVVvuuӾ#YGGǟ~ !$p6m߻;l e+goذE~߾}Ϟ=i/Z'@F<򪯯_`ADDɼyFE7N bPKzmtxS8ett\nttʕ+?KrrƍE"Nj9s&d2]\\ϟ6o޼t; vڵaÆ7778??˗/#d{TEUUF@ܿ? H$pm߾}֭iii:::8ٗ_~pD|@ݶmۅ L&Jw)gΜ޵N***P wH$B!!!" S<<}xN#sss<D&tScgg׎;|+t\^Ћ/LLLƌcoofB퐘'+ҥK6...@ʵijj$@фA];,B+W$d2yժU!@,l/?uwJ.[ѷo;\z5DRVVh%33flnn9///dz7ʯ_>||||nnnTTTTTTVV۷qOٳYYY=B=}422d"<==z5x`A^nP(㏩T뛛q(kvtXwGEъ{d K/.]糝O}ll!>lEŗS(! S3 B TWW5jp6Xivhii XxX#GS۷o?sL\\ˋH$ @7v(/sAG:wBzzz"ZHMMurr>^joo^XX,D&L@ D"cp---RakhY,Vaa ijj) pމOPP?;\\\8X1)= |ѝHFllիW/Ffx<^wuJJJRUUՅ 5(R!,,,55((((p6Xiv"---ǍgffF"^z8SrrrccYd2B{qt̙3cbb\\\ZZZ eR@%%%777##b͛x<Ν;̙sUܱHmN>}iݻwٓ&M{PTTp8n~wW癢89k -Leغuk``MMMB!sN}YGGǚzgg .8q_%ҥK7lؠSRRPSS#u֐|駟FGG>|XrǏ[[[8q:zQhh(vG`lvyyyII O]zD"}~~~FFF\.r .\駟***{n[syŁDbwa]xIkk+F ~ cɞ?+ܠssm۶}]v_K.=yd'6ɓ}Keff @/Ϸ| v7޽{FFF_~d2L&~dyyy|>ʕ~~~"]}zʔ)ޒS䀀"OOυ oo޼?}MJJJfgg߻w ,^W^jnnOt]|o/utΝccI&u^Z)JKK={`0-[&+9 ;X SUUuܹ'OdeeuDbC  ׯ߿_(޽{TTT骪ZZZ^^^_|񅏏N$$$? Þհ?\$}'#A OݗVKX,֑#G drQQQ`` >&:n:wwɓ'{01:PH$+v7>>>""bd2ŋXP___..C; ِGmܸ_ u@n^re۶m;vprrڼyѣG >^m455D"a+L!_ֆ?= B066ӧ3f̐U@/vq!77SN:rL0!::o߶JLL4޽{PG\A&7nܘ~3ft% MMMGjjjvG {:pKy;s۷:{y7((ʕ+x4p8JJJdegOm0̿1ď?xҥ?5hhѢϗH$BoyX){#nJOɖafy;\(I$@K,sww?ai! %!!A x{{Ǘ-L, ,+ HO> kG ]:[[[!eyf0Qhkk0QUUmhhD=ʷAUU﹓d)'|LPɓLҥ|]\\p  @d@^^A?VVV52444)1惒nMMLÀ*MMM Sh41"hbb"/SYY)}---Rzܒ2w ^,}y;4EEE\v asL!_%%%/J:ӔH ޝEu?waa}WPbhiZ5Iڬ,511mLŘ͘XԴ1V4.}w;: 000q3?6gzΝ; "KPV5<<Ud&M∈ЗЇGEDD@ z\ndd䍯}鵵}ٳuuuIIIv6l?C{㧣}֛/_enj7njjjffڻB骫G˩٩V !V588׷aHDSjKJJ!&I(/! >ǩS<==CCCq_ett{ff&Not***p8 $&&Wf8:>}zܹh_lqE뮻Fk]"(111+++))i8mmm|rllę((([ڌFcuuu]]]LL̨$H;kj FN ҢE>쳖R9{BDJqqqÜl6奤D"e;;;{{{f͚ޮVd2zNsBbbb._l4%\hQA`ҢݪT.{=bo{SpwǏ:t-8&HmΫVZbEMM͔)S.:  :ܹSTޤ~&GyDс===oҵKHbŊ/b׮]s`miiٿGG?Aa3fP쯟`_[^@l6;H`ݺuoO>IRooo/\]]#""Z[[h%++q@?+1}xJՊb@0D 7L⿗_~9..n8h_oc˖-1NlGZ[[nka'J`3|믿T*]fkllūV?_zyf577ߤU$H0 X]}ُ?zwrz{{z:d}>xr@n>o6%TccckEKJeNNNLL0x7|?8~yɐXl\.7߼׭[wfeee8f\^{5 =r5k֜8q"'''''d2ժM&@ >}.g$H0l}%|G}tѢEt؜!+WWW1 r%CCCJeEEEPP\."h4wwwBH%,,qKٹ~6%A9]wݕ;wv֝`!:,g N?/z[N(.^orJSSSgg'!D*KE=#AIw5Wz衳gϮ\… }RL뛗88 &//r D"Qz:"J/=}z jZh4ڵ +On3cƌ+V>|]Ktjnnnmm5uuu ?:Zj͚5+WDS 66666z$H0 !d۶m%%%-:xJUYYP(R)=QHLLμ}: ]1tIQQ@ מ7O>{쨼5 :Ryٳg?;w|}}@<蔛lٲ c36'Xf:x욇GRR111׬ٳg>}~e',ArӦM90!ߏ ȹ^fw߽bŊ2ɀzzz~8z8ٳgggg[,~>BL0W\Yb}kc{r7o?cbb~~8-- .PUUU{ݾ}{OO/vZtX?33s֭o׮]r@`X~]v޽;11رcC\GJ@0, .ڳgG}4{lww3gFDDxyyM¡Xmooɩ/r*0 6<[ly֯_q֦V/\v޽b 4% A}gժUV!fm~<.n~̟ΆJKeF0B* ȽG^|O*(,tFqJL>o;GvOC}"=ۧ jȏn|\,!C.2c9z#"<==?߱}W FfX&H}执~v£'NTTTN zQɴcO2Ms<ԓb²잯>t::;ccc^|3{Yi+uw?p߄~1$(苿рzzz9{jk[ !yǡ!ч|cvttj_xvK٧2{gc !6l o  A|֊%w߿>߽xJ$wn/M?y]_<%`ԽW^ZO}\T*ZV`[zEݩծ]:iZˋ0Z, gY6j\:#$o?y凣~ɒ v{Og;;;w{g+g-KIiiQq !C.O5k7{z2:k0 ۀzzz`ggGU_筸x9] Ddo~my{+fL>Ī|uq$x.vf|Ͻ V%pʔ~̜Occcv|'R7MO߱v>pBIހ }tl?7)t@ `@x `]\t  A@ $$HH  A@ $$HH  A@ $$HH  AlIIIbT *77Oa~~~EE* x{3g6448>|8>>g90;SO%KQ9Hƫ+Wmذ^b2֭[L:y7|M{|P__~zTJ w>s -z-T af3!l6oܸQR9^p$HҥK-ZsBzzzx 6T* o1[l!lݺ`0ڵ i{[[[O:n췁eY4~iBӧ.\j@4EEE=SH$mlqf Bٿ?* i&>_l˲Hooo4-[ A ]rɓJR͛X@$H㒷wkkkBBq1MAᇻw.)) feeֶEGGZgquuű  &N'J'/`6x≿Ɏ= Ytҿw}>zy$ M4F'ܳg /~zwwwBH{{{qqqCC!/::z̙3g|饗6o޼z3gرC(P:  wEEEG`Yv߾}|IffjOr̙z˗o޼yѢE˗/p0 !tLCPL=}'Ϟ=Q^^r>>B kj u:ݫaÆ9sTVVs=f8Kkoo_lYYYYFFK/? Gt>oB@I}}<~/h4~'+W0/-))ٱcGDDΝ;m6-|Ynfկ~6j4f,˾{8&g{WK!t A`0ї/_>x޽{GUVuvv_~T+**V^699ӄO?ݻsrrwYYY{JO?_|#`BzW!III=PKK B$:y7/]2}=?' WWM6Ν;wܹs!d#[L/~QYY`BJLL0̆ 6l0YVuɒ%$Iff&!|z0.\hnn;qD||<H_vرqFd7$H ūtXoE"H$D.s8buu}VZuܹ>Ylŋhq'==}ͨa~O>7x^x 8%K޽_>~ڵ;wD$pV=>y衇jC=3̜9̙3;FFF?~|޽ǎJt_x\.!`bXbKKKM&:&A,/~e˖Oڰa]-˗SSSSVBVkppoUUUKK 0 "ҧe^%˵ZmII MHBaJJ !`0$''šW7nsѓJE%Bg̘AK***BBB NV0'NJ\$lcEAAAOOÉ Nrn۶ɓsΝء4Hƽp\wuuuI$ah6RRRfgggoooSSӬYjuBBBVk2RRRSRRd2 r =!\|h4K^rrr]]DR8p;2 Cgާ!RtF!2a "zq?VlWo3oP(r>tBqf=bYe쬬ύJ%^0\.$xzzvvvBb:Bo5559^^p8cvD3gNeeZ #0m4릺zΜ9[AݒVtϟ/((X,N 0.c^=Ri{{...hb wƱ^>5""UBC@\f}4`ؾ}O|pV`娭I IDATTn'j:pi}z_xiii!ѻ 6-88X.?a:H$ST*/\`X"##'Rj-K#kÆ 6mZ`Abb={゙ko߾?O6m:;;KJJ\.q|F9[&g+l6ŋŎ8q;QCǀ̈́@a.]:ѣwmhh(((Xxioo> իלWTUU* ٣"G{8Ͷlٲfgg\|Y7mڴoֱ;8jG9[ c5AmmZ^p;vlݮwu`QS؍cIIINJwp#O^TTm6>裢iӦ榦ݻw;c2 "J333_Zvڵk\DQTaaaسg:: L2СC7o~Wms?w[nmkk۸qK/0 t t A\ƍ{_3<B_aTYYY\\uoܸ:B$ YwyJG}u3gΜ:uRfΜ9wn m pkqܹsΝ;U Dv0 0 g0LFF$Y^xat  Au;) U*O>M/i_Bo0L`` kҥ ЮvSO,?yڴib%99/}hsnٲeʔ)"h֬Y999#G}aJeX蔯 0RT;l߾=44u5kX,OiBΝ;]\\\\\f͚u>  ÓO>www#*!Ȍਞ1n׮]}бeO{=Bjk\z5c Ͳt,h{QiwvXL6mw=c @ceDe;jB^{5eя b%~~~^x~Bp8*{OOώ\_tb{̾".+Ji_: /@H$qqqR?Oaf޼y'V>(^TrDB[RR25?VUU'??… D46GD N=hI$>B_pdCǖ!>Cn$%%%%%׌-c=@MM͑#G=zͲQ0NMDVND"X,nnn22/9sF%K,Y7K!s=Vl6/^466qBa}}=˲ϟ7Fs!y,fgg)ϝ;x2D7nH?mii)))h4e樮UeZ_cن:wiXziӐ M$csTOԘlxҥK,߿-׌<֭fl 2EEExseHBN9uTNNNWWO?pN:u)zq̙>|>}J(!p8<oժU+EVV}cƤЋ#gy}WTBhIssŋm6!瞣khk6֯_Oڵ֪`^TTD}\˽ދ2{TOԘllL777-Ì<Ï-7Ϥ0ҥK~juffffffaa!=? 8@~ӧOkZBȜ9s|u^>$П>L&o<;LRSSӒGyqvz8P@s9)S8DaV@ BD%='jLp1`: c 3 twwoڴ￯Zv-!ܹsӌ ò,HO>gΜ#G_\:ٱcKf̘AKfZKz.dߘBK䫯.\.w͚5{?׬[c۶mb9z{{ok{zz˱ڏ?NKh @zgg|=i_c5# MM{zz[=n RUU!$22g?ҥK/~ 3;eYz1)ޑ @:u*h4#lFC !shܹ_|&''ux ->>},DIHHXlYBBǻۆSo/^<{l:g&9'jLpa| ,ݻ>|e,A3HxipwwX=s̏?P(V^'_YO9 !^^^۶m۷oOLLlmmh4ӧO϶l8MRRg}Ʋ,KMM=r?m-x}kzwvڕjjBHKKCs\9![nfΜYVVvV{]w=٘?JgΜQ(* \Q=QcF{|OLJcПWz Emm Z[[[=nfҥ~p!^/H=ji ?Fjj Ν{ZG}3WWW۟+[NѣAAAζa>(7 b8ZZpqǎ[`Aww]w5y` YgggBDB_W2 !/΄nmsr H&u8q"##cYSO=Ө[bq*O&&&w}wE:Isr H&ܚ@sXg1 3^_kł, $H#A_g8 `lb9RLrz:c[k]qqqrZV"jkk Q(:BIrTՄ[UU0LBBH$")jEEEaDPh6O8!J !t "|jq/d2 Ι F %33s޼y7Ѭ $#rp+ BT*f9///!!!%%%--M$655ғ%"(%%%55URUUUEdT1118s)L=Xy<.FB_0e4<==Ѭi$|||lO teʆ>kQ*,0r{zzҷ/ Ο?_PPñZ׵/,655:gU3 Ѐ`|ŨvTĨ& { RRڪj !%++q@m4̽`\};iii{>6-88X.?a:̔H$Sj6<<<;;;KJJ\.IHH/b uF $G2,888//O" ?@U1*<<.ŋ111MÏQ6ҥK"hԩhPpҥKСCz^"=ztNW\)//OMM@C¨h4UUUt('QTTdZZܹsSL?Xx^p9`b(esss[[[;`nWW׻k(8~'<<\ן?>!!`yxx8a=n999 "22r90ӧO?w\ff3QQf9;;c̙x?,8=b̴iBCCsssA̬VkiiiVVVPPPRRp59>?k,wwgֲ,`:::~'z}@ Q 1N(LZ,թjeUTVVVXXXUUT*Ѹ@wwZnjjR* uHn ___BQQQQRRVe2X,_F VdZN2 aZ}eX̃@EdTPxHnnx v`8f3(ryhh߄@,'&&644TTTClt=HP(Ñ1%m6[wwwOObq|8px<+}i#H""""""f^7 & O b AgRy06JKKјi0|wwwJ`zzzQ &ra"""P0|:Ào0:l6[YYM0: _[[[gg'˲jH`,[^^ `YH"⚚. Aqh4BT*Uee^G5zBryQQ WRR"|}} !^^^C3W\+&&5H`j 111 677r`jᄆd2b 8VZZT*%W\A`z{{kjj_i2Q?p`oQӦM?l]LL j e2cP(LKK[ c@ ?AdGCt@ $$HH  A@ `TPbtzl6, c绺JR a2Z-˲@aLRj ZGRr(W\ r$HN-''fq8xF@ P*J2:::11  TWWGGG7lgԩ.\ B Ap  3|>?!!ͭh4FDDN bӧOEm D999 GvJsuuuwwG t^^^aaa 8sÇϝ;wKYTT@pk7EGG*tvv655*.v7ZH$iX%0 M^fͺ Hj5:| AkFϘ1s̙NRY]]m4e2YllL&TWWvww3 #HLHihh!,\P(jX<|Bŋ^Akkkkjj !R444TT:noeeeOO… ^G;w!Ou-W\\楛񊋋YUTt6BHFFFEEE]]P(\`ͣjuYY[pQmkk+++tV绹{xxB***z{{f3˕d RPPPSS㸢Rp .NKKf XvFRSj4/]nfL6Z:::d2pl&t:PZm~~~II !nPFc`0,a8??_պdK.;n@gggaafx5 gT$l6FC3mRQQQMMlxj>%]h4ВFBJ0;2͗.]joowqqE&)J>~ENGhlmm744B|}}{`50WWWTjp;H7Q{{=Eq äD3gΘLJU]]MIJJ"\x2$$D(J$vgX4T*`"DEEM:WWWWRRo:m4???boooBO0K-Ng4m6nRooo]]!DT&'',{N:T*h4>>>ZVB힞J>}+!bBH\\P(4fjffflFT*ɤRNkhht4lE˲C joo7  D"B;7:Bh.Ve;;;JMt:b hooǓ4)))(KWJqqqС+)bh2F^MgU0Jr(5Mkk`k["D'Nu^^^lmmUq^G```aaassb\\\H# ;7B*  `L&2Z tf|:^^^]]]̈́W$U*X,vz X{dzwa4XUbPWWG qWΞ=Ck4.))MeY//gX W\\lZi4kf>>[L#((b0 C> jZ,pjVWWͅ"""ryOOmkDŽ׷h42 3t4k΍)bA `\.̙3=ǝ2e  nnn>~8}B@IRVk6 0&H...UUUUUUt]]]r|`0\z՞ /b+jkk=j$xyJVрF'$ 0mmmsd2y{{:`4 ! b7߆;#FQ\ $k2߿Kv IDATbcc%}oLfj:}pg@ J111nnn]]]"HT^3Y捉ajБ|??ZCjf BooHM>]VǺ"""i.X...===\э A4\QQQ^jPtv*>pX??>nl#,{9:9H$-"A6m`:huof]@0֢"LZ-mI{544477Nޏtǻ#$H$" EHHNVmjj}n̻H&Ar|֬Y}=`.Կt A}N8 $$HH  A{Njmm;ag޼pܹu6*3*h4={~(,, PhhD"ɓ#3l89T&&-IJ*kjjbEbcc pBxQI;AòͻG!pTBeOOZ vرz^P(Babb\.':u*::ZPWWW[,>׿>`(,,h4|>? 44f;v,00իfY,'&& BM*((' <{=>V]7'77WI$oo.6k{{;!&::nۈ2Q7luC4M6I2\ +cmѼ>--m11.T*NBWZ[[[SS3{!ܦ&SSSj }q Af̘rϝ;_^^^XX8{ld:rΜ9"h4%|\._``p@ 2e -55斗8P(hˬYD"Q[[ۥKd2q s ׮Coz Wbx޼y,fggEDDִ4.[RR?cƌg˳ܘ˗/+ . /̀˧:k֬ӧO755I${^smܿ8YՃnߦC0iٳkƜ/qh4;vh4\s3FYuss `_!pS G,2 }2 cٴZj }⮮(.+HBBBq\BRjBJ%!^^^^^^ݭh0 8gtwfGz=66SNmiisR2>]]ۘpaRi@@pwlVBc=`6*uy۶fZWW0Lnn tYYY}&Fc`0y---%gggx޲=BL&ST>,QtР߸=.!!! ±;؄!b A8,KiiiAAAZZZd_:5 ץ7777--^|~vn4O>0ăm?~|G,s8oaL˲2>^66m8\6}߬m n`عs J~xmщ뮹sy睎{yy}/Z&lܸ|߾}AAA[lYd m+VL6mÆ MO?P(׿Ο?_'f;MX|̙3*fǰ?x<{lq 3``fǧ!,,|tC1m$HLww7 r|>0KDGG ʐ:ߢF aήVLFH$IGG;qn{zz>dz%\./(({UUU:nIIz 1nnnbvʔ)fN,Yu:]jjpooVLB]]}FmL9r뿖/_^SS3o޼ׇj4cǎZ ǹFcUUÇ9{ٲeo&!ŋrjVVV !/++{}h !՟| 9tvv_tȑ#nRR͛,XIY,{1`̔dW^df~fp\Oqq`P*C ÉiCoHj-**G*Y,>%'''</00pGZPPV333BfRRRqqɓ'VL&;O2`_}v饥OX,bxʔ)^t`0xxx$$$ >xۘ:@gnO~"^Wm׻k֬9z,Xe6is r<(vVL&J2??Q i4Z>UUUuuu6lj[AAA{{{#p>}+y_;Xp;Fvn=zƜf@9tf!?> OȡCߍĴ!wC`1K.CzDr磦h;L8u9vXbbɓ'|ys'NdddKx?|m۶ p9mr_{wUuٷ,dd5{&$ƅTDM>@yKk߶"R-Ui]Ab feAB =IfW4ː`H<ȓܹ9ss9ee۶mkii׿tYZ>yҥKBᜇB?~<--78+VjP3s0̰$p\K,]?}իWmvvdgg qk6[ZZZZZBaTT0X,;w\~}BBœTd21 #jqqq֭{n+.o:<̀Γ'O*TPP/B,Y"H\ !(nB~;3Z(Yuuu㷤Qdɒ}q8zIg߾}Q.]}CCCBŋRxjz+f]]]-[vq!Ło''' @_/j}|@ HNN~뭷lNj?0EQ&޲k.o^WW7 撒*OOe˖iNOO )((}}}'e˖;ӏ bNw;drrrg?;w2 ֭U*++}Qj4O>rJz̒Jj*o].Bā_GJKKKJJ:}wN|ɭ[9sF*Ezg['|Ψ=Jo׿ERRRo Cb22,333::fU1󳳳 ! BB>O?oՄ//H:52ͧOvqqS:A;gggt:ݡCe2?V]IIIQQ?O===jNT%널>/ѣGy'݉TPPP]]=<vr:wZn`X6l VD:vX{{Ç !QQQiiiԦ&:9IBZC@ (//?p@iiicccQQQQQQ]] |}焐;ѣ*9N0: _Mv ۊbKwl<6mX,˖-{衇x<͛=@F_M$5MjWp;CgG ,X, "** 76@ãߎńVVرc b۶mӧO{.Y`X}D̖ojժUV]xq-SB]ss3=^N~zbO>DVBbcc㥗^ڰaCBB;qXp!]l?`۶md9tb1͇Vd>ㄐ?ϭl6{ƍGt# s=HOBdzzz"""L'{wBBBee-b233Gg/$ MeB+W,))KJJR---3RA>P(!nnn[l`Fg[}a뱱m۶k=Å SSS'1"00p֭O-KGG!g=#wÞc~ ! +k׮ZǏJ=;cSBcccշo߾yfDP(nfz.))Vb}7b8$$>J)knnnJJJSO)kށܗ_~j$ׯ_OMO jժU~pF# 7&V{ĉ1ݰ4M~~%KD"5P^^ފ+jP(D޽{|I__߶6ۘYVO]p~`iեyڵ^n;wPacRP۫Rԥr>:ΎlF62Jt:plvQQ`HIIf @ z]vuGEE~@?/pUV U###cFB&X1zZ=z ͶMNw B|uwwl^xVZh]&UWWGGG{xxL.S$r Rll x≔)>;ꡡ!gggFPH&DM1L d---<jbBApuu%bK,X`Jb&it4twwo۶ǝ  fƾ}222'Npl6{P///\9+==}J.B,KPPX,,--( B'KζWd2˗;a;ddF+^}UH`899}駩ׯ5Ay{{KRggg:b?Woqsssss}KQTbb3s8ZvÆ eeew ̌Яjՙ}t:AO}EwygWWW_}5& i&I\?]jjjYYjMHHػw`@[\o Þ={LfYYf}[ҷ( A 9O;vDEEYR>~*Ǻy.88888//(R__p2e0/^, x)))%%% .zN]onZd2bn07,qvv^h***R('+F,KkkkQQ^h*Ѓ0{\nzzzsssccB wp-L˗/777 ] L`?N,bPp08~ l04RT* ח@pr7tSDDDOOO___oo F#"?2 )7$by{{{{{۶L&ՊU( k Ao)00ff EQ\;UUUՈ A@Պ^J@~xp*((E_\o-; OA:y|*氱Ey`22 f jX Zh럏 `7E1L\ &I(ھ5ս N+,,LJJrwwX,EEE~~~Fќ9s`Mx,!$//߿`0,Z߿h4x.Kinnx`r ,S ۛJs .,^~ƔvLF_`0={l6;;;2J~رoɉ~ҥtmmm&fGDDLV{.̘2 Orqbة **J*NF#ˇD"G?}~眬aLv a2  \i:Q|>ҥV|>?&&:++BRczzzmKKKc2gΜinn& W^^B?yOhk;wNӏ󱝂/ILL̘z.bJVɇZ[[333y<^7p=ɪyuqVF@𖨨djL 9j9'+S;O-`vh5jժV)zGt:Ō\ &/KENE!AMY,$H0 F[L&!dr~=}`;BGan2LP/&{Z\.W"tttt+l|I&V麸M,Jb\.NV{?-yqnF7V (ϯ.=YM0;Vk_Ozh7ՍucfI56Ӹ{x+$z=áj'O>=-00($$d§Cx1[wUQe0\]]'+kwttHR.;44d`d2:=M/J"DEEt K8~S;YL.^XSSCStu!FFF\-1д.=YM0;Cxj0sQ)<:^ L jqL&Q3e˖oXr߅ |}}w9v*FFFΜ9N?VTTε<==kkk;::,X 6z~KvJbl`m1LΝc3g*1Rzܦ"VpZMi2bs&li)eOdj5Y,EyvuboIbx*LW?tvvDb~tIϞ=fcccªb+;F(:Uk1LOOφN'ɮ`5nnnFj X,;%wqqkw%[Bd2l6}%6v,rrrMMMVUV_& 7Yy&yZmȈ/ ;p,: z`&yyy566vww.3s\gΝ+,,4L|>? @*vttdffRpM7666GFFNxԟ\P(v[ZZGikGIII 'O4...)))vJy̙.188H1`8;;LV \Eܦ"V΁v;d\_D"JuƚNy<ݶkbPiސX`B BgDz(2[,ԪU&ȑ#F$}˗/G`jjjSRR\\\ 쨡ŋ-{9بaT0_XBV œ "b+Gh>jF\g?CB&/&=\)q'իW |=$azS&9;;|6ԙfH,t%[Jx}{r˘ė)'8wm۰x⧟~ȑ#7l<#apf[0!l# l|˗p[j*+.TFV{l㹹#BHXP0TrY躍yS> O׭]Ο kL 'UUdzG*~;00ЬSGh?X|y3HUWG6Bzm[ pEgw77T"i/t˛ }"BZfq\Xb'nr?_>|wI&"3z.uUϺ?n_77DH}VO?v+\xJ,"n""l]G?8j?v3gh4 'AG7~ ,[~WNZ tZz#wfztc{^h02 yT+Ÿ}Ge˗v 8: ?7 ?]JwBiPy]A֋RSrʕ+W{wC HG>>>V |y ۭb%p#G#imhϰX߿q'8 G;vaaa !bDR~~~)))+WD  <+ƞ8*RCٳgӦMaaaoP(-{{{ryiiŋ/_yJR,N@0K=O?Mh4}ݩS***~ﻹI$77-[/577;v@ (6pX?HPlٲe˖M?{0 eH㐳4YF$%''{_|EOOnnn~5kNp;=H$=oÇ8p`... ,bl6+JR900PSS#ӟ{3gNp\H~tĉn멧zꩧ!MMM̓?`X!!!b8&&vl|||AA : պm6'''BHXXXXX.\{-[N@Ȑ 7776}/tdcXkkkO:URRRTTfq'84LpM#q)ٹsۍF#rss u6h4R)Ho]\\p'8 \ OllLEErvOJJ:rl(͖d ,H$#VwްŋvmƊx|8䤤?t''?7͆ '[.666fee})))sw߽A7{{k{?kB({JUVVv'N6ƍ8>|g9[$H@yhz+7'gz~ӦM...+W\rN_/>; p##?$777+++))I$M yHl*.*:{OO \.7&&fٷd#Ȏ 80٬7kWX~kv6$ fl24&$0cGa4Ā8܈[ GCp0#Z-/@0\n}peM `"*F\fJ9P#prD0 ]as/_jk1[#\ 7 E`0n^yIENDB`crystal-facet-uml-1.34.1/user_doc/doc/screenshot_3.png000066400000000000000000003327141415120503000226120ustar00rootroot00000000000000PNG  IHDR`v3cB pHYs  tIME "1,. IDATxuXTn, (%4b (( vb7؊ "؊ HKl?^^J_Ν{̍9siQ@ @@@ @ H@ @ ZW[U^Jy@NNNVVPPPPXX1kLwIIɾ1lz t s+cXs/ܽw/{S|!,Ǿb0ND)//////11j#F ԲH 7QQ+V111#ɿux}}}||˗/ϝ=;zqOֆ޹z1p\׻Ϝ|d..?ckh|/QFFڳـGOVZa Aav33ӵVtXF?pڵnnn֭:{ÇXY)..{-d2=x76Nvuy@h*\^^{…˖m޼F /rs\gg.p]|w1@ kmܴ56ݸG1 J up8SS)SֆKHHٮW\4iR7Oxׯâ=TTT–,Yr- r:TiéI/hF;Z]W bݙHko242:t谔Te FII JnFٳǏ3>}@$z`+2jXIb8yDz I7ܹsm =uȗ,qPe癳6l &&v֭իW{1d\ 'g[Y .l4SLIII>aٲe;vhژq keْt[Zt<==/\p] 5lzc^xl[L &}8s>FȣҢbm|T̝ؗY #%%%=##[~Aa={}N@yϽ{ݓ;{ Ὁ8gǻrss(ʗ/_qss[fMZzkXuf9U[h|Q/4a8el6ڵk6ۤeָɓ VUQ;ҥKCBBz666Ӧ6Œu RY\5[RRƶ1b?EES2ZWrڵm۶zӃHcӧhs ϟ~Jom}@JKD^i?HLPy=Bok$+Wbbb&""ZUUؘbIIIVS ɷoX($P^GvdW }K^oDs5mv:,^⩩3gΤP([nn<ɓ'O:::} kbo(c{̚v?{,44ŋ |6AAA>9r$|B -(縸x =EB|B7&D._F% }C 000%b23g9-Z:Ħ$>n KE O5J9lX˯999.]= HcAHH(d6o:̀eDuPs=̟{{~ՒZ_~ """UUUKNjĔJ+v $hNAt^+,oz6)cϱXʪJ s?8sC{/h;;;Yfإr…'e O@?׼u!CBCCO039uF36~a:M|899mذ[P A H))) .l}~ǷY55Z,G R)""#͌2zzzwnohӰ*B-}r\\ֽ{̳L&]~ ce5AP!eO׃g,uyjbbg"MYL|6qƅɢ>n+V9jŊ^O߶oabblٲWeccbţ_ۑ# ڽ{w]eU`AD7X rVLL Bi=k׮]ٶmpܜֱxrPm{ׯ_4)rlq>j zxx}m<ʨ;NKxܞa]`͗.]zxSSVVv. ..M[]S DHRb@ `+JԢ{v'|9ܢ< /f݀X ^y|/c!!!"(!!1cF/66n]{ce6&ffma̙6P/YX\\%h~ 䡈^2ɓǎKIIqZ7" %%%[2~o7KGH$_m_o֬^ q*m5Hp[Ųv&"GOIMRvv>?#K<==]DD) WG@GlMCCC*׻hmXa?bqqJXJ ]g$Ü,(㛫#Ν;G1*C̦VОs1 HR-Pzv@ZwI`]{s?ܹs9zԷ;uc%x)t.^J&h4{{@臷XX~}?┺x6ˠ!c9H\mX.|m]%oix6 ws8;qɸqʣE;|JR4߾ 9GoE̜ -#Fx蝗%BdR5 C==}4m?|>Rt:fh4xJ烄 hS@xG3W>ܤQ}qsoNZZzUO5+W._yFˁL7DDDL/]6VF 6M`эpppR ݘ#fܽq9;ۛn2 p B\>0pNNNnܸnh;ܹ{Wie}8no,?ѣ<>q{7nX]vر͉sx5#@%`98Wc.Z׷_ J YLOdP@7ټys{d +ߍ5ҳIRLS^ו#,.]ܵ -=U]-ߣMS D)"j'k8~z}}}Jrs33SS#_&ApeX5LY۷mw\R>QDӝßtt|%Rk0N%'%@dkXD8=1At۳2H~1$aaqX6 yeâ޾USSk=Z'_rE}eC(6*,ѺֈСQog)++xzXcC1k Xo!++oO4m'RRRQveDO744\n]eDDDJJJd2vvv-H$LrjFff/rgsU7u7TOϏݏ5^EEE66ow-j(}9Νn&Nr-Llidh]G qtQz6(4t_$""IȽmѣG+8߫544dUV,je6Q i-v_vǜg8ᗜ H };v~ѐX܋(,36_Ay}gN{6jYPPmq-s~MM4 H>i|عsGP`uuM돍lo/fP:ɓclؓ6ך;wjvv&z=ls9:_HZb˖-STT}kwk M{+稯n%諏8mQ7=kV&Hnn/\ݸQHHfӧO@8zQ |fIA0ۨd})]~+U~HWa' ;я+ UVVNqix]Qu%r㮗%LI2V N fk;/((kg|+֭[eعsjc WDDDosQR#0R 6ƪQ-vh)f_`:=8)55=!zxPĄ< lG$}C?eBd9wMX bI7y ޽{ۆኪGt173+> $$ĨSlh|8$$$'&&SU%h0[6]yN4BL̷ xf!c1WgSKJϜ.?"x~F^%ƚfUl2h _UdqJ}(;!~I=*+Qݤ 1O-Q4`ĉ$+eJKK ܹsN윕i&QQϟ? B7 u1Y Zc?TUUO>ǏÇ*U"H&lXqqqc(Wjl9$~C?c@Uv0[kŋmqYJ?3EqorEnz ,--Ϝ=,))ieĺܼ\eeeD\.W_DEDeee;O7gK EU@ <&iǀ>KشjMb9; -ݱtY2XVnΔAg9'H.N:jDFF&;Җk[.G>yVlkϰ7ooٲq˗}}}_z ') 72etm"H JKKzxx}Zz3g?՝jJJJ z!,x(w2D `.x &!<>rrrH Y^'|tk-s`>=}GǏ]>~T_W]~ Y QD(  xQ^^>cXˑTױR(03}l@e&8MX1gy_q܅ ]ɘL7‹K\KVSe`>A=g1LP(35OBBBCk]#C ܍^ze~1,22hFFF7n|}&""$tT3 Ʉ[u ey4&hTRRj~P $''>O]Y >]|=8͚DiEC#>_%/DGx[/-n"@'L#uI;um_:u +wWiXbbbxx Z$Q}\ 0~.:kvtFڽ{wBB¼yJKK@QߥK+Jҍ:P4.lF5;A]VRR3go9^"""Nprv>xʕ [[z*5777  \.W9EDDjjj:8 HMMMy~YʿZ5v`DnÔo'J6c׎ܼQkV/-vH~dnϤ/1%qnJPg8Cu/NӟL"?%0==/_>6L\\Gw+L!Y2__at=ټ! C g-Mit|@.I9!yQ;otqtE6&<:g | NB{|x3_x6y]ݯ޺qs `1oV&{?7SS[ØLYbb-[,Ybii,냲0̑DSpz|/z>ƍ #--8ZCw JFDڊF%A;RJlX,k4 z".))1e0AG[d&} OLL  R__ AK5}fD<n·dg2&hWv K,}~:bU8g箭Ia ?}_"&7!o\,eJQ3\ :ۥb\l77>Gfjrʴi222a>>>ZZZb7d8uٷ#BKn2k-$IIIIpX҃g {(OG^zbcnnsǃqj@N pCeDm|27g{tL$~~_Fza!s }}>G+>~zjx8NAAŋ{QNNNf̘1yǏs\Dμ[qeA"8孢xaaa֮ ,HKKsrrBdVWWw0FZ (((H?*`D{½&J޿y;}7LF767o.RSSNqj#B<$%%ϟxr..s̽w>|(w/_Zp̘1ZZZBLh/@jBQQq֭I) lۆ{ D!8: hɳ̷{/N3y1G8ZHSi &M2dC{0TWWEEE5ޙ4iÇ'Oܝ?099{ޫdzuY_^%$$hjj« i.A:c`2Â@0R@~hlQ}zfRS ȮY?5gx߼ta zE}w/)5Hi ww֓ eۚIF-Zz}__UV-Yd…_R{XZWGwoS‹/^pAFFfҥ;j_|i }yw}J o DE}ӄUUU{cMj~Aƽ># _bVTT_M'&]Rr>>̓]\\&Lk)))hBͻy.p,PK|)Ql^aբTM-( vXZZϏzS\.:^x g L F|x#V1Jʽ2E B/P\%mEY>/2N9N2ezMy:Ǐ/?|݇ ۜs#C.f=e- ...QQQ߳rٽH]KQQQGG244Ǐ ,hVVnTGPc$H,ybʪGNbճkCuAnYflp?>TKP65}o1j~ 1q􌌐/IIkVF -]3}ywdgeev ZT%X &Z]RSSmmmggǺq|2!!ֶft:A(Wbn?m/# ʽ.kky)T8 c_Vdi,!)B\]k)VP5vܸq·j=rժUsΝ4iR Kv0a**C] -|{{W17Zs9?j+a'i㎭4#4,70ToRx6y<.Ih```}mmhhCDF h ?R)+)vܱfjL022w^Jr4+++SQ6u֭ۮ߸˗6;-')-d TUWWr$f=X^G\yZ4^OTY4iq(qǛNN?۷o۶[nUPP_Dk7 1bDpޠ_;zwY`^o Qnqe@:!vDL5T!*2˟z:zQ2|~O%an1cƌ+**x[_wid~DIIQAA!((hѢEuǏ=:k֬_VٳC jjj^re…SPPPPP>}z'ds8FF]6 Ϙ>ȑ#ޭu™.67^Ln|>r¥U{ĉYc?Q6{V굹4 %W<TXG17}uԚuu~4@mmϟ?O07^_O|,&311wׯ]7nlF.HL6h>/i~3sX,&H-PT555{{{AdI7f+p鿤%%$RaEǍ;f8Wnj윜ɓG}nᯊF&Dfa0Ewg)0U,1xP=U| C0m}(t…?{:|􌔔Cs #M$$!ttsjWA\:9-4k*\ Thd2{XMQPNg<6sÚӻ{c E ;ϋ{Ι}cĆWM^cH$"i aa䴛7opȏ`4jS"dD ($j*ZMUT|R솤]#CWo7Κ!!n ^\VEES{PB~ǷZ9V?5uG8p˫27otvv~Yǩ{gϞ% wwºѣ==={^t@:ujRK,Y~;wZ0ad)㳑 $ o-]){ 8l$1*k/h׾YfS%wKHH`0Ӧ]reFFFؽ{ W^e#G ߿{NOI$837!3Ļ:,O***Z# K-!ǃ6V4 ~N %ƣ;cǂdu6oNوC0\,#>I^xH$MM͸X,յӧOQ?$?Ȭpa "&":J`́y0ߠFpWAy))/OayGSV=ByYN+3I@6mj]BBƦ+S_|љ-3ֻ Kqqq:k^LLߑe+W)**mr?~IYYY3f޿W]@FFvr=3f8x~jd"w61?tЙ3g++)/j1!У&޽{7{jNzL,gpcrpX\t8<&1lذ|())i(#gXaQB]bw~(é+..f(6r\@(++ה ^W)455555zԴ c˫kj{.V4PٻPQQ9uꔿNNNFF`͉]a8..իHΎ>G~۳w7cjj .ܱc{_25+ Eޫ8/ DΊCѱqw^xqcJ oݺuk۶mJ[l٬Y-[=^~k׮EuRr߶mУ*tр/^i&11pxp8,۾^paҥ6mȺIzc|KxԔ#[wFc?5vuQasǓ8Sz~4.Bgma BBB*C{~M¢]Nη;ĵ6;o{?z@GNnN^n^:~4Yvvc|^LKKbxw!%l"qqO~a|^ÃP9| ['5b\H9Wb|ᣪlO47e$'CT$uz։It)IƴL& Oґ*.a]!{(׼'a2vuϰR6a}1{X_JYdx ]5CXW^(5#?ѻΞ@ꫫ*7Ho OMM ksuA 5q uBBBTt'Z)+)u. &5ЧOSRRKKKd2PUUbe5u|߻f }V\\\RR qUԿä3%٣k O[k=cҘ"]yH7[Qw?bA,c`/!.0ag1wX$zݒ<aC!hѦ"R\ l)Fva6O=Zv'axOüdxZ frz]aat7 $Hfg>>bFlCUC6 @ d .#!x<I] @ P AQ I6ݛI"~l[f@ @ P AYHD&3t.ۏ* 0tY,׌@  t?j]mUyAqyb!D%%:@ @@ @ %`@ @@ @ P A @ HY(VTV,H@ N㣈IH5v) :1,?Q@D\,(  Es $ e%,cP<6@ Y,~~dEY1FFNA"é.MPXX\Rj"tb6TG@ GGauuҙ Η4ib >f |aXF8l(CDcldr cx<(X7zEG<(_,$ AJ;jl@ HHVDMIP>D"٩++%K0 H-p@ ?( !.ޗ $(b$&`H@ H~K>}͛߫BBBjcnj"))ٙ22ƍx(P?L @ 3AQ^Aa!h~|Ƴ1c?(?~r劥䏟>vueb(ʃG @ @JJ(nv+WˣP(-  ikkkkkϟ?F={v=wWh' p@ 䏅Jm7!ٷ| u{m ۷o)))$iƍf)))՜5HR $@ d`PRVh ˖/|TSE(J*Corm= krqQ1.0@ 򇂢CA1ٗ&O*.aXEi)}/\trrRVV{綾^(!@@ @zwzٮ{mSUWW\.DpE'/^25 99dJw.dC @ &(%e-ryl6~˗y\Y94WG E#!n+VZYY])$H@ ȀHʊKffFxxWß>E}vÁP 7sss_z,dAD @ XPiwv.,,f@8fj!Y+/o`}ʘ1c^spEC IRLViB݉>8es\|{{;BH$mߵ;hcM|,yab؀!cT*]~544&MTQQ;wӱbbEDD?BQQQFFFL&sf{?jVV\4$>BuAwaٯJN^湤U```999=|PSG H[w*}CI9I{!H$X#sg~'Wq ;hg:xsY2c|GhWUSيi?hu"!π;@}iii\.S?^" nܸٙkccx͛7\nIIڵkY,[lΜ9999p f---=7q%N!FdyРp!8mhhnݺtyF~ydHː OMM .ez׵jo<6{ȎАgTZV.WH!7{~M?jQ+'M|",zM,wt`.ܾ{i_B Y\US!0JJJT*U hSϟ?]ߺ!!!_~%BÇRENMG(v$INGGD"J‹d2jʔ)vZjUUUm@@@FFԩSkkkHMMM&3 ,>2dn:H.Gu{/e;>Bףdn1l0=MMMTh4x4pu3Q,Ť!}]Rv. 457G/r`$IqI[/76]oRbqAA=<ԩS_t'N!SSSv)&>0RMMM0Ws=\d;pdRdidg d{d"?%KO<{rn H|Kُ++kΝrD@XL=c=X\T\|~BHKK-oMMM_xXZkjh زmUm8xe[|]oaCBB>ӛ7o-]tW_}5n8ƍc)ʪU/\ B5- ^{̾tf;јce㿕}KJYesrȟidd$ψEJFF?RUU%?_bHlwh\ özf𬙶6Ɔ8&vqscWk?IDX,lnfanCںz2O>Ϯ]V^=i$XS~X0aB\\|!W_)++/YRWW7::پ@d9D#F xQO<(--566Ŕ#_UQ2Uty|= \2-yr?PYYI${>|ӦM^^^?SFFk2dȆb<3#xPgFy sAza)))qjj3^̙3B$gB]$R׊˓&M9 D{L*ψH$Bx.Bz䁋 zzznذ~3g9l7/KJJRWW뫘KEx.BjlB2Duˑ#GRSS_uLJJʌ3zӾիׯOJ-scA;w#4ȩU~ҥKoܸr7oJ$33k׮<]iiiPP z $ރg.[d2`dgĉǏ755uڴiѣUTT^u .x{{;Rފ'PD$g!!X2tf洠 ._c!Ht"gϞn) oӑ#nn"4z2ha7`$HfBssӜO <811Q$!mӄw9T*=zիW\fEnON$H;/7;HhJ}~2== """==y֬YJJJX3gDEEڵk?)_ufhb7A;jz+m-OZY$---))jjj8Jq:3Ҳ]9S}]]2o$3</H^H, ͈˗'Sh#'HbH$ⷶ&k xhJ55HdUkKRagV[SAW*)÷[C"END&ih6h?zdok- !N؂㍛D[$"[PH&2f*bkmyjmiQpOe%%K [wTV67/sWYjm9t1Vv m(ߋb$З訲BUi/ ˗#g'p'4/nP 0k֬Ν۸qcuuuddd*zyɷdff*++ hz~r-Ckk+NE^^^QQQ^{&|!@zBD"qܸq]6fddt!?k֬ǏGDD/B!LvרQ$>eh+KW\5k>Tp8`.d2Bdn%H$G? 05>|ԤyuS\\L"###MMMB޻wB(55u֭)Sl߾!TZZXPP  "## eڵ400p, ##!ty*%@zU1ϟOJJ_hQ,z(gMM͎;\nkkw}<-"D"u+99Y*N:U*h4DB H$SQQ`06m?ƍ7mB/]dmmMRtzkk+9&]<\EE!$TTTb1Ǯ2=:!HBP$dTݛov/̜9@ PyU__XZZ! y<JKK H̙37n!ɉ;vƁptt D*L6-%%E (++s\KBBzRRBhСg޷o_ll,5x+V+,,\dIKKb p8&&&XA###M=S,}嗣F> .x  " '_}m99cccuttfϞ={ua{v;(Kި7v$@wyYcc*6Çg]9"t:rF555lki3m IDAT\]]=??k ꚕd2I$#BHEEO6'7a„hT:~.z.*L$i7/Beee۶mc2~~~RQQ | R`ˏ?}mA&mmmϟ?xbQkmm[偖s^^ޣGktGT*v6}e˖j>>|ȑ#^1/0~QuuuEE~iffbŊ_~l`Hw$o̢E"#####ۓT7oXgeeEѰi/_p… 1梢"ҥKߠHd2yoVరŋ߿<oP()gMMMLLرcx|VVX,y@@ $ɭ[ϫbqCCC8pbbbDKdd$6d6hdccu["ll;fp8 |>DmSl LܹsIMLLRSSDill|$&9uĉܹS[[;f̘WvU<zQKKː!Cd2٥KƍGPN<鉵|ónݺnB LOOQp//;0,D233|>B#|6YG]]ݽ{tT*=s Lnll'$9&)={`0?~,ɆM >@|^T86z5BBXZZB>IGG)++C>bX, fX U;"QMML! Vt)J #E$544tvvAI6@ي%H=z ",J>|hffF N2 O4A(bBm xӧO*-hgL͟:;;dJuu555,K tvvuuN "?[UUER͋zDL&zHJIQ([[BMMgϞĶ'O(++߹sFijj*++x"BaGGGII D"R^Te ~vQ[[K&544UUU|T* ! ƶZ, ne/`bbѣFcccNG1 _LdNNNP 0˗} 7ytz3{ ;YN8ѯ:`%tssWܞ͛ov˗5q#||޻1;y r @ۚ5km۶f7ڵ J=}Leeeb@P(?l @ꉋ׸q͏?^5jb/_ W n"!4W4:uO'8qbo3<ÇMMMׯ_p8$922!t{bqnݺ5444<<!TYY9eʔ۷{zz"JKK BUdd!CO>~]v^ۂdddY[[#Ο?ORTū 9|RRRuuEdC9kjjvr[[[544;x0訕+|GV%vssrs:35?lp+9O* ZbwOe748YJMM !$ eHtJJJ512i7o,_bbbijj*ߢTUUKRM6]b555!+++:OP\.rx<]l&;  hkkxyB0::SGGaUΝ;'H $!cbb1~͛7?{L~lEEEf5jèQbbb'?  --={r1ɓ'[[[7oᵵ^xM>_WWmT !ֆ嘖&Ӷutt477˃y .w(.gϘ`hM7v='cnj07[0_&͞1COW`iwjim8s6jY:SGgy9WcWZ v0z@$y29s` 8n̘1W X;:bX*޹sP(,//omm IKK+,,r'OFD".;c "Yyyy@ qqq%%%zzzW\Q5Ce2ݻwCBBa=H$ZXX$'' WWW333LXCCBHe#7nxx<^"`[#"">LY,֙3g<<<BOd E`bq{ww FlY*b,`o7f,KYYY__F!RizZZZeeeزP(}vIIeX<f#Z[[bqJJ'H$#@0"555.嫯-g||<ٿllٳgϞ kTTT̝;i>lllNsdXNNNSUUզ&l 300311IOOP(`07$QTh<[D뫫g*=zw^[[B魭]peT( \*fש>bgcoE>^çLddh7bMEE&$Bk X\LLLt</0/\]]=?? L&DrttDiӦrN0!::Z*?ˮ J&[ZZޔSGG/@o۶dK2l7nVg̘q52OB!LvrsspX1fΜn9s{yy]r%,,L"O5|X,Ux {%;QIRy4R4++ ^X|ȑ/V8WWWWTTfff+V_ @Ryt+++377ź7 !_QQ455zt{-uy_X^s$8b!4N6;{ai=O?gϘ{PT*FmO&/:BhѢEAAAT*588Xu묬h4Oi/_p… 1fҥoGL&o޼ xO>}7͙z(gMMMLLرcx|VVX,vss:jcI8N&R/]BGS1c3H$!cCÈEauczА*m -Y3#0 '$$p8"+Ou4-aRvv63xÇs8>M"Zl6{Æ IIIL&sܹR&&&uuuD"466V>E kkkssʷXXX`SZa#X,h|>L&cH$P("T Э;v@ \鲅@ #_;3?~D2L~K*=Cܦ Po'MNM~X0Э[큁>>uuuXC`ԩ?F 4_~qvvFֲXFH$t<@$I$H$>`0D"/Q(/))Y?TUUd2K,P']svv.**r8Ehii ng4Ɔhjj ~ 566v ~J>>=ǚؽ@Ckݺu_`pH|0UUUUTT^`Xaaa=yiaa aKƩSjjjLcƍW\\~Fb2 zQMM?0|p__tmmm,ɓ'C$08qbҤIWf2qqqpN/))9pIXX)JUUURǎSRR MMM555_5N 8qℳ]\&L rssL܅H$ruu`N<`0<<<✜l8l0X󃃃㏶ذ쌌7o<$Ht:ݝl6 \ :&v£ǎ=NF07_0r0¦(d.ûhg.NDΜ<4*=##xχY5_}"ammBSL'P(/F!BRtΜ9JJJe˖!$<6b"(vek>[e`ݻjjخv*+Q/xexGI?3,4`$N!n)Q>Aݻw˗=3xՄEx<}; ޽{L&Bttvv溸U{ ̘L/0 eY;bB>O '<@ 8fvnA% [bbرc  R[[tQ==˗ 7n 2$ !mffg)%^toX__cjj O*JeOI݉2O#\274$X(&B{OǻO6s6֝RΜySêe,KFOWkbM=ƽUiƌ>bYYg#B !tG{G졳ȟ,Ŝ׍ MD"nNrNnn}C#SG{~qcF\Q>:g'GнEQQ9'ZC!6|.hϞ=OF-^<,,K`ii@&b,Xpڵdl|0luٲeة;܌uw|H$xq;w>|kYgLrА`Pl|B}}á䤃Ľvٵζ{y9Ix<.2*J"twkץR)vȕ>#Sg.Y(!{[%+?=!(ںe+W|G`5`0VGdv ¬ Lutz;Ix{[ʧO{(գǏEbF< ${@E7sYn߽\USs:yH$CfN :֖ǟ="rU^R(H$2 a[HDLy ~FLD, ι7ҧ\x~.Malsرy~H*sJUUD,626|Ѿ#> Ux;h_12B-flBeeek׮0aɓlق=ɗ_~9w\EEE+9.C^TUO >A.((Z 566 2D__7'imm[nݠA.\ip5 IDAT&%%S".]f7m޾gϞ =zTWWʊN;99!)|pU. z LMMcbbh4ZZZZxx_7o^r6U_uuIBBB"##_^υBatt4xٵkD"'|"H222RRRBD" ի8PRRoiuZUU ൲.\05Do 577p.L&񅅅***!$VZeoo|Y>|h׀/gIIziu'Rqq1BH*K*pCX,NMM=sLmm@ 6VTT~@CCCARQQq9 )X5@ڥ ]6?z d <@u`/Rbb-- ۷oXXXhjj:99q\l6BU,?~\~Dש}|p3{ٳgw2!!ĉK,qppPVVnnn^pagggݧ +顡l;Vmڴ)22FWw 2Y4ɱK[[NFčf{%%%X+5WW׬,&I"_-֦MHGG/@o۶d̙3Avd2Y"(nikk鯭@Ankk/noo}5k7~&gϞe0zzzd2𠶶֭[6i89//֭[XfKJJ.^hgg d2f߼ySOObXL&c/d26F&utt(F2ϟM8xnmm?T \͠xo޽K_GPuu|XÇggg77H27ɔ|>6[vvڵk6c- jooONNRc]]]7o,ʊFa#7,_|… . b2EEEKH555'O7o^xxx՚c,Xu255 ?Lpww_Y,VVVVFFkk哌=ڵkΜ9]Z(P#Gamms;L&J/mWtIjjj]]H4553)SݻE[[111[lY`D"qrrںu zOblliӦ}} 8q>[Hf7B*j77M6M4iL&3..n^^^.\%%%011 255RT*uРAÆ  P(rU<9غu󽽽}}}3D՟EGDݼU 'ZC[8TBsl&֗`f'?}b 1'׭[`ԧ⺺^Nѣg.Xßw͛1cBh/Jeee^^^ᣏ>ڲe#|>*//oժU񇍍mll.]ptuu&O1}gϞ]t_E͛76}%>ȑ#cƌWTUUd2v7ەh"(fMRSci444o߾rhrppxmt455޼jjj¦H$-%H\r%BHYY9""ǷT|AP/^Cac>T*3g6peˎ9ڴiBHe˖%&&.\ڵk999&M @wFcGSqom0?l1_XVVnlbHk++s{qP$^SQkb(d҆oA !dhhHъx<| DGҍ7 ?sGGGb޽[__x|Z3Є _Uv9b.8ԩSϟqpp8yG x&ؔi mD~Vu:B aN9يe,摟S,*** mN [!E">[loookk~W˗/_A~ .\}.cOGGbT>|8Ç_x$~=\EE!$TTTbqGGFؠd2D"a BP&,|?wtkni_\uzlWД@;[в׳.;jdƙiDZ.? )zJ aѯ>xسV:N :;;SQQ"ɷnݲkmmmiih@[[@ JJJͿ/wz3ç"Q4 U {٩"8`<{`D:>Hd23'7.C^U>}ZYD&-XmǡHh#F(//gX'NpwwtFúdffR(#F5 ,~FLD, ι7ҧ4=ebXYY{ϗH$]'#x/$ Б||]]^ѣ[_||{M|d.KII);qc @RiVV/HDX2w&&&RagXOX+++KK> 'b˛ .)kkkTSSonn>{l@?D"F ߱N}ރ mm~9.hE"fϘ{PT*FmO&/?t 0&b x<[~y7s .[t(++J}:V$AK.ퟵto1n.;Hz.]'j7H@222L2tP7>I~~{2>>~̘1 @Cݻ $P(J ť5[.*AЄ%!$,?̝ `@|{{އssJVurr Owq!\.Go7onܸdMfw|ychHɞby{svl{⧀QQQJD=@V֭[j:""~j7o޼fsέ]Θ1!t˗kvttڵ+55oqww 8@*,,dJSTT__Lwرe˖ݻ7((t֭[b?IiӦwYȈ]z֭[}||pR<<<Ba]]ݾ}rrr?$WZ%^ޗ g݆AA^C=Y]o;֮={(}G}G{)<;/_)`EޯZɚG1Lgg&|4֊D"ކ:99rJnjVI,))4iH$WE\~M$˵ZmJJ _BJ>GGtqqqF#""l~`e_~xѲ~v묤Б#\wZ&rr۴ڼztPꚶpA?Ǽ_Z0w.;qFs>>O>\@L<)`p٢4Ms?p;˟ON}ggw/wА!CBwppX,ԠITIE"QXXRH$WjM&B8z(ulXlH/+++77 upphmmMKK3x-[ݻqFWWy͛7|mHԗVj?9!fq߾Wn׺ 1gZSd2u :U$۷3ߺZW`8ZT?  7%b\.W֧l61S8tj 655!\\\AjڶZD~~~B EFF9s͍d5 k̙3g͚5p?{9sŒۭ~!Bɓ:6ÞFK+چ1"d:A>=@B |պ?{G7NS^oxc[&M53qHh6V+q`X%i4M=O6m|)X,Jt#Ξ=tRpڵ54-<R@yGGG~suu{::7[Ccخk.[ӥ^bTj6o+XeKMG58C==VF Eg%=gQ$:n;Dl;|G\.wΝ:g+((Xz5kɒ%fؽ{7INN\n.00 TYf"/GJ5} ,v iǏ7nD"9s N 'W"̙3& sKCBCCY,Vڶm[[[L&;sJ>RƍOcƌ'lS`XyKK/8lGs{'N;d2weK\GVܹcXGƮO?H$rzyh{zY~OwYYtM(3gk{ >_/O^qW%2<Ωy 1ó .FPy_~ ***BaFFFR?謬LWcE`‘RAA^ >/tx&"#VbvY.33sf9,,lÆ x@ dnlld07n܄ b".nݺ~Tݼylsrr1bĝ;won']^-_,z+d2 7Rz֒س'J陿MYO~o{}/;w:l6DFnYyXLѨ{[Fa?UCeeeIIIhhyZO> 7a͚5=OLLLNNf>`2=<<5nܸQCCñcǖ.]>}:""(""K.^;::O=uꔧȑ#a`08::j4.KјL   vܹdɒ;f]]ۣd2߿ɓWoa

$ `ĉ'O|WөN駟.\pZS"ݽ{f[,І>BYV h؟m AiiiV @#d2LȀv={v  Ff#N8!ccc7o~QF3d2t˗/GGGooo/)) rB0((?1`tt4> u8ۣtww7ÇꫯpO۽Y|2wlC}7Id0/ }y=<ŋC; 'K*>|MI)d2涴h4Du᭷ "J2 l6{ҥ!< |Ek{#d{.G1u~j/O1@qq1F 8uTBB:th bup`c'xo9rӯ\~G;vpvvNOO?xٳg')yWcǎ˗/\2%%aX=z4ޫ %%~TWC@zXrOOϚ>ji {>N#HBdCCVǎjxN{A{{[[[pFm%IR7442'Nj{.Ѐ+VV5M[[>~QQ>>l𩩒xh4S~駟rʕ+No\t .]ZUUx\:..aaa7n|饗BK.;XB.zj#GT@eee )|~GGBH|d0xcƌ<ш⒛J$~!((l6^xQ 23g޻wl6߸qCP5.]/((3fLW|ABBªUzMRBMY8o޼O>٤Żw&"66`0򊊊@`26'A}\\h4:99uvvvy---bfwttX,_UyyyWwX,hĉtcKK ^h<==RL&;y$6L! CJ$FP`0qvŨl磢lӈz{{{zzöh/L&6- [ZZBJNX,A▖RKcc#^5dT_ KReSNuّJXZLH 8ۦLrر{Μ9ٙ$Iٶm[uuӜ9sϟO石o߾d2}}}B%%%{ C>|xÆ o6))i֭/BbǎW^%I2000==}Ѷ϶mVQQh5k!p%̙{UVVܸqCѸK˖-xJ_(JV駟رСC!\ruuϷ7oܸqcEEE[M6=j訨HRDC |-Za?Fj7o^fϹs֮]r0/_^|\._vmGGǮ]RSSww@@PXXB6T*1J%A8 *//OMMxǎ[l޽{$u:ݺuVXO$B~ڴi)))]322bccW^uVT*PXWWo߾|>$UV\tsѢEf9//OP cժU)))2… [lK+uԨT#G)VUUU\\\SS#|CBBBӧO/--NLL;vpww/t:BhԨQXjJE,իWgΜP(zR vpp@eee ;wr\PLL̼yrrr6n܈+HJ4 |.B!"Jqcǎ;;w;wL&SiiG} P|>AAz 233LjnnK+!lutt|:SZHd?:B:99rJnjVI,))4iH$WE\~M$˵ZmJJ _BJ>GGtqqqF#""l~Ft:{ .Z`p8x !"Pնj5B~~~B EFF9s͍d5 k̙3g͚5p?{9sŒۭ~!Bɓ5fͰhJk.&z[n?ŋǏ///vZggg]]㤂7nP(xMiiK % L&;wm4͚5k=<<ݻ UVf:ڵ GGAiilhV*p_֭[ bmmm_|񅷷Ǎ7g*-0О:uJ,KR5bĈgR!VCCõkרp4-<<׮]\./++;ȑ#qbryQQT*'Uyj0ٳ=6lػbp9!x~w}i^>|xdd$:<GZ+$$Y,lPcc#^b0ԎT*H$bh46p8OOO6v5T* ikkj /b2*uUe0 S`pSNfl>#.sNN^dɒYfutt޽$''SFFF[JXpLFFFZZZZZڬYZ[[KKKB˗/XT*,X;F>~q$ə3gppP8AgΜ1L+___$:bҶmd2ϝ;V={60o޼FWWqƙLqገ&ʹcEh4f4qF ƍg[!o'2 5B:ӧy?:tcjն<$>eh4j: ;ׯ߰aCEEP(HJJ›333 FDDDzz:^y<BGJx=6|/2;;;++Kᙈ쏸Zu]ffSSSfsXX؆ RSS&@ >`0|}}7n܈ù &$%%ٳD\.wݺuh%[O ɤϴ[\Av˸P<^_qm:>lذOU{IVJss3@z>o2 t,d$Io <iСnݪRфz#G8pM111111LJۼysb2OSGR*bDDDDkڮ ?SzիW>T%Jv f6G!b٥k dFb;XNh:O9@dj^,wsdRF*zyyA0t:ݗ_~iZ1?~l0LB $IvIپxpIh:O9@h555555UUUǞt՗A~knn޶mۊ+ P(!_ߠd2[DO9@1Pmm-%!Ad0pmVv3 L&FS!N|ƍѣG\pYD"lnhhe~' vwd2hgN2F :n4z;< $q:Dd[&''gʕd=]O={„B d w& .\8!@He"<йslB8/Ɏ8pGG{>}:99yĉ<ASSݺukڴi!!!4:2Bh޼yYfNe,˙3gp}_t:2L&$I&i0pqqyh8yC_R8L7xEP lj.x?F@ GeeeQolٲe49P(]" h4d2be0E1 D"Z+jc<ֽدȵ744 VJEdCCN{N#I˸XQQ`hjjG߿ҥKmmm:qVxaAxfggC h[x1Bٙ$II{(x&Bx&V&d3=GJ|>!L&E"`gÓJ }WUUI$u6 8L$ Ã,Fdvvvf .lOJJ$**fʺ?|pOOO3L\ !DӵZȑ#]]]lxE/&A-X p1<ҴiӞZhц ~)Ϧq?N۱cnj3~mƍhYש~ N\ +Y"b'ɨee'H3fL:Q9rd'''Y[,(( f/]!4rH~#%!!*R*; !ۧ䇹wl6m?x._'Y?l߾IǺ:jVWW_x1??n ޽Ԑ[l|X.Sǵrċ+V0aBlloqڵ.rJJJJll-[Wx͚5M6!>w/^{kxUb+++W^ꫯN>}:ߴi޽{u:\.SNE݆u픚%%%gΜh4?ZYԧ$ZTTRD"L&5j677ߺuKVGDDOj7o޼fsέ]W/_|r\vڎ]v~70,, !TXXfQJ ѣG#SSS}}}333y<ޱcǖ-[wޠ \Xӭ[nŊ$I"Me1###66v[n\vŪT*PXWWo߾ТEfs^^B@ݒ}XUJ5n8. tvv޺ukĈpk6@QT#G.JUUUqqqMML&S AM>4;;;11Nر/QF%&&8p`ժU8Q*-X,W^9sBJ288ǒ% w܉cbb͛qF\$WZIU O|OeQ(`\\\R@|vŎ;vرsxxx@@ܹsܹ xؕvkv\7b  pkgQ֊D^urrE-3FVד$YRR2i$*PH$W^ŋr͛$Ikڔ)Jtvv*xO 8jlBNGDDVʕ+˖-qq@zvZk2'$$| ~kF=DGAX,-@9a0}At})|]ex<߿`Xpw+++H$_^VV/”JD"h4r!jM&B8z(ul=dȐlj_xجܷ~;445--h4l655@2p[^i4jT]ft:\Vk0bMMM!@@Z-V jBaaaaYY/с|>d2 X,htsskiiAuttp8w'I#11199^%ɴ'O>^p/x9FxI&zX}ԓdRF*zyyAFEDDTUUu{Fy<^hhW_R xZv=nR(^`PHqHÇ6CB;0d @ =  b' s/HwAhO< YAS* ֬YУ#x @KJJ0aBsrr~&߿a N|3f̘:u*z/ȑ# ,899@#Iט޽{fyڴiv ߬VkMMMMMM{{{t::tL&?-[?m۶UWW;99͙3gT9;;L&3<<<==!TRRgϞ0Ç7lo,[ !T[[u֗^z !TQQcǎW$>zh |g۶mHLL\r Y&//!+9gΜ{>ꫯb/6mK=VVVܸqCѸK˖-M6:t!$B999{*Ao*))())ikkp8>>>jT*HcdZoݺV#""HZvk֬9wڵk\3B/_^|\._vmGGǮ]RSSww@@PXXB6MMT* Ayyyjjoff&;vزe tu֭Xߟ$IP}}iRRRӻ,fddƮ^z֭>>>8x\u-֏UT Bn߾}eee999E漼> "..tzDDmݯ\Gu_P^ŚLz 8CêhlO#n3SN^ݻx< !4d, =`ee%IE"QXXRH$6jM&B8z(ulXlH%VvZbrss~Pִ4ؿlV#k<lcDA{} jŦ&@ BVV8@ ²2_y777&9j(!6sYf \X.N*x$^Ϟ={Μ9xqj4t:RN>M}>uX,J,kĈgϞbk׮Q#h4Zxx˗]$\^VVv#Gb"T*OO T=kٿj-kZ m,w.XUFӥO <@鶣0Ͷzrw7\t>+((Xx1kɒ%ϟ_t)INN,..6 8a]`` S*x|Q__^r̙3YYYYYYvRobw&Mt۶mh4Vzj;-KѢ?^UUOd2jF#JYϝ;qF<>AٶC%Z!fZOMhf7x HD"""jjjjjj=</44˫/` qݻ-˜9st:N'Ih4'N,//hoob$IF#H;x ooF#vxt:a5/f>g|>d2t:SQX,$I'Z...{!;;[$$''k4HXTT4qDf0jjjBBBoW_}4 ?ĉ jFt|].\5jT^^S6kkkD">&\p/F777J< HO$\FFFFFƋʵgqBbh4jbK$ jll0aBii LN+))h4k֬jN 4۷nj3|hRwFɩZAh4oKKX,6Vb jnnDV?h4bxƌ3s---tR||<.,]/ΝKܹs O `)$$S8qۛ$I|:B ?p4{^HqHÇ6hs駟fŋRiHHȃZZZBBP.:uJ"q8ɓ'SNO0v=vXhs`#IKZ|PإH$B988 z=1LT%UUUb!`0E"QZZڮ]lT*%Ο?UZZf]]]׿Λgt:]xyy={V,766RDŽ  lI2b؟rrrºLfe!h4>&1L |s9d2߿ɓt/PÙlvM+- FmNAl7,]{x)L&mh$\:H,$\t{u2ԗwr\.d>j?pR~$+++===` O @>|00 \.^xRD"Qmmi^@hb6}&h4Z,h2H4Lkmm[qw B޽{& )$`4q ?- MOzfT*'''Zsd& fZvvvnooommZK*LRggg6`0lsR-Kcc#t"ߠ "" jjU!$\3p8$I p1F3L\.W $" , .d2;;; :g`AL_?dZqFf D"δkZ80;Bklld^^^/Գ>yu3 oood2 @ eX:::~sj0$I`0Lk8wVUQ.-ܥlNh % HCQ<566F]]]u:hBPRI$^o4tP(4l6Fq8HبV9N]]]1:h4R=Fpww/..r|>wًḺr CgVmiiF lan457\nHHAuuu---:8n߾MzvF$]A z#ɉ{.*b|`ZAA {Q6C >>>n?dpJFKK ˭HTl6Ob6}zxx̙3ќ<999BѣGYf +))ɑnݺxkת-H$7nܸx͛7ܹ& N/pc:899999pm7reG P c0˼C1ÙJSSSmmFA7ۥRFFQRF(Hjjj h:-6 悂TfA^lnii)**d(m۶}W^ݲe L5k w]fP(ܲeKGGGzzz||#Gx<r IDAT7ND"Q$:E"=z4 Æ KLLRYYYW޿(R>OOO i%Hf̘yז SRR>S@p[1"hƍ}YkkkjjFF$""9+++11\^[[v6lp@~OT:dȐh&YWW?۷A &hK.yzzJrݻwAEEE~~~`{qq1JR2thoo XikktVf,wlvddSf͚uڵ ۷oؿ֭[.\pBARSSO:GR(Bl2V =z4Ͽpرcʾg`VhDDәL&U`y1 2JZ&z޾@FeJJZ+Y#uuuC m:C  F= :XlllDёNcXLfYX&AL&3??3&''nȑh4,;{9s=O}`\nyP.h4tw|AQQѩS=<>P"Vw}@{_}@ 6^II=_8Ua0 X,$t 1Pxvrr4h4 ehXL U*+++l6kmmuqq#tMMMPD"H$\^[[ ^5L&Xfj0f=@ Gvvv6ʕ+U__=4 ݽ{޽{A ׯ_@ |>_x+õ ڵkǏ[ ><55#Kn:PYY d+WO6MV_vҥKOk;L&2Rloo46a„#K!ФFRI$gvtMj H$$H0 )4Urh4ufA*dP]RRC˭2P+ @%6 p8߃F2|Kd={T*Pݸq#jʕ sػw/D԰3fLRR*XMRrZfڵ˖-[lٜ9s ^fͳ$JgΜxbj>OcVXjժ 6(4ٳg'%%1I&uT8ydWWW,c0Ǝ`BBBN>rsrrΟ?ouΝ;Nڇ///WWWNW^^N$_Aїl~wQܹsԏvԩɓ'E\ޤO}R!@h:n5f{ۻ@6Ml@ DѬ"ߞU0س䔔G1̵kעYGCBBRSS322x|pppBB*t FqTJb|||r3& iCP;==}ݺu... jTTTRR{رc x<~ذa[nebbbrrr||h5jTJJJ||SNMNNvrr888UTTS(ǏGYes{nee/bU7d2ǏAU`A7˖-RlΝ;ĴomR@˰lVZ&K;,y@^b,@ *S MR %%% }l߾ŋ!v 111WIZ7|s>(k kk׮yyy٨bbb} :s> |tAh+ynU,77W"L<ٲ?}Z.MMM }M]]pq_I;#H:4iҤgAzdgΜ>|xo= /={= #h42L;;;WV5 HTT@рU.`U x`FR~@h4JR>8Y@^˄Fp2X"p8# r9yZsΐ eڴi={DDDޑ-?feee@ ttt>(7|||<<<?~[ZZh4cQ4`0h4*RN Hvvv`Ȫ\\\j*Κ5 ^ݷL-[,==?NJ DVA!Њ`Ť qMj9ӫh4 B^omm5 Vq\S"V* bj @ Ag|cǺ$=z4PF߾WTB~ҫ~ P(Z[[A, 8RvXy;@ t [ H$ J{˃}v$F#FTTTt:B $sݾ};44R pz.k2?>eʔzT}:C/򊊊jmmJ6mǏ7MfFEAAApppp)hyk2gEwP(D"q@ذ`֟NrDR]]=? R$DGG'''92,,,77׷7$$d۶m 3g8[C/1bġCx*jժS.]O> [n-,,lkk[bŴi,A|cc#ũSp8͛BZ_$`t:R4&h4+ T*HPzuG.ݻ'd1c yɓ'w>&c0O<+A 8Q5?~<0}_@ bݡ @ } X FJ+d0xmëITtGGG[1!khh˛1cF[[liiʚ;t萏ZիU*xT?D"Rb|||[ RYYo߾rGG7xc4 4/8ze5k4779rd߾}6n9$H***j5Jz ;vl}$fC Ϸ5J$GGy |LIF&B!HX,… a ҖU(=&ɻ%:zh4s͝;7---22ҥK2LR9;;{zzT;;;=| \{}XrJhX$\PP Jlv.lnii)**dwGJm۾kwwWnٲL&Ϛ5 AwYF(nٲ#===>>ȑ#<ۛN)??H$D"PH$b񨨨6lXbb"JZzQBR%%%}':tg̘yז SRR>S@p[1"hƍ}YkkkjjFF$""9+++11\^[[v6lpz=p d2~}!2av%AwBh4DR\\LRd<OӕmONN^pKEUUնm>gϞԤ/^oZmm-tHCC 8N.HzwwwRYR\]]Bavv!CL&FJNNd2̙3Ç3H9HbX*w򤪪X,wO}x͜94###&&åx92&&6lH$Z|d*,,={vffZP("חB d2C& ]p}n 1cƠM`0X,ڵ/$?s粳ԇƤ{zz&%%]t> 8p`ݺuÞ>}Bϲ`(--ꫯ"##tcܸqƍAAA^^^ ,x@裏@ʋll%0L^[[+HT^^`0AIq|ewرc.]G3bA@'^$/ŋ!!!].p# lZt*ڟʟ9..ۡsrTϟYGGz>?m4AΝ;SWVV޹s֭[s)++?@AH$L&_hG{n``ǧLB_|{n"h; WWWKR>_]]}%KAZmz3JH$vg2d4+رcvvv&LtrL&c0+WL<( f^B899H$+W[n/o}3g P( bٲeZ\5zh>…cVWW}`JMәL&5L$d2Y]zN'''H$A"N:5~ׯO ~d;H82*,{'ςL&ٳGR܍7V\0gΜ{Hv̘1III`7J hk.[lٲesqvvV(YYMJ3g\x1x[i̊+VZaÆB`57{줤$1iҤ J'Obsrr رc1LHHӧ#""\nNN筮uuu߹sgccԩS啗WPPˉDb?b6N#XMM>Abz"f̘!\\\"## B?h0:X`9j+롅;iUL"x<|]n!(6-7 IblO灹g a0rXipv,y-$f, %''>h45*%%%>>S&'';99YZv***)Ǐm1}<oƍmmm zeޚl6;99}/S>AVDZZZbICCCnnn\\N;qDLL چ@ A :{J\nKԲ<Nwww4`۶m ͛7wYڵk׮]ku[Vk J1[8wsssUU d,Gl-[,X}jA}+k7rҘ|>lkZJondTϖ>7S*zb`l^~ڨ n(**xO>b'ZJ |yyyJ:H/Ɋ% <`0d2\.e }@Vܹ3$$o=pBAe>}gϞ~?FYY!``}~Piiih@\Vh4hTJk4h+4/d2,m ^LPdoomg˖-K,b0Gy{{jGGǽ{z *cX ܸqcȑEEEJrĈmmmT* T@Z DEEٵQ(T2'NxzzjZT|%<<\RYC t ,bqUUUg:GR]]]ap~%x|CC͛ B NNNF{!)))6l~?|vpp &oH7~jkkVQyX,t\0`p8MMM@ ǎ&cҤI'O={ZmJjӧOGEEˋJV%4M*r\FRZq4J333z333o޼I}ݖ٬V/]y<˗ N>P]]b A~'^_WWSRpf͚U[[k4;bG}sN%`9dBW>R>@ x)gAPw|f޼y]Xl/]=СC ,Fna|RrQ$`0/ZZZqqqpr\RD>b(8sAWW׀LPUUZUUp'ˇ >xY@@ 2ǎO^[[gbL&dzwߗoK$ tVbbb`җAkk+HT8@ lR__O"ʴ!C<~bS---, = fDDDL&KmnA֯_6&Nh0)(tRɄϟO$`Mohh(8jDВ%K@ǏWTT{, ~A- y0t?•$ |>~rss#""aF ( :X[g- @ b֭O8188ǒݏ2Xb0NhлtAh***BaBBBvvv~~~TTTvvvtt͛7l'D"ѬYq8eU*@Va0k׮EEEjNP(z=@UAڦ&ZDPJ% @ Th4 p dz`0LFRdxK:HObY?GӍ5j֬YYOeeeUUՋjU[[[zz:NӶݨetX, CD'&&~WqqqUUUeeer_-++3 2ƍT*B|%%%>>>F1''G&ׯߵk𵢢v=a„tL`b3Ο?o @@~b1@`0] 0s :ӂbq8Frj@4448::toߎ:s̙3]]]nܸacjTTT=z4''֭o k֬.^v՝;w.Ydr-00P.\pH$2VXTTrc^~VWWׯ;99u @@d2D" Śf@ӵZ-T<>dxyyh4TẺT*uvv u`… \.~ rNR@@@FFFddTaĉgϞ8qÇz^g1bĦM<{l2i&lXXخ]oߞ'899߿ĉAAAQQQx<,mBd_fNX,V{{{ccL͛7ǎ 뜜<<<.\t,際[[[l+8Nўnwvv6 b>plقzDt<{lUU\.ojjZ|9bh* t ZV[[[sPf޽bM:to߾][[S4ǁ98D"Q͓dW\OOO4?BQrf744DEEفlf+W\~@  ڶmۨQ.1bġCCBB=zE*ݻwCBBt d0;H`0p8h4x>퍦x8% DqӧO7o\TTVtzXj_Ѡ!>)77w֬Y貲ǏO2@ dZ-ˏ9йΖ٬V+++333r_t^x/_ ,8}t[[[@@O?>}RZZj49άYjkkFczX,裏g~wfev#俋%OVJߖjD"qժU<*5RkkH$h4Cuuue2hB!>}4z藷"˿YfM:fرq֭4 ؎d_[[[i4 IldZ6007~ѣGe2JE5FZZZ:::gժU _ג%KBCC###׬Yb >H2, *44ᴶ2Æ ]I.Y#9H---w%ƍrzd2t&d2{ϱc *]Ct3fGBرcvFcRRR\\KZ֭Ç!%%%͟?ͭ_5Ν;ŋ?`e˖-yyy!!! L ٳ< KMM]bHd`v޽zj ~г'N4 \t)H*XG Z-xٻw/ȮKRZnkksttDԩSFs=sƍw9/ `0pP(LJdD'>+n/^ܴiӮ]qƩT AcÇ/\qb)^l[  pB^^^XX~َʒ%K{/ aС/_~%: ҽ{H$R<*w-;;1&&fC:OtttdddXQdh4Oh4 իWC{=pWy#/t`@v]@d@:Heeefܸq$I"Zהdn=z!CB͛7KKKVpZT*m__zu˖-d2w߽{w͚5Bp˖-Gxt:=??ԜO$D"/">>~ذaT*5++kU*URR'|@?iƌqqq wiڵk7nܸcwwwP+VX"@lݾ};44R pz.[^^.Ju:Ϟ=DxM ȑ#G޽HPnݺ5gΜܸ8NDxoܸ1֊~fEt:/vM$mXOҹVpIuuT*.\ptt933SחEFF>|O>AzDA.޿d>}d2uL}[oc2$^_[[;tP&P( 0U_4ݽYHz>]3gfddp4?H#G8p`Æ D˗/7Lg"$nOMMe2{!.\p߾}[nE6l0fˡ/,_[v*& |>(T* >~8LtyyyW^$`HSN?'O޵kW@@ ~~~ׯOLLJ6mp8BT7..nMPp8y۶mK,p8`HDDDTT:ߣ,Knذ\BǏy~׮]0+=A<ط%:d:N zPTJb/N.h4;;;L2{…ZA4 jY,Ç@X`(be2ّ#Glv{{iӸ\.N7 2lĈ^^^z~ʔ);vѠS(J3@`0@|YY\d2a0P77JT* IDATZ ;yD"qvvqtgr P(ܹsNR*qqqYYYWxxH$9zH$;w.ƏY&p@]t[ Ȗ-[r6Lh@7==}ΝojjBD.#A+@-F?EEYЍ?vu..gϞ۷oGDD{xnӧXV>qÇ7j^nΝ;Ǎ͢pףP#֖C׶[sI! H$x<^VdM/\P(D"p9ĭgMx;vtfٷ6EEExt((tÉD"!.Z[[L&E2d <O׻޽2 *##2LMMM{onn;wn@ 3r^|yƌ`;;;|wʕUVߤ{Ā &((ݻQTЃ!B?~!VA 6"ɞ J6ܫѣ={!z3 00000P*8?yhkkCEk@@RSSSrշFmKeoy Gm޼yXBa0~V\F"h"05z-+;w.Q-[f___776pTZmSS۷0F!ǻヒXzyy#Ft`@D"fi+A1Z2d2yϞ=* nܸV\0gΜ{H$1c$%%uT*(7e֮]lٲe˖͙3YP"f͚g5I*Μ9s@4jVA 6=l"lobF+Po eBbꯕo8ġfGGG^,Yd޼yMMM@jYyFEX:TVΕ0#&lÇz}cc7JTWWX 0qČ dee *(W\ , HwLfuuBrmtG0 &*Jv3J&SRR=zd2׮] IMMHLL } חJ"<\p0bĈfddT*}t~C4h@3f|7nԡuf3'I_J:t(Wpp0Fs Q'/=\34v#n8pKvRv!: !VSSsڵI& 4H$T*W^ex@,Yʕ+}EQ)))Ү]iNt>,#P/xk>>'OX,XX,$zڵkfy„ nn&L:2zA$@'@[ntaaaNJJJ{\.?xG۸Vܑd'Nz ,J !E555WTTp863R~ҥKCQ\\ܡVܹS.O8Ν;-*--ݹsgJJʹs,Kllzey>L&6mZQQX,@ In㡙C|||fϞŕBaÆu/^H$cǎʚb3~7|3))W_7oҥKׯ_O/gdd|]C:N@7فr7鬨`0Z78N\~uhs Az^ZzԩS|IZ:tȓɔ BpŊ8 @^UUUAAA8NE{GYYVu?yZQK{ꩧ`@'0 <ڼ 6Ap p8N'!f~p%nEdP' @KV|H4L2d2)$$~MJ+}S ;: R pEvgn8X"Ow7l6|l6;)-rV+t4`V(Yj!$̾uh4޻w~p8z=]|=6Y,@@w hrbpN_B ]_ϣ>  @Ց$IDCCB|رc7C(..:޾xv:ujjjC B &չ… -W^umYVV͛k׮5kĉOrs>= ӧO;viNss? >=AZvh駟6nX]]NO8?~\(fWVVVHHHjjj@@h]f֭[`Op8D"Q5N&sʝ;wB#F`g-;v1bDAAA/ {N ѣj㏷~2::U9sfjj_y$115@2?̙3lƍYYYӦM۸q#}O.^pn=ҥKvlk4 Pvvv``ܹsXVVV4w6:Ad p8muqH"@BrO[444hZmLѣ޽ミLNN>vXAAȑ#BgΜ no[-.ҏ11qdٸ\n׷~Dr_~!4uԿ?>RPP  ;F[l6???T ܗ566:V&z <9EP(BCC=inbXb~fǏǓ"m?~QݻwۛaÆueW^5jVݶmە+W9996/B{(OO{pTWW,w8Nz׶+Ϝ9;AGQév8onn755o%V"jft+WL6ŹHrrg}kz~k3&IRdJOO qqq j+6駟t;w6m4al|ڵk'L0𺴾'p8veXNgj ݡCj4 D"q`pP @j… 1cFFFF3gܶmŋT*՘1cp }pbl6A$IX,D"B111nnGx8\j|WkmޚC'!X\__P(Z~L&GGnǧ CJ҆ JP( Dx{{?~899bH$ ,yf`0AVU$bX,|>XV&n<;?w}7|wϏ1n„ mW+J]u#z/n=.WcV(6MQT]Z[[yǏ_xuΘ1R \.I~z8|D(M&SUUU@@llOחsܚ&oooPX]]g}PhJ%Q/ @];` چ;6443gιsgϞ ccc]& a $fAdp( .kZ]sXX}v\!4dȐbX,C'X,\.f.ΤDžۥ8/Dno/{+)oo p8nܸqXQQ\nAAEQ"?/i4617n܀4F$ ^5MMM555AhZouu鬩ihhhhh~qtEY'tt2|~7O<;]# Kן+QFᅸ8رcBTB3rHŋÆ gm =sFf3ǃ I&=#ׯ_kgسgϞ={bqdddff)S`7=w Ŝ9sإ~MPI՞8qz lvҥKgϞH$EEE|>ˋ/Zh˖-/1gExƍ$I;wnH$4hPm}!!!˖- 6lرcGnm!m۶ŋ+ SN>}_!C,[L(.;k(h@Cll̙3BÇ9sBRLL̽{^TXXh'MS\\۶mqaBKo\|ƍyPDD4ioݺs[JKK7gDv`tcHd||<[CCCM<m>p ꦠYsss}}^f:.//Weee,xyk8z\.$:jhhj?8oϓzdX\ j}$I< 9pVX+9r޽DL&;v>-VՓgzRRT*xpQl0< =t;ڥ$I"L&[]}g6M&SG:ȑ#u,t3|E\YPH$z(ٌks8</A fIβd2{y;xtϼVLi>uC\2A,S9s.i}׷?G8ﺗnЕnh75:rnҞf4mt:KKKl .?`Bx-שv]w3͸>@BpG ,tvT*}_[w=pr:,DdƉy2Z _t8 ^^^6]f|$ɆsE3ТzCw0z_QVVfXI555xYyyZVj5IPЗ`*))咾ݨQ,[,lr(czRtCQE"QMMCա"\;jJZyyy|h#v;~d2 |P!:(  K ifdz c IPx$ H4l0f2\Kl$> nTTvЂP(6lnkhA>p溺Υ}677w]V5,, z"jw'}*:***x$I//^ۢZn}p0@j4 tA CUgh4v}=\.2z`0t`XD"H$뽽k1 IDATۼl2 R{UUUIVsܛ7o$)LNc2<f1 `6V+3!!!Z!X[[kpoV dH@7`0R袣5Q:ۻ^.=:??ㅅROUTTfryAAA@@@}}}mmfBhl6^ B߿~Z:p@ff&^ AAAO=ԓO> WLcw]paժUO?4::n߻ܼysϞ=ׯ_ojjD)))fiZcbr9p c0f3ǓJWKdqÇW(2d2zyy BL&+..$I"pa6b(LWb@ڵkFO?qtU>ĉ~Bl6BBBRSSFcnn5knݚ{vh!HŕPUQQѕ5L&//bB7D"ݻw#""~wRy]|ӚF3D"Qqq!Cd3I6xsbV'&mkBH.+v544;"d=ݻMMM>>>cǎ9!t>&@o8[oEGG؈#`M]]Rё'H߿=NbA.y\N3((Q&Y,riӦue[.(( Efs #] IPzғ5UUU,K,5<~8?l/77w9}ln3?\.W,WWW4WLffT*uMRbXRQM :.((d2ᔤ* s,]VY,VIIɈ#pz|E(J_q@ bd2UUUjЁ)d .:uc=Θ1㭷j`̙ŋ'NPTcƌ]@p\LTF$e2L&cΏL&kjj2LZd2D6V(tFݻw 7'JfssssMM 3ooL?wX-P Z-A%.R4GjqmooRFf]]])pܸqߟ 6(JPǏ/..NNNv6X,aw  #!\\` bt&L9(uKmhА!C8TMu CMMRv$ш'O6=d7?~P7)j1*d[nN5$`0 3|A: _+zzq(z=wŋh¢' ͔)Sy___OHKKٰakoН;w.58Ů FwEGȥKpۻCSٺn."""??-F1̈>/ ŭ[XRGnm^{~# !R1cz{:in޼QQQW޺ukjjjrrJ2 gΜٶmfЍd0\. 96p8VD"!f;N.[SSCg26YPL&D=*p]$Il NS*t:Y,mlVN?WE?$6njjekZP8FBѣz{g:N (\jOK$6wYEEX,H$2FaX0T*%IW88O盡Vu- 1k3P dGy}<3{ٳgOSSX,̜2e fn#^^^`0D" ˵Z\.7LEYV@RV+EQJ"rhllldX<OWUUyw%"44[,H$bVF|>_jGGz 6ON7Ɵ(|5pq=&z\vtYY\.7<Od2Vb:&6w\˗5_`0\+_۾+\naݮ8 o:հH8 I_r{駟~Nѣ7m;h9w}}=BH*jZ/@n{!ϠD yyy,d2<O(vDg.ZvQ \!nfXnŸ27, uEᾺx`0bcc{4?/pJnǻ KFos:$jL&.HlSccX,sf|CjD"rv;evpp\$=j_}\dsKnR ndYHZĉk?#.OBEr/~::%88?C_K Պg [z{{+qM0LFƧ C&l9ftcԴ)Sp\rV@SSw ZkYYً/ء ܁t+ |vf=%0l2 ߴlqkd2 /A/s\ ]wt +(HEOÇ6lX ɴ&CۅO]O)ZD"h4hiBtKPin566677*1Bl6</c5o<͖ot%gөhRk<[_wحwndՍ8HtIcccYYYA2tІVw x<<[NfsCCCeۿ/<ݹJ{y<ʕ+_|[t:>\B.CzOO 랿=]֡>cZjn0Jd곅qPu(YnL}}}-KO,؃z >9$Ir8~ҥgJ$L>:t(!!fڱcѣgϞ; !n:F~zBW|򐐐e˖]t !|-[,^8::KV\\qF$J%\6ͷf\¾q\@E$Og 3:JE p7ө8xL>Nn㉆\g7r]-^WW1 \Zd2b<.U[[~V%.Kϧt?x111ǎzjRRRff1c&Mq툈P\\\MMw|'""µÇ űcl6xјm۶ _v] N>Mw;۽5% n٨ H$£}Rn3xJ6pB~U(x<$@`r\nX𠚚@ZWT*y>>-xBBBUdp8tᙗ7ޢ\.w sRiH<@ &Pyw|fsH-[<$B{o']1~%L,:WKbu˄.EI](J Ї8N"Uy>jTFA~&G@-,p ߬Y6mSO1+Є0x СCO=HDQTÁ׿>}ٳ=Z#J$I27lا IJ*((}35k֬$G(566JnL&zORT>@1H Zü< F Bzݻw߸qCN3L*6ͫW|8nCQԭ[^xÇw;6;=}(!!o 0 GcN $zK\upP(Of㴱ƍR?>a„{!p8wA$I~b׮]_|EVVs=sϵ:ꫯFEE K2\nbHT]]n3׏rov[|^o}||\⡫uxG&TkV^ G5x:qFcGCQT}}dmm-BH.wtm ֮]{ P#БƼyϟz-PIIɑ#G'%%9qij>`<66ҥKzsE;]///.KWUt:]GZBoO駟g(ΖH$aaaXarrl>wɓ'|;\.7&&ի**yaÆk\.yVD"9s指3-- 6HsNAAvb #22!tNݲ޾VVV7bdggfdd;uOGG͞=~~ժUK.]tqr6ףh֭[7k֬`&yiÁ6F qqq?ԩSJӧ;猊Zz֭[SSSU*`=s̶mڍR:ݗ^zik֬IIIinn޹s\.oUZ !++뫯駟7n|G;ٳggffSXhh7|k׮۷F<;DZ6=tЬ,z$ںu233,Yt:ǎe˖%Kx9y晈={ٳI,GFFfffzRխۍ?駟kAAA_u'Rk=}v=z4,,̓2EEE](􄆆+Vvz~m[6ؿ:RCCC76l6GqqqxnٯZ(&''?0p$V-3۵lvmm{, 333zc3f b NT*ᇹsZV^/z}yyرckkk DW.z`0w; IDATLjDƌR|0ubb fX,v8F6\nrqssR4L>vX6 \.711bf6}ԩaÆUTTL>dr8&y!裏655t:Db6\.}H^/ RtXccvr, @2EQfd߾}C ӟ駟t~[![ pdZ\ޓ'O?ѣGC7l6L&AEQL&8nZ֞ tUV}&ITVWW_p!>>t>|̛7˫O>INN/t:WppR _NDyyO>nXXhjjR(Aб ]PPPUUUQQ?~Jرc|VVl bfFDDeX:h4xXt:ȑ#9B!|\ǟ?~„ p,:r >wꫯdo ,%%%--$ >d0!qΝ?˖-cX6㹾p 7EQ$IX,7ϱcFGGp8#GtPWWIDѿg̙3AAA$I$f@, r}( Sp,s,:tBwF?wxb޽[>UBBȑ#a>x,nTp,#-ibؓ;H (ZVM&l*Ń q_?qwQVV&,XpBok׮B3~C"n߾矏;!-[ +V@ϝ;>bݎhѢ5M```RRT*/+ $ZhF5d7JKKoݺVCBB4#7x≂]vX;w|8y}̘1)))_5kp/$yڵy۷l6 ¼Pھ}T*OBhĉ=ݻk֬?Ig̷x8eRSS޽;|p00=iT^^>:B :T&v6dVb4iVo~GDT?ڵkaLLaۋ âE\n~~>B(//<A%&&o.!!7X,VBFW\z:={,\0)))>>A#z`~XWWH$L&Sպ6j8B >\*EOp8cƌAb&9o޼wW8qg]`~xm0 1VSN) Jr###Ϝ9CX555ׯ_ /_|u ?~ԨQ8r111W^UT!s(*HgΜ9bt:۝P |'{t҆ rrr-[/WWW?ĉ˗/iii{cccoݺeZqpHUVUWW/]ѣW\9}۷o#i4 &|ǭ2l69rرc bq̷tN$233իW_xqժUs/m߾j[nӦM!!!wߋHK{H|MPPTծe!Z($IU֭9r%Kf͚u-[AO%ƽ{n޼TCII۷|6xV;Я XJJJZZÁꫯ9SNݼy7V?L;@ؿ:HCHHVuVuuB`٭j:NRCf=s =O>nF`0jZ.--m]bD` Wuuu~~~xfds6773sM>ٳӧOg0VUV{yyXǏϘ1t: KR jժUVA쪪|UQQA@ (,,$I?}ƍu: /pY8cƌ}Fm@1 sNWWWG/D" (2*IҦ&B"IRӱT* y'69|>?99/$[ i^|98cpB`$I_z%r{}}}Y$'L&9-twfhCGGGAH $IO+B(;;} n:~xIIo n)v9ǎ~4gwdddx_~ERUVV| ,@ܹS*'O22rǎGȘ0aBڵk+W4ht2$SIIɓ >K.}7-ˆ vڅ\._ޓJ^^^iii/_>|B5jwݎϰX,]&Mھ}K/4ydgH~֭[jzĈ#FhBhRvvvtt\.Ě; ,?>.^?+w}B()) !dZy<+9d-IDeW_!XV> _ܹS&K_|Ņ ϟ_[[h"ݎ;wLIIIJJ*,,ܺuŚǍ9ro!b賦NWWWG/0L^t:炂p8B )44Tղl6][[RF}ER[B-J2111444((!4a„Bx='`t}Ν 7$@oà xb$pB@;uKrO:UWW{VZ7l1e|>?99/^1 A{.^^~e͆E&Lx~^' .$bԩqHHBF ;wׯlC tkҬFajVVV+\/^/^ҥK]Q]L&iY/ Κ5O?ݾ5&h_ #&&o;IJJ7Btڌ^_u %u]tŘlg~^Ck%8'СC|>?##`0dggx-:;+N@ pPEQΝΦ(÷TWWFEgg>f=7Oh*//^ 3[<-a۶mk׮^lَ;:_|ʕ+|M%Kh4PxxD"-sssy<^^^~d2qT\\ /hueeeXFq˖-;|pjj*rJZZZjjjzz:NjP(2224 KNNy^GEFFfdd!mܸ G/iEN'ZoIKx≂]vX;w|1cƤ|k֬O^^ދ/Hk͛o>, """B!BhRO>C&Ns޽Nk֬/2~xZ_>|XP;v, f_k>>ð0j @YL&s„ I&}8T*Ǐ50&&棏>aѢE?C~~~|||^^.^DD^^3))@(N8 )@***2L0BpᴬR-inn&KRiVvP]\\N>]QQAEGG|>СDpO p||>̘1FQ&) H0̏?8i$a:::$^sرC&9sÃNtfR6MMMǏ:uRtqqijj:}IBbijjrwwW*rZ͖~Ckڠ͛7gffvW-[̞=7 <.\0dl6ӉNN:'}||\nXX؏?A7669sK0O>_W``] ŋKJJP(ϝ;RWWg߻o4lb2ZZZO^SSk׮gyft&300PV_rQSSh"sGGnCnihpal6 gߺT[?~<zS4rȮ>H$Qۿ#G^u-Zhɒ%K,IIIt|򉃃}UV BBBb1ʚ7o޼yRRR<==;::賶/7='M&Smm!CBT*UTt(Bń{O* T__?p=񚚚W* URF󋊊ڷo_>}\\\h=+zHTPP0`n{6DB:hZDb6zX,V`0xzzj4hlh;@|#4^ "{/^⒕LWĬ]677wҥ</22rɒ%AAbB9BSAAA_~ennڵkjkhh(FtG}466v y0 qͣ˭VرcE :l6x<0n8ƍBY2{:]Љ`puuU*&ӜarkrdBO .1x/↫Fy^~sQWZ@@C…W8a>YdB7|whj>?w\y$/)O /BV+˗書d@d2R)[ѤvZ}  g_f+e˖8s7)C$$$N#G\rnNC"Jt>^߾}^홼'{ 8|DDD@@}v&Y6Zpss_Tt3gvo}M/[ =1@7pttH$ꚓC c[Cprr.Ew0ҝٻw5kvO5HRSSriiiMMM`````୷*--e&88x߾}Ǐ?|pdd &!=z}lfu^X, @^` .ܸqѣGSRR92sLѸ}pZɓ3gά,// Q(yyy ;~ɓҥKu:]tt޽{Ҳm۶ɓ'Г3f:\.;'' 8h9~Wooﺺe˖m۶h4fddTVV.X<#Rpo߾\.7x̙-oԩS驩4^FF=$ !s}Gq ܘb!l߾]$ X'''ig̘vZ:45jԨkזBbbbƎzꈈny#-Ξ?dCO$SSSW\iˁFۄ!vS[>RrV5--M$Bz=o>BȦM!^wppJ+Wd稽OSOl6ڃd2' 7C;`fOߺT@p84:"tWtd?4z}gF;"mmmDBZD"1z^,j@  IDAT`0<==5hF!v3 h^w|djr8a8^ooowtt4LfY z4= @Oƞ0aB2W^eg1bLȗ nW_9;;٭, ;B6Qhs@ʕ+gϞbŊo \x1$$Dպ'</11Q&)JP~Y+:4t_UR*JXjZBpsskjj*..NHHJQׯYť`0+ΊM]ZZcǎɓ'766666ٓO>I3Yeeew!CHp'<==nj2Ν;uÇKҧ~fid2y{{~J2<mڴZ_L_|O>4XNNguԩذaƍ{gϞc-_<***!!aΝG~7֭[Gײfdd,X 888..N.*+//~J;@陼٧zNݦG<. @aaÆ9;; BFr BV B___T* !NNN u[[[+++GYYY$iZV4 s[Çg3t4bm޼9&&ŋU'O6mEEEӦM h4\.W.jJ% D"|>_$$$p8.k0L&B"h4JP(R)RST...l¶BۻaÆء{kjҸ{M4Ad } 5k!dVaA)ٴ0vXL̙cZ\s=Gfȑ#O`0qMgf 8p2,66OmI_vm[(fdd~ꫯ TV+++s!Xx~o>}bٳg׎;?#B1uԄ?x̘16lP(NNN~~~555SNݽ{7ہL6.啘XD/=UWP^] &H 8[40h6>)jNbb" #^;KP(gZ !C ={x[3ϱ ~{]lG}T]]sϥN8[^^d:~KOOO_?gΜ^xrʕ5k<#/_h4,Ydذa'oG/^LJJbJ]]]nn.ɏt4RxL2w{qZ1dr!Vaf V >7-k.7d-ccEiHgB4{b &.++#b\^PPm6j:::D"ND77ۍ wHJzz_~_rH$N PRR2}[\EEE rtt$]%''9r3>>h_ʪpĉ;Al^&a[ eܽ{wWH<=rU^wrI$wkaaKdL&`=[,{uql6>(]2h By~FJ^ q8#F/G7\zӓc{yy >ZnhTT3gܱcٳgccc|IdQQ3<΂pv/ ŝ jjj'~}MRNgil48^wMII^چC~&Ohl444<= <SSKI˫?y})_WP^ ̙s_:wn߯OOAK/?wь͖+6w;s3o}<==|СC !L>=%%WsChv{9vرcQFEÆ cW+**nqVI-[PxGqU-'Oĸ^Y2"‰RP( +,_~`Jv{^O<ҥKMϋD":=h˳hFFF.H˾!ٲT*e˝ae駟=1@2]ijӨ©S}r 322h3g$%%њ >ɓUUU4bi%333o=$<ЯN֭L?^N)*#df#VOY2&{J8ƾ¶mEw&oش)9x43Mx썘sXhĈmmmnnnҿ9)rrrj5bwȑ_FD-Zdɒ%KRRRt:'|nj*6a]HHX,:YYY͛7o^JJgGGK/z@Wsp(noV2qw)S|8}Vܹs555-m6!aNϢܺ~so#OLNH]_SX4a l W{{;U(st:99 0j4_vח֗H$n{=T*7AjkkH$:j%lbXV (:::Yyzz*m?uδjuwwǝwa0<==5h1j%Dsٳgi'X, ͚52zhBluΞ=-B{9?11_~4orddF4iRGGGyFlnoo':%4e0\]]JdbJlp8au:Sf76 ϙgk<^ǝ{C׷rD{8qHƅHF<Sx,[nZBСC999o{Ѵ˖-cWd2i^{m̘1&b~V D7VەJL'd2\.0 S*\.7??b/T* $''gBPlݺuذatS͚5K~~~/_:uq:|2ۉt3&~ H[p!rĉ IZhE 6wpZZfZw3GPرC&겲2P0B YW\:t޽{]\\N>]WWK`~_U(4mCYY!D,򂂂hܧO:XGGH$t"gΜy^{  @OFD亙U9bVar4y䶶6777)},___eee П,,,l&l6Օ9;;0@RTl p8.krr7`M2N<):M4n8ٖ !>(]Bge白fZ8x 7 ޗ/_NNN` OHH`FTWW:99q={$&& BBr !--- wlh:u"ubl2ٳT[[k2D"Qyyj=|]]ݮ]BCC-KmmbMMM-++t ѧNJHHXbB3gjubb֭[j5.%=̃еL&޽{c޽bѣG{xx477Xl2l6Z>{lllOeeP(tqqioo4 !j* wa+>>^R'|p) _c6%?ѣGlvpp =;>+8882|a6nh6]]]ׯ_/ɖ,Yl2Я_ǏORm|~LLرcW^CTD"@K%5h b$;eȑ/^Ξ9sfee%:.::b`NۡV̟?ԩS)))՝544xzzo߾=))~QVVĉvЯ_'N$%%uQenA|^r%l߾}III..7<--tWEEENpO BνIDAT}sJ:u*===55mz駥RÇkkk,XR ryvv *++i." ~wGѵo?GM4iÆ 4: ;@2cƌkYhQvvM&:99F8 ͛7474tmBB[ྡ`Cg򩧞lA}^/ 322(cǎ-^844WDI1l;2'v.RZZTUU1b9 @^~7Щ;E7@ꘜ>XPP  'N Cvyyy@.\hhh@@O$;ֶ 6 R??~< <׿0ɩMpȑ3gm۶MWl=| R4L+ar\(t:@q)tI&=Ho'$$$$$œ\hx޽:gX,67C PxU\M@w+v;y6 Bjl cbb`CDr~@ aÆٶvqơ8{g*** @ÃuTBBŠ+ Ŝ9s߯VnݪVDѣG{xx477XLgRgϞ񩬬 ...t*v???:jU(<tW||JO>dKK -$?N˴`Zccc;`aBH@@3--B'JZpB(BHЛp8tZx<^:ltD>>UUU"HՆ;v=rH$7oOP8qD4,kk'l6ѣf3[ x46`XөSSSSy<^PPٴ\.wߍJJJJe~~_~e/\Ѐ}zV託DI6ؠӠ hѢ쀀Ds|ۧ펉pRZ-66r*33shXgX{5!جVb#oY FwJ{ XVHӧ?SlZy>mw]]]sssRRһKaS۷.֭[GAhpgl6k;gFSmAə3jB#1pF˶ӱ<))Q. @KM}n<{/211ӪSUM7hcڴi삸]vH{-{]$ =`&Ivp?M&lL@ף,-o> e{}tD _Ty¼ R~O<駟.xAv@@%ɌF J7M?+ F1 8[믿 :u t7YH97'-(6 ׯ_NNB#b0\]]JdYw^ooo4vQARr$!!Mhnnvww- R9+<ڷo_RѴGBB™g ]<pfwX,&8::BZP(D^4_KgϞCO,~"8:bl.?hM>!Umڶ'psJuM63^p۶mkH.$Dccnkk7n $i/tTUi[.\SkJ2Fk V2KxabI"[E[ڵ~;{FUq"$[oF@|tY_L}}P,oxؽx o}ν:  Lx)0$鷀{~wwQo z/_|MV:{Z  ޾}q:{] !B_====///888mFڹc'6=>iU_v s1o˿N0a„ ?`/{o# @@|ӧO}}=Կs?\ðWl C^UVr_x6t ǧ6$^{ܹsAAA|h$xbծMy;/ =gt{o߾#F0aB}bUl1!%%%mmmg^fͬY 2jԨ LqG}u֭---Ν;qĕ+W̙e˖6WW^w~쬬,BF9ycNJyf777L6dȐCҁv.]yz{Geze;we&N*ogȑ#k֬齍g4B}Y%ITTO?w577M^ti͑saO>}􎎎SN?~i]\\4?amV[[;) [h~/\x≩|YrWK.!GX$ӛP3&22R"=TB߯o !bO?׾/`0=_mbDACfX  &Nr٤;6l1[:M/mH]X,N3 &D]phpzz[Z#$.hfZ=jU^sr!@"Q*XvM{,Ѧ/R t #{ kMW/[z".+J}K]9q'4gIENDB`crystal-facet-uml-1.34.1/user_doc/template_to_go/000077500000000000000000000000001415120503000217305ustar00rootroot00000000000000crystal-facet-uml-1.34.1/user_doc/template_to_go/tree_structure_proposal.cfu1000066400000000000000000001200001415120503000274770ustar00rootroot00000000000000SQLite format 3@ d d.K   w##5tableclassifiersclassifiersCREATE TABLE classifiers ( id INTEGER PRIMARY KEY ASC, main_type INTEGER, stereotype TEXT, name TEXT UNIQUE, description TEXT, x_order INTEGER, y_order INTEGER , list_order INTEGER, uuid TEXT NOT NULL DEFAULT '') $tablediagramsdiagramsCREATE TABLE diagrams ( id INTEGER PRIMARY KEY ASC, parent_id INTEGER, diagram_type INTEGER, name TEXT, description TEXT, list_order INTEGER, display_flags INTEGER NOT NULL DEFAULT 0, uuid TEXT NOT NULL DEFAULT '', FOREIGN KEY(parent_id) REFERENCES diagrams(id) )H++WtablediagramelementsdiagramelementsCREATE TABLE diagramelements ( id INTEGER PRIMARY KEY ASC, diagram_id INTEGER, classifier_id INTEGER, display_flags INTEGER, focused_feature_id INTEGER DEFAULT NULL, uuid TEXT NOT NULL DEFAULT '', FOREIGN KEY(diagram_id) REFERENCES diagrams(id), FOREIGN KEY(classifier_id) REFERENCES classifiers(id), FOREIGN KEY(focused_feature_id) REFERENCES feature(id) ) mtablefeaturesfeaturesCREATE TABLE features ( id INTEGER PRIMARY KEY ASC, main_type INTEGER, classifier_id INTEGER, key TEXT, value TEXT, description TEXT, list_order INTEGER, uuid TEXT NOT NULL DEFAULT '', FOREIGN KEY(classifier_id) REFERENCES classifiers(id) )#''tablerelationshipsrelationshipsCREATE TABLE relationships ( id INTEGER PRIMARY KEY ASC, main_type INTEGER, from_classifier_id INTEGER, to_classifier_id INTEGER, name TEXT, description TEXT, list_order INTEGER, from_feature_id INTEGER DEFAULT NULL, to_feature_id INTEGER DEFAULT NULL, uuid TEXT NOT NULL DEFAULT '', FOREIGN KEY(from_classifier_id) REFERENCES classifiers(id), FOREIGN KEY(to_classifier_id) REFERENCES classifiers(id), FOREIGN KEY(from_feature_id) REFERENCES features(id), FOREIGN KEY(to_feature_id) REFERENCES features(id) )5I#indexsqlite_autoindex_classifiers_1classifiers nb>  o O ( f I - @p-gm4'  cQ: Which format to use for persistent data?Assumptions: Influencing Factors: Persisted data shall be stored to git搑+  ) A-4: SQLITE DBy7j *  / A-3: Binary BLOBs{̜)   A-2: JSONzRF  A-1: XMLyTgC&  79Resource RequirementsCPU: 100.000 cycles per incoming event RAM: 2 GB worst case Flash: 50 MB Footprint + 200 MB Persisted Data Network: 300 MB traffic per software updateG9NZ3)LG@%  iDebt: Interface change only partly implementedBackground: Interface of module XZ was changed from pull to push mechanism. The new interface is used by only 70% of clients, 30% use the old interface. Effect on Maintenance: 1) Difficult to understand by developers, 2) Both interfaces need to be maintained|c:b$  5 Risk: Clock is resetScenario: Due to a power loss, the system clock is reset to an old date. Risk: Due to the reset time, old security certificates are valid again Effect: An attacker can authenicate using the old, unsecure certificate Mitigation: The system persists the current date and does not allow to reset the clock to older dates.z9h#  QyRisk: Inconsistent persistent dataScenario: During operation, power suddenly drops. Risk: Some components may have already persisted their state, others not Effect: At the next start, an inconsistent system comes up Mitigation: The persistence module implements a rollback feature that allows to switch back in time to the last consistent state,z"  gSW-UnitIn the context of this project, a software unit is a small piece of software: It provides max two different interfaces (for max 2 types of clients) and max 20 different attributes/functions to be read/changed/called from outside. It uses max 10 interfaces provided by other SW units. A SW unit can be fully tested by only using/mocking above mentioned interfaces.|.!  %SSW-ComponentIn the context of this project, a software component is a part of the software that addresses max one group of semantic coherent, functional requirements. It may address additional, cross-cutting, non-functional requirements. {ЅZ|  USoftwareIn the context of this project, software refers to the program code running on the operation-hardware. Excluded are build-tools, test-tools, version control system, requirements-trace-tools, reporting tools, bug-tracking tools.{ЅZ@  aSystemIn the context of this project, system encompasses hardware and software: The metal case of the product box, connectors, PCB, PMIC, SoC, RAM, Flash. Included is also the software stored and running on this hardware. Excluded are Power Cables, Cables to network, Peripherals, Monitor and Keyboard O   ! zControllerBUTZ3)Z3)   zView]lPlP   zModel^+  7 nThe system shuts down)7  O nThe component T waits for event E+tGG1  C nThe component T performs XY$V$Lˑ^'  / nThe system starts!߷L%  + yThe Component T!Z3)   xSystem H!竛F%  + xRemote System X# Pi.j  !cUsabilityThe graphical user interface shall explain the choices a user can perform. *PP6  '1cAnalyzabilityErrors during operation shall be logged with the information: - SW and HW version, - Date and Time, - The event causing the error, - System state.&  - eExplain SolutionBם፲j)  3 eDecide AlternativesBo܎.  = eUnderstand the ChallengeBr@Yf"  % dSW DeveloperD#*   dSW TesterjjOU[ys#  ' dSW IntegratorjjOoܪ(%  + fSW ArchitectureB-?f"  % dSW ArchitectD#o܊0!  # dStakeholderD#U[U[V  UKTemplate according to arc42 proposalsee https://arc42.org/overview/jjO;Fm  + fSystem Boundary/b;k  + eAnalyze Problem/b;:x ! eUse System/b;{  dService I*7d  dUs ) 8; Z z = 7 A & q X Z  j   d( K fm7 ) Wl  L m Q3kTh-_The system shall react)Report Problem>7set flags for changes6-release lock (1)7-get spinlock (1)4-release lock (2)<5read data if changed; Eread and reset changed-flags:-get spinlock (2)9 #IPC-Concept2'Poll for data8 `s+Cache coherency=!write data5  Software %Provide data3 #IPC-Concept21gOperation shall go on in case of single fault11gFailures during operation shall be analyzable0,]A watchdog shall supervise the software./ Th"IThe system shall be updateable.7operating temperature-3kTemplate structured according to arc42 proposal /A-3: Binary BLOBs* A-1: XML( Idle-72)A-4: SQLITE DB+ A-2: JSON)/cQ: Which format to use for persistent data?'7Resource Requirements&2iDebt: Interface change only partly implemented%5Risk: Clock is reset$&QRisk: Inconsistent persistent data# SW-Unit"%SW-Component! System!ControllerView7The system shuts down%OThe component T waits for event ECThe component T performs XY/The system starts+The Component T-Explain Solution3Decide Alternatives: Und9Understand the Problem%SW Developer SW Tester'SW Integrator +SW Architecture %SW Architect #Stakeholder SW Model System H+Remote System X Usability'Analyzability Idle-1597no reliable time-base,+System Boundary+Analyze Problem!Use System Service User 1 ` )  [ K "  m 4}TD  3 U S   qs< 964  U>25bffd2d-d261-43a6-8925-4f374abf4e5c53   U>06065618-3f98-4fb8-83a8-40c949ae09ec51  U:;4c1cad04-60e7-4038-82a5-6153cdfc997850  U9:b6f9e163-5c73-4ed2-9462-5263c3f478af5/  U57 5de89a03-db52-49df-a612-c5d765ae9a925-  U467d73be94-87fb-4e83-afbb-0883d9cde29f7,  U,8<540d8b35-be53-44a6-a8b0-b8dcf9097eee7*  U,8:B1f8491a4-a8f6-45d0-bc12-f56354a771f87(  U,37D0e522622-8d27-4627-8a82-007a484ec23a7'  U,36:˛27ec0ff8-2575-4606-94eb-c023802bd1db7%  U,34g'a9d483ba-68c9-4f58-8a60-bf3345e96d4b3$  U&e9a693f1-0f96-462c-b2bb-46be2af2de28L" 5  Uregister for changesk.47f45dd2-0d91-4632-bd7c-a6379157c445C #  Uchange data%5a420fbc-689b-41c6-ada2-b0b06a8dcb43E '  Ustart (model)ф;05a8787b-1866-4514-a5af-4ceeff5c0402E '  Ustart (model)K@D17f22848-5457-4333-94e6-f31d46042ec47  U,lPad8e261c-2daa-4f22-9436-11f5ea41f5777  U,37b8714e-86b7-4e7c-b600-5b2b4688de675  U 8626c12e-d63c-4908-9a9d-7de0870a2bbf5  U107ae2fd-5100-4dfa-b114-e5b97d99bd557  U,39e86f55-4a0c-4132-ae82-dbc2f73d72135  U $fde9940e-0f20-453b-9f56-777cc48699e15  U 2298a649-0ce5-48ff-bc17-aafdf39c9c985  U85380a03-f1f5-4f17-a73d-c6a84d1165d67  U, ed9ee7d4-646d-47a0-a659-ba53cf36983b5  U15b7d24e-d2c0-4698-a75c-fac0871c88e35  U  175d9fef-20a2-44c4-b26b-5d9d3d2d1c135  U 4daa065a-d517-4c91-ad9a-094748b5d2197  U, fc52893dd-5a5e-4d72-9323-17e57ae6100c5  U,ec022251-b899-43e9-9ba4-9641b19f804e5  U 451c2b8d-168a-4aa9-b7d2-725573debbc54   U24c9b553-770e-4fe8-acfa-23ef73e41f1c4   Ub3c016a3-60b3-46e9-aa8b-d98cfdf16714 652  U;<d89237c3-bbe6-4cd5-b9ba-661bc0f265e1 5.  U65e69ed9a6-6842-430e-8a0e-b4eb6fc38af9 7+  U,8;=4cb547f3-b024-4eb1-a3bb-6b82996c99e67)  U,89Wd11e885a-58db-4b1b-8b84-9d3dc2bdaa617&  U,35+}43c312b4-433b-40d5-a1e7-e419a9c31784E# '  Unotify change_Wd898b186-3714-4e1a-abb0-29bb590a7fc6D! # Uchange data/Naedf2961-d338-4ac5-b44e-52cf4be9389f>  UstartC$e805084d-56dc-4952-8990-2d00e48a68da7  U,Z3)5e74b3bf-7c8c-4d48-9a75-b2ece2a1f0135  U4f170e35-5640-4be2-b4bf-fb6b5abe798d5  U2ed5fa12-a728-4e2d-9b0b-5cf879f0a36b5  U  403df4d2-4eb4-475c-9bdc-cab38cb0c6d27  U, jdabd5ea6-078f-4433-a953-e7656c0c66745  U4fce2c1a-8f3f-4fc4-b608-f4dcd2c806ae5  U 29e6cdd6-55a6-4451-9d04-d4b827aad0375  U,0d9c2d86-af4e-4cba-a458-2852f60179c8  n= /  U88f91539-1e10-437b-8ed0-a220f0ebe7d5/  Ud098972e-a0c9-42a3-bb47-01fb9a6f448e/  U4c0cf62e-2d48-4877-8a17-04884210df3b/  U2db988db-75b3-46c7-bb87-474fbf41772b0 E* H U7 R } :   t '9  &> % U Runtime Viewaf21d17f-95eb-49ca-a189-48a8bc188491E 3 UBuilding Block Viewd60570ba-182d-4a1c-bbfb-9e65cab7078aE 3 UBuilding Block View1c41f3ce-df2a-4dd2-9cd9-9cc71a412d9bH 9 U<> Controllerd416b9ea-7669-4df2-afb4-efdce316d711B - U<> View941eb4ab-1e69-427e-bd40-03c65f220128p #qU ConstraintsWhile goals represent the wishes of the customer, constraints state the conditions imposed by e.g. physical limits, technical feasibility, law, costs, licenses, patents, ethics.4e748ad0-6b08-4991-ab9c-7d9a23931a6dz 3}U About this DocumentAbout this Document: (C) We acknowledge that this document uses material from the arc 42 architecture template, http://www.arc42.de. Created by Dr. Peter Hruschka & Dr. Gernot Starke.19d14e67-4cb2-4db5-8429-1178438f7611 E 3 U Building Block View6d0ba2d8-e522-4e5e-80d8-9965b8aec785|> % U Runtime Viewa293bc89-a9b0-4d33-b664-b2658698b5b3> % U Runtime View673de54e-5414-40d0-abe5-072926058768E 3 UBuilding Block Viewb9fcbc66-ba92-4b03-9b67-3fcf67618c14n|@ / U<> Model6f7663d8-bb49-4a28-814b-5645a87711799  UGlossary4f170675-4443-40f4-a832-73a0ae1542e0G 7 U Crosscutting Concepts5a848d43-fdac-4df6-8ca7-8d4be78ce0ffA + UDeployment View9959527e-f433-4343-b3e1-ffac60760349> % U Runtime Viewa49c9d82-6d1f-4c41-9def-c24b1d539423x /wU Solution StrategyThe software implements an event driven architecture.6160f4aa-d07e-4c10-872e-51df0b3ad32cC / U Context and Scope30c9cbbc-2938-4e99-a630-002518b29bffsI = URisks and Technical Debtd581c205-15dd-4401-9b9c-206aa27082eaH ; UArchitectural Decisions734356c1-8095-4e81-a6a9-1f9028551024G  9 UIntroduction and Goalsc83bc101-3673-4eba-af5e-aed5d1f48bc2F 5 U Quality Requirements945c13e2-4467-429f-a5be-b3f0d0b76b38 *C j ; U  P !  b 3   u F `[,1pA G }Ng8 |M b3 4 -SU1f671533-8e32-46f4-a88d-700f47da38ce-QUeac630e1-0922-4c7b-983c-05ad1db2e008-NU0bfaaa31-9e35-4354-b3c7-3439eba68eae-MU>f60de244-2a65-459f-b8eb-a9c253a9a0a4-LU =7be08426-59f2-4961-88c5-f6a333ee4637-KU <0f03a727-3ae1-4e31-b44d-b8440fa4b5f8-JU ;cbbc3427-2643-47a6-8a79-549df8bd8836-HU 932074b1b-1ec1-4d67-98a6-40a675ab9354-GU 83d5df8b6-1d4b-4392-8012-05bdf8244f7d-FU 738feff48-b2ae-49be-9e87-5889aad2ba84-EU 600d4dbf4-040d-4b47-acd3-302d4297c4ae-CU 4fe6a9e86-f692-4392-85e4-4ab0470cafca-BU 337496243-3d69-4dd9-9f6c-1afbf6b16a4b,@ U11a996442-2746-42f1-8a3a-3869b91759b1,? U0bb0a01d0-2878-4407-a89b-148525dc3ce6,> U/8acebd85-da4b-4508-9d7d-3c959a186f9e,= U.140fc905-c543-4c09-8800-0b7cf8209a7f-<U-f795e1bf-868a-4ca4-830b-60432c84d0f5-;U,175c3af9-a434-4330-8958-8a9de45b00de-:U 18703e8c-e1d9-48e1-b34b-29a87d6b61db-8U +faa65d9a-f3c4-4fec-8418-ccdc8d97d98617U *e25a8b39-e914-4166-9717-be281d1767f115U (3a0bac4c-6113-4916-8f58-f2e2d9daf8e0-4U 'c970e13a-e56d-41c9-9572-d991e4ee0b61-3U&b7f3897f-e283-4f6e-b11c-5d2d73fbcd27-2U121709ea-0193-4246-bee2-7039f63347c3-1 U504bc8e2-abaa-4cb1-a30a-2b2eda660f60-/Ud665a7dc-fad5-4927-8708-f929bc6752a7-.Ubbbea546-975b-44a1-9dd9-f5fe8a9408a6--U6850f606-e915-44f6-b54a-6dbaaf065a92-+U917d2406-f22a-4146-8287-d7f0f50b1e41-*U %c9d4d11e-430a-44da-8554-96499d7d1a37-)U $baadd513-158a-4e24-8f3c-00fed954c61b-'U "7b26a0dd-524b-4802-9499-7faa999bf4ce-&U !69ae272e-cb63-4c0f-a6ff-994b682e8575-%U c1ab96c5-a51d-4e47-a141-d8633a90f375-$U 37c46226-5f59-458d-aa1a-2979f7074b99."U7de4182d-bd21-4966-b929-5425881f173f.!Uc81a10e2-7774-4d93-baf2-f7dc05a68a08-  Ub2bfc1b3-460c-486a-92a6-dda20d0cffb1.U13bcad97-5aa7-4469-8ed1-92dca03d92c8.U9c041e76-9525-472b-b1eb-05cc298f803d.Ueab2c2ac-4f38-4552-a10e-9483eb135415-U5bbd02ed-c146-40ba-98d9-2ebd93c4fff6-Ua9a73477-3dd5-4fac-88e2-44684edddf05-U6066e55d-cfa1-4bb7-8338-ccd35338231b-U5e7f8fb4-f32f-47e2-8a00-2ea7f7e69f33-Ub1c63ec6-d8e2-4986-a9a0-10b798b54480-Udba295bc-a0fd-4fad-9217-1a72508f2ea6-U34231235-6877-43ba-8696-a528681a7251-Ua4f2ef1d-5ca4-4271-8dad-d4cc21b67a25- U a299953c-f3f1-4d64-9df3-c264260e299f- U fe44f11d-dade-447b-9cb5-db1cbdf8806c- U 492949e1-ee5a-453e-b6a6-00487c9c051d1 U 112728ff-3266-48fe-bec4-1f3f9c4e604c z16U )cf31a16e-2b5c-411c-99d1-6f7a169aace5-IU :2acef5cc-be4e-44df-abde-098a63441aa3-DU 51e77034f-75fb-434d-bdbb-009a3dd56b6c-9U 24c34471-ae59-44c6-9ff9-ae952cbb3b14-0Ua9556067-227c-4a79-9493-058bfcde8af1,, Ub07ee9e3-c2cf-4ca7-9b71-161c7ab5eedc-(U #a6eaea70-8387-4fb5-ac59-92ede6c8d0fc.#U6f2d3887-9c1a-4a96-8931-d9be5b5311904-U16e11ece-69da-4eae-a194-ab92d2d8f70f-Ua8ddbd17-4c64-4253-a870-1e89dc0501a4- U 999d7268-a36b-4181-87e2-9bd2535ba18e-AU 2cc6da442-078e-4a10-a593-159b2e4bb3d8 u+ s ' H G b0  [ __ + [UEXAMPLESoftwareIn the context of this project, software refers to the program code running on the operation-hardware. Excluded are build-tools, test-tools, version control system, requirements-trace-tools, reporting tools, bug-tracking tools.{ЅZb5e00353-5242-4716-b87d-75930bc73fbdF  UyEXAMPLEView]lPlP064d6ce8-9172-4de4-aac8-7a0402abd3ffG  UyEXAMPLEModel^05bdba2f-48a6-4f7a-bde6-44a1b80c74d5K  - UeExplain SolutionB*jce004acc-5b21-4725-869a-a22f9e85fa27Q  9 UeUnderstand the ProblemBr@Yf99623701-1f04-4daf-a214-c8a38c821eb9G  % UdSW DeveloperD#*368b7857-7a5e-44ba-ba62-88cd87c4d11aJ  UxEXAMPLESystem H!竛Fca6abcf5-4136-4b37-a13c-fccbdeeb54edQ + UxEXAMPLERemote System X# Pi.658dac9a-133b-4d0a-a224-26b73880d640 !UcEXAMPLEUsabilityThe graphical user interface shall explain the choices a user can perform. *PP02c7305a-3046-4eb5-9f9a-a46998b685b2L ! UyEXAMPLEControllerBUTZ3)Z3)426cf835-28ee-405c-9ce4-6d07e2d54ed2  UEXAMPLESystemIn the context of this project, system encompasses hardware and software: The metal case of the product box, connectors, PCB, PMIC, SoC, RAM, Flash. Included is also the software stored and running on this hardware. Excluded are Power Cables, Cables to network, Peripherals, Monitor and Keyboard, Development Tools O9f532975-b03e-4a36-ac16-2f41f9fa4e30W 7 UnEXAMPLEThe system shuts down)b0366cfe-c2af-4cb8-9548-455a37ac9495d O UEXAMPLEThe component T waits for event E_UAa0Gd176acd4-773c-47e6-aa9c-fb1d0a655e69] C UnEXAMPLEThe component T performs XY!n>^a3574399-5d67-4c67-b5a9-5748778879f4S / UnEXAMPLEThe system starts!߷L8b94df3e-857d-493f-a8b5-907847825188Q + UyEXAMPLEThe Component T!Z3)cccc2d08-b7f1-4a79-8323-389c11fe8d7ab '1UcEXAMPLEAnalyzabilityErrors during operation shall be logged with the information: - SW and HW version, - Date and Time, - The event causing the error, - System state.zaec273c6-bad8-4e27-878c-6163d6b4f088N  3 UeDecide AlternativesBםᎶ135b8885-5338-48e5-9338-8d82bfa3fff4D   UdSW TesterjjOU[ysed8d8fd6-7d5a-45d2-8ee3-f254b5f33f3aH  ' UdSW IntegratorjjOoܪ(8bcdca45-87fa-4f56-b0e4-63e7144032c9J  + UfSW ArchitectureB-?f9280a4ca-a208-41f7-bef7-90d5b0921fb5G  % UdSW ArchitectD#o܊05184bb1b-a807-4b2d-9f81-7278a6e7f195F  # UdStakeholderD#U[U[dc9ef752-d463-4b54-9c93-17aea066b6f8  kKUTemplate structured according to arc42 proposalsee https://arc42.org/overview/jjO$|7f0b3a66-eecf-4acb-b451-99f5b1eecf82M + UfEXAMPLESystem Boundary/b;8756fed6d-09c5-4057-bd8c-810fcef38938M + UeEXAMPLEAnalyze Problem/b;:x56616eee-6205-4288-999b-93592c10f9b6H ! UeEXAMPLEUse System/b;{6d6b18d3-f74e-4e6d-a2fa-4c5c0bbf981cE  UdEXAMPLEService I*7df4abcf18-9905-46a3-a199-70271bda4534B  UdEXAMPLEUserq[V+5c7e4c31-2601-48c1-b61f-fd1cd806dbe0  Dv !_D ~ A b R # Z +:) wUEXAMPLEA-2: JSONPro: - Simple, Human-Readable, Machine Readable Con: - No standard structure-definition (schema) like DTD or XsdzRF694e47ec-7b11-4494-869d-332dc49a158eC(  UEXAMPLEA-1: XMLPro: - Human-Readable, Machine-Readable Con: - Complex error handling in SW: What to do if e.g. an entitiy is not defined?yTg93229bca-b0f8-4aef-abb2-cdc6ded006bc4' c'UEXAMPLEQ: Which format to use for persistent data?Assumptions: - Format changes between SW versions are expected Influencing Factors: - Persisted data shall be stored to git Decision: - A-4 (Rationale: Fits for use case even if stored data exceeds RAM)搑1cba6dcc-3a74-454e-9599-909e30716a83o& 79UEXAMPLEResource RequirementsCPU: 100.000 cycles per incoming event RAM: 2 GB worst case Flash: 50 MB Footprint + 200 MB Persisted Data Network: 300 MB traffic per software updateG9NZ3)LGe9049d42-91fa-464a-9672-c705036011c3l% iUEXAMPLEDebt: Interface change only partly implementedBackground: Interface of module XZ was changed from pull to push mechanism. The new interface is used by only 70% of clients, 30% use the old interface. Effect on Maintenance: 1) Difficult to understand by developers, 2) Both interfaces need to be maintained|c:c512e695-41a8-45e5-8f6c-a604f2234796$ 5 UEXAMPLERisk: Clock is resetScenario: Due to a power loss, the system clock is reset to an old date. Risk: Due to the reset time, old security certificates are valid again Effect: An attacker can authenicate using the old, unsecure certificate Mitigation: The system persists the current date and does not allow to reset the clock to older dates.z962711fd2-0ddd-4c88-a36e-8930afba58ea# QyUEXAMPLERisk: Inconsistent persistent dataScenario: During operation, power suddenly drops. Risk: Some components may have already persisted their state, others not Effect: At the next start, an inconsistent system comes up Mitigation: The persistence module implements a rollback feature that allows to switch back in time to the last consistent state,z44fb7b86-a9bf-4cf3-a4c4-41cd4488e3bbR" +UEXAMPLESW-UnitIn the context of this project, a software unit is a small piece of software: It provides max 2 different interfaces to the outside. It uses max 10 interfaces provided by other SW units. A SW unit can be fully tested by only using/mocking above mentioned interfaces.|.a7b1d462-e58a-4dc7-b8e8-4a62f2803e47! % UEXAMPLESW-ComponentIn the context of this project, a software component is a part of the software that addresses a set of semantic coherent, functional requirements. It may address additional, cross-cutting, non-functional requirements. Software components may be a part of other software components, but they cannot partly overlap. {ЅZ7fbabe31-a139-471d-a1b5-29e43d345da6 bM;d   +  4K   /MP> ) UeEXAMPLEReport Problem I+?b9ecb08d-d55a-4527-8fea-a5dd0c4d5622V; 5 UnEXAMPLEread data if changed 0{˜=947955a6-1edb-4ce5-a795-68eaa7e12913R9 - UnEXAMPLEget spinlock (2) LoWW0a8760aa-b2e9-4498-be4f-8b10055fc32eR7 - UnEXAMPLErelease lock (1)dDDf32e8bb9-f9d5-4432-a732-6bdaf0b58212R4 - UnEXAMPLEget spinlock (1)dWg'8544065e-00a5-4e32-9474-5c54f8f5ca31o1 g UbEXAMPLEOperation shall go on in case of single faultNl C5ca7db3e-5d1c-45ad-aa91-036b402953f3{+ )oUEXAMPLEA-4: SQLITE DBPro: - Flexible, Searchable, RAM-efficient (no need to copy everything to RAM) Con: - not human-readable, Dependance on SQLITE, binary format is less suited for git-storagey7j0ebb5c42-4e71-48c2-9ec2-4c841cb39ce6-= +UcEXAMPLECache coherencyAll communication partners shall run on cache-coherent cores and memory 0{_}x=2161a1c9-1150-40f8-a530-01e47427dc73R< - UnEXAMPLErelease lock (2) LoD02084515-ab2e-417f-9350-165d5d322820^: E UnEXAMPLEread and reset changed-flags 0{=B0b61a010-d778-4003-b95f-0fe2cc7edc9fO8 ' UnEXAMPLEPoll for data Lo𣙔4eb380c9-c500-4adc-98e3-8f60578e59a2W6 7 UnEXAMPLEset flags for changes7=:˛9b6ac433-ccd9-46b8-ab05-78206f09c927L5 ! UnEXAMPLEwrite data7ˡ+}7a39dce3-58ed-4c59-acb0-89b5e073b009N3 % UnEXAMPLEProvide data7|8c07b06d5-7b9c-4f6e-9ff0-762dda3aefbf|2 #iUEXAMPLEIPC-ConceptWhenever two software components exchange datad_}p8c3bb15a-00f6-4cff-a7e1-f87b8b124488o0 g UbEXAMPLEFailures during operation shall be analyzable\\3a83a5eb-282d-49c7-a95d-e4336723b05aj/ ] UbEXAMPLEA watchdog shall supervise the software.-Y??3d2f8114-3a47-479d-b3f7-aeb906ae878b`. I UbEXAMPLEThe system shall be updateable4Nl51eb7a03-f7d9-4765-a458-911903e54848f- 7)UcEXAMPLEoperating temperatureWhen the measured temperature exceeds the systems operating temperature range, a HW-watchdog triggers the software to power down the system.a|@m@mc1d06d19-169f-4515-9040-ff0c5a845355g, 7+UcEXAMPLEno reliable time-baseWhenever using date and time functions, the software shall cope with date and time - changing forward or backwards, - not reflecting the real-word time. Rationale: The system does not provide a reliable time base. From time to time, it synchronizes with a time master.\1SӎS3bffa13c-4034-4651-a260-fe79684d00e9B* /wUEXAMPLEA-3: Binary BLOBsPro: - Fast, Easy implementable, Space-efficient Con: - Not portable, not version-compatible, not human-readable{̜5d302c54-0b51-464e-8a69-3bc189fb45ffcrystal-facet-uml-1.34.1/utf8stringbuf/000077500000000000000000000000001415120503000177355ustar00rootroot00000000000000crystal-facet-uml-1.34.1/utf8stringbuf/include/000077500000000000000000000000001415120503000213605ustar00rootroot00000000000000crystal-facet-uml-1.34.1/utf8stringbuf/include/util/000077500000000000000000000000001415120503000223355ustar00rootroot00000000000000crystal-facet-uml-1.34.1/utf8stringbuf/include/util/string/000077500000000000000000000000001415120503000236435ustar00rootroot00000000000000crystal-facet-uml-1.34.1/utf8stringbuf/include/util/string/utf8codepoint.h000066400000000000000000000122031415120503000266050ustar00rootroot00000000000000/* File: utf8codepoint.h; Copyright and License: see below */ #ifndef UTF8CODEPOINT_H_ #define UTF8CODEPOINT_H_ /*! * \file utf8codepoint.h * \brief utf8codepoint is a struct of utf8-byte-length and the code-point of a character. * * You typically do not create a code point object yourself. * It is simply the return value of \link utf8stringbuf_get_char_at(utf8stringbuf_t,unsigned int) utf8stringbuf_get_char_at \endlink * * \note License: Use this code according to the license: Apache 2.0. * \author Copyright 2012-2021 A.Warnke; Email-contact: utf8stringbuf-at-andreaswarnke-dot-de */ #include #include #include #ifdef __cplusplus extern "C" { #endif struct utf8codepointseq_struct { char seq[4]; }; typedef struct utf8codepointseq_struct utf8codepointseq_t; /*! * \brief A character is a codepoint and a utf8-byte-count. * * Most code points are represented by a positive length and a positive code point. * The 0-termination of strings is represented as byte_length 1 and code_point 0. * A byte_length of 0 indcates an invalid code_point. */ struct utf8codepoint_struct { unsigned int byte_length; uint32_t code_point; }; /*! * \typedef utf8codepoint_t * \brief An utf-8 code point object */ typedef struct utf8codepoint_struct utf8codepoint_t; /*! * \brief utf8codepoint returns a code point struct */ static inline utf8codepoint_t utf8codepoint( uint32_t code_point ); /*! * \brief Creates a utf8codepoint_t struct from a pointer to an utf-8 character * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param that Pointer to an utf-8 character or NULL. * \param max_size maximum number of bytes to read. * \return A utf8codepoint_t struct. Even if that was NULL. */ static inline utf8codepoint_t utf8codepoint_init( const char *that, unsigned int max_size ); /*! * \brief Gets the unicode code point * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ The code point object * \return Unicode code point */ static inline uint32_t utf8codepoint_get_char( const utf8codepoint_t this_ ); /*! * \brief Gets the length of the utf8 encoded character in bytes. * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ The code point object * \return length of the utf8 encoded character in bytes. 0 if the code point is invalid. */ static inline unsigned int utf8codepoint_get_length( const utf8codepoint_t this_ ); /*! * \brief Gets the utf8 sequence * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ The code point object * \return utf8 sequence, unused bytes filled with 0 */ static inline utf8codepointseq_t utf8codepoint_get_utf8( const utf8codepoint_t this_ ); /*! * \brief Determines if this_ object is a valid unicode codepoint. * * Unicode defines code points in the range from 0x000000 to 0x10ffff. * Even within this range, the following integers are illegal: * 0xd800,..,0xdfff, 0xfdd0,..,0xfdef, * 0xfffe,0xffff,0x1fffe,0x1ffff,0x2fffe,0x2ffff,...,0x10fffe,0x10ffff. * \n * The 0x0 character which terminates strings is a valid unicode character. * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ The code point object * \return 1 if this object is valid and encodes a valid unicode code point, 0 otherwise. */ static inline int utf8codepoint_is_unicode( const utf8codepoint_t this_ ); /*! * \brief Determines if this_ object is valid. * * Utf8 can encode any integer from 0x00000000 to 0x0010ffff. For all these integers, * this function will return 1. Only illegal byte sequences in the input byte array will * result in 0. * \n * Unicode only defines code points from 0x000000 to 0x10ffff. And even within this range, * some code points are invalid. Call * \link utf8codepoint_is_unicode(const utf8codepoint_t this_) utf8codepoint_is_unicode \endlink * to check if the code point encodes a valid unicode character. * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ The code point object * \return 1 if this object is valid, 0 otherwise. */ static inline int utf8codepoint_is_valid( const utf8codepoint_t this_ ); extern const utf8codepoint_t UTF8CODEPOINT_INVAL_CHAR; #ifdef __cplusplus } #endif #include "util/string/utf8codepoint.inl" #endif /*UTF8CODEPOINT_H_*/ /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/include/util/string/utf8codepoint.inl000066400000000000000000000256051415120503000271520ustar00rootroot00000000000000/* File: utf8codepoint.inl; Copyright and License: see below */ /*! * \file utf8codepoint.inl * * \note License: Use this code according to the license: Apache 2.0. * \author Copyright 2012-2021 A.Warnke; Email-contact: utf8stringbuf-at-andreaswarnke-dot-de */ /*#ifndef UTF8CODEPOINT_INL_*/ /*#define UTF8CODEPOINT_INL_*/ #include #include #include #include #ifdef __cplusplus extern "C" { #endif /*! * \enum utf8codepoint_enum * \private */ /* enumeration for invalid code points */ enum utf8codepoint_enum {UTF8CODEPOINT_INVALID_LEN=0,}; /*! * \fn utf8codepoint_private_init_from_multi_byte( const char *that, unsigned int max_size ) * \private * \param that Pointer to a multi-byte utf-8 character; must not be NULL. * \param max_size maximum number of bytes to read. */ static inline utf8codepoint_t utf8codepoint_private_init_from_multi_byte( const char *that, unsigned int max_size ); static inline utf8codepoint_t utf8codepoint( uint32_t code_point ) { utf8codepoint_t result; /* for balanced performance between standard and worst cases, */ /* this_ is implemented as asymmetric decision tree: */ /* in the best case, we have 2 comparisons, in the worst case 3 */ result.byte_length = ( code_point <= 0x7ff ) ? ( ( code_point <= 0x7f ) ? 1 : 2 ) : ( ( code_point <= 0x10ffff ) ? ( ( code_point <= 0xffff ) ? 3 : 4 ) : UTF8CODEPOINT_INVALID_LEN ); result.code_point = code_point; return result; } static inline utf8codepoint_t utf8codepoint_init( const char *that, unsigned int max_size ) { utf8codepoint_t result = { UTF8CODEPOINT_INVALID_LEN, 0x0, }; if (( that != NULL )&&( max_size > 0 )) { const unsigned char firstByte = (const unsigned char) (that[0]); if (( 0x80 & firstByte ) == 0x00 ) { /* 7-bit ASCII character */ result.byte_length = 1; result.code_point = firstByte; } else if ( firstByte < 0xe0 ) { if ( max_size >= 2 ) { const unsigned char secondByte = (const unsigned char) (that[1]); if (( ( 0xe0 & firstByte ) == 0xc0 ) && ( ( 0xc0 & secondByte ) == 0x80 )) { /* first and second byte are valid */ result.byte_length = 2; result.code_point = (((uint32_t)(firstByte & 0x1f))<<6) |(secondByte & 0x3f); } } } else if ( firstByte < 0xf0 ) { if ( max_size >= 3 ) { const unsigned char secondByte = (const unsigned char) (that[1]); const unsigned char thirdByte = (const unsigned char) (that[2]); if (( ( 0xc0 & secondByte ) == 0x80 ) && ( ( 0xc0 & thirdByte ) == 0x80 )) { /* second and third bytes are valid */ result.byte_length = 3; result.code_point = (((uint32_t)(firstByte & 0x0f))<<12) |(((uint32_t)(secondByte & 0x3f))<<6) |(thirdByte & 0x3f); } } } else if ( firstByte < 0xf8 ) { if ( max_size >= 4 ) { const unsigned char secondByte = (const unsigned char) (that[1]); const unsigned char thirdByte = (const unsigned char) (that[2]); const unsigned char fourthByte = (const unsigned char) (that[3]); if (( ( 0xc0 & secondByte ) == 0x80 ) && ( ( 0xc0 & thirdByte ) == 0x80 ) && ( ( 0xc0 & fourthByte ) == 0x80 )) { /* second, third and fourth bytes are valid */ result.byte_length = 4; result.code_point = (((uint32_t)(firstByte & 0x07))<<18) |(((uint32_t)(secondByte & 0x3f))<<12) |(((uint32_t)(thirdByte & 0x3f))<<6) |(fourthByte & 0x3f); if ( result.code_point > 0x10ffff ) { /* invalid */ result.byte_length = UTF8CODEPOINT_INVALID_LEN; } } } } } return result; } static inline uint32_t utf8codepoint_get_char( const utf8codepoint_t this_ ) { return this_.code_point; } static inline unsigned int utf8codepoint_get_length( const utf8codepoint_t this_ ) { return this_.byte_length; } static inline utf8codepointseq_t utf8codepoint_get_utf8( const utf8codepoint_t this_ ) { utf8codepointseq_t result; const uint32_t code_point = this_.code_point; if ( code_point <= 0x7ff ) { if ( code_point <= 0x7f ) { result.seq[0] = code_point; result.seq[1] = '\0'; result.seq[2] = '\0'; result.seq[3] = '\0'; assert( this_.byte_length == 1 ); } else { result.seq[0] = (0xc0 | (code_point>>6)); result.seq[1] = (0x80 | (code_point&0x3f)); result.seq[2] = '\0'; result.seq[3] = '\0'; assert( this_.byte_length == 2 ); } } else { if ( code_point <= 0x10ffff ) { if ( code_point <= 0xffff ) { result.seq[0] = (0xe0 | (code_point>>12)); result.seq[1] = (0x80 | ((code_point>>6)&0x3f)); result.seq[2] = (0x80 | (code_point&0x3f)); result.seq[3] = '\0'; assert( this_.byte_length == 3 ); } else { result.seq[0] = (0xf0 | (code_point>>18)); result.seq[1] = (0x80 | ((code_point>>12)&0x3f)); result.seq[2] = (0x80 | ((code_point>>6)&0x3f)); result.seq[3] = (0x80 | (code_point&0x3f)); assert( this_.byte_length == 4 ); } } else { /* UTF8CODEPOINT_INVALID_LEN */ result.seq[0] = '\0'; result.seq[1] = '\0'; result.seq[2] = '\0'; result.seq[3] = '\0'; assert( this_.byte_length == 0 ); } } return result; } static inline int utf8codepoint_is_valid( const utf8codepoint_t this_ ) { return ( UTF8CODEPOINT_INVALID_LEN != this_.byte_length ) ? 1 : 0; } static inline int utf8codepoint_is_unicode( const utf8codepoint_t this_ ) { int result = 0; if ( this_.byte_length != UTF8CODEPOINT_INVALID_LEN ) { if ( this_.code_point < 0xd800 ) { result = 1; } else if (( this_.code_point > 0xdfff ) && ( this_.code_point < 0xfdd0 )) { result = 1; } else if (( this_.code_point > 0xfdef ) && ( this_.code_point < 0x110000 )) { if (( this_.code_point & 0x00fffe ) != 0x00fffe ) { result = 1; } } } return result; } /* function to initialize an code point from a multi-byte character, non-inline */ static inline utf8codepoint_t utf8codepoint_private_init_from_multi_byte( const char *that, unsigned int max_size ) { utf8codepoint_t result = { UTF8CODEPOINT_INVALID_LEN, 0x0, }; if ( max_size >= 1 ) { unsigned char firstByte = (unsigned char) (that[0]); unsigned int byte_length = ( firstByte < 0xe0 ) ? ( ( firstByte < 0xc0 ) ? 1 : 2 ) : ( ( firstByte < 0xf8 ) ? ( ( firstByte < 0xf0 ) ? 3 : 4 ) : UTF8CODEPOINT_INVALID_LEN ); switch ( byte_length ) { case 1: if ( firstByte < 0x80 ) { /* first byte is valid */ result.byte_length = 1; result.code_point = firstByte; } break; case 2: if ( max_size >= 2 ) { unsigned char secondByte = (unsigned char) (that[1]); if (( 0xc0 & secondByte ) == 0x80 ) { /* second byte is valid */ result.byte_length = 2; result.code_point = (((uint32_t)(firstByte & 0x1f))<<6) |(secondByte & 0x3f); } } break; case 3: if ( max_size >= 3 ) { unsigned char secondByte = (unsigned char) (that[1]); unsigned char thirdByte = (unsigned char) (that[2]); if (( ( 0xc0 & secondByte ) == 0x80 ) && ( ( 0xc0 & thirdByte ) == 0x80 )) { /* second and third bytes are valid */ result.byte_length = 3; result.code_point = (((uint32_t)(firstByte & 0x0f))<<12) |(((uint32_t)(secondByte & 0x3f))<<6) |(thirdByte & 0x3f); } } break; case 4: if ( max_size >= 4 ) { unsigned char secondByte = (unsigned char) (that[1]); unsigned char thirdByte = (unsigned char) (that[2]); unsigned char fourthByte = (unsigned char) (that[3]); if (( ( 0xc0 & secondByte ) == 0x80 ) && ( ( 0xc0 & thirdByte ) == 0x80 ) && ( ( 0xc0 & fourthByte ) == 0x80 )) { /* second, third and fourth bytes are valid */ result.byte_length = 4; result.code_point = (((uint32_t)(firstByte & 0x07))<<18) |(((uint32_t)(secondByte & 0x3f))<<12) |(((uint32_t)(thirdByte & 0x3f))<<6) |(fourthByte & 0x3f); } } break; default: break; } } return result; } #ifdef __cplusplus } #endif /*#endif*/ /*UTF8CODEPOINT_INL_*/ /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/include/util/string/utf8codepointiterator.h000066400000000000000000000067171415120503000303740ustar00rootroot00000000000000/* File: utf8codepointiterator.h; Copyright and License: see below */ #ifndef UTF8CODEPOINTITERATOR_H #define UTF8CODEPOINTITERATOR_H /* public file for the doxygen documentation: */ /*! * \file * \brief Iterates over codepoints of e.g. a stringview */ #include "util/string/utf8codepoint.h" #include "util/string/utf8string.h" #include "util/string/utf8stringview.h" #include /*! * \brief all data attributes needed for the code point iterator functions * * The iterator works similar to the J2SE-ListIterator, hibernate-query-Iterator and QT-QListIterator: * while ( hasNext() ) { element = next() }; */ struct utf8codepointiterator_struct { utf8codepoint_t next; /*!< the next codepoint-element */ utf8stringview_t remaining; /*!< remaining part of the element_list which is not yet processed */ }; typedef struct utf8codepointiterator_struct utf8codepointiterator_t; /*! * \brief initializes the utf8codepointiterator_t struct * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ pointer to own object attributes * \param string list of code points */ static inline void utf8codepointiterator_init ( utf8codepointiterator_t *this_, utf8stringview_t string ); /*! * \brief destroys the utf8codepointiterator_t struct * * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ pointer to own object attributes */ static inline void utf8codepointiterator_destroy ( utf8codepointiterator_t *this_ ); /*! * \brief checks if a next code point-element exists in the iterator - does not modify the iterator state * * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ pointer to own object attributes * \return true if there is a next element in the iterator */ static inline bool utf8codepointiterator_has_next ( const utf8codepointiterator_t *this_ ); /*! * \brief reads the next code point-element from the stringview. * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ pointer to own object attributes * \return the next code point-element parsed from the stringview; * in case there is no next code point-element, utf8codepoint_is_valid() of the result is false */ static inline utf8codepoint_t utf8codepointiterator_next ( utf8codepointiterator_t *this_ ); /*! * \brief moves the iterator to the next code point-element, updates (*this_).next * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ pointer to own object attributes */ static inline void utf8codepointiterator_private_step_to_next ( utf8codepointiterator_t *this_ ); #include "utf8codepointiterator.inl" #endif /* UTF8CODEPOINTITERATOR_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/include/util/string/utf8codepointiterator.inl000066400000000000000000000043501415120503000307160ustar00rootroot00000000000000/* File: utf8codepointiterator.inl; Copyright and License: see below */ static inline void utf8codepointiterator_init ( utf8codepointiterator_t *this_, utf8stringview_t string ) { (*this_).remaining = string; utf8codepointiterator_private_step_to_next( this_ ); } static inline void utf8codepointiterator_destroy ( utf8codepointiterator_t *this_ ) { } static inline bool utf8codepointiterator_has_next ( const utf8codepointiterator_t *this_ ) { return utf8codepoint_is_valid( (*this_).next ); } static inline utf8codepoint_t utf8codepointiterator_next ( utf8codepointiterator_t *this_ ) { utf8codepoint_t result = (*this_).next; utf8codepointiterator_private_step_to_next( this_ ); return result; } static inline void utf8codepointiterator_private_step_to_next ( utf8codepointiterator_t *this_ ) { const size_t remaining_len = utf8stringview_get_length( (*this_).remaining ); if ( remaining_len == 0 ) { (*this_).next = UTF8CODEPOINT_INVAL_CHAR; } else { (*this_).next = utf8codepoint_init( utf8stringview_get_start( (*this_).remaining ), remaining_len ); if ( utf8codepoint_is_valid( (*this_).next ) ) { const unsigned int next_len = utf8codepoint_get_length( (*this_).next ); (*this_).remaining = utf8stringview_init_region( utf8stringview_get_start( (*this_).remaining ), next_len, (remaining_len - next_len ) ); } else { (*this_).remaining = UTF8STRINGVIEW_NULL; } } } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/include/util/string/utf8error.h000066400000000000000000000040761415120503000257630ustar00rootroot00000000000000/* File: utf8error.h; Copyright and License: see below */ #ifndef UTF8ERROR_H_ #define UTF8ERROR_H_ /*! * \file utf8error.h * \brief utf8error is an enumeration of error constants. * * \note License: Use this code according to the license: Apache 2.0. * \author Copyright 2012-2021 A.Warnke; Email-contact: utf8stringbuf-at-andreaswarnke-dot-de */ #ifdef __cplusplus extern "C" { #endif /*! * \enum utf8error_enum * * Enumeration for success and error states. * * It is possible to bitwise-or multiple errors to collect errors over several statements, * e.g. { strerr |= utf8stringbuf_copy_str(...); strerr |= utf8stringbuf_append_str(...); }, * and evaluate multiple errors only once at the end. */ enum utf8error_enum { UTF8ERROR_SUCCESS = 0x000000, /*!< success, there was no error */ UTF8ERROR_NOT_FOUND = 0x010000, /*!< pattern not found */ UTF8ERROR_NULL_PARAM = 0x020000, /*!< NULL was provided as parameter instead of a valid pointer */ UTF8ERROR_OUT_OF_RANGE = 0x040000, /*!< some integer parameter was out of range */ UTF8ERROR_TRUNCATED = 0x080000, /*!< the resulting string did not fit into the buffer, the string was truncated */ UTF8ERROR_NOT_A_CODEPOINT = 0x100000, /*!< a codepoint was out of range: only 0x00000000 to 0x0010ffff are valid in utf8 (since 2003) */ }; /*! * \typedef utf8error_t * \brief Enumeration of error constants */ typedef enum utf8error_enum utf8error_t; #ifdef __cplusplus } #endif #endif /*UTF8ERROR_H_*/ /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/include/util/string/utf8string.h000066400000000000000000000276631415120503000261470ustar00rootroot00000000000000/* File: utf8string.h; Copyright and License: see below */ #ifndef UTF8STRING_H_ #define UTF8STRING_H_ /*! * \file utf8string.h * \brief utf8string provides functions to search and compare c-strings. * * \note License: Use this code according to the license: Apache 2.0. * \author Copyright 2012-2021 A.Warnke; Email-contact: utf8stringbuf-at-andreaswarnke-dot-de */ #include "util/string/utf8codepoint.h" #include "util/string/utf8stringbuf.h" #include #include #include #ifdef __cplusplus extern "C" { #endif /*! * \def UTF8STRING_NULL * \brief NULL value of an utf8string_t * * \n * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) */ #define UTF8STRING_NULL (NULL) /*! * \typedef utf8string_t * \brief The string object: A const char pointer. * * utf8string_t objects point to immutable strings, use a utf8stringbuf_t to modify the string object. */ typedef const char* utf8string_t; /* Note: If optimization level is zero, inline might not work. */ /* You possibly have to append the following string */ /* after every function prototype for gcc: */ /* __attribute__((always_inline)) */ /* Or prepend the following string */ /* to every function prototype for Visual Studio: */ /* __forceinline */ /*! * \brief Gets the size of the string: the length plus 1 for the terminating zero * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ The string object * \return Size of the string. This is always positive, never 0. */ static inline size_t utf8string_get_size( const char *this_ ); /*! * \brief Gets the length of the string. * * The 0 termination byte is not counted. * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A string object * \return Length of the string in bytes (not in utf-8 code-points) */ static inline unsigned int utf8string_get_length( const char *this_ ); /*! * \brief Checks if two strings are equal. * * NULL never equals anything. * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A 0-terminated c string. In case of NULL, this function returns 0. * \param that Another 0-terminated c string. In case of NULL, this function returns 0. * \return 1 if the strings are equal, 0 if not. */ static inline int utf8string_equals_str( const char *this_, const char *that ); /*! * \brief Checks if two strings are equal. * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A 0-terminated c string. In case of NULL, this function returns 0. * \param that A string buffer object * \return 1 if the strings are equal, 0 if not. */ static inline int utf8string_equals_buf( const char *this_, const utf8stringbuf_t that ); /*! * \brief Checks if the region equals the given string. * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A 0-terminated c string. In case of NULL, this function returns 0. * \param start the start position of the region to compare. * \param that A 0-terminated c string. In case of NULL, this function returns 0. * \return 1 if the region equals the given string, 0 if not. */ static inline int utf8string_equals_region_str( const char *this_, int start, const char *that ); /*! * \brief Checks if the region equals the given string. * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A 0-terminated c string. In case of NULL, this function returns 0. * \param start the start position of the region to compare. * \param that A string buffer object * \return 1 if the region equals the given string, 0 if not. */ static inline int utf8string_equals_region_buf( const char *this_, int start, const utf8stringbuf_t that ); /*! * \brief Checks if the string buffer starts with the specified characters. * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A 0-terminated c string. In case of NULL, this function returns 0. * \param that A 0-terminated c string. In case of NULL, this function returns 0. * \return 1 if the string starts with the characters in that, 0 if not. */ static inline int utf8string_starts_with_str( const char *this_, const char *that ); /*! * \brief Checks if the string buffer starts with the specified characters. * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A 0-terminated c string. In case of NULL, this function returns 0. * \param that A string buffer object. * \return 1 if the string starts with the characters in that, 0 if not. */ static inline int utf8string_starts_with_buf( const char *this_, const utf8stringbuf_t that ); /*! * \brief Checks if the string buffer ends with the specified characters. * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A 0-terminated c string. In case of NULL, this function returns 0. * \param that A 0-terminated c string. In case of NULL, this function returns 0. * \return 1 if the string ends with the characters in that, 0 if not. */ static inline int utf8string_ends_with_str( const char *this_, const char *that ); /*! * \brief Checks if the string buffer ends with the specified characters. * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A 0-terminated c string. In case of NULL, this function returns 0. * \param that A string buffer object. * \return 1 if the string ends with the characters in that, 0 if not. */ static inline int utf8string_ends_with_buf( const char *this_, const utf8stringbuf_t that ); /*! * \brief Searches a pattern within a string * * Example: * \code * utf8string_find_first_buf( "hasta la vista", utf8stringbuf( "sta" )); * \endcode * will return index 2. * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n*m), n:strlen, m:patternlen * \param this_ The 0-terminated string within which to search * \param pattern The string buffer containing the byte-sequence to search * \return Index of the first occurrence within the string. * -1 if there is no match. */ static inline int utf8string_find_first_buf( const char *this_, const utf8stringbuf_t pattern ); /*! * \brief Searches a pattern within a string * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n*m), n:strlen, m:patternlen * \param this_ The 0-terminated string within which to search * \param pattern The 0-terminated string to search * \return Index of the first occurrence within the string. * -1 if there is no match. */ static inline int utf8string_find_first_str( const char *this_, const char *pattern ); /*! * \brief Searches a pattern within a string starting at the end * * Example: * \code * utf8string_find_last_buf( "hasta la vista", utf8stringbuf( "sta" )); * \endcode * will return index 11. * \note Performance-Rating: [ ]single-operation [ ]fast [ ]medium [x]slow ; Performance-Class: O(n*m), n:strlen, m:patternlen * \param this_ The 0-terminated string within which to search * \param pattern The string buffer containing the byte-sequence to search * \return Index of the first occurrence within the string. * -1 if there is no match. */ static inline int utf8string_find_last_buf( const char *this_, const utf8stringbuf_t pattern ); /*! * \brief Searches a pattern within a string starting at the end * \note Performance-Rating: [ ]single-operation [ ]fast [ ]medium [x]slow ; Performance-Class: O(n*m), n:strlen, m:patternlen * \param this_ The 0-terminated string within which to search * \param pattern The 0-terminated string to search * \return Index of the first occurrence within the string. * -1 if there is no match. */ static inline int utf8string_find_last_str( const char *this_, const char *pattern ); /*! * \brief Searches a pattern within a string * * Example: * \code * utf8string_find_next_buf( "hasta la vista", utf8stringbuf( "sta" ), 3); * \endcode * will return index 11. * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n*m), n:strlen, m:patternlen * \param this_ The 0-terminated string within which to search * \param pattern The string buffer containing the byte-sequence to search * \param start_index Index where to start the search. * \return Index of the next occurrence within the string equal or greater than start_index. * -1 if there is no match. */ static inline int utf8string_find_next_buf( const char *this_, const utf8stringbuf_t pattern, int start_index ); /*! * \brief Searches a pattern within a string * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n*m), n:strlen, m:patternlen * \param this_ The 0-terminated string within which to search * \param pattern The 0-terminated string to search * \param start_index Index where to start the search. * \return Index of the next occurrence within the string equal or greater than start_index. * -1 if there is no match. */ static inline int utf8string_find_next_str( const char *this_, const char *pattern, int start_index ); /*! * \brief Gets the code point at a given byte index. * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ The 0-terminated string object * \param byte_index index where to read the character from. * \return A unicode codepoint. * utf8codepoint_is_valid will state 0 if there is an illegal byte-sequence within the string * or if byte_index is out of range. * The terminating zero of a string is a valid character. */ static inline utf8codepoint_t utf8string_get_char_at( const char *this_, unsigned int byte_index ); /*! * \brief Parses a signed integer from a string in decimal format * * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A 0-terminated c string. In case of NULL, this function returns UTF8ERROR_NULL_PARAM. * \param out_byte_length The number of bytes parsed. (In utf8, this is identical to the number of code points) * \param out_number The parsed integer * \return UTF8ERROR_SUCCESS in case of success: An integer number has been parsed. * UTF8ERROR_NOT_FOUND in case there is no decimal integer. * UTF8ERROR_NULL_PARAM in this_ or out_number is NULL * UTF8ERROR_OUT_OF_RANGE in case there is a decimal integer which does not fit into int64_t. */ static inline utf8error_t utf8string_parse_int( const char *this_, unsigned int *out_byte_length, int64_t *out_number ); #ifdef __cplusplus } #endif #include "util/string/utf8string.inl" #endif /*UTF8STRING_H_*/ /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/include/util/string/utf8string.inl000066400000000000000000000224571415120503000264760ustar00rootroot00000000000000/* File: utf8string.inl; Copyright and License: see below */ /*! * \file utf8string.inl * * \note License: Use this code according to the license: Apache 2.0. * \author Copyright 2012-2021 A.Warnke; Email-contact: utf8stringbuf-at-andreaswarnke-dot-de */ /*#ifndef UTF8STRING_INL_*/ /*#define UTF8STRING_INL_*/ #include "util/string/utf8codepoint.h" #include "util/string/utf8stringbuf.h" #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /*! * \enum utf8string_bool_enum * \private */ /* enumeration for true and false or success and failure */ enum utf8string_bool_enum {UTF8STRING_FALSE=0, UTF8STRING_TRUE=1,}; /*! * \enum utf8string_search_enum * \private */ /* enumeration for search pattern not found */ enum utf8string_search_enum {UTF8STRING_NOT_FOUND=-1,}; static inline size_t utf8string_get_size( const char *this_ ) { size_t sizeResult = 0; if ( this_ != NULL ) { sizeResult = strlen( this_ ) + 1; /* 1 for size of terminating 0 character */ } return sizeResult; } static inline unsigned int utf8string_get_length( const char *this_ ) { unsigned int lenResult = 0; if ( this_ != NULL ) { lenResult = strlen( this_ ); } return lenResult; } static inline int utf8string_equals_str( const char *this_, const char *that ) { int cmpResult = -1; if (( this_ != NULL ) && ( that != NULL )) { cmpResult = strcmp( this_, that ); } return ( cmpResult == 0 ) ? UTF8STRING_TRUE : UTF8STRING_FALSE; } static inline int utf8string_equals_buf( const char *this_, const utf8stringbuf_t that ) { int cmpResult = -1; if ( this_ != NULL ) { cmpResult = strcmp( this_, that.buf ); } return ( cmpResult == 0 ) ? UTF8STRING_TRUE : UTF8STRING_FALSE; } static inline int utf8string_equals_region_str( const char *this_, int start, const char *that ) { int cmpResult = -1; if (( this_ != NULL ) && ( that != NULL )) { int thisLen = strlen(this_); int thatLen = strlen(that); unsigned int end = ((unsigned int)start) + ((unsigned int)thatLen); if (( 0 <= start )&&( end <= thisLen )) { cmpResult = memcmp( &(this_[start]), that, thatLen ); } } return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE; } static inline int utf8string_equals_region_buf( const char *this_, int start, const utf8stringbuf_t that ) { int cmpResult = -1; if ( this_ != NULL ) { int thisLen = strlen(this_); int thatLen = strlen(that.buf); unsigned int end = ((unsigned int)start) + ((unsigned int)thatLen); if (( 0 <= start )&&( end <= thisLen )) { cmpResult = memcmp( &(this_[start]), that.buf, thatLen ); } } return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE; } static inline int utf8string_starts_with_str( const char *this_, const char *that ) { int cmpResult = -1; if (( this_ != NULL )&&( that != NULL )) { unsigned int thatLen = strlen( that ); cmpResult = strncmp( this_, that, thatLen ); } return ( cmpResult == 0 ) ? UTF8STRING_TRUE : UTF8STRING_FALSE; } static inline int utf8string_starts_with_buf( const char *this_, const utf8stringbuf_t that ) { int cmpResult = -1; if ( this_ != NULL ) { unsigned int thatLen = strlen( that.buf ); cmpResult = strncmp( this_, that.buf, thatLen ); } return ( cmpResult == 0 ) ? UTF8STRING_TRUE : UTF8STRING_FALSE; } static inline int utf8string_ends_with_str( const char *this_, const char *that ) { int cmpResult = -1; if (( this_ != NULL )&&( that != NULL )) { unsigned int thatLen = strlen( that ); unsigned int thisLen = strlen( this_ ); if ( thatLen <= thisLen ) { cmpResult = memcmp( &(this_[thisLen-thatLen]), that, thatLen ); } } return ( cmpResult == 0 ) ? UTF8STRING_TRUE : UTF8STRING_FALSE; } static inline int utf8string_ends_with_buf( const char *this_, const utf8stringbuf_t that ) { int cmpResult = -1; if ( this_ != NULL ) { unsigned int thatLen = strlen( that.buf ); unsigned int thisLen = strlen( this_ ); if ( thatLen <= thisLen ) { cmpResult = memcmp( &(this_[thisLen-thatLen]), that.buf, thatLen ); } } return ( cmpResult == 0 ) ? UTF8STRING_TRUE : UTF8STRING_FALSE; } static inline int utf8string_find_first_buf( const char *this_, const utf8stringbuf_t pattern ) { int result = UTF8STRING_NOT_FOUND; if ( this_ != NULL ) { const char *ptrResult = strstr( this_, pattern.buf ); if ( ptrResult != NULL ) { result = (int) (ptrResult - this_); } } return result; } static inline int utf8string_find_first_str( const char *this_, const char *pattern ) { int result = UTF8STRING_NOT_FOUND; if (( pattern != NULL )&&( this_ != NULL )) { const char *ptrResult = strstr( this_, pattern ); if ( ptrResult != NULL ) { result = (int) (ptrResult - this_); } } return result; } static inline int utf8string_find_last_buf( const char *this_, const utf8stringbuf_t pattern ) { int result = UTF8STRING_NOT_FOUND; if ( this_ != NULL ) { int thisLen = strlen( this_ ); int patternLen = strlen( pattern.buf ); if ( patternLen <= thisLen ) { for ( int probeIdx = (thisLen-patternLen); probeIdx >= 0; probeIdx --) { if ( 0 == memcmp( &(this_[probeIdx]), pattern.buf, patternLen )) { /* last occurrence found! */ result = probeIdx; break; } } } } return result; } static inline int utf8string_find_last_str( const char *this_, const char *pattern ) { int result = UTF8STRING_NOT_FOUND; if (( pattern != NULL )&&( this_ != NULL )) { int thisLen = strlen( this_ ); int patternLen = strlen( pattern ); if ( patternLen <= thisLen ) { for ( int probeIdx = (thisLen-patternLen); probeIdx >= 0; probeIdx --) { if ( 0 == memcmp( &(this_[probeIdx]), pattern, patternLen )) { /* last occurrence found! */ result = probeIdx; break; } } } } return result; } static inline int utf8string_find_next_buf( const char *this_, const utf8stringbuf_t pattern, int start_index ) { int result = UTF8STRING_NOT_FOUND; unsigned int thisSize = utf8string_get_size( this_ ); if (( start_index >= 0 ) && ( start_index < thisSize )) { const char *ptrResult = strstr( &(this_[start_index]), pattern.buf ); if ( ptrResult != NULL ) { result = (int) (ptrResult - this_); } } return result; } static inline int utf8string_find_next_str( const char *this_, const char *pattern, int start_index ) { int result = UTF8STRING_NOT_FOUND; unsigned int thisSize = utf8string_get_size( this_ ); if (( pattern != NULL ) && ( start_index >= 0 ) && ( start_index < thisSize )) { const char *ptrResult = strstr( &(this_[start_index]), pattern ); if ( ptrResult != NULL ) { result = (int) (ptrResult - this_); } } return result; } static inline utf8codepoint_t utf8string_get_char_at( const char *this_, unsigned int byte_index ) { utf8codepoint_t result = UTF8CODEPOINT_INVAL_CHAR; unsigned int thisSize = utf8string_get_size( this_ ); if ( byte_index < thisSize ) { result = utf8codepoint_init( &(this_[byte_index]), thisSize-byte_index ); } return result; } static inline utf8error_t utf8string_parse_int( const char *this_, unsigned int *out_byte_length, int64_t *out_number ) { utf8error_t result = UTF8ERROR_SUCCESS; if (( this_ != NULL )&&( out_number != NULL )) { char *endptr; errno=0; long long parseResult = strtoll( this_, &endptr, 10 /* base */); if ((parseResult==0)||(parseResult==LLONG_MIN)||(parseResult==LLONG_MAX)) { if (( errno == ERANGE )||( errno == EINVAL )) { result = UTF8ERROR_OUT_OF_RANGE; } } unsigned int length; if ( endptr == NULL ) { length = utf8string_get_length( this_ ); } else { length = (int)(endptr-this_); } if ( out_byte_length != NULL ) { *out_byte_length = length; } if ( length == 0 ) { result = UTF8ERROR_NOT_FOUND; } *out_number = parseResult; } else { result = UTF8ERROR_NULL_PARAM; } return result; } #ifdef __cplusplus } #endif /*#endif*/ /*UTF8STRING_INL_*/ /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/include/util/string/utf8stringbuf.h000066400000000000000000001247731415120503000266440ustar00rootroot00000000000000/* File: utf8stringbuf.h; Copyright and License: see below */ #ifndef UTF8STRINGBUF_H_ #define UTF8STRINGBUF_H_ /*! * \file utf8stringbuf.h * \brief utf8stringbuf provides functions to build, search and modify c-strings. * * utf8stringbuf provides a struct consisting of * \li a pointer to an character array and * \li the size of the array. * * Initialize the struct: * \code * char myBuf[50] = ""; * utf8stringbuf_t myStrBuf = UTF8STRINGBUF(myBuf); * \endcode * * Use the utf8stringbuf functions like * \code * utf8stringbuf_append_str( myStrBuf, "Hello" ); * \endcode * to build strings, search strings and copy strings. * * Get a standard, 0-terminated C-String whenever needed: * \code * char* cStr = utf8stringbuf_get_string( myStrBuf ); * \endcode * * \note License: Use this code according to the license: Apache 2.0. * \author Copyright 2012-2021 A.Warnke; Email-contact: utf8stringbuf-at-andreaswarnke-dot-de */ #include "util/string/utf8codepoint.h" #include "util/string/utf8error.h" #include "util/string/utf8stringntuple.h" #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* Note: If optimization level is zero, inline might not work. */ /* You possibly have to append the following string */ /* after every function prototype for gcc: */ /* __attribute__((always_inline)) */ /* Or prepend the following string */ /* to every function prototype for Visual Studio: */ /* __forceinline */ /*! * \def UTF8STRINGBUF(charArr) * \brief Macro to facilitate static initialisation of an utf8stringbuf_t * * Example usage: * \n * If you need only a small, temporary stringbuffer, consider to create this dynamically on the stack: * \code * #include "util/string/utf8stringbuf.h" * void MySampleFunction() { * char myArr[50] = ""; * utf8stringbuf_t myStrBuf = UTF8STRINGBUF(myArr); * \endcode * \n * If you need a stringbuffer that is either big or permanent, * and which is accessed only by one single thread, * consider to create this in the data section of your compilation-unit: * \code * #include "util/string/utf8stringbuf.h" * static char mySqlArr[16384] = ""; * utf8stringbuf_t mySqlBuf = UTF8STRINGBUF(mySqlArr); * \endcode * \n * In a bigger project or in a multithreaded environment, * consider to encapsulate your stringbuffer within a struct. * You still have to cope with locking but all functions can work on a pointer * to that struct instead of accessing global variables. * \code * #include "util/string/utf8stringbuf.h" * struct InitTestStruct { * char urlArr[8192]; * utf8stringbuf_t url; * pthread_mutex_t lock; * }; * typedef struct InitTestStruct InitTest_t; * static InitTest_t structTest = { "http://", UTF8STRINGBUF(structTest.urlArr), PTHREAD_MUTEX_INITIALIZER, }; * \endcode * \n * To statically initialize a whole array of the struct shown above, an own macro may help: * \code * #define INITTEST(testStr,this_) { testStr, UTF8STRINGBUF( this_.urlArr), PTHREAD_MUTEX_INITIALIZER, } * static InitTest_t structArrTest[] = { * INITTEST( "svn://first", structArrTest[0] ), * INITTEST( "http://second", structArrTest[1] ), * INITTEST( "ftp://third", structArrTest[2] ), * INITTEST( "file://last", structArrTest[3] ), * }; * \endcode * \n * To reduce footprint size while allocating static strings, put the character-arrays to bss-segment * while initializing the utf8stringbufs in the data segment: * \code * static char ThousandPathNames[1000][256]; // no initialiation given here, will be located in bss and be initialized to zero * #define PATH_INIT(x) UTF8STRINGBUF( ThousandPathNames[x] ) * #define FIVE_PATHS_INIT(x) PATH_INIT(x+0), PATH_INIT(x+1), PATH_INIT(x+2), PATH_INIT(x+3), PATH_INIT(x+4) * #define TWENTY_PATHS_INIT(x) FIVE_PATHS_INIT(x+0), FIVE_PATHS_INIT(x+5), FIVE_PATHS_INIT(x+10), FIVE_PATHS_INIT(x+15) * #define HUNDRED_PATHS_INIT(x) TWENTY_PATHS_INIT(x+0), TWENTY_PATHS_INIT(x+20), TWENTY_PATHS_INIT(x+40), TWENTY_PATHS_INIT(x+60), TWENTY_PATHS_INIT(x+80) * static utf8stringbuf_t ThousandPaths[1000] = { * HUNDRED_PATHS_INIT(0), HUNDRED_PATHS_INIT(100), HUNDRED_PATHS_INIT(200), HUNDRED_PATHS_INIT(300), * HUNDRED_PATHS_INIT(400), HUNDRED_PATHS_INIT(500), HUNDRED_PATHS_INIT(600), HUNDRED_PATHS_INIT(700), * HUNDRED_PATHS_INIT(800), HUNDRED_PATHS_INIT(900), * }; // only these utf8stringbuf_t objects will exist in data segment. On a 32-bit platform, this should be 8kB. * \endcode * \n * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) */ #define UTF8STRINGBUF(charArr) {.size=sizeof(charArr),.buf=charArr} /*! * \brief A string buffer is a pair of size and an array of that size. * * \invariant size must not be zero. * buf points to an array of size bytes. * The array shall be valid and null-terminated and located on a writeable memory page (non-const). */ struct utf8stringbuf_struct { size_t size; char* buf; }; /*! * \typedef utf8stringbuf_t * \brief The string buffer object * * It encapsulates memory-pointers (char*), memory-sizes (size_t) and indices (ptrdiff_t) * so that the calling code only sees a pointer-like utf8stringbuf_t struct and integer-indices. * Errors are reported via an utf8error_t, in some exceptional cases via -1 as special-index. */ typedef struct utf8stringbuf_struct utf8stringbuf_t; /*! * \brief Creates a utf8stringbuf_t struct from a 0-terminated string * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param that Pointer to a 0-terminated string or NULL. * The length of that string plus 1 is taken as buffer size. * that must not point to a const character array. * \return A utf8stringbuf_t struct. Even if that was NULL. */ static inline utf8stringbuf_t utf8stringbuf( char *that ); /*! * \brief utf8stringbuf_init returns a stringbuf struct, buf is not modified * * Use \link utf8stringbuf_clear(utf8stringbuf_t) utf8stringbuf_clear \endlink to empty the string buffer. * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param size size of the buf array. size shall be greater or equal 1. * \param buf pointer to a non-const byte array. buf must not be NULL. * \return A valid utf8stringbuf_t struct. Even if buf or size were NULL. */ static inline utf8stringbuf_t utf8stringbuf_init( size_t size, char *buf ); /*! * \brief utf8stringbuf_clear clears the contents of the string buffer. * * The complete buffer is erased by zeroes. * \n * This function may be called on an uninitialized buffer that possibly is not null-terminated. * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:size * \param this_ The string buffer object to be cleared. */ static inline void utf8stringbuf_clear( utf8stringbuf_t this_ ); /*! * \brief Gets the pointer to the character array * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ The string buffer object * \return Pointer to the character array, never NULL */ static inline char* utf8stringbuf_get_string( const utf8stringbuf_t this_ ); /*! * \brief Gets the size of the character array (not the length of the current c string which is always shorter) * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ The string buffer object * \return Size of the character array. This is always positive, never 0. */ static inline size_t utf8stringbuf_get_size( const utf8stringbuf_t this_ ); /*! * \brief Gets the length of the string. * * The 0 termination byte is not counted. * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A string buffer object * \return Length of the string in bytes (not in utf-8 code-points) */ static inline unsigned int utf8stringbuf_get_length( const utf8stringbuf_t this_ ); /*! * \brief Checks if two strings are equal. * * Only the strings are compared, not the possibly trailing bytes after the string. * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A string buffer object * \param that A 0-terminated c string. In case of NULL, this function returns 0. * \return 1 if the strings are equal, 0 if not. */ static inline int utf8stringbuf_equals_str( const utf8stringbuf_t this_, const char *that ); /*! * \brief Checks if two strings are equal. * * Only the strings are compared, not the trailing bytes after the string. * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A string buffer object * \param that Another string buffer object * \return 1 if the strings are equal, 0 if not. */ static inline int utf8stringbuf_equals_buf( const utf8stringbuf_t this_, const utf8stringbuf_t that ); /*! * \brief Checks if the region equals the given string. * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A string buffer object * \param start the start position of the region to compare. * \param that A 0-terminated c string. In case of NULL, this function returns 0. * \return 1 if the region equals the given string, 0 if not. */ static inline int utf8stringbuf_equals_region_str( const utf8stringbuf_t this_, int start, const char *that ); /*! * \brief Checks if the region equals the given string. * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A string buffer object * \param start the start position of the region to compare. * \param that Another string buffer object * \return 1 if the region equals the given string, 0 if not. */ static inline int utf8stringbuf_equals_region_buf( const utf8stringbuf_t this_, int start, const utf8stringbuf_t that ); /*! * \brief Checks if the string buffer starts with the specified characters. * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A string buffer object * \param that A 0-terminated c string. In case of NULL, this function returns 0. * \return 1 if the string buffer starts with the characters in that, 0 if not. */ static inline int utf8stringbuf_starts_with_str( const utf8stringbuf_t this_, const char *that ); /*! * \brief Checks if the string buffer starts with the specified characters. * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A string buffer object * \param that Another string buffer object. * \return 1 if the string buffer starts with the characters in that, 0 if not. */ static inline int utf8stringbuf_starts_with_buf( const utf8stringbuf_t this_, const utf8stringbuf_t that ); /*! * \brief Checks if the string buffer ends with the specified characters. * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A string buffer object * \param that A 0-terminated c string. In case of NULL, this function returns 0. * \return 1 if the string buffer ends with the characters in that, 0 if not. */ static inline int utf8stringbuf_ends_with_str( const utf8stringbuf_t this_, const char *that ); /*! * \brief Checks if the string buffer ends with the specified characters. * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ A string buffer object * \param that Another string buffer object. * \return 1 if the string buffer ends with the characters in that, 0 if not. */ static inline int utf8stringbuf_ends_with_buf( const utf8stringbuf_t this_, const utf8stringbuf_t that ); /*! * \brief Searches a pattern within a string * * Example: * \code * utf8stringbuf_find_first_buf( utf8stringbuf( "hasta la vista" ), utf8stringbuf( "sta" )); * \endcode * will return index 2. * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n*m), n:strlen, m:patternlen * \param this_ The string buffer within which to search * \param pattern The string buffer containing the byte-sequence to search * \return Index of the first occurrence within the string buffer. * -1 if there is no match. */ static inline int utf8stringbuf_find_first_buf( const utf8stringbuf_t this_, const utf8stringbuf_t pattern ); /*! * \brief Searches a pattern within a string * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n*m), n:strlen, m:patternlen * \param this_ The string buffer within which to search * \param pattern The 0-terminated string to search * \return Index of the first occurrence within the string buffer. * -1 if there is no match. */ static inline int utf8stringbuf_find_first_str( const utf8stringbuf_t this_, const char *pattern ); /*! * \brief Searches a pattern within a string starting at the end * * Example: * \code * utf8stringbuf_find_last_buf( utf8stringbuf( "hasta la vista" ), utf8stringbuf( "sta" )); * \endcode * will return index 11. * \note Performance-Rating: [ ]single-operation [ ]fast [ ]medium [x]slow ; Performance-Class: O(n*m), n:strlen, m:patternlen * \param this_ The string buffer within which to search * \param pattern The string buffer containing the byte-sequence to search * \return Index of the first occurrence within the string buffer. * -1 if there is no match. */ static inline int utf8stringbuf_find_last_buf( const utf8stringbuf_t this_, const utf8stringbuf_t pattern ); /*! * \brief Searches a pattern within a string starting at the end * \note Performance-Rating: [ ]single-operation [ ]fast [ ]medium [x]slow ; Performance-Class: O(n*m), n:strlen, m:patternlen * \param this_ The string buffer within which to search * \param pattern The 0-terminated string to search * \return Index of the first occurrence within the string buffer. * -1 if there is no match. */ static inline int utf8stringbuf_find_last_str( const utf8stringbuf_t this_, const char *pattern ); /*! * \brief Searches a pattern within a string * * Example: * \code * utf8stringbuf_find_next_buf( utf8stringbuf( "hasta la vista" ), utf8stringbuf( "sta" ), 3); * \endcode * will return index 11. * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n*m), n:strlen, m:patternlen * \param this_ The string buffer within which to search * \param pattern The string buffer containing the byte-sequence to search * \param start_index Index where to start the search. * \return Index of the next occurrence within the string buffer equal or greater than start_index. * -1 if there is no match. */ static inline int utf8stringbuf_find_next_buf( const utf8stringbuf_t this_, const utf8stringbuf_t pattern, int start_index ); /*! * \brief Searches a pattern within a string * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n*m), n:strlen, m:patternlen * \param this_ The string buffer within which to search * \param pattern The 0-terminated string to search * \param start_index Index where to start the search. * \return Index of the next occurrence within the string buffer equal or greater than start_index. * -1 if there is no match. */ static inline int utf8stringbuf_find_next_str( const utf8stringbuf_t this_, const char *pattern, int start_index ); /*! * \brief Gets the code point at a given byte index. * * Example usage: * \n * You can read a codepoint at a given byte index, * e.g. within a trademark information, where C2 AE is the (R) sign: * \code * utf8codepoint_t result; * char testArr[] = "\xC2\xAE 2005 A.A. \xC2\xAE 2006-2012 B.B."; * utf8stringbuf_t testBuf = UTF8STRINGBUF(testArr); * result = utf8stringbuf_get_char_at( testBuf, 13 ); * printf( "Code Point: %x", utf8codepoint_get_char(result) ); * \endcode * This code will print "Code Point: ae" because the utf-8 sequence C2 AE is the unicode character 00AE. * \n * * You can iterate over all code points: * \code * size_t byteSize = utf8stringbuf_get_size( testBuf ); * unsigned int currentIndex = 0; * for ( int loopCount = 0; loopCount < byteSize; loopCount ++ ) { * result = utf8stringbuf_get_char_at( testBuf, currentIndex ); * if ( utf8codepoint_is_valid(result) && ( utf8codepoint_get_char(result) != '\0' )) { * // do something with the current code point here * currentIndex += utf8codepoint_get_length(result); * } * else { * break; * } * } * \endcode * Note: the loopCount variable is just an unnecessary fallback to ensure that this is no endless loop, an unconditional for(;;) will also succeed. * \n * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ The string buffer object * \param byte_index index where to read the character from. * \return A unicode codepoint. The result is undefined if byte_index is out of range. * utf8codepoint_is_valid will state 0 if there is an illegal byte-sequence within the string buffer. * The terminating zero of a string buffer is a valid character. */ static inline utf8codepoint_t utf8stringbuf_get_char_at( const utf8stringbuf_t this_, unsigned int byte_index ); /*! * \brief Copies a string * * If the source string does not fit into the destination buffer, * the copied string gets truncated. This function ensures, that * truncation does not split an utf8 code-point in half. * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ The destination string buffer. It is valid to provide an uninitialized string buffer that possibly is not null-terminated. * \param original The source string buffer. The buffers of this_ and original must not overlap! * \return UTF8ERROR_SUCCESS in case of success: All bytes have been copied. * UTF8ERROR_TRUNCATED in case of truncation. */ static inline utf8error_t utf8stringbuf_copy_buf( utf8stringbuf_t this_, const utf8stringbuf_t original ); /*! * \brief Copies a string * * If the source string does not fit into the destination buffer, * the copied string gets truncated. This function ensures, that * truncation does not split an utf8 code-point in half. * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ The destination string buffer. It is valid to provide an uninitialized string buffer that possibly is not null-terminated. * \param original The 0-terminated source string. The buffers of this_ and original must not overlap! * NULL will cause the destination to be the empty string. * \return UTF8ERROR_SUCCESS in case of success: All bytes have been copied. * UTF8ERROR_TRUNCATED in case of truncation or UTF8ERROR_NULL_PARAM if that was NULL. */ static inline utf8error_t utf8stringbuf_copy_str( utf8stringbuf_t this_, const char *original ); /* sub returns 1 if all characters have been copied, 0 if truncated, 0 if that was NULL, 0 if illegal range */ /*! * \brief Copies a substring * * If the source string does not fit into the destination buffer, * the copied string gets truncated. This function ensures, that * truncation does not split an utf8 code-point in half. * \n * This function does not check, that the provided range in the source string is a valid utf8 sequence. * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ The destination string buffer. It is valid to provide an uninitialized buffer that possibly is not null-terminated. * \param that The source string buffer. The buffers of this_ and that must not overlap! * \param start Start index within the source string, from which to copy. 0 is the index of the first byte. * \param length Length in bytes to be copied. * \return UTF8ERROR_SUCCESS in case of success: All bytes have been copied. * UTF8ERROR_TRUNCATED in case of truncation or * UTF8ERROR_OUT_OF_RANGE in case of illegal range. */ extern utf8error_t utf8stringbuf_copy_region_from_buf( utf8stringbuf_t this_, const utf8stringbuf_t that, int start, int length ); /*! * \brief Copies a substring * * If the source string does not fit into the destination buffer, * the copied string gets truncated. This function ensures, that * truncation does not split an utf8 code-point in half. * \n * This function does not check, that the provided range in the source string is a valid utf8 sequence. * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ The destination string buffer. It is valid to provide an uninitialized string buffer that possibly is not null-terminated. * \param that The 0-terminated source string. The buffers of this_ and that must not overlap! * \param start Start index within the source string, from which to copy. 0 is the index of the first byte. * \param length Length in bytes to be copied. * \return UTF8ERROR_SUCCESS in case of success: All bytes have been copied. * UTF8ERROR_TRUNCATED in case of truncation or * UTF8ERROR_OUT_OF_RANGE in case of illegal range or * UTF8ERROR_NULL_PARAM if that was NULL. */ extern utf8error_t utf8stringbuf_copy_region_from_str( utf8stringbuf_t this_, const char *that, int start, int length ); /*! * \brief Replaces all occurrences of pattern by replacement. * \note Performance-Rating: [ ]single-operation [ ]fast [ ]medium [x]slow ; Performance-Class: O(n*p+n*(n+r)), n:strlen, p:patternlen, r:replacelen * \param this_ The string buffer within which to search * \param pattern The 0-terminated string to search. Empty or NULL patterns are not replaced. * \param replacement The 0-terminated string to replace the pattern with. * \return UTF8ERROR_SUCCESS in case of success, * UTF8ERROR_TRUNCATED if the string buffer was truncated or * UTF8ERROR_NULL_PARAM if pattern is NULL. */ static inline utf8error_t utf8stringbuf_replace_all_str_by_str( const utf8stringbuf_t this_, const char *pattern, const char *replacement ); /*! * \brief Replaces all occurrences of pattern by replacement. * \note Performance-Rating: [ ]single-operation [ ]fast [ ]medium [x]slow ; Performance-Class: O(n*p+n*(n+r)), n:strlen, p:patternlen, r:replacelen * \param this_ The string buffer within which to search * \param pattern The string to search. Empty patterns are not replaced. * \param replacement The string to replace the pattern with. * \return UTF8ERROR_SUCCESS in case of success, * UTF8ERROR_TRUNCATED if the string buffer was truncated. */ static inline utf8error_t utf8stringbuf_replace_all_buf_by_buf( const utf8stringbuf_t this_, const utf8stringbuf_t pattern, const utf8stringbuf_t replacement ); /*! * \brief Replaces all occurrences of patterns by the corresponding replacement strings * * This function is intended to escape character sequences. * \n * Examples: * \code * const char *const SQL_ENCODE[][2] = { * { "\0", "\\0" }, // within strings, null cannot be represented. * { "\x09", "\\t" }, * { "\x0a", "\\n" }, * { "\x0d", "\\r" }, * { "\x0e", "\\b" }, * { "\x1a", "\\z" }, * { "\"", "\\\"" }, * { "'", "\\'" }, * { "\\", "\\\\" }, * { "%", "\\%" }, // % replacement only needed in searches by LIKE operator * { "_", "\\_" }, // _ replacement only needed in searches by LIKE operator * { NULL, NULL } * }; * utf8stringbuf_replace_all( mySqlBuf, &SQL_ENCODE ); * const char *const XML_ENCODE[][2] = { * { "<", "<" }, * { ">", ">" }, * { "&", "&" }, * { "\"", """ }, // " replacement only needed in attribute values * { "'", "'" }, // ' replacement only needed in attribute values * { NULL, NULL } * }; * utf8stringbuf_replace_all( myXmlBuf, &XML_ENCODE ); * \endcode * \see https://dev.mysql.com/doc/refman/5.6/en/string-literals.html * \note Performance-Rating: [ ]single-operation [ ]fast [ ]medium [x]slow ; Performance-Class: O(n*p+n*(n+r)), n:strlen, p:sumOfPatternlen, r:maxOfReplacelen * \param this_ The string buffer within which to search * \param patterns_and_replacements The string array containing the byte-sequences to search and to replace, * terminated by a NULL-pair. Empty patterns are not replaced. * The string buffer this_ is processed from start to end; * if multiple patterns match, the first pattern is replaced. * \return UTF8ERROR_SUCCESS in case of success, * UTF8ERROR_TRUNCATED if the string buffer was truncated or * UTF8ERROR_NULL_PARAM if patterns_and_replacements is NULL. */ extern utf8error_t utf8stringbuf_replace_all( const utf8stringbuf_t this_, const char *const ((*patterns_and_replacements)[][2]) ); /*! * \brief Replaces a region within a string buffer * * If the resulting string does not fit into the destination buffer, * the destination string gets truncated. This function ensures, that * truncation does not split an utf8 code-point in half. * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n+r), n:strlen, r:replacelen * \param this_ The destination string buffer * \param start Start index within the string buffer, where to start the replacement. 0 is the index of the first byte. * \param length Length in bytes to be replaced. Provide 0 to only insert characters without deleting. * \param replacement The 0-terminated replacement string. The buffers of this_ and replacement must not overlap! * Provide the empty string or NULL to simply delete a region within a string buffer. * \return UTF8ERROR_SUCCESS in case of success: All bytes have been copied. * UTF8ERROR_OUT_OF_RANGE in case of illegal ranges or UTF8ERROR_TRUNCATED in case of truncation. */ static inline utf8error_t utf8stringbuf_replace_region_by_str( utf8stringbuf_t this_, int start, int length, const char *replacement ); /*! * \brief Replaces a region within a string buffer * * If the resulting string does not fit into the destination buffer, * the destination string gets truncated. This function ensures, that * truncation does not split an utf8 code-point in half. * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n+r), n:strlen, r:replacelen * \param this_ The destination string buffer * \param start Start index within the string buffer, where to start the replacement. 0 is the index of the first byte. * \param length Length in bytes to be replaced. Provide 0 to only insert characters without deleting. * \param replacement The replacement string buffer. The buffers of this_ and replacement must not overlap! * \return UTF8ERROR_SUCCESS in case of success: All bytes have been copied. * UTF8ERROR_OUT_OF_RANGE in case of illegal ranges or UTF8ERROR_TRUNCATED in case of truncation. */ static inline utf8error_t utf8stringbuf_replace_region_by_buf( utf8stringbuf_t this_, int start, int length, const utf8stringbuf_t replacement ); /*! * \brief Deletes a region within a string buffer * * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ The string buffer * \param start Start index within the string buffer, where to start deleting. 0 is the index of the first byte. * \param length Length in bytes to be deleted. * \return UTF8ERROR_SUCCESS in case of success: All bytes have been deleted. * UTF8ERROR_OUT_OF_RANGE in case of illegal ranges. */ static inline utf8error_t utf8stringbuf_delete( utf8stringbuf_t this_, int start, int length ); /*! * \brief Deletes a region at the end of a string buffer * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ The string buffer * \param length Length in bytes to be deleted. * \return UTF8ERROR_SUCCESS in case of success: All bytes have been deleted. * UTF8ERROR_OUT_OF_RANGE in case of illegal ranges. */ static inline utf8error_t utf8stringbuf_delete_from_end( utf8stringbuf_t this_, int length ); /*! * \brief Truncates a string buffer * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ The string buffer * \param start Start index within the string buffer, where to start deleting. 0 is the index of the first byte. * \return UTF8ERROR_SUCCESS in case of success: All bytes have been deleted. * UTF8ERROR_OUT_OF_RANGE in case of illegal ranges. */ static inline utf8error_t utf8stringbuf_delete_to_end( utf8stringbuf_t this_, int start ); /*! * \brief Inserts a string to a string buffer * * If the resulting string does not fit into the buffer, * the string gets truncated. This function ensures, that * truncation does not split an utf8 code-point in half. * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n+i), n:strlen, i:insertlen * \param this_ The string buffer * \param start Start index within the string buffer, where to start the insertation. 0 is the index of the first byte. * \param insert The 0-terminated inseration string. The buffers of this_ and insert must not overlap! * \return UTF8ERROR_SUCCESS in case of success: All bytes have been inserted. * UTF8ERROR_OUT_OF_RANGE in case of illegal ranges or UTF8ERROR_TRUNCATED in case of truncation. */ static inline utf8error_t utf8stringbuf_insert_str( utf8stringbuf_t this_, int start, const char *insert ); /*! * \brief Inserts a string buffer to a string buffer * * If the resulting string does not fit into the buffer, * the string gets truncated. This function ensures, that * truncation does not split an utf8 code-point in half. * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n+i), n:strlen, i:insertlen * \param this_ The string buffer * \param start Start index within the string buffer, where to start the insertation. 0 is the index of the first byte. * \param insert The inseration string buffer. The buffers of this_ and insert must not overlap! * \return UTF8ERROR_SUCCESS in case of success: All bytes have been inserted. * UTF8ERROR_OUT_OF_RANGE in case of illegal ranges or UTF8ERROR_TRUNCATED in case of truncation. */ static inline utf8error_t utf8stringbuf_insert_buf( utf8stringbuf_t this_, int start, const utf8stringbuf_t insert ); /*! * \brief Splits a string buffer into an ignored first part and the unfilled terminating part * * This function may be useful when building an string using the append functions: * Future append calls are faster because the utf8stringbuf is smaller and you may modify the last * appended part by the replace functions without touching the first part. * Do not call \link utf8stringbuf_join(utf8stringbuf_t) utf8stringbuf_join \endlink after this operation. * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ The string buffer * \return an utf8stringbuf containing only the end */ static inline utf8stringbuf_t utf8stringbuf_get_end( utf8stringbuf_t this_ ); /*! * \brief Splits a string buffer into two substrings * * This function changes the string buffer in a way that every substring is null-terminated. * Therefore, some '\\0' characters have to be inserted. * The resulting substrings are only valid as long as you do not modify the string buffer. * To restore the original content, call \link utf8stringbuf_join(utf8stringbuf_t) utf8stringbuf_join \endlink. * * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ The string buffer * \param start2 Start index within the string buffer, where the second substring shall start. * \return a tuple of several substrings and an error code. * UTF8ERROR_SUCCESS in case of success: All substrings were successfully created. * UTF8ERROR_OUT_OF_RANGE in case of illegal ranges. * UTF8ERROR_TRUNCATED if splitting this string caused the last characters of this string to be dropped. */ extern utf8string2tuple_t utf8stringbuf_split_in_2( utf8stringbuf_t this_, int start2 ); /*! * \brief Splits a string buffer into three substrings * * This function changes the string buffer in a way that every substring is null-terminated. * Therefore, some '\\0' characters have to be inserted. * The resulting substrings are only valid as long as you do not modify the string buffer. * To restore the original content, call \link utf8stringbuf_join(utf8stringbuf_t) utf8stringbuf_join \endlink. * * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ The string buffer * \param start2 Start index within the string buffer, where the second substring shall start. * \param start3 Start index within the string buffer, where the third substring shall start. * \return a tuple of several substrings and an error code. * UTF8ERROR_SUCCESS in case of success: All substrings were successfully created. * UTF8ERROR_OUT_OF_RANGE in case of illegal ranges. * UTF8ERROR_TRUNCATED if splitting this string caused the last characters of this string to be dropped. */ extern utf8string3tuple_t utf8stringbuf_split_in_3( utf8stringbuf_t this_, int start2, int start3 ); /*! * \brief Splits a string buffer into four substrings * * This function changes the string buffer in a way that every substring is null-terminated. * Therefore, some '\\0' characters have to be inserted. * The resulting substrings are only valid as long as you do not modify the string buffer. * To restore the original content, call \link utf8stringbuf_join(utf8stringbuf_t) utf8stringbuf_join \endlink. * * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ The string buffer * \param start2 Start index within the string buffer, where the second substring shall start. * \param start3 Start index within the string buffer, where the third substring shall start. * \param start4 Start index within the string buffer, where the fourth substring shall start. * \return a tuple of several substrings and an error code. * UTF8ERROR_SUCCESS in case of success: All substrings were successfully created. * UTF8ERROR_OUT_OF_RANGE in case of illegal ranges. * UTF8ERROR_TRUNCATED if splitting this string caused the last characters of this string to be dropped. */ extern utf8string4tuple_t utf8stringbuf_split_in_4( utf8stringbuf_t this_, int start2, int start3, int start4 ); /*! * \brief Splits a string buffer into five substrings * * This function changes the string buffer in a way that every substring is null-terminated. * Therefore, some '\\0' characters have to be inserted. * The resulting substrings are only valid as long as you do not modify the string buffer. * To restore the original content, call \link utf8stringbuf_join(utf8stringbuf_t) utf8stringbuf_join \endlink. * * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ The string buffer * \param start2 Start index within the string buffer, where the second substring shall start. * \param start3 Start index within the string buffer, where the third substring shall start. * \param start4 Start index within the string buffer, where the fourth substring shall start. * \param start5 Start index within the string buffer, where the fifth substring shall start. * \return a tuple of several substrings and an error code. * UTF8ERROR_SUCCESS in case of success: All substrings were successfully created. * UTF8ERROR_OUT_OF_RANGE in case of illegal ranges. * UTF8ERROR_TRUNCATED if splitting this string caused the last characters of this string to be dropped. */ extern utf8string5tuple_t utf8stringbuf_split_in_5( utf8stringbuf_t this_, int start2, int start3, int start4, int start5 ); /*! * \brief Joins all substrings within a string buffer that was split before. * * Any non-zero character before the last terminating zero will be joined. * \n * All trailing characters are set to zero. * \note Performance-Rating: [ ]single-operation [ ]fast [ ]medium [x]slow ; Performance-Class: O(n), n:size * \param this_ The string buffer */ extern void utf8stringbuf_join( utf8stringbuf_t this_ ); /*! * \brief Appends a string to a string buffer * * If the source string does not fit into the destination buffer, * the copied string gets truncated. This function ensures, that * truncation does not split an utf8 code-point in half. * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n+a), n:strlen, a:appendlen * \param this_ The destination string buffer * \param appendix The 0-terminated source string. * \return UTF8ERROR_SUCCESS in case of success: All bytes have been copied. * UTF8ERROR_TRUNCATED in case of truncation or * UTF8ERROR_NULL_PARAM if appendix was NULL. */ static inline utf8error_t utf8stringbuf_append_str( utf8stringbuf_t this_, const char *appendix ); /*! * \brief Appends a string buffer to a string buffer * * If the source string does not fit into the destination buffer, * the copied string gets truncated. This function ensures, that * truncation does not split an utf8 code-point in half. * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n+a), n:strlen, a:appendlen * \param this_ The destination string buffer * \param appendix The source string buffer * \return UTF8ERROR_SUCCESS in case of success: All bytes have been copied. * UTF8ERROR_TRUNCATED in case of truncation. */ static inline utf8error_t utf8stringbuf_append_buf( utf8stringbuf_t this_, const utf8stringbuf_t appendix ); /*! * \brief Appends a signed integer to a string buffer in decimal format * * If the integer not fit to the destination buffer, * the copied string gets truncated. This function ensures, that * truncation does not split an utf8 code-point in half. * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ The destination string buffer * \param appendix The integer to be appended * \return UTF8ERROR_SUCCESS in case of success: All bytes have been copied. * UTF8ERROR_TRUNCATED in case of truncation. */ static inline utf8error_t utf8stringbuf_append_int( utf8stringbuf_t this_, const int64_t appendix ); /*! * \brief Appends an unsigned integer to a string buffer in hexadecimal format * * If the integer not fit to the destination buffer, * the copied string gets truncated. This function ensures, that * truncation does not split an utf8 code-point in half. * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ The destination string buffer * \param appendix The integer to be appended * \return UTF8ERROR_SUCCESS in case of success: All bytes have been copied. * UTF8ERROR_TRUNCATED in case of truncation. */ static inline utf8error_t utf8stringbuf_append_hex( utf8stringbuf_t this_, const uint64_t appendix ); /*! * \brief Appends an unicode character to a string buffer * * If the character does not fit to the destination buffer, * the destinatoin buffer is not modified. * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param this_ The destination string buffer * \param appendix The unicode codepoint to be appended * \return UTF8ERROR_SUCCESS in case of success: All bytes have been copied. * UTF8ERROR_TRUNCATED if the character could not be appended. * UTF8ERROR_NOT_A_CODEPOINT if appendix is greater than 0x7fffffff */ extern utf8error_t utf8stringbuf_append_char( utf8stringbuf_t this_, const uint32_t appendix ); /*! * \brief Appends a string of wchar_t to a string buffer * * If the source string does not fit into the destination buffer, * the copied string gets truncated. This function ensures, that * truncation does not split an utf8 code-point in half. * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n+a), n:strlen, a:appendlen * \param this_ The destination string buffer * \param appendix The 0-terminated source string. * \return UTF8ERROR_SUCCESS in case of success: All bytes have been copied. * UTF8ERROR_TRUNCATED in case of truncation or * UTF8ERROR_NULL_PARAM if appendix was NULL or * UTF8ERROR_NOT_A_CODEPOINT if one or more characters of appendix are greater than 0x7fffffff */ extern utf8error_t utf8stringbuf_append_wstr( utf8stringbuf_t this_, const wchar_t *appendix ); #ifdef __cplusplus } #endif #include "util/string/utf8stringbuf.inl" #endif /*UTF8STRINGBUF_H_*/ /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/include/util/string/utf8stringbuf.inl000066400000000000000000000415241415120503000271670ustar00rootroot00000000000000/* File: utf8stringbuf.inl; Copyright and License: see below */ /*! * \file utf8stringbuf.inl * * \note License: Use this code according to the license: Apache 2.0. * \author Copyright 2012-2021 A.Warnke; Email-contact: utf8stringbuf-at-andreaswarnke-dot-de */ /*#ifndef UTF8STRINGBUF_INL_*/ /*#define UTF8STRINGBUF_INL_*/ #include "util/string/utf8codepoint.h" #include #include #include #ifdef __cplusplus extern "C" { #endif /*! * \enum utf8stringbuf_bool_enum * \private */ /* enumeration for true and false or success and failure */ enum utf8stringbuf_bool_enum {UTF8STRINGBUF_FALSE=0, UTF8STRINGBUF_TRUE=1,}; /*! * \enum utf8stringbuf_search_enum * \private */ /* enumeration for search pattern not found */ enum utf8stringbuf_search_enum {UTF8STRINGBUF_NOT_FOUND=-1,}; /*! * \var utf8stringbuf_private_format_signed_64_bit_int * \private */ /* a character array containing nothing but a single zero */ extern const char *utf8stringbuf_private_format_signed_64_bit_int; /*! * \var utf8stringbuf_private_format_64_bit_hex * \private */ /* a character array containing nothing but a single zero */ extern const char *utf8stringbuf_private_format_64_bit_hex; /*! * \var utf8stringbuf_private_empty_buf * \private */ /* a character array containing nothing but a single zero */ extern char utf8stringbuf_private_empty_buf[1]; /*! * \fn utf8_string_buf_private_make_null_termination( utf8stringbuf_t this_ ) * \private * \return new, truncated length of the string */ /* function to make a buffer null terminated while ensuring that all utf8 character sequences are valid */ extern unsigned int utf8_string_buf_private_make_null_termination( utf8stringbuf_t this_ ); /*! * \fn utf8_string_buf_private_replace_region_by_str( utf8stringbuf_t this_, unsigned int this_Length, int start, int length, const char *replacement ) * \private */ /* function to replace a region within a string buffer, the original string length must be provided in this_Length */ extern utf8error_t utf8_string_buf_private_replace_region_by_str( utf8stringbuf_t this_, unsigned int this_Length, int start, int length, const char *replacement ); static inline utf8stringbuf_t utf8stringbuf( char *that ) { utf8stringbuf_t result; if ( that == NULL ) { result.size = 1; result.buf = utf8stringbuf_private_empty_buf; } else { result.size = strlen( that )+1; result.buf = that; } return result; } static inline utf8stringbuf_t utf8stringbuf_init( size_t size, char *buf ) { utf8stringbuf_t result; if (( buf == NULL )||(size==0)) { result.size = 1; result.buf = utf8stringbuf_private_empty_buf; } else { result.size = size; result.buf = buf; } return result; } static inline void utf8stringbuf_clear( utf8stringbuf_t this_ ) { memset( this_.buf, '\0', this_.size ); } static inline char* utf8stringbuf_get_string( const utf8stringbuf_t this_ ) { return this_.buf; } static inline size_t utf8stringbuf_get_size( const utf8stringbuf_t this_ ) { return this_.size; } static inline unsigned int utf8stringbuf_get_length( const utf8stringbuf_t this_ ) { unsigned int lenResult; lenResult = strlen( this_.buf ); return lenResult; } static inline int utf8stringbuf_equals_str( const utf8stringbuf_t this_, const char *that ) { int cmpResult = -1; if ( that != NULL ) { cmpResult = strcmp( this_.buf, that ); } return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE; } static inline int utf8stringbuf_equals_buf( const utf8stringbuf_t this_, const utf8stringbuf_t that ) { int cmpResult = -1; cmpResult = strcmp( this_.buf, that.buf ); return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE; } static inline int utf8stringbuf_equals_region_str( const utf8stringbuf_t this_, int start, const char *that ) { int cmpResult = -1; if ( that != NULL ) { int thisLen = strlen(this_.buf); int thatLen = strlen(that); unsigned int end = ((unsigned int)start) + ((unsigned int)thatLen); if (( 0 <= start )&&( end <= thisLen )) { cmpResult = memcmp( &(this_.buf[start]), that, thatLen ); } } return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE; } static inline int utf8stringbuf_equals_region_buf( const utf8stringbuf_t this_, int start, const utf8stringbuf_t that ) { int cmpResult = -1; int thisLen = strlen(this_.buf); int thatLen = strlen(that.buf); unsigned int end = ((unsigned int)start) + ((unsigned int)thatLen); if (( 0 <= start )&&( end <= thisLen )) { cmpResult = memcmp( &(this_.buf[start]), that.buf, thatLen ); } return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE; } static inline int utf8stringbuf_find_first_buf( const utf8stringbuf_t this_, const utf8stringbuf_t pattern ) { int result = UTF8STRINGBUF_NOT_FOUND; const char *ptrResult = strstr( this_.buf, pattern.buf ); if ( ptrResult != NULL ) { result = (int) (ptrResult - this_.buf); } return result; } static inline int utf8stringbuf_starts_with_str( const utf8stringbuf_t this_, const char *that ) { int cmpResult = -1; if ( that != NULL ) { unsigned int thatLen = strlen( that ); cmpResult = strncmp( this_.buf, that, thatLen ); } return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE; } static inline int utf8stringbuf_starts_with_buf( const utf8stringbuf_t this_, const utf8stringbuf_t that ) { int cmpResult = -1; unsigned int thatLen = strlen( that.buf ); cmpResult = strncmp( this_.buf, that.buf, thatLen ); return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE; } static inline int utf8stringbuf_ends_with_str( const utf8stringbuf_t this_, const char *that ) { int cmpResult = -1; if ( that != NULL ) { unsigned int thatLen = strlen( that ); unsigned int thisLen = strlen( this_.buf ); if ( thatLen <= thisLen ) { cmpResult = memcmp( &(this_.buf[thisLen-thatLen]), that, thatLen ); } } return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE; } static inline int utf8stringbuf_ends_with_buf( const utf8stringbuf_t this_, const utf8stringbuf_t that ) { int cmpResult = -1; unsigned int thatLen = strlen( that.buf ); unsigned int thisLen = strlen( this_.buf ); if ( thatLen <= thisLen ) { cmpResult = memcmp( &(this_.buf[thisLen-thatLen]), that.buf, thatLen ); } return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE; } static inline int utf8stringbuf_find_first_str( const utf8stringbuf_t this_, const char *pattern ) { int result = UTF8STRINGBUF_NOT_FOUND; if ( pattern != NULL ) { const char *ptrResult = strstr( this_.buf, pattern ); if ( ptrResult != NULL ) { result = (int) (ptrResult - this_.buf); } } return result; } static inline int utf8stringbuf_find_last_buf( const utf8stringbuf_t this_, const utf8stringbuf_t pattern ) { int result = UTF8STRINGBUF_NOT_FOUND; int thisLen = utf8stringbuf_get_length( this_ ); int patternLen = strlen( pattern.buf ); if ( patternLen <= thisLen ) { for ( int probeIdx = (thisLen-patternLen); probeIdx >= 0; probeIdx --) { if ( 0 == memcmp( &(this_.buf[probeIdx]), pattern.buf, patternLen )) { /* last occurrence found! */ result = probeIdx; break; } } } return result; } static inline int utf8stringbuf_find_last_str( const utf8stringbuf_t this_, const char *pattern ) { int result = UTF8STRINGBUF_NOT_FOUND; if ( pattern != NULL ) { int thisLen = utf8stringbuf_get_length( this_ ); int patternLen = strlen( pattern ); if ( patternLen <= thisLen ) { for ( int probeIdx = (thisLen-patternLen); probeIdx >= 0; probeIdx --) { if ( 0 == memcmp( &(this_.buf[probeIdx]), pattern, patternLen )) { /* last occurrence found! */ result = probeIdx; break; } } } } return result; } static inline int utf8stringbuf_find_next_buf( const utf8stringbuf_t this_, const utf8stringbuf_t pattern, int start_index ) { int result = UTF8STRINGBUF_NOT_FOUND; if (( start_index >= 0 ) && ( start_index < this_.size )) { const char *ptrResult = strstr( &(this_.buf[start_index]), pattern.buf ); if ( ptrResult != NULL ) { result = (int) (ptrResult - this_.buf); } } return result; } static inline int utf8stringbuf_find_next_str( const utf8stringbuf_t this_, const char *pattern, int start_index ) { int result = UTF8STRINGBUF_NOT_FOUND; if (( pattern != NULL ) && ( start_index >= 0 ) && ( start_index < this_.size )) { const char *ptrResult = strstr( &(this_.buf[start_index]), pattern ); if ( ptrResult != NULL ) { result = (int) (ptrResult - this_.buf); } } return result; } static inline utf8codepoint_t utf8stringbuf_get_char_at( const utf8stringbuf_t this_, unsigned int byte_index ) { utf8codepoint_t result = UTF8CODEPOINT_INVAL_CHAR; if ( byte_index < this_.size ) { result = utf8codepoint_init( &(this_.buf[byte_index]), this_.size-byte_index ); } return result; } static inline utf8error_t utf8stringbuf_copy_buf( utf8stringbuf_t this_, const utf8stringbuf_t original ) { utf8error_t complete = UTF8ERROR_SUCCESS; #if __GNUC__ >= 8 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstringop-truncation" #endif strncpy( this_.buf, original.buf, this_.size ); #if __GNUC__ >= 8 #pragma GCC diagnostic pop #endif if ( this_.buf[this_.size-1] != '\0' ) { utf8_string_buf_private_make_null_termination( this_ ); complete = UTF8ERROR_TRUNCATED; } return complete; } static inline utf8error_t utf8stringbuf_copy_str( utf8stringbuf_t this_, const char *original ) { utf8error_t complete = UTF8ERROR_SUCCESS; if ( original == NULL ) { this_.buf[0] = '\0'; complete = UTF8ERROR_NULL_PARAM; } else { #if __GNUC__ >= 8 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstringop-truncation" #endif strncpy( this_.buf, original, this_.size ); #if __GNUC__ >= 8 #pragma GCC diagnostic pop #endif if ( this_.buf[this_.size-1] != '\0' ) { utf8_string_buf_private_make_null_termination( this_ ); complete = UTF8ERROR_TRUNCATED; } } return complete; } static inline utf8error_t utf8stringbuf_replace_all_str_by_str( const utf8stringbuf_t this_, const char *pattern, const char *replacement ) { utf8error_t result = UTF8ERROR_NULL_PARAM; if ( pattern != NULL ) { const char *const patterns_and_replacements[][2] = { { pattern, replacement }, { NULL, NULL } }; result = utf8stringbuf_replace_all( this_, &patterns_and_replacements ); } return result; } static inline utf8error_t utf8stringbuf_replace_all_buf_by_buf( const utf8stringbuf_t this_, const utf8stringbuf_t pattern, const utf8stringbuf_t replacement ) { const char *const patterns_and_replacements[][2] = { { pattern.buf, replacement.buf }, { NULL, NULL } }; return utf8stringbuf_replace_all( this_, &patterns_and_replacements ); } static inline utf8error_t utf8stringbuf_append_str( utf8stringbuf_t this_, const char *appendix ) { utf8error_t result = UTF8ERROR_SUCCESS; if ( appendix == NULL ) { result = UTF8ERROR_NULL_PARAM; } else { const size_t start = strlen( this_.buf ); const size_t appLen = strlen( appendix ); if ( start + appLen < this_.size ) { memcpy( &(this_.buf[start]), appendix, appLen+1 ); } else { const size_t appPartLen = (this_.size-start)-1; if (( appPartLen > 0 )&&( appPartLen <= PTRDIFF_MAX )) /* check to suppress compiler warning */ { memcpy( &(this_.buf[start]), appendix, appPartLen ); } else { /* buffer full */ } utf8_string_buf_private_make_null_termination( this_ ); result = UTF8ERROR_TRUNCATED; } /* For the standard use case, strlen and memcpy are faster than strncpy; strncat does not provide an error */ } return result; } static inline utf8error_t utf8stringbuf_append_buf( utf8stringbuf_t this_, const utf8stringbuf_t appendix ) { utf8error_t result = UTF8ERROR_SUCCESS; const size_t start = strlen( this_.buf ); const size_t appLen = strlen( appendix.buf ); if ( start + appLen < this_.size ) { memcpy( &(this_.buf[start]), appendix.buf, appLen+1 ); } else { const size_t appPartLen = (this_.size-start)-1; if (( appPartLen > 0 )&&( appPartLen <= PTRDIFF_MAX )) /* check to suppress compiler warning */ { memcpy( &(this_.buf[start]), appendix.buf, appPartLen ); } else { /* buffer full */ } utf8_string_buf_private_make_null_termination( this_ ); result = UTF8ERROR_TRUNCATED; } /* For the standard use case, strlen and memcpy are faster than strncpy; strncat does not provide an error */ return result; } static inline utf8error_t utf8stringbuf_append_int( utf8stringbuf_t this_, const int64_t appendix ) { char numberStr[21]; /* this is sufficient for signed 64 bit integers: -9223372036854775806 */ /* Note: snprintf is not available on every OS */ sprintf( numberStr, utf8stringbuf_private_format_signed_64_bit_int, appendix ); return utf8stringbuf_append_str( this_, numberStr ); } static inline utf8error_t utf8stringbuf_append_hex( utf8stringbuf_t this_, const uint64_t appendix ) { char numberStr[17]; /* this is sufficient for 64 bit integers */ /* Note: snprintf is not available on every OS */ sprintf( numberStr, utf8stringbuf_private_format_64_bit_hex, appendix ); return utf8stringbuf_append_str( this_, numberStr ); } static inline utf8error_t utf8stringbuf_replace_region_by_str( utf8stringbuf_t this_, int start, int length, const char *replacement ) { unsigned int this_Length = utf8stringbuf_get_length( this_ ); return utf8_string_buf_private_replace_region_by_str( this_, this_Length, start, length, replacement ); } static inline utf8error_t utf8stringbuf_replace_region_by_buf( utf8stringbuf_t this_, int start, int length, const utf8stringbuf_t replacement ) { unsigned int this_Length = utf8stringbuf_get_length( this_ ); return utf8_string_buf_private_replace_region_by_str( this_, this_Length, start, length, replacement.buf ); } static inline utf8error_t utf8stringbuf_delete( utf8stringbuf_t this_, int start, int length ) { unsigned int this_Length = utf8stringbuf_get_length( this_ ); return utf8_string_buf_private_replace_region_by_str( this_, this_Length, start, length, NULL ); } static inline utf8error_t utf8stringbuf_delete_from_end( utf8stringbuf_t this_, int length ) { int this_Length = utf8stringbuf_get_length( this_ ); return utf8_string_buf_private_replace_region_by_str( this_, this_Length, this_Length-length, length, NULL ); } static inline utf8error_t utf8stringbuf_delete_to_end( utf8stringbuf_t this_, int start ) { int this_Length = utf8stringbuf_get_length( this_ ); return utf8_string_buf_private_replace_region_by_str( this_, this_Length, start, this_Length-start, NULL ); } static inline utf8error_t utf8stringbuf_insert_str( utf8stringbuf_t this_, int start, const char *insert ) { unsigned int this_Length = utf8stringbuf_get_length( this_ ); return utf8_string_buf_private_replace_region_by_str( this_, this_Length, start, 0, insert ); } static inline utf8error_t utf8stringbuf_insert_buf( utf8stringbuf_t this_, int start, const utf8stringbuf_t insert ) { unsigned int this_Length = utf8stringbuf_get_length( this_ ); return utf8_string_buf_private_replace_region_by_str( this_, this_Length, start, 0, insert.buf ); } static inline utf8stringbuf_t utf8stringbuf_get_end( utf8stringbuf_t this_ ) { unsigned int this_Length = utf8stringbuf_get_length( this_ ); return utf8stringbuf_init( this_.size-this_Length, &(this_.buf[this_Length]) ); } #ifdef __cplusplus } #endif /*#endif*/ /*UTF8STRINGBUF_INL_*/ /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/include/util/string/utf8stringntuple.h000066400000000000000000000100631415120503000273610ustar00rootroot00000000000000/* File: utf8stringntuple.h; Copyright and License: see below */ #ifndef UTF8STRINGNTUPLE_H_ #define UTF8STRINGNTUPLE_H_ /*! * \file utf8stringntuple.h * \brief utf8stringNTuple provides types for pairs, triples and n-tuples of c-strings. * * \note License: Use this code according to the license: Apache 2.0. * \author Copyright 2012-2021 A.Warnke; Email-contact: utf8stringbuf-at-andreaswarnke-dot-de */ #include "util/string/utf8error.h" #ifdef __cplusplus extern "C" { #endif /*! * \brief A pair of standard utf8-encoded C-Strings. */ struct utf8string2tuple_struct { char* first; /*!< pointer to the first 0-terminated and utf8-encoded string */ char* second; /*!< pointer to the second 0-terminated and utf8-encoded string */ utf8error_t error; /*!< the error code of the split function. See \link utf8stringbuf_split_in_2( utf8stringbuf_t, int ) utf8stringbuf_split_in_2 \endlink. */ }; /*! * \typedef utf8string2tuple_t * \brief A pair of standard utf8-encoded C-Strings. */ typedef struct utf8string2tuple_struct utf8string2tuple_t; /*! * \brief A triple of standard utf8-encoded C-Strings. */ struct utf8string3tuple_struct { char* first; /*!< pointer to the first 0-terminated and utf8-encoded string */ char* second; /*!< pointer to the second 0-terminated and utf8-encoded string */ char* third; /*!< pointer to the third 0-terminated and utf8-encoded string */ utf8error_t error; /*!< the error code of the split function. See \link utf8stringbuf_split_in_3( utf8stringbuf_t, int, int ) utf8stringbuf_split_in_3 \endlink. */ }; /*! * \typedef utf8string3tuple_t * \brief A triple of standard utf8-encoded C-Strings. */ typedef struct utf8string3tuple_struct utf8string3tuple_t; /*! * \brief A quadruple of standard utf8-encoded C-Strings. */ struct utf8string4tuple_struct { char* first; /*!< pointer to the first 0-terminated and utf8-encoded string */ char* second; /*!< pointer to the second 0-terminated and utf8-encoded string */ char* third; /*!< pointer to the third 0-terminated and utf8-encoded string */ char* fourth; /*!< pointer to the fourth 0-terminated and utf8-encoded string */ utf8error_t error; /*!< the error code of the split function. See \link utf8stringbuf_split_in_4( utf8stringbuf_t, int, int, int ) utf8stringbuf_split_in_4 \endlink. */ }; /*! * \typedef utf8string4tuple_t * \brief A quadruple of standard utf8-encoded C-Strings. */ typedef struct utf8string4tuple_struct utf8string4tuple_t; /*! * \brief A quintuple of standard utf8-encoded C-Strings. */ struct utf8string5tuple_struct { char* first; /*!< pointer to the first 0-terminated and utf8-encoded string */ char* second; /*!< pointer to the second 0-terminated and utf8-encoded string */ char* third; /*!< pointer to the third 0-terminated and utf8-encoded string */ char* fourth; /*!< pointer to the fourth 0-terminated and utf8-encoded string */ char* fifth; /*!< pointer to the fifth 0-terminated and utf8-encoded string */ utf8error_t error; /*!< the error code of the split function. See \link utf8stringbuf_split_in_5( utf8stringbuf_t, int, int, int, int ) utf8stringbuf_split_in_5 \endlink. */ }; /*! * \typedef utf8string5tuple_t * \brief A quintuple of standard utf8-encoded C-Strings. */ typedef struct utf8string5tuple_struct utf8string5tuple_t; #ifdef __cplusplus } #endif #endif /*UTF8STRINGNTUPLE_H_*/ /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/include/util/string/utf8stringview.h000066400000000000000000000125471415120503000270350ustar00rootroot00000000000000/* File: utf8stringview.h; Copyright and License: see below */ #ifndef UTF8STRINGVIEW_H_ #define UTF8STRINGVIEW_H_ /*! * \file utf8stringview.h * \brief utf8stringview provides functions to search and compare non-terminated char sequences. * * utf8stringview provides a struct consisting of * \li a pointer to an character array (non null-terminated) and * \li the length of the array. * * \note License: Use this code according to the license: Apache 2.0. * \author Copyright 2021-2021 A.Warnke; Email-contact: utf8stringbuf-at-andreaswarnke-dot-de */ #include "util/string/utf8codepoint.h" #include "util/string/utf8error.h" #include #include #include #include #ifdef __cplusplus extern "C" { #endif /*! * \def UTF8STRINGVIEW(start_param,length_param) * \brief Macro to facilitate static initialisation of an utf8stringview_t * * \n * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) */ #define UTF8STRINGVIEW(start_param,length_param) (utf8stringview_t){.start=start_param,.length=length_param} /*! * \def UTF8STRINGVIEW_STR(string_param) * \brief Macro to facilitate static initialisation of an utf8stringview_t from a null-terminated string * * \n * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) */ #define UTF8STRINGVIEW_STR(string_param) (utf8stringview_t){.start=string_param,.length=(string_param==NULL)?0:strlen(string_param)} /*! * \def UTF8STRINGVIEW_NULL * \brief Macro to facilitate static initialisation of an utf8stringview_t * * \n * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) */ #define UTF8STRINGVIEW_NULL (utf8stringview_t){.start=NULL,.length=0} /*! * \brief A string view is a pair of start pointer and length in bytes. * * \invariant if length!=0 then start!=NULL. */ struct utf8stringview_struct { const char* start; size_t length; }; /*! * \typedef utf8stringview_t * \brief The string view object * * It represents a non-null terminated immutable sequence of utf8 characters. */ typedef struct utf8stringview_struct utf8stringview_t; /*! * \brief utf8stringview_init returns a stringview struct * * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param start pointer to a byte array. * \param length length of the byte array. In case start is NULL, length must be 0. * \return A valid utf8stringview_t struct. */ static inline utf8stringview_t utf8stringview_init( const char* start, size_t length ); /*! * \brief utf8stringview_init returns a stringview struct * * \note Performance-Rating: [ ]single-operation [x]fast [ ]medium [ ]slow ; Performance-Class: O(n), n:strlen * \param cstring a 0-terminated string. * \return A valid utf8stringview_t struct. */ static inline utf8stringview_t utf8stringview_init_str( const char* cstring ); /*! * \brief utf8stringview_init returns a stringview struct * * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param string a pointer to a character array. NULL is not allowed. * \param start_idx the start index from where the stringview shall start. * \param length length of the stringview. * \return A valid utf8stringview_t struct. */ static inline utf8stringview_t utf8stringview_init_region( const char* string, size_t start_idx, size_t length ); /*! * \brief Gets the pointer to the start of the character array * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ The string view object * \return Pointer to the start of the character array */ static inline const char* utf8stringview_get_start( const utf8stringview_t this_ ); /*! * \brief Gets the length of the character array * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ The string view object * \return Length of the character array. */ static inline size_t utf8stringview_get_length( const utf8stringview_t this_ ); /*! * \brief Searches a pattern within a stringview * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n*m), n:strlen, m:patternlen * \param this_ The 0-terminated string within which to search * \param pattern The 0-terminated string to search * \return Index of the first occurrence within the stringview. * -1 if there is no match. */ static inline int utf8stringview_find_first_str( const utf8stringview_t this_, const char *pattern ); #ifdef __cplusplus } #endif #include "util/string/utf8stringview.inl" #endif /*UTF8STRINGVIEW_H_*/ /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/include/util/string/utf8stringview.inl000066400000000000000000000044731415120503000273670ustar00rootroot00000000000000/* File: utf8stringview.inl; Copyright and License: see below */ /*! * \file utf8stringview.inl * * \note License: Use this code according to the license: Apache 2.0. * \author Copyright 2021-2021 A.Warnke; Email-contact: utf8stringbuf-at-andreaswarnke-dot-de */ #ifdef __cplusplus extern "C" { #endif static inline utf8stringview_t utf8stringview_init( const char* start, size_t length ) { return (utf8stringview_t){.start=start,.length=length}; } static inline utf8stringview_t utf8stringview_init_str( const char* cstring ) { return (utf8stringview_t){.start=cstring,.length=(cstring==NULL)?0:strlen(cstring)}; } static inline utf8stringview_t utf8stringview_init_region( const char* string, size_t start_idx, size_t length ) { return (utf8stringview_t){.start=(string+start_idx),.length=(string==NULL)?0:length}; } static inline const char* utf8stringview_get_start( const utf8stringview_t this_ ) { return this_.start; } static inline size_t utf8stringview_get_length( const utf8stringview_t this_ ) { return this_.length; } static inline int utf8stringview_find_first_str( const utf8stringview_t this_, const char *pattern ) { int result = -1; if (( pattern != NULL )&&( this_.start != NULL )) { const size_t pattern_len = strlen( pattern ); if ( pattern_len != 0 ) { const char *const end = this_.start + this_.length; for ( const char* pos = this_.start; ( pos + pattern_len <= end )&&( result == -1 ); pos ++ ) { if ( 0 == memcmp( pos, pattern, pattern_len ) ) { result = ( pos - this_.start ); } } } } return result; } #ifdef __cplusplus } #endif /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/include/util/string/utf8stringviewiterator.h000066400000000000000000000103231415120503000305750ustar00rootroot00000000000000/* File: utf8stringviewiterator.h; Copyright and License: see below */ #ifndef UTF8STRINGVIEWITERATOR_H #define UTF8STRINGVIEWITERATOR_H /* public file for the doxygen documentation: */ /*! * \file * \brief Iterates over a character-separated list of a stringview */ #include "util/string/utf8string.h" #include "util/string/utf8stringview.h" #include /*! * \brief all data attributes needed for the character-separated iterator functions * * The iterator works similar to the J2SE-ListIterator, hibernate-query-Iterator and QT-QListIterator: * while ( hasNext() ) { element = next() }; */ struct utf8stringviewiterator_struct { bool has_next; /*!< true if there is a next stringview-element, even in case of a possibly empty end */ bool next_is_end; /*!< true if next stringview-element is the last one */ utf8stringview_t next; /*!< the next stringview-element */ utf8stringview_t remaining; /*!< remaining part of the element_list which is not yet processed */ utf8string_t separator; /*!< character-sequence that separates the stringviews */ }; typedef struct utf8stringviewiterator_struct utf8stringviewiterator_t; /*! * \brief initializes the utf8stringviewiterator_t struct * * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n*m), n:element_list_len, m:separator_len * \param this_ pointer to own object attributes * \param element_list character-separated list of stringviews * \param separator character-sequence that separates the stringviews to retrieve; length must not be 0 */ static inline void utf8stringviewiterator_init ( utf8stringviewiterator_t *this_, utf8stringview_t element_list, utf8string_t separator ); /*! * \brief destroys the utf8stringviewiterator_t struct * * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ pointer to own object attributes */ static inline void utf8stringviewiterator_destroy ( utf8stringviewiterator_t *this_ ); /*! * \brief checks if a next stringview-element exists in the iterator - does not modify the iterator state * * Note that even an empty string contains one empty stringview-element * * \note Performance-Rating: [x]single-operation [ ]fast [ ]medium [ ]slow ; Performance-Class: O(1) * \param this_ pointer to own object attributes * \return true if there is a next element in the iterator */ static inline bool utf8stringviewiterator_has_next ( const utf8stringviewiterator_t *this_ ); /*! * \brief reads the next stringview-element from the character-separated list of stringviews. * * Internally advances to the stringview-element after next. * * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n*m), n:remaining_len, m:separator_len * \param this_ pointer to own object attributes * \return the next stringview-element parsed from the character-separated list of stringviews, * in case there is no next stringview-element, utf8stringview_get_length() of the result is 0 */ static inline utf8stringview_t utf8stringviewiterator_next ( utf8stringviewiterator_t *this_ ); /*! * \brief moves the iterator to the next stringview-element, updates (*this_).next and (*this_).has_next * * \note Performance-Rating: [ ]single-operation [ ]fast [x]medium [ ]slow ; Performance-Class: O(n*m), n:remaining_len, m:separator_len * \param this_ pointer to own object attributes */ static inline void utf8stringviewiterator_private_step_to_next ( utf8stringviewiterator_t *this_ ); #include "utf8stringviewiterator.inl" #endif /* UTF8STRINGVIEWITERATOR_H */ /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/include/util/string/utf8stringviewiterator.inl000066400000000000000000000054061415120503000311360ustar00rootroot00000000000000/* File: utf8stringviewiterator.inl; Copyright and License: see below */ static inline void utf8stringviewiterator_init ( utf8stringviewiterator_t *this_, utf8stringview_t element_list, utf8string_t separator ) { (*this_).remaining = element_list; (*this_).separator = separator; (*this_).next_is_end = false; (*this_).has_next = true; utf8stringviewiterator_private_step_to_next( this_ ); } static inline void utf8stringviewiterator_destroy ( utf8stringviewiterator_t *this_ ) { } static inline bool utf8stringviewiterator_has_next ( const utf8stringviewiterator_t *this_ ) { return (*this_).has_next; } static inline utf8stringview_t utf8stringviewiterator_next ( utf8stringviewiterator_t *this_ ) { utf8stringview_t result = (*this_).next; utf8stringviewiterator_private_step_to_next( this_ ); return result; } static inline void utf8stringviewiterator_private_step_to_next ( utf8stringviewiterator_t *this_ ) { const size_t remaining_len = utf8stringview_get_length( (*this_).remaining ); if ( (*this_).next_is_end ) { (*this_).has_next = false; (*this_).next = UTF8STRINGVIEW_NULL; } else { const int next_sep = utf8stringview_find_first_str( (*this_).remaining, (*this_).separator ); if ( next_sep == -1 ) { (*this_).next_is_end = true; (*this_).next = (*this_).remaining; (*this_).remaining = UTF8STRINGVIEW_NULL; } else { const size_t separator_len = utf8string_get_length( (*this_).separator ); (*this_).next = utf8stringview_init_region( utf8stringview_get_start( (*this_).remaining ), 0, next_sep ); (*this_).remaining = utf8stringview_init_region( utf8stringview_get_start( (*this_).remaining ), (next_sep + separator_len ), (remaining_len - next_sep - separator_len ) ); } } } /* Copyright 2021-2021 Andreas Warnke Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/source/000077500000000000000000000000001415120503000212355ustar00rootroot00000000000000crystal-facet-uml-1.34.1/utf8stringbuf/source/util/000077500000000000000000000000001415120503000222125ustar00rootroot00000000000000crystal-facet-uml-1.34.1/utf8stringbuf/source/util/string/000077500000000000000000000000001415120503000235205ustar00rootroot00000000000000crystal-facet-uml-1.34.1/utf8stringbuf/source/util/string/utf8codepoint.c000066400000000000000000000020741415120503000264620ustar00rootroot00000000000000/* File: utf8codepoint.c; Copyright and License: see below */ /*! * \file utf8codepoint.c * * \note License: Use this code according to the license: Apache 2.0. * \author Copyright 2012-2021 A.Warnke; Email-contact: utf8stringbuf-at-andreaswarnke-dot-de */ #include "util/string/utf8codepoint.h" /* UTF8CODEPOINT_INVAL_CHAR is a constant, may be stored in a read-only memory page */ const utf8codepoint_t UTF8CODEPOINT_INVAL_CHAR = { UTF8CODEPOINT_INVALID_LEN, 0x0, }; /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/source/util/string/utf8stringbuf.c000066400000000000000000000701601415120503000265020ustar00rootroot00000000000000/* File: utf8stringbuf.c; Copyright and License: see below */ /*! * \file utf8stringbuf.c * * \note License: Use this code according to the license: Apache 2.0. * \author Copyright 2012-2021 A.Warnke; Email-contact: utf8stringbuf-at-andreaswarnke-dot-de */ #include #include "util/string/utf8stringbuf.h" /* utf8stringbuf_private_empty_buf is constantly 0, but may be overwritten by a 0 - therefore stored in a read-writeable memory page */ char utf8stringbuf_private_empty_buf[1] = ""; const char *utf8stringbuf_private_format_signed_64_bit_int = "%" PRIi64; const char *utf8stringbuf_private_format_64_bit_hex = "%" PRIx64; /*! * \fn utf8stringbuf_private_write_char( char *destination, unsigned int max_size, const uint32_t source ) * \private */ /* function to write a code point as utf8, returns the number of bytes written and an error code */ static inline utf8error_t utf8stringbuf_private_write_char( char *destination, unsigned int max_size, const uint32_t source, int *out_len ); /* utf8 sequences longer or equal 2 bytes start with a byte with 2 highest bits set: 0xc0 */ /* utf8 sequences longer or equal 3 bytes start with a byte with 3 highest bits set: 0xe0 */ /* utf8 sequences equal 4 bytes start with a byte with 4 highest bits set: 0xf0 */ static const unsigned char utf8stringbuf_private_pattern_to_detect_half_utf8_sequences[5] = { 0, 0, 0xc0, 0xe0, 0xf0 }; /* Note: There is some magic in the design of utf8 which makes the implementation of this function quite short */ unsigned int utf8_string_buf_private_make_null_termination( utf8stringbuf_t this_ ) { unsigned int truncatedLength; int clearAtEnd = 1; for ( int searchBackwards = 2; searchBackwards <= 4; searchBackwards ++ ) { if ( searchBackwards > this_.size ) { break; } const char pattern = utf8stringbuf_private_pattern_to_detect_half_utf8_sequences[searchBackwards]; if ( ( this_.buf[this_.size-searchBackwards] & pattern ) == pattern ) { clearAtEnd = searchBackwards; break; } } truncatedLength = this_.size - clearAtEnd; /* this_.buf[truncatedLength] = '\0'; */ /* Note: some functions like splitIn2 require complete zeroed trailings */ memset( &(this_.buf[truncatedLength]), '\0', clearAtEnd ); return truncatedLength; } utf8error_t utf8stringbuf_copy_region_from_buf( utf8stringbuf_t this_, const utf8stringbuf_t that, int start, int length ) { utf8error_t result; if (( start < 0 ) || ( length < 0 )) { this_.buf[0] = '\0'; result = UTF8ERROR_OUT_OF_RANGE; } else { int thatLen = utf8stringbuf_get_length( that ); if ( start > thatLen ) { this_.buf[0] = '\0'; result = UTF8ERROR_OUT_OF_RANGE; } else if ( start+length > thatLen ) { strncpy( this_.buf, &(that.buf[start]), this_.size ); utf8_string_buf_private_make_null_termination( this_ ); result = UTF8ERROR_OUT_OF_RANGE; } else { if ( length >= this_.size ) { memcpy( this_.buf, &(that.buf[start]), this_.size-1); utf8_string_buf_private_make_null_termination( this_ ); result = UTF8ERROR_TRUNCATED; } else { memcpy( this_.buf, &(that.buf[start]), length ); this_.buf[length] = '\0'; result = UTF8ERROR_SUCCESS; } } } return result; } utf8error_t utf8stringbuf_copy_region_from_str( utf8stringbuf_t this_, const char *that, int start, int length ) { utf8error_t result; if (( start < 0 ) || ( length < 0 )) { this_.buf[0] = '\0'; result = UTF8ERROR_OUT_OF_RANGE; } else if ( that == NULL ) { this_.buf[0] = '\0'; result = UTF8ERROR_NULL_PARAM; } else { int thatLen = strlen( that ); if ( start > thatLen ) { this_.buf[0] = '\0'; result = UTF8ERROR_OUT_OF_RANGE; } else if ( start+length > thatLen ) { strncpy( this_.buf, &(that[start]), this_.size ); utf8_string_buf_private_make_null_termination( this_ ); result = UTF8ERROR_OUT_OF_RANGE; } else { if ( length >= this_.size ) { memcpy( this_.buf, &(that[start]), this_.size-1); utf8_string_buf_private_make_null_termination( this_ ); result = UTF8ERROR_TRUNCATED; } else { memcpy( this_.buf, &(that[start]), length ); this_.buf[length] = '\0'; result = UTF8ERROR_SUCCESS; } } } return result; } utf8error_t utf8stringbuf_append_char( utf8stringbuf_t this_, const uint32_t appendix ) { utf8error_t result; const unsigned int start = utf8stringbuf_get_length( this_ ); int appendLen; result = utf8stringbuf_private_write_char( &(this_.buf[start]), this_.size - start - 1, appendix, &appendLen ); if ( result == UTF8ERROR_SUCCESS ) { this_.buf[start+appendLen] = '\0'; } return result; } utf8error_t utf8stringbuf_append_wstr( utf8stringbuf_t this_, const wchar_t *appendix ) { utf8error_t result = UTF8ERROR_NULL_PARAM; if ( appendix != NULL ) { unsigned int start = utf8stringbuf_get_length( this_ ); result = UTF8ERROR_SUCCESS; for( ; appendix[0]!=L'\0'; appendix = &(appendix[1]) ) { int appendLen; result |= utf8stringbuf_private_write_char( &(this_.buf[start]), this_.size - start - 1, appendix[0], &appendLen ); if ( result != UTF8ERROR_SUCCESS ) { if ( ( result & UTF8ERROR_TRUNCATED ) != 0 ) { break; } } start = start + appendLen; } this_.buf[start] = '\0'; } return result; } static inline utf8error_t utf8stringbuf_private_write_char( char *destination, unsigned int max_size, const uint32_t source, int *out_len ) { *out_len = 0; utf8error_t result = UTF8ERROR_TRUNCATED; if ( source <= 0x7ff ) { if ( source <= 0x7f ) { /* 1 byte character */ /* check if there is enough space for the character */ if ( max_size >= 1 ) { destination[0] = source; *out_len = 1; result = UTF8ERROR_SUCCESS; } } else { /* 2 byte character */ if ( max_size >= 2 ) { destination[0] = 0xc0 | ( source >> 6 ); destination[1] = 0x80 | ( source & 0x3f ); *out_len = 2; result = UTF8ERROR_SUCCESS; } } } else { if ( source <= 0x10ffff ) { if ( source <= 0xffff ) { /* 3 byte character */ if ( max_size >= 3 ) { destination[0] = 0xe0 | ( source >> 12 ); destination[1] = 0x80 | (( source >> 6 ) & 0x3f ); destination[2] = 0x80 | ( source & 0x3f ); *out_len = 3; result = UTF8ERROR_SUCCESS; } } else { /* 4 byte character */ if ( max_size >= 4 ) { destination[0] = 0xf0 | ( source >> 18 ); destination[1] = 0x80 | (( source >> 12 ) & 0x3f ); destination[2] = 0x80 | (( source >> 6 ) & 0x3f ); destination[3] = 0x80 | ( source & 0x3f ); *out_len = 4; result = UTF8ERROR_SUCCESS; } } } else { /* note: utf8 can not encode more than 21 bits per character, and even there only 0-0x10ffff is allowed. */ result = UTF8ERROR_NOT_A_CODEPOINT; } } return result; } utf8error_t utf8_string_buf_private_replace_region_by_str( utf8stringbuf_t this_, unsigned int this_Length, int start, int length, const char *replacement ) { utf8error_t result = UTF8ERROR_OUT_OF_RANGE; if (( start >= 0 ) && ( start <= this_Length ) && ( length >= 0 )) { result = UTF8ERROR_SUCCESS; unsigned int replaceLen = ( replacement == NULL ) ? (0) : ( strlen(replacement) ); if (( start + length ) > this_Length ) { /* length value was too big. update this; success is 0 */ length = this_Length - start; result = UTF8ERROR_OUT_OF_RANGE; } int tailLen = this_Length - start - length; if ( length > replaceLen ) { memmove( &(this_.buf[start+replaceLen]), &(this_.buf[start+length]), tailLen+1 ); } else if ( length < replaceLen ) { if ( ( start + replaceLen + tailLen ) < this_.size ) { memmove( &(this_.buf[start+replaceLen]), &(this_.buf[start+length]), tailLen+1 ); } else if ( ( start + replaceLen ) < this_.size ) { tailLen = this_.size - start - replaceLen - 1; memmove( &(this_.buf[start+replaceLen]), &(this_.buf[start+length]), tailLen ); result = UTF8ERROR_TRUNCATED; } else { replaceLen = this_.size - start - 1; result = UTF8ERROR_TRUNCATED; } } else { /* original and replacement strings have equal lengths */ } /* replace string */ if ( replaceLen > 0 ) { const size_t replace_len = (size_t)(replaceLen); memcpy ( &(this_.buf[start]), replacement, replace_len ); } /* terminate string */ if ( result != UTF8ERROR_SUCCESS ) { utf8_string_buf_private_make_null_termination( this_ ); } } return result; } utf8error_t utf8stringbuf_replace_all( const utf8stringbuf_t this_, const char *const ((*patterns_and_replacements)[][2]) ) { utf8error_t result = UTF8ERROR_NULL_PARAM; /* count input patterns */ int maxPatternIdx = 0; if ( patterns_and_replacements != NULL ) { result = UTF8ERROR_SUCCESS; for ( maxPatternIdx = 0; (*patterns_and_replacements)[maxPatternIdx][0] != NULL; maxPatternIdx ++ ) { }; } /* search patterns */ unsigned int thisLen = utf8stringbuf_get_length( this_ ); for ( int index = 0; index < thisLen; index ++ ) { int matchingPatternIdx = -1; unsigned int remainingLength = thisLen-index; for ( int patternIdx = 0; ( patternIdx < maxPatternIdx )&&( matchingPatternIdx == -1 ); patternIdx ++ ) { int finished = 0; for ( int compareIdx = 0; ( compareIdx <= remainingLength )&&( finished == 0 ); compareIdx ++ ) { char cmpChar = (*patterns_and_replacements)[patternIdx][0][compareIdx]; if ( cmpChar == '\0' ) { if ( compareIdx != 0 ) { /* all characters were equal (and there was at least one) */ matchingPatternIdx = patternIdx; } finished = 1; } if ( this_.buf[index+compareIdx] != cmpChar ) { /* difference found */ finished = 1; } } } /* replace pattern */ if ( matchingPatternIdx != -1 ) { const char * pattern = (*patterns_and_replacements)[matchingPatternIdx][0]; int patternLen = strlen( pattern ); const char * replacement = (*patterns_and_replacements)[matchingPatternIdx][1]; int replaceLen = 0; if ( replacement != NULL ) { replaceLen = strlen(replacement); } utf8error_t replaceErr; replaceErr = utf8_string_buf_private_replace_region_by_str( this_, thisLen, index, patternLen, replacement ); if ( replaceErr != UTF8ERROR_SUCCESS ) { result = UTF8ERROR_TRUNCATED; thisLen = utf8stringbuf_get_length( this_ ); } else { thisLen = thisLen - patternLen + replaceLen; } index = index + replaceLen - 1; } } return result; } static const int SIZE_OF_TERM0 = 1; /*!< Size of the terminating zero */ utf8string2tuple_t utf8stringbuf_split_in_2( utf8stringbuf_t this_, int start2 ) { utf8string2tuple_t result; unsigned int length = utf8stringbuf_get_length( this_ ); /* zero all trailing data, otherwise joins will not work */ memset( &(this_.buf[length+SIZE_OF_TERM0]), '\0', this_.size - length - SIZE_OF_TERM0 ); if (( 0 <= start2 )&&( start2 <= length )) { int newStart2 = start2+SIZE_OF_TERM0; if ( length+SIZE_OF_TERM0 < this_.size ) { /* everything fits */ memmove( &(this_.buf[newStart2]), &(this_.buf[start2]), length-start2+SIZE_OF_TERM0 ); this_.buf[newStart2-SIZE_OF_TERM0] = '\0'; result.first = this_.buf; result.second = &(this_.buf[start2+1]); result.error = UTF8ERROR_SUCCESS; } else { /* we need to truncate */ int secondLen = this_.size - SIZE_OF_TERM0 - newStart2; if ( secondLen <= 0 ) { secondLen = 0; newStart2 = this_.size - SIZE_OF_TERM0; this_.buf[newStart2] = '\0'; } else { memmove( &(this_.buf[newStart2]), &(this_.buf[start2]), secondLen ); utf8_string_buf_private_make_null_termination( utf8stringbuf_init( secondLen+SIZE_OF_TERM0, &(this_.buf[newStart2])) ); } this_.buf[start2] = '\0'; /* at the end of the first string, always write a terminating zero */ /* printf("\nFIRST=%i SECOND=%i \\0=%i TRAIL=%i [size=%i] -> FIRST=%i \\0=%i SECOND=%i \\0=%i [size=%i]", start2, length-start2, SIZE_OF_TERM0, this_.size-length-SIZE_OF_TERM0, this_.size, start2, newStart2-start2, secondLen, SIZE_OF_TERM0, this_.size ); */ result.first = this_.buf; result.second = &(this_.buf[newStart2]); result.error = UTF8ERROR_TRUNCATED; } } else { /* out of range */ result.first = this_.buf; result.second = &(this_.buf[length]); result.error = UTF8ERROR_OUT_OF_RANGE; } return result; } utf8string3tuple_t utf8stringbuf_split_in_3( utf8stringbuf_t this_, int start2, int start3 ) { utf8string3tuple_t result; unsigned int length = utf8stringbuf_get_length( this_ ); /* zero all trailing data, otherwise joins will not work */ memset( &(this_.buf[length+SIZE_OF_TERM0]), '\0', this_.size - length - SIZE_OF_TERM0 ); if (( 0 <= start2 )&&( start2 <= start3 )&&( start3 <= length )) { int newStart2 = start2+SIZE_OF_TERM0; int newStart3 = start3+SIZE_OF_TERM0+SIZE_OF_TERM0; if ( length+SIZE_OF_TERM0+SIZE_OF_TERM0 < this_.size ) { /* everything fits */ memmove( &(this_.buf[newStart3]), &(this_.buf[start3]), length-start3+SIZE_OF_TERM0 ); this_.buf[newStart3-SIZE_OF_TERM0] = '\0'; memmove( &(this_.buf[newStart2]), &(this_.buf[start2]), start3-start2 ); this_.buf[newStart2-SIZE_OF_TERM0] = '\0'; result.first = this_.buf; result.second = &(this_.buf[newStart2]); result.third = &(this_.buf[newStart3]); result.error = UTF8ERROR_SUCCESS; } else { /* we need to truncate */ int thirdLen = this_.size - SIZE_OF_TERM0 - newStart3; if ( thirdLen <= 0 ) { thirdLen = 0; newStart3 = this_.size - SIZE_OF_TERM0; this_.buf[newStart3] = '\0'; } else { memmove( &(this_.buf[newStart3]), &(this_.buf[start3]), thirdLen ); utf8_string_buf_private_make_null_termination( utf8stringbuf_init( thirdLen+SIZE_OF_TERM0, &(this_.buf[newStart3])) ); } int secondLen = newStart3 - SIZE_OF_TERM0 - newStart2; if ( secondLen < 0 ) { secondLen = 0; newStart2 = this_.size - SIZE_OF_TERM0; } else if ( secondLen == 0 ) { this_.buf[newStart2] = '\0'; } else { memmove( &(this_.buf[newStart2]), &(this_.buf[start2]), secondLen ); utf8_string_buf_private_make_null_termination( utf8stringbuf_init( secondLen+SIZE_OF_TERM0, &(this_.buf[newStart2])) ); } this_.buf[start2] = '\0'; /* at the end of the first string, always write a terminating zero */ /* printf("\nFIRST=%i SECOND=%i THIRD=%i \\0=%i TRAIL=%i [size=%i] -> FIRST=%i \\0=%i SECOND=%i \\0=%i THIRD=%i \\0=%i [size=%i]", start2, start3-start2, length-start3, SIZE_OF_TERM0, this_.size-length-SIZE_OF_TERM0, this_.size, start2, newStart2-start2, secondLen, (int)(newStart3!=newStart2), thirdLen, SIZE_OF_TERM0, this_.size ); */ result.first = this_.buf; result.second = &(this_.buf[newStart2]); result.third = &(this_.buf[newStart3]); result.error = UTF8ERROR_TRUNCATED; } } else { /* out of range */ result.first = this_.buf; result.second = &(this_.buf[length]); result.third = &(this_.buf[length]); result.error = UTF8ERROR_OUT_OF_RANGE; } return result; } utf8string4tuple_t utf8stringbuf_split_in_4( utf8stringbuf_t this_, int start2, int start3, int start4 ) { utf8string4tuple_t result; unsigned int length = utf8stringbuf_get_length( this_ ); /* zero all trailing data, otherwise joins will not work */ memset( &(this_.buf[length+SIZE_OF_TERM0]), '\0', this_.size - length - SIZE_OF_TERM0 ); if (( 0 <= start2 )&&( start2 <= start3 )&&( start3 <= start4 )&&( start4 <= length )) { int newStart2 = start2+SIZE_OF_TERM0; int newStart3 = start3+SIZE_OF_TERM0+SIZE_OF_TERM0; int newStart4 = start4+SIZE_OF_TERM0+SIZE_OF_TERM0+SIZE_OF_TERM0; if ( length+SIZE_OF_TERM0+SIZE_OF_TERM0+SIZE_OF_TERM0 < this_.size ) { /* everything fits */ memmove( &(this_.buf[newStart4]), &(this_.buf[start4]), length-start4+SIZE_OF_TERM0 ); this_.buf[newStart4-SIZE_OF_TERM0] = '\0'; memmove( &(this_.buf[newStart3]), &(this_.buf[start3]), start4-start3 ); this_.buf[newStart3-SIZE_OF_TERM0] = '\0'; memmove( &(this_.buf[newStart2]), &(this_.buf[start2]), start3-start2 ); this_.buf[newStart2-SIZE_OF_TERM0] = '\0'; result.first = this_.buf; result.second = &(this_.buf[newStart2]); result.third = &(this_.buf[newStart3]); result.fourth = &(this_.buf[newStart4]); result.error = UTF8ERROR_SUCCESS; } else { /* we need to truncate */ int fourthLen = this_.size - SIZE_OF_TERM0 - newStart4; if ( fourthLen <= 0 ) { fourthLen = 0; newStart4 = this_.size - SIZE_OF_TERM0; this_.buf[newStart4] = '\0'; } else { memmove( &(this_.buf[newStart4]), &(this_.buf[start4]), fourthLen ); utf8_string_buf_private_make_null_termination( utf8stringbuf_init( fourthLen+SIZE_OF_TERM0, &(this_.buf[newStart4])) ); } int thirdLen = newStart4 - SIZE_OF_TERM0 - newStart3; if ( thirdLen < 0 ) { thirdLen = 0; newStart3 = this_.size - SIZE_OF_TERM0; } else if ( thirdLen == 0 ) { this_.buf[newStart3] = '\0'; } else { memmove( &(this_.buf[newStart3]), &(this_.buf[start3]), thirdLen ); utf8_string_buf_private_make_null_termination( utf8stringbuf_init( thirdLen+SIZE_OF_TERM0, &(this_.buf[newStart3])) ); } int secondLen = newStart3 - SIZE_OF_TERM0 - newStart2; if ( secondLen < 0 ) { secondLen = 0; newStart2 = this_.size - SIZE_OF_TERM0; } else if ( secondLen == 0 ) { this_.buf[newStart2] = '\0'; } else { memmove( &(this_.buf[newStart2]), &(this_.buf[start2]), secondLen ); utf8_string_buf_private_make_null_termination( utf8stringbuf_init( secondLen+SIZE_OF_TERM0, &(this_.buf[newStart2])) ); } this_.buf[start2] = '\0'; /* at the end of the first string, always write a terminating zero */ /* printf("\nFIRST=%i SECOND=%i THIRD=%i FOURTH=%i \\0=%i TRAIL=%i [size=%i] -> FIRST=%i \\0=%i SECOND=%i \\0=%i THIRD=%i \\0=%i FOURTH=%i \\0=%i [size=%i]", start2, start3-start2, start4-start3, length-start4, SIZE_OF_TERM0, this_.size-length-SIZE_OF_TERM0, this_.size, start2, newStart2-start2, secondLen, (int)(newStart3!=newStart2), thirdLen, (int)(newStart4!=newStart3), fourthLen, SIZE_OF_TERM0, this_.size ); */ result.first = this_.buf; result.second = &(this_.buf[newStart2]); result.third = &(this_.buf[newStart3]); result.fourth = &(this_.buf[newStart4]); result.error = UTF8ERROR_TRUNCATED; } } else { /* out of range */ result.first = this_.buf; result.second = &(this_.buf[length]); result.third = &(this_.buf[length]); result.fourth = &(this_.buf[length]); result.error = UTF8ERROR_OUT_OF_RANGE; } return result; } utf8string5tuple_t utf8stringbuf_split_in_5( utf8stringbuf_t this_, int start2, int start3, int start4, int start5 ) { utf8string5tuple_t result; unsigned int length = utf8stringbuf_get_length( this_ ); /* zero all trailing data, otherwise joins will not work */ memset( &(this_.buf[length+SIZE_OF_TERM0]), '\0', this_.size - length - SIZE_OF_TERM0 ); if (( 0 <= start2 )&&( start2 <= start3 )&&( start3 <= start4 )&&( start4 <= start5 )&&( start5 <= length )) { int newStart2 = start2+SIZE_OF_TERM0; int newStart3 = start3+SIZE_OF_TERM0+SIZE_OF_TERM0; int newStart4 = start4+SIZE_OF_TERM0+SIZE_OF_TERM0+SIZE_OF_TERM0; int newStart5 = start4+SIZE_OF_TERM0+SIZE_OF_TERM0+SIZE_OF_TERM0+SIZE_OF_TERM0; if ( length+SIZE_OF_TERM0+SIZE_OF_TERM0+SIZE_OF_TERM0+SIZE_OF_TERM0 < this_.size ) { /* everything fits */ memmove( &(this_.buf[newStart5]), &(this_.buf[start5]), length-start5+SIZE_OF_TERM0 ); this_.buf[newStart5-SIZE_OF_TERM0] = '\0'; memmove( &(this_.buf[newStart4]), &(this_.buf[start4]), start5-start4 ); this_.buf[newStart4-SIZE_OF_TERM0] = '\0'; memmove( &(this_.buf[newStart3]), &(this_.buf[start3]), start4-start3 ); this_.buf[newStart3-SIZE_OF_TERM0] = '\0'; memmove( &(this_.buf[newStart2]), &(this_.buf[start2]), start3-start2 ); this_.buf[newStart2-SIZE_OF_TERM0] = '\0'; result.first = this_.buf; result.second = &(this_.buf[newStart2]); result.third = &(this_.buf[newStart3]); result.fourth = &(this_.buf[newStart4]); result.fifth = &(this_.buf[newStart5]); result.error = UTF8ERROR_SUCCESS; } else { /* we need to truncate */ int fifthLen = this_.size - SIZE_OF_TERM0 - newStart5; if ( fifthLen <= 0 ) { fifthLen = 0; newStart5 = this_.size - SIZE_OF_TERM0; this_.buf[newStart5] = '\0'; } else { memmove( &(this_.buf[newStart5]), &(this_.buf[start5]), fifthLen ); utf8_string_buf_private_make_null_termination( utf8stringbuf_init( fifthLen+SIZE_OF_TERM0, &(this_.buf[newStart5])) ); } int fourthLen = newStart5 - SIZE_OF_TERM0 - newStart4; if ( fourthLen < 0 ) { fourthLen = 0; newStart4 = this_.size - SIZE_OF_TERM0; } else if ( fourthLen == 0 ) { this_.buf[newStart4] = '\0'; } else { memmove( &(this_.buf[newStart4]), &(this_.buf[start4]), fourthLen ); utf8_string_buf_private_make_null_termination( utf8stringbuf_init( fourthLen+SIZE_OF_TERM0, &(this_.buf[newStart4])) ); } int thirdLen = newStart4 - SIZE_OF_TERM0 - newStart3; if ( thirdLen < 0 ) { thirdLen = 0; newStart3 = this_.size - SIZE_OF_TERM0; } else if ( thirdLen == 0 ) { this_.buf[newStart3] = '\0'; } else { memmove( &(this_.buf[newStart3]), &(this_.buf[start3]), thirdLen ); utf8_string_buf_private_make_null_termination( utf8stringbuf_init( thirdLen+SIZE_OF_TERM0, &(this_.buf[newStart3])) ); } int secondLen = newStart3 - SIZE_OF_TERM0 - newStart2; if ( secondLen < 0 ) { secondLen = 0; newStart2 = this_.size - SIZE_OF_TERM0; } else if ( secondLen == 0 ) { this_.buf[newStart2] = '\0'; } else { memmove( &(this_.buf[newStart2]), &(this_.buf[start2]), secondLen ); utf8_string_buf_private_make_null_termination( utf8stringbuf_init( secondLen+SIZE_OF_TERM0, &(this_.buf[newStart2])) ); } this_.buf[start2] = '\0'; /* at the end of the first string, always write a terminating zero */ /* printf("\nFIRST=%i SECOND=%i THIRD=%i FOURTH=%i FIFTH=%i \\0=%i TRAIL=%i [size=%i] -> FIRST=%i \\0=%i SECOND=%i \\0=%i THIRD=%i \\0=%i FOURTH=%i \\0=%i FIFTH=%i \\0=%i [size=%i]", start2, start3-start2, start4-start3, start5-start4, length-start5, SIZE_OF_TERM0, this_.size-length-SIZE_OF_TERM0, this_.size, start2, newStart2-start2, secondLen, (int)(newStart3!=newStart2), thirdLen, (int)(newStart4!=newStart3), fourthLen, (int)(newStart5!=newStart4), fifthLen, SIZE_OF_TERM0, this_.size ); */ result.first = this_.buf; result.second = &(this_.buf[newStart2]); result.third = &(this_.buf[newStart3]); result.fourth = &(this_.buf[newStart4]); result.fifth = &(this_.buf[newStart5]); result.error = UTF8ERROR_TRUNCATED; } } else { /* out of range */ result.first = this_.buf; result.second = &(this_.buf[length]); result.third = &(this_.buf[length]); result.fourth = &(this_.buf[length]); result.fifth = &(this_.buf[length]); result.error = UTF8ERROR_OUT_OF_RANGE; } return result; } void utf8stringbuf_join( utf8stringbuf_t this_ ) { /* search first terminating zero, start from there. */ unsigned int currentReadPos = strlen( this_.buf ); unsigned int currentWritePos = currentReadPos; unsigned int confirmedLength = currentReadPos; /* copy all characters except the zeroes */ for ( ; currentReadPos < this_.size; currentReadPos ++ ) { char buf = this_.buf[currentReadPos]; if ( buf == '\0' ) { confirmedLength = currentWritePos; } else { this_.buf[currentWritePos] = buf; currentWritePos ++; } } /* set all trailing characters to 0 */ const size_t trailing_space = (size_t)( this_.size - confirmedLength ); memset( &(this_.buf[confirmedLength]), '\0', trailing_space ); } /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/test/000077500000000000000000000000001415120503000207145ustar00rootroot00000000000000crystal-facet-uml-1.34.1/utf8stringbuf/test/unit/000077500000000000000000000000001415120503000216735ustar00rootroot00000000000000crystal-facet-uml-1.34.1/utf8stringbuf/test/unit/utf8codepoint_test.c000066400000000000000000000403421415120503000256740ustar00rootroot00000000000000/* File: utf8codepoint_test.c; Copyright and License: see below */ #include "utf8codepoint_test.h" #include "util/string/utf8stringbuf.h" #include "util/string/utf8codepoint.h" #include "test_assert.h" #include #include static void setUp(void); static void tearDown(void); static void testInit1(void); static void testInit2(void); static void testIntToUtf8ToInt(void); static void testIntToUtf8(void); static void testUnicode(void); test_suite_t utf8codepoint_test_get_list(void) { test_suite_t result; test_suite_init( &result, "utf8CodePointTest", &setUp, &tearDown ); test_suite_add_test_case( &result, "testInit1", &testInit1 ); test_suite_add_test_case( &result, "testInit2", &testInit2 ); test_suite_add_test_case( &result, "testIntToUtf8ToInt", &testIntToUtf8ToInt ); test_suite_add_test_case( &result, "testIntToUtf8", &testIntToUtf8 ); test_suite_add_test_case( &result, "testUnicode", &testUnicode ); return result; } static void setUp(void) { } static void tearDown(void) { } static void testInit1(void) { /* check initialization */ utf8codepoint_t code_point1 = utf8codepoint( 'a' ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_get_length( code_point1 ) ); TEST_ASSERT_EQUAL_INT( 97, utf8codepoint_get_char( code_point1 ) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid( code_point1 ) ); code_point1 = utf8codepoint( 0x00e4 ); TEST_ASSERT_EQUAL_INT( 2, utf8codepoint_get_length( code_point1 ) ); TEST_ASSERT_EQUAL_INT( 0x00e4, utf8codepoint_get_char( code_point1 ) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid( code_point1 ) ); code_point1 = utf8codepoint( 0x20ac ); TEST_ASSERT_EQUAL_INT( 3, utf8codepoint_get_length( code_point1 ) ); TEST_ASSERT_EQUAL_INT( 0x20ac, utf8codepoint_get_char( code_point1 ) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid( code_point1 ) ); code_point1 = utf8codepoint( 0x1d11e ); TEST_ASSERT_EQUAL_INT( 4, utf8codepoint_get_length( code_point1 ) ); TEST_ASSERT_EQUAL_INT( 0x1d11e, utf8codepoint_get_char( code_point1 ) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid( code_point1 ) ); code_point1 = utf8codepoint( '\0' ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_get_length( code_point1 ) ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_get_char( code_point1 ) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid( code_point1 ) ); code_point1 = utf8codepoint( 0x7fffffff ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_get_length( code_point1 ) ); TEST_ASSERT_EQUAL_INT( 0x7fffffff, utf8codepoint_get_char( code_point1 ) ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_valid( code_point1 ) ); code_point1 = utf8codepoint( 0x20ffff ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_get_length( code_point1 ) ); TEST_ASSERT_EQUAL_INT( 0x20ffff, utf8codepoint_get_char( code_point1 ) ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_valid( code_point1 ) ); code_point1 = utf8codepoint( 0xffffffff ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_get_length( code_point1 ) ); TEST_ASSERT_EQUAL_INT( 0xffffffff, utf8codepoint_get_char( code_point1 ) ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_valid( code_point1 ) ); } static void testInit2(void) { /* check init function */ utf8codepoint_t code_point2 = utf8codepoint_init( "a", 1 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_get_length( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 97, utf8codepoint_get_char( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid( code_point2 ) ); code_point2 = utf8codepoint_init( "\0", 1 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_get_length( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_get_char( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid( code_point2 ) ); code_point2 = utf8codepoint_init( "\xC3\xA4", 100 ); TEST_ASSERT_EQUAL_INT( 2, utf8codepoint_get_length( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 0x00e4, utf8codepoint_get_char( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid( code_point2 ) ); code_point2 = utf8codepoint_init( "\xC3\xA4", 2 ); TEST_ASSERT_EQUAL_INT( 2, utf8codepoint_get_length( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 0x00e4, utf8codepoint_get_char( code_point2 ) ); TEST_ASSERT ( 0 != memcmp( &UTF8CODEPOINT_INVAL_CHAR, &code_point2, sizeof(utf8codepoint_t) ) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid( code_point2 ) ); code_point2 = utf8codepoint_init( "\xC3\xA4", 1 ); TEST_ASSERT_EQUAL_INT( UTF8CODEPOINT_INVALID_LEN, utf8codepoint_get_length( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 0x0, utf8codepoint_get_char( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_valid( code_point2 ) ); code_point2 = utf8codepoint_init( "\xC3\xA4", 0 ); TEST_ASSERT_EQUAL_INT( UTF8CODEPOINT_INVALID_LEN, utf8codepoint_get_length( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 0x0, utf8codepoint_get_char( code_point2 ) ); TEST_ASSERT ( 0 == memcmp( &UTF8CODEPOINT_INVAL_CHAR, &code_point2, sizeof(utf8codepoint_t) ) ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_valid( code_point2 ) ); code_point2 = utf8codepoint_init( NULL, 2 ); TEST_ASSERT_EQUAL_INT( UTF8CODEPOINT_INVALID_LEN, utf8codepoint_get_length( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 0x0, utf8codepoint_get_char( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_valid( code_point2 ) ); code_point2 = utf8codepoint_init( "\xE2\x82\xAC", 3 ); TEST_ASSERT_EQUAL_INT( 3, utf8codepoint_get_length( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 0x20ac, utf8codepoint_get_char( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid( code_point2 ) ); code_point2 = utf8codepoint_init( "\xF0\x9D\x84\x9E", 4 ); TEST_ASSERT_EQUAL_INT( 4, utf8codepoint_get_length( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 0x1d11e, utf8codepoint_get_char( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid( code_point2 ) ); code_point2 = utf8codepoint_init( "\xF0\x9D\x84\x9E", 3 ); TEST_ASSERT_EQUAL_INT( UTF8CODEPOINT_INVALID_LEN, utf8codepoint_get_length( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 0x0, utf8codepoint_get_char( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_valid( code_point2 ) ); code_point2 = utf8codepoint_init( "\x9D\x84\x9E", 3 ); TEST_ASSERT_EQUAL_INT( UTF8CODEPOINT_INVALID_LEN, utf8codepoint_get_length( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 0x0, utf8codepoint_get_char( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_valid( code_point2 ) ); code_point2 = utf8codepoint_init( "\xF0\x9D\x84\x00", 4 ); TEST_ASSERT_EQUAL_INT( UTF8CODEPOINT_INVALID_LEN, utf8codepoint_get_length( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 0x0, utf8codepoint_get_char( code_point2 ) ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_valid( code_point2 ) ); } static void testIntToUtf8ToInt(void) { utf8codepoint_t result; char dynTestArr1[7] = ""; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); /* check to convert a character to and back from utf8 */ /* 0 */ result = utf8stringbuf_get_char_at( dynTestBuf1, 0 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0x0, utf8codepoint_get_char(result) ); /* 1 byte code points */ utf8stringbuf_clear( dynTestBuf1 ); utf8stringbuf_append_char( dynTestBuf1, 0x01 ); result = utf8stringbuf_get_char_at( dynTestBuf1, 0 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0x01, utf8codepoint_get_char(result) ); utf8stringbuf_clear( dynTestBuf1 ); utf8stringbuf_append_char( dynTestBuf1, 0x7f ); result = utf8stringbuf_get_char_at( dynTestBuf1, 0 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0x7f, utf8codepoint_get_char(result) ); /* 2 byte code points */ utf8stringbuf_clear( dynTestBuf1 ); utf8stringbuf_append_char( dynTestBuf1, 0x80 ); result = utf8stringbuf_get_char_at( dynTestBuf1, 0 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( 2, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0x80, utf8codepoint_get_char(result) ); utf8stringbuf_clear( dynTestBuf1 ); utf8stringbuf_append_char( dynTestBuf1, 0x07ff ); result = utf8stringbuf_get_char_at( dynTestBuf1, 0 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( 2, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0x07ff, utf8codepoint_get_char(result) ); /* 3 byte code points */ utf8stringbuf_clear( dynTestBuf1 ); utf8stringbuf_append_char( dynTestBuf1, 0x800 ); result = utf8stringbuf_get_char_at( dynTestBuf1, 0 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( 3, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0x800, utf8codepoint_get_char(result) ); utf8stringbuf_clear( dynTestBuf1 ); utf8stringbuf_append_char( dynTestBuf1, 0xffff ); result = utf8stringbuf_get_char_at( dynTestBuf1, 0 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( 3, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0xffff, utf8codepoint_get_char(result) ); /* 4 byte code points */ utf8stringbuf_clear( dynTestBuf1 ); utf8stringbuf_append_char( dynTestBuf1, 0x10000 ); result = utf8stringbuf_get_char_at( dynTestBuf1, 0 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( 4, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0x10000, utf8codepoint_get_char(result) ); utf8stringbuf_clear( dynTestBuf1 ); utf8stringbuf_append_char( dynTestBuf1, 0x10ffff ); result = utf8stringbuf_get_char_at( dynTestBuf1, 0 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( 4, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0x10ffff, utf8codepoint_get_char(result) ); char invalid_1fffff[5] = "\xF7\xBF\xBF\xBF"; utf8stringbuf_t invalidBuf = UTF8STRINGBUF(invalid_1fffff); result = utf8stringbuf_get_char_at( invalidBuf, 0 ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0x1fffff, utf8codepoint_get_char(result) ); } static void testIntToUtf8(void) { utf8codepoint_t probe; utf8codepointseq_t expect; utf8codepointseq_t result; /* check to convert a character to utf8 */ /* 0 */ probe = utf8codepoint( 0 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(probe) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_get_length(probe) ); result = utf8codepoint_get_utf8( probe ); expect = (utf8codepointseq_t){.seq={'\0', '\0', '\0', '\0'}}; TEST_ASSERT_EQUAL_INT( 0, memcmp( &result, &expect, sizeof(utf8codepointseq_t) ) ); /* 1 byte code points */ probe = utf8codepoint( 0x24 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(probe) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_get_length(probe) ); result = utf8codepoint_get_utf8( probe ); expect = (utf8codepointseq_t){.seq={'\x24', '\0', '\0', '\0'}}; TEST_ASSERT_EQUAL_INT( 0, memcmp( &result, &expect, sizeof(utf8codepointseq_t) ) ); /* 2 byte code points */ probe = utf8codepoint( 0xa2 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(probe) ); TEST_ASSERT_EQUAL_INT( 2, utf8codepoint_get_length(probe) ); result = utf8codepoint_get_utf8( probe ); expect = (utf8codepointseq_t){.seq={'\xc2', '\xa2', '\0', '\0'}}; TEST_ASSERT_EQUAL_INT( 0, memcmp( &result, &expect, sizeof(utf8codepointseq_t) ) ); /* 3 byte code points */ probe = utf8codepoint( 0x20ac ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(probe) ); TEST_ASSERT_EQUAL_INT( 3, utf8codepoint_get_length(probe) ); result = utf8codepoint_get_utf8( probe ); expect = (utf8codepointseq_t){.seq={'\xe2', '\x82', '\xac', '\0'}}; TEST_ASSERT_EQUAL_INT( 0, memcmp( &result, &expect, sizeof(utf8codepointseq_t) ) ); /* 4 byte code points */ probe = utf8codepoint( 0x10348 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(probe) ); TEST_ASSERT_EQUAL_INT( 4, utf8codepoint_get_length(probe) ); result = utf8codepoint_get_utf8( probe ); expect = (utf8codepointseq_t){.seq={'\xf0', '\x90', '\x8d', '\x88'}}; TEST_ASSERT_EQUAL_INT( 0, memcmp( &result, &expect, sizeof(utf8codepointseq_t) ) ); /* invalid */ probe = utf8codepoint( 0x110000 ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_valid(probe) ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_get_length(probe) ); result = utf8codepoint_get_utf8( probe ); expect = (utf8codepointseq_t){.seq={'\0', '\0', '\0', '\0'}}; TEST_ASSERT_EQUAL_INT( 0, memcmp( &result, &expect, sizeof(utf8codepointseq_t) ) ); } static void testUnicode(void) { /* check valid code points */ utf8codepoint_t code_point1 = utf8codepoint( '\0' ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0xd7ff ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0xe000 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0xfdcf ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0xfdf0 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0xfffc ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0x10000 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0x1fffc ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0x100000 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0x10fffc ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_unicode( code_point1 ) ); /* check invalid code points */ code_point1 = utf8codepoint( 0xd800 ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0xdfff ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0xfdd0 ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0xfdef ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0xfffe ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0xffff ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0x1fffe ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0x1ffff ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0x10fffe ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0x10ffff ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0x110000 ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_unicode( code_point1 ) ); code_point1 = utf8codepoint( 0xffffffff ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_unicode( code_point1 ) ); } /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/test/unit/utf8codepoint_test.h000066400000000000000000000015101415120503000256730ustar00rootroot00000000000000/* File: utf8codepoint_test.h; Copyright and License: see below */ #ifndef UTF8CODEPOINT_TEST_H_ #define UTF8CODEPOINT_TEST_H_ #include "test_suite.h" test_suite_t utf8codepoint_test_get_list(void); #endif /*UTF8CODEPOINT_TEST_H_*/ /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/test/unit/utf8codepointiterator_test.c000066400000000000000000000126401415120503000274460ustar00rootroot00000000000000/* File: utf8codepointiterator_test.c; Copyright and License: see below */ #include "utf8string_test.h" #include "util/string/utf8codepointiterator.h" #include "util/string/utf8stringview.h" #include "test_assert.h" #include #include static void setUp(void); static void tearDown(void); static void testStandardUseCase(void); static void testEmptyUseCase(void); static void testIllegalUseCase(void); test_suite_t utf8codepointiterator_test_get_list(void) { test_suite_t result; test_suite_init( &result, "utf8CodePointIteratorTest", &setUp, &tearDown ); test_suite_add_test_case( &result, "testStandardUseCase", &testStandardUseCase ); test_suite_add_test_case( &result, "testEmptyUseCase", &testEmptyUseCase ); test_suite_add_test_case( &result, "testIllegalUseCase", &testIllegalUseCase ); return result; } static void setUp(void) { } static void tearDown(void) { } static void testStandardUseCase(void) { bool has_next; utf8codepoint_t next; static const char my_string[] = "a" "\0" "\xC3\xA4" "\xE2\x82\xAC" "\xF0\x9D\x84\x9E"; /* init */ utf8codepointiterator_t it; utf8codepointiterator_init( &it, UTF8STRINGVIEW( my_string, sizeof(my_string)-1 ) ); has_next = utf8codepointiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( true, has_next ); next = utf8codepointiterator_next( &it ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_get_length( next ) ); TEST_ASSERT_EQUAL_INT( 97, utf8codepoint_get_char( next ) ); /* a == 97 */ TEST_ASSERT_EQUAL_INT( true, utf8codepoint_is_valid( next ) ); has_next = utf8codepointiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( true, has_next ); next = utf8codepointiterator_next( &it ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_get_length( next ) ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_get_char( next ) ); /* 0 == 0 */ TEST_ASSERT_EQUAL_INT( true, utf8codepoint_is_valid( next ) ); has_next = utf8codepointiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( true, has_next ); next = utf8codepointiterator_next( &it ); TEST_ASSERT_EQUAL_INT( 2, utf8codepoint_get_length( next ) ); TEST_ASSERT_EQUAL_INT( 0x00e4, utf8codepoint_get_char( next ) ); TEST_ASSERT_EQUAL_INT( true, utf8codepoint_is_valid( next ) ); has_next = utf8codepointiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( true, has_next ); next = utf8codepointiterator_next( &it ); TEST_ASSERT_EQUAL_INT( 3, utf8codepoint_get_length( next ) ); TEST_ASSERT_EQUAL_INT( 0x20ac, utf8codepoint_get_char( next ) ); TEST_ASSERT_EQUAL_INT( true, utf8codepoint_is_valid( next ) ); has_next = utf8codepointiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( true, has_next ); next = utf8codepointiterator_next( &it ); TEST_ASSERT_EQUAL_INT( 4, utf8codepoint_get_length( next ) ); TEST_ASSERT_EQUAL_INT( 0x1d11e, utf8codepoint_get_char( next ) ); /* a == 97 */ TEST_ASSERT_EQUAL_INT( true, utf8codepoint_is_valid( next ) ); has_next = utf8codepointiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( false, has_next ); next = utf8codepointiterator_next( &it ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_get_length( next ) ); TEST_ASSERT_EQUAL_INT( false, utf8codepoint_is_valid( next ) ); /* finish */ utf8codepointiterator_destroy( &it ); } static void testEmptyUseCase(void) { bool has_next; utf8codepoint_t next; static const char *const my_string = "\xF0\x9D\x84\x9E"; /* init */ utf8codepointiterator_t it; utf8codepointiterator_init( &it, UTF8STRINGVIEW( my_string, 0 ) ); has_next = utf8codepointiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( false, has_next ); next = utf8codepointiterator_next( &it ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_get_length( next ) ); TEST_ASSERT_EQUAL_INT( false, utf8codepoint_is_valid( next ) ); /* finish */ utf8codepointiterator_destroy( &it ); } static void testIllegalUseCase(void) { bool has_next; utf8codepoint_t next; static const char *const my_string = "\xF0\x9D\x84\x9E"; /* init */ utf8codepointiterator_t it; utf8codepointiterator_init( &it, UTF8STRINGVIEW( my_string, 1 ) ); has_next = utf8codepointiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( false, has_next ); next = utf8codepointiterator_next( &it ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_get_length( next ) ); TEST_ASSERT_EQUAL_INT( false, utf8codepoint_is_valid( next ) ); has_next = utf8codepointiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( false, has_next ); next = utf8codepointiterator_next( &it ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_get_length( next ) ); TEST_ASSERT_EQUAL_INT( false, utf8codepoint_is_valid( next ) ); /* finish */ utf8codepointiterator_destroy( &it ); } /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/test/unit/utf8codepointiterator_test.h000066400000000000000000000015601415120503000274520ustar00rootroot00000000000000/* File: utf8codepointiterator_test.h; Copyright and License: see below */ #ifndef UTF8CODEPOINTITERATOR_TEST_H_ #define UTF8CODEPOINTITERATOR_TEST_H_ #include "test_suite.h" test_suite_t utf8codepointiterator_test_get_list(void); #endif /*UTF8CODEPOINTITERATOR_TEST_H_*/ /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/test/unit/utf8string_test.c000066400000000000000000000511511415120503000252160ustar00rootroot00000000000000/* File: utf8string_test.c; Copyright and License: see below */ #include "utf8string_test.h" #include "util/string/utf8string.h" #include "util/string/utf8stringbuf.h" #include "test_assert.h" #include #include static void setUp(void); static void tearDown(void); static void testSize(void); static void testLength(void); static void testEquals(void); static void testEqualsRegion(void); static void testStartsWith(void); static void testEndsWith(void); static void testFindFirst(void); static void testFindNext(void); static void testFindLast(void); static void testCharAt(void); static void testCharAtLoops(void); static void testParseInt(void); test_suite_t utf8string_test_get_list(void) { test_suite_t result; test_suite_init( &result, "utf8StringTest", &setUp, &tearDown ); test_suite_add_test_case( &result, "testSize", &testSize ); test_suite_add_test_case( &result, "testLength", &testLength ); test_suite_add_test_case( &result, "testEquals", &testEquals ); test_suite_add_test_case( &result, "testEqualsRegion", &testEqualsRegion ); test_suite_add_test_case( &result, "testStartsWith", &testStartsWith ); test_suite_add_test_case( &result, "testEndsWith", &testEndsWith ); test_suite_add_test_case( &result, "testFindFirst", &testFindFirst ); test_suite_add_test_case( &result, "testFindNext", &testFindNext ); test_suite_add_test_case( &result, "testFindLast", &testFindLast ); test_suite_add_test_case( &result, "testCharAt", &testCharAt ); test_suite_add_test_case( &result, "testCharAtLoops", &testCharAtLoops ); test_suite_add_test_case( &result, "testParseInt", &testParseInt ); return result; } static void setUp(void) { } static void tearDown(void) { } static void testSize(void) { unsigned int size; /* check size */ size = utf8string_get_size( NULL ); TEST_ASSERT_EQUAL_INT( 0, size ); size = utf8string_get_size( "" ); TEST_ASSERT_EQUAL_INT( 1, size ); size = utf8string_get_size( "123456789 123456789" ); TEST_ASSERT_EQUAL_INT( 20, size ); size = utf8string_get_size( "ab\xC2\xA2\0" "efg" ); TEST_ASSERT_EQUAL_INT( 5, size ); } static void testEquals(void) { // prepare int equal; char dynTestArr1[] = "Hello"; utf8stringbuf_t dynTestBuf1 = utf8stringbuf(dynTestArr1); char dynTestArr2[] = "Hello World"; // test utf8string_equals_buf equal = utf8string_equals_buf( dynTestArr1, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8string_equals_buf( "Hello", dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8string_equals_buf( dynTestArr2, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8string_equals_buf( "", utf8stringbuf( "" ) ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8string_equals_buf( NULL, utf8stringbuf( "" ) ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8string_equals_buf( NULL, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 0, equal ); // test utf8string_equals_str equal = utf8string_equals_str( NULL, NULL ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8string_equals_str( "", NULL ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8string_equals_str( "", "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8string_equals_str( dynTestArr1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8string_equals_str( NULL, "Hello" ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8string_equals_str( dynTestArr1, dynTestArr2 ); TEST_ASSERT_EQUAL_INT( 0, equal ); } static void testEqualsRegion(void) { // prepare int equal; char dynTestArr1[] = "Hello"; utf8stringbuf_t dynTestBuf1 = utf8stringbuf(dynTestArr1); char dynTestArr2[] = "Hello Hell Hello Hello"; utf8stringbuf_t dynTestBuf2 = utf8stringbuf(dynTestArr2); // test utf8string_equals_region_buf equal = utf8string_equals_region_buf( dynTestArr1, 0, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8string_equals_region_buf( dynTestArr1, -1, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8string_equals_region_buf( dynTestArr1, 1, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8string_equals_region_buf( dynTestArr1, 6, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8string_equals_region_buf( dynTestArr1, 0, dynTestBuf2 ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8string_equals_region_buf( dynTestArr2, 0, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8string_equals_region_buf( dynTestArr2, 6, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8string_equals_region_buf( dynTestArr2, 11, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8string_equals_region_buf( dynTestArr2, 17, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8string_equals_region_buf( NULL, 3, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 0, equal ); // test utf8string_equals_region_str equal = utf8string_equals_region_str( dynTestArr1, 0, dynTestArr1 ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8string_equals_region_str( dynTestArr1, 0, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8string_equals_region_str( dynTestArr1, 5, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8string_equals_region_str( dynTestArr1, 0, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8string_equals_region_str( dynTestArr2, 6, dynTestArr1 ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8string_equals_region_str( dynTestArr2, 17, dynTestArr1 ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8string_equals_region_str( NULL, 0, "Hi" ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8string_equals_region_str( "", 0, NULL ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8string_equals_region_str( dynTestArr1, -1, NULL ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8string_equals_region_str( NULL, 0, NULL ); TEST_ASSERT_EQUAL_INT( 0, equal ); } static void testLength(void) { int len; /* check utf8string_get_length */ len = utf8string_get_length( NULL ); TEST_ASSERT_EQUAL_INT( 0, len ); len = utf8string_get_length( "" ); TEST_ASSERT_EQUAL_INT( 0, len ); len = utf8string_get_length( "12" ); TEST_ASSERT_EQUAL_INT( 2, len ); len = utf8string_get_length( "123456789 123456789" ); TEST_ASSERT_EQUAL_INT( 19, len ); } static void testStartsWith(void) { // prepare int matches; char dynTestArr1[] = "Hello"; utf8stringbuf_t dynTestBuf1 = utf8stringbuf(dynTestArr1); char dynTestArr2[] = "Hello World"; utf8stringbuf_t dynTestBuf2 = utf8stringbuf(dynTestArr2); // test utf8string_starts_with_str matches = utf8string_starts_with_str( dynTestArr1, dynTestArr2 ); TEST_ASSERT_EQUAL_INT( 0, matches ); matches = utf8string_starts_with_str( dynTestArr2, dynTestArr1 ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8string_starts_with_str( dynTestArr1, dynTestArr1 ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8string_starts_with_str( dynTestArr1, "" ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8string_starts_with_str( dynTestArr1, NULL ); TEST_ASSERT_EQUAL_INT( 0, matches ); matches = utf8string_starts_with_str( NULL, NULL ); TEST_ASSERT_EQUAL_INT( 0, matches ); matches = utf8string_starts_with_str( NULL, dynTestArr1 ); TEST_ASSERT_EQUAL_INT( 0, matches ); matches = utf8string_starts_with_str( "", "" ); TEST_ASSERT_EQUAL_INT( 1, matches ); // test utf8string_starts_with_buf matches = utf8string_starts_with_buf( dynTestArr1, dynTestBuf2 ); TEST_ASSERT_EQUAL_INT( 0, matches ); matches = utf8string_starts_with_buf( dynTestArr2, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8string_starts_with_buf( dynTestArr1, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8string_starts_with_buf( dynTestArr1, utf8stringbuf("") ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8string_starts_with_buf( NULL, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 0, matches ); matches = utf8string_starts_with_buf( "", utf8stringbuf("") ); TEST_ASSERT_EQUAL_INT( 1, matches ); } static void testEndsWith(void) { // prepare int matches; char dynTestArr1[] = "World"; utf8stringbuf_t dynTestBuf1 = utf8stringbuf(dynTestArr1); char dynTestArr2[] = "Hello World"; utf8stringbuf_t dynTestBuf2 = utf8stringbuf(dynTestArr2); // test utf8stringbuf_ends_with_str matches = utf8string_ends_with_str( dynTestArr1, dynTestArr2 ); TEST_ASSERT_EQUAL_INT( 0, matches ); matches = utf8string_ends_with_str( dynTestArr2, dynTestArr1 ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8string_ends_with_str( dynTestArr1, dynTestArr1 ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8string_ends_with_str( dynTestArr1, "" ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8string_ends_with_str( dynTestArr1, NULL ); TEST_ASSERT_EQUAL_INT( 0, matches ); matches = utf8string_ends_with_str( NULL, NULL ); TEST_ASSERT_EQUAL_INT( 0, matches ); matches = utf8string_ends_with_str( NULL, dynTestArr1 ); TEST_ASSERT_EQUAL_INT( 0, matches ); matches = utf8string_ends_with_str( "", "" ); TEST_ASSERT_EQUAL_INT( 1, matches ); // test utf8stringbuf_ends_with_buf matches = utf8string_ends_with_buf( dynTestArr1, dynTestBuf2 ); TEST_ASSERT_EQUAL_INT( 0, matches ); matches = utf8string_ends_with_buf( dynTestArr2, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8string_ends_with_buf( dynTestArr1, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8string_ends_with_buf( dynTestArr1, utf8stringbuf("") ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8string_ends_with_buf( NULL, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 0, matches ); matches = utf8string_ends_with_buf( "", utf8stringbuf("") ); TEST_ASSERT_EQUAL_INT( 1, matches ); } static void testFindFirst(void) { int pos; char srchArr3[] = "N/A"; utf8stringbuf_t srchBuf3 = UTF8STRINGBUF(srchArr3); pos = utf8string_find_first_str( NULL, srchArr3); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_first_str( NULL, ""); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_first_str( NULL, NULL); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_first_str( srchArr3, srchArr3); TEST_ASSERT_EQUAL_INT( 0, pos ); pos = utf8string_find_first_str( "", srchArr3); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_first_str( "_N/A_N/A", srchArr3); TEST_ASSERT_EQUAL_INT( 1, pos ); pos = utf8string_find_first_str( "_n/a_n/a", srchArr3); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_first_buf( NULL, srchBuf3); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_first_buf( NULL, utf8stringbuf( "" ) ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_first_buf( srchArr3, srchBuf3); TEST_ASSERT_EQUAL_INT( 0, pos ); pos = utf8string_find_first_buf( "", srchBuf3); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_first_buf( "_N/A_N/A", srchBuf3); TEST_ASSERT_EQUAL_INT( 1, pos ); pos = utf8string_find_first_buf( "_n/a_n/a", srchBuf3); TEST_ASSERT_EQUAL_INT( -1, pos ); } static void testFindNext(void) { int pos; char srchArr1[10] = "aaaa"; utf8stringbuf_t srchBuf1 = UTF8STRINGBUF(srchArr1); pos = utf8string_find_next_buf( "", srchBuf1, -17 ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_next_buf( "", srchBuf1, 17 ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_next_buf( "", srchBuf1, 0 ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_next_buf( NULL, srchBuf1, 0 ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_next_buf( NULL, srchBuf1, 1 ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_next_buf( "aaaaaa", srchBuf1, 1 ); TEST_ASSERT_EQUAL_INT( 1, pos ); pos = utf8string_find_next_buf( "abaaaaa", srchBuf1, 1 ); TEST_ASSERT_EQUAL_INT( 2, pos ); pos = utf8string_find_next_str( NULL, NULL, 1000 ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_next_str( NULL, NULL, 0 ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_next_str( "aaaaaa", srchArr1, 1 ); TEST_ASSERT_EQUAL_INT( 1, pos ); pos = utf8string_find_next_str( "aaaaaa", srchArr1, 3 ); TEST_ASSERT_EQUAL_INT( -1, pos ); } static void testFindLast(void) { int pos; char srchArr1[10] = "aaaab"; utf8stringbuf_t srchBuf1 = UTF8STRINGBUF(srchArr1); char srchArr3[] = "N/A"; utf8stringbuf_t srchBuf3 = UTF8STRINGBUF(srchArr3); pos = utf8string_find_last_buf( NULL, srchBuf3 ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_last_buf( NULL, utf8stringbuf("") ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_last_buf( srchArr1, utf8stringbuf("aa") ); TEST_ASSERT_EQUAL_INT( 2, pos ); pos = utf8string_find_last_buf( "", srchBuf1 ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_last_buf( srchArr3, srchBuf3 ); TEST_ASSERT_EQUAL_INT( 0, pos ); pos = utf8string_find_last_buf( srchArr1, utf8stringbuf("bb") ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_last_str( srchArr1, NULL ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_last_str( NULL, NULL ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8string_find_last_str( srchArr1, "" ); TEST_ASSERT_EQUAL_INT( 5, pos ); pos = utf8string_find_last_str( srchArr1, "aaa" ); TEST_ASSERT_EQUAL_INT( 1, pos ); } static void testCharAt(void) { utf8codepoint_t result; char dynTestArr1[6] = "He\xE2\x82\xAC"; /* check utf8string_get_char_at */ result = utf8string_get_char_at( dynTestArr1, 0 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 'H', utf8codepoint_get_char(result) ); result = utf8string_get_char_at( dynTestArr1, 2 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( 3, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0x20ac, utf8codepoint_get_char(result) ); result = utf8string_get_char_at( dynTestArr1, 3 ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( UTF8CODEPOINT_INVALID_LEN, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0x0, utf8codepoint_get_char(result) ); result = utf8string_get_char_at( dynTestArr1, 5 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0x0, utf8codepoint_get_char(result) ); result = utf8string_get_char_at( dynTestArr1, 6 ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( UTF8CODEPOINT_INVALID_LEN, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0x0, utf8codepoint_get_char(result) ); result = utf8string_get_char_at( NULL, 0 ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( UTF8CODEPOINT_INVALID_LEN, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0x0, utf8codepoint_get_char(result) ); } static void testCharAtLoops(void) { utf8codepoint_t result; char dynTestArr1[6] = "He\xE2\x82\xAC"; /* loop over all bytes, independant of code-points */ unsigned int countCodePoints = 0; unsigned int byte_length = utf8string_get_length( dynTestArr1 ); for ( int idx = 0; idx < byte_length; idx ++ ) { result = utf8string_get_char_at( dynTestArr1, idx ); if ( utf8codepoint_is_valid(result) ) { countCodePoints ++; } } TEST_ASSERT_EQUAL_INT( 3, countCodePoints ); /* loop over all code points */ countCodePoints = 0; byte_length = utf8string_get_length( dynTestArr1 ); for ( int idx = 0; idx < byte_length; ) { result = utf8string_get_char_at( dynTestArr1, idx ); if ( utf8codepoint_is_valid(result) ) { countCodePoints ++; idx += utf8codepoint_get_length(result); } else { break; } } TEST_ASSERT_EQUAL_INT( 3, countCodePoints ); /* loop over buffer size */ /* this is possibly the fastest way to loop over the buffer contents */ countCodePoints = 0; unsigned int byteSize = utf8string_get_size( dynTestArr1 ); for ( int idx = 0; idx < byteSize; ) { result = utf8string_get_char_at( dynTestArr1, idx ); if ( utf8codepoint_is_valid(result) && ( utf8codepoint_get_char(result) != '\0' )) { countCodePoints ++; idx += utf8codepoint_get_length(result); } else { break; } } TEST_ASSERT_EQUAL_INT( 3, countCodePoints ); /* safely loop over buffer size, using a position-index and a loop-limit-counter */ countCodePoints = 0; byteSize = utf8string_get_size( dynTestArr1 ); unsigned int currentIndex = 0; for ( int loopCount = 0; loopCount < byteSize; loopCount ++ ) { result = utf8string_get_char_at( dynTestArr1, currentIndex ); if ( utf8codepoint_is_valid(result) && ( utf8codepoint_get_char(result) != '\0' )) { countCodePoints ++; currentIndex += utf8codepoint_get_length(result); } else { break; } } TEST_ASSERT_EQUAL_INT( 3, countCodePoints ); } static void testParseInt(void) { unsigned int byte_length; int64_t number; utf8error_t u8err; u8err = utf8string_parse_int( NULL, &byte_length, &number ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_NULL_PARAM, u8err ); u8err = utf8string_parse_int( "", &byte_length, &number ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_NOT_FOUND, u8err ); TEST_ASSERT_EQUAL_INT( 0, byte_length ); TEST_ASSERT_EQUAL_INT( 0, number ); u8err = utf8string_parse_int( " void", &byte_length, &number ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_NOT_FOUND, u8err ); TEST_ASSERT_EQUAL_INT( 0, byte_length ); TEST_ASSERT_EQUAL_INT( 0, number ); u8err = utf8string_parse_int( "0", NULL, &number ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, u8err ); TEST_ASSERT_EQUAL_INT( 0, number ); u8err = utf8string_parse_int( "-9223372036854775809", &byte_length, &number ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, u8err ); TEST_ASSERT_EQUAL_INT( 20, byte_length ); TEST_ASSERT( (0==number)||(LLONG_MIN==number) ); u8err = utf8string_parse_int( "+9223372036854775808", &byte_length, &number ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, u8err ); TEST_ASSERT_EQUAL_INT( 20, byte_length ); TEST_ASSERT( (0==number)||(LLONG_MAX==number) ); u8err = utf8string_parse_int( "15", &byte_length, &number ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, u8err ); TEST_ASSERT_EQUAL_INT( 2, byte_length ); TEST_ASSERT_EQUAL_INT( 15, number ); u8err = utf8string_parse_int( "-15", &byte_length, &number ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, u8err ); TEST_ASSERT_EQUAL_INT( 3, byte_length ); TEST_ASSERT_EQUAL_INT( -15, number ); u8err = utf8string_parse_int( "+2000111222", &byte_length, &number ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, u8err ); TEST_ASSERT_EQUAL_INT( 11, byte_length ); TEST_ASSERT( +2000111222 == number ); u8err = utf8string_parse_int( "-2000111222", &byte_length, &number ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, u8err ); TEST_ASSERT_EQUAL_INT( 11, byte_length ); TEST_ASSERT( -2000111222 == number ); u8err = utf8string_parse_int( " 15 cm", &byte_length, &number ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, u8err ); TEST_ASSERT_EQUAL_INT( 4, byte_length ); TEST_ASSERT_EQUAL_INT( 15, number ); u8err = utf8string_parse_int( " -015 cm", &byte_length, &number ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, u8err ); TEST_ASSERT_EQUAL_INT( 5, byte_length ); TEST_ASSERT_EQUAL_INT( -15, number ); } /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/test/unit/utf8string_test.h000066400000000000000000000014711415120503000252230ustar00rootroot00000000000000/* File: utf8string_test.h; Copyright and License: see below */ #ifndef UTF8STRING_TEST_H_ #define UTF8STRING_TEST_H_ #include "test_suite.h" test_suite_t utf8string_test_get_list(void); #endif /*UTF8STRING_TEST_H_*/ /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/test/unit/utf8stringbuf_cross_language.cpp000066400000000000000000000057031415120503000302720ustar00rootroot00000000000000/* File: utf8stringbuf_cross_language.cpp; Copyright and License: see below */ #include "utf8stringbuf_cross_language.h" #ifdef __cplusplus static char unitTestResultArr[512]; static utf8stringbuf_t unitTestResultBuf = UTF8STRINGBUF( unitTestResultArr ); static utf8stringbufCrossLanguage utf8StringBufCrossLanguageObject = utf8stringbufCrossLanguage(); utf8stringbuf_t utf8stringbuf_cross_language_create_stringbuf( const char* charSequence ) { return utf8StringBufCrossLanguageObject.CreateStringBuf( charSequence ); } int utf8stringbuf_cross_language_check_stringbuf( utf8stringbuf_t buf, const char* charSequence ) { return utf8StringBufCrossLanguageObject.CheckStringBuf( buf, charSequence ); } utf8stringbuf_t utf8stringbufCrossLanguage::CreateStringBuf( const char* charSequence ) { utf8stringbuf_clear( unitTestResultBuf ); utf8stringbuf_append_str( unitTestResultBuf, charSequence ); /* do some stuff simply to test some utf8stringbuf functions from cpp linkage context */ { int len = utf8stringbuf_get_length( unitTestResultBuf ); const int64_t someNumber = -98345769308475LL; utf8stringbuf_append_int( unitTestResultBuf, someNumber ); int len2 = utf8stringbuf_find_last_str( unitTestResultBuf, "-9834" ); if ( len == len2 ) { utf8stringbuf_delete_to_end( unitTestResultBuf, len2 ); } } return unitTestResultBuf; } int utf8stringbufCrossLanguage::CheckStringBuf( const utf8stringbuf_t buf, const char* charSequence ) { /* do some stuff simply to test some utf8stringbuf functions from cpp linkage context */ if ( utf8stringbuf_get_length(buf) >= 5 ) { char unitTestArr[5]; utf8stringbuf_t unitTestBuf = UTF8STRINGBUF( unitTestArr ); utf8stringbuf_copy_region_from_buf( unitTestBuf, buf, 1, 4 ); utf8stringbuf_delete( buf, 1, 4 ); utf8stringbuf_insert_buf( buf, 1, unitTestBuf ); } if ( CompareCodePoint( utf8stringbuf_get_char_at( buf, 0 ), charSequence ) != 1 ) { return 0; } return utf8stringbuf_equals_str( buf, charSequence ); } int utf8stringbufCrossLanguage::CompareCodePoint( utf8codepoint_t theChar, const char* charSequence ) { utf8codepoint_t test = utf8codepoint_init( charSequence, strlen(charSequence) ); return ( utf8codepoint_get_char(theChar) == utf8codepoint_get_char(test) ) ? (1) : (0); } #endif /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/test/unit/utf8stringbuf_cross_language.h000066400000000000000000000040211415120503000277270ustar00rootroot00000000000000/* File: utf8stringbuf_cross_language.h; Copyright and License: see below */ #ifndef UTF8STRINGBUF_CROSS_LANGUAGE_H_ #define UTF8STRINGBUF_CROSS_LANGUAGE_H_ #include "util/string/utf8stringbuf.h" #include "util/string/utf8codepoint.h" #ifdef __cplusplus /* function to test if a utf8stringbuf_t generated by cpp code works in c linkage environment */ extern "C" utf8stringbuf_t utf8stringbuf_cross_language_create_stringbuf( const char* charSequence ); /* function to test if a utf8stringbuf_t generated in c linkage environment works in cpp code */ extern "C" int utf8stringbuf_cross_language_check_stringbuf( utf8stringbuf_t buf, const char* charSequence ); /* class to initialize and test a utf8stringbuf_t struct */ class utf8stringbufCrossLanguage { public: utf8stringbuf_t CreateStringBuf( const char* charSequence ); int CheckStringBuf( const utf8stringbuf_t buf, const char* charSequence ); private: int CompareCodePoint( utf8codepoint_t theChar, const char* charSequence ); }; #else /* function to test if a utf8stringbuf_t generated by cpp code works in c linkage environment */ extern utf8stringbuf_t utf8stringbuf_cross_language_create_stringbuf( const char* charSequence ); /* function to test if a utf8stringbuf_t generated in c linkage environment works in cpp code */ extern int utf8stringbuf_cross_language_check_stringbuf( utf8stringbuf_t buf, const char* charSequence ); #endif #endif /*UTF8STRINGBUF_CROSS_LANGUAGE_H_*/ /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/test/unit/utf8stringbuf_performance.c000066400000000000000000000304001415120503000272270ustar00rootroot00000000000000/* File: utf8stringbuf_performance.c; Copyright and License: see below */ #include "util/string/utf8stringbuf.h" #include "utf8stringbuf_performance.h" #include "test_assert.h" #include #include #include static void setUp(void); static void tearDown(void); static void testClear(void); static void testAppendStr(void); static void testFindFirst(void); static void testInsertAndDelete(void); enum testSize_enum{ TEST_BUF_SIZE=100000, /*!< string buffer size used for tests */ }; enum testPerformanceReq_enum{ TEST_MAX_DURATION_PERCENT=125, /*!< maximum acceptable duration in percent - compared to standard c string library */ TEST_MAX_DURATION_FACTOR=8, /*!< maximum acceptable duration as factor for slow functions */ }; static char posixBuf[TEST_BUF_SIZE]; static char utf8sbArr[TEST_BUF_SIZE]; static utf8stringbuf_t utf8sbBuf = UTF8STRINGBUF( utf8sbArr ); static char tempArr[TEST_BUF_SIZE]; static int CpuPerfFactor = 0; test_suite_t utf8stringbuf_performance_get_list(void) { test_suite_t result; test_suite_init( &result, "utf8CodePointTest", &setUp, &tearDown ); test_suite_add_test_case( &result, "testClear", &testClear ); test_suite_add_test_case( &result, "testAppendStr", &testAppendStr ); test_suite_add_test_case( &result, "testFindFirst", &testFindFirst ); test_suite_add_test_case( &result, "testInsertAndDelete", &testInsertAndDelete ); return result; } static void setUp(void) { if ( CpuPerfFactor == 0 ) { /* measure the time until 3 times new clock measurements were registered */ clock_t posixCurrent; clock_t posixLast; int newValues = 0; posixLast = clock(); while ( newValues < 3 ) { for ( int loop1 = 0; loop1 < 1000; loop1 ++ ) { memset( posixBuf, '\0', TEST_BUF_SIZE ); } CpuPerfFactor += 1000; posixCurrent = clock(); if ( posixCurrent != posixLast ) { newValues ++; posixLast = posixCurrent; } } /* print the time measurement */ printf( "CPU-Speed correction factor: %d\n", CpuPerfFactor ); } } static void tearDown(void) { } static void testClear(void) { clock_t posixStart; clock_t posixEnd; clock_t posixDiff; clock_t utf8sbStart; clock_t utf8sbEnd; clock_t utf8sbDiff; int loopMax = 40*CpuPerfFactor; /* measure the time of the standard posix function */ posixStart = clock(); for ( int loop1 = 0; loop1 < loopMax; loop1 ++ ) { memset( posixBuf, '\0', TEST_BUF_SIZE ); } posixEnd = clock(); posixDiff = posixEnd - posixStart; /* measure the time of the utf8stringbuf function */ utf8sbStart = clock(); for ( int loop2 = 0; loop2 < loopMax; loop2 ++ ) { utf8stringbuf_clear( utf8sbBuf ); } utf8sbEnd = clock(); utf8sbDiff = utf8sbEnd - utf8sbStart; /* check the result */ int equal = memcmp( posixBuf, utf8sbArr, TEST_BUF_SIZE ); TEST_ASSERT_EQUAL_INT( 0, equal ); /* print the time measurement */ printf( "CPU-Time: %ld (POSIX) vs %ld (utf8stringbuf) [s/%ld] for clear\n", (long)posixDiff, (long)utf8sbDiff, (long)CLOCKS_PER_SEC ); /* We are at least TEST_MAX_DURATION_PERCENT as fast as POSIX: */ TEST_ASSERT( ( utf8sbDiff * 100 ) <= ( posixDiff * TEST_MAX_DURATION_PERCENT ) ); } static void testAppendStr(void) { clock_t posixStart; clock_t posixEnd; clock_t posixDiff; clock_t utf8sbStart; clock_t utf8sbEnd; clock_t utf8sbDiff; int loopMax = 80*CpuPerfFactor; /* measure the time of the standard posix function */ posixStart = clock(); for ( int loop1 = 0; loop1 < loopMax; loop1 ++ ) { if (( loop1 & 0x3ff ) == 0 ) { /* reset */ posixBuf[0] = '\0'; } int pos = strlen( posixBuf ); //strncpy( &(posixBuf[pos]), "Hello World", TEST_BUF_SIZE-pos ); strncat( &(posixBuf[pos]), "Hello World 345678[20]345678[30]34567890", TEST_BUF_SIZE-pos ); } posixEnd = clock(); posixDiff = posixEnd - posixStart; /* measure the time of the utf8stringbuf function */ utf8sbStart = clock(); for ( int loop2 = 0; loop2 < loopMax; loop2 ++ ) { if (( loop2 & 0x3ff ) == 0 ) { /* reset */ utf8sbArr[0] = '\0'; } utf8stringbuf_append_str( utf8sbBuf, "Hello World 345678[20]345678[30]34567890" ); } utf8sbEnd = clock(); utf8sbDiff = utf8sbEnd - utf8sbStart; /* check the result */ //int equal = strcmp( posixBuf, utf8sbArr ); int equal = memcmp( posixBuf, utf8sbArr, TEST_BUF_SIZE ); TEST_ASSERT_EQUAL_INT( 0, equal ); /* print the time measurement */ printf( "CPU-Time: %ld (POSIX) vs %ld (utf8stringbuf) [s/%ld] for append string\n", (long)posixDiff, (long)utf8sbDiff, (long)CLOCKS_PER_SEC ); /* We are at least TEST_MAX_DURATION_PERCENT as fast as POSIX: */ TEST_ASSERT( ( utf8sbDiff * 100 ) <= ( posixDiff * TEST_MAX_DURATION_PERCENT ) ); } static void testFindFirst(void) { clock_t posixStart; clock_t posixEnd; clock_t posixDiff; clock_t utf8sbStart; clock_t utf8sbEnd; clock_t utf8sbDiff; int loopMax = 20*CpuPerfFactor; char* posixLoc = NULL; int utf8sbLoc = -1; /* measure the time of the standard posix function */ posixStart = clock(); for ( int loop1 = 0; loop1 < loopMax; loop1 ++ ) { posixLoc = strstr( posixBuf, "1234"); } posixEnd = clock(); posixDiff = posixEnd - posixStart; /* measure the time of the utf8stringbuf function */ utf8sbStart = clock(); for ( int loop2 = 0; loop2 < loopMax; loop2 ++ ) { utf8sbLoc = utf8stringbuf_find_first_str( utf8sbBuf, "1234" ); } utf8sbEnd = clock(); utf8sbDiff = utf8sbEnd - utf8sbStart; /* check the result */ TEST_ASSERT( posixLoc == NULL ); TEST_ASSERT_EQUAL_INT( -1, utf8sbLoc ); /* print the time measurement */ printf( "CPU-Time: %ld (POSIX) vs %ld (utf8stringbuf) [s/%ld] for find string\n", (long)posixDiff, (long)utf8sbDiff, (long)CLOCKS_PER_SEC ); /* We are at least TEST_MAX_DURATION_PERCENT as fast as POSIX: */ TEST_ASSERT( ( utf8sbDiff * 100 ) <= ( posixDiff * TEST_MAX_DURATION_PERCENT ) ); } const char EXAMPLE_DATA[] = "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890" "12345678[10]345678[20]345678[30]345678[40]345678[50]345678[60]34567890"; /*enum TestPositionsAndSizes { TEST_INDEX = 21, TEST_SHIFT = 678, };*/ static void testInsertAndDelete(void) { clock_t posixStart; clock_t posixEnd; clock_t posixDiff; clock_t utf8sbStart; clock_t utf8sbEnd; clock_t utf8sbDiff; int loopMax = 200*CpuPerfFactor; /* prepare test */ memcpy( posixBuf, EXAMPLE_DATA, sizeof(EXAMPLE_DATA) ); /* measure the time of the standard posix function */ posixStart = clock(); for ( int loop1 = 0; loop1 < loopMax; loop1 ++ ) { const int TEST_INDEX = (loop1 & 0x1f); const int TEST_SHIFT = (loop1 & 0x3ff); /* insert TEST_SHIFT at pos TEST_INDEX */ /* Note: memcpy must not copy between overlapping regions. Therefore, we need to copy to a tempArr first */ memcpy( tempArr, &(posixBuf[TEST_INDEX]), sizeof(EXAMPLE_DATA)-TEST_INDEX ); memcpy( &(posixBuf[TEST_INDEX+TEST_SHIFT]), tempArr, sizeof(EXAMPLE_DATA)-TEST_INDEX ); memcpy( &(posixBuf[TEST_INDEX]), EXAMPLE_DATA, TEST_SHIFT ); /* delete TEST_SHIFT at pos TEST_INDEX */ memcpy( tempArr, &(posixBuf[TEST_INDEX+TEST_SHIFT]), sizeof(EXAMPLE_DATA)-TEST_INDEX ); memcpy( &(posixBuf[TEST_INDEX]), tempArr, sizeof(EXAMPLE_DATA)-TEST_INDEX ); } posixEnd = clock(); posixDiff = posixEnd - posixStart; /* prepare test */ memcpy( utf8sbArr, EXAMPLE_DATA, sizeof(EXAMPLE_DATA) ); /* measure the time of the utf8stringbuf function */ utf8sbStart = clock(); for ( int loop2 = 0; loop2 < loopMax; loop2 ++ ) { const int TEST_INDEX = (loop2 & 0x1f); const int TEST_SHIFT = (loop2 & 0x3ff); /* insert TEST_SHIFT at pos TEST_INDEX */ utf8stringbuf_insert_str( utf8sbBuf, TEST_INDEX, &(EXAMPLE_DATA[sizeof(EXAMPLE_DATA)-1-TEST_SHIFT]) ); /* delete TEST_SHIFT at pos TEST_INDEX */ utf8stringbuf_delete( utf8sbBuf, TEST_INDEX, TEST_SHIFT ); } utf8sbEnd = clock(); utf8sbDiff = utf8sbEnd - utf8sbStart; /* check the result */ int equal = memcmp( posixBuf, utf8sbArr, sizeof(EXAMPLE_DATA) ); TEST_ASSERT_EQUAL_INT( 0, equal ); /* print the time measurement */ printf( "CPU-Time: %ld (POSIX) vs %ld (utf8stringbuf) [s/%ld] for insert and delete\n", (long)posixDiff, (long)utf8sbDiff, (long)CLOCKS_PER_SEC ); /* We are at least TEST_MAX_DURATION_PERCENT as fast as POSIX: */ TEST_ASSERT( ( utf8sbDiff ) <= ( posixDiff * TEST_MAX_DURATION_FACTOR ) ); } /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/test/unit/utf8stringbuf_performance.h000066400000000000000000000015531415120503000272430ustar00rootroot00000000000000/* File: utf8stringbuf_performance.h; Copyright and License: see below */ #ifndef UTF8STRINGBUF_PERFORMANCE_H_ #define UTF8STRINGBUF_PERFORMANCE_H_ #include "test_suite.h" test_suite_t utf8stringbuf_performance_get_list(void); #endif /*UTF8STRINGBUF_PERFORMANCE_H_*/ /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/test/unit/utf8stringbuf_test.c000066400000000000000000003121061415120503000257130ustar00rootroot00000000000000/* File: utf8stringbuf_test.c; Copyright and License: see below */ #include "utf8stringbuf_test.h" #include "util/string/utf8stringbuf.h" #include "utf8stringbuf_cross_language.h" #include "test_assert.h" #include #include #include static const char * const SQL_ENCODE[][2] = { { "\0", "\\0" }, // within strings, null cannot be represented. { "\x09", "\\t" }, { "\x0a", "\\n" }, { "\x0d", "\\r" }, { "\x0e", "\\b" }, { "\x1a", "\\z" }, { "\"", "\\\"" }, { "'", "\\'" }, { "\\", "\\\\" }, { "%", "\\%" }, // % replacement only needed in searches by LIKE operator { "_", "\\_" }, // _ replacement only needed in searches by LIKE operator { NULL, NULL } }; static const char *const XML_ENCODE[][2] = { { "<", "<" }, { ">", ">" }, { "&", "&" }, { "\"", """ }, // " replacement only needed in attribute values { "'", "'" }, // " replacement only needed in attribute values { NULL, NULL } }; const char END[] = ""; static const char *const TO_UPPER_CASE[][2] = { { "a", "A" }, { "b", "B" }, { "c", "C" }, { "d", "D" }, { "e", "E" }, { "f", "F" }, { "g", "G" }, { "h", "H" }, { "i", "I" }, { "j", "J" }, { "k", "K" }, { "l", "L" }, { "m", "M" }, { "n", "N" }, { "o", "O" }, { "p", "P" }, { "q", "Q" }, { "r", "R" }, { "s", "S" }, { "t", "T" }, { "u", "U" }, { "v", "V" }, { "w", "W" }, { "x", "X" }, { "y", "Y" }, { "z", "Z" }, { "\xc3\xa4", "\xc3\x84" }, { "\xc3\xb6", "\xc3\x96" }, { "\xc3\xbc", "\xc3\x9c" }, { NULL, NULL } }; static const char *const TO_LOWER_CASE[][2] = { { "A", "a" }, { "B", "b" }, { "C", "c" }, { "D", "d" }, { "E", "e" }, { "F", "f" }, { "G", "g" }, { "H", "h" }, { "I", "i" }, { "J", "j" }, { "K", "k" }, { "L", "l" }, { "M", "m" }, { "N", "n" }, { "O", "o" }, { "P", "p" }, { "Q", "q" }, { "R", "r" }, { "S", "s" }, { "T", "t" }, { "U", "u" }, { "V", "v" }, { "W", "w" }, { "X", "x" }, { "Y", "y" }, { "Z", "z" }, { "\xc3\x84", "\xc3\xa4" }, { "\xc3\x96", "\xc3\xb6" }, { "\xc3\x9c", "\xc3\xbc" }, { NULL, NULL } }; static const char *const SHRINK_DUPLICATES_EXCEPT_Z[][2] = { { "aa", "A" }, { "bb", "B" }, { "cc", "C" }, { "dd", "D" }, { "ee", "E" }, { "ff", "F" }, { "gg", "G" }, { "hh", "H" }, { "ii", "I" }, { "jj", "J" }, { "kk", "K" }, { "ll", "L" }, { "mm", "M" }, { "nn", "N" }, { "oo", "O" }, { "pp", "P" }, { "qq", "Q" }, { "rr", "R" }, { "ss", "S" }, { "tt", "T" }, { "uu", "U" }, { "vv", "V" }, { "ww", "W" }, { "xx", "X" }, { "yy", "Y" }, { NULL, NULL } }; static const char *const EXPAND_SINGLES_EXCEPT_Z[][2] = { { "A", "aa" }, { "B", "bb" }, { "C", "cc" }, { "D", "dd" }, { "E", "ee" }, { "F", "ff" }, { "G", "gg" }, { "H", "hh" }, { "I", "ii" }, { "J", "jj" }, { "K", "kk" }, { "L", "ll" }, { "M", "mm" }, { "N", "nn" }, { "O", "oo" }, { "P", "pp" }, { "Q", "qq" }, { "R", "rr" }, { "S", "ss" }, { "T", "tt" }, { "U", "uu" }, { "V", "vv" }, { "W", "ww" }, { "X", "xx" }, { "Y", "yy" }, { NULL, NULL } }; static char oneByteArr[] = ""; static utf8stringbuf_t oneByteBuf = UTF8STRINGBUF(oneByteArr); static char fourByteArr[4] = "12"; static utf8stringbuf_t fourByteBuf = UTF8STRINGBUF(fourByteArr); struct InitTestStruct { char urlArr[8192]; utf8stringbuf_t url; pthread_mutex_t lock; }; typedef struct InitTestStruct InitTest_t; static InitTest_t structTest = { "http://", UTF8STRINGBUF( structTest.urlArr), PTHREAD_MUTEX_INITIALIZER, }; #define INITTEST(testStr,this_) { testStr, UTF8STRINGBUF( this_.urlArr), PTHREAD_MUTEX_INITIALIZER, } static InitTest_t structArrTest[] = { INITTEST( "svn://first", structArrTest[0] ), INITTEST( "http://second", structArrTest[1] ), INITTEST( "ftp://third", structArrTest[2] ), INITTEST( "file://last", structArrTest[3] ), }; static char ThousandPathNames[1000][256]; #define PATH_INIT(x) UTF8STRINGBUF( ThousandPathNames[x] ) #define FIVE_PATHS_INIT(x) PATH_INIT(x+0), PATH_INIT(x+1), PATH_INIT(x+2), PATH_INIT(x+3), PATH_INIT(x+4) #define TWENTY_PATHS_INIT(x) FIVE_PATHS_INIT(x+0), FIVE_PATHS_INIT(x+5), FIVE_PATHS_INIT(x+10), FIVE_PATHS_INIT(x+15) #define HUNDRED_PATHS_INIT(x) TWENTY_PATHS_INIT(x+0), TWENTY_PATHS_INIT(x+20), TWENTY_PATHS_INIT(x+40), TWENTY_PATHS_INIT(x+60), TWENTY_PATHS_INIT(x+80) static utf8stringbuf_t ThousandPaths[1000] = { HUNDRED_PATHS_INIT(0), HUNDRED_PATHS_INIT(100), HUNDRED_PATHS_INIT(200), HUNDRED_PATHS_INIT(300), HUNDRED_PATHS_INIT(400), HUNDRED_PATHS_INIT(500), HUNDRED_PATHS_INIT(600), HUNDRED_PATHS_INIT(700), HUNDRED_PATHS_INIT(800), HUNDRED_PATHS_INIT(900), }; enum { UTF8STRINGBUFTEST_MEGASIZE = (1024*1024), }; static char megaByteArr[UTF8STRINGBUFTEST_MEGASIZE] = ""; static utf8stringbuf_t megaByteBuf = UTF8STRINGBUF(megaByteArr); static void setUp(void); static void tearDown(void); static void testInit(void); static void testClear(void); static void testLength(void); static void testEquals(void); static void testEqualsRegion(void); static void testStartsWith(void); static void testEndsWith(void); static void testFindFirst(void); static void testFindNext(void); static void testFindLast(void); static void testCopyBuf(void); static void testCopyStr(void); static void testCopyWithCutUtf8(void); static void testCopyRegion(void); static void testReplaceRegion(void); static void testReplaceRegionExceededRanges(void); static void testReplaceRegionWithCutUtf8(void); static void testReplaceRegionBuf(void); static void testReplaceAll(void); static void testReplaceAllBadCases(void); static void testReplaceAllStr(void); static void testReplaceAllBuf(void); static void testInsertBuf(void); static void testInsertStr(void); static void testDelete(void); static void testDeleteToEnd(void); static void testDeleteFromEnd(void); static void testAppendStr(void); static void testAppendBuf(void); static void testAppendInt(void); static void testAppendHex(void); static void testAppendWStr(void); static void testAppendChar(void); static void testCharAt(void); static void testCharAtLoops(void); #ifdef __cplusplus static void testCrossLanguage(void); #endif static void testSplitIn2(void); static void testSplitIn3(void); static void testSplitIn4(void); static void testSplitIn5(void); static void testJoin(void); static void testSplitAndJoin(void); static void testGetEnd(void); test_suite_t utf8stringbuf_test_get_list(void) { test_suite_t result; test_suite_init( &result, "utf8StringBufTest", &setUp, &tearDown ); test_suite_add_test_case( &result, "testInit", &testInit ); test_suite_add_test_case( &result, "testClear", &testClear ); test_suite_add_test_case( &result, "testLength", &testLength ); test_suite_add_test_case( &result, "testEquals", &testEquals ); test_suite_add_test_case( &result, "testEqualsRegion", &testEqualsRegion ); test_suite_add_test_case( &result, "testStartsWith", &testStartsWith ); test_suite_add_test_case( &result, "testEndsWith", &testEndsWith ); test_suite_add_test_case( &result, "testFindFirst", &testFindFirst ); test_suite_add_test_case( &result, "testFindNext", &testFindNext ); test_suite_add_test_case( &result, "testFindLast", &testFindLast ); test_suite_add_test_case( &result, "testCopyBuf", &testCopyBuf ); test_suite_add_test_case( &result, "testCopyStr", &testCopyStr ); test_suite_add_test_case( &result, "testCopyWithCutUtf8", &testCopyWithCutUtf8 ); test_suite_add_test_case( &result, "testCopyRegion", &testCopyRegion ); test_suite_add_test_case( &result, "testReplaceRegion", &testReplaceRegion ); test_suite_add_test_case( &result, "testReplaceRegionExceededRanges", &testReplaceRegionExceededRanges ); test_suite_add_test_case( &result, "testReplaceRegionWithCutUtf8", &testReplaceRegionWithCutUtf8 ); test_suite_add_test_case( &result, "testReplaceRegionBuf", &testReplaceRegionBuf ); test_suite_add_test_case( &result, "testReplaceAll", &testReplaceAll ); test_suite_add_test_case( &result, "testReplaceAllBadCases", &testReplaceAllBadCases ); test_suite_add_test_case( &result, "testReplaceAllStr", &testReplaceAllStr ); test_suite_add_test_case( &result, "testReplaceAllBuf", &testReplaceAllBuf ); test_suite_add_test_case( &result, "testInsertBuf", &testInsertBuf ); test_suite_add_test_case( &result, "testInsertStr", &testInsertStr ); test_suite_add_test_case( &result, "testDelete", &testDelete ); test_suite_add_test_case( &result, "testDeleteToEnd", &testDeleteToEnd ); test_suite_add_test_case( &result, "testDeleteFromEnd", &testDeleteFromEnd ); test_suite_add_test_case( &result, "testAppendStr", &testAppendStr ); test_suite_add_test_case( &result, "testAppendBuf", &testAppendBuf ); test_suite_add_test_case( &result, "testAppendInt", &testAppendInt ); test_suite_add_test_case( &result, "testAppendHex", &testAppendHex ); test_suite_add_test_case( &result, "testAppendChar", &testAppendChar ); test_suite_add_test_case( &result, "testAppendWStr", &testAppendWStr ); test_suite_add_test_case( &result, "testCharAt", &testCharAt ); test_suite_add_test_case( &result, "testCharAtLoops", &testCharAtLoops ); #ifdef __cplusplus test_suite_add_test_case( &result, "testCrossLanguage", &testCrossLanguage ); #endif test_suite_add_test_case( &result, "testSplitIn2", &testSplitIn2 ); test_suite_add_test_case( &result, "testSplitIn3", &testSplitIn3 ); test_suite_add_test_case( &result, "testSplitIn4", &testSplitIn4 ); test_suite_add_test_case( &result, "testSplitIn5", &testSplitIn5 ); test_suite_add_test_case( &result, "testJoin", &testJoin ); test_suite_add_test_case( &result, "testSplitAndJoin", &testSplitAndJoin ); test_suite_add_test_case( &result, "testGetEnd", &testGetEnd ); return result; } static void setUp(void) { memset( megaByteArr, 'a', UTF8STRINGBUFTEST_MEGASIZE-1 ); megaByteArr[UTF8STRINGBUFTEST_MEGASIZE-1] = '\0'; megaByteArr[1000] = 'Z'; megaByteArr[1004] = 'Z'; megaByteArr[900000] = 'Z'; } static void tearDown(void) { } static void testInit(void) { /* check static initialization */ TEST_ASSERT( utf8stringbuf_get_string( oneByteBuf ) == oneByteArr ); TEST_ASSERT_EQUAL_INT( 1, utf8stringbuf_get_size( oneByteBuf ) ); TEST_ASSERT( utf8stringbuf_get_string( fourByteBuf ) == fourByteArr ); TEST_ASSERT_EQUAL_INT( 4, utf8stringbuf_get_size( fourByteBuf ) ); TEST_ASSERT( utf8stringbuf_get_string( megaByteBuf ) == megaByteArr ); TEST_ASSERT_EQUAL_INT( UTF8STRINGBUFTEST_MEGASIZE, utf8stringbuf_get_size( megaByteBuf ) ); /* check dynamic initialization */ char dynTestArr[] = "Hello"; utf8stringbuf_t dynTestBuf = utf8stringbuf(dynTestArr); TEST_ASSERT( utf8stringbuf_get_string( dynTestBuf ) == dynTestArr ); TEST_ASSERT_EQUAL_INT( 6, utf8stringbuf_get_size( dynTestBuf ) ); /* compile time initialization on stack */ char dynTestArr2[17] = ""; utf8stringbuf_t dynTestBuf2 = UTF8STRINGBUF( dynTestArr2 ); TEST_ASSERT( utf8stringbuf_get_string( dynTestBuf2 ) == dynTestArr2 ); TEST_ASSERT_EQUAL_INT( 17, utf8stringbuf_get_size( dynTestBuf2 ) ); /* check static struct initialization */ TEST_ASSERT( utf8stringbuf_get_string( structTest.url ) == structTest.urlArr ); TEST_ASSERT_EQUAL_INT( 8192, utf8stringbuf_get_size( structTest.url ) ); /* check static struct-array initialization */ TEST_ASSERT( utf8stringbuf_get_string( structArrTest[0].url ) == structArrTest[0].urlArr ); TEST_ASSERT_EQUAL_INT( 8192, utf8stringbuf_get_size( structArrTest[0].url ) ); TEST_ASSERT( utf8stringbuf_equals_str( structArrTest[0].url, "svn://first" )); TEST_ASSERT( utf8stringbuf_get_string( structArrTest[1].url ) == structArrTest[1].urlArr ); TEST_ASSERT_EQUAL_INT( 8192, utf8stringbuf_get_size( structArrTest[0].url ) ); TEST_ASSERT( utf8stringbuf_equals_str( structArrTest[1].url, "http://second" )); TEST_ASSERT( utf8stringbuf_get_string( structArrTest[2].url ) == structArrTest[2].urlArr ); TEST_ASSERT_EQUAL_INT( 8192, utf8stringbuf_get_size( structArrTest[0].url ) ); TEST_ASSERT( utf8stringbuf_equals_str( structArrTest[2].url, "ftp://third" )); TEST_ASSERT( utf8stringbuf_get_string( structArrTest[3].url ) == structArrTest[3].urlArr ); TEST_ASSERT_EQUAL_INT( 8192, utf8stringbuf_get_size( structArrTest[0].url ) ); TEST_ASSERT( utf8stringbuf_equals_str( structArrTest[3].url, "file://last" )); /* check static array initialization */ strcpy( ThousandPathNames[99], "one-hundred" ); TEST_ASSERT( utf8stringbuf_get_string( ThousandPaths[99] ) == ThousandPathNames[99] ); TEST_ASSERT_EQUAL_INT( 256, utf8stringbuf_get_size( ThousandPaths[99] ) ); TEST_ASSERT( utf8stringbuf_equals_str( ThousandPaths[99], "one-hundred" )); TEST_ASSERT( utf8stringbuf_get_string( ThousandPaths[100] ) == ThousandPathNames[100] ); TEST_ASSERT_EQUAL_INT( 256, utf8stringbuf_get_size( ThousandPaths[100] ) ); TEST_ASSERT( utf8stringbuf_equals_str( ThousandPaths[100], "" )); /* check runtime init function */ utf8stringbuf_t dynTestBuf3 = utf8stringbuf_init( 10, dynTestArr2 ); TEST_ASSERT( utf8stringbuf_get_string( dynTestBuf3 ) == dynTestArr2 ); TEST_ASSERT_EQUAL_INT( 10, utf8stringbuf_get_size( dynTestBuf3 ) ); } static void testClear(void) { /* clear regular string */ char dynTestArr[] = "Hello"; utf8stringbuf_t dynTestBuf = UTF8STRINGBUF( dynTestArr ); utf8stringbuf_clear ( dynTestBuf ); TEST_ASSERT( 0 == memcmp( utf8stringbuf_get_string( dynTestBuf ), "\0\0\0\0\0", 6 ) ); TEST_ASSERT_EQUAL_INT( 6, utf8stringbuf_get_size( dynTestBuf ) ); /* clear NULL */ utf8stringbuf_t dynTestBuf2 = utf8stringbuf( NULL ); utf8stringbuf_clear ( dynTestBuf2 ); TEST_ASSERT( 0 == memcmp( utf8stringbuf_get_string( dynTestBuf2 ), "", 1 ) ); TEST_ASSERT_EQUAL_INT( 1, utf8stringbuf_get_size( dynTestBuf2 ) ); } static void testEquals(void) { // prepare int equal; char dynTestArr1[] = "Hello"; utf8stringbuf_t dynTestBuf1 = utf8stringbuf(dynTestArr1); char dynTestArr2[] = "Hello World"; utf8stringbuf_t dynTestBuf2 = utf8stringbuf(dynTestArr2); // test utf8stringbuf_equals_buf equal = utf8stringbuf_equals_buf( dynTestBuf1, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8stringbuf_equals_buf( dynTestBuf1, dynTestBuf2 ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8stringbuf_equals_buf( dynTestBuf2, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8stringbuf_equals_buf( dynTestBuf2, oneByteBuf ); TEST_ASSERT_EQUAL_INT( 0, equal ); // test utf8stringbuf_equals_str equal = utf8stringbuf_equals_str( dynTestBuf1, dynTestArr1 ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8stringbuf_equals_str( dynTestBuf2, dynTestArr1 ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8stringbuf_equals_str( oneByteBuf, "Hi" ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8stringbuf_equals_str( oneByteBuf, NULL ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8stringbuf_equals_str( dynTestBuf1, NULL ); TEST_ASSERT_EQUAL_INT( 0, equal ); } static void testEqualsRegion(void) { // prepare int equal; char dynTestArr1[] = "Hello"; utf8stringbuf_t dynTestBuf1 = utf8stringbuf(dynTestArr1); char dynTestArr2[] = "Hello Hell Hello Hello"; utf8stringbuf_t dynTestBuf2 = utf8stringbuf(dynTestArr2); // test utf8stringbuf_equals_region_buf equal = utf8stringbuf_equals_region_buf( dynTestBuf1, 0, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8stringbuf_equals_region_buf( dynTestBuf1, -1, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8stringbuf_equals_region_buf( dynTestBuf1, 1, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8stringbuf_equals_region_buf( dynTestBuf1, 6, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8stringbuf_equals_region_buf( dynTestBuf1, 0, dynTestBuf2 ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8stringbuf_equals_region_buf( dynTestBuf2, 0, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8stringbuf_equals_region_buf( dynTestBuf2, 6, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8stringbuf_equals_region_buf( dynTestBuf2, 11, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8stringbuf_equals_region_buf( dynTestBuf2, 17, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8stringbuf_equals_region_buf( dynTestBuf2, 3, oneByteBuf ); TEST_ASSERT_EQUAL_INT( 1, equal ); // test utf8stringbuf_equals_region_str equal = utf8stringbuf_equals_region_str( dynTestBuf1, 0, dynTestArr1 ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8stringbuf_equals_region_str( dynTestBuf1, 0, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8stringbuf_equals_region_str( dynTestBuf1, 5, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8stringbuf_equals_region_str( dynTestBuf1, 0, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8stringbuf_equals_region_str( dynTestBuf2, 6, dynTestArr1 ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8stringbuf_equals_region_str( dynTestBuf2, 17, dynTestArr1 ); TEST_ASSERT_EQUAL_INT( 1, equal ); equal = utf8stringbuf_equals_region_str( oneByteBuf, 0, "Hi" ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8stringbuf_equals_region_str( oneByteBuf, 0, NULL ); TEST_ASSERT_EQUAL_INT( 0, equal ); equal = utf8stringbuf_equals_region_str( dynTestBuf1, -1, NULL ); TEST_ASSERT_EQUAL_INT( 0, equal ); } static void testLength(void) { int len; /* check utf8stringbuf_get_length */ len = utf8stringbuf_get_length( oneByteBuf ); TEST_ASSERT_EQUAL_INT( 0, len ); len = utf8stringbuf_get_length( fourByteBuf ); TEST_ASSERT_EQUAL_INT( 2, len ); len = utf8stringbuf_get_length( megaByteBuf ); TEST_ASSERT_EQUAL_INT( UTF8STRINGBUFTEST_MEGASIZE-1, len ); } static void testStartsWith(void) { // prepare int matches; char dynTestArr1[] = "Hello"; utf8stringbuf_t dynTestBuf1 = utf8stringbuf(dynTestArr1); char dynTestArr2[] = "Hello World"; utf8stringbuf_t dynTestBuf2 = utf8stringbuf(dynTestArr2); // test utf8stringbuf_starts_with_str matches = utf8stringbuf_starts_with_str( dynTestBuf1, dynTestArr2 ); TEST_ASSERT_EQUAL_INT( 0, matches ); matches = utf8stringbuf_starts_with_str( dynTestBuf2, dynTestArr1 ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8stringbuf_starts_with_str( dynTestBuf1, dynTestArr1 ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8stringbuf_starts_with_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8stringbuf_starts_with_str( dynTestBuf1, NULL ); TEST_ASSERT_EQUAL_INT( 0, matches ); matches = utf8stringbuf_starts_with_str( utf8stringbuf(""), "" ); TEST_ASSERT_EQUAL_INT( 1, matches ); // test utf8stringbuf_starts_with_buf matches = utf8stringbuf_starts_with_buf( dynTestBuf1, dynTestBuf2 ); TEST_ASSERT_EQUAL_INT( 0, matches ); matches = utf8stringbuf_starts_with_buf( dynTestBuf2, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8stringbuf_starts_with_buf( dynTestBuf1, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8stringbuf_starts_with_buf( dynTestBuf1, utf8stringbuf("") ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8stringbuf_starts_with_buf( utf8stringbuf(""), utf8stringbuf("") ); TEST_ASSERT_EQUAL_INT( 1, matches ); } static void testEndsWith(void) { // prepare int matches; char dynTestArr1[] = "World"; utf8stringbuf_t dynTestBuf1 = utf8stringbuf(dynTestArr1); char dynTestArr2[] = "Hello World"; utf8stringbuf_t dynTestBuf2 = utf8stringbuf(dynTestArr2); // test utf8stringbuf_ends_with_str matches = utf8stringbuf_ends_with_str( dynTestBuf1, dynTestArr2 ); TEST_ASSERT_EQUAL_INT( 0, matches ); matches = utf8stringbuf_ends_with_str( dynTestBuf2, dynTestArr1 ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8stringbuf_ends_with_str( dynTestBuf1, dynTestArr1 ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8stringbuf_ends_with_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8stringbuf_ends_with_str( dynTestBuf1, NULL ); TEST_ASSERT_EQUAL_INT( 0, matches ); matches = utf8stringbuf_ends_with_str( utf8stringbuf(""), "" ); TEST_ASSERT_EQUAL_INT( 1, matches ); // test utf8stringbuf_ends_with_buf matches = utf8stringbuf_ends_with_buf( dynTestBuf1, dynTestBuf2 ); TEST_ASSERT_EQUAL_INT( 0, matches ); matches = utf8stringbuf_ends_with_buf( dynTestBuf2, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8stringbuf_ends_with_buf( dynTestBuf1, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8stringbuf_ends_with_buf( dynTestBuf1, utf8stringbuf("") ); TEST_ASSERT_EQUAL_INT( 1, matches ); matches = utf8stringbuf_ends_with_buf( utf8stringbuf(""), utf8stringbuf("") ); TEST_ASSERT_EQUAL_INT( 1, matches ); } static void testCopyBuf(void) { int error; int equal; char dynTestArr1[] = "World"; utf8stringbuf_t dynTestBuf1 = utf8stringbuf(dynTestArr1); char dynTestArr2[] = "Hello World"; utf8stringbuf_t dynTestBuf2 = utf8stringbuf(dynTestArr2); /* check utf8stringbuf_copy_buf */ error = utf8stringbuf_copy_buf( dynTestBuf1, dynTestBuf2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_buf( oneByteBuf, dynTestBuf2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( oneByteBuf, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_buf( dynTestBuf2, dynTestBuf1 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_buf( dynTestBuf2, oneByteBuf ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testCopyStr(void) { int error; int equal; char dynTestArr1[] = "World"; utf8stringbuf_t dynTestBuf1 = utf8stringbuf(dynTestArr1); /* check utf8stringbuf_copy_str */ error = utf8stringbuf_copy_str( dynTestBuf1, "Hello World" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_str( oneByteBuf, "Hi" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( oneByteBuf, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_str( dynTestBuf1, NULL ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_NULL_PARAM, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_str( dynTestBuf1, "Hi" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hi" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_str( dynTestBuf1, "World" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "World" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testCopyWithCutUtf8(void) { int error; int equal; char dynTestArr1[3] = "Wo"; utf8stringbuf_t dynTestBuf1 = utf8stringbuf(dynTestArr1); char dynTestArr2[8] = "Hello W"; utf8stringbuf_t dynTestBuf2 = utf8stringbuf(dynTestArr2); /* check utf8stringbuf_copy_str, \xE2\x82\xAC is the euro symbol in utf8 */ error = utf8stringbuf_copy_str( dynTestBuf1, "\xE2\x82\xAC" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_str( dynTestBuf2, "\xE2\x82\xAC" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "\xE2\x82\xAC" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_str( dynTestBuf2, "\xE2\x82\xAC\xE2\x82\xAC" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "\xE2\x82\xAC\xE2\x82\xAC" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_str( dynTestBuf2, "\xE2\x82\xAC\xE2\x82\xAC\xE2\x82\xAC" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "\xE2\x82\xAC\xE2\x82\xAC" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_str( dynTestBuf2, "__\xE2\x82\xAC\xE2\x82\xAC" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "__\xE2\x82\xAC" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_str( dynTestBuf2, "_\xE2\x82\xAC\xE2\x82\xAC" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "_\xE2\x82\xAC\xE2\x82\xAC" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_str( dynTestBuf2, "_\xE2\x82\xAC\xE2\x82\xAC_" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "_\xE2\x82\xAC\xE2\x82\xAC" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* check utf8stringbuf_copy_str, \xC2\xA2 and \xF0\xA4\xAD\xA2 are other characters in utf8 */ error = utf8stringbuf_copy_str( dynTestBuf1, "\xC2\xA2_" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "\xC2\xA2" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_str( dynTestBuf1, "\xF0\xA4\xAD\xA2" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* check utf8stringbuf_copy_str, \xC2\xA2 but not \xFC\xA4\xAD\xA2\xAD\xA2 are other characters in utf8 */ error = utf8stringbuf_copy_str( dynTestBuf2, "\xC2\xA2\xFC\xA4\xAD\xA2\xAD\xA2" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "\xC2\xA2\xFC\xA4\xAD\xA2\xAD" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_str( dynTestBuf2, "\xC2\xA2_\xFC\xA4\xAD\xA2\xAD\xA2" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "\xC2\xA2_\xFC\xA4\xAD\xA2" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_str( dynTestBuf2, "\xC2\xA2_\xC2\xA2_\xC2\xA2" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "\xC2\xA2_\xC2\xA2_" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testFindFirst(void) { int pos; char srchArr1[] = "aaaaaaaaaaaaaaaaaaaaaaa"; utf8stringbuf_t srchBuf1 = utf8stringbuf(srchArr1); char srchArr2[100] = "aaaaaaaaaaaaaaaaaaaaZaa"; utf8stringbuf_t srchBuf2 = utf8stringbuf(srchArr2); char srchArr3[] = "N/A"; utf8stringbuf_t srchBuf3 = UTF8STRINGBUF(srchArr3); pos = utf8stringbuf_find_first_str( megaByteBuf, srchArr1); TEST_ASSERT_EQUAL_INT( 0, pos ); pos = utf8stringbuf_find_first_str( megaByteBuf, srchArr2); TEST_ASSERT_EQUAL_INT( 980, pos ); pos = utf8stringbuf_find_first_str( megaByteBuf, ""); TEST_ASSERT_EQUAL_INT( 0, pos ); pos = utf8stringbuf_find_first_str( megaByteBuf, NULL); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringbuf_find_first_str( megaByteBuf, srchArr3); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringbuf_find_first_str( oneByteBuf, srchArr3); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringbuf_find_first_str( srchBuf3, srchArr3); TEST_ASSERT_EQUAL_INT( 0, pos ); pos = utf8stringbuf_find_first_buf( megaByteBuf, srchBuf1); TEST_ASSERT_EQUAL_INT( 0, pos ); pos = utf8stringbuf_find_first_buf( megaByteBuf, srchBuf2); TEST_ASSERT_EQUAL_INT( 980, pos ); pos = utf8stringbuf_find_first_buf( megaByteBuf, oneByteBuf); TEST_ASSERT_EQUAL_INT( 0, pos ); pos = utf8stringbuf_find_first_buf( megaByteBuf, srchBuf3); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringbuf_find_first_buf( oneByteBuf, srchBuf3); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringbuf_find_first_buf( srchBuf3, srchBuf3); TEST_ASSERT_EQUAL_INT( 0, pos ); } static void testFindNext(void) { int pos; char srchArr1[10] = "aaaa"; utf8stringbuf_t srchBuf1 = UTF8STRINGBUF(srchArr1); char srchArr2[] = "aaaZaaa"; utf8stringbuf_t srchBuf2 = utf8stringbuf(srchArr2); char srchArr3[] = "N/A"; utf8stringbuf_t srchBuf3 = UTF8STRINGBUF(srchArr3); pos = utf8stringbuf_find_next_buf( oneByteBuf, srchBuf3, -17 ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringbuf_find_next_buf( oneByteBuf, srchBuf3, 17 ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringbuf_find_next_buf( oneByteBuf, srchBuf3, 0 ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringbuf_find_next_buf( srchBuf1, megaByteBuf, 1 ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringbuf_find_next_buf( megaByteBuf, srchBuf1, 0 ); TEST_ASSERT_EQUAL_INT( 0, pos ); pos = utf8stringbuf_find_next_buf( megaByteBuf, srchBuf1, 1 ); TEST_ASSERT_EQUAL_INT( 1, pos ); pos = utf8stringbuf_find_next_buf( megaByteBuf, srchBuf2, 1 ); TEST_ASSERT_EQUAL_INT( 997, pos ); pos = utf8stringbuf_find_next_buf( megaByteBuf, srchBuf2, 1001 ); TEST_ASSERT_EQUAL_INT( 1001, pos ); pos = utf8stringbuf_find_next_buf( megaByteBuf, srchBuf2, 1002 ); TEST_ASSERT_EQUAL_INT( 899997, pos ); pos = utf8stringbuf_find_next_buf( megaByteBuf, srchBuf2, 899998 ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringbuf_find_next_buf( megaByteBuf, srchBuf3, 1000 ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringbuf_find_next_str( megaByteBuf, NULL, 1000 ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringbuf_find_next_str( megaByteBuf, srchArr1, 1000 ); TEST_ASSERT_EQUAL_INT( 1005, pos ); } static void testFindLast(void) { int pos; char srchArr1[10] = "aaaa"; utf8stringbuf_t srchBuf1 = UTF8STRINGBUF(srchArr1); char srchArr2[] = "aaaZaaa"; utf8stringbuf_t srchBuf2 = utf8stringbuf(srchArr2); char srchArr3[] = "N/A"; utf8stringbuf_t srchBuf3 = UTF8STRINGBUF(srchArr3); pos = utf8stringbuf_find_last_buf( oneByteBuf, srchBuf3 ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringbuf_find_last_buf( srchBuf1, megaByteBuf ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringbuf_find_last_buf( megaByteBuf, srchBuf1 ); TEST_ASSERT_EQUAL_INT( UTF8STRINGBUFTEST_MEGASIZE - 1 - 4, pos ); pos = utf8stringbuf_find_last_buf( megaByteBuf, srchBuf2 ); TEST_ASSERT_EQUAL_INT( 899997, pos ); pos = utf8stringbuf_find_last_buf( megaByteBuf, srchBuf3 ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringbuf_find_last_buf( srchBuf2, srchBuf2 ); TEST_ASSERT_EQUAL_INT( 0, pos ); pos = utf8stringbuf_find_last_str( megaByteBuf, NULL ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringbuf_find_last_str( megaByteBuf, "" ); TEST_ASSERT_EQUAL_INT( UTF8STRINGBUFTEST_MEGASIZE - 1, pos ); pos = utf8stringbuf_find_last_str( srchBuf2, "aaa" ); TEST_ASSERT_EQUAL_INT( 4, pos ); } static void testCopyRegion(void) { int error; int equal; char dynTestArr1[3] = ""; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); char dynTestArr2[8] = "Hello W"; utf8stringbuf_t dynTestBuf2 = UTF8STRINGBUF(dynTestArr2); /* check utf8stringbuf_copy_region_from_buf: standard cases */ error = utf8stringbuf_copy_region_from_buf( dynTestBuf1, dynTestBuf2, 0, 2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "He" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_region_from_buf( dynTestBuf1, dynTestBuf2, 5, 2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, " W" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* check utf8stringbuf_copy_region_from_buf: illegal ranges */ error = utf8stringbuf_copy_region_from_buf( dynTestBuf1, dynTestBuf2, -1, 2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_region_from_buf( dynTestBuf1, dynTestBuf2, 0, -2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_region_from_buf( dynTestBuf1, dynTestBuf2, 0, 0 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* check utf8stringbuf_copy_region_from_buf: out of bounds */ error = utf8stringbuf_copy_region_from_buf( dynTestBuf1, dynTestBuf2, 6, 2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "W" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_region_from_buf( dynTestBuf1, dynTestBuf2, 8, 2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_region_from_buf( dynTestBuf1, dynTestBuf2, 1, 4 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "el" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* check utf8stringbuf_copy_region_from_str */ error = utf8stringbuf_copy_region_from_str( dynTestBuf1, "Hello", 0, 4 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "He" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_region_from_str( dynTestBuf1, "Hello", 0, 2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "He" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_region_from_str( dynTestBuf1, "Hello", 3, 2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "lo" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_region_from_str( dynTestBuf1, "Hello", 4, 2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "o" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_region_from_str( dynTestBuf1, "Hello", 5, 2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_region_from_str( dynTestBuf1, "Hello", 7, 2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_region_from_str( dynTestBuf1, "Hello", -1, 2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_region_from_str( dynTestBuf1, "Hello", 3, 0 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_region_from_str( dynTestBuf1, "Hello", 3, -1 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_region_from_str( dynTestBuf1, "\xC2\xA2_\xC2\xA2", 2, 3 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "_" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_region_from_str( dynTestBuf1, "\xC2\xA2_\xC2\xA2", 0, 3 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "\xC2\xA2" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_region_from_str( dynTestBuf1, "\xC2\xA2_\xC2\xA2", 3, 2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "\xC2\xA2" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_copy_region_from_str( dynTestBuf1, NULL, 0, 0 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_NULL_PARAM, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testReplaceRegion(void) { int error; int equal; char dynTestArr1[15] = ""; utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(13,&(dynTestArr1[1])); /* check that markers at start and end are not overwritten */ dynTestArr1[0]=127; dynTestArr1[14]=127; /* check utf8stringbuf_replace_region_by_str: standard cases */ error = utf8stringbuf_replace_region_by_str( dynTestBuf1, 0, 0, "all inserted" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "all inserted" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_replace_region_by_str( dynTestBuf1, 0, 12, "all replaced" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "all replaced" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_replace_region_by_str( dynTestBuf1, 1, 5, " 5 " ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "a 5 placed" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_replace_region_by_str( dynTestBuf1, 2, 1, "333" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); /*printf("%s",dynTestArr1);*/ equal = utf8stringbuf_equals_str( dynTestBuf1, "a 333 placed" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_replace_region_by_str( dynTestBuf1, 1, 10, "" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "ad" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_replace_region_by_str( dynTestBuf1, 2, 0, "." ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "ad." ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_replace_region_by_str( dynTestBuf1, 0, 3, NULL ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* check that markers at start and end are not overwritten */ TEST_ASSERT_EQUAL_INT( 127, dynTestArr1[0] ); TEST_ASSERT_EQUAL_INT( 127, dynTestArr1[14] ); } static void testReplaceRegionExceededRanges(void) { int error; int equal; char dynTestArr1[15] = ""; utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(13,&(dynTestArr1[1])); /* check that markers at start and end are not overwritten */ dynTestArr1[0]=127; dynTestArr1[14]=127; /* check utf8stringbuf_replace_region_by_str: range exceeded cases */ utf8stringbuf_copy_str( dynTestBuf1, "Hello" ); error = utf8stringbuf_replace_region_by_str( dynTestBuf1, -1, 2, "replaced" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "Hello" ); error = utf8stringbuf_replace_region_by_str( dynTestBuf1, 0, 12, "replaced" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "replaced" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "Hello" ); error = utf8stringbuf_replace_region_by_str( dynTestBuf1, 2, 12, "." ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "He." ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "Hello" ); error = utf8stringbuf_replace_region_by_str( dynTestBuf1, 0, 14, "replaced" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "replaced" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /*TEST_ASSERT_EQUAL_INT( 127, dynTestArr1[14] );*/ utf8stringbuf_copy_str( dynTestBuf1, "Hello" ); error = utf8stringbuf_replace_region_by_str( dynTestBuf1, 6, 0, "replaced" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /*TEST_ASSERT_EQUAL_INT( 127, dynTestArr1[14] );*/ utf8stringbuf_copy_str( dynTestBuf1, "Hello" ); error = utf8stringbuf_replace_region_by_str( dynTestBuf1, 5, 0, "12345678" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello1234567" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "Hello" ); error = utf8stringbuf_replace_region_by_str( dynTestBuf1, 2, 0, "12345678" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "He12345678ll" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "Hello" ); error = utf8stringbuf_replace_region_by_str( dynTestBuf1, 2, 0, "1234567890" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "He1234567890" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "Hello" ); error = utf8stringbuf_replace_region_by_str( dynTestBuf1, 2, 0, "1234567890A" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "He1234567890" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* check that markers at start and end are not overwritten */ TEST_ASSERT_EQUAL_INT( 127, dynTestArr1[0] ); TEST_ASSERT_EQUAL_INT( 127, dynTestArr1[14] ); } static void testReplaceRegionWithCutUtf8(void) { int error; int equal; char dynTestArr1[15] = ""; utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(13,&(dynTestArr1[1])); /* check that markers at start and end are not overwritten */ dynTestArr1[0]=127; dynTestArr1[14]=127; /* check utf8stringbuf_copy_str, \xE2\x82\xAC is the euro symbol in utf8 */ utf8stringbuf_copy_str( dynTestBuf1, "Hello \xE2\x82\xAC" ); error = utf8stringbuf_replace_region_by_str( dynTestBuf1, 2, 0, "1234" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "He1234llo " ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "Hello" ); error = utf8stringbuf_replace_region_by_str( dynTestBuf1, 2, 0, "12345678\xE2\x82\xAC" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "He12345678" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "Hello " ); error = utf8stringbuf_replace_region_by_str( dynTestBuf1, 6, 0, "1234\xE2\x82\xAC" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello 1234" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* check that markers at start and end are not overwritten */ TEST_ASSERT_EQUAL_INT( 127, dynTestArr1[0] ); TEST_ASSERT_EQUAL_INT( 127, dynTestArr1[14] ); } static void testReplaceRegionBuf(void) { /* utf8stringbuf_replace_region_by_buf is just a wrapper around utf8stringbuf_replace_region_by_str */ /* therefore, we do only one test */ int error; int equal; char dynTestArr1[7] = "Helllo"; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); char dynTestArr2[] = "ll"; utf8stringbuf_t dynTestBuf2 = UTF8STRINGBUF(dynTestArr2); /* check utf8stringbuf_replace_region_by_buf */ error = utf8stringbuf_replace_region_by_buf( dynTestBuf1, 2, 3, dynTestBuf2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testReplaceAll(void) { int error; int equal; char dynTestArr1[20] = "He&l<'"; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); /* check utf8stringbuf_replace_all */ error = utf8stringbuf_replace_all( dynTestBuf1, &XML_ENCODE ); /*printf( "%s", utf8stringbuf_get_string(dynTestBuf1) );*/ TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "He&l<'" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_replace_all( dynTestBuf1, &SQL_ENCODE ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "He&l<'" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_replace_all( dynTestBuf1, &XML_ENCODE ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "He&amp;l&lt" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* change nearly everything */ error = utf8stringbuf_replace_all( megaByteBuf, &TO_UPPER_CASE ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_starts_with_str( megaByteBuf, "AAAAAAAAAA" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* change everything */ error = utf8stringbuf_replace_all( megaByteBuf, &TO_LOWER_CASE ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_starts_with_str( megaByteBuf, "aaaaaaaaaaaaaaaaaaaaaaaaaaa" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* change nothing */ error = utf8stringbuf_replace_all( megaByteBuf, &TO_LOWER_CASE ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_starts_with_str( megaByteBuf, "aaaaaaaaaaaaaaaaaaaaaaaaaaa" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* shrink because performance hungry function */ utf8stringbuf_delete_to_end( megaByteBuf, 20000 ); /* shrink at each replacement */ error = utf8stringbuf_replace_all( megaByteBuf, &SHRINK_DUPLICATES_EXCEPT_Z ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_starts_with_str( megaByteBuf, "AAAAAAAAAA" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* grow at each replacement */ error = utf8stringbuf_replace_all( megaByteBuf, &EXPAND_SINGLES_EXCEPT_Z ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_starts_with_str( megaByteBuf, "aaaaaaaaaaaaaaaaaaaaaaaaaaa" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static const char *const TEST_PATTERNS[][2] = { { "", "" }, { "", NULL }, { "Z", NULL }, { "Y", "yyy" }, { "Hello", "Hello World" }, { "World", "Hello World" }, { "Hello World", "" }, { "\xE2\x82\xAC", "EUR" }, { "EUR", "\xE2\x82\xAC" }, { "5E", "5 \xE2\x82\xAC" }, { NULL, "anything" } }; static void testReplaceAllBadCases(void) { int error; int equal; char dynTestArr1[32] = ""; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); char dynTestArr2[8] = ""; utf8stringbuf_t dynTestBuf2 = UTF8STRINGBUF(dynTestArr2); /* check utf8stringbuf_replace_all */ utf8stringbuf_copy_str( dynTestBuf1, "Hello World" ); error = utf8stringbuf_replace_all( dynTestBuf1, &TEST_PATTERNS ); /*printf( "%s", utf8stringbuf_get_string(dynTestBuf1) );*/ TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello World Hello World" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* replace everything, including shrinking */ utf8stringbuf_copy_str( dynTestBuf2, "\xE2\x82\xAC" "Z" "\xE2\x82\xAC" ); error = utf8stringbuf_replace_all( dynTestBuf2, &TEST_PATTERNS ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "EUREUR" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* test null pattern*/ utf8stringbuf_copy_str( dynTestBuf2, "\xE2\x82\xAC" "Z" "\xE2\x82\xAC" ); error = utf8stringbuf_replace_all( dynTestBuf2, NULL ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_NULL_PARAM, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "\xE2\x82\xAC" "Z" "\xE2\x82\xAC" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* try to cut trailing string code point */ utf8stringbuf_copy_str( dynTestBuf2, "\xE2\x82\xAC" "Y" "\xE2\x82\xAC" ); error = utf8stringbuf_replace_all( dynTestBuf2, &TEST_PATTERNS ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "EURyyy" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* first shrink, then grow, fit exactly*/ utf8stringbuf_copy_str( dynTestBuf2, "ZZaY" "\xE2\x82\xAC" ); error = utf8stringbuf_replace_all( dynTestBuf2, &TEST_PATTERNS ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "ayyyEUR" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* first shrink, then grow, cut after second byte of multibyte code point*/ utf8stringbuf_copy_str( dynTestBuf2, "ZaaY" "\xE2\x82\xAC" ); error = utf8stringbuf_replace_all( dynTestBuf2, &TEST_PATTERNS ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "aayyy" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* first grow, then shrink, cut after first byte of multibyte code point*/ utf8stringbuf_copy_str( dynTestBuf2, "YZZa" "\xE2\x82\xAC" ); error = utf8stringbuf_replace_all( dynTestBuf2, &TEST_PATTERNS ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "yyya" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* first grow, then shrink, cut after second byte of multibyte code point*/ utf8stringbuf_copy_str( dynTestBuf2, "YZa" "\xE2\x82\xAC" ); error = utf8stringbuf_replace_all( dynTestBuf2, &TEST_PATTERNS ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "yyya" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* try to cut replacement string*/ utf8stringbuf_copy_str( dynTestBuf2, "aZWorld" ); error = utf8stringbuf_replace_all( dynTestBuf2, &TEST_PATTERNS ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "aHello " ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* try to cut replacement code point */ utf8stringbuf_copy_str( dynTestBuf2, "Y5EHell" ); error = utf8stringbuf_replace_all( dynTestBuf2, &TEST_PATTERNS ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "yyy5 " ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* try to cut trailing string code point */ utf8stringbuf_copy_str( dynTestBuf2, "a5E" "\xE2\x82\xAC" ); error = utf8stringbuf_replace_all( dynTestBuf2, &TEST_PATTERNS ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf2, "a5 " "\xE2\x82\xAC" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testReplaceAllStr(void) { /* utf8stringbuf_replace_all_str_by_str is just a wrapper around utf8stringbuf_replace_all */ /* therefore, we do only two tests */ int error; int equal; char dynTestArr1[7] = "Helllo"; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); /* check utf8stringbuf_replace_all_str_by_str */ error = utf8stringbuf_replace_all_str_by_str( dynTestBuf1, NULL, "" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_NULL_PARAM, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Helllo" ); TEST_ASSERT_EQUAL_INT( 1, equal ); error = utf8stringbuf_replace_all_str_by_str( dynTestBuf1, "lo", "o!" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello!" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testReplaceAllBuf(void) { /* utf8stringbuf_replace_all_buf_by_buf is just a wrapper around utf8stringbuf_replace_all */ /* therefore, we do only one test */ int error; int equal; char dynTestArr1[7] = "Helllo"; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); /* check utf8stringbuf_replace_all_buf_by_buf */ error = utf8stringbuf_replace_all_buf_by_buf( dynTestBuf1, utf8stringbuf("ll"), utf8stringbuf("l") ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testInsertBuf(void) { /* utf8stringbuf_insert_buf is just a wrapper around utf8stringbuf_replace_region_by_str */ /* therefore, we do only one test */ int error; int equal; char dynTestArr1[6] = "Heo"; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); char dynTestArr2[] = "ll"; utf8stringbuf_t dynTestBuf2 = UTF8STRINGBUF(dynTestArr2); /* check utf8stringbuf_insert_buf */ error = utf8stringbuf_insert_buf( dynTestBuf1, 2, dynTestBuf2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testInsertStr(void) { /* utf8stringbuf_insert_str is just a wrapper around utf8stringbuf_replace_region_by_str */ /* therefore, we do only one test */ int error; int equal; char dynTestArr1[6] = "He"; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); /* check utf8stringbuf_insert_str */ error = utf8stringbuf_insert_str( dynTestBuf1, 2, "llo" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testDelete(void) { /* utf8stringbuf_delete is just a wrapper around utf8stringbuf_replace_region_by_str */ /* therefore, we do only one test */ int error; int equal; char dynTestArr1[12] = "Hellllllllo"; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); /* check utf8stringbuf_delete */ error = utf8stringbuf_delete( dynTestBuf1, 4, 6 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testDeleteFromEnd(void) { /* utf8stringbuf_delete is just a wrapper around utf8stringbuf_replace_region_by_str */ /* therefore, we do only one test */ int error; int equal; char dynTestArr1[12] = "Hellllllllo"; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); /* check utf8stringbuf_delete_from_end */ error = utf8stringbuf_delete_from_end( dynTestBuf1, 7 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hell" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testDeleteToEnd(void) { /* utf8stringbuf_delete is just a wrapper around utf8stringbuf_replace_region_by_str */ /* therefore, we do only one test */ int error; int equal; char dynTestArr1[12] = "Hellllllllo"; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); /* check utf8stringbuf_delete_to_end */ error = utf8stringbuf_delete_to_end( dynTestBuf1, 4 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hell" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testAppendStr(void) { int error; int equal; char dynTestArr1[6] = ""; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); /* check utf8stringbuf_append_str */ utf8stringbuf_copy_str( dynTestBuf1, "Hell" ); error = utf8stringbuf_append_str( dynTestBuf1, "o" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "" ); error = utf8stringbuf_append_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "Hello" ); error = utf8stringbuf_append_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "Hello" ); error = utf8stringbuf_append_str( dynTestBuf1, NULL ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_NULL_PARAM, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "Hell" ); error = utf8stringbuf_append_str( dynTestBuf1, "\xC2\xA2" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hell" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "Hell" ); error = utf8stringbuf_append_str( dynTestBuf1, "o!" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "Hel" ); error = utf8stringbuf_append_str( dynTestBuf1, "\xC2\xA2!" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hel\xC2\xA2" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testAppendBuf(void) { int error; int equal; char dynTestArr1[6] = ""; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); char dynTestArr2[] = "l\xC2\xA2"; utf8stringbuf_t dynTestBuf2 = UTF8STRINGBUF(dynTestArr2); /* check utf8stringbuf_append_buf */ utf8stringbuf_copy_str( dynTestBuf1, "He" ); error = utf8stringbuf_append_buf( dynTestBuf1, dynTestBuf2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hel\xC2\xA2" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "Hel" ); error = utf8stringbuf_append_buf( dynTestBuf1, dynTestBuf2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hell" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "Hello" ); error = utf8stringbuf_append_buf( dynTestBuf1, dynTestBuf2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testAppendInt(void) { int error; int equal; char dynTestArr1[6] = ""; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); /* check utf8stringbuf_append_int */ utf8stringbuf_copy_str( dynTestBuf1, "12" ); error = utf8stringbuf_append_int( dynTestBuf1, 345 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "12345" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "" ); error = utf8stringbuf_append_int( dynTestBuf1, -1234 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "-1234" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "1234" ); error = utf8stringbuf_append_int( dynTestBuf1, 0 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "12340" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "12345" ); error = utf8stringbuf_append_int( dynTestBuf1, 6 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "12345" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "1" ); error = utf8stringbuf_append_int( dynTestBuf1, 234567 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "12345" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "1234" ); error = utf8stringbuf_append_int( dynTestBuf1, -1 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "1234-" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testAppendHex(void) { int error; int equal; char dynTestArr1[6] = ""; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); /* check utf8stringbuf_append_hex */ utf8stringbuf_copy_str( dynTestBuf1, "0x" ); error = utf8stringbuf_append_hex( dynTestBuf1, -1 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "0xfff" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "0x" ); error = utf8stringbuf_append_hex( dynTestBuf1, 0 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "0x0" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "0x" ); error = utf8stringbuf_append_hex( dynTestBuf1, 0x1000555 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "0x100" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testAppendChar(void) { int error; int equal; char dynTestArr1[6] = ""; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); /* check utf8stringbuf_append_char */ utf8stringbuf_copy_str( dynTestBuf1, "Hell" ); error = utf8stringbuf_append_char( dynTestBuf1, 'o' ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* append one byte too much */ utf8stringbuf_copy_str( dynTestBuf1, "Hello" ); error = utf8stringbuf_append_char( dynTestBuf1, 'o' ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* check utf8stringbuf_append_char */ utf8stringbuf_copy_str( dynTestBuf1, "He" ); error = utf8stringbuf_append_char( dynTestBuf1, 0x20ac ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "He\xE2\x82\xAC" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* append one byte too much */ utf8stringbuf_copy_str( dynTestBuf1, "Hel" ); error = utf8stringbuf_append_char( dynTestBuf1, 0x20ac ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hel" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* append illegal code point */ utf8stringbuf_clear( dynTestBuf1 ); error = utf8stringbuf_append_char( dynTestBuf1, 0x80000000 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_NOT_A_CODEPOINT, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testAppendWStr(void) { int error; int equal; char dynTestArr1[6] = ""; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); /* check utf8stringbuf_append_wstr */ wchar_t *wideString = L"lo"; utf8stringbuf_copy_str( dynTestBuf1, "Hel" ); error = utf8stringbuf_append_wstr( dynTestBuf1, wideString ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* check utf8stringbuf_append_wstr with multibyte */ const wchar_t *wideString2 = L"e\x20ac"; utf8stringbuf_copy_str( dynTestBuf1, "H" ); error = utf8stringbuf_append_wstr( dynTestBuf1, wideString2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "He\xE2\x82\xAC" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* check utf8stringbuf_append_wstr with truncation */ utf8stringbuf_copy_str( dynTestBuf1, "He" ); error = utf8stringbuf_append_wstr( dynTestBuf1, wideString2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hee" ); TEST_ASSERT_EQUAL_INT( 1, equal ); utf8stringbuf_copy_str( dynTestBuf1, "Hello" ); error = utf8stringbuf_append_wstr( dynTestBuf1, wideString2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Hello" ); TEST_ASSERT_EQUAL_INT( 1, equal ); /* check utf8stringbuf_append_wstr with NULL */ utf8stringbuf_copy_str( dynTestBuf1, "He" ); error = utf8stringbuf_append_wstr( dynTestBuf1, NULL ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_NULL_PARAM, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "He" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } static void testCharAt(void) { utf8codepoint_t result; char dynTestArr1[6] = "He\xE2\x82\xAC"; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); /* check utf8stringbuf_get_char_at */ result = utf8stringbuf_get_char_at( dynTestBuf1, 0 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 'H', utf8codepoint_get_char(result) ); result = utf8stringbuf_get_char_at( dynTestBuf1, 2 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( 3, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0x20ac, utf8codepoint_get_char(result) ); result = utf8stringbuf_get_char_at( dynTestBuf1, 3 ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( UTF8CODEPOINT_INVALID_LEN, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0x0, utf8codepoint_get_char(result) ); result = utf8stringbuf_get_char_at( dynTestBuf1, 5 ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( 1, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0x0, utf8codepoint_get_char(result) ); /* check example from documentation */ char testArr[] = "\xC2\xAE 2005 A.A. \xC2\xAE 2006-2012 B.B."; utf8stringbuf_t testBuf = UTF8STRINGBUF(testArr); result = utf8stringbuf_get_char_at( testBuf, 13 ); TEST_ASSERT_EQUAL_INT( 0xae, utf8codepoint_get_char(result) ); /* check undefined behaviour */ result = utf8stringbuf_get_char_at( dynTestBuf1, 6 ); TEST_ASSERT_EQUAL_INT( 0, utf8codepoint_is_valid(result) ); TEST_ASSERT_EQUAL_INT( UTF8CODEPOINT_INVALID_LEN, utf8codepoint_get_length(result) ); TEST_ASSERT_EQUAL_INT( 0x0, utf8codepoint_get_char(result) ); } static void testCharAtLoops(void) { utf8codepoint_t result; char dynTestArr1[6] = "He\xE2\x82\xAC"; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); /* loop over all bytes, independant of code-points */ unsigned int countCodePoints = 0; unsigned int byte_length = utf8stringbuf_get_length( dynTestBuf1 ); for ( int idx = 0; idx < byte_length; idx ++ ) { result = utf8stringbuf_get_char_at( dynTestBuf1, idx ); if ( utf8codepoint_is_valid(result) ) { countCodePoints ++; } } TEST_ASSERT_EQUAL_INT( 3, countCodePoints ); /* loop over all code points */ countCodePoints = 0; byte_length = utf8stringbuf_get_length( dynTestBuf1 ); for ( int idx = 0; idx < byte_length; ) { result = utf8stringbuf_get_char_at( dynTestBuf1, idx ); if ( utf8codepoint_is_valid(result) ) { countCodePoints ++; idx += utf8codepoint_get_length(result); } else { break; } } TEST_ASSERT_EQUAL_INT( 3, countCodePoints ); /* loop over buffer size */ /* this is possibly the fastest way to loop over the buffer contents */ countCodePoints = 0; unsigned int byteSize = utf8stringbuf_get_size( dynTestBuf1 ); for ( int idx = 0; idx < byteSize; ) { result = utf8stringbuf_get_char_at( dynTestBuf1, idx ); if ( utf8codepoint_is_valid(result) && ( utf8codepoint_get_char(result) != '\0' )) { countCodePoints ++; idx += utf8codepoint_get_length(result); } else { break; } } TEST_ASSERT_EQUAL_INT( 3, countCodePoints ); /* safely loop over buffer size, using a position-index and a loop-limit-counter */ countCodePoints = 0; byteSize = utf8stringbuf_get_size( dynTestBuf1 ); unsigned int currentIndex = 0; for ( int loopCount = 0; loopCount < byteSize; loopCount ++ ) { result = utf8stringbuf_get_char_at( dynTestBuf1, currentIndex ); if ( utf8codepoint_is_valid(result) && ( utf8codepoint_get_char(result) != '\0' )) { countCodePoints ++; currentIndex += utf8codepoint_get_length(result); } else { break; } } TEST_ASSERT_EQUAL_INT( 3, countCodePoints ); } #ifdef __cplusplus static void testCrossLanguage(void) { int success; int equal; char dynTestArr1[] = "World, Hello!"; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); static const char dynTestString2[] = "Hello World!"; utf8stringbuf_t dynTestBuf2; #ifdef __cplusplus TEST_FAIL( "testCrossLanguage was run in c++ linkage environment." ); #endif dynTestBuf2 = utf8stringbuf_cross_language_create_stringbuf( dynTestString2 ); equal = utf8stringbuf_equals_str( dynTestBuf2, dynTestString2 ); TEST_ASSERT_EQUAL_INT( 1, equal ); success = utf8stringbuf_cross_language_check_stringbuf( dynTestBuf1, "World, Hello!" ); TEST_ASSERT_EQUAL_INT( 1, success ); } #endif static void testSplitIn2(void) { utf8string2tuple_t tuple; int equals; /* test good case */ { char dynTestArr10_withBorders[9] = " H\xE2\x82\xAC\0z "; char *dynTestArr10 = &(dynTestArr10_withBorders[1]); utf8stringbuf_t dynTestBuf10 = utf8stringbuf_init(6,dynTestArr10); tuple = utf8stringbuf_split_in_2( dynTestBuf10, 1 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, tuple.error ); equals = memcmp( "H\0\xE2\x82\xAC", dynTestArr10, 6 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr10[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr10[2]) == tuple.second ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr10_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr10_withBorders[7] ); } /* test good case, empty first string */ { char dynTestArr11_withBorders[9] = " H\xE2\x82\xAC\0z "; char *dynTestArr11 = &(dynTestArr11_withBorders[1]); utf8stringbuf_t dynTestBuf11 = utf8stringbuf_init(6,dynTestArr11); tuple = utf8stringbuf_split_in_2( dynTestBuf11, 0 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, tuple.error ); equals = memcmp( "\0H\xE2\x82\xAC", dynTestArr11, 6 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr11[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr11[1]) == tuple.second ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr11_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr11_withBorders[7] ); } /* test good case, empty second string */ { char dynTestArr12_withBorders[9] = " H\xE2\x82\xAC\0z "; char *dynTestArr12 = &(dynTestArr12_withBorders[1]); utf8stringbuf_t dynTestBuf12 = utf8stringbuf_init(6,dynTestArr12); tuple = utf8stringbuf_split_in_2( dynTestBuf12, 4 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, tuple.error ); equals = memcmp( "H\xE2\x82\xAC\0", dynTestArr12, 6 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr12[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr12[5]) == tuple.second ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr12_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr12_withBorders[7] ); } /* test good case, both strings empty */ { char dynTestArr13_withBorders[9] = " \0trash "; char *dynTestArr13 = &(dynTestArr13_withBorders[1]); utf8stringbuf_t dynTestBuf13 = utf8stringbuf_init(6,dynTestArr13); tuple = utf8stringbuf_split_in_2( dynTestBuf13, 0 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, tuple.error ); equals = memcmp( "\0\0\0\0\0", dynTestArr13, 6 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr13[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr13[1]) == tuple.second ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr13_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr13_withBorders[7] ); } /* test truncation of second string only */ { char dynTestArr1_withBorders[9] = " He\xE2\x82\xAC\0 "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(6,dynTestArr1); tuple = utf8stringbuf_split_in_2( dynTestBuf1, 1 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, tuple.error ); equals = memcmp( "H\0e\0\0", dynTestArr1, 6 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr1[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr1[2]) == tuple.second ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[7] ); } /* test truncation of both strings */ { /* this is not possible, but this is a try: */ char dynTestArr2_withBorders[9] = " He\xE2\x82\xAC\0 "; char *dynTestArr2 = &(dynTestArr2_withBorders[1]); utf8stringbuf_t dynTestBuf2 = utf8stringbuf_init(6,dynTestArr2); tuple = utf8stringbuf_split_in_2( dynTestBuf2, 5 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, tuple.error ); equals = memcmp( "He\xE2\x82\xAC", dynTestArr2, 6 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr2[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr2[5]) == tuple.second ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr2_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr2_withBorders[7] ); } /* test for illegal parameters: -1 */ { char dynTestArr3_withBorders[9] = " He\xE2\x82\xAC\0 "; char *dynTestArr3 = &(dynTestArr3_withBorders[1]); utf8stringbuf_t dynTestBuf3 = utf8stringbuf_init(6,dynTestArr3); tuple = utf8stringbuf_split_in_2( dynTestBuf3, -1 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, tuple.error ); equals = memcmp( "He\xE2\x82\xAC", dynTestArr3, 6 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr3[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr3[5]) == tuple.second ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr3_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr3_withBorders[7] ); } /* test for illegal parameters: 5 */ { char dynTestArr4_withBorders[9] = " H\xE2\x82\xAC\0z "; char *dynTestArr4 = &(dynTestArr4_withBorders[1]); utf8stringbuf_t dynTestBuf4 = utf8stringbuf_init(6,dynTestArr4); tuple = utf8stringbuf_split_in_2( dynTestBuf4, 5 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, tuple.error ); equals = memcmp( "H\xE2\x82\xAC", dynTestArr4, 5 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr4[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr4[4]) == tuple.second ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr4_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr4_withBorders[7] ); } } static void testSplitIn3(void) { utf8string3tuple_t tuple; int equals; /* test standard case */ { char dynTestArr1_withBorders[9] = " He\0yzz "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(6,dynTestArr1); tuple = utf8stringbuf_split_in_3( dynTestBuf1, 0, 1 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, tuple.error ); equals = memcmp( "\0H\0e\0", dynTestArr1, 6 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr1[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr1[1]) == tuple.second ); TEST_ASSERT( &(dynTestArr1[3]) == tuple.third ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[7] ); } /* test full buffer case, no truncation */ { char dynTestArr1_withBorders[9] = " \xE2\x82\xAC\0yz "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(6,dynTestArr1); tuple = utf8stringbuf_split_in_3( dynTestBuf1, 0, 0 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, tuple.error ); equals = memcmp( "\0\0\xE2\x82\xAC", dynTestArr1, 6 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr1[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr1[1]) == tuple.second ); TEST_ASSERT( &(dynTestArr1[2]) == tuple.third ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[7] ); } /* test full buffer case, no truncation */ { char dynTestArr1_withBorders[9] = " \xE2\x82\xAC\0yz "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(6,dynTestArr1); tuple = utf8stringbuf_split_in_3( dynTestBuf1, 3, 3 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, tuple.error ); equals = memcmp( "\xE2\x82\xAC\0\0", dynTestArr1, 6 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr1[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr1[4]) == tuple.second ); TEST_ASSERT( &(dynTestArr1[5]) == tuple.third ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[7] ); } /* test min buffer case */ { char dynTestArr3_withBorders[6] = " \0yz "; char *dynTestArr3 = &(dynTestArr3_withBorders[1]); utf8stringbuf_t dynTestBuf3 = utf8stringbuf_init(3,dynTestArr3); tuple = utf8stringbuf_split_in_3( dynTestBuf3, 0, 0 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, tuple.error ); equals = memcmp( "\0\0", dynTestArr3, 3 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr3[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr3[1]) == tuple.second ); TEST_ASSERT( &(dynTestArr3[2]) == tuple.third ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr3_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr3_withBorders[4] ); } /* test small buffer case */ { char dynTestArr4_withBorders[5] = " y\0 "; char *dynTestArr4 = &(dynTestArr4_withBorders[1]); utf8stringbuf_t dynTestBuf4 = utf8stringbuf_init(2,dynTestArr4); tuple = utf8stringbuf_split_in_3( dynTestBuf4, 0, 0 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, tuple.error ); equals = memcmp( "\0", dynTestArr4, 2 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr4[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr4[1]) == tuple.second ); TEST_ASSERT( &(dynTestArr4[1]) == tuple.third ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr4_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr4_withBorders[3] ); } /* test full buffer case, truncate 3rd */ { char dynTestArr1_withBorders[9] = " z\xE2\x82\xAC\0y "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(6,dynTestArr1); tuple = utf8stringbuf_split_in_3( dynTestBuf1, 4, 4 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, tuple.error ); equals = memcmp( "z\xE2\x82\xAC\0", dynTestArr1, 6 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr1[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr1[5]) == tuple.second ); TEST_ASSERT( &(dynTestArr1[5]) == tuple.third ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[7] ); } /* test full buffer case, truncate 2nd and 3rd */ { char dynTestArr1_withBorders[9] = " yz\xE2\x82\xAC\0 "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(6,dynTestArr1); tuple = utf8stringbuf_split_in_3( dynTestBuf1, 5, 5 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, tuple.error ); equals = memcmp( "yz\xE2\x82\xAC", dynTestArr1, 6 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr1[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr1[5]) == tuple.second ); TEST_ASSERT( &(dynTestArr1[5]) == tuple.third ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[7] ); } /* test out of range case */ { char dynTestArr1_withBorders[9] = " \xE2\x82\xAC\0yz "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(6,dynTestArr1); tuple = utf8stringbuf_split_in_3( dynTestBuf1, 3, 0 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, tuple.error ); equals = memcmp( "\xE2\x82\xAC\0\0", dynTestArr1, 6 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr1[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr1[3]) == tuple.second ); TEST_ASSERT( &(dynTestArr1[3]) == tuple.third ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[7] ); } /* test truncate third string only case */ { char dynTestArr1_withBorders[9] = " He\xC2\xA2\0y "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(6,dynTestArr1); tuple = utf8stringbuf_split_in_3( dynTestBuf1, 1, 2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, tuple.error ); equals = memcmp( "H\0e\0\0", dynTestArr1, 6 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr1[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr1[2]) == tuple.second ); TEST_ASSERT( &(dynTestArr1[4]) == tuple.third ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[7] ); } /* test truncate second and third strings case */ { char dynTestArr1_withBorders[9] = " H\xE2\x82\xACy\0 "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(6,dynTestArr1); tuple = utf8stringbuf_split_in_3( dynTestBuf1, 4, 5 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, tuple.error ); equals = memcmp( "H\xE2\x82\xAC\0", dynTestArr1, 6 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr1[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr1[5]) == tuple.second ); TEST_ASSERT( &(dynTestArr1[5]) == tuple.third ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[7] ); } /* test for illegal parameters: -1 */ { char dynTestArr4_withBorders[9] = " H\xE2\x82\xAC\0z "; char *dynTestArr4 = &(dynTestArr4_withBorders[1]); utf8stringbuf_t dynTestBuf4 = utf8stringbuf_init(6,dynTestArr4); tuple = utf8stringbuf_split_in_3( dynTestBuf4, 1, -1 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, tuple.error ); equals = memcmp( "H\xE2\x82\xAC", dynTestArr4, 5 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr4[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr4[4]) == tuple.second ); TEST_ASSERT( &(dynTestArr4[4]) == tuple.third ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr4_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr4_withBorders[7] ); } } static void testSplitIn4(void) { int equals; utf8string4tuple_t tuple; /* test standard case */ { char dynTestArr1_withBorders[13] = " H\xE2\x82\xAC\0yyzzz "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(10,dynTestArr1); tuple = utf8stringbuf_split_in_4( dynTestBuf1, 0, 1, 4 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, tuple.error ); equals = memcmp( "\0H\0\xE2\x82\xAC\0\0\0", dynTestArr1, 10 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr1[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr1[1]) == tuple.second ); TEST_ASSERT( &(dynTestArr1[3]) == tuple.third ); TEST_ASSERT( &(dynTestArr1[7]) == tuple.fourth ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[11] ); } /* test buffer full case, no truncation */ { char dynTestArr1_withBorders[13] = " H\xE2\x82\xACzz\0yzz "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(10,dynTestArr1); tuple = utf8stringbuf_split_in_4( dynTestBuf1, 0, 1, 4 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, tuple.error ); equals = memcmp( "\0H\0\xE2\x82\xAC\0zz", dynTestArr1, 10 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr1[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr1[1]) == tuple.second ); TEST_ASSERT( &(dynTestArr1[3]) == tuple.third ); TEST_ASSERT( &(dynTestArr1[7]) == tuple.fourth ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[11] ); } /* test truncation of 3rd and 4th */ { char dynTestArr1_withBorders[13] = " H\xE2\x82\xACzzz\0yz "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(10,dynTestArr1); tuple = utf8stringbuf_split_in_4( dynTestBuf1, 1, 4, 7 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, tuple.error ); equals = memcmp( "H\0\xE2\x82\xAC\0zz\0", dynTestArr1, 10 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr1[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr1[2]) == tuple.second ); TEST_ASSERT( &(dynTestArr1[6]) == tuple.third ); TEST_ASSERT( &(dynTestArr1[9]) == tuple.fourth ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[11] ); } /* test truncation of 3rd */ { char dynTestArr1_withBorders[13] = " Hqqqq\xE2\x82\xAC\0z "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(10,dynTestArr1); tuple = utf8stringbuf_split_in_4( dynTestBuf1, 4, 8, 8 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, tuple.error ); equals = memcmp( "Hqqq\0q\0\0\0", dynTestArr1, 10 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr1[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr1[5]) == tuple.second ); TEST_ASSERT( &(dynTestArr1[9]) == tuple.third ); TEST_ASSERT( &(dynTestArr1[9]) == tuple.fourth ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[11] ); } /* test for illegal parameters: 5 */ { char dynTestArr4_withBorders[9] = " H\xE2\x82\xAC\0z "; char *dynTestArr4 = &(dynTestArr4_withBorders[1]); utf8stringbuf_t dynTestBuf4 = utf8stringbuf_init(6,dynTestArr4); tuple = utf8stringbuf_split_in_4( dynTestBuf4, 1, 4, 5 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, tuple.error ); equals = memcmp( "H\xE2\x82\xAC", dynTestArr4, 5 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr4[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr4[4]) == tuple.second ); TEST_ASSERT( &(dynTestArr4[4]) == tuple.third ); TEST_ASSERT( &(dynTestArr4[4]) == tuple.fourth ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr4_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr4_withBorders[7] ); } } static void testSplitIn5(void) { int equals; utf8string5tuple_t tuple; /* test standard case */ { char dynTestArr1_withBorders[13] = " H\xE2\x82\xAC\0yyzzz "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(10,dynTestArr1); tuple = utf8stringbuf_split_in_5( dynTestBuf1, 0, 1, 4, 4 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, tuple.error ); equals = memcmp( "\0H\0\xE2\x82\xAC\0\0\0", dynTestArr1, 10 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr1[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr1[1]) == tuple.second ); TEST_ASSERT( &(dynTestArr1[3]) == tuple.third ); TEST_ASSERT( &(dynTestArr1[7]) == tuple.fourth ); TEST_ASSERT( &(dynTestArr1[8]) == tuple.fifth ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[11] ); } /* test buffer full case, no truncation */ { char dynTestArr1_withBorders[13] = " H\xE2\x82\xACq\0yyzz "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(10,dynTestArr1); tuple = utf8stringbuf_split_in_5( dynTestBuf1, 0, 1, 4, 4 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, tuple.error ); equals = memcmp( "\0H\0\xE2\x82\xAC\0\0q", dynTestArr1, 10 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr1[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr1[1]) == tuple.second ); TEST_ASSERT( &(dynTestArr1[3]) == tuple.third ); TEST_ASSERT( &(dynTestArr1[7]) == tuple.fourth ); TEST_ASSERT( &(dynTestArr1[8]) == tuple.fifth ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[11] ); } /* test truncation of 4th, 4th has own terminating zero, and 5th */ { char dynTestArr1_withBorders[13] = " H\xE2\x82\xACqq\0yyz "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(10,dynTestArr1); tuple = utf8stringbuf_split_in_5( dynTestBuf1, 1, 4, 5, 6 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, tuple.error ); equals = memcmp( "H\0\xE2\x82\xAC\0q\0\0", dynTestArr1, 10 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr1[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr1[2]) == tuple.second ); TEST_ASSERT( &(dynTestArr1[6]) == tuple.third ); TEST_ASSERT( &(dynTestArr1[8]) == tuple.fourth ); TEST_ASSERT( &(dynTestArr1[9]) == tuple.fifth ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[11] ); } /* test truncation of 4th, 4th has no own terminating zero anymore, and 5th */ { char dynTestArr1_withBorders[13] = " Hqq\xE2\x82\xAC\0yyz "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(10,dynTestArr1); tuple = utf8stringbuf_split_in_5( dynTestBuf1, 3, 6, 6, 6 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, tuple.error ); equals = memcmp( "Hqq\0\xE2\x82\xAC\0\0", dynTestArr1, 10 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr1[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr1[4]) == tuple.second ); TEST_ASSERT( &(dynTestArr1[8]) == tuple.third ); TEST_ASSERT( &(dynTestArr1[9]) == tuple.fourth ); TEST_ASSERT( &(dynTestArr1[9]) == tuple.fifth ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[11] ); } /* test truncation of 3rd, 4th and 5th */ { char dynTestArr1_withBorders[13] = " Hqqzzz\xE2\x82\xAC\0 "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(10,dynTestArr1); tuple = utf8stringbuf_split_in_5( dynTestBuf1, 5, 9, 9, 9 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, tuple.error ); equals = memcmp( "Hqqzz\0z\0\0", dynTestArr1, 10 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr1[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr1[6]) == tuple.second ); TEST_ASSERT( &(dynTestArr1[9]) == tuple.third ); TEST_ASSERT( &(dynTestArr1[9]) == tuple.fourth ); TEST_ASSERT( &(dynTestArr1[9]) == tuple.fifth ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[11] ); } /* test for illegal parameters: wrong order */ { char dynTestArr4_withBorders[9] = " H\xE2\x82\xAC\0z "; char *dynTestArr4 = &(dynTestArr4_withBorders[1]); utf8stringbuf_t dynTestBuf4 = utf8stringbuf_init(6,dynTestArr4); tuple = utf8stringbuf_split_in_5( dynTestBuf4, 1, 4, 1, 4 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_OUT_OF_RANGE, tuple.error ); equals = memcmp( "H\xE2\x82\xAC", dynTestArr4, 5 ); TEST_ASSERT_EQUAL_INT( 0, equals ); TEST_ASSERT( &(dynTestArr4[0]) == tuple.first ); TEST_ASSERT( &(dynTestArr4[4]) == tuple.second ); TEST_ASSERT( &(dynTestArr4[4]) == tuple.third ); TEST_ASSERT( &(dynTestArr4[4]) == tuple.fourth ); TEST_ASSERT( &(dynTestArr4[4]) == tuple.fifth ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr4_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr4_withBorders[7] ); } } static void testJoin(void) { int equals; char dynTestArr1_withBorders[12] = " ab\0cd\0efg "; char *dynTestArr1 = &(dynTestArr1_withBorders[1]); utf8stringbuf_t dynTestBuf1 = utf8stringbuf_init(9,dynTestArr1); /* test one join, one string-end and some terminating nonsense */ { utf8stringbuf_join( dynTestBuf1 ); equals = memcmp( dynTestArr1, "abcd\0\0\0\0", 9 ); TEST_ASSERT_EQUAL_INT( 0, equals ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[10] ); } /* test calling the function again on the result */ { utf8stringbuf_join( dynTestBuf1 ); equals = memcmp( dynTestArr1, "abcd\0\0\0\0", 9 ); TEST_ASSERT_EQUAL_INT( 0, equals ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr1_withBorders[10] ); } /* test two string-ends right at start and some terminating nonsense */ { char dynTestArr2_withBorders[12] = " \0\0a\0bcdef "; char *dynTestArr2 = &(dynTestArr2_withBorders[1]); utf8stringbuf_t dynTestBuf2 = utf8stringbuf_init(9,dynTestArr2); utf8stringbuf_join( dynTestBuf2 ); equals = memcmp( dynTestArr2, "a\0\0\0\0\0\0\0", 9 ); TEST_ASSERT_EQUAL_INT( 0, equals ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr2_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr2_withBorders[10] ); } /* test one single full string without trailing data */ { char dynTestArr3_withBorders[12] = " abcdefgh\0 "; char *dynTestArr3 = &(dynTestArr3_withBorders[1]); utf8stringbuf_t dynTestBuf3 = utf8stringbuf_init(9,dynTestArr3); utf8stringbuf_join( dynTestBuf3 ); equals = memcmp( dynTestArr3, "abcdefgh", 9 ); TEST_ASSERT_EQUAL_INT( 0, equals ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr3_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr3_withBorders[10] ); } /* test 5 substrings without trailing data */ { char dynTestArr4_withBorders[12] = " \0a\0b\0c\0d\0 "; char *dynTestArr4 = &(dynTestArr4_withBorders[1]); utf8stringbuf_t dynTestBuf4 = utf8stringbuf_init(9,dynTestArr4); utf8stringbuf_join( dynTestBuf4 ); equals = memcmp( dynTestArr4, "abcd\0\0\0\0", 9 ); TEST_ASSERT_EQUAL_INT( 0, equals ); /* check buffer boundaries */ TEST_ASSERT_EQUAL_INT( ' ', dynTestArr4_withBorders[0] ); TEST_ASSERT_EQUAL_INT( ' ', dynTestArr4_withBorders[10] ); } } static void testSplitAndJoin(void) { /* test standard case */ { char dynTestArr1[10] = "He\xE2\x82\xACllo"; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); utf8string2tuple_t tuple; tuple = utf8stringbuf_split_in_2( dynTestBuf1, 2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, tuple.error ); TEST_ASSERT_EQUAL_STRING( "He", tuple.first ); TEST_ASSERT_EQUAL_STRING( "\xE2\x82\xACllo", tuple.second ); utf8stringbuf_join( dynTestBuf1 ); TEST_ASSERT_EQUAL_STRING( "He\xE2\x82\xACllo", dynTestBuf1.buf ); } /* test trailing non-zeroes */ { char dynTestArr2[10] = "Hello\0QQQ"; utf8stringbuf_t dynTestBuf2 = UTF8STRINGBUF(dynTestArr2); utf8string2tuple_t tuple2; tuple2 = utf8stringbuf_split_in_2( dynTestBuf2, 2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, tuple2.error ); TEST_ASSERT_EQUAL_STRING( "He", tuple2.first ); TEST_ASSERT_EQUAL_STRING( "llo", tuple2.second ); utf8stringbuf_join( dynTestBuf2 ); TEST_ASSERT_EQUAL_STRING( "Hello", dynTestBuf2.buf ); } /* test truncation */ { char dynTestArr3[10] = "Hello \xE2\x82\xAC"; utf8stringbuf_t dynTestBuf3 = UTF8STRINGBUF(dynTestArr3); utf8string2tuple_t tuple3; tuple3 = utf8stringbuf_split_in_2( dynTestBuf3, 2 ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, tuple3.error ); TEST_ASSERT_EQUAL_STRING( "He", tuple3.first ); TEST_ASSERT_EQUAL_STRING( "llo ", tuple3.second ); utf8stringbuf_join( dynTestBuf3 ); TEST_ASSERT_EQUAL_STRING( "Hello ", dynTestBuf3.buf ); } } static void testGetEnd(void) { int error; int equal; char dynTestArr1[4] = ""; utf8stringbuf_t dynTestBuf1 = UTF8STRINGBUF(dynTestArr1); utf8stringbuf_t dynTestEnd; // test utf8stringbuf_get_end dynTestEnd = utf8stringbuf_get_end( dynTestBuf1 ); error = utf8stringbuf_append_str( dynTestEnd, "Aa" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_SUCCESS, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "Aa" ); TEST_ASSERT_EQUAL_INT( 1, equal ); dynTestEnd = utf8stringbuf_get_end( dynTestBuf1 ); error = utf8stringbuf_append_str( dynTestEnd, "Bb" ); TEST_ASSERT_EQUAL_INT( UTF8ERROR_TRUNCATED, error ); equal = utf8stringbuf_equals_str( dynTestBuf1, "AaB" ); TEST_ASSERT_EQUAL_INT( 1, equal ); } /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/test/unit/utf8stringbuf_test.h000066400000000000000000000015101415120503000257120ustar00rootroot00000000000000/* File: utf8stringbuf_test.h; Copyright and License: see below */ #ifndef UTF8STRINGBUF_TEST_H_ #define UTF8STRINGBUF_TEST_H_ #include "test_suite.h" test_suite_t utf8stringbuf_test_get_list(void); #endif /*UTF8STRINGBUF_TEST_H_*/ /* * Copyright 2012-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/test/unit/utf8stringview_test.c000066400000000000000000000140341415120503000261100ustar00rootroot00000000000000/* File: utf8stringview_test.c; Copyright and License: see below */ #include "utf8string_test.h" #include "util/string/utf8string.h" #include "util/string/utf8stringview.h" #include "test_assert.h" #include #include static void setUp(void); static void tearDown(void); static void testInitMacros(void); static void testInitFunctions(void); static void testFindFirst(void); test_suite_t utf8stringview_test_get_list(void) { test_suite_t result; test_suite_init( &result, "utf8StringViewTest", &setUp, &tearDown ); test_suite_add_test_case( &result, "testInitMacros", &testInitMacros ); test_suite_add_test_case( &result, "testInitFunctions", &testInitFunctions ); test_suite_add_test_case( &result, "testFindFirst", &testFindFirst ); return result; } static void setUp(void) { } static void tearDown(void) { } static void testInitMacros(void) { const char* start; size_t len; utf8stringview_t my_view; static const char *const my_txt = "txt"; /* check anonymous struct usage of UTF8STRINGVIEW_NULL macro */ start = utf8stringview_get_start( UTF8STRINGVIEW_NULL ); TEST_ASSERT_EQUAL_PTR( NULL, start ); len = utf8stringview_get_length( UTF8STRINGVIEW_NULL ); TEST_ASSERT_EQUAL_INT( 0, len ); /* check initialization by UTF8STRINGVIEW_NULL macro */ my_view = UTF8STRINGVIEW_NULL; start = utf8stringview_get_start( my_view ); TEST_ASSERT_EQUAL_PTR( NULL, start ); len = utf8stringview_get_length( my_view ); TEST_ASSERT_EQUAL_INT( 0, len ); /* check anonymous struct usage of UTF8STRINGVIEW_STR macro */ start = utf8stringview_get_start( UTF8STRINGVIEW_STR( my_txt ) ); TEST_ASSERT_EQUAL_PTR( my_txt, start ); len = utf8stringview_get_length( UTF8STRINGVIEW_STR( my_txt ) ); TEST_ASSERT_EQUAL_INT( strlen( my_txt ), len ); /* check initialization by UTF8STRINGVIEW_STR macro */ my_view = UTF8STRINGVIEW_STR( my_txt ); start = utf8stringview_get_start( my_view ); TEST_ASSERT_EQUAL_PTR( my_txt, start ); len = utf8stringview_get_length( my_view ); TEST_ASSERT_EQUAL_INT( strlen( my_txt ), len ); /* check anonymous struct usage of UTF8STRINGVIEW macro */ start = utf8stringview_get_start( UTF8STRINGVIEW( my_txt, 2 ) ); TEST_ASSERT_EQUAL_PTR( my_txt, start ); len = utf8stringview_get_length( UTF8STRINGVIEW( my_txt, 2 ) ); TEST_ASSERT_EQUAL_INT( 2, len ); /* check initialization by UTF8STRINGVIEW macro */ const utf8stringview_t my_view_2 = UTF8STRINGVIEW( my_txt, 2 ); start = utf8stringview_get_start( my_view_2 ); TEST_ASSERT_EQUAL_PTR( my_txt, start ); len = utf8stringview_get_length( my_view_2 ); TEST_ASSERT_EQUAL_INT( 2, len ); } static void testInitFunctions(void) { static const char *const my_txt = "txt"; /* check initialization with utf8stringview_init function */ utf8stringview_t my_view_1 = utf8stringview_init( NULL, 0 ); TEST_ASSERT_EQUAL_PTR( NULL, utf8stringview_get_start( my_view_1 ) ); TEST_ASSERT_EQUAL_INT( 0, utf8stringview_get_length( my_view_1 ) ); const utf8stringview_t my_view_2 = utf8stringview_init( my_txt, 4 ); TEST_ASSERT_EQUAL_PTR( my_txt, utf8stringview_get_start( my_view_2 ) ); TEST_ASSERT_EQUAL_INT( 4, utf8stringview_get_length( my_view_2 ) ); /* check initialization with utf8stringview_init_str function */ utf8stringview_t my_view_3 = utf8stringview_init_str( NULL ); TEST_ASSERT_EQUAL_PTR( NULL, utf8stringview_get_start( my_view_3 ) ); TEST_ASSERT_EQUAL_INT( 0, utf8stringview_get_length( my_view_3 ) ); const utf8stringview_t my_view_4 = utf8stringview_init_str( my_txt ); TEST_ASSERT_EQUAL_PTR( my_txt, utf8stringview_get_start( my_view_4 ) ); TEST_ASSERT_EQUAL_INT( strlen( my_txt ), utf8stringview_get_length( my_view_4 ) ); /* check initialization with utf8stringview_init_region function */ utf8stringview_t my_view_5 = utf8stringview_init_region( NULL, 0, 0 ); TEST_ASSERT_EQUAL_PTR( NULL, utf8stringview_get_start( my_view_5 ) ); TEST_ASSERT_EQUAL_INT( 0, utf8stringview_get_length( my_view_5 ) ); const utf8stringview_t my_view_6 = utf8stringview_init_region( my_txt, 1, 3 ); TEST_ASSERT_EQUAL_PTR( (my_txt+1), utf8stringview_get_start( my_view_6 ) ); TEST_ASSERT_EQUAL_INT( 3, utf8stringview_get_length( my_view_6 ) ); } static void testFindFirst(void) { int pos; char memoryArr[] = "beforeHELLO ANANASafter"; utf8stringview_t srchView = utf8stringview_init_region( memoryArr, 6, 12 ); /* check search with utf8stringview_find_first_str function */ pos = utf8stringview_find_first_str( srchView, NULL ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringview_find_first_str( UTF8STRINGVIEW_NULL, "HELLO" ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringview_find_first_str( UTF8STRINGVIEW_STR(""), "" ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringview_find_first_str( srchView, "eHELLO" ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringview_find_first_str( srchView, "HELLO" ); TEST_ASSERT_EQUAL_INT( 0, pos ); pos = utf8stringview_find_first_str( srchView, "ANANASa" ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringview_find_first_str( srchView, "ANAS" ); TEST_ASSERT_EQUAL_INT( 8, pos ); pos = utf8stringview_find_first_str( srchView, "" ); TEST_ASSERT_EQUAL_INT( -1, pos ); pos = utf8stringview_find_first_str( srchView, " " ); TEST_ASSERT_EQUAL_INT( 5, pos ); } /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/test/unit/utf8stringview_test.h000066400000000000000000000015151415120503000261150ustar00rootroot00000000000000/* File: utf8stringview_test.h; Copyright and License: see below */ #ifndef UTF8STRINGVIEW_TEST_H_ #define UTF8STRINGVIEW_TEST_H_ #include "test_suite.h" test_suite_t utf8stringview_test_get_list(void); #endif /*UTF8STRINGVIEW_TEST_H_*/ /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/test/unit/utf8stringviewiterator_test.c000066400000000000000000000234261415120503000276670ustar00rootroot00000000000000/* File: utf8stringviewiterator_test.c; Copyright and License: see below */ #include "utf8string_test.h" #include "util/string/utf8stringviewiterator.h" #include "util/string/utf8stringview.h" #include "test_assert.h" #include #include static void setUp(void); static void tearDown(void); static void testStandardUseCase(void); static void testNoSeparatorUseCase(void); static void testEmptyElementsUseCase(void); static void testEmptyListUseCase(void); static void testEmptySeparatorUseCase(void); static void testNullListUseCase(void); static void testNullSeparatorUseCase(void); test_suite_t utf8stringviewiterator_test_get_list(void) { test_suite_t result; test_suite_init( &result, "utf8StringViewIteratorTest", &setUp, &tearDown ); test_suite_add_test_case( &result, "testStandardUseCase", &testStandardUseCase ); test_suite_add_test_case( &result, "testNoSeparatorUseCase", &testNoSeparatorUseCase ); test_suite_add_test_case( &result, "testEmptyElementsUseCase", &testEmptyElementsUseCase ); test_suite_add_test_case( &result, "testEmptyListUseCase", &testEmptyListUseCase ); test_suite_add_test_case( &result, "testEmptySeparatorUseCase", &testEmptySeparatorUseCase ); test_suite_add_test_case( &result, "testNullListUseCase", &testNullListUseCase ); test_suite_add_test_case( &result, "testNullSeparatorUseCase", &testNullSeparatorUseCase ); return result; } static void setUp(void) { } static void tearDown(void) { } static void testStandardUseCase(void) { bool has_next; utf8stringview_t next; static const char *const my_list = "23,, 24"; /* init */ utf8stringviewiterator_t it; utf8stringviewiterator_init( &it, UTF8STRINGVIEW_STR( my_list ), ", " ); has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( true, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_PTR( (my_list+0), utf8stringview_get_start( next ) ); TEST_ASSERT_EQUAL_INT( 3, utf8stringview_get_length( next ) ); has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( true, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_PTR( (my_list+5), utf8stringview_get_start( next ) ); TEST_ASSERT_EQUAL_INT( 2, utf8stringview_get_length( next ) ); has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( false, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_PTR( NULL, utf8stringview_get_start( next ) ); TEST_ASSERT_EQUAL_INT( 0, utf8stringview_get_length( next ) ); /* finish */ utf8stringviewiterator_destroy( &it ); } static void testNoSeparatorUseCase(void) { bool has_next; utf8stringview_t next; static const char *const my_list = "23,, 24"; /* init */ utf8stringviewiterator_t it; utf8stringviewiterator_init( &it, UTF8STRINGVIEW_STR( my_list ), ",, 24567" ); has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( true, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_PTR( (my_list+0), utf8stringview_get_start( next ) ); TEST_ASSERT_EQUAL_INT( strlen( my_list ), utf8stringview_get_length( next ) ); has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( false, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_PTR( NULL, utf8stringview_get_start( next ) ); TEST_ASSERT_EQUAL_INT( 0, utf8stringview_get_length( next ) ); /* finish */ utf8stringviewiterator_destroy( &it ); } static void testEmptyElementsUseCase(void) { bool has_next; utf8stringview_t next; static const char *const my_list = ",23,, 24,"; /* init */ utf8stringviewiterator_t it; utf8stringviewiterator_init( &it, UTF8STRINGVIEW_STR( my_list ), "," ); has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( true, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_PTR( (my_list+0), utf8stringview_get_start( next ) ); TEST_ASSERT_EQUAL_INT( 0, utf8stringview_get_length( next ) ); has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( true, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_PTR( (my_list+1), utf8stringview_get_start( next ) ); TEST_ASSERT_EQUAL_INT( 2, utf8stringview_get_length( next ) ); has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( true, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_PTR( (my_list+4), utf8stringview_get_start( next ) ); TEST_ASSERT_EQUAL_INT( 0, utf8stringview_get_length( next ) ); has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( true, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_PTR( (my_list+5), utf8stringview_get_start( next ) ); TEST_ASSERT_EQUAL_INT( 3, utf8stringview_get_length( next ) ); has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( true, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_PTR( (my_list+9), utf8stringview_get_start( next ) ); TEST_ASSERT_EQUAL_INT( 0, utf8stringview_get_length( next ) ); has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( false, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_PTR( NULL, utf8stringview_get_start( next ) ); TEST_ASSERT_EQUAL_INT( 0, utf8stringview_get_length( next ) ); /* finish */ utf8stringviewiterator_destroy( &it ); } static void testEmptyListUseCase(void) { bool has_next; utf8stringview_t next; static const char *const my_list = ""; /* init */ utf8stringviewiterator_t it; utf8stringviewiterator_init( &it, UTF8STRINGVIEW_STR( my_list ), "," ); has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( true, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_INT( 0, utf8stringview_get_length( next ) ); has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( false, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_PTR( NULL, utf8stringview_get_start( next ) ); TEST_ASSERT_EQUAL_INT( 0, utf8stringview_get_length( next ) ); /* finish */ utf8stringviewiterator_destroy( &it ); } static void testEmptySeparatorUseCase(void) { bool has_next; utf8stringview_t next; static const char *const my_list = "1,2,3"; /* init */ utf8stringviewiterator_t it; utf8stringviewiterator_init( &it, UTF8STRINGVIEW_STR( my_list ), "" ); /* unspecified case */ has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( true, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_PTR( my_list, utf8stringview_get_start( next ) ); TEST_ASSERT_EQUAL_INT( strlen( my_list ), utf8stringview_get_length( next ) ); has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( false, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_PTR( NULL, utf8stringview_get_start( next ) ); TEST_ASSERT_EQUAL_INT( 0, utf8stringview_get_length( next ) ); /* finish */ utf8stringviewiterator_destroy( &it ); } static void testNullListUseCase(void) { bool has_next; utf8stringview_t next; /* init */ utf8stringviewiterator_t it; utf8stringviewiterator_init( &it, UTF8STRINGVIEW_NULL, "" ); /* unspecified case */ has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( true, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_INT( 0, utf8stringview_get_length( next ) ); has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( false, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_PTR( NULL, utf8stringview_get_start( next ) ); TEST_ASSERT_EQUAL_INT( 0, utf8stringview_get_length( next ) ); /* finish */ utf8stringviewiterator_destroy( &it ); } static void testNullSeparatorUseCase(void) { bool has_next; utf8stringview_t next; static const char *const my_list = "1,2,3"; /* init */ utf8stringviewiterator_t it; utf8stringviewiterator_init( &it, UTF8STRINGVIEW_STR( my_list ), NULL ); /* unspecified case */ has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( true, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_PTR( my_list, utf8stringview_get_start( next ) ); TEST_ASSERT_EQUAL_INT( strlen( my_list ), utf8stringview_get_length( next ) ); has_next = utf8stringviewiterator_has_next( &it ); TEST_ASSERT_EQUAL_INT( false, has_next ); next = utf8stringviewiterator_next( &it ); TEST_ASSERT_EQUAL_PTR( NULL, utf8stringview_get_start( next ) ); TEST_ASSERT_EQUAL_INT( 0, utf8stringview_get_length( next ) ); /* finish */ utf8stringviewiterator_destroy( &it ); } /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ crystal-facet-uml-1.34.1/utf8stringbuf/test/unit/utf8stringviewiterator_test.h000066400000000000000000000015651415120503000276740ustar00rootroot00000000000000/* File: utf8stringviewiterator_test.h; Copyright and License: see below */ #ifndef UTF8STRINGVIEWITERATOR_TEST_H_ #define UTF8STRINGVIEWITERATOR_TEST_H_ #include "test_suite.h" test_suite_t utf8stringviewiterator_test_get_list(void); #endif /*UTF8STRINGVIEWITERATOR_TEST_H_*/ /* * Copyright 2021-2021 Andreas Warnke * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */