Repository: zenkovich/o2 Branch: master Commit: 47bf364fee1f Files: 4848 Total size: 32.7 MB Directory structure: gitextract_vp8reetq/ ├── .gitattributes ├── .gitignore ├── .gitmodules ├── AssetsBuildTool/ │ ├── CMakeLists.txt │ └── Sources/ │ ├── AssetsBuildTool.cpp │ └── o2AssetBuilder/ │ ├── AssetsBuilder.cpp │ ├── AssetsBuilder.h │ ├── AssetsBuilderRunner.cpp │ ├── Converters/ │ │ ├── AtlasAssetConverter.cpp │ │ ├── AtlasAssetConverter.h │ │ ├── FolderAssetConverter.cpp │ │ ├── FolderAssetConverter.h │ │ ├── IAssetConverter.cpp │ │ ├── IAssetConverter.h │ │ ├── ImageAssetConverter.cpp │ │ ├── ImageAssetConverter.h │ │ ├── StdAssetConverter.cpp │ │ └── StdAssetConverter.h │ ├── ImageCompressor.cpp │ └── ImageCompressor.h ├── CMake/ │ ├── CMakeDetermineMetalCompiler.cmake │ ├── CMakeMetalCompiler.cmake.in │ ├── CMakeMetalInformation.cmake │ ├── CMakeTestMetalCompiler.cmake │ ├── CheckLanguage.cmake │ └── MetalShaderSupport.cmake ├── CMakeLists.txt ├── CodeTool/ │ ├── CMakeLists.txt │ └── Src/ │ ├── CodeTool.cpp │ ├── CodeToolApp.cpp │ ├── CodeToolApp.h │ ├── CppSyntaxParser.cpp │ ├── CppSyntaxParser.h │ ├── SyntaxTree.cpp │ ├── SyntaxTree.h │ └── pugixml/ │ ├── pugiconfig.hpp │ ├── pugixml.cpp │ └── pugixml.hpp ├── CompressToolsConfig.json ├── Docs/ │ ├── en/ │ │ ├── Architecture/ │ │ │ └── architecture.md │ │ └── main.md │ └── ru/ │ ├── Architecture/ │ │ ├── HighLevel/ │ │ │ ├── components.md │ │ │ ├── scene.md │ │ │ └── ui.md │ │ ├── LowLevel/ │ │ │ ├── animations.md │ │ │ ├── application.md │ │ │ ├── assets.md │ │ │ ├── input.md │ │ │ ├── physics.md │ │ │ ├── render.md │ │ │ └── scripting.md │ │ ├── Utils/ │ │ │ ├── containers.md │ │ │ ├── debug.md │ │ │ ├── filesystem.md │ │ │ ├── function.md │ │ │ ├── logging.md │ │ │ ├── math.md │ │ │ ├── memory.md │ │ │ ├── properties.md │ │ │ ├── reflection.md │ │ │ ├── serialization.md │ │ │ └── string.md │ │ └── architecture.md │ ├── Editor/ │ │ ├── Animation/ │ │ │ └── animation.md │ │ ├── Assets/ │ │ │ └── assets.md │ │ ├── Game/ │ │ │ └── game.md │ │ ├── Log/ │ │ │ └── log.md │ │ ├── Properties/ │ │ │ └── properties.md │ │ ├── Scene/ │ │ │ └── scene.md │ │ ├── Tree/ │ │ │ └── tree.md │ │ └── editor.md │ └── main.md ├── Editor/ │ ├── Assets/ │ │ ├── BasicAtlas.atlas │ │ ├── BasicAtlas.atlas.meta │ │ ├── Editor UI styles.meta │ │ ├── SimulationDevicesList.json │ │ ├── SimulationDevicesList.json.meta │ │ ├── debugFont.ttf.meta │ │ ├── stdFont.ttf.meta │ │ ├── ui/ │ │ │ ├── .meta │ │ │ ├── CurveHandle.png.meta │ │ │ ├── CurveHandleHover.png.meta │ │ │ ├── CurveHandlePressed.png.meta │ │ │ ├── CurveHandleSelected.png.meta │ │ │ ├── CurveSupportHandle.png.meta │ │ │ ├── CurveSupportHandleHover.png.meta │ │ │ ├── CurveSupportHandlePressed.png.meta │ │ │ ├── CurveSupportHandleSelected.png.meta │ │ │ ├── JSFileIcon.png.meta │ │ │ ├── TopologyTool.png.meta │ │ │ ├── UI2_accept_prefab.png.meta │ │ │ ├── UI2_accept_prefab_pressed.png.meta │ │ │ ├── UI2_accept_prefab_select.png.meta │ │ │ ├── UI2_actor_icon.png.meta │ │ │ ├── UI2_add_asset_icon.png.meta │ │ │ ├── UI2_anim_file_icon.png.meta │ │ │ ├── UI2_asset_icon_selection.png.meta │ │ │ ├── UI2_big_file_icon.png.meta │ │ │ ├── UI2_big_folder_icon.png.meta │ │ │ ├── UI2_big_lock_close.png.meta │ │ │ ├── UI2_big_lock_open.png.meta │ │ │ ├── UI2_big_lock_unknown.png.meta │ │ │ ├── UI2_big_text_file_icon.png.meta │ │ │ ├── UI2_break_prefab.png.meta │ │ │ ├── UI2_break_prefab_pressed.png.meta │ │ │ ├── UI2_break_prefab_select.png.meta │ │ │ ├── UI2_component_head.png.meta │ │ │ ├── UI2_enable_dot_big.png.meta │ │ │ ├── UI2_enable_dot_big_unknown.png.meta │ │ │ ├── UI2_enable_toggle_big.png.meta │ │ │ ├── UI2_enable_toggle_big_focused.png.meta │ │ │ ├── UI2_enable_toggle_big_pressed.png.meta │ │ │ ├── UI2_enable_toggle_big_select.png.meta │ │ │ ├── UI2_eye_closed_icon.png.meta │ │ │ ├── UI2_eye_opened_icon.png.meta │ │ │ ├── UI2_filter_icon.png.meta │ │ │ ├── UI2_folder_icon.png.meta │ │ │ ├── UI2_gear_icon.png.meta │ │ │ ├── UI2_gray_options.png.meta │ │ │ ├── UI2_gray_options_pressed.png.meta │ │ │ ├── UI2_gray_options_select.png.meta │ │ │ ├── UI2_green_edit_box.png.meta │ │ │ ├── UI2_handle_pressed.png.meta │ │ │ ├── UI2_handle_regular.png.meta │ │ │ ├── UI2_handle_select.png.meta │ │ │ ├── UI2_handle_side_pressed.png.meta │ │ │ ├── UI2_handle_side_regular.png.meta │ │ │ ├── UI2_handle_side_select.png.meta │ │ │ ├── UI2_image_asset_back.png.meta │ │ │ ├── UI2_layer_big.png.meta │ │ │ ├── UI2_layer_icon_t.png.meta │ │ │ ├── UI2_link_icon.png.meta │ │ │ ├── UI2_log_errors_icon.png.meta │ │ │ ├── UI2_log_errors_inactive_icon.png.meta │ │ │ ├── UI2_log_info_icon.png.meta │ │ │ ├── UI2_log_info_inactive_icon.png.meta │ │ │ ├── UI2_log_warnings_icon.png.meta │ │ │ ├── UI2_log_warnings_inactive_icon.png.meta │ │ │ ├── UI2_move_tool_center.png.meta │ │ │ ├── UI2_move_tool_center_pressed.png.meta │ │ │ ├── UI2_move_tool_center_select.png.meta │ │ │ ├── UI2_pivot.png.meta │ │ │ ├── UI2_pivot_icon.png.meta │ │ │ ├── UI2_pivot_pressed.png.meta │ │ │ ├── UI2_pivot_select.png.meta │ │ │ ├── UI2_position_icon.png.meta │ │ │ ├── UI2_prefab_link_big.png.meta │ │ │ ├── UI2_red_edit_box.png.meta │ │ │ ├── UI2_revert_prefab.png.meta │ │ │ ├── UI2_revert_prefab_pressed.png.meta │ │ │ ├── UI2_revert_prefab_select.png.meta │ │ │ ├── UI2_right_move_arrow.png.meta │ │ │ ├── UI2_right_move_arrow_pressed.png.meta │ │ │ ├── UI2_right_move_arrow_select.png.meta │ │ │ ├── UI2_right_scale_arrow.png.meta │ │ │ ├── UI2_right_scale_arrow_pressed.png.meta │ │ │ ├── UI2_right_scale_arrow_select.png.meta │ │ │ ├── UI2_rotate_icon.png.meta │ │ │ ├── UI2_round_field.png.meta │ │ │ ├── UI2_round_field_focused.png.meta │ │ │ ├── UI2_round_field_gray.png.meta │ │ │ ├── UI2_round_field_gray_pressed.png.meta │ │ │ ├── UI2_round_field_gray_select.png.meta │ │ │ ├── UI2_round_field_pressed.png.meta │ │ │ ├── UI2_round_field_select.png.meta │ │ │ ├── UI2_save_gray copy 2.png.meta │ │ │ ├── UI2_save_gray copy.png.meta │ │ │ ├── UI2_save_gray.png.meta │ │ │ ├── UI2_scale_both.png.meta │ │ │ ├── UI2_scale_both_pressed.png.meta │ │ │ ├── UI2_scale_both_select.png.meta │ │ │ ├── UI2_scale_icon.png.meta │ │ │ ├── UI2_scene_icon.png.meta │ │ │ ├── UI2_small_panel_back.png.meta │ │ │ ├── UI2_small_panel_down_back.png.meta │ │ │ ├── UI2_small_trash_icon.png.meta │ │ │ ├── UI2_tag_big.png.meta │ │ │ ├── UI2_trach_icon.png.meta │ │ │ ├── UI2_transform_icon.png.meta │ │ │ ├── UI2_up_move_arrow.png.meta │ │ │ ├── UI2_up_move_arrow_pressed.png.meta │ │ │ ├── UI2_up_move_arrow_select.png.meta │ │ │ ├── UI2_up_scale_arrow.png.meta │ │ │ ├── UI2_up_scale_arrow_pressed.png.meta │ │ │ ├── UI2_up_scale_arrow_select.png.meta │ │ │ ├── UI3_add_btn.png.meta │ │ │ ├── UI3_add_btn_hover.png.meta │ │ │ ├── UI3_add_btn_pressed.png.meta │ │ │ ├── UI3_anchor_hover.png.meta │ │ │ ├── UI3_anchor_pressed.png.meta │ │ │ ├── UI3_anchor_regular.png.meta │ │ │ ├── UI3_anchors_hover.png.meta │ │ │ ├── UI3_anchors_pressed.png.meta │ │ │ ├── UI3_ch_arrows.png.meta │ │ │ ├── UI3_icon_anchor.png.meta │ │ │ ├── UI3_icon_max_size.png.meta │ │ │ ├── UI3_icon_min_size.png.meta │ │ │ ├── UI3_icon_offsets.png.meta │ │ │ ├── UI3_icon_size.png.meta │ │ │ ├── UI3_icon_weight.png.meta │ │ │ ├── UI3_rotate_hover.png.meta │ │ │ ├── UI3_rotate_pressed.png.meta │ │ │ ├── UI3_rotate_regular.png.meta │ │ │ ├── UI4_Background.png.meta │ │ │ ├── UI4_Box_focus.png.meta │ │ │ ├── UI4_Box_pressed.png.meta │ │ │ ├── UI4_Box_regular.png.meta │ │ │ ├── UI4_Box_select.png.meta │ │ │ ├── UI4_Check_bk.png.meta │ │ │ ├── UI4_Check_bk_focus.png.meta │ │ │ ├── UI4_Check_bk_pressed.png.meta │ │ │ ├── UI4_Check_bk_select.png.meta │ │ │ ├── UI4_Check_unknown.png.meta │ │ │ ├── UI4_Ckeck.png.meta │ │ │ ├── UI4_Close_button_pressed.png.meta │ │ │ ├── UI4_Close_button_regular.png.meta │ │ │ ├── UI4_Close_button_select.png.meta │ │ │ ├── UI4_Context_menu.png.meta │ │ │ ├── UI4_Context_menu_select.png.meta │ │ │ ├── UI4_Context_menu_white.png.meta │ │ │ ├── UI4_Down_icn.png.meta │ │ │ ├── UI4_Down_icn_pressed.png.meta │ │ │ ├── UI4_Down_icn_select.png.meta │ │ │ ├── UI4_Down_icn_white.png.meta │ │ │ ├── UI4_Editbox_focus.png.meta │ │ │ ├── UI4_Editbox_pressed.png.meta │ │ │ ├── UI4_Editbox_regular.png.meta │ │ │ ├── UI4_Editbox_select.png.meta │ │ │ ├── UI4_Hor_scrollbar_bk.png.meta │ │ │ ├── UI4_Hor_scrollhandle_pressed.png.meta │ │ │ ├── UI4_Hor_scrollhandle_regular.png.meta │ │ │ ├── UI4_Hor_scrollhandle_select.png.meta │ │ │ ├── UI4_Options_button_pressed.png.meta │ │ │ ├── UI4_Options_button_regular.png.meta │ │ │ ├── UI4_Options_button_select.png.meta │ │ │ ├── UI4_Radio.png.meta │ │ │ ├── UI4_Radio_bk.png.meta │ │ │ ├── UI4_Radio_bk_focus.png.meta │ │ │ ├── UI4_Radio_bk_pressed.png.meta │ │ │ ├── UI4_Radio_bk_select.png.meta │ │ │ ├── UI4_Record_icon.png.meta │ │ │ ├── UI4_Right_icn.png.meta │ │ │ ├── UI4_Right_icn_pressed.png.meta │ │ │ ├── UI4_Right_icn_select.png.meta │ │ │ ├── UI4_Right_icn_white.png.meta │ │ │ ├── UI4_Right_icn_white_pressed.png.meta │ │ │ ├── UI4_Right_icn_white_select.png.meta │ │ │ ├── UI4_Separator.png.meta │ │ │ ├── UI4_ToolsPanel_bk.png.meta │ │ │ ├── UI4_Up_Menu.png.meta │ │ │ ├── UI4_Up_Menu_pressed.png.meta │ │ │ ├── UI4_Up_Menu_select.png.meta │ │ │ ├── UI4_Ver_scrollbar_bk.png.meta │ │ │ ├── UI4_Ver_scrollhandle_pressed.png.meta │ │ │ ├── UI4_Ver_scrollhandle_regular.png.meta │ │ │ ├── UI4_Ver_scrollhandle_select.png.meta │ │ │ ├── UI4_Ver_separator.png.meta │ │ │ ├── UI4_Window_place.png.meta │ │ │ ├── UI4_accept_prefab.png.meta │ │ │ ├── UI4_accept_prefab_pressed.png.meta │ │ │ ├── UI4_accept_prefab_select.png.meta │ │ │ ├── UI4_actor_icon.png.meta │ │ │ ├── UI4_add_asset_icon.png.meta │ │ │ ├── UI4_add_btn.png.meta │ │ │ ├── UI4_add_btn_hover.png.meta │ │ │ ├── UI4_add_btn_pressed.png.meta │ │ │ ├── UI4_add_key.png.meta │ │ │ ├── UI4_add_key_hover.png.meta │ │ │ ├── UI4_add_key_pressed.png.meta │ │ │ ├── UI4_anchor_hover.png.meta │ │ │ ├── UI4_anchor_pressed.png.meta │ │ │ ├── UI4_anchor_regular.png.meta │ │ │ ├── UI4_anchors_hover.png.meta │ │ │ ├── UI4_anchors_pressed.png.meta │ │ │ ├── UI4_anim_file_icon.png.meta │ │ │ ├── UI4_anim_loop.png.meta │ │ │ ├── UI4_anim_loop_hover.png.meta │ │ │ ├── UI4_anim_loop_pressed.png.meta │ │ │ ├── UI4_anim_loop_regular.png.meta │ │ │ ├── UI4_anim_not_loop.png.meta │ │ │ ├── UI4_anim_pause.png.meta │ │ │ ├── UI4_anim_play.png.meta │ │ │ ├── UI4_anim_properties_icon.png.meta │ │ │ ├── UI4_anim_type.png.meta │ │ │ ├── UI4_animation_bar.png.meta │ │ │ ├── UI4_animation_component.png.meta │ │ │ ├── UI4_animation_icon.png.meta │ │ │ ├── UI4_animation_state_default.png.meta │ │ │ ├── UI4_animation_state_frame.png.meta │ │ │ ├── UI4_animation_state_hover.png.meta │ │ │ ├── UI4_animation_state_pressed.png.meta │ │ │ ├── UI4_animation_state_regular.png.meta │ │ │ ├── UI4_animation_state_shadow.png.meta │ │ │ ├── UI4_animation_wnd_icon.png.meta │ │ │ ├── UI4_asset_icon_selection.png.meta │ │ │ ├── UI4_big_file_icon.png.meta │ │ │ ├── UI4_big_folder_icon.png.meta │ │ │ ├── UI4_big_fragment_shader_icon.png.meta │ │ │ ├── UI4_big_js_file_icon.png.meta │ │ │ ├── UI4_big_lock_close.png.meta │ │ │ ├── UI4_big_lock_open.png.meta │ │ │ ├── UI4_big_lock_unknown.png.meta │ │ │ ├── UI4_big_material_icon.png.meta │ │ │ ├── UI4_big_text_file_icon.png.meta │ │ │ ├── UI4_big_vertex_shader_icon.png.meta │ │ │ ├── UI4_bones_tool.png.meta │ │ │ ├── UI4_bool_type.png.meta │ │ │ ├── UI4_break_prefab.png.meta │ │ │ ├── UI4_break_prefab_pressed.png.meta │ │ │ ├── UI4_break_prefab_select.png.meta │ │ │ ├── UI4_brush_tool.png.meta │ │ │ ├── UI4_button_focus.png.meta │ │ │ ├── UI4_button_pressed-87.png.meta │ │ │ ├── UI4_button_pressed-90.png.meta │ │ │ ├── UI4_button_pressed.png.meta │ │ │ ├── UI4_button_regular.png.meta │ │ │ ├── UI4_button_select.png.meta │ │ │ ├── UI4_camera_icn.png.meta │ │ │ ├── UI4_ch_arrows.png.meta │ │ │ ├── UI4_color_type.png.meta │ │ │ ├── UI4_common_anim_track.png.meta │ │ │ ├── UI4_component_head.png.meta │ │ │ ├── UI4_component_icon.png.meta │ │ │ ├── UI4_component_icon_dark.png.meta │ │ │ ├── UI4_create_asset_instance.png.meta │ │ │ ├── UI4_create_asset_instance_hover.png.meta │ │ │ ├── UI4_create_asset_instance_pressed.png.meta │ │ │ ├── UI4_curve_color.png.meta │ │ │ ├── UI4_curves_mode.png.meta │ │ │ ├── UI4_dopesheet_back.png.meta │ │ │ ├── UI4_drag_handle.png.meta │ │ │ ├── UI4_edit_anim_hover.png.meta │ │ │ ├── UI4_edit_anim_pressed.png.meta │ │ │ ├── UI4_edit_anim_regular.png.meta │ │ │ ├── UI4_emitter_component.png.meta │ │ │ ├── UI4_enable_dot_big.png.meta │ │ │ ├── UI4_enable_dot_big_unknown.png.meta │ │ │ ├── UI4_enable_toggle_big.png.meta │ │ │ ├── UI4_enable_toggle_big_focused.png.meta │ │ │ ├── UI4_enable_toggle_big_pressed.png.meta │ │ │ ├── UI4_enable_toggle_big_select.png.meta │ │ │ ├── UI4_eye_closed_icon.png.meta │ │ │ ├── UI4_eye_opened_icon.png.meta │ │ │ ├── UI4_filter_icon .png.meta │ │ │ ├── UI4_filter_icon.png.meta │ │ │ ├── UI4_float_type.png.meta │ │ │ ├── UI4_folder_icn.png.meta │ │ │ ├── UI4_folder_icon.png.meta │ │ │ ├── UI4_folder_icon_dark.png.meta │ │ │ ├── UI4_frame_tool.png.meta │ │ │ ├── UI4_game_icon.png.meta │ │ │ ├── UI4_gear_icon.png.meta │ │ │ ├── UI4_graph_component.png.meta │ │ │ ├── UI4_graph_icon.png.meta │ │ │ ├── UI4_gray_options.png.meta │ │ │ ├── UI4_gray_options_pressed.png.meta │ │ │ ├── UI4_gray_options_select.png.meta │ │ │ ├── UI4_green_edit_box.png.meta │ │ │ ├── UI4_handles_mode.png.meta │ │ │ ├── UI4_icon_anchor.png.meta │ │ │ ├── UI4_icon_max_size.png.meta │ │ │ ├── UI4_icon_min_size.png.meta │ │ │ ├── UI4_icon_offsets.png.meta │ │ │ ├── UI4_icon_size.png.meta │ │ │ ├── UI4_icon_weight.png.meta │ │ │ ├── UI4_image_asset_back.png.meta │ │ │ ├── UI4_image_component.png.meta │ │ │ ├── UI4_image_frame_tool.png.meta │ │ │ ├── UI4_image_icn.png.meta │ │ │ ├── UI4_key.png.meta │ │ │ ├── UI4_key_hover.png.meta │ │ │ ├── UI4_key_pressed.png.meta │ │ │ ├── UI4_keys_select border.png.meta │ │ │ ├── UI4_keys_select border_hover.png.meta │ │ │ ├── UI4_keys_select border_pressed.png.meta │ │ │ ├── UI4_keys_select.png.meta │ │ │ ├── UI4_keys_select_hover.png.meta │ │ │ ├── UI4_keys_select_pressed.png.meta │ │ │ ├── UI4_layer_big.png.meta │ │ │ ├── UI4_layer_icon_t.png.meta │ │ │ ├── UI4_link_icon-143.png.meta │ │ │ ├── UI4_link_icon.png.meta │ │ │ ├── UI4_list_icon.png.meta │ │ │ ├── UI4_lock_icon.png.meta │ │ │ ├── UI4_log_errors_icon.png.meta │ │ │ ├── UI4_log_errors_inactive_icon.png.meta │ │ │ ├── UI4_log_icon.png.meta │ │ │ ├── UI4_log_info_icon.png.meta │ │ │ ├── UI4_log_info_inactive_icon.png.meta │ │ │ ├── UI4_log_warnings_icon.png.meta │ │ │ ├── UI4_log_warnings_inactive_icon.png.meta │ │ │ ├── UI4_log_wnd_icon.png.meta │ │ │ ├── UI4_map_key.png.meta │ │ │ ├── UI4_map_key_hover.png.meta │ │ │ ├── UI4_map_key_pressed.png.meta │ │ │ ├── UI4_menu_new_asset.png.meta │ │ │ ├── UI4_menu_open_asset.png.meta │ │ │ ├── UI4_menu_revert_asset.png.meta │ │ │ ├── UI4_menu_save_as_asset.png.meta │ │ │ ├── UI4_menu_save_asset.png.meta │ │ │ ├── UI4_menu_toggled.png.meta │ │ │ ├── UI4_menu_toggled_hover.png.meta │ │ │ ├── UI4_menu_toggled_pressed.png.meta │ │ │ ├── UI4_minus_small_hover.png.meta │ │ │ ├── UI4_minus_small_pressed.png.meta │ │ │ ├── UI4_minus_small_regular.png.meta │ │ │ ├── UI4_move_left.png.meta │ │ │ ├── UI4_move_right.png.meta │ │ │ ├── UI4_move_tool.png.meta │ │ │ ├── UI4_non_loop_anim_hover.png.meta │ │ │ ├── UI4_non_loop_anim_pressed.png.meta │ │ │ ├── UI4_non_loop_anim_regular.png.meta │ │ │ ├── UI4_o2_sign.png.meta │ │ │ ├── UI4_off_dot.png.meta │ │ │ ├── UI4_on_dot.png.meta │ │ │ ├── UI4_on_off_dot.png.meta │ │ │ ├── UI4_other_type.png.meta │ │ │ ├── UI4_panel_button.png.meta │ │ │ ├── UI4_panel_button_focus.png.meta │ │ │ ├── UI4_panel_button_pressed.png.meta │ │ │ ├── UI4_panel_button_select.png.meta │ │ │ ├── UI4_panel_subpanel_bk.png.meta │ │ │ ├── UI4_panel_subpanel_pressed.png.meta │ │ │ ├── UI4_panel_subpanel_select.png.meta │ │ │ ├── UI4_path_tool.png.meta │ │ │ ├── UI4_pause_btn_inactive.png.meta │ │ │ ├── UI4_pause_btn_pressed.png.meta │ │ │ ├── UI4_pause_btn_regular.png.meta │ │ │ ├── UI4_pause_btn_select .png.meta │ │ │ ├── UI4_pause_btn_select.png.meta │ │ │ ├── UI4_pause_green.png.meta │ │ │ ├── UI4_pause_green_pressed.png.meta │ │ │ ├── UI4_pause_green_selected.png.meta │ │ │ ├── UI4_pencil_icon_green.png.meta │ │ │ ├── UI4_pivot.png.meta │ │ │ ├── UI4_pivot_icon.png.meta │ │ │ ├── UI4_pivot_pressed.png.meta │ │ │ ├── UI4_pivot_select.png.meta │ │ │ ├── UI4_play_anim_hover.png.meta │ │ │ ├── UI4_play_anim_pressed.png.meta │ │ │ ├── UI4_play_anim_regular.png.meta │ │ │ ├── UI4_play_btn_pressed.png.meta │ │ │ ├── UI4_play_btn_regular.png.meta │ │ │ ├── UI4_play_btn_select.png.meta │ │ │ ├── UI4_play_green.png.meta │ │ │ ├── UI4_play_green_pressed.png.meta │ │ │ ├── UI4_play_green_selected.png.meta │ │ │ ├── UI4_play_panel_bk.png.meta │ │ │ ├── UI4_plus_small_hover.png.meta │ │ │ ├── UI4_plus_small_pressed.png.meta │ │ │ ├── UI4_plus_small_regular.png.meta │ │ │ ├── UI4_position_icon.png.meta │ │ │ ├── UI4_prefab_link_big.png.meta │ │ │ ├── UI4_preview_anim.png.meta │ │ │ ├── UI4_red_edit_box.png.meta │ │ │ ├── UI4_remove_asset_instance.png.meta │ │ │ ├── UI4_remove_asset_instance_hover.png.meta │ │ │ ├── UI4_remove_asset_instance_pressed.png.meta │ │ │ ├── UI4_revert.png.meta │ │ │ ├── UI4_revert_prefab.png.meta │ │ │ ├── UI4_revert_prefab_pressed.png.meta │ │ │ ├── UI4_revert_prefab_select.png.meta │ │ │ ├── UI4_rewind_left.png.meta │ │ │ ├── UI4_rewind_right.png.meta │ │ │ ├── UI4_rotate_hover.png.meta │ │ │ ├── UI4_rotate_icon.png.meta │ │ │ ├── UI4_rotate_pressed.png.meta │ │ │ ├── UI4_rotate_regular.png.meta │ │ │ ├── UI4_rotate_tool.png.meta │ │ │ ├── UI4_round_field.png.meta │ │ │ ├── UI4_round_field_focused.png.meta │ │ │ ├── UI4_round_field_gray.png.meta │ │ │ ├── UI4_round_field_gray_pressed.png.meta │ │ │ ├── UI4_round_field_gray_select.png.meta │ │ │ ├── UI4_round_field_pressed.png.meta │ │ │ ├── UI4_round_field_select.png.meta │ │ │ ├── UI4_save_asset_instance.png.meta │ │ │ ├── UI4_save_asset_instance_hover.png.meta │ │ │ ├── UI4_save_asset_instance_pressed.png.meta │ │ │ ├── UI4_save_gray copy.png.meta │ │ │ ├── UI4_save_gray.png.meta │ │ │ ├── UI4_save_gray_pressed.png.meta │ │ │ ├── UI4_scale_icon.png.meta │ │ │ ├── UI4_scale_tool.png.meta │ │ │ ├── UI4_scene_icon.png.meta │ │ │ ├── UI4_search_pressed.png.meta │ │ │ ├── UI4_search_regular.png.meta │ │ │ ├── UI4_search_select.png.meta │ │ │ ├── UI4_select_tool.png.meta │ │ │ ├── UI4_selected_key.png.meta │ │ │ ├── UI4_selected_key_hover.png.meta │ │ │ ├── UI4_selected_key_pressed.png.meta │ │ │ ├── UI4_selected_map_key.png.meta │ │ │ ├── UI4_selected_map_key_hover.png.meta │ │ │ ├── UI4_selected_map_key_pressed.png.meta │ │ │ ├── UI4_selection_frame.png.meta │ │ │ ├── UI4_shadow_separator.png.meta │ │ │ ├── UI4_shear_icon.png.meta │ │ │ ├── UI4_small_panel_back.png.meta │ │ │ ├── UI4_small_panel_down_back.png.meta │ │ │ ├── UI4_small_trash_icon.png.meta │ │ │ ├── UI4_square_button.png.meta │ │ │ ├── UI4_square_button_pressed.png.meta │ │ │ ├── UI4_square_button_select.png.meta │ │ │ ├── UI4_square_field.png.meta │ │ │ ├── UI4_step_btn_pressed .png.meta │ │ │ ├── UI4_step_btn_pressed.png.meta │ │ │ ├── UI4_step_btn_regular .png.meta │ │ │ ├── UI4_step_btn_regular.png.meta │ │ │ ├── UI4_step_btn_select.png.meta │ │ │ ├── UI4_stop_anim_hover.png.meta │ │ │ ├── UI4_stop_anim_pressed.png.meta │ │ │ ├── UI4_stop_anim_regular.png.meta │ │ │ ├── UI4_stop_btn_pressed.png.meta │ │ │ ├── UI4_stop_btn_regular.png.meta │ │ │ ├── UI4_stop_btn_select.png.meta │ │ │ ├── UI4_sub_track.png.meta │ │ │ ├── UI4_tag_big.png.meta │ │ │ ├── UI4_time_line.png.meta │ │ │ ├── UI4_time_line_hover.png.meta │ │ │ ├── UI4_time_line_left.png.meta │ │ │ ├── UI4_time_line_pressed.png.meta │ │ │ ├── UI4_time_line_right.png.meta │ │ │ ├── UI4_time_line_right_hover.png.meta │ │ │ ├── UI4_time_line_right_pressed.png.meta │ │ │ ├── UI4_trach_icon.png.meta │ │ │ ├── UI4_transform_icon.png.meta │ │ │ ├── UI4_transform_icon_white.png.meta │ │ │ ├── UI4_tree_icon-223.png.meta │ │ │ ├── UI4_tree_icon-61.png.meta │ │ │ ├── UI4_tree_icon.png.meta │ │ │ ├── UI4_tree_wnd_icon.png.meta │ │ │ ├── UI4_unlock_icon.png.meta │ │ │ ├── UI4_vector_type.png.meta │ │ │ ├── UI4_weight_tool.png.meta │ │ │ ├── UI4_window_frame_docked.png.meta │ │ │ ├── UI4_window_frame_docked_tab.png.meta │ │ │ ├── UI4_window_frame_docked_tab_active_back copy.png.meta │ │ │ ├── UI4_window_frame_docked_tab_back.png.meta │ │ │ ├── UI4_window_frame_docked_tab_inactive.png.meta │ │ │ ├── UI4_window_frame_regular.png.meta │ │ │ ├── UI_Background.png.meta │ │ │ ├── UI_Box_focus.png.meta │ │ │ ├── UI_Box_pressed.png.meta │ │ │ ├── UI_Box_regular.png.meta │ │ │ ├── UI_Box_select.png.meta │ │ │ ├── UI_Check_bk.png.meta │ │ │ ├── UI_Check_bk_focus.png.meta │ │ │ ├── UI_Check_bk_pressed.png.meta │ │ │ ├── UI_Check_bk_select.png.meta │ │ │ ├── UI_Check_unknown.png.meta │ │ │ ├── UI_Ckeck.png.meta │ │ │ ├── UI_Close_button_pressed.png.meta │ │ │ ├── UI_Close_button_regular.png.meta │ │ │ ├── UI_Close_button_select.png.meta │ │ │ ├── UI_Context_menu.png.meta │ │ │ ├── UI_Context_menu_select copy.png.meta │ │ │ ├── UI_Context_menu_select.png.meta │ │ │ ├── UI_Context_menu_white.png.meta │ │ │ ├── UI_Down_icn.png.meta │ │ │ ├── UI_Editbox_focus.png.meta │ │ │ ├── UI_Editbox_pressed.png.meta │ │ │ ├── UI_Editbox_regular.png.meta │ │ │ ├── UI_Editbox_select.png.meta │ │ │ ├── UI_Hor_scrollbar_bk.png.meta │ │ │ ├── UI_Hor_scrollhandle_pressed.png.meta │ │ │ ├── UI_Hor_scrollhandle_regular.png.meta │ │ │ ├── UI_Hor_scrollhandle_select.png.meta │ │ │ ├── UI_ListBox_selection_hover.png.meta │ │ │ ├── UI_ListBox_selection_pressed.png.meta │ │ │ ├── UI_ListBox_selection_regular.png.meta │ │ │ ├── UI_Options_button_pressed.png.meta │ │ │ ├── UI_Options_button_regular.png.meta │ │ │ ├── UI_Options_button_select.png.meta │ │ │ ├── UI_Radio.png.meta │ │ │ ├── UI_Radio_bk.png.meta │ │ │ ├── UI_Radio_bk_focus.png.meta │ │ │ ├── UI_Radio_bk_pressed.png.meta │ │ │ ├── UI_Radio_bk_select.png.meta │ │ │ ├── UI_Right_icn.png.meta │ │ │ ├── UI_Right_icn_pressed.png.meta │ │ │ ├── UI_Right_icn_select.png.meta │ │ │ ├── UI_Separator.png.meta │ │ │ ├── UI_ToolsPanel_bk.png.meta │ │ │ ├── UI_Up_Menu.png.meta │ │ │ ├── UI_Up_Menu_pressed.png.meta │ │ │ ├── UI_Up_Menu_select.png.meta │ │ │ ├── UI_Ver_scrollbar_bk.png.meta │ │ │ ├── UI_Ver_scrollhandle_pressed.png.meta │ │ │ ├── UI_Ver_scrollhandle_regular.png.meta │ │ │ ├── UI_Ver_scrollhandle_select.png.meta │ │ │ ├── UI_Ver_separator.png.meta │ │ │ ├── UI_Window_place.png.meta │ │ │ ├── UI_brush_tool.png.meta │ │ │ ├── UI_brush_tool_pressed.png.meta │ │ │ ├── UI_brush_tool_select.png.meta │ │ │ ├── UI_button_focus.png.meta │ │ │ ├── UI_button_pressed.png.meta │ │ │ ├── UI_button_regular.png.meta │ │ │ ├── UI_button_select.png.meta │ │ │ ├── UI_frame_tool.png.meta │ │ │ ├── UI_frame_tool_pressed.png.meta │ │ │ ├── UI_frame_tool_select.png.meta │ │ │ ├── UI_link_icon.png.meta │ │ │ ├── UI_list_icon.png.meta │ │ │ ├── UI_lock_icon.png.meta │ │ │ ├── UI_move_tool.png.meta │ │ │ ├── UI_move_tool_pressed.png.meta │ │ │ ├── UI_move_tool_select.png.meta │ │ │ ├── UI_o2_sign.png.meta │ │ │ ├── UI_off_dot.png.meta │ │ │ ├── UI_on_dot.png.meta │ │ │ ├── UI_on_off_dot.png.meta │ │ │ ├── UI_panel_button.png.meta │ │ │ ├── UI_panel_button_focus.png.meta │ │ │ ├── UI_panel_button_pressed.png.meta │ │ │ ├── UI_panel_button_select.png.meta │ │ │ ├── UI_panel_subpanel_bk.png.meta │ │ │ ├── UI_panel_subpanel_pressed.png.meta │ │ │ ├── UI_panel_subpanel_select.png.meta │ │ │ ├── UI_pause_btn_inactive.png.meta │ │ │ ├── UI_pause_btn_pressed.png.meta │ │ │ ├── UI_pause_btn_regular.png.meta │ │ │ ├── UI_pause_btn_select.png.meta │ │ │ ├── UI_play_btn_regular.png.meta │ │ │ ├── UI_play_btn_select copy.png.meta │ │ │ ├── UI_play_btn_select.png.meta │ │ │ ├── UI_play_panel_bk.png.meta │ │ │ ├── UI_rotate_tool.png.meta │ │ │ ├── UI_rotate_tool_pressed.png.meta │ │ │ ├── UI_rotate_tool_select.png.meta │ │ │ ├── UI_scale_tool.png.meta │ │ │ ├── UI_scale_tool_pressed.png.meta │ │ │ ├── UI_scale_tool_select.png.meta │ │ │ ├── UI_search_pressed.png.meta │ │ │ ├── UI_search_regular.png.meta │ │ │ ├── UI_search_select.png.meta │ │ │ ├── UI_select_tool.png.meta │ │ │ ├── UI_select_tool_pressed.png.meta │ │ │ ├── UI_select_tool_select.png.meta │ │ │ ├── UI_square_button.png.meta │ │ │ ├── UI_square_button_pressed.png.meta │ │ │ ├── UI_square_button_select.png.meta │ │ │ ├── UI_square_field.png.meta │ │ │ ├── UI_step_btn_pressed.png.meta │ │ │ ├── UI_step_btn_regular.png.meta │ │ │ ├── UI_step_btn_select.png.meta │ │ │ ├── UI_stop_btn_pressed.png.meta │ │ │ ├── UI_stop_btn_regular.png.meta │ │ │ ├── UI_stop_btn_select.png.meta │ │ │ ├── UI_tree_icon.png.meta │ │ │ ├── UI_unlock_icon.png.meta │ │ │ ├── UI_window_frame_docked.png.meta │ │ │ ├── UI_window_frame_docked_tab.png.meta │ │ │ ├── UI_window_frame_docked_tab_active_back copy.png.meta │ │ │ ├── UI_window_frame_docked_tab_back.png.meta │ │ │ ├── UI_window_frame_docked_tab_inactive.png.meta │ │ │ ├── UI_window_frame_regular.png.meta │ │ │ ├── circle_hole_handle.png.meta │ │ │ ├── function_icon.png.meta │ │ │ ├── hor_hole_handle.png.meta │ │ │ ├── hor_slice_line.png.meta │ │ │ ├── ver_hole_handle.png.meta │ │ │ └── ver_slice_line.png.meta │ │ └── ui.meta │ ├── Platforms/ │ │ ├── Mac/ │ │ │ └── Editor.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ └── xcuserdata/ │ │ │ └── playrix.xcuserdatad/ │ │ │ └── xcschemes/ │ │ │ └── xcschememanagement.plist │ │ └── Windows/ │ │ ├── Editor.vcxproj │ │ ├── Editor.vcxproj.filters │ │ └── resource.h │ └── Sources/ │ └── o2Editor/ │ ├── Actions/ │ │ ├── ActionsList.cpp │ │ ├── ActionsList.h │ │ ├── Create.cpp │ │ ├── Create.h │ │ ├── Delete.cpp │ │ ├── Delete.h │ │ ├── Enable.cpp │ │ ├── Enable.h │ │ ├── IAction.cpp │ │ ├── IAction.h │ │ ├── Lock.cpp │ │ ├── Lock.h │ │ ├── PropertyChange.cpp │ │ ├── PropertyChange.h │ │ ├── Reparent.cpp │ │ ├── Reparent.h │ │ ├── Select.cpp │ │ ├── Select.h │ │ ├── Transform.cpp │ │ └── Transform.h │ ├── Dialogs/ │ │ ├── ColorPickerDlg.cpp │ │ ├── ColorPickerDlg.h │ │ ├── CurveEditorDlg.cpp │ │ ├── CurveEditorDlg.h │ │ ├── EditNameDlg.cpp │ │ ├── EditNameDlg.h │ │ ├── KeyEditDlg.cpp │ │ ├── KeyEditDlg.h │ │ ├── System/ │ │ │ ├── Linux/ │ │ │ │ └── OpenSaveDialog.cpp │ │ │ ├── Mac/ │ │ │ │ └── OpenSaveDialog.mm │ │ │ ├── OpenSaveDialog.h │ │ │ └── Windows/ │ │ │ └── OpenSaveDialog.cpp │ │ ├── YesNoCancelDlg.cpp │ │ └── YesNoCancelDlg.h │ ├── EditorApplication.cpp │ ├── EditorApplication.h │ ├── EditorConfig.cpp │ ├── EditorConfig.h │ ├── MenuPanel.cpp │ ├── MenuPanel.h │ ├── Properties/ │ │ ├── Basic/ │ │ │ ├── ActorProperty.cpp │ │ │ ├── ActorProperty.h │ │ │ ├── AssetProperty.cpp │ │ │ ├── AssetProperty.h │ │ │ ├── BooleanProperty.cpp │ │ │ ├── BooleanProperty.h │ │ │ ├── BorderFloatProperty.cpp │ │ │ ├── BorderFloatProperty.h │ │ │ ├── BorderIntProperty.cpp │ │ │ ├── BorderIntProperty.h │ │ │ ├── ColorGradientProperty.cpp │ │ │ ├── ColorGradientProperty.h │ │ │ ├── ColorProperty.cpp │ │ │ ├── ColorProperty.h │ │ │ ├── ComponentProperty.cpp │ │ │ ├── ComponentProperty.h │ │ │ ├── CurveProperty.cpp │ │ │ ├── CurveProperty.h │ │ │ ├── EnumMaskProperty.h │ │ │ ├── EnumProperty.cpp │ │ │ ├── EnumProperty.h │ │ │ ├── FloatProperty.cpp │ │ │ ├── FloatProperty.h │ │ │ ├── FunctionProperty.cpp │ │ │ ├── FunctionProperty.h │ │ │ ├── IntegerProperty.cpp │ │ │ ├── IntegerProperty.h │ │ │ ├── ObjectProperty.cpp │ │ │ ├── ObjectProperty.h │ │ │ ├── ObjectPtrProperty.cpp │ │ │ ├── ObjectPtrProperty.h │ │ │ ├── RectangleFloatProperty.cpp │ │ │ ├── RectangleFloatProperty.h │ │ │ ├── RectangleIntProperty.cpp │ │ │ ├── RectangleIntProperty.h │ │ │ ├── SceneLayerRefProperty.cpp │ │ │ ├── SceneLayerRefProperty.h │ │ │ ├── SceneLayersListProperty.cpp │ │ │ ├── SceneLayersListProperty.h │ │ │ ├── ScriptValueProperty.cpp │ │ │ ├── ScriptValueProperty.h │ │ │ ├── StringProperty.cpp │ │ │ ├── StringProperty.h │ │ │ ├── TagProperty.cpp │ │ │ ├── TagProperty.h │ │ │ ├── Vector2FloatProperty.cpp │ │ │ ├── Vector2FloatProperty.h │ │ │ ├── Vector2IntProperty.cpp │ │ │ ├── Vector2IntProperty.h │ │ │ ├── VectorProperty.cpp │ │ │ ├── VectorProperty.h │ │ │ ├── WStringProperty.cpp │ │ │ └── WStringProperty.h │ │ ├── IObjectPropertiesViewer.cpp │ │ ├── IObjectPropertiesViewer.h │ │ ├── IPropertyField.cpp │ │ ├── IPropertyField.h │ │ ├── ObjectViewer.cpp │ │ ├── ObjectViewer.h │ │ ├── Objects/ │ │ │ ├── Actors/ │ │ │ │ ├── CameraActorViewer.cpp │ │ │ │ └── CameraActorViewer.h │ │ │ ├── Assets/ │ │ │ │ ├── ImageAssetViewer.cpp │ │ │ │ ├── ImageAssetViewer.h │ │ │ │ ├── VectorFontAssetViewer.cpp │ │ │ │ └── VectorFontAssetViewer.h │ │ │ ├── Components/ │ │ │ │ ├── AnimationStateViewer.cpp │ │ │ │ ├── AnimationStateViewer.h │ │ │ │ ├── MeshComponentViewer.cpp │ │ │ │ ├── MeshComponentViewer.h │ │ │ │ ├── ParticlesEmitterComponentViewer.cpp │ │ │ │ ├── ParticlesEmitterComponentViewer.h │ │ │ │ ├── SkinnedMesh/ │ │ │ │ │ ├── SkinningMeshBoneComponentViewer.cpp │ │ │ │ │ ├── SkinningMeshBoneComponentViewer.h │ │ │ │ │ ├── SkinningMeshComponentViewer.cpp │ │ │ │ │ ├── SkinningMeshComponentViewer.h │ │ │ │ │ ├── SkinningMeshEditorLayer.cpp │ │ │ │ │ └── SkinningMeshEditorLayer.h │ │ │ │ ├── SplineColliderViewer.cpp │ │ │ │ └── SplineColliderViewer.h │ │ │ ├── DefaultObjectPropertiesViewer.cpp │ │ │ ├── DefaultObjectPropertiesViewer.h │ │ │ ├── ParticlesSplineEffectViewer.cpp │ │ │ ├── ParticlesSplineEffectViewer.h │ │ │ ├── SpriteViewer.cpp │ │ │ ├── SpriteViewer.h │ │ │ ├── TextViewer.cpp │ │ │ └── TextViewer.h │ │ ├── Properties.cpp │ │ ├── Properties.h │ │ ├── PropertiesContext.cpp │ │ └── PropertiesContext.h │ ├── Tools/ │ │ ├── CustomFrameTool.cpp │ │ ├── CustomFrameTool.h │ │ ├── FrameTool.cpp │ │ ├── FrameTool.h │ │ ├── IEditorTool.cpp │ │ ├── IEditorTool.h │ │ ├── ITransformTool.cpp │ │ ├── ITransformTool.h │ │ ├── MeshTopologyTool.cpp │ │ ├── MeshTopologyTool.h │ │ ├── MeshWeightsTool.cpp │ │ ├── MeshWeightsTool.h │ │ ├── MoveTool.cpp │ │ ├── MoveTool.h │ │ ├── RotateTool.cpp │ │ ├── RotateTool.h │ │ ├── ScaleTool.cpp │ │ ├── ScaleTool.h │ │ ├── SelectionTool.cpp │ │ ├── SelectionTool.h │ │ ├── SkeletonTool.cpp │ │ ├── SkeletonTool.h │ │ ├── SplineTool.cpp │ │ └── SplineTool.h │ ├── ToolsPanel.cpp │ ├── ToolsPanel.h │ ├── UI/ │ │ ├── CurveEditor/ │ │ │ ├── CurveActions.cpp │ │ │ ├── CurveActions.h │ │ │ ├── CurvesEditor.cpp │ │ │ └── CurvesEditor.h │ │ ├── CurvePreview.cpp │ │ ├── CurvePreview.h │ │ ├── FrameScrollView.cpp │ │ ├── FrameScrollView.h │ │ ├── ImageSlicesEditorWidget.cpp │ │ ├── ImageSlicesEditorWidget.h │ │ ├── ScrollView.cpp │ │ ├── ScrollView.h │ │ ├── SplineEditor/ │ │ │ ├── SplineEditor.cpp │ │ │ └── SplineEditor.h │ │ ├── SpoilerWithHead.cpp │ │ ├── SpoilerWithHead.h │ │ ├── Style/ │ │ │ ├── BasicUIStyle.cpp │ │ │ ├── BasicUIStyle.h │ │ │ ├── EditorUIStyle.cpp │ │ │ └── EditorUIStyle.h │ │ ├── TexturePreview.cpp │ │ └── TexturePreview.h │ ├── UIRoot.cpp │ ├── UIRoot.h │ ├── Utils/ │ │ ├── CommonTextures.cpp │ │ └── CommonTextures.h │ ├── Windows/ │ │ ├── AnimationStateGraphWindow/ │ │ │ ├── AnimationGraphTransitionViewer.cpp │ │ │ ├── AnimationGraphTransitionViewer.h │ │ │ ├── AnimationStateGraphEditor.cpp │ │ │ ├── AnimationStateGraphEditor.h │ │ │ ├── AnimationStateGraphWindow.cpp │ │ │ ├── AnimationStateGraphWindow.h │ │ │ ├── GraphAnimationStateViewer.cpp │ │ │ └── GraphAnimationStateViewer.h │ │ ├── AnimationWindow/ │ │ │ ├── AnimationKeysActions.cpp │ │ │ ├── AnimationKeysActions.h │ │ │ ├── AnimationWindow.cpp │ │ │ ├── AnimationWindow.h │ │ │ ├── CurvesSheet.cpp │ │ │ ├── CurvesSheet.h │ │ │ ├── KeyHandlesSheet.cpp │ │ │ ├── KeyHandlesSheet.h │ │ │ ├── PropertiesListDlg.cpp │ │ │ ├── PropertiesListDlg.h │ │ │ ├── Timeline.cpp │ │ │ ├── Timeline.h │ │ │ ├── TrackControls/ │ │ │ │ ├── AnimationKeyDragHandle.cpp │ │ │ │ ├── AnimationKeyDragHandle.h │ │ │ │ ├── AnimationTrackWrapper.h │ │ │ │ ├── ITrackControl.cpp │ │ │ │ ├── ITrackControl.h │ │ │ │ ├── KeyFramesTrackControl.cpp │ │ │ │ ├── KeyFramesTrackControl.h │ │ │ │ ├── MapKeyFramesTrackControl.cpp │ │ │ │ ├── MapKeyFramesTrackControl.h │ │ │ │ ├── SubTrackControl.cpp │ │ │ │ ├── SubTrackControl.h │ │ │ │ ├── Vec2KeyFramesTrackControl.cpp │ │ │ │ └── Vec2KeyFramesTrackControl.h │ │ │ ├── Tree.cpp │ │ │ └── Tree.h │ │ ├── AssetsWindow/ │ │ │ ├── AssetIcon.cpp │ │ │ ├── AssetIcon.h │ │ │ ├── AssetsIconsScroll.cpp │ │ │ ├── AssetsIconsScroll.h │ │ │ ├── AssetsWindow.cpp │ │ │ ├── AssetsWindow.h │ │ │ ├── FoldersTree.cpp │ │ │ └── FoldersTree.h │ │ ├── DockWindowPlace.cpp │ │ ├── DockWindowPlace.h │ │ ├── DockableWindow.cpp │ │ ├── DockableWindow.h │ │ ├── GameWindow/ │ │ │ ├── GameWindow.cpp │ │ │ └── GameWindow.h │ │ ├── IAssetEditorWindow.cpp │ │ ├── IAssetEditorWindow.h │ │ ├── IEditorWindow.cpp │ │ ├── IEditorWindow.h │ │ ├── LogWindow/ │ │ │ ├── LogWindow.cpp │ │ │ └── LogWindow.h │ │ ├── MemoryAnalyzerWindow/ │ │ │ ├── MemoryAnalyzerWindow.cpp │ │ │ └── MemoryAnalyzerWindow.h │ │ ├── PropertiesWindow/ │ │ │ ├── ActorsViewer/ │ │ │ │ ├── ActorViewer.cpp │ │ │ │ ├── ActorViewer.h │ │ │ │ ├── AddComponentPanel.cpp │ │ │ │ ├── AddComponentPanel.h │ │ │ │ ├── DefaultActorComponentViewer.cpp │ │ │ │ ├── DefaultActorComponentViewer.h │ │ │ │ ├── DefaultActorHeaderViewer.cpp │ │ │ │ ├── DefaultActorHeaderViewer.h │ │ │ │ ├── DefaultActorPropertiesViewer.cpp │ │ │ │ ├── DefaultActorPropertiesViewer.h │ │ │ │ ├── DefaultActorTransformViewer.cpp │ │ │ │ ├── DefaultActorTransformViewer.h │ │ │ │ ├── IActorComponentViewer.cpp │ │ │ │ ├── IActorComponentViewer.h │ │ │ │ ├── IActorHeaderViewer.cpp │ │ │ │ ├── IActorHeaderViewer.h │ │ │ │ ├── IActorPropertiesViewer.cpp │ │ │ │ ├── IActorPropertiesViewer.h │ │ │ │ ├── IActorTransformViewer.cpp │ │ │ │ └── IActorTransformViewer.h │ │ │ ├── AssetPropertiesViewer.cpp │ │ │ ├── AssetPropertiesViewer.h │ │ │ ├── DefaultPropertiesViewer.cpp │ │ │ ├── DefaultPropertiesViewer.h │ │ │ ├── IPropertiesViewer.cpp │ │ │ ├── IPropertiesViewer.h │ │ │ ├── PropertiesWindow.cpp │ │ │ ├── PropertiesWindow.h │ │ │ └── WidgetLayerViewer/ │ │ │ ├── DefaultWidgetLayerHeadViewer.cpp │ │ │ ├── DefaultWidgetLayerHeadViewer.h │ │ │ ├── DefaultWidgetLayerLayoutViewer.cpp │ │ │ ├── DefaultWidgetLayerLayoutViewer.h │ │ │ ├── DefaultWidgetLayerPropertiesViewer.cpp │ │ │ ├── DefaultWidgetLayerPropertiesViewer.h │ │ │ ├── IWidgetLayerHeadViewer.cpp │ │ │ ├── IWidgetLayerHeadViewer.h │ │ │ ├── IWidgetLayerLayoutViewer.cpp │ │ │ ├── IWidgetLayerLayoutViewer.h │ │ │ ├── IWidgetLayerPropertiesViewer.cpp │ │ │ ├── IWidgetLayerPropertiesViewer.h │ │ │ ├── WidgetLayerViewer.cpp │ │ │ └── WidgetLayerViewer.h │ │ ├── SceneWindow/ │ │ │ ├── LayersPopup.cpp │ │ │ ├── LayersPopup.h │ │ │ ├── SceneDragHandle.cpp │ │ │ ├── SceneDragHandle.h │ │ │ ├── SceneEditScreen.cpp │ │ │ ├── SceneEditScreen.h │ │ │ ├── SceneEditorLayer.h │ │ │ ├── SceneWindow.cpp │ │ │ └── SceneWindow.h │ │ ├── TreeWindow/ │ │ │ ├── DrawOrderTree.cpp │ │ │ ├── DrawOrderTree.h │ │ │ ├── SceneHierarchyTree.cpp │ │ │ ├── SceneHierarchyTree.h │ │ │ ├── TreeWindow.cpp │ │ │ └── TreeWindow.h │ │ ├── WindowsLayout.cpp │ │ ├── WindowsLayout.h │ │ ├── WindowsManager.cpp │ │ └── WindowsManager.h │ ├── o2Editor.cpp │ ├── stdafx.cpp │ └── stdafx.h ├── FindOpenGLES2.cmake ├── Framework/ │ ├── 3rdPartyLibs/ │ │ ├── Box2D/ │ │ │ ├── Box2D.h │ │ │ ├── Box2DConfig.cmake │ │ │ ├── CMakeLists.txt │ │ │ ├── Collision/ │ │ │ │ ├── Shapes/ │ │ │ │ │ ├── b2ChainShape.cpp │ │ │ │ │ ├── b2ChainShape.h │ │ │ │ │ ├── b2CircleShape.cpp │ │ │ │ │ ├── b2CircleShape.h │ │ │ │ │ ├── b2EdgeShape.cpp │ │ │ │ │ ├── b2EdgeShape.h │ │ │ │ │ ├── b2PolygonShape.cpp │ │ │ │ │ ├── b2PolygonShape.h │ │ │ │ │ └── b2Shape.h │ │ │ │ ├── b2BroadPhase.cpp │ │ │ │ ├── b2BroadPhase.h │ │ │ │ ├── b2CollideCircle.cpp │ │ │ │ ├── b2CollideEdge.cpp │ │ │ │ ├── b2CollidePolygon.cpp │ │ │ │ ├── b2Collision.cpp │ │ │ │ ├── b2Collision.h │ │ │ │ ├── b2Distance.cpp │ │ │ │ ├── b2Distance.h │ │ │ │ ├── b2DynamicTree.cpp │ │ │ │ ├── b2DynamicTree.h │ │ │ │ ├── b2TimeOfImpact.cpp │ │ │ │ └── b2TimeOfImpact.h │ │ │ ├── Common/ │ │ │ │ ├── b2BlockAllocator.cpp │ │ │ │ ├── b2BlockAllocator.h │ │ │ │ ├── b2Draw.cpp │ │ │ │ ├── b2Draw.h │ │ │ │ ├── b2GrowableStack.h │ │ │ │ ├── b2Math.cpp │ │ │ │ ├── b2Math.h │ │ │ │ ├── b2Settings.cpp │ │ │ │ ├── b2Settings.h │ │ │ │ ├── b2StackAllocator.cpp │ │ │ │ ├── b2StackAllocator.h │ │ │ │ ├── b2Timer.cpp │ │ │ │ └── b2Timer.h │ │ │ ├── Dynamics/ │ │ │ │ ├── Contacts/ │ │ │ │ │ ├── b2ChainAndCircleContact.cpp │ │ │ │ │ ├── b2ChainAndCircleContact.h │ │ │ │ │ ├── b2ChainAndPolygonContact.cpp │ │ │ │ │ ├── b2ChainAndPolygonContact.h │ │ │ │ │ ├── b2CircleContact.cpp │ │ │ │ │ ├── b2CircleContact.h │ │ │ │ │ ├── b2Contact.cpp │ │ │ │ │ ├── b2Contact.h │ │ │ │ │ ├── b2ContactSolver.cpp │ │ │ │ │ ├── b2ContactSolver.h │ │ │ │ │ ├── b2EdgeAndCircleContact.cpp │ │ │ │ │ ├── b2EdgeAndCircleContact.h │ │ │ │ │ ├── b2EdgeAndPolygonContact.cpp │ │ │ │ │ ├── b2EdgeAndPolygonContact.h │ │ │ │ │ ├── b2PolygonAndCircleContact.cpp │ │ │ │ │ ├── b2PolygonAndCircleContact.h │ │ │ │ │ ├── b2PolygonContact.cpp │ │ │ │ │ └── b2PolygonContact.h │ │ │ │ ├── Joints/ │ │ │ │ │ ├── b2DistanceJoint.cpp │ │ │ │ │ ├── b2DistanceJoint.h │ │ │ │ │ ├── b2FrictionJoint.cpp │ │ │ │ │ ├── b2FrictionJoint.h │ │ │ │ │ ├── b2GearJoint.cpp │ │ │ │ │ ├── b2GearJoint.h │ │ │ │ │ ├── b2Joint.cpp │ │ │ │ │ ├── b2Joint.h │ │ │ │ │ ├── b2MotorJoint.cpp │ │ │ │ │ ├── b2MotorJoint.h │ │ │ │ │ ├── b2MouseJoint.cpp │ │ │ │ │ ├── b2MouseJoint.h │ │ │ │ │ ├── b2PrismaticJoint.cpp │ │ │ │ │ ├── b2PrismaticJoint.h │ │ │ │ │ ├── b2PulleyJoint.cpp │ │ │ │ │ ├── b2PulleyJoint.h │ │ │ │ │ ├── b2RevoluteJoint.cpp │ │ │ │ │ ├── b2RevoluteJoint.h │ │ │ │ │ ├── b2RopeJoint.cpp │ │ │ │ │ ├── b2RopeJoint.h │ │ │ │ │ ├── b2WeldJoint.cpp │ │ │ │ │ ├── b2WeldJoint.h │ │ │ │ │ ├── b2WheelJoint.cpp │ │ │ │ │ └── b2WheelJoint.h │ │ │ │ ├── b2Body.cpp │ │ │ │ ├── b2Body.h │ │ │ │ ├── b2ContactManager.cpp │ │ │ │ ├── b2ContactManager.h │ │ │ │ ├── b2Fixture.cpp │ │ │ │ ├── b2Fixture.h │ │ │ │ ├── b2Island.cpp │ │ │ │ ├── b2Island.h │ │ │ │ ├── b2TimeStep.h │ │ │ │ ├── b2World.cpp │ │ │ │ ├── b2World.h │ │ │ │ ├── b2WorldCallbacks.cpp │ │ │ │ └── b2WorldCallbacks.h │ │ │ └── Rope/ │ │ │ ├── b2Rope.cpp │ │ │ └── b2Rope.h │ │ ├── CDT/ │ │ │ ├── LICENSE │ │ │ ├── extras/ │ │ │ │ ├── InitializeWithGrid.h │ │ │ │ └── VerifyTopology.h │ │ │ ├── include/ │ │ │ │ ├── CDT.h │ │ │ │ ├── CDT.hpp │ │ │ │ ├── CDTUtils.h │ │ │ │ ├── CDTUtils.hpp │ │ │ │ ├── KDTree.h │ │ │ │ ├── LocatorKDTree.h │ │ │ │ ├── predicates.h │ │ │ │ └── remove_at.hpp │ │ │ └── src/ │ │ │ └── CDT.cpp │ │ ├── CMakeLists.txt │ │ ├── CheckGCCVersion.cmake │ │ ├── FreeType/ │ │ │ ├── CMakeLists.txt │ │ │ ├── devel/ │ │ │ │ ├── ft2build.h │ │ │ │ └── ftoption.h │ │ │ ├── freetype.cmake │ │ │ ├── include/ │ │ │ │ ├── config/ │ │ │ │ │ ├── ftconfig.h │ │ │ │ │ ├── ftheader.h │ │ │ │ │ ├── ftmodule.h │ │ │ │ │ ├── ftoption.h │ │ │ │ │ └── ftstdlib.h │ │ │ │ ├── freetype.h │ │ │ │ ├── ft2build.h │ │ │ │ ├── ftadvanc.h │ │ │ │ ├── ftautoh.h │ │ │ │ ├── ftbbox.h │ │ │ │ ├── ftbdf.h │ │ │ │ ├── ftbitmap.h │ │ │ │ ├── ftbzip2.h │ │ │ │ ├── ftcache.h │ │ │ │ ├── ftcffdrv.h │ │ │ │ ├── ftchapters.h │ │ │ │ ├── ftcid.h │ │ │ │ ├── fterrdef.h │ │ │ │ ├── fterrors.h │ │ │ │ ├── ftgasp.h │ │ │ │ ├── ftglyph.h │ │ │ │ ├── ftgxval.h │ │ │ │ ├── ftgzip.h │ │ │ │ ├── ftimage.h │ │ │ │ ├── ftincrem.h │ │ │ │ ├── ftlcdfil.h │ │ │ │ ├── ftlist.h │ │ │ │ ├── ftlzw.h │ │ │ │ ├── ftmac.h │ │ │ │ ├── ftmm.h │ │ │ │ ├── ftmodapi.h │ │ │ │ ├── ftmoderr.h │ │ │ │ ├── ftotval.h │ │ │ │ ├── ftoutln.h │ │ │ │ ├── ftpfr.h │ │ │ │ ├── ftrender.h │ │ │ │ ├── ftsizes.h │ │ │ │ ├── ftsnames.h │ │ │ │ ├── ftstroke.h │ │ │ │ ├── ftsynth.h │ │ │ │ ├── ftsystem.h │ │ │ │ ├── fttrigon.h │ │ │ │ ├── ftttdrv.h │ │ │ │ ├── fttypes.h │ │ │ │ ├── ftwinfnt.h │ │ │ │ ├── ftxf86.h │ │ │ │ ├── internal/ │ │ │ │ │ ├── autohint.h │ │ │ │ │ ├── ftcalc.h │ │ │ │ │ ├── ftdebug.h │ │ │ │ │ ├── ftdriver.h │ │ │ │ │ ├── ftgloadr.h │ │ │ │ │ ├── ftmemory.h │ │ │ │ │ ├── ftobjs.h │ │ │ │ │ ├── ftpic.h │ │ │ │ │ ├── ftrfork.h │ │ │ │ │ ├── ftserv.h │ │ │ │ │ ├── ftstream.h │ │ │ │ │ ├── fttrace.h │ │ │ │ │ ├── ftvalid.h │ │ │ │ │ ├── internal.h │ │ │ │ │ ├── psaux.h │ │ │ │ │ ├── pshints.h │ │ │ │ │ ├── services/ │ │ │ │ │ │ ├── svbdf.h │ │ │ │ │ │ ├── svcid.h │ │ │ │ │ │ ├── svgldict.h │ │ │ │ │ │ ├── svgxval.h │ │ │ │ │ │ ├── svkern.h │ │ │ │ │ │ ├── svmm.h │ │ │ │ │ │ ├── svotval.h │ │ │ │ │ │ ├── svpfr.h │ │ │ │ │ │ ├── svpostnm.h │ │ │ │ │ │ ├── svprop.h │ │ │ │ │ │ ├── svpscmap.h │ │ │ │ │ │ ├── svpsinfo.h │ │ │ │ │ │ ├── svsfnt.h │ │ │ │ │ │ ├── svttcmap.h │ │ │ │ │ │ ├── svtteng.h │ │ │ │ │ │ ├── svttglyf.h │ │ │ │ │ │ ├── svwinfnt.h │ │ │ │ │ │ └── svxf86nm.h │ │ │ │ │ ├── sfnt.h │ │ │ │ │ ├── t1types.h │ │ │ │ │ └── tttypes.h │ │ │ │ ├── t1tables.h │ │ │ │ ├── ttnameid.h │ │ │ │ ├── tttables.h │ │ │ │ ├── tttags.h │ │ │ │ └── ttunpat.h │ │ │ └── src/ │ │ │ ├── autofit/ │ │ │ │ ├── afangles.c │ │ │ │ ├── afangles.h │ │ │ │ ├── afblue.c │ │ │ │ ├── afblue.cin │ │ │ │ ├── afblue.h │ │ │ │ ├── afblue.hin │ │ │ │ ├── afcjk.c │ │ │ │ ├── afcjk.h │ │ │ │ ├── afcover.h │ │ │ │ ├── afdummy.c │ │ │ │ ├── afdummy.h │ │ │ │ ├── aferrors.h │ │ │ │ ├── afglobal.c │ │ │ │ ├── afglobal.h │ │ │ │ ├── afhints.c │ │ │ │ ├── afhints.h │ │ │ │ ├── afindic.c │ │ │ │ ├── afindic.h │ │ │ │ ├── aflatin.c │ │ │ │ ├── aflatin.h │ │ │ │ ├── aflatin2.c │ │ │ │ ├── aflatin2.h │ │ │ │ ├── afloader.c │ │ │ │ ├── afloader.h │ │ │ │ ├── afmodule.c │ │ │ │ ├── afmodule.h │ │ │ │ ├── afpic.c │ │ │ │ ├── afpic.h │ │ │ │ ├── afranges.c │ │ │ │ ├── afranges.h │ │ │ │ ├── afscript.h │ │ │ │ ├── afstyles.h │ │ │ │ ├── aftypes.h │ │ │ │ ├── afwarp.c │ │ │ │ ├── afwarp.h │ │ │ │ ├── afwrtsys.h │ │ │ │ ├── autofit.c │ │ │ │ ├── hbshim.c │ │ │ │ └── hbshim.h │ │ │ ├── base/ │ │ │ │ ├── basepic.c │ │ │ │ ├── basepic.h │ │ │ │ ├── ftadvanc.c │ │ │ │ ├── ftapi.c │ │ │ │ ├── ftbase.c │ │ │ │ ├── ftbase.h │ │ │ │ ├── ftbbox.c │ │ │ │ ├── ftbdf.c │ │ │ │ ├── ftbitmap.c │ │ │ │ ├── ftcalc.c │ │ │ │ ├── ftcid.c │ │ │ │ ├── ftdbgmem.c │ │ │ │ ├── ftdebug.c │ │ │ │ ├── ftfstype.c │ │ │ │ ├── ftgasp.c │ │ │ │ ├── ftgloadr.c │ │ │ │ ├── ftglyph.c │ │ │ │ ├── ftgxval.c │ │ │ │ ├── ftinit.c │ │ │ │ ├── ftlcdfil.c │ │ │ │ ├── ftmac.c │ │ │ │ ├── ftmm.c │ │ │ │ ├── ftobjs.c │ │ │ │ ├── ftotval.c │ │ │ │ ├── ftoutln.c │ │ │ │ ├── ftpatent.c │ │ │ │ ├── ftpfr.c │ │ │ │ ├── ftpic.c │ │ │ │ ├── ftrfork.c │ │ │ │ ├── ftsnames.c │ │ │ │ ├── ftstream.c │ │ │ │ ├── ftstroke.c │ │ │ │ ├── ftsynth.c │ │ │ │ ├── ftsystem.c │ │ │ │ ├── fttrigon.c │ │ │ │ ├── fttype1.c │ │ │ │ ├── ftutil.c │ │ │ │ ├── ftwinfnt.c │ │ │ │ ├── ftxf86.c │ │ │ │ ├── md5.c │ │ │ │ └── md5.h │ │ │ ├── bdf/ │ │ │ │ ├── README │ │ │ │ ├── bdf.c │ │ │ │ ├── bdf.h │ │ │ │ ├── bdfdrivr.c │ │ │ │ ├── bdfdrivr.h │ │ │ │ ├── bdferror.h │ │ │ │ └── bdflib.c │ │ │ ├── bzip2/ │ │ │ │ └── ftbzip2.c │ │ │ ├── cache/ │ │ │ │ ├── ftcache.c │ │ │ │ ├── ftcbasic.c │ │ │ │ ├── ftccache.c │ │ │ │ ├── ftccache.h │ │ │ │ ├── ftccback.h │ │ │ │ ├── ftccmap.c │ │ │ │ ├── ftcerror.h │ │ │ │ ├── ftcglyph.c │ │ │ │ ├── ftcglyph.h │ │ │ │ ├── ftcimage.c │ │ │ │ ├── ftcimage.h │ │ │ │ ├── ftcmanag.c │ │ │ │ ├── ftcmanag.h │ │ │ │ ├── ftcmru.c │ │ │ │ ├── ftcmru.h │ │ │ │ ├── ftcsbits.c │ │ │ │ └── ftcsbits.h │ │ │ ├── cff/ │ │ │ │ ├── cf2arrst.c │ │ │ │ ├── cf2arrst.h │ │ │ │ ├── cf2blues.c │ │ │ │ ├── cf2blues.h │ │ │ │ ├── cf2error.c │ │ │ │ ├── cf2error.h │ │ │ │ ├── cf2fixed.h │ │ │ │ ├── cf2font.c │ │ │ │ ├── cf2font.h │ │ │ │ ├── cf2ft.c │ │ │ │ ├── cf2ft.h │ │ │ │ ├── cf2glue.h │ │ │ │ ├── cf2hints.c │ │ │ │ ├── cf2hints.h │ │ │ │ ├── cf2intrp.c │ │ │ │ ├── cf2intrp.h │ │ │ │ ├── cf2read.c │ │ │ │ ├── cf2read.h │ │ │ │ ├── cf2stack.c │ │ │ │ ├── cf2stack.h │ │ │ │ ├── cf2types.h │ │ │ │ ├── cff.c │ │ │ │ ├── cffcmap.c │ │ │ │ ├── cffcmap.h │ │ │ │ ├── cffdrivr.c │ │ │ │ ├── cffdrivr.h │ │ │ │ ├── cfferrs.h │ │ │ │ ├── cffgload.c │ │ │ │ ├── cffgload.h │ │ │ │ ├── cffload.c │ │ │ │ ├── cffload.h │ │ │ │ ├── cffobjs.c │ │ │ │ ├── cffobjs.h │ │ │ │ ├── cffparse.c │ │ │ │ ├── cffparse.h │ │ │ │ ├── cffpic.c │ │ │ │ ├── cffpic.h │ │ │ │ ├── cfftoken.h │ │ │ │ └── cfftypes.h │ │ │ ├── cid/ │ │ │ │ ├── ciderrs.h │ │ │ │ ├── cidgload.c │ │ │ │ ├── cidgload.h │ │ │ │ ├── cidload.c │ │ │ │ ├── cidload.h │ │ │ │ ├── cidobjs.c │ │ │ │ ├── cidobjs.h │ │ │ │ ├── cidparse.c │ │ │ │ ├── cidparse.h │ │ │ │ ├── cidriver.c │ │ │ │ ├── cidriver.h │ │ │ │ ├── cidtoken.h │ │ │ │ └── type1cid.c │ │ │ ├── gxvalid/ │ │ │ │ ├── README │ │ │ │ ├── gxvalid.c │ │ │ │ ├── gxvalid.h │ │ │ │ ├── gxvbsln.c │ │ │ │ ├── gxvcommn.c │ │ │ │ ├── gxvcommn.h │ │ │ │ ├── gxverror.h │ │ │ │ ├── gxvfeat.c │ │ │ │ ├── gxvfeat.h │ │ │ │ ├── gxvfgen.c │ │ │ │ ├── gxvjust.c │ │ │ │ ├── gxvkern.c │ │ │ │ ├── gxvlcar.c │ │ │ │ ├── gxvmod.c │ │ │ │ ├── gxvmod.h │ │ │ │ ├── gxvmort.c │ │ │ │ ├── gxvmort.h │ │ │ │ ├── gxvmort0.c │ │ │ │ ├── gxvmort1.c │ │ │ │ ├── gxvmort2.c │ │ │ │ ├── gxvmort4.c │ │ │ │ ├── gxvmort5.c │ │ │ │ ├── gxvmorx.c │ │ │ │ ├── gxvmorx.h │ │ │ │ ├── gxvmorx0.c │ │ │ │ ├── gxvmorx1.c │ │ │ │ ├── gxvmorx2.c │ │ │ │ ├── gxvmorx4.c │ │ │ │ ├── gxvmorx5.c │ │ │ │ ├── gxvopbd.c │ │ │ │ ├── gxvprop.c │ │ │ │ └── gxvtrak.c │ │ │ ├── gzip/ │ │ │ │ ├── adler32.c │ │ │ │ ├── ftgzip.c │ │ │ │ ├── infblock.c │ │ │ │ ├── infblock.h │ │ │ │ ├── infcodes.c │ │ │ │ ├── infcodes.h │ │ │ │ ├── inffixed.h │ │ │ │ ├── inflate.c │ │ │ │ ├── inftrees.c │ │ │ │ ├── inftrees.h │ │ │ │ ├── infutil.c │ │ │ │ ├── infutil.h │ │ │ │ ├── zconf.h │ │ │ │ ├── zlib.h │ │ │ │ ├── zutil.c │ │ │ │ └── zutil.h │ │ │ ├── lzw/ │ │ │ │ ├── ftlzw.c │ │ │ │ ├── ftzopen.c │ │ │ │ └── ftzopen.h │ │ │ ├── otvalid/ │ │ │ │ ├── otvalid.c │ │ │ │ ├── otvalid.h │ │ │ │ ├── otvbase.c │ │ │ │ ├── otvcommn.c │ │ │ │ ├── otvcommn.h │ │ │ │ ├── otverror.h │ │ │ │ ├── otvgdef.c │ │ │ │ ├── otvgpos.c │ │ │ │ ├── otvgpos.h │ │ │ │ ├── otvgsub.c │ │ │ │ ├── otvjstf.c │ │ │ │ ├── otvmath.c │ │ │ │ ├── otvmod.c │ │ │ │ └── otvmod.h │ │ │ ├── pcf/ │ │ │ │ ├── README │ │ │ │ ├── pcf.c │ │ │ │ ├── pcf.h │ │ │ │ ├── pcfdrivr.c │ │ │ │ ├── pcfdrivr.h │ │ │ │ ├── pcferror.h │ │ │ │ ├── pcfread.c │ │ │ │ ├── pcfread.h │ │ │ │ ├── pcfutil.c │ │ │ │ └── pcfutil.h │ │ │ ├── pfr/ │ │ │ │ ├── pfr.c │ │ │ │ ├── pfrcmap.c │ │ │ │ ├── pfrcmap.h │ │ │ │ ├── pfrdrivr.c │ │ │ │ ├── pfrdrivr.h │ │ │ │ ├── pfrerror.h │ │ │ │ ├── pfrgload.c │ │ │ │ ├── pfrgload.h │ │ │ │ ├── pfrload.c │ │ │ │ ├── pfrload.h │ │ │ │ ├── pfrobjs.c │ │ │ │ ├── pfrobjs.h │ │ │ │ ├── pfrsbit.c │ │ │ │ ├── pfrsbit.h │ │ │ │ └── pfrtypes.h │ │ │ ├── psaux/ │ │ │ │ ├── afmparse.c │ │ │ │ ├── afmparse.h │ │ │ │ ├── psaux.c │ │ │ │ ├── psauxerr.h │ │ │ │ ├── psauxmod.c │ │ │ │ ├── psauxmod.h │ │ │ │ ├── psconv.c │ │ │ │ ├── psconv.h │ │ │ │ ├── psobjs.c │ │ │ │ ├── psobjs.h │ │ │ │ ├── t1cmap.c │ │ │ │ ├── t1cmap.h │ │ │ │ ├── t1decode.c │ │ │ │ └── t1decode.h │ │ │ ├── pshinter/ │ │ │ │ ├── pshalgo.c │ │ │ │ ├── pshalgo.h │ │ │ │ ├── pshglob.c │ │ │ │ ├── pshglob.h │ │ │ │ ├── pshinter.c │ │ │ │ ├── pshmod.c │ │ │ │ ├── pshmod.h │ │ │ │ ├── pshnterr.h │ │ │ │ ├── pshpic.c │ │ │ │ ├── pshpic.h │ │ │ │ ├── pshrec.c │ │ │ │ └── pshrec.h │ │ │ ├── psnames/ │ │ │ │ ├── psmodule.c │ │ │ │ ├── psmodule.h │ │ │ │ ├── psnamerr.h │ │ │ │ ├── psnames.c │ │ │ │ ├── pspic.c │ │ │ │ ├── pspic.h │ │ │ │ └── pstables.h │ │ │ ├── raster/ │ │ │ │ ├── ftmisc.h │ │ │ │ ├── ftraster.c │ │ │ │ ├── ftraster.h │ │ │ │ ├── ftrend1.c │ │ │ │ ├── ftrend1.h │ │ │ │ ├── raster.c │ │ │ │ ├── rasterrs.h │ │ │ │ ├── rastpic.c │ │ │ │ └── rastpic.h │ │ │ ├── sfnt/ │ │ │ │ ├── pngshim.c │ │ │ │ ├── pngshim.h │ │ │ │ ├── sfdriver.c │ │ │ │ ├── sfdriver.h │ │ │ │ ├── sferrors.h │ │ │ │ ├── sfnt.c │ │ │ │ ├── sfntpic.c │ │ │ │ ├── sfntpic.h │ │ │ │ ├── sfobjs.c │ │ │ │ ├── sfobjs.h │ │ │ │ ├── ttbdf.c │ │ │ │ ├── ttbdf.h │ │ │ │ ├── ttcmap.c │ │ │ │ ├── ttcmap.h │ │ │ │ ├── ttcmapc.h │ │ │ │ ├── ttkern.c │ │ │ │ ├── ttkern.h │ │ │ │ ├── ttload.c │ │ │ │ ├── ttload.h │ │ │ │ ├── ttmtx.c │ │ │ │ ├── ttmtx.h │ │ │ │ ├── ttpost.c │ │ │ │ ├── ttpost.h │ │ │ │ ├── ttsbit.c │ │ │ │ └── ttsbit.h │ │ │ ├── smooth/ │ │ │ │ ├── ftgrays.c │ │ │ │ ├── ftgrays.h │ │ │ │ ├── ftsmerrs.h │ │ │ │ ├── ftsmooth.c │ │ │ │ ├── ftsmooth.h │ │ │ │ ├── ftspic.c │ │ │ │ ├── ftspic.h │ │ │ │ └── smooth.c │ │ │ ├── truetype/ │ │ │ │ ├── truetype.c │ │ │ │ ├── ttdriver.c │ │ │ │ ├── ttdriver.h │ │ │ │ ├── tterrors.h │ │ │ │ ├── ttgload.c │ │ │ │ ├── ttgload.h │ │ │ │ ├── ttgxvar.c │ │ │ │ ├── ttgxvar.h │ │ │ │ ├── ttinterp.c │ │ │ │ ├── ttinterp.h │ │ │ │ ├── ttobjs.c │ │ │ │ ├── ttobjs.h │ │ │ │ ├── ttpic.c │ │ │ │ ├── ttpic.h │ │ │ │ ├── ttpload.c │ │ │ │ ├── ttpload.h │ │ │ │ ├── ttsubpix.c │ │ │ │ └── ttsubpix.h │ │ │ ├── type1/ │ │ │ │ ├── t1afm.c │ │ │ │ ├── t1afm.h │ │ │ │ ├── t1driver.c │ │ │ │ ├── t1driver.h │ │ │ │ ├── t1errors.h │ │ │ │ ├── t1gload.c │ │ │ │ ├── t1gload.h │ │ │ │ ├── t1load.c │ │ │ │ ├── t1load.h │ │ │ │ ├── t1objs.c │ │ │ │ ├── t1objs.h │ │ │ │ ├── t1parse.c │ │ │ │ ├── t1parse.h │ │ │ │ ├── t1tokens.h │ │ │ │ └── type1.c │ │ │ ├── type42/ │ │ │ │ ├── t42drivr.c │ │ │ │ ├── t42drivr.h │ │ │ │ ├── t42error.h │ │ │ │ ├── t42objs.c │ │ │ │ ├── t42objs.h │ │ │ │ ├── t42parse.c │ │ │ │ ├── t42parse.h │ │ │ │ ├── t42types.h │ │ │ │ └── type42.c │ │ │ └── winfonts/ │ │ │ ├── fnterrs.h │ │ │ ├── winfnt.c │ │ │ └── winfnt.h │ │ ├── OpenGL/ │ │ │ ├── glext.h │ │ │ └── wglext.h │ │ ├── Spine/ │ │ │ ├── CMakeLists.txt │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── flags.cmake │ │ │ └── spine-cpp/ │ │ │ ├── include/ │ │ │ │ └── spine/ │ │ │ │ ├── Animation.h │ │ │ │ ├── AnimationState.h │ │ │ │ ├── AnimationStateData.h │ │ │ │ ├── Atlas.h │ │ │ │ ├── AtlasAttachmentLoader.h │ │ │ │ ├── Attachment.h │ │ │ │ ├── AttachmentLoader.h │ │ │ │ ├── AttachmentTimeline.h │ │ │ │ ├── AttachmentType.h │ │ │ │ ├── BlendMode.h │ │ │ │ ├── BlockAllocator.h │ │ │ │ ├── Bone.h │ │ │ │ ├── BoneData.h │ │ │ │ ├── BoundingBoxAttachment.h │ │ │ │ ├── ClippingAttachment.h │ │ │ │ ├── Color.h │ │ │ │ ├── ColorTimeline.h │ │ │ │ ├── ConstraintData.h │ │ │ │ ├── ContainerUtil.h │ │ │ │ ├── CurveTimeline.h │ │ │ │ ├── Debug.h │ │ │ │ ├── DeformTimeline.h │ │ │ │ ├── DrawOrderTimeline.h │ │ │ │ ├── Event.h │ │ │ │ ├── EventData.h │ │ │ │ ├── EventTimeline.h │ │ │ │ ├── Extension.h │ │ │ │ ├── HasRendererObject.h │ │ │ │ ├── HashMap.h │ │ │ │ ├── IkConstraint.h │ │ │ │ ├── IkConstraintData.h │ │ │ │ ├── IkConstraintTimeline.h │ │ │ │ ├── Inherit.h │ │ │ │ ├── InheritTimeline.h │ │ │ │ ├── Json.h │ │ │ │ ├── LinkedMesh.h │ │ │ │ ├── Log.h │ │ │ │ ├── MathUtil.h │ │ │ │ ├── MeshAttachment.h │ │ │ │ ├── MixBlend.h │ │ │ │ ├── MixDirection.h │ │ │ │ ├── PathAttachment.h │ │ │ │ ├── PathConstraint.h │ │ │ │ ├── PathConstraintData.h │ │ │ │ ├── PathConstraintMixTimeline.h │ │ │ │ ├── PathConstraintPositionTimeline.h │ │ │ │ ├── PathConstraintSpacingTimeline.h │ │ │ │ ├── Physics.h │ │ │ │ ├── PhysicsConstraint.h │ │ │ │ ├── PhysicsConstraintData.h │ │ │ │ ├── PhysicsConstraintTimeline.h │ │ │ │ ├── PointAttachment.h │ │ │ │ ├── Pool.h │ │ │ │ ├── PositionMode.h │ │ │ │ ├── Property.h │ │ │ │ ├── RTTI.h │ │ │ │ ├── RegionAttachment.h │ │ │ │ ├── RotateMode.h │ │ │ │ ├── RotateTimeline.h │ │ │ │ ├── ScaleTimeline.h │ │ │ │ ├── Sequence.h │ │ │ │ ├── SequenceTimeline.h │ │ │ │ ├── ShearTimeline.h │ │ │ │ ├── Skeleton.h │ │ │ │ ├── SkeletonBinary.h │ │ │ │ ├── SkeletonBounds.h │ │ │ │ ├── SkeletonClipping.h │ │ │ │ ├── SkeletonData.h │ │ │ │ ├── SkeletonJson.h │ │ │ │ ├── SkeletonRenderer.h │ │ │ │ ├── Skin.h │ │ │ │ ├── Slot.h │ │ │ │ ├── SlotData.h │ │ │ │ ├── SpacingMode.h │ │ │ │ ├── SpineObject.h │ │ │ │ ├── SpineString.h │ │ │ │ ├── TextureLoader.h │ │ │ │ ├── TextureRegion.h │ │ │ │ ├── Timeline.h │ │ │ │ ├── TransformConstraint.h │ │ │ │ ├── TransformConstraintData.h │ │ │ │ ├── TransformConstraintTimeline.h │ │ │ │ ├── TranslateTimeline.h │ │ │ │ ├── Triangulator.h │ │ │ │ ├── Updatable.h │ │ │ │ ├── Vector.h │ │ │ │ ├── Version.h │ │ │ │ ├── VertexAttachment.h │ │ │ │ ├── Vertices.h │ │ │ │ ├── dll.h │ │ │ │ └── spine.h │ │ │ └── src/ │ │ │ └── spine/ │ │ │ ├── Animation.cpp │ │ │ ├── AnimationState.cpp │ │ │ ├── AnimationStateData.cpp │ │ │ ├── Atlas.cpp │ │ │ ├── AtlasAttachmentLoader.cpp │ │ │ ├── Attachment.cpp │ │ │ ├── AttachmentLoader.cpp │ │ │ ├── AttachmentTimeline.cpp │ │ │ ├── Bone.cpp │ │ │ ├── BoneData.cpp │ │ │ ├── BoundingBoxAttachment.cpp │ │ │ ├── ClippingAttachment.cpp │ │ │ ├── ColorTimeline.cpp │ │ │ ├── ConstraintData.cpp │ │ │ ├── CurveTimeline.cpp │ │ │ ├── DeformTimeline.cpp │ │ │ ├── DrawOrderTimeline.cpp │ │ │ ├── Event.cpp │ │ │ ├── EventData.cpp │ │ │ ├── EventTimeline.cpp │ │ │ ├── Extension.cpp │ │ │ ├── IkConstraint.cpp │ │ │ ├── IkConstraintData.cpp │ │ │ ├── IkConstraintTimeline.cpp │ │ │ ├── InheritTimeline.cpp │ │ │ ├── Json.cpp │ │ │ ├── LinkedMesh.cpp │ │ │ ├── Log.cpp │ │ │ ├── MathUtil.cpp │ │ │ ├── MeshAttachment.cpp │ │ │ ├── PathAttachment.cpp │ │ │ ├── PathConstraint.cpp │ │ │ ├── PathConstraintData.cpp │ │ │ ├── PathConstraintMixTimeline.cpp │ │ │ ├── PathConstraintPositionTimeline.cpp │ │ │ ├── PathConstraintSpacingTimeline.cpp │ │ │ ├── PhysicsConstraint.cpp │ │ │ ├── PhysicsConstraintData.cpp │ │ │ ├── PhysicsConstraintTimeline.cpp │ │ │ ├── PointAttachment.cpp │ │ │ ├── RTTI.cpp │ │ │ ├── RegionAttachment.cpp │ │ │ ├── RotateTimeline.cpp │ │ │ ├── ScaleTimeline.cpp │ │ │ ├── Sequence.cpp │ │ │ ├── SequenceTimeline.cpp │ │ │ ├── ShearTimeline.cpp │ │ │ ├── Skeleton.cpp │ │ │ ├── SkeletonBinary.cpp │ │ │ ├── SkeletonBounds.cpp │ │ │ ├── SkeletonClipping.cpp │ │ │ ├── SkeletonData.cpp │ │ │ ├── SkeletonJson.cpp │ │ │ ├── SkeletonRenderer.cpp │ │ │ ├── Skin.cpp │ │ │ ├── Slot.cpp │ │ │ ├── SlotData.cpp │ │ │ ├── SpineObject.cpp │ │ │ ├── TextureLoader.cpp │ │ │ ├── Timeline.cpp │ │ │ ├── TransformConstraint.cpp │ │ │ ├── TransformConstraintData.cpp │ │ │ ├── TransformConstraintTimeline.cpp │ │ │ ├── TranslateTimeline.cpp │ │ │ ├── Triangulator.cpp │ │ │ ├── Updatable.cpp │ │ │ └── VertexAttachment.cpp │ │ ├── boost/ │ │ │ └── CMakeLists.txt │ │ ├── jerryscript/ │ │ │ ├── .github/ │ │ │ │ ├── ISSUE_TEMPLATE/ │ │ │ │ │ └── bug_report.md │ │ │ │ ├── pull_request_template.md │ │ │ │ └── workflows/ │ │ │ │ └── gh-actions.yml │ │ │ ├── .gitignore │ │ │ ├── CMakeLists.txt │ │ │ ├── CONTRIBUTING.md │ │ │ ├── DCO.md │ │ │ ├── Doxyfile │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── appveyor.yml │ │ │ ├── cmake/ │ │ │ │ ├── toolchain-esp32.cmake │ │ │ │ ├── toolchain_linux_aarch64.cmake │ │ │ │ ├── toolchain_linux_armv7l-el.cmake │ │ │ │ ├── toolchain_linux_armv7l.cmake │ │ │ │ ├── toolchain_linux_i686.cmake │ │ │ │ ├── toolchain_mcu_stm32f3.cmake │ │ │ │ ├── toolchain_mcu_stm32f4.cmake │ │ │ │ ├── toolchain_mcu_stm32f7.cmake │ │ │ │ ├── toolchain_mcu_tim4f.cmake │ │ │ │ ├── toolchain_openwrt_mips.cmake │ │ │ │ └── toolchain_openwrt_mipsel.cmake │ │ │ ├── docs/ │ │ │ │ ├── 00.GETTING-STARTED.md │ │ │ │ ├── 01.CONFIGURATION.md │ │ │ │ ├── 02.API-REFERENCE.md │ │ │ │ ├── 03.API-EXAMPLE.md │ │ │ │ ├── 04.INTERNALS.md │ │ │ │ ├── 05.PORT-API.md │ │ │ │ ├── 06.REFERENCE-COUNTING.md │ │ │ │ ├── 07.DEBUGGER.md │ │ │ │ ├── 08.CODING-STANDARDS.md │ │ │ │ ├── 09.EXT-REFERENCE-ARG.md │ │ │ │ ├── 10.EXT-REFERENCE-HANDLER.md │ │ │ │ ├── 11.EXT-REFERENCE-AUTORELEASE.md │ │ │ │ ├── 12.EXT-REFERENCE-MODULE.md │ │ │ │ ├── 13.DEBUGGER-TRANSPORT.md │ │ │ │ ├── 14.EXT-REFERENCE-HANDLE-SCOPE.md │ │ │ │ ├── 15.MODULE-SYSTEM.md │ │ │ │ └── 16.MIGRATION-GUIDE.md │ │ │ ├── jerry-core/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── api/ │ │ │ │ │ ├── jerry-debugger-transport.c │ │ │ │ │ ├── jerry-debugger.c │ │ │ │ │ ├── jerry-snapshot.c │ │ │ │ │ ├── jerry-snapshot.h │ │ │ │ │ └── jerry.c │ │ │ │ ├── config.h │ │ │ │ ├── debugger/ │ │ │ │ │ ├── debugger.c │ │ │ │ │ └── debugger.h │ │ │ │ ├── ecma/ │ │ │ │ │ ├── base/ │ │ │ │ │ │ ├── ecma-alloc.c │ │ │ │ │ │ ├── ecma-alloc.h │ │ │ │ │ │ ├── ecma-gc.c │ │ │ │ │ │ ├── ecma-gc.h │ │ │ │ │ │ ├── ecma-globals.h │ │ │ │ │ │ ├── ecma-helpers-collection.c │ │ │ │ │ │ ├── ecma-helpers-conversion.c │ │ │ │ │ │ ├── ecma-helpers-errol.c │ │ │ │ │ │ ├── ecma-helpers-external-pointers.c │ │ │ │ │ │ ├── ecma-helpers-number.c │ │ │ │ │ │ ├── ecma-helpers-string.c │ │ │ │ │ │ ├── ecma-helpers-value.c │ │ │ │ │ │ ├── ecma-helpers.c │ │ │ │ │ │ ├── ecma-helpers.h │ │ │ │ │ │ ├── ecma-init-finalize.c │ │ │ │ │ │ ├── ecma-init-finalize.h │ │ │ │ │ │ ├── ecma-lcache.c │ │ │ │ │ │ ├── ecma-lcache.h │ │ │ │ │ │ ├── ecma-literal-storage.c │ │ │ │ │ │ ├── ecma-literal-storage.h │ │ │ │ │ │ ├── ecma-module.c │ │ │ │ │ │ ├── ecma-module.h │ │ │ │ │ │ ├── ecma-property-hashmap.c │ │ │ │ │ │ └── ecma-property-hashmap.h │ │ │ │ │ ├── builtin-objects/ │ │ │ │ │ │ ├── ecma-builtin-array-iterator-prototype.c │ │ │ │ │ │ ├── ecma-builtin-array-iterator-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-array-prototype-unscopables.c │ │ │ │ │ │ ├── ecma-builtin-array-prototype-unscopables.inc.h │ │ │ │ │ │ ├── ecma-builtin-array-prototype.c │ │ │ │ │ │ ├── ecma-builtin-array-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-array.c │ │ │ │ │ │ ├── ecma-builtin-array.inc.h │ │ │ │ │ │ ├── ecma-builtin-arraybuffer-prototype.c │ │ │ │ │ │ ├── ecma-builtin-arraybuffer-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-arraybuffer.c │ │ │ │ │ │ ├── ecma-builtin-arraybuffer.inc.h │ │ │ │ │ │ ├── ecma-builtin-async-function-prototype.c │ │ │ │ │ │ ├── ecma-builtin-async-function-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-async-function.c │ │ │ │ │ │ ├── ecma-builtin-async-function.inc.h │ │ │ │ │ │ ├── ecma-builtin-async-generator-function.c │ │ │ │ │ │ ├── ecma-builtin-async-generator-function.inc.h │ │ │ │ │ │ ├── ecma-builtin-async-generator-prototype.c │ │ │ │ │ │ ├── ecma-builtin-async-generator-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-async-generator.c │ │ │ │ │ │ ├── ecma-builtin-async-generator.inc.h │ │ │ │ │ │ ├── ecma-builtin-async-iterator-prototype.c │ │ │ │ │ │ ├── ecma-builtin-async-iterator-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-bigint-prototype.c │ │ │ │ │ │ ├── ecma-builtin-bigint-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-bigint.c │ │ │ │ │ │ ├── ecma-builtin-bigint.inc.h │ │ │ │ │ │ ├── ecma-builtin-boolean-prototype.c │ │ │ │ │ │ ├── ecma-builtin-boolean-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-boolean.c │ │ │ │ │ │ ├── ecma-builtin-boolean.inc.h │ │ │ │ │ │ ├── ecma-builtin-dataview-prototype.c │ │ │ │ │ │ ├── ecma-builtin-dataview-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-dataview.c │ │ │ │ │ │ ├── ecma-builtin-dataview.inc.h │ │ │ │ │ │ ├── ecma-builtin-date-prototype.c │ │ │ │ │ │ ├── ecma-builtin-date-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-date.c │ │ │ │ │ │ ├── ecma-builtin-date.inc.h │ │ │ │ │ │ ├── ecma-builtin-error-prototype.c │ │ │ │ │ │ ├── ecma-builtin-error-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-error.c │ │ │ │ │ │ ├── ecma-builtin-error.inc.h │ │ │ │ │ │ ├── ecma-builtin-evalerror-prototype.c │ │ │ │ │ │ ├── ecma-builtin-evalerror-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-evalerror.c │ │ │ │ │ │ ├── ecma-builtin-evalerror.inc.h │ │ │ │ │ │ ├── ecma-builtin-function-prototype.c │ │ │ │ │ │ ├── ecma-builtin-function-prototype.h │ │ │ │ │ │ ├── ecma-builtin-function-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-function.c │ │ │ │ │ │ ├── ecma-builtin-function.inc.h │ │ │ │ │ │ ├── ecma-builtin-generator-function.c │ │ │ │ │ │ ├── ecma-builtin-generator-function.inc.h │ │ │ │ │ │ ├── ecma-builtin-generator-prototype.c │ │ │ │ │ │ ├── ecma-builtin-generator-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-generator.c │ │ │ │ │ │ ├── ecma-builtin-generator.inc.h │ │ │ │ │ │ ├── ecma-builtin-global.c │ │ │ │ │ │ ├── ecma-builtin-global.inc.h │ │ │ │ │ │ ├── ecma-builtin-handlers.c │ │ │ │ │ │ ├── ecma-builtin-handlers.h │ │ │ │ │ │ ├── ecma-builtin-handlers.inc.h │ │ │ │ │ │ ├── ecma-builtin-helpers-date.c │ │ │ │ │ │ ├── ecma-builtin-helpers-error.c │ │ │ │ │ │ ├── ecma-builtin-helpers-json.c │ │ │ │ │ │ ├── ecma-builtin-helpers-macro-defines.inc.h │ │ │ │ │ │ ├── ecma-builtin-helpers-macro-undefs.inc.h │ │ │ │ │ │ ├── ecma-builtin-helpers-sort.c │ │ │ │ │ │ ├── ecma-builtin-helpers.c │ │ │ │ │ │ ├── ecma-builtin-helpers.h │ │ │ │ │ │ ├── ecma-builtin-internal-routines-template.inc.h │ │ │ │ │ │ ├── ecma-builtin-intrinsic.c │ │ │ │ │ │ ├── ecma-builtin-intrinsic.inc.h │ │ │ │ │ │ ├── ecma-builtin-iterator-prototype.c │ │ │ │ │ │ ├── ecma-builtin-iterator-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-json.c │ │ │ │ │ │ ├── ecma-builtin-json.inc.h │ │ │ │ │ │ ├── ecma-builtin-map-iterator-prototype.c │ │ │ │ │ │ ├── ecma-builtin-map-iterator-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-map-prototype.c │ │ │ │ │ │ ├── ecma-builtin-map-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-map.c │ │ │ │ │ │ ├── ecma-builtin-map.inc.h │ │ │ │ │ │ ├── ecma-builtin-math.c │ │ │ │ │ │ ├── ecma-builtin-math.inc.h │ │ │ │ │ │ ├── ecma-builtin-number-prototype.c │ │ │ │ │ │ ├── ecma-builtin-number-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-number.c │ │ │ │ │ │ ├── ecma-builtin-number.inc.h │ │ │ │ │ │ ├── ecma-builtin-object-prototype.c │ │ │ │ │ │ ├── ecma-builtin-object-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-object.c │ │ │ │ │ │ ├── ecma-builtin-object.h │ │ │ │ │ │ ├── ecma-builtin-object.inc.h │ │ │ │ │ │ ├── ecma-builtin-promise-prototype.c │ │ │ │ │ │ ├── ecma-builtin-promise-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-promise.c │ │ │ │ │ │ ├── ecma-builtin-promise.inc.h │ │ │ │ │ │ ├── ecma-builtin-proxy.c │ │ │ │ │ │ ├── ecma-builtin-proxy.inc.h │ │ │ │ │ │ ├── ecma-builtin-rangeerror-prototype.c │ │ │ │ │ │ ├── ecma-builtin-rangeerror-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-rangeerror.c │ │ │ │ │ │ ├── ecma-builtin-rangeerror.inc.h │ │ │ │ │ │ ├── ecma-builtin-referenceerror-prototype.c │ │ │ │ │ │ ├── ecma-builtin-referenceerror-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-referenceerror.c │ │ │ │ │ │ ├── ecma-builtin-referenceerror.inc.h │ │ │ │ │ │ ├── ecma-builtin-reflect.c │ │ │ │ │ │ ├── ecma-builtin-reflect.inc.h │ │ │ │ │ │ ├── ecma-builtin-regexp-prototype.c │ │ │ │ │ │ ├── ecma-builtin-regexp-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-regexp-string-iterator-prototype.c │ │ │ │ │ │ ├── ecma-builtin-regexp-string-iterator-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-regexp.c │ │ │ │ │ │ ├── ecma-builtin-regexp.inc.h │ │ │ │ │ │ ├── ecma-builtin-set-iterator-prototype.c │ │ │ │ │ │ ├── ecma-builtin-set-iterator-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-set-prototype.c │ │ │ │ │ │ ├── ecma-builtin-set-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-set.c │ │ │ │ │ │ ├── ecma-builtin-set.inc.h │ │ │ │ │ │ ├── ecma-builtin-string-iterator-prototype.c │ │ │ │ │ │ ├── ecma-builtin-string-iterator-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-string-prototype.c │ │ │ │ │ │ ├── ecma-builtin-string-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-string.c │ │ │ │ │ │ ├── ecma-builtin-string.inc.h │ │ │ │ │ │ ├── ecma-builtin-symbol-prototype.c │ │ │ │ │ │ ├── ecma-builtin-symbol-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-symbol.c │ │ │ │ │ │ ├── ecma-builtin-symbol.inc.h │ │ │ │ │ │ ├── ecma-builtin-syntaxerror-prototype.c │ │ │ │ │ │ ├── ecma-builtin-syntaxerror-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-syntaxerror.c │ │ │ │ │ │ ├── ecma-builtin-syntaxerror.inc.h │ │ │ │ │ │ ├── ecma-builtin-type-error-thrower.c │ │ │ │ │ │ ├── ecma-builtin-type-error-thrower.inc.h │ │ │ │ │ │ ├── ecma-builtin-typeerror-prototype.c │ │ │ │ │ │ ├── ecma-builtin-typeerror-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-typeerror.c │ │ │ │ │ │ ├── ecma-builtin-typeerror.inc.h │ │ │ │ │ │ ├── ecma-builtin-urierror-prototype.c │ │ │ │ │ │ ├── ecma-builtin-urierror-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-urierror.c │ │ │ │ │ │ ├── ecma-builtin-urierror.inc.h │ │ │ │ │ │ ├── ecma-builtin-weakmap-prototype.c │ │ │ │ │ │ ├── ecma-builtin-weakmap-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-weakmap.c │ │ │ │ │ │ ├── ecma-builtin-weakmap.inc.h │ │ │ │ │ │ ├── ecma-builtin-weakset-prototype.c │ │ │ │ │ │ ├── ecma-builtin-weakset-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-weakset.c │ │ │ │ │ │ ├── ecma-builtin-weakset.inc.h │ │ │ │ │ │ ├── ecma-builtins-internal.h │ │ │ │ │ │ ├── ecma-builtins.c │ │ │ │ │ │ ├── ecma-builtins.h │ │ │ │ │ │ ├── ecma-builtins.inc.h │ │ │ │ │ │ └── typedarray/ │ │ │ │ │ │ ├── ecma-builtin-bigint64array-prototype.c │ │ │ │ │ │ ├── ecma-builtin-bigint64array-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-bigint64array.c │ │ │ │ │ │ ├── ecma-builtin-bigint64array.inc.h │ │ │ │ │ │ ├── ecma-builtin-biguint64array-prototype.c │ │ │ │ │ │ ├── ecma-builtin-biguint64array-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-biguint64array.c │ │ │ │ │ │ ├── ecma-builtin-biguint64array.inc.h │ │ │ │ │ │ ├── ecma-builtin-float32array-prototype.c │ │ │ │ │ │ ├── ecma-builtin-float32array-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-float32array.c │ │ │ │ │ │ ├── ecma-builtin-float32array.inc.h │ │ │ │ │ │ ├── ecma-builtin-float64array-prototype.c │ │ │ │ │ │ ├── ecma-builtin-float64array-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-float64array.c │ │ │ │ │ │ ├── ecma-builtin-float64array.inc.h │ │ │ │ │ │ ├── ecma-builtin-int16array-prototype.c │ │ │ │ │ │ ├── ecma-builtin-int16array-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-int16array.c │ │ │ │ │ │ ├── ecma-builtin-int16array.inc.h │ │ │ │ │ │ ├── ecma-builtin-int32array-prototype.c │ │ │ │ │ │ ├── ecma-builtin-int32array-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-int32array.c │ │ │ │ │ │ ├── ecma-builtin-int32array.inc.h │ │ │ │ │ │ ├── ecma-builtin-int8array-prototype.c │ │ │ │ │ │ ├── ecma-builtin-int8array-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-int8array.c │ │ │ │ │ │ ├── ecma-builtin-int8array.inc.h │ │ │ │ │ │ ├── ecma-builtin-typedarray-helpers.c │ │ │ │ │ │ ├── ecma-builtin-typedarray-helpers.h │ │ │ │ │ │ ├── ecma-builtin-typedarray-prototype-template.inc.h │ │ │ │ │ │ ├── ecma-builtin-typedarray-prototype.c │ │ │ │ │ │ ├── ecma-builtin-typedarray-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-typedarray-template.inc.h │ │ │ │ │ │ ├── ecma-builtin-typedarray.c │ │ │ │ │ │ ├── ecma-builtin-typedarray.inc.h │ │ │ │ │ │ ├── ecma-builtin-uint16array-prototype.c │ │ │ │ │ │ ├── ecma-builtin-uint16array-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-uint16array.c │ │ │ │ │ │ ├── ecma-builtin-uint16array.inc.h │ │ │ │ │ │ ├── ecma-builtin-uint32array-prototype.c │ │ │ │ │ │ ├── ecma-builtin-uint32array-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-uint32array.c │ │ │ │ │ │ ├── ecma-builtin-uint32array.inc.h │ │ │ │ │ │ ├── ecma-builtin-uint8array-prototype.c │ │ │ │ │ │ ├── ecma-builtin-uint8array-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-uint8array.c │ │ │ │ │ │ ├── ecma-builtin-uint8array.inc.h │ │ │ │ │ │ ├── ecma-builtin-uint8clampedarray-prototype.c │ │ │ │ │ │ ├── ecma-builtin-uint8clampedarray-prototype.inc.h │ │ │ │ │ │ ├── ecma-builtin-uint8clampedarray.c │ │ │ │ │ │ └── ecma-builtin-uint8clampedarray.inc.h │ │ │ │ │ └── operations/ │ │ │ │ │ ├── ecma-arguments-object.c │ │ │ │ │ ├── ecma-arguments-object.h │ │ │ │ │ ├── ecma-array-object.c │ │ │ │ │ ├── ecma-array-object.h │ │ │ │ │ ├── ecma-arraybuffer-object.c │ │ │ │ │ ├── ecma-arraybuffer-object.h │ │ │ │ │ ├── ecma-async-generator-object.c │ │ │ │ │ ├── ecma-async-generator-object.h │ │ │ │ │ ├── ecma-big-uint.c │ │ │ │ │ ├── ecma-big-uint.h │ │ │ │ │ ├── ecma-bigint-object.c │ │ │ │ │ ├── ecma-bigint-object.h │ │ │ │ │ ├── ecma-bigint.c │ │ │ │ │ ├── ecma-bigint.h │ │ │ │ │ ├── ecma-boolean-object.c │ │ │ │ │ ├── ecma-boolean-object.h │ │ │ │ │ ├── ecma-comparison.c │ │ │ │ │ ├── ecma-comparison.h │ │ │ │ │ ├── ecma-container-object.c │ │ │ │ │ ├── ecma-container-object.h │ │ │ │ │ ├── ecma-conversion.c │ │ │ │ │ ├── ecma-conversion.h │ │ │ │ │ ├── ecma-dataview-object.c │ │ │ │ │ ├── ecma-dataview-object.h │ │ │ │ │ ├── ecma-eval.c │ │ │ │ │ ├── ecma-eval.h │ │ │ │ │ ├── ecma-exceptions.c │ │ │ │ │ ├── ecma-exceptions.h │ │ │ │ │ ├── ecma-function-object.c │ │ │ │ │ ├── ecma-function-object.h │ │ │ │ │ ├── ecma-get-put-value.c │ │ │ │ │ ├── ecma-iterator-object.c │ │ │ │ │ ├── ecma-iterator-object.h │ │ │ │ │ ├── ecma-jobqueue.c │ │ │ │ │ ├── ecma-jobqueue.h │ │ │ │ │ ├── ecma-lex-env.c │ │ │ │ │ ├── ecma-lex-env.h │ │ │ │ │ ├── ecma-number-arithmetic.c │ │ │ │ │ ├── ecma-number-arithmetic.h │ │ │ │ │ ├── ecma-number-object.c │ │ │ │ │ ├── ecma-number-object.h │ │ │ │ │ ├── ecma-objects-general.c │ │ │ │ │ ├── ecma-objects-general.h │ │ │ │ │ ├── ecma-objects.c │ │ │ │ │ ├── ecma-objects.h │ │ │ │ │ ├── ecma-promise-object.c │ │ │ │ │ ├── ecma-promise-object.h │ │ │ │ │ ├── ecma-proxy-object.c │ │ │ │ │ ├── ecma-proxy-object.h │ │ │ │ │ ├── ecma-reference.c │ │ │ │ │ ├── ecma-reference.h │ │ │ │ │ ├── ecma-regexp-object.c │ │ │ │ │ ├── ecma-regexp-object.h │ │ │ │ │ ├── ecma-string-object.c │ │ │ │ │ ├── ecma-string-object.h │ │ │ │ │ ├── ecma-symbol-object.c │ │ │ │ │ ├── ecma-symbol-object.h │ │ │ │ │ ├── ecma-typedarray-object.c │ │ │ │ │ └── ecma-typedarray-object.h │ │ │ │ ├── include/ │ │ │ │ │ ├── jerryscript-compiler.h │ │ │ │ │ ├── jerryscript-core.h │ │ │ │ │ ├── jerryscript-debugger-transport.h │ │ │ │ │ ├── jerryscript-debugger.h │ │ │ │ │ ├── jerryscript-port.h │ │ │ │ │ ├── jerryscript-snapshot.h │ │ │ │ │ └── jerryscript.h │ │ │ │ ├── jcontext/ │ │ │ │ │ ├── jcontext.c │ │ │ │ │ └── jcontext.h │ │ │ │ ├── jmem/ │ │ │ │ │ ├── jmem-allocator-internal.h │ │ │ │ │ ├── jmem-allocator.c │ │ │ │ │ ├── jmem-heap.c │ │ │ │ │ ├── jmem-poolman.c │ │ │ │ │ └── jmem.h │ │ │ │ ├── jrt/ │ │ │ │ │ ├── jrt-bit-fields.h │ │ │ │ │ ├── jrt-fatals.c │ │ │ │ │ ├── jrt-libc-includes.h │ │ │ │ │ ├── jrt-types.h │ │ │ │ │ └── jrt.h │ │ │ │ ├── libjerry-core.pc.in │ │ │ │ ├── lit/ │ │ │ │ │ ├── lit-char-helpers.c │ │ │ │ │ ├── lit-char-helpers.h │ │ │ │ │ ├── lit-globals.h │ │ │ │ │ ├── lit-magic-strings.c │ │ │ │ │ ├── lit-magic-strings.h │ │ │ │ │ ├── lit-magic-strings.inc.h │ │ │ │ │ ├── lit-magic-strings.ini │ │ │ │ │ ├── lit-strings.c │ │ │ │ │ ├── lit-strings.h │ │ │ │ │ ├── lit-unicode-conversions-sup.inc.h │ │ │ │ │ ├── lit-unicode-conversions.inc.h │ │ │ │ │ ├── lit-unicode-folding.inc.h │ │ │ │ │ ├── lit-unicode-ranges-sup.inc.h │ │ │ │ │ └── lit-unicode-ranges.inc.h │ │ │ │ ├── parser/ │ │ │ │ │ ├── js/ │ │ │ │ │ │ ├── byte-code.c │ │ │ │ │ │ ├── byte-code.h │ │ │ │ │ │ ├── common.c │ │ │ │ │ │ ├── common.h │ │ │ │ │ │ ├── js-lexer.c │ │ │ │ │ │ ├── js-lexer.h │ │ │ │ │ │ ├── js-parser-expr.c │ │ │ │ │ │ ├── js-parser-internal.h │ │ │ │ │ │ ├── js-parser-limits.h │ │ │ │ │ │ ├── js-parser-mem.c │ │ │ │ │ │ ├── js-parser-module.c │ │ │ │ │ │ ├── js-parser-statm.c │ │ │ │ │ │ ├── js-parser-tagged-template-literal.c │ │ │ │ │ │ ├── js-parser-tagged-template-literal.h │ │ │ │ │ │ ├── js-parser-util.c │ │ │ │ │ │ ├── js-parser.c │ │ │ │ │ │ ├── js-parser.h │ │ │ │ │ │ ├── js-scanner-internal.h │ │ │ │ │ │ ├── js-scanner-ops.c │ │ │ │ │ │ ├── js-scanner-util.c │ │ │ │ │ │ ├── js-scanner.c │ │ │ │ │ │ └── js-scanner.h │ │ │ │ │ └── regexp/ │ │ │ │ │ ├── re-bytecode.c │ │ │ │ │ ├── re-bytecode.h │ │ │ │ │ ├── re-compiler-context.h │ │ │ │ │ ├── re-compiler.c │ │ │ │ │ ├── re-compiler.h │ │ │ │ │ ├── re-parser.c │ │ │ │ │ ├── re-parser.h │ │ │ │ │ └── re-token.h │ │ │ │ ├── profiles/ │ │ │ │ │ ├── README.md │ │ │ │ │ ├── es.next.profile │ │ │ │ │ ├── es2015-subset.profile │ │ │ │ │ ├── es5.1.profile │ │ │ │ │ └── minimal.profile │ │ │ │ └── vm/ │ │ │ │ ├── opcodes-ecma-arithmetics.c │ │ │ │ ├── opcodes-ecma-bitwise.c │ │ │ │ ├── opcodes-ecma-relational-equality.c │ │ │ │ ├── opcodes.c │ │ │ │ ├── opcodes.h │ │ │ │ ├── vm-defines.h │ │ │ │ ├── vm-stack.c │ │ │ │ ├── vm-stack.h │ │ │ │ ├── vm-utils.c │ │ │ │ ├── vm.c │ │ │ │ └── vm.h │ │ │ ├── jerry-debugger/ │ │ │ │ ├── README.md │ │ │ │ ├── jerry_client.py │ │ │ │ ├── jerry_client_main.py │ │ │ │ ├── jerry_client_rawpacket.py │ │ │ │ ├── jerry_client_serial.py │ │ │ │ ├── jerry_client_tcp.py │ │ │ │ └── jerry_client_websocket.py │ │ │ ├── jerry-ext/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── arg/ │ │ │ │ │ ├── arg-internal.h │ │ │ │ │ ├── arg-js-iterator-helper.c │ │ │ │ │ ├── arg-transform-functions.c │ │ │ │ │ └── arg.c │ │ │ │ ├── common/ │ │ │ │ │ └── jext-common.h │ │ │ │ ├── debugger/ │ │ │ │ │ ├── debugger-common.c │ │ │ │ │ ├── debugger-rp.c │ │ │ │ │ ├── debugger-serial.c │ │ │ │ │ ├── debugger-sha1.c │ │ │ │ │ ├── debugger-sha1.h │ │ │ │ │ ├── debugger-tcp.c │ │ │ │ │ └── debugger-ws.c │ │ │ │ ├── handle-scope/ │ │ │ │ │ ├── handle-scope-allocator.c │ │ │ │ │ ├── handle-scope-internal.h │ │ │ │ │ └── handle-scope.c │ │ │ │ ├── handler/ │ │ │ │ │ ├── handler-assert.c │ │ │ │ │ ├── handler-gc.c │ │ │ │ │ ├── handler-print.c │ │ │ │ │ ├── handler-register.c │ │ │ │ │ └── handler-resource-name.c │ │ │ │ ├── include/ │ │ │ │ │ └── jerryscript-ext/ │ │ │ │ │ ├── arg.h │ │ │ │ │ ├── arg.impl.h │ │ │ │ │ ├── autorelease.h │ │ │ │ │ ├── autorelease.impl.h │ │ │ │ │ ├── debugger.h │ │ │ │ │ ├── handle-scope.h │ │ │ │ │ ├── handler.h │ │ │ │ │ └── module.h │ │ │ │ ├── libjerry-ext.pc.in │ │ │ │ └── module/ │ │ │ │ └── module.c │ │ │ ├── jerry-main/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── benchmarking.c │ │ │ │ ├── cli.c │ │ │ │ ├── cli.h │ │ │ │ ├── libfuzzer.c │ │ │ │ ├── main-options.c │ │ │ │ ├── main-options.h │ │ │ │ ├── main-unix-snapshot.c │ │ │ │ ├── main-unix-test.c │ │ │ │ ├── main-unix.c │ │ │ │ ├── main-utils.c │ │ │ │ └── main-utils.h │ │ │ ├── jerry-math/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── acos.c │ │ │ │ ├── acosh.c │ │ │ │ ├── asin.c │ │ │ │ ├── asinh.c │ │ │ │ ├── atan.c │ │ │ │ ├── atan2.c │ │ │ │ ├── atanh.c │ │ │ │ ├── cbrt.c │ │ │ │ ├── ceil.c │ │ │ │ ├── copysign.c │ │ │ │ ├── cosh.c │ │ │ │ ├── exp.c │ │ │ │ ├── expm1.c │ │ │ │ ├── fabs.c │ │ │ │ ├── floor.c │ │ │ │ ├── fmod.c │ │ │ │ ├── include/ │ │ │ │ │ └── math.h │ │ │ │ ├── jerry-math-internal.h │ │ │ │ ├── libjerry-math.pc.in │ │ │ │ ├── log.c │ │ │ │ ├── log10.c │ │ │ │ ├── log1p.c │ │ │ │ ├── log2.c │ │ │ │ ├── nextafter.c │ │ │ │ ├── pow.c │ │ │ │ ├── scalbn.c │ │ │ │ ├── sinh.c │ │ │ │ ├── sqrt.c │ │ │ │ ├── tanh.c │ │ │ │ └── trig.c │ │ │ ├── jerry-port/ │ │ │ │ └── default/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── default-date.c │ │ │ │ ├── default-debugger.c │ │ │ │ ├── default-external-context.c │ │ │ │ ├── default-fatal.c │ │ │ │ ├── default-io.c │ │ │ │ ├── default-module.c │ │ │ │ ├── default-promise.c │ │ │ │ ├── include/ │ │ │ │ │ └── jerryscript-port-default.h │ │ │ │ └── libjerry-port-default.pc.in │ │ │ ├── sonar-project.properties │ │ │ ├── targets/ │ │ │ │ ├── curie_bsp/ │ │ │ │ │ ├── README.md │ │ │ │ │ ├── include/ │ │ │ │ │ │ ├── inttypes.h │ │ │ │ │ │ └── setjmp.h │ │ │ │ │ ├── jerry_app/ │ │ │ │ │ │ ├── arc/ │ │ │ │ │ │ │ ├── defconfig │ │ │ │ │ │ │ ├── main.c │ │ │ │ │ │ │ └── memory_pool_list.def │ │ │ │ │ │ ├── include/ │ │ │ │ │ │ │ └── project_mapping.h │ │ │ │ │ │ └── quark/ │ │ │ │ │ │ ├── defconfig │ │ │ │ │ │ ├── main.c │ │ │ │ │ │ └── memory_pool_list.def │ │ │ │ │ ├── setup.py │ │ │ │ │ └── source/ │ │ │ │ │ ├── curie-bsp-port.c │ │ │ │ │ └── setjmp.S │ │ │ │ ├── esp-idf/ │ │ │ │ │ ├── CMakeLists.txt.example │ │ │ │ │ ├── README.md │ │ │ │ │ ├── date.c │ │ │ │ │ ├── debugger.c │ │ │ │ │ ├── external-context.c │ │ │ │ │ ├── fatal.c │ │ │ │ │ ├── io.c │ │ │ │ │ ├── module.c │ │ │ │ │ └── promise.c │ │ │ │ ├── esp8266/ │ │ │ │ │ ├── LICENSE │ │ │ │ │ ├── Makefile │ │ │ │ │ ├── Makefile.esp8266 │ │ │ │ │ ├── Makefile.travis │ │ │ │ │ ├── docs/ │ │ │ │ │ │ └── ESP-PREREQUISITES.md │ │ │ │ │ ├── include/ │ │ │ │ │ │ ├── jerry_extapi.h │ │ │ │ │ │ ├── jerry_run.h │ │ │ │ │ │ └── user_config.h │ │ │ │ │ ├── js/ │ │ │ │ │ │ ├── blink.js │ │ │ │ │ │ └── main.js │ │ │ │ │ ├── ld/ │ │ │ │ │ │ └── eagle.app.v6.ld │ │ │ │ │ ├── readme.md │ │ │ │ │ └── user/ │ │ │ │ │ ├── Makefile │ │ │ │ │ ├── jerry_extapi.c │ │ │ │ │ ├── jerry_port.c │ │ │ │ │ ├── jerry_run.c │ │ │ │ │ └── user_main.c │ │ │ │ ├── mbedos5/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── Makefile │ │ │ │ │ ├── Makefile.travis │ │ │ │ │ ├── README.md │ │ │ │ │ ├── jerryscript-mbed/ │ │ │ │ │ │ ├── jerryscript-mbed-drivers/ │ │ │ │ │ │ │ ├── AnalogIn-js.h │ │ │ │ │ │ │ ├── DigitalOut-js.h │ │ │ │ │ │ │ ├── I2C-js.h │ │ │ │ │ │ │ ├── InterruptIn-js.h │ │ │ │ │ │ │ ├── PwmOut-js.h │ │ │ │ │ │ │ ├── lib_drivers.h │ │ │ │ │ │ │ ├── setInterval-js.h │ │ │ │ │ │ │ ├── setTimeout-js.h │ │ │ │ │ │ │ └── source/ │ │ │ │ │ │ │ ├── AnalogIn-js.cpp │ │ │ │ │ │ │ ├── DigitalOut-js.cpp │ │ │ │ │ │ │ ├── I2C-js.cpp │ │ │ │ │ │ │ ├── InterruptIn-js.cpp │ │ │ │ │ │ │ ├── PwmOut-js.cpp │ │ │ │ │ │ │ ├── setInterval-js.cpp │ │ │ │ │ │ │ └── setTimeout-js.cpp │ │ │ │ │ │ ├── jerryscript-mbed-event-loop/ │ │ │ │ │ │ │ ├── BoundCallback.h │ │ │ │ │ │ │ ├── EventLoop.h │ │ │ │ │ │ │ └── source/ │ │ │ │ │ │ │ └── EventLoop.cpp │ │ │ │ │ │ ├── jerryscript-mbed-launcher/ │ │ │ │ │ │ │ ├── launcher.h │ │ │ │ │ │ │ ├── setup.h │ │ │ │ │ │ │ └── source/ │ │ │ │ │ │ │ ├── launcher.cpp │ │ │ │ │ │ │ └── setup.cpp │ │ │ │ │ │ ├── jerryscript-mbed-library-registry/ │ │ │ │ │ │ │ ├── registry.h │ │ │ │ │ │ │ ├── source/ │ │ │ │ │ │ │ │ ├── registry.cpp │ │ │ │ │ │ │ │ └── wrap_tools.cpp │ │ │ │ │ │ │ └── wrap_tools.h │ │ │ │ │ │ └── jerryscript-mbed-util/ │ │ │ │ │ │ ├── js_source.h │ │ │ │ │ │ ├── logging.h │ │ │ │ │ │ └── wrappers.h │ │ │ │ │ ├── js/ │ │ │ │ │ │ ├── flash_leds.js │ │ │ │ │ │ └── main.js │ │ │ │ │ ├── mbed-os.lib │ │ │ │ │ ├── mbed_app.json │ │ │ │ │ ├── source/ │ │ │ │ │ │ └── jerry_port_mbed.c │ │ │ │ │ ├── template-mbedignore.txt │ │ │ │ │ └── tools/ │ │ │ │ │ ├── check_pins.sh │ │ │ │ │ ├── cmsis.h │ │ │ │ │ ├── generate_pins.py │ │ │ │ │ ├── jshint.conf │ │ │ │ │ └── requirements.txt │ │ │ │ ├── nuttx-stm32f4/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── Kconfig │ │ │ │ │ ├── Make.defs │ │ │ │ │ ├── Makefile │ │ │ │ │ ├── Makefile.travis │ │ │ │ │ ├── README.md │ │ │ │ │ ├── jerry_main.c │ │ │ │ │ ├── jerry_port.c │ │ │ │ │ ├── setjmp.S │ │ │ │ │ └── setjmp.h │ │ │ │ ├── openwrt/ │ │ │ │ │ └── readme.md │ │ │ │ ├── particle/ │ │ │ │ │ ├── Makefile.particle │ │ │ │ │ ├── README.md │ │ │ │ │ └── source/ │ │ │ │ │ └── main.cpp │ │ │ │ ├── riot-stm32f4/ │ │ │ │ │ ├── Makefile │ │ │ │ │ ├── Makefile.riot │ │ │ │ │ ├── Makefile.travis │ │ │ │ │ ├── README.md │ │ │ │ │ └── source/ │ │ │ │ │ └── main-riotos.c │ │ │ │ └── zephyr/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── Makefile.travis │ │ │ │ ├── Makefile.zephyr │ │ │ │ ├── README.md │ │ │ │ ├── prj.conf │ │ │ │ └── src/ │ │ │ │ ├── Makefile │ │ │ │ ├── getline-zephyr.c │ │ │ │ ├── getline-zephyr.h │ │ │ │ ├── jerry-port.c │ │ │ │ └── main-zephyr.c │ │ │ ├── tests/ │ │ │ │ ├── .gitattributes │ │ │ │ ├── benchmarks/ │ │ │ │ │ └── jerry/ │ │ │ │ │ ├── fill-array-with-numbers-3-times-5000-elements.js │ │ │ │ │ ├── function_loop.js │ │ │ │ │ ├── gc.js │ │ │ │ │ ├── loop_arithmetics_10kk.js │ │ │ │ │ └── loop_arithmetics_1kk.js │ │ │ │ ├── debugger/ │ │ │ │ │ ├── client_source.cmd │ │ │ │ │ ├── client_source.expected │ │ │ │ │ ├── client_source.js │ │ │ │ │ ├── client_source_multiple.cmd │ │ │ │ │ ├── client_source_multiple.expected │ │ │ │ │ ├── client_source_multiple_1.js │ │ │ │ │ ├── client_source_multiple_2.js │ │ │ │ │ ├── do_abort.cmd │ │ │ │ │ ├── do_abort.expected │ │ │ │ │ ├── do_abort.js │ │ │ │ │ ├── do_backtrace.cmd │ │ │ │ │ ├── do_backtrace.expected │ │ │ │ │ ├── do_backtrace.js │ │ │ │ │ ├── do_break.cmd │ │ │ │ │ ├── do_break.expected │ │ │ │ │ ├── do_break.js │ │ │ │ │ ├── do_continue.cmd │ │ │ │ │ ├── do_continue.expected │ │ │ │ │ ├── do_continue.js │ │ │ │ │ ├── do_delete.cmd │ │ │ │ │ ├── do_delete.expected │ │ │ │ │ ├── do_delete.js │ │ │ │ │ ├── do_delete_all.cmd │ │ │ │ │ ├── do_delete_all.expected │ │ │ │ │ ├── do_delete_all.js │ │ │ │ │ ├── do_display.cmd │ │ │ │ │ ├── do_display.expected │ │ │ │ │ ├── do_display.js │ │ │ │ │ ├── do_eval.cmd │ │ │ │ │ ├── do_eval.expected │ │ │ │ │ ├── do_eval.js │ │ │ │ │ ├── do_eval_at.cmd │ │ │ │ │ ├── do_eval_at.expected │ │ │ │ │ ├── do_eval_at.js │ │ │ │ │ ├── do_eval_syntax.cmd │ │ │ │ │ ├── do_eval_syntax.expected │ │ │ │ │ ├── do_eval_syntax.js │ │ │ │ │ ├── do_exception.cmd │ │ │ │ │ ├── do_exception.expected │ │ │ │ │ ├── do_exception.js │ │ │ │ │ ├── do_finish.cmd │ │ │ │ │ ├── do_finish.expected │ │ │ │ │ ├── do_finish.js │ │ │ │ │ ├── do_help.cmd │ │ │ │ │ ├── do_help.expected │ │ │ │ │ ├── do_help.js │ │ │ │ │ ├── do_list.cmd │ │ │ │ │ ├── do_list.expected │ │ │ │ │ ├── do_list.js │ │ │ │ │ ├── do_next.cmd │ │ │ │ │ ├── do_next.expected │ │ │ │ │ ├── do_next.js │ │ │ │ │ ├── do_pending_breakpoints.cmd │ │ │ │ │ ├── do_pending_breakpoints.expected │ │ │ │ │ ├── do_pending_breakpoints.js │ │ │ │ │ ├── do_print.cmd │ │ │ │ │ ├── do_print.expected │ │ │ │ │ ├── do_print.js │ │ │ │ │ ├── do_quit.cmd │ │ │ │ │ ├── do_quit.expected │ │ │ │ │ ├── do_quit.js │ │ │ │ │ ├── do_restart.cmd │ │ │ │ │ ├── do_restart.expected │ │ │ │ │ ├── do_restart.js │ │ │ │ │ ├── do_scope.cmd │ │ │ │ │ ├── do_scope.expected │ │ │ │ │ ├── do_scope.js │ │ │ │ │ ├── do_src.cmd │ │ │ │ │ ├── do_src.expected │ │ │ │ │ ├── do_src.js │ │ │ │ │ ├── do_step.cmd │ │ │ │ │ ├── do_step.expected │ │ │ │ │ ├── do_step.js │ │ │ │ │ ├── do_throw.cmd │ │ │ │ │ ├── do_throw.expected │ │ │ │ │ ├── do_throw.js │ │ │ │ │ ├── do_throw_adv.cmd │ │ │ │ │ ├── do_throw_adv.expected │ │ │ │ │ ├── do_throw_adv.js │ │ │ │ │ ├── do_variables.cmd │ │ │ │ │ ├── do_variables.expected │ │ │ │ │ └── do_variables.js │ │ │ │ ├── hello.js │ │ │ │ ├── jerry/ │ │ │ │ │ ├── and-or.js │ │ │ │ │ ├── arguments-parse.js │ │ │ │ │ ├── arguments.js │ │ │ │ │ ├── arithmetics-bignums.js │ │ │ │ │ ├── arithmetics.js │ │ │ │ │ ├── array-prototype-concat.js │ │ │ │ │ ├── array-prototype-every.js │ │ │ │ │ ├── array-prototype-filter.js │ │ │ │ │ ├── array-prototype-foreach.js │ │ │ │ │ ├── array-prototype-indexof.js │ │ │ │ │ ├── array-prototype-join.js │ │ │ │ │ ├── array-prototype-lastindexof.js │ │ │ │ │ ├── array-prototype-map.js │ │ │ │ │ ├── array-prototype-pop.js │ │ │ │ │ ├── array-prototype-push.js │ │ │ │ │ ├── array-prototype-reduce-right.js │ │ │ │ │ ├── array-prototype-reduce.js │ │ │ │ │ ├── array-prototype-reverse.js │ │ │ │ │ ├── array-prototype-shift.js │ │ │ │ │ ├── array-prototype-slice.js │ │ │ │ │ ├── array-prototype-some.js │ │ │ │ │ ├── array-prototype-sort.js │ │ │ │ │ ├── array-prototype-splice.js │ │ │ │ │ ├── array-prototype-tolocalestring.js │ │ │ │ │ ├── array-prototype-tostring.js │ │ │ │ │ ├── array-prototype-unshift.js │ │ │ │ │ ├── array.js │ │ │ │ │ ├── assignments.js │ │ │ │ │ ├── bitwise-logic.js │ │ │ │ │ ├── break-continue-nested-to-try-with-blocks.js │ │ │ │ │ ├── builtin-constructor-class.js │ │ │ │ │ ├── builtin-prototypes.js │ │ │ │ │ ├── date-annexb.js │ │ │ │ │ ├── date-construct.js │ │ │ │ │ ├── date-getters.js │ │ │ │ │ ├── date-parse.js │ │ │ │ │ ├── date-setters.js │ │ │ │ │ ├── date-toisostring.js │ │ │ │ │ ├── date-tojson.js │ │ │ │ │ ├── date-tostring.js │ │ │ │ │ ├── date-utc.js │ │ │ │ │ ├── delete.js │ │ │ │ │ ├── do-while.js │ │ │ │ │ ├── empty-varg.js │ │ │ │ │ ├── equality.js │ │ │ │ │ ├── error.js │ │ │ │ │ ├── es.next/ │ │ │ │ │ │ ├── argument-spread.js │ │ │ │ │ │ ├── arguments-iterator.js │ │ │ │ │ │ ├── arguments.js │ │ │ │ │ │ ├── arithmetic-parse.js │ │ │ │ │ │ ├── arithmetics-2.js │ │ │ │ │ │ ├── arithmetics-3.js │ │ │ │ │ │ ├── array-from.js │ │ │ │ │ │ ├── array-isarray.js │ │ │ │ │ │ ├── array-new-target-support.js │ │ │ │ │ │ ├── array-of.js │ │ │ │ │ │ ├── array-pattern.js │ │ │ │ │ │ ├── array-prototype-copywithin.js │ │ │ │ │ │ ├── array-prototype-entries.js │ │ │ │ │ │ ├── array-prototype-fill.js │ │ │ │ │ │ ├── array-prototype-find-index.js │ │ │ │ │ │ ├── array-prototype-find.js │ │ │ │ │ │ ├── array-prototype-flat-flatMap.js │ │ │ │ │ │ ├── array-prototype-includes.js │ │ │ │ │ │ ├── array-prototype-keys.js │ │ │ │ │ │ ├── array-prototype-slice.js │ │ │ │ │ │ ├── array-prototype-sort.js │ │ │ │ │ │ ├── array-prototype-unshift.js │ │ │ │ │ │ ├── array-prototype-values.js │ │ │ │ │ │ ├── array-species.js │ │ │ │ │ │ ├── array-spread.js │ │ │ │ │ │ ├── arraybuffer-isview.js │ │ │ │ │ │ ├── arrow-assignment.js │ │ │ │ │ │ ├── arrow-eval.js │ │ │ │ │ │ ├── arrow-function.js │ │ │ │ │ │ ├── arrow-this.js │ │ │ │ │ │ ├── bigint-typedarray-prototype-filter.js │ │ │ │ │ │ ├── bigint-typedarray-prototype-reduce.js │ │ │ │ │ │ ├── bigint1.js │ │ │ │ │ │ ├── bigint2.js │ │ │ │ │ │ ├── bigint3.js │ │ │ │ │ │ ├── bigint4.js │ │ │ │ │ │ ├── bigint5.js │ │ │ │ │ │ ├── bigint6.js │ │ │ │ │ │ ├── bigint7.js │ │ │ │ │ │ ├── bigint8.js │ │ │ │ │ │ ├── bigint9.js │ │ │ │ │ │ ├── binary-literal.js │ │ │ │ │ │ ├── block-var-redecl.js │ │ │ │ │ │ ├── builtin-objects-accessor-property-configurable.js │ │ │ │ │ │ ├── builtin-prototypes.js │ │ │ │ │ │ ├── class-fields1.js │ │ │ │ │ │ ├── class-fields2.js │ │ │ │ │ │ ├── class-fields3.js │ │ │ │ │ │ ├── class-fields4.js │ │ │ │ │ │ ├── class-fields5.js │ │ │ │ │ │ ├── class-get-set-as-method.js │ │ │ │ │ │ ├── class-inheritance-bound.js │ │ │ │ │ │ ├── class-inheritance-builtin-array.js │ │ │ │ │ │ ├── class-inheritance-builtin-typedarray.js │ │ │ │ │ │ ├── class-inheritance-core-1.js │ │ │ │ │ │ ├── class-inheritance-core-10.js │ │ │ │ │ │ ├── class-inheritance-core-11.js │ │ │ │ │ │ ├── class-inheritance-core-12.js │ │ │ │ │ │ ├── class-inheritance-core-13.js │ │ │ │ │ │ ├── class-inheritance-core-14.js │ │ │ │ │ │ ├── class-inheritance-core-15.js │ │ │ │ │ │ ├── class-inheritance-core-2.js │ │ │ │ │ │ ├── class-inheritance-core-3.js │ │ │ │ │ │ ├── class-inheritance-core-4.js │ │ │ │ │ │ ├── class-inheritance-core-5.js │ │ │ │ │ │ ├── class-inheritance-core-6.js │ │ │ │ │ │ ├── class-inheritance-core-7.js │ │ │ │ │ │ ├── class-inheritance-core-8.js │ │ │ │ │ │ ├── class-inheritance-core-9.js │ │ │ │ │ │ ├── class-inheritance-early-semantics.js │ │ │ │ │ │ ├── class-inheritance-has-instance.js │ │ │ │ │ │ ├── class-inheritance-inner-class.js │ │ │ │ │ │ ├── class-inheritance-mixins-1.js │ │ │ │ │ │ ├── class-inheritance-mixins-2.js │ │ │ │ │ │ ├── class-super-access-direct.js │ │ │ │ │ │ ├── class-super-access-indirect.js │ │ │ │ │ │ ├── class-with.js │ │ │ │ │ │ ├── class.js │ │ │ │ │ │ ├── const1.js │ │ │ │ │ │ ├── continue.js │ │ │ │ │ │ ├── dataview.js │ │ │ │ │ │ ├── date-construct.js │ │ │ │ │ │ ├── date-prototype-toprimitive.js │ │ │ │ │ │ ├── decimal-with-leading-zero.js │ │ │ │ │ │ ├── directive.js │ │ │ │ │ │ ├── error-names.js │ │ │ │ │ │ ├── error.js │ │ │ │ │ │ ├── exponentiation.js │ │ │ │ │ │ ├── for-await-of-iterator-close.js │ │ │ │ │ │ ├── for-await-of.js │ │ │ │ │ │ ├── for-let-reference-error.js │ │ │ │ │ │ ├── for-let.js │ │ │ │ │ │ ├── for-of-iterator-close.js │ │ │ │ │ │ ├── for-of.js │ │ │ │ │ │ ├── for-pattern.js │ │ │ │ │ │ ├── forin-header-strict.js │ │ │ │ │ │ ├── function-accessor.js │ │ │ │ │ │ ├── function-arguments-caller.js │ │ │ │ │ │ ├── function-async-gen1.js │ │ │ │ │ │ ├── function-async-gen2.js │ │ │ │ │ │ ├── function-async-gen3.js │ │ │ │ │ │ ├── function-async-gen4.js │ │ │ │ │ │ ├── function-async1.js │ │ │ │ │ │ ├── function-async2.js │ │ │ │ │ │ ├── function-async3.js │ │ │ │ │ │ ├── function-await1.js │ │ │ │ │ │ ├── function-await2.js │ │ │ │ │ │ ├── function-await3.js │ │ │ │ │ │ ├── function-call.js │ │ │ │ │ │ ├── function-decl.js │ │ │ │ │ │ ├── function-if.js │ │ │ │ │ │ ├── function-name.js │ │ │ │ │ │ ├── function-new-target.js │ │ │ │ │ │ ├── function-param-init.js │ │ │ │ │ │ ├── function-param-init2.js │ │ │ │ │ │ ├── function-param-init3.js │ │ │ │ │ │ ├── function-param-init4.js │ │ │ │ │ │ ├── function-pattern1.js │ │ │ │ │ │ ├── function-pattern2.js │ │ │ │ │ │ ├── function-properties.js │ │ │ │ │ │ ├── function-prototype-bind.js │ │ │ │ │ │ ├── function-prototype-hasinstance-class.js │ │ │ │ │ │ ├── function-prototype-hasinstance.js │ │ │ │ │ │ ├── function-rest-parameter.js │ │ │ │ │ │ ├── function-scope.js │ │ │ │ │ │ ├── function-scope2.js │ │ │ │ │ │ ├── generator-function.js │ │ │ │ │ │ ├── generator-initializer.js │ │ │ │ │ │ ├── generator-return.js │ │ │ │ │ │ ├── generator-throw.js │ │ │ │ │ │ ├── generator-yield-iterator.js │ │ │ │ │ │ ├── generator-yield.js │ │ │ │ │ │ ├── generator.js │ │ │ │ │ │ ├── global-this.js │ │ │ │ │ │ ├── global-unescape.js │ │ │ │ │ │ ├── identifier-escape.js │ │ │ │ │ │ ├── instanceof-symbol-hasinstance-class.js │ │ │ │ │ │ ├── instanceof-symbol-hasinstance.js │ │ │ │ │ │ ├── intrinsic-properties.js │ │ │ │ │ │ ├── iterator-prototype.js │ │ │ │ │ │ ├── json-parse-proxy.js │ │ │ │ │ │ ├── json-stringify.js │ │ │ │ │ │ ├── json-superset.js │ │ │ │ │ │ ├── length-property.js │ │ │ │ │ │ ├── let1.js │ │ │ │ │ │ ├── let10.js │ │ │ │ │ │ ├── let11.js │ │ │ │ │ │ ├── let12.js │ │ │ │ │ │ ├── let13.js │ │ │ │ │ │ ├── let14.js │ │ │ │ │ │ ├── let15.js │ │ │ │ │ │ ├── let2.js │ │ │ │ │ │ ├── let3.js │ │ │ │ │ │ ├── let4.js │ │ │ │ │ │ ├── let5.js │ │ │ │ │ │ ├── let6.js │ │ │ │ │ │ ├── let7.js │ │ │ │ │ │ ├── let8.js │ │ │ │ │ │ ├── let9.js │ │ │ │ │ │ ├── map-iterators.js │ │ │ │ │ │ ├── map-prototype-foreach.js │ │ │ │ │ │ ├── map.js │ │ │ │ │ │ ├── math-acosh.js │ │ │ │ │ │ ├── math-asinh.js │ │ │ │ │ │ ├── math-atanh.js │ │ │ │ │ │ ├── math-cbrt.js │ │ │ │ │ │ ├── math-cosh.js │ │ │ │ │ │ ├── math-expm1.js │ │ │ │ │ │ ├── math-functions-tonumber-rule2.js │ │ │ │ │ │ ├── math-log10.js │ │ │ │ │ │ ├── math-log1p.js │ │ │ │ │ │ ├── math-log2.js │ │ │ │ │ │ ├── math-sign.js │ │ │ │ │ │ ├── math-sinh.js │ │ │ │ │ │ ├── math-tanh.js │ │ │ │ │ │ ├── math-trunc.js │ │ │ │ │ │ ├── module-export-01.mjs │ │ │ │ │ │ ├── module-export-02.mjs │ │ │ │ │ │ ├── module-export-03.mjs │ │ │ │ │ │ ├── module-export-04.mjs │ │ │ │ │ │ ├── module-export-05.mjs │ │ │ │ │ │ ├── module-export-06.mjs │ │ │ │ │ │ ├── module-export-07.mjs │ │ │ │ │ │ ├── module-export-08.mjs │ │ │ │ │ │ ├── module-export-default-1.mjs │ │ │ │ │ │ ├── module-export-default-2.mjs │ │ │ │ │ │ ├── module-export-default-3.mjs │ │ │ │ │ │ ├── module-export-default-4.mjs │ │ │ │ │ │ ├── module-export-default-5.mjs │ │ │ │ │ │ ├── module-export-default-6.mjs │ │ │ │ │ │ ├── module-export-default-7.mjs │ │ │ │ │ │ ├── module-export-default-8.mjs │ │ │ │ │ │ ├── module-export-default-9.mjs │ │ │ │ │ │ ├── module-export-default-main.mjs │ │ │ │ │ │ ├── module-export-fail-test.mjs │ │ │ │ │ │ ├── module-import-01.mjs │ │ │ │ │ │ ├── module-import-02.mjs │ │ │ │ │ │ ├── module-import-03.mjs │ │ │ │ │ │ ├── module-import-04.mjs │ │ │ │ │ │ ├── module-import-05.mjs │ │ │ │ │ │ ├── module-resource-name-export.mjs │ │ │ │ │ │ ├── module-resource-name.mjs │ │ │ │ │ │ ├── new-target-async.js │ │ │ │ │ │ ├── new-target-class.js │ │ │ │ │ │ ├── new-target-error.js │ │ │ │ │ │ ├── new-target-for-boolean.js │ │ │ │ │ │ ├── new-target-for-containers.js │ │ │ │ │ │ ├── new-target-for-dataview.js │ │ │ │ │ │ ├── new-target-for-date-object.js │ │ │ │ │ │ ├── new-target-for-number.js │ │ │ │ │ │ ├── new-target-for-string.js │ │ │ │ │ │ ├── new-target-for-typedarray-and-arraybuffer.js │ │ │ │ │ │ ├── new-target-generator.js │ │ │ │ │ │ ├── new-target.js │ │ │ │ │ │ ├── nullish-coalescing.js │ │ │ │ │ │ ├── number-constants.js │ │ │ │ │ │ ├── number-isfinite.js │ │ │ │ │ │ ├── number-isinteger.js │ │ │ │ │ │ ├── number-isnan.js │ │ │ │ │ │ ├── number-issafeinteger.js │ │ │ │ │ │ ├── number-methods.js │ │ │ │ │ │ ├── numeric-separator.js │ │ │ │ │ │ ├── object-assign.js │ │ │ │ │ │ ├── object-computed-prescanner.js │ │ │ │ │ │ ├── object-computed.js │ │ │ │ │ │ ├── object-copy-data.js │ │ │ │ │ │ ├── object-define-properties.js │ │ │ │ │ │ ├── object-entries.js │ │ │ │ │ │ ├── object-freeze-with-symbol.js │ │ │ │ │ │ ├── object-fromEntries.js │ │ │ │ │ │ ├── object-get-own-property-descriptors.js │ │ │ │ │ │ ├── object-get-own-property-names.js │ │ │ │ │ │ ├── object-get-own-property-symbols.js │ │ │ │ │ │ ├── object-getprototypeof.js │ │ │ │ │ │ ├── object-initializer.js │ │ │ │ │ │ ├── object-is.js │ │ │ │ │ │ ├── object-keys.js │ │ │ │ │ │ ├── object-literal-super.js │ │ │ │ │ │ ├── object-methods.js │ │ │ │ │ │ ├── object-pattern.js │ │ │ │ │ │ ├── object-pattern2.js │ │ │ │ │ │ ├── object-property-redefiniton.js │ │ │ │ │ │ ├── object-prototype-define-getter.js │ │ │ │ │ │ ├── object-prototype-define-setter.js │ │ │ │ │ │ ├── object-prototype-lookup-getter.js │ │ │ │ │ │ ├── object-prototype-lookup-setter.js │ │ │ │ │ │ ├── object-prototype-proto.js │ │ │ │ │ │ ├── object-prototype-tostring.js │ │ │ │ │ │ ├── object-seal-with-symbol.js │ │ │ │ │ │ ├── object-values.js │ │ │ │ │ │ ├── octal-literal.js │ │ │ │ │ │ ├── parser-additive-op-assign.js │ │ │ │ │ │ ├── parser-binary-bitwise-op-assign-1.js │ │ │ │ │ │ ├── parser-binary-bitwise-op-assign-2.js │ │ │ │ │ │ ├── parser-binary-bitwise-op-assign-3.js │ │ │ │ │ │ ├── parser-binary-logical-op-assign.js │ │ │ │ │ │ ├── parser-covered-parenthesized-exp-assign.js │ │ │ │ │ │ ├── parser-delete-op-assign.js │ │ │ │ │ │ ├── parser-equality-exp-assign-1.js │ │ │ │ │ │ ├── parser-equality-exp-assign-2.js │ │ │ │ │ │ ├── parser-mult-op-assign-1.js │ │ │ │ │ │ ├── parser-mult-op-assign-2.js │ │ │ │ │ │ ├── parser-mult-op-assign-3.js │ │ │ │ │ │ ├── parser-not-op-assign.js │ │ │ │ │ │ ├── parser-plus-negation-op-assign.js │ │ │ │ │ │ ├── parser-postfix-exp-assign.js │ │ │ │ │ │ ├── parser-prefix-exp-assign.js │ │ │ │ │ │ ├── parser-rational-exp-assign-1.js │ │ │ │ │ │ ├── parser-rational-exp-assign-2.js │ │ │ │ │ │ ├── parser-shift-exp-assign.js │ │ │ │ │ │ ├── parser-typeof-op-assign.js │ │ │ │ │ │ ├── parser-void-op-assign.js │ │ │ │ │ │ ├── promise-all-iterator.js │ │ │ │ │ │ ├── promise-new-target.js │ │ │ │ │ │ ├── promise-on-finally.js │ │ │ │ │ │ ├── promise-race-iterator.js │ │ │ │ │ │ ├── promise-species.js │ │ │ │ │ │ ├── promise-thenable.js │ │ │ │ │ │ ├── proxy-date-prototype-json.js │ │ │ │ │ │ ├── proxy-extension.js │ │ │ │ │ │ ├── proxy-for-in.js │ │ │ │ │ │ ├── proxy_call.js │ │ │ │ │ │ ├── proxy_construct.js │ │ │ │ │ │ ├── proxy_create.js │ │ │ │ │ │ ├── proxy_define_own_property.js │ │ │ │ │ │ ├── proxy_delete.js │ │ │ │ │ │ ├── proxy_flags.js │ │ │ │ │ │ ├── proxy_get.js │ │ │ │ │ │ ├── proxy_get_own_property_descriptor.js │ │ │ │ │ │ ├── proxy_get_prototoype_of.js │ │ │ │ │ │ ├── proxy_has.js │ │ │ │ │ │ ├── proxy_is_extensible.js │ │ │ │ │ │ ├── proxy_own_keys.js │ │ │ │ │ │ ├── proxy_prevent_extensions.js │ │ │ │ │ │ ├── proxy_revocable.js │ │ │ │ │ │ ├── proxy_set.js │ │ │ │ │ │ ├── proxy_set_apply_receiver.js │ │ │ │ │ │ ├── proxy_set_prototoype_of.js │ │ │ │ │ │ ├── realms1.js │ │ │ │ │ │ ├── realms2.js │ │ │ │ │ │ ├── realms3.js │ │ │ │ │ │ ├── realms4.js │ │ │ │ │ │ ├── reflect-apply.js │ │ │ │ │ │ ├── reflect-construct.js │ │ │ │ │ │ ├── reflect-define-Property.js │ │ │ │ │ │ ├── reflect-deleteproperty.js │ │ │ │ │ │ ├── reflect-get-own-property-description.js │ │ │ │ │ │ ├── reflect-get.js │ │ │ │ │ │ ├── reflect-getPrototypeOf.js │ │ │ │ │ │ ├── reflect-has.js │ │ │ │ │ │ ├── reflect-isextensible.js │ │ │ │ │ │ ├── reflect-own-keys.js │ │ │ │ │ │ ├── reflect-preventextensions.js │ │ │ │ │ │ ├── reflect-set.js │ │ │ │ │ │ ├── reflect-setPrototypeOf.js │ │ │ │ │ │ ├── regexp-accessors-descriptors.js │ │ │ │ │ │ ├── regexp-construct.js │ │ │ │ │ │ ├── regexp-dotAll.js │ │ │ │ │ │ ├── regexp-flags.js │ │ │ │ │ │ ├── regexp-lastindex.js │ │ │ │ │ │ ├── regexp-new-target.js │ │ │ │ │ │ ├── regexp-prototype-match-all.js │ │ │ │ │ │ ├── regexp-prototype-match.js │ │ │ │ │ │ ├── regexp-prototype-source.js │ │ │ │ │ │ ├── regexp-prototype-split.js │ │ │ │ │ │ ├── regexp-prototype-test.js │ │ │ │ │ │ ├── regexp-routines.js │ │ │ │ │ │ ├── regexp-unicode.js │ │ │ │ │ │ ├── regression-test-issue-1616.js │ │ │ │ │ │ ├── regression-test-issue-1622.js │ │ │ │ │ │ ├── regression-test-issue-1633.js │ │ │ │ │ │ ├── regression-test-issue-1670.js │ │ │ │ │ │ ├── regression-test-issue-1763.js │ │ │ │ │ │ ├── regression-test-issue-1765.js │ │ │ │ │ │ ├── regression-test-issue-1881.js │ │ │ │ │ │ ├── regression-test-issue-1936.js │ │ │ │ │ │ ├── regression-test-issue-1995.js │ │ │ │ │ │ ├── regression-test-issue-1996.js │ │ │ │ │ │ ├── regression-test-issue-1997.js │ │ │ │ │ │ ├── regression-test-issue-2058.js │ │ │ │ │ │ ├── regression-test-issue-2107.js │ │ │ │ │ │ ├── regression-test-issue-2110.js │ │ │ │ │ │ ├── regression-test-issue-2111.js │ │ │ │ │ │ ├── regression-test-issue-2143.js │ │ │ │ │ │ ├── regression-test-issue-2181.js │ │ │ │ │ │ ├── regression-test-issue-2414.js │ │ │ │ │ │ ├── regression-test-issue-2435.js │ │ │ │ │ │ ├── regression-test-issue-2465.js │ │ │ │ │ │ ├── regression-test-issue-2468.js │ │ │ │ │ │ ├── regression-test-issue-2486.js │ │ │ │ │ │ ├── regression-test-issue-2487.js │ │ │ │ │ │ ├── regression-test-issue-2488.js │ │ │ │ │ │ ├── regression-test-issue-2489-original.js │ │ │ │ │ │ ├── regression-test-issue-2490.js │ │ │ │ │ │ ├── regression-test-issue-2528.js │ │ │ │ │ │ ├── regression-test-issue-2544.js │ │ │ │ │ │ ├── regression-test-issue-2587.js │ │ │ │ │ │ ├── regression-test-issue-2602.js │ │ │ │ │ │ ├── regression-test-issue-2603.js │ │ │ │ │ │ ├── regression-test-issue-2657.js │ │ │ │ │ │ ├── regression-test-issue-2658.js │ │ │ │ │ │ ├── regression-test-issue-2664.js │ │ │ │ │ │ ├── regression-test-issue-2666.js │ │ │ │ │ │ ├── regression-test-issue-2667.js │ │ │ │ │ │ ├── regression-test-issue-2671.js │ │ │ │ │ │ ├── regression-test-issue-2693.js │ │ │ │ │ │ ├── regression-test-issue-2698.js │ │ │ │ │ │ ├── regression-test-issue-2724.js │ │ │ │ │ │ ├── regression-test-issue-2743.js │ │ │ │ │ │ ├── regression-test-issue-2757.js │ │ │ │ │ │ ├── regression-test-issue-2768.js │ │ │ │ │ │ ├── regression-test-issue-2769.js │ │ │ │ │ │ ├── regression-test-issue-2770.js │ │ │ │ │ │ ├── regression-test-issue-2777.js │ │ │ │ │ │ ├── regression-test-issue-2779.js │ │ │ │ │ │ ├── regression-test-issue-2782.js │ │ │ │ │ │ ├── regression-test-issue-2783.js │ │ │ │ │ │ ├── regression-test-issue-2822.js │ │ │ │ │ │ ├── regression-test-issue-2823.js │ │ │ │ │ │ ├── regression-test-issue-2825.js │ │ │ │ │ │ ├── regression-test-issue-2842.mjs │ │ │ │ │ │ ├── regression-test-issue-2848.js │ │ │ │ │ │ ├── regression-test-issue-2850.js │ │ │ │ │ │ ├── regression-test-issue-2851.js │ │ │ │ │ │ ├── regression-test-issue-2852.js │ │ │ │ │ │ ├── regression-test-issue-2853.js │ │ │ │ │ │ ├── regression-test-issue-2854.js │ │ │ │ │ │ ├── regression-test-issue-2891.js │ │ │ │ │ │ ├── regression-test-issue-2895.js │ │ │ │ │ │ ├── regression-test-issue-2910.js │ │ │ │ │ │ ├── regression-test-issue-2911.js │ │ │ │ │ │ ├── regression-test-issue-2947.js │ │ │ │ │ │ ├── regression-test-issue-2948.js │ │ │ │ │ │ ├── regression-test-issue-2950.js │ │ │ │ │ │ ├── regression-test-issue-2951.js │ │ │ │ │ │ ├── regression-test-issue-2975.js │ │ │ │ │ │ ├── regression-test-issue-2990.js │ │ │ │ │ │ ├── regression-test-issue-3040.js │ │ │ │ │ │ ├── regression-test-issue-3043-3046.js │ │ │ │ │ │ ├── regression-test-issue-3045.js │ │ │ │ │ │ ├── regression-test-issue-3049.js │ │ │ │ │ │ ├── regression-test-issue-3050.js │ │ │ │ │ │ ├── regression-test-issue-3062.js │ │ │ │ │ │ ├── regression-test-issue-3063.js │ │ │ │ │ │ ├── regression-test-issue-3067.js │ │ │ │ │ │ ├── regression-test-issue-3070.js │ │ │ │ │ │ ├── regression-test-issue-3072.js │ │ │ │ │ │ ├── regression-test-issue-3078.js │ │ │ │ │ │ ├── regression-test-issue-3079.js │ │ │ │ │ │ ├── regression-test-issue-3084.js │ │ │ │ │ │ ├── regression-test-issue-3095.js │ │ │ │ │ │ ├── regression-test-issue-3097.js │ │ │ │ │ │ ├── regression-test-issue-3105.js │ │ │ │ │ │ ├── regression-test-issue-3106.js │ │ │ │ │ │ ├── regression-test-issue-3107.js │ │ │ │ │ │ ├── regression-test-issue-3109.js │ │ │ │ │ │ ├── regression-test-issue-3129.js │ │ │ │ │ │ ├── regression-test-issue-3162.js │ │ │ │ │ │ ├── regression-test-issue-3204.js │ │ │ │ │ │ ├── regression-test-issue-3222.js │ │ │ │ │ │ ├── regression-test-issue-3237.js │ │ │ │ │ │ ├── regression-test-issue-3243.js │ │ │ │ │ │ ├── regression-test-issue-3250.js │ │ │ │ │ │ ├── regression-test-issue-3252.js │ │ │ │ │ │ ├── regression-test-issue-3262.js │ │ │ │ │ │ ├── regression-test-issue-3267.js │ │ │ │ │ │ ├── regression-test-issue-3298.js │ │ │ │ │ │ ├── regression-test-issue-3302.js │ │ │ │ │ │ ├── regression-test-issue-3306.js │ │ │ │ │ │ ├── regression-test-issue-3348.js │ │ │ │ │ │ ├── regression-test-issue-3355.js │ │ │ │ │ │ ├── regression-test-issue-3356.js │ │ │ │ │ │ ├── regression-test-issue-3360.js │ │ │ │ │ │ ├── regression-test-issue-3361.js │ │ │ │ │ │ ├── regression-test-issue-3363.js │ │ │ │ │ │ ├── regression-test-issue-3364.js │ │ │ │ │ │ ├── regression-test-issue-3376.js │ │ │ │ │ │ ├── regression-test-issue-3381.js │ │ │ │ │ │ ├── regression-test-issue-3383.js │ │ │ │ │ │ ├── regression-test-issue-3390.js │ │ │ │ │ │ ├── regression-test-issue-3395.js │ │ │ │ │ │ ├── regression-test-issue-3396.js │ │ │ │ │ │ ├── regression-test-issue-3408.js │ │ │ │ │ │ ├── regression-test-issue-3409.js │ │ │ │ │ │ ├── regression-test-issue-3411.js │ │ │ │ │ │ ├── regression-test-issue-3419.js │ │ │ │ │ │ ├── regression-test-issue-3420.js │ │ │ │ │ │ ├── regression-test-issue-3421.js │ │ │ │ │ │ ├── regression-test-issue-3422.js │ │ │ │ │ │ ├── regression-test-issue-3431.js │ │ │ │ │ │ ├── regression-test-issue-3434.js │ │ │ │ │ │ ├── regression-test-issue-3437.js │ │ │ │ │ │ ├── regression-test-issue-3454.js │ │ │ │ │ │ ├── regression-test-issue-3455.js │ │ │ │ │ │ ├── regression-test-issue-3458.js │ │ │ │ │ │ ├── regression-test-issue-3459.js │ │ │ │ │ │ ├── regression-test-issue-3478.js │ │ │ │ │ │ ├── regression-test-issue-3479.js │ │ │ │ │ │ ├── regression-test-issue-3483.js │ │ │ │ │ │ ├── regression-test-issue-3485.js │ │ │ │ │ │ ├── regression-test-issue-3519.js │ │ │ │ │ │ ├── regression-test-issue-3527.js │ │ │ │ │ │ ├── regression-test-issue-3534.js │ │ │ │ │ │ ├── regression-test-issue-3536.js │ │ │ │ │ │ ├── regression-test-issue-3580.js │ │ │ │ │ │ ├── regression-test-issue-3588.js │ │ │ │ │ │ ├── regression-test-issue-3589.js │ │ │ │ │ │ ├── regression-test-issue-3595.js │ │ │ │ │ │ ├── regression-test-issue-3606.js │ │ │ │ │ │ ├── regression-test-issue-3611.js │ │ │ │ │ │ ├── regression-test-issue-3625.js │ │ │ │ │ │ ├── regression-test-issue-3628.js │ │ │ │ │ │ ├── regression-test-issue-3630.js │ │ │ │ │ │ ├── regression-test-issue-3636.js │ │ │ │ │ │ ├── regression-test-issue-3637.js │ │ │ │ │ │ ├── regression-test-issue-3640.js │ │ │ │ │ │ ├── regression-test-issue-3641.js │ │ │ │ │ │ ├── regression-test-issue-3647.js │ │ │ │ │ │ ├── regression-test-issue-3655.js │ │ │ │ │ │ ├── regression-test-issue-3656.js │ │ │ │ │ │ ├── regression-test-issue-3658.js │ │ │ │ │ │ ├── regression-test-issue-3665.js │ │ │ │ │ │ ├── regression-test-issue-3671.js │ │ │ │ │ │ ├── regression-test-issue-3713.js │ │ │ │ │ │ ├── regression-test-issue-3715.js │ │ │ │ │ │ ├── regression-test-issue-3727.js │ │ │ │ │ │ ├── regression-test-issue-3751.js │ │ │ │ │ │ ├── regression-test-issue-3760.js │ │ │ │ │ │ ├── regression-test-issue-3784.js │ │ │ │ │ │ ├── regression-test-issue-3785.js │ │ │ │ │ │ ├── regression-test-issue-3787.js │ │ │ │ │ │ ├── regression-test-issue-3812.js │ │ │ │ │ │ ├── regression-test-issue-3814.js │ │ │ │ │ │ ├── regression-test-issue-3815.js │ │ │ │ │ │ ├── regression-test-issue-3817.js │ │ │ │ │ │ ├── regression-test-issue-3819.js │ │ │ │ │ │ ├── regression-test-issue-3820.js │ │ │ │ │ │ ├── regression-test-issue-3822.js │ │ │ │ │ │ ├── regression-test-issue-3823.js │ │ │ │ │ │ ├── regression-test-issue-3824.js │ │ │ │ │ │ ├── regression-test-issue-3825.js │ │ │ │ │ │ ├── regression-test-issue-3836.js │ │ │ │ │ │ ├── regression-test-issue-3837.js │ │ │ │ │ │ ├── regression-test-issue-3841.js │ │ │ │ │ │ ├── regression-test-issue-3842.js │ │ │ │ │ │ ├── regression-test-issue-3845.js │ │ │ │ │ │ ├── regression-test-issue-3849.js │ │ │ │ │ │ ├── regression-test-issue-3856.js │ │ │ │ │ │ ├── regression-test-issue-3857.js │ │ │ │ │ │ ├── regression-test-issue-3860.js │ │ │ │ │ │ ├── regression-test-issue-3861.js │ │ │ │ │ │ ├── regression-test-issue-3862.js │ │ │ │ │ │ ├── regression-test-issue-3866.js │ │ │ │ │ │ ├── regression-test-issue-3868.js │ │ │ │ │ │ ├── regression-test-issue-3869.js │ │ │ │ │ │ ├── regression-test-issue-3870.js │ │ │ │ │ │ ├── regression-test-issue-3871.js │ │ │ │ │ │ ├── regression-test-issue-3880.js │ │ │ │ │ │ ├── regression-test-issue-3888.js │ │ │ │ │ │ ├── regression-test-issue-3893.js │ │ │ │ │ │ ├── regression-test-issue-3908.js │ │ │ │ │ │ ├── regression-test-issue-3935.js │ │ │ │ │ │ ├── regression-test-issue-3945.js │ │ │ │ │ │ ├── regression-test-issue-3950.js │ │ │ │ │ │ ├── regression-test-issue-3975.js │ │ │ │ │ │ ├── regression-test-issue-4013.js │ │ │ │ │ │ ├── regression-test-issue-4016-4019.js │ │ │ │ │ │ ├── regression-test-issue-4017.js │ │ │ │ │ │ ├── regression-test-issue-4018.js │ │ │ │ │ │ ├── regression-test-issue-4043.js │ │ │ │ │ │ ├── regression-test-issue-4044.js │ │ │ │ │ │ ├── regression-test-issue-4045.js │ │ │ │ │ │ ├── regression-test-issue-4048.js │ │ │ │ │ │ ├── regression-test-issue-4050.js │ │ │ │ │ │ ├── regression-test-issue-4051.js │ │ │ │ │ │ ├── regression-test-issue-4052.js │ │ │ │ │ │ ├── regression-test-issue-4054.js │ │ │ │ │ │ ├── regression-test-issue-4059.js │ │ │ │ │ │ ├── regression-test-issue-4093.js │ │ │ │ │ │ ├── regression-test-issue-4094.js │ │ │ │ │ │ ├── regression-test-issue-4097.js │ │ │ │ │ │ ├── regression-test-issue-4129.js │ │ │ │ │ │ ├── regression-test-issue-4131.js │ │ │ │ │ │ ├── regression-test-issue-4132.js │ │ │ │ │ │ ├── regression-test-issue-4138.js │ │ │ │ │ │ ├── regression-test-issue-4139.js │ │ │ │ │ │ ├── regression-test-issue-4146.js │ │ │ │ │ │ ├── regression-test-issue-4147.js │ │ │ │ │ │ ├── regression-test-issue-4148.js │ │ │ │ │ │ ├── regression-test-issue-4149.js │ │ │ │ │ │ ├── regression-test-issue-4213.js │ │ │ │ │ │ ├── regression-test-issue-4214.js │ │ │ │ │ │ ├── regression-test-issue-4234.js │ │ │ │ │ │ ├── regression-test-issue-4265.js │ │ │ │ │ │ ├── regression-test-issue-4341.js │ │ │ │ │ │ ├── regression-test-issue-4375.js │ │ │ │ │ │ ├── regression-test-issue-4385.js │ │ │ │ │ │ ├── regression-test-issue-4396.js │ │ │ │ │ │ ├── regression-test-issue-4397.js │ │ │ │ │ │ ├── regression-test-issue-4398.js │ │ │ │ │ │ ├── regression-test-issue-4402.js │ │ │ │ │ │ ├── regression-test-issue-4405.js │ │ │ │ │ │ ├── regression-test-issue-4408.js │ │ │ │ │ │ ├── regression-test-issue-4413.js │ │ │ │ │ │ ├── regression-test-issue-4432.js │ │ │ │ │ │ ├── regression-test-issue-4440.js │ │ │ │ │ │ ├── regression-test-issue-4441.js │ │ │ │ │ │ ├── regression-test-issue-4442.js │ │ │ │ │ │ ├── regression-test-issue-4445.js │ │ │ │ │ │ ├── regression-test-issue-4446.js │ │ │ │ │ │ ├── regression-test-issue-4463.js │ │ │ │ │ │ ├── regression-test-issue-4464.js │ │ │ │ │ │ ├── regression-test-issue-4466.js │ │ │ │ │ │ ├── regression-test-issue-4468.js │ │ │ │ │ │ ├── regression-test-issue-4469.js │ │ │ │ │ │ ├── regression-test-issue-612.js │ │ │ │ │ │ ├── regression-test-issue-782.js │ │ │ │ │ │ ├── restricted-properties.js │ │ │ │ │ │ ├── set-iterators.js │ │ │ │ │ │ ├── set.js │ │ │ │ │ │ ├── string-fromcodepoint.js │ │ │ │ │ │ ├── string-iterator.js │ │ │ │ │ │ ├── string-prototype-codepointat.js │ │ │ │ │ │ ├── string-prototype-endswith.js │ │ │ │ │ │ ├── string-prototype-includes.js │ │ │ │ │ │ ├── string-prototype-match-all.js │ │ │ │ │ │ ├── string-prototype-match.js │ │ │ │ │ │ ├── string-prototype-padding.js │ │ │ │ │ │ ├── string-prototype-repeat.js │ │ │ │ │ │ ├── string-prototype-replace-all.js │ │ │ │ │ │ ├── string-prototype-split.js │ │ │ │ │ │ ├── string-prototype-startswith.js │ │ │ │ │ │ ├── string-prototype-trim.js │ │ │ │ │ │ ├── string-raw-crash-escaping-backslash.js │ │ │ │ │ │ ├── string-raw.js │ │ │ │ │ │ ├── string-upper-lower-case-conversion.js │ │ │ │ │ │ ├── super-assignment.js │ │ │ │ │ │ ├── symbol-computed-object-literal.js │ │ │ │ │ │ ├── symbol-exception.js │ │ │ │ │ │ ├── symbol-in.js │ │ │ │ │ │ ├── symbol-isconcatspreadable.js │ │ │ │ │ │ ├── symbol-key-keyfor.js │ │ │ │ │ │ ├── symbol-prototype-description.js │ │ │ │ │ │ ├── symbol-prototype-symbol-toprimitive.js │ │ │ │ │ │ ├── symbol-prototype-tostring.js │ │ │ │ │ │ ├── symbol-prototype-valueof.js │ │ │ │ │ │ ├── symbol-prototype.toprimitive.js │ │ │ │ │ │ ├── symbol-replace.js │ │ │ │ │ │ ├── symbol-search.js │ │ │ │ │ │ ├── symbol-split.js │ │ │ │ │ │ ├── symbol-unscopables.js │ │ │ │ │ │ ├── symbol.js │ │ │ │ │ │ ├── tagged-template-literal.js │ │ │ │ │ │ ├── template_string.js │ │ │ │ │ │ ├── test_suite_15.js │ │ │ │ │ │ ├── test_suite_19.js │ │ │ │ │ │ ├── test_suite_22.js │ │ │ │ │ │ ├── test_suite_24.js │ │ │ │ │ │ ├── test_suite_25.js │ │ │ │ │ │ ├── to-length.js │ │ │ │ │ │ ├── to-number-string.js │ │ │ │ │ │ ├── to-property-key.js │ │ │ │ │ │ ├── try-catch.js │ │ │ │ │ │ ├── try-pattern.js │ │ │ │ │ │ ├── typedArray-fill.js │ │ │ │ │ │ ├── typedArray-find-index.js │ │ │ │ │ │ ├── typedArray-find.js │ │ │ │ │ │ ├── typedArray-join.js │ │ │ │ │ │ ├── typedArray-set-with-typedArray.js │ │ │ │ │ │ ├── typedArray-sort.js │ │ │ │ │ │ ├── typedArray-stringify.js │ │ │ │ │ │ ├── typedArray-subarray.js │ │ │ │ │ │ ├── typedArray-tostring.js │ │ │ │ │ │ ├── typedarray-from.js │ │ │ │ │ │ ├── typedarray-of.js │ │ │ │ │ │ ├── typedarray-offset-modulo.js │ │ │ │ │ │ ├── typedarray-prototype-copy-within.js │ │ │ │ │ │ ├── typedarray-prototype-entries.js │ │ │ │ │ │ ├── typedarray-prototype-includes.js │ │ │ │ │ │ ├── typedarray-prototype-indexof.js │ │ │ │ │ │ ├── typedarray-prototype-keys.js │ │ │ │ │ │ ├── typedarray-prototype-lastindexof.js │ │ │ │ │ │ ├── typedarray-prototype-slice-ext-arraybuffer.js │ │ │ │ │ │ ├── typedarray-prototype-slice.js │ │ │ │ │ │ ├── typedarray-prototype-tolocalestring.js │ │ │ │ │ │ ├── typedarray-prototype-values.js │ │ │ │ │ │ ├── typedarray-symbol-properties.js │ │ │ │ │ │ ├── unicode-escape-identifiers.js │ │ │ │ │ │ ├── weakmap.js │ │ │ │ │ │ └── weakset.js │ │ │ │ │ ├── es5.1/ │ │ │ │ │ │ ├── arguments.js │ │ │ │ │ │ ├── arithmetic-parse.js │ │ │ │ │ │ ├── arithmetics.js │ │ │ │ │ │ ├── array-prototype-push.js │ │ │ │ │ │ ├── array-prototype-unshift.js │ │ │ │ │ │ ├── builtin-prototypes.js │ │ │ │ │ │ ├── date-utc.js │ │ │ │ │ │ ├── func-decl.js │ │ │ │ │ │ ├── func-length.js │ │ │ │ │ │ ├── json-superset.js │ │ │ │ │ │ ├── object-getprototypeof.js │ │ │ │ │ │ ├── object-literal-fails.js │ │ │ │ │ │ ├── object-methods.js │ │ │ │ │ │ ├── regexp-construct.js │ │ │ │ │ │ ├── regexp-lastindex.js │ │ │ │ │ │ ├── regexp-routines.js │ │ │ │ │ │ ├── regression-test-issue-1065.js │ │ │ │ │ │ ├── regression-test-issue-1080.js │ │ │ │ │ │ ├── regression-test-issue-116.js │ │ │ │ │ │ ├── regression-test-issue-1546.js │ │ │ │ │ │ ├── regression-test-issue-1641.js │ │ │ │ │ │ ├── regression-test-issue-2058.js │ │ │ │ │ │ ├── regression-test-issue-312.js │ │ │ │ │ │ ├── regression-test-issue-3151-function.js │ │ │ │ │ │ ├── regression-test-issue-3637.js │ │ │ │ │ │ ├── regression-test-issue-3815.js │ │ │ │ │ │ ├── regression-test-issue-787.js │ │ │ │ │ │ ├── string-prototype-split.js │ │ │ │ │ │ ├── string-regexp-methods.js │ │ │ │ │ │ ├── string-upper-lower-case-conversion.js │ │ │ │ │ │ ├── test_suite_15.js │ │ │ │ │ │ └── try-catch.js │ │ │ │ │ ├── escape-sequences.js │ │ │ │ │ ├── eval-with.js │ │ │ │ │ ├── eval.js │ │ │ │ │ ├── fail/ │ │ │ │ │ │ ├── arguments-assignment-strict.js │ │ │ │ │ │ ├── arguments-catch-strict.js │ │ │ │ │ │ ├── arguments-in-prop-set-param-list-strict.js │ │ │ │ │ │ ├── arguments-in-var-decl-strict.js │ │ │ │ │ │ ├── arguments-param-strict.js │ │ │ │ │ │ ├── arguments-postfix-strict.js │ │ │ │ │ │ ├── arguments-prefix-strict.js │ │ │ │ │ │ ├── delete-strict.js │ │ │ │ │ │ ├── escape-sequences-invalid-hex.js │ │ │ │ │ │ ├── escape-sequences-invalid-unicode.js │ │ │ │ │ │ ├── escape-sequences-invalid-variable.js │ │ │ │ │ │ ├── eval-assignment-strict.js │ │ │ │ │ │ ├── eval-catch-strict.js │ │ │ │ │ │ ├── eval-in-prop-set-param-list-strict.js │ │ │ │ │ │ ├── eval-in-var-decl-strict.js │ │ │ │ │ │ ├── eval-param-strict.js │ │ │ │ │ │ ├── eval-postfix-strict.js │ │ │ │ │ │ ├── eval-prefix-strict.js │ │ │ │ │ │ ├── func-expr-strict.js │ │ │ │ │ │ ├── labelled-statements-break-across-function.js │ │ │ │ │ │ ├── labelled-statements-duplicate-label.js │ │ │ │ │ │ ├── labelled-statements-no-label.js │ │ │ │ │ │ ├── let-strict.js │ │ │ │ │ │ ├── module-001.mjs │ │ │ │ │ │ ├── module-002.mjs │ │ │ │ │ │ ├── module-003.mjs │ │ │ │ │ │ ├── module-004.mjs │ │ │ │ │ │ ├── module-005.mjs │ │ │ │ │ │ ├── module-006.mjs │ │ │ │ │ │ ├── module-007.mjs │ │ │ │ │ │ ├── module-008.mjs │ │ │ │ │ │ ├── module-009.mjs │ │ │ │ │ │ ├── module-010.mjs │ │ │ │ │ │ ├── module-011.mjs │ │ │ │ │ │ ├── module-012.mjs │ │ │ │ │ │ ├── module-013.mjs │ │ │ │ │ │ ├── module-014.mjs │ │ │ │ │ │ ├── module-015.mjs │ │ │ │ │ │ ├── module-016.mjs │ │ │ │ │ │ ├── module-017.mjs │ │ │ │ │ │ ├── module-018.mjs │ │ │ │ │ │ ├── module-019.mjs │ │ │ │ │ │ ├── module-020.mjs │ │ │ │ │ │ ├── module-021.mjs │ │ │ │ │ │ ├── module-022.mjs │ │ │ │ │ │ ├── module-023.mjs │ │ │ │ │ │ ├── module-024.mjs │ │ │ │ │ │ ├── module-025.mjs │ │ │ │ │ │ ├── module-026.mjs │ │ │ │ │ │ ├── module-027.mjs │ │ │ │ │ │ ├── module-028.mjs │ │ │ │ │ │ ├── module-029.mjs │ │ │ │ │ │ ├── module-030.mjs │ │ │ │ │ │ ├── module-031.mjs │ │ │ │ │ │ ├── module-032.mjs │ │ │ │ │ │ ├── module-033.mjs │ │ │ │ │ │ ├── module-034.mjs │ │ │ │ │ │ ├── module-035.mjs │ │ │ │ │ │ ├── module-036.mjs │ │ │ │ │ │ ├── module-037.mjs │ │ │ │ │ │ ├── module-await-001.mjs │ │ │ │ │ │ ├── module-export-001.mjs │ │ │ │ │ │ ├── module-export-default-arrow.mjs │ │ │ │ │ │ ├── module-sideeffect.mjs │ │ │ │ │ │ ├── octal-strict.js │ │ │ │ │ │ ├── param-duplication-strict.js │ │ │ │ │ │ ├── regression-test-issue-1387.js │ │ │ │ │ │ ├── regression-test-issue-1549.js │ │ │ │ │ │ ├── regression-test-issue-1550.js │ │ │ │ │ │ ├── regression-test-issue-1597.js │ │ │ │ │ │ ├── regression-test-issue-1598.js │ │ │ │ │ │ ├── regression-test-issue-1615.js │ │ │ │ │ │ ├── regression-test-issue-1624.js │ │ │ │ │ │ ├── regression-test-issue-1671.js │ │ │ │ │ │ ├── regression-test-issue-1831.js │ │ │ │ │ │ ├── regression-test-issue-1871-1.js │ │ │ │ │ │ ├── regression-test-issue-1871-2.js │ │ │ │ │ │ ├── regression-test-issue-1873.js │ │ │ │ │ │ ├── regression-test-issue-1918.js │ │ │ │ │ │ ├── regression-test-issue-2039.js │ │ │ │ │ │ ├── regression-test-issue-2069.js │ │ │ │ │ │ ├── regression-test-issue-2094.js │ │ │ │ │ │ ├── regression-test-issue-2095.js │ │ │ │ │ │ ├── regression-test-issue-2106.js │ │ │ │ │ │ ├── regression-test-issue-2180.js │ │ │ │ │ │ ├── regression-test-issue-2192.js │ │ │ │ │ │ ├── regression-test-issue-2344.js │ │ │ │ │ │ ├── regression-test-issue-2489.js │ │ │ │ │ │ ├── regression-test-issue-2654.js │ │ │ │ │ │ ├── regression-test-issue-2659.js │ │ │ │ │ │ ├── regression-test-issue-2719.js │ │ │ │ │ │ ├── regression-test-issue-2774.js │ │ │ │ │ │ ├── regression-test-issue-2775.js │ │ │ │ │ │ ├── regression-test-issue-2819.js │ │ │ │ │ │ ├── regression-test-issue-2846.js │ │ │ │ │ │ ├── regression-test-issue-2885.js │ │ │ │ │ │ ├── regression-test-issue-2894.js │ │ │ │ │ │ ├── regression-test-issue-2896.js │ │ │ │ │ │ ├── regression-test-issue-2897.js │ │ │ │ │ │ ├── regression-test-issue-2901.js │ │ │ │ │ │ ├── regression-test-issue-2902.js │ │ │ │ │ │ ├── regression-test-issue-2908-1.js │ │ │ │ │ │ ├── regression-test-issue-2908-2.js │ │ │ │ │ │ ├── regression-test-issue-2908-3.js │ │ │ │ │ │ ├── regression-test-issue-2908-4.js │ │ │ │ │ │ ├── regression-test-issue-2993.js │ │ │ │ │ │ ├── regression-test-issue-3094.js │ │ │ │ │ │ ├── regression-test-issue-3096.js │ │ │ │ │ │ ├── regression-test-issue-3101.js │ │ │ │ │ │ ├── regression-test-issue-3102.js │ │ │ │ │ │ ├── regression-test-issue-3112.js │ │ │ │ │ │ ├── regression-test-issue-3117.js │ │ │ │ │ │ ├── regression-test-issue-3119.js │ │ │ │ │ │ ├── regression-test-issue-3121.js │ │ │ │ │ │ ├── regression-test-issue-3123.js │ │ │ │ │ │ ├── regression-test-issue-3131.js │ │ │ │ │ │ ├── regression-test-issue-3140.js │ │ │ │ │ │ ├── regression-test-issue-3145.js │ │ │ │ │ │ ├── regression-test-issue-3152.js │ │ │ │ │ │ ├── regression-test-issue-3173.js │ │ │ │ │ │ ├── regression-test-issue-3174.js │ │ │ │ │ │ ├── regression-test-issue-3214.js │ │ │ │ │ │ ├── regression-test-issue-3253-1.js │ │ │ │ │ │ ├── regression-test-issue-3253-2.js │ │ │ │ │ │ ├── regression-test-issue-3275.js │ │ │ │ │ │ ├── regression-test-issue-3276.js │ │ │ │ │ │ ├── regression-test-issue-3297.js │ │ │ │ │ │ ├── regression-test-issue-3299.js │ │ │ │ │ │ ├── regression-test-issue-3300.js │ │ │ │ │ │ ├── regression-test-issue-3394.js │ │ │ │ │ │ ├── regression-test-issue-3398.js │ │ │ │ │ │ ├── regression-test-issue-3410.js │ │ │ │ │ │ ├── regression-test-issue-3554.js │ │ │ │ │ │ ├── regression-test-issue-358.js │ │ │ │ │ │ ├── regression-test-issue-3714.js │ │ │ │ │ │ ├── regression-test-issue-3735.js │ │ │ │ │ │ ├── regression-test-issue-384.js │ │ │ │ │ │ ├── regression-test-issue-3882.js │ │ │ │ │ │ ├── regression-test-issue-4403.js │ │ │ │ │ │ ├── throw-error-object.js │ │ │ │ │ │ ├── throw-number.js │ │ │ │ │ │ ├── throw-string.js │ │ │ │ │ │ └── with-strict.js │ │ │ │ │ ├── for-in-parse.js │ │ │ │ │ ├── for-in.js │ │ │ │ │ ├── for-parse.js │ │ │ │ │ ├── for.js │ │ │ │ │ ├── func-decl.js │ │ │ │ │ ├── function-args.js │ │ │ │ │ ├── function-construct.js │ │ │ │ │ ├── function-expr-named.js │ │ │ │ │ ├── function-external.js │ │ │ │ │ ├── function-prototype-apply.js │ │ │ │ │ ├── function-prototype-bind.js │ │ │ │ │ ├── function-prototype-tostring.js │ │ │ │ │ ├── function-return.js │ │ │ │ │ ├── function-scopes.js │ │ │ │ │ ├── function.js │ │ │ │ │ ├── function.prototype.js │ │ │ │ │ ├── gc.js │ │ │ │ │ ├── get-value.js │ │ │ │ │ ├── getter-setter-this-value.js │ │ │ │ │ ├── global-escaping.js │ │ │ │ │ ├── global-parsefloat.js │ │ │ │ │ ├── global-parseint.js │ │ │ │ │ ├── global-uri-coding.js │ │ │ │ │ ├── global.js │ │ │ │ │ ├── hash.js │ │ │ │ │ ├── if-else.js │ │ │ │ │ ├── if_parser.js │ │ │ │ │ ├── insert-semicolon.js │ │ │ │ │ ├── json-parse.js │ │ │ │ │ ├── json-stringify.js │ │ │ │ │ ├── keyword.js │ │ │ │ │ ├── labelled-statements.js │ │ │ │ │ ├── large_literal.js │ │ │ │ │ ├── logical.js │ │ │ │ │ ├── math-abs.js │ │ │ │ │ ├── math-exp.js │ │ │ │ │ ├── math-functions-tonumber-rule.js │ │ │ │ │ ├── math-log.js │ │ │ │ │ ├── math-max.js │ │ │ │ │ ├── math-min.js │ │ │ │ │ ├── math-pow.js │ │ │ │ │ ├── math-round.js │ │ │ │ │ ├── math-trig.js │ │ │ │ │ ├── nested-function.js │ │ │ │ │ ├── new-line-in-literal.js │ │ │ │ │ ├── number-prototype-to-exponential.js │ │ │ │ │ ├── number-prototype-to-fixed.js │ │ │ │ │ ├── number-prototype-to-precision.js │ │ │ │ │ ├── number-prototype-to-string.js │ │ │ │ │ ├── object-create.js │ │ │ │ │ ├── object-define-properties.js │ │ │ │ │ ├── object-defineproperty.js │ │ │ │ │ ├── object-get-own-property-descriptor.js │ │ │ │ │ ├── object-get-own-property-names.js │ │ │ │ │ ├── object-is-extensible.js │ │ │ │ │ ├── object-keys.js │ │ │ │ │ ├── object-literal-2.js │ │ │ │ │ ├── object-literal-prescanner.js │ │ │ │ │ ├── object-literal.js │ │ │ │ │ ├── object-prototype-hasownproperty.js │ │ │ │ │ ├── object-prototype-isprototypeof.js │ │ │ │ │ ├── object-prototype-propertyisenumerable.js │ │ │ │ │ ├── object-prototype-tolocalestring.js │ │ │ │ │ ├── object_freeze.js │ │ │ │ │ ├── object_seal.js │ │ │ │ │ ├── octal.js │ │ │ │ │ ├── parser-oom.js │ │ │ │ │ ├── parser-oom2.js │ │ │ │ │ ├── prescanner.js │ │ │ │ │ ├── regexp-alternatives.js │ │ │ │ │ ├── regexp-assertions.js │ │ │ │ │ ├── regexp-backreference.js │ │ │ │ │ ├── regexp-backtrack.js │ │ │ │ │ ├── regexp-capture-groups.js │ │ │ │ │ ├── regexp-character-class.js │ │ │ │ │ ├── regexp-construct.js │ │ │ │ │ ├── regexp-literal.js │ │ │ │ │ ├── regexp-non-capture-groups.js │ │ │ │ │ ├── regexp-routines.js │ │ │ │ │ ├── regexp-simple-atom-and-iterations.js │ │ │ │ │ ├── regexp-web-compatibility.js │ │ │ │ │ ├── regression-test-issue-1054.js │ │ │ │ │ ├── regression-test-issue-1071.js │ │ │ │ │ ├── regression-test-issue-1072.js │ │ │ │ │ ├── regression-test-issue-1073.js │ │ │ │ │ ├── regression-test-issue-1074.js │ │ │ │ │ ├── regression-test-issue-1075.js │ │ │ │ │ ├── regression-test-issue-1076.js │ │ │ │ │ ├── regression-test-issue-1078.js │ │ │ │ │ ├── regression-test-issue-1079.js │ │ │ │ │ ├── regression-test-issue-1081.js │ │ │ │ │ ├── regression-test-issue-1082.js │ │ │ │ │ ├── regression-test-issue-1083.js │ │ │ │ │ ├── regression-test-issue-112.js │ │ │ │ │ ├── regression-test-issue-113.js │ │ │ │ │ ├── regression-test-issue-114.js │ │ │ │ │ ├── regression-test-issue-115.js │ │ │ │ │ ├── regression-test-issue-117.js │ │ │ │ │ ├── regression-test-issue-121.js │ │ │ │ │ ├── regression-test-issue-122.js │ │ │ │ │ ├── regression-test-issue-123.js │ │ │ │ │ ├── regression-test-issue-128.js │ │ │ │ │ ├── regression-test-issue-1282.js │ │ │ │ │ ├── regression-test-issue-1284.js │ │ │ │ │ ├── regression-test-issue-1286.js │ │ │ │ │ ├── regression-test-issue-129.js │ │ │ │ │ ├── regression-test-issue-1292.js │ │ │ │ │ ├── regression-test-issue-130.js │ │ │ │ │ ├── regression-test-issue-1300.js │ │ │ │ │ ├── regression-test-issue-1309.js │ │ │ │ │ ├── regression-test-issue-132.js │ │ │ │ │ ├── regression-test-issue-1386.js │ │ │ │ │ ├── regression-test-issue-1389.js │ │ │ │ │ ├── regression-test-issue-1533.js │ │ │ │ │ ├── regression-test-issue-1547.js │ │ │ │ │ ├── regression-test-issue-1552.js │ │ │ │ │ ├── regression-test-issue-1555.js │ │ │ │ │ ├── regression-test-issue-1556.js │ │ │ │ │ ├── regression-test-issue-156.js │ │ │ │ │ ├── regression-test-issue-1621.js │ │ │ │ │ ├── regression-test-issue-1636.js │ │ │ │ │ ├── regression-test-issue-164.js │ │ │ │ │ ├── regression-test-issue-1657.js │ │ │ │ │ ├── regression-test-issue-1821.js │ │ │ │ │ ├── regression-test-issue-1829.js │ │ │ │ │ ├── regression-test-issue-1830.js │ │ │ │ │ ├── regression-test-issue-1855.js │ │ │ │ │ ├── regression-test-issue-1917.js │ │ │ │ │ ├── regression-test-issue-1934.js │ │ │ │ │ ├── regression-test-issue-1947.js │ │ │ │ │ ├── regression-test-issue-195.js │ │ │ │ │ ├── regression-test-issue-1970.js │ │ │ │ │ ├── regression-test-issue-1972.js │ │ │ │ │ ├── regression-test-issue-1973.js │ │ │ │ │ ├── regression-test-issue-1974.js │ │ │ │ │ ├── regression-test-issue-1990.js │ │ │ │ │ ├── regression-test-issue-1993.js │ │ │ │ │ ├── regression-test-issue-2008.js │ │ │ │ │ ├── regression-test-issue-2073.js │ │ │ │ │ ├── regression-test-issue-2105.js │ │ │ │ │ ├── regression-test-issue-2108.js │ │ │ │ │ ├── regression-test-issue-212.js │ │ │ │ │ ├── regression-test-issue-2178.js │ │ │ │ │ ├── regression-test-issue-2182.js │ │ │ │ │ ├── regression-test-issue-2190.js │ │ │ │ │ ├── regression-test-issue-2198.js │ │ │ │ │ ├── regression-test-issue-2200.js │ │ │ │ │ ├── regression-test-issue-2204.js │ │ │ │ │ ├── regression-test-issue-2230.js │ │ │ │ │ ├── regression-test-issue-2237.js │ │ │ │ │ ├── regression-test-issue-2258-2963.js │ │ │ │ │ ├── regression-test-issue-2272.js │ │ │ │ │ ├── regression-test-issue-2384.js │ │ │ │ │ ├── regression-test-issue-2386.js │ │ │ │ │ ├── regression-test-issue-2398.js │ │ │ │ │ ├── regression-test-issue-2400.js │ │ │ │ │ ├── regression-test-issue-2409.js │ │ │ │ │ ├── regression-test-issue-2448.js │ │ │ │ │ ├── regression-test-issue-245.js │ │ │ │ │ ├── regression-test-issue-2451.js │ │ │ │ │ ├── regression-test-issue-2452.js │ │ │ │ │ ├── regression-test-issue-2453.js │ │ │ │ │ ├── regression-test-issue-2478.js │ │ │ │ │ ├── regression-test-issue-2494.js │ │ │ │ │ ├── regression-test-issue-255.js │ │ │ │ │ ├── regression-test-issue-257.js │ │ │ │ │ ├── regression-test-issue-260.js │ │ │ │ │ ├── regression-test-issue-261.js │ │ │ │ │ ├── regression-test-issue-2614.js │ │ │ │ │ ├── regression-test-issue-262.js │ │ │ │ │ ├── regression-test-issue-263.js │ │ │ │ │ ├── regression-test-issue-264.js │ │ │ │ │ ├── regression-test-issue-265.js │ │ │ │ │ ├── regression-test-issue-2652-2653.js │ │ │ │ │ ├── regression-test-issue-2656.js │ │ │ │ │ ├── regression-test-issue-266.js │ │ │ │ │ ├── regression-test-issue-2660.js │ │ │ │ │ ├── regression-test-issue-267.js │ │ │ │ │ ├── regression-test-issue-2699.js │ │ │ │ │ ├── regression-test-issue-274.js │ │ │ │ │ ├── regression-test-issue-2755.js │ │ │ │ │ ├── regression-test-issue-276.js │ │ │ │ │ ├── regression-test-issue-279.js │ │ │ │ │ ├── regression-test-issue-280.js │ │ │ │ │ ├── regression-test-issue-2802.js │ │ │ │ │ ├── regression-test-issue-2805.js │ │ │ │ │ ├── regression-test-issue-281.js │ │ │ │ │ ├── regression-test-issue-285.js │ │ │ │ │ ├── regression-test-issue-2905.js │ │ │ │ │ ├── regression-test-issue-2914.js │ │ │ │ │ ├── regression-test-issue-2936.js │ │ │ │ │ ├── regression-test-issue-2937.js │ │ │ │ │ ├── regression-test-issue-3039.js │ │ │ │ │ ├── regression-test-issue-3048.js │ │ │ │ │ ├── regression-test-issue-3055.js │ │ │ │ │ ├── regression-test-issue-3060.js │ │ │ │ │ ├── regression-test-issue-3068.js │ │ │ │ │ ├── regression-test-issue-3072.js │ │ │ │ │ ├── regression-test-issue-3082.js │ │ │ │ │ ├── regression-test-issue-3114.js │ │ │ │ │ ├── regression-test-issue-316.js │ │ │ │ │ ├── regression-test-issue-3229.js │ │ │ │ │ ├── regression-test-issue-3271.js │ │ │ │ │ ├── regression-test-issue-3313.js │ │ │ │ │ ├── regression-test-issue-3325.js │ │ │ │ │ ├── regression-test-issue-339.js │ │ │ │ │ ├── regression-test-issue-3397.js │ │ │ │ │ ├── regression-test-issue-340.js │ │ │ │ │ ├── regression-test-issue-341.js │ │ │ │ │ ├── regression-test-issue-3467.js │ │ │ │ │ ├── regression-test-issue-3477.js │ │ │ │ │ ├── regression-test-issue-3523.js │ │ │ │ │ ├── regression-test-issue-3532.js │ │ │ │ │ ├── regression-test-issue-354.js │ │ │ │ │ ├── regression-test-issue-3553.js │ │ │ │ │ ├── regression-test-issue-359.js │ │ │ │ │ ├── regression-test-issue-3608.js │ │ │ │ │ ├── regression-test-issue-3648.js │ │ │ │ │ ├── regression-test-issue-3650.js │ │ │ │ │ ├── regression-test-issue-3711.js │ │ │ │ │ ├── regression-test-issue-3748-3749.js │ │ │ │ │ ├── regression-test-issue-3761.js │ │ │ │ │ ├── regression-test-issue-3778.js │ │ │ │ │ ├── regression-test-issue-3779.js │ │ │ │ │ ├── regression-test-issue-380.js │ │ │ │ │ ├── regression-test-issue-381.js │ │ │ │ │ ├── regression-test-issue-3813.js │ │ │ │ │ ├── regression-test-issue-3821.js │ │ │ │ │ ├── regression-test-issue-3878.js │ │ │ │ │ ├── regression-test-issue-3903.js │ │ │ │ │ ├── regression-test-issue-3934.js │ │ │ │ │ ├── regression-test-issue-3944.js │ │ │ │ │ ├── regression-test-issue-4056.js │ │ │ │ │ ├── regression-test-issue-4238.js │ │ │ │ │ ├── regression-test-issue-429.js │ │ │ │ │ ├── regression-test-issue-440.js │ │ │ │ │ ├── regression-test-issue-447.js │ │ │ │ │ ├── regression-test-issue-453.js │ │ │ │ │ ├── regression-test-issue-541.js │ │ │ │ │ ├── regression-test-issue-563.js │ │ │ │ │ ├── regression-test-issue-566.js │ │ │ │ │ ├── regression-test-issue-613.js │ │ │ │ │ ├── regression-test-issue-614.js │ │ │ │ │ ├── regression-test-issue-639.js │ │ │ │ │ ├── regression-test-issue-640.js │ │ │ │ │ ├── regression-test-issue-641.js │ │ │ │ │ ├── regression-test-issue-642.js │ │ │ │ │ ├── regression-test-issue-644.js │ │ │ │ │ ├── regression-test-issue-646.js │ │ │ │ │ ├── regression-test-issue-652.js │ │ │ │ │ ├── regression-test-issue-653.js │ │ │ │ │ ├── regression-test-issue-654.js │ │ │ │ │ ├── regression-test-issue-655.js │ │ │ │ │ ├── regression-test-issue-667.js │ │ │ │ │ ├── regression-test-issue-669.js │ │ │ │ │ ├── regression-test-issue-680.js │ │ │ │ │ ├── regression-test-issue-686.js │ │ │ │ │ ├── regression-test-issue-689.js │ │ │ │ │ ├── regression-test-issue-703.js │ │ │ │ │ ├── regression-test-issue-725.js │ │ │ │ │ ├── regression-test-issue-736.js │ │ │ │ │ ├── regression-test-issue-737.js │ │ │ │ │ ├── regression-test-issue-738.js │ │ │ │ │ ├── regression-test-issue-739.js │ │ │ │ │ ├── regression-test-issue-741.js │ │ │ │ │ ├── regression-test-issue-743.js │ │ │ │ │ ├── regression-test-issue-745.js │ │ │ │ │ ├── regression-test-issue-747.js │ │ │ │ │ ├── regression-test-issue-781.js │ │ │ │ │ ├── regression-test-issue-783.js │ │ │ │ │ ├── regression-test-issue-785.js │ │ │ │ │ ├── regression-test-issue-786.js │ │ │ │ │ ├── regression-test-issue-798.js │ │ │ │ │ ├── regression-test-issue-962.js │ │ │ │ │ ├── regression-test-issues-43-183.js │ │ │ │ │ ├── relational.js │ │ │ │ │ ├── shift.js │ │ │ │ │ ├── sqrt.js │ │ │ │ │ ├── stack-limit.js │ │ │ │ │ ├── strict.js │ │ │ │ │ ├── strict2.js │ │ │ │ │ ├── string-prototype-charat.js │ │ │ │ │ ├── string-prototype-charcodeat.js │ │ │ │ │ ├── string-prototype-concat.js │ │ │ │ │ ├── string-prototype-indexof.js │ │ │ │ │ ├── string-prototype-lastindexof.js │ │ │ │ │ ├── string-prototype-localecompare.js │ │ │ │ │ ├── string-prototype-match.js │ │ │ │ │ ├── string-prototype-replace.js │ │ │ │ │ ├── string-prototype-search.js │ │ │ │ │ ├── string-prototype-slice.js │ │ │ │ │ ├── string-prototype-split.js │ │ │ │ │ ├── string-prototype-substr.js │ │ │ │ │ ├── string-prototype-substring.js │ │ │ │ │ ├── string-prototype-trim.js │ │ │ │ │ ├── string-prototype.js │ │ │ │ │ ├── string-surrogates-concat.js │ │ │ │ │ ├── string-upper-lower-case-conversion.js │ │ │ │ │ ├── string.js │ │ │ │ │ ├── switch-case.js │ │ │ │ │ ├── test-new-string.js │ │ │ │ │ ├── test_suite_06.js │ │ │ │ │ ├── test_suite_07.js │ │ │ │ │ ├── test_suite_08.js │ │ │ │ │ ├── test_suite_10.js │ │ │ │ │ ├── test_suite_11.js │ │ │ │ │ ├── test_suite_12.js │ │ │ │ │ ├── test_suite_13.js │ │ │ │ │ ├── test_suite_15.js │ │ │ │ │ ├── this-arg.js │ │ │ │ │ ├── try-catch-finally.js │ │ │ │ │ ├── try-eval.js │ │ │ │ │ ├── typeof.js │ │ │ │ │ ├── unary-plus-minus.js │ │ │ │ │ ├── unicode-format-control-characters.js │ │ │ │ │ ├── unusual.js │ │ │ │ │ ├── var-decl.js │ │ │ │ │ ├── variables.js │ │ │ │ │ ├── windows-line-ending.js │ │ │ │ │ └── zero-character.js │ │ │ │ ├── test262-es6-excludelist.xml │ │ │ │ ├── test262-esnext-excludelist.xml │ │ │ │ ├── unit-core/ │ │ │ │ │ ├── CMakeLists.txt │ │ │ │ │ ├── test-abort.c │ │ │ │ │ ├── test-api-binary-operations-arithmetics.c │ │ │ │ │ ├── test-api-binary-operations-comparisons.c │ │ │ │ │ ├── test-api-binary-operations-instanceof.c │ │ │ │ │ ├── test-api-errortype.c │ │ │ │ │ ├── test-api-functiontype.c │ │ │ │ │ ├── test-api-iteratortype.c │ │ │ │ │ ├── test-api-object-property-names.c │ │ │ │ │ ├── test-api-objecttype.c │ │ │ │ │ ├── test-api-promise.c │ │ │ │ │ ├── test-api-property.c │ │ │ │ │ ├── test-api-set-and-clear-error-flag.c │ │ │ │ │ ├── test-api-strings.c │ │ │ │ │ ├── test-api-value-type.c │ │ │ │ │ ├── test-api.c │ │ │ │ │ ├── test-arraybuffer.c │ │ │ │ │ ├── test-backtrace.c │ │ │ │ │ ├── test-bigint.c │ │ │ │ │ ├── test-common.h │ │ │ │ │ ├── test-container.c │ │ │ │ │ ├── test-context-data.c │ │ │ │ │ ├── test-dataview.c │ │ │ │ │ ├── test-date-helpers.c │ │ │ │ │ ├── test-error-callback.c │ │ │ │ │ ├── test-exec-stop.c │ │ │ │ │ ├── test-external-string.c │ │ │ │ │ ├── test-from-property-descriptor.c │ │ │ │ │ ├── test-has-property.c │ │ │ │ │ ├── test-internal-properties.c │ │ │ │ │ ├── test-jmem.c │ │ │ │ │ ├── test-json.c │ │ │ │ │ ├── test-lit-char-helpers.c │ │ │ │ │ ├── test-literal-storage.c │ │ │ │ │ ├── test-mem-stats.c │ │ │ │ │ ├── test-native-callback-nested.c │ │ │ │ │ ├── test-native-instanceof.c │ │ │ │ │ ├── test-newtarget.c │ │ │ │ │ ├── test-number-converter.c │ │ │ │ │ ├── test-number-to-int32.c │ │ │ │ │ ├── test-number-to-string.c │ │ │ │ │ ├── test-objects-foreach.c │ │ │ │ │ ├── test-poolman.c │ │ │ │ │ ├── test-promise.c │ │ │ │ │ ├── test-proxy.c │ │ │ │ │ ├── test-realm.c │ │ │ │ │ ├── test-regexp-dotall-unicode.c │ │ │ │ │ ├── test-regexp.c │ │ │ │ │ ├── test-regression-3588.c │ │ │ │ │ ├── test-resource-name.c │ │ │ │ │ ├── test-snapshot.c │ │ │ │ │ ├── test-string-to-number.c │ │ │ │ │ ├── test-stringbuilder.c │ │ │ │ │ ├── test-strings.c │ │ │ │ │ ├── test-symbol.c │ │ │ │ │ ├── test-to-integer.c │ │ │ │ │ ├── test-to-length.c │ │ │ │ │ ├── test-to-property-descriptor.c │ │ │ │ │ ├── test-typedarray.c │ │ │ │ │ └── test-unicode.c │ │ │ │ ├── unit-doc/ │ │ │ │ │ └── CMakeLists.txt │ │ │ │ ├── unit-ext/ │ │ │ │ │ ├── CMakeLists.txt │ │ │ │ │ ├── module/ │ │ │ │ │ │ ├── CMakeLists.txt │ │ │ │ │ │ ├── jerry-module-test.c │ │ │ │ │ │ ├── my-broken-module.c │ │ │ │ │ │ └── my-custom-module.c │ │ │ │ │ ├── test-common.h │ │ │ │ │ ├── test-ext-arg.c │ │ │ │ │ ├── test-ext-autorelease.c │ │ │ │ │ ├── test-ext-handle-scope-escape.c │ │ │ │ │ ├── test-ext-handle-scope-handle-prelist-escape.c │ │ │ │ │ ├── test-ext-handle-scope-handle-prelist.c │ │ │ │ │ ├── test-ext-handle-scope-nested.c │ │ │ │ │ ├── test-ext-handle-scope-remove.c │ │ │ │ │ ├── test-ext-handle-scope-root.c │ │ │ │ │ ├── test-ext-handle-scope.c │ │ │ │ │ ├── test-ext-method-register.c │ │ │ │ │ ├── test-ext-module-canonical.c │ │ │ │ │ └── test-ext-module-empty.c │ │ │ │ └── unit-math/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── test-math.c │ │ │ │ └── test-math.inc.h │ │ │ ├── third-party/ │ │ │ │ └── valgrind/ │ │ │ │ ├── memcheck.h │ │ │ │ └── valgrind.h │ │ │ └── tools/ │ │ │ ├── amalgam.py │ │ │ ├── apt-get-install-deps.sh │ │ │ ├── apt-get-install-qemu-arm.sh │ │ │ ├── babel/ │ │ │ │ ├── .babelrc │ │ │ │ ├── README.md │ │ │ │ ├── package.json │ │ │ │ └── scripts/ │ │ │ │ └── transpile.sh │ │ │ ├── brew-install-deps.sh │ │ │ ├── build.py │ │ │ ├── check-cppcheck.sh │ │ │ ├── check-doxygen.sh │ │ │ ├── check-license.py │ │ │ ├── check-magic-strings.sh │ │ │ ├── check-pylint.sh │ │ │ ├── check-signed-off.sh │ │ │ ├── check-sonarqube.sh │ │ │ ├── check-vera.sh │ │ │ ├── cppcheck/ │ │ │ │ └── suppressions-list │ │ │ ├── gen-doctest.py │ │ │ ├── gen-magic-strings.py │ │ │ ├── gen-test-math.sh │ │ │ ├── gen-unicode.py │ │ │ ├── gen_c_source.py │ │ │ ├── heaplimit_measure.py │ │ │ ├── js2c.py │ │ │ ├── mem-stats-measure.sh │ │ │ ├── perf.sh │ │ │ ├── pylint/ │ │ │ │ └── pylintrc │ │ │ ├── rss-measure.sh │ │ │ ├── run-mem-stats-test.sh │ │ │ ├── run-perf-test.sh │ │ │ ├── run-tests.py │ │ │ ├── runners/ │ │ │ │ ├── run-benchmarks.sh │ │ │ │ ├── run-debugger-test.sh │ │ │ │ ├── run-test-suite-test262.py │ │ │ │ ├── run-test-suite.py │ │ │ │ ├── run-unittests.py │ │ │ │ ├── test262-harness.py │ │ │ │ └── util.py │ │ │ ├── settings.py │ │ │ ├── unit-tests/ │ │ │ │ ├── Makefile │ │ │ │ └── gen-test-math.c │ │ │ ├── update-webpage.sh │ │ │ ├── vera++/ │ │ │ │ ├── profiles/ │ │ │ │ │ └── jerry │ │ │ │ └── scripts/ │ │ │ │ └── rules/ │ │ │ │ ├── jerry_always_curly.tcl │ │ │ │ ├── jerry_braces_on_separate_line.tcl │ │ │ │ ├── jerry_braces_same_line_or_column.tcl │ │ │ │ ├── jerry_comment_function_end.tcl │ │ │ │ ├── jerry_funcname_space_parentheses.tcl │ │ │ │ ├── jerry_identifier_no_space_bracket.tcl │ │ │ │ ├── jerry_indentation.tcl │ │ │ │ ├── jerry_max_line_length.tcl │ │ │ │ ├── jerry_no_consecutive_empty_lines.tcl │ │ │ │ ├── jerry_no_leading_or_trailing_empty_line.tcl │ │ │ │ ├── jerry_no_space_after_opening_parentheses.tcl │ │ │ │ ├── jerry_no_space_before_closing_parentheses.tcl │ │ │ │ ├── jerry_no_tabs.tcl │ │ │ │ ├── jerry_no_trailing_spaces.tcl │ │ │ │ ├── jerry_pointer_declarator_space.tcl │ │ │ │ ├── jerry_switch_case.tcl │ │ │ │ └── jerry_typecast_space_parentheses.tcl │ │ │ └── version.py │ │ ├── libpng/ │ │ │ ├── CMakeLists.txt │ │ │ ├── png.c │ │ │ ├── png.h │ │ │ ├── pngconf.h │ │ │ ├── pngerror.c │ │ │ ├── pnggccrd.c │ │ │ ├── pngget.c │ │ │ ├── pngmem.c │ │ │ ├── pngpread.c │ │ │ ├── pngread.c │ │ │ ├── pngrio.c │ │ │ ├── pngrtran.c │ │ │ ├── pngrutil.c │ │ │ ├── pngset.c │ │ │ ├── pngtest.c │ │ │ ├── pngtrans.c │ │ │ ├── pngvcrd.c │ │ │ ├── pngwio.c │ │ │ ├── pngwrite.c │ │ │ ├── pngwtran.c │ │ │ └── pngwutil.c │ │ ├── pthreads/ │ │ │ ├── ANNOUNCE │ │ │ ├── BUGS │ │ │ ├── Bmakefile │ │ │ ├── CONTRIBUTORS │ │ │ ├── COPYING │ │ │ ├── ChangeLog │ │ │ ├── FAQ │ │ │ ├── GNUmakefile │ │ │ ├── MAINTAINERS │ │ │ ├── Makefile │ │ │ ├── Makefile_copy │ │ │ ├── NEWS │ │ │ ├── Nmakefile │ │ │ ├── Nmakefile.tests │ │ │ ├── PROGRESS │ │ │ ├── README │ │ │ ├── README.Borland │ │ │ ├── README.CV │ │ │ ├── README.NONPORTABLE │ │ │ ├── README.Watcom │ │ │ ├── README.WinCE │ │ │ ├── TODO │ │ │ ├── WinCE-PORT │ │ │ ├── attr.c │ │ │ ├── barrier.c │ │ │ ├── builddmc.bat │ │ │ ├── cancel.c │ │ │ ├── cleanup.c │ │ │ ├── condvar.c │ │ │ ├── config.h │ │ │ ├── create.c │ │ │ ├── dll.c │ │ │ ├── errno.c │ │ │ ├── exit.c │ │ │ ├── fork.c │ │ │ ├── global.c │ │ │ ├── implement.h │ │ │ ├── manual/ │ │ │ │ ├── ChangeLog │ │ │ │ ├── PortabilityIssues.html │ │ │ │ ├── index.html │ │ │ │ ├── pthreadCancelableWait.html │ │ │ │ ├── pthread_attr_init.html │ │ │ │ ├── pthread_attr_setstackaddr.html │ │ │ │ ├── pthread_attr_setstacksize.html │ │ │ │ ├── pthread_barrier_init.html │ │ │ │ ├── pthread_barrier_wait.html │ │ │ │ ├── pthread_barrierattr_init.html │ │ │ │ ├── pthread_barrierattr_setpshared.html │ │ │ │ ├── pthread_cancel.html │ │ │ │ ├── pthread_cleanup_push.html │ │ │ │ ├── pthread_cond_init.html │ │ │ │ ├── pthread_condattr_init.html │ │ │ │ ├── pthread_condattr_setpshared.html │ │ │ │ ├── pthread_create.html │ │ │ │ ├── pthread_delay_np.html │ │ │ │ ├── pthread_detach.html │ │ │ │ ├── pthread_equal.html │ │ │ │ ├── pthread_exit.html │ │ │ │ ├── pthread_getw32threadhandle_np.html │ │ │ │ ├── pthread_join.html │ │ │ │ ├── pthread_key_create.html │ │ │ │ ├── pthread_kill.html │ │ │ │ ├── pthread_mutex_init.html │ │ │ │ ├── pthread_mutexattr_init.html │ │ │ │ ├── pthread_mutexattr_setpshared.html │ │ │ │ ├── pthread_num_processors_np.html │ │ │ │ ├── pthread_once.html │ │ │ │ ├── pthread_rwlock_init.html │ │ │ │ ├── pthread_rwlock_rdlock.html │ │ │ │ ├── pthread_rwlock_timedrdlock.html │ │ │ │ ├── pthread_rwlock_timedwrlock.html │ │ │ │ ├── pthread_rwlock_unlock.html │ │ │ │ ├── pthread_rwlock_wrlock.html │ │ │ │ ├── pthread_rwlockattr_init.html │ │ │ │ ├── pthread_rwlockattr_setpshared.html │ │ │ │ ├── pthread_self.html │ │ │ │ ├── pthread_setcancelstate.html │ │ │ │ ├── pthread_setcanceltype.html │ │ │ │ ├── pthread_setconcurrency.html │ │ │ │ ├── pthread_setschedparam.html │ │ │ │ ├── pthread_spin_init.html │ │ │ │ ├── pthread_spin_lock.html │ │ │ │ ├── pthread_spin_unlock.html │ │ │ │ ├── pthread_timechange_handler_np.html │ │ │ │ ├── pthread_win32_attach_detach_np.html │ │ │ │ ├── pthread_win32_test_features_np.html │ │ │ │ ├── sched_get_priority_max.html │ │ │ │ ├── sched_getscheduler.html │ │ │ │ ├── sched_setscheduler.html │ │ │ │ ├── sched_yield.html │ │ │ │ └── sem_init.html │ │ │ ├── misc.c │ │ │ ├── mutex.c │ │ │ ├── need_errno.h │ │ │ ├── nonportable.c │ │ │ ├── private.c │ │ │ ├── pthread.c │ │ │ ├── pthread.dsp │ │ │ ├── pthread.dsw │ │ │ ├── pthread.h │ │ │ ├── pthread.sln │ │ │ ├── pthread.vcxproj │ │ │ ├── pthread.vcxproj.filters │ │ │ ├── pthreadVC2.lib │ │ │ ├── pthread_attr_destroy.c │ │ │ ├── pthread_attr_getdetachstate.c │ │ │ ├── pthread_attr_getinheritsched.c │ │ │ ├── pthread_attr_getschedparam.c │ │ │ ├── pthread_attr_getschedpolicy.c │ │ │ ├── pthread_attr_getscope.c │ │ │ ├── pthread_attr_getstackaddr.c │ │ │ ├── pthread_attr_getstacksize.c │ │ │ ├── pthread_attr_init.c │ │ │ ├── pthread_attr_setdetachstate.c │ │ │ ├── pthread_attr_setinheritsched.c │ │ │ ├── pthread_attr_setschedparam.c │ │ │ ├── pthread_attr_setschedpolicy.c │ │ │ ├── pthread_attr_setscope.c │ │ │ ├── pthread_attr_setstackaddr.c │ │ │ ├── pthread_attr_setstacksize.c │ │ │ ├── pthread_barrier_destroy.c │ │ │ ├── pthread_barrier_init.c │ │ │ ├── pthread_barrier_wait.c │ │ │ ├── pthread_barrierattr_destroy.c │ │ │ ├── pthread_barrierattr_getpshared.c │ │ │ ├── pthread_barrierattr_init.c │ │ │ ├── pthread_barrierattr_setpshared.c │ │ │ ├── pthread_cancel.c │ │ │ ├── pthread_cond_destroy.c │ │ │ ├── pthread_cond_init.c │ │ │ ├── pthread_cond_signal.c │ │ │ ├── pthread_cond_wait.c │ │ │ ├── pthread_condattr_destroy.c │ │ │ ├── pthread_condattr_getpshared.c │ │ │ ├── pthread_condattr_init.c │ │ │ ├── pthread_condattr_setpshared.c │ │ │ ├── pthread_delay_np.c │ │ │ ├── pthread_detach.c │ │ │ ├── pthread_equal.c │ │ │ ├── pthread_exit.c │ │ │ ├── pthread_getconcurrency.c │ │ │ ├── pthread_getschedparam.c │ │ │ ├── pthread_getspecific.c │ │ │ ├── pthread_getw32threadhandle_np.c │ │ │ ├── pthread_join.c │ │ │ ├── pthread_key_create.c │ │ │ ├── pthread_key_delete.c │ │ │ ├── pthread_kill.c │ │ │ ├── pthread_mutex_destroy.c │ │ │ ├── pthread_mutex_init.c │ │ │ ├── pthread_mutex_lock.c │ │ │ ├── pthread_mutex_timedlock.c │ │ │ ├── pthread_mutex_trylock.c │ │ │ ├── pthread_mutex_unlock.c │ │ │ ├── pthread_mutexattr_destroy.c │ │ │ ├── pthread_mutexattr_getkind_np.c │ │ │ ├── pthread_mutexattr_getpshared.c │ │ │ ├── pthread_mutexattr_gettype.c │ │ │ ├── pthread_mutexattr_init.c │ │ │ ├── pthread_mutexattr_setkind_np.c │ │ │ ├── pthread_mutexattr_setpshared.c │ │ │ ├── pthread_mutexattr_settype.c │ │ │ ├── pthread_num_processors_np.c │ │ │ ├── pthread_once.c │ │ │ ├── pthread_once.x │ │ │ ├── pthread_rwlock_destroy.c │ │ │ ├── pthread_rwlock_init.c │ │ │ ├── pthread_rwlock_rdlock.c │ │ │ ├── pthread_rwlock_timedrdlock.c │ │ │ ├── pthread_rwlock_timedwrlock.c │ │ │ ├── pthread_rwlock_tryrdlock.c │ │ │ ├── pthread_rwlock_trywrlock.c │ │ │ ├── pthread_rwlock_unlock.c │ │ │ ├── pthread_rwlock_wrlock.c │ │ │ ├── pthread_rwlockattr_destroy.c │ │ │ ├── pthread_rwlockattr_getpshared.c │ │ │ ├── pthread_rwlockattr_init.c │ │ │ ├── pthread_rwlockattr_setpshared.c │ │ │ ├── pthread_self.c │ │ │ ├── pthread_setcancelstate.c │ │ │ ├── pthread_setcanceltype.c │ │ │ ├── pthread_setconcurrency.c │ │ │ ├── pthread_setschedparam.c │ │ │ ├── pthread_setspecific.c │ │ │ ├── pthread_spin_destroy.c │ │ │ ├── pthread_spin_init.c │ │ │ ├── pthread_spin_lock.c │ │ │ ├── pthread_spin_trylock.c │ │ │ ├── pthread_spin_unlock.c │ │ │ ├── pthread_testcancel.c │ │ │ ├── pthread_timechange_handler_np.c │ │ │ ├── pthread_win32_attach_detach_np.c │ │ │ ├── ptw32_InterlockedCompareExchange.c │ │ │ ├── ptw32_MCS_lock.c │ │ │ ├── ptw32_callUserDestroyRoutines.c │ │ │ ├── ptw32_calloc.c │ │ │ ├── ptw32_cond_check_need_init.c │ │ │ ├── ptw32_getprocessors.c │ │ │ ├── ptw32_is_attr.c │ │ │ ├── ptw32_mutex_check_need_init.c │ │ │ ├── ptw32_new.c │ │ │ ├── ptw32_processInitialize.c │ │ │ ├── ptw32_processTerminate.c │ │ │ ├── ptw32_relmillisecs.c │ │ │ ├── ptw32_reuse.c │ │ │ ├── ptw32_rwlock_cancelwrwait.c │ │ │ ├── ptw32_rwlock_check_need_init.c │ │ │ ├── ptw32_semwait.c │ │ │ ├── ptw32_spinlock_check_need_init.c │ │ │ ├── ptw32_threadDestroy.c │ │ │ ├── ptw32_threadStart.c │ │ │ ├── ptw32_throw.c │ │ │ ├── ptw32_timespec.c │ │ │ ├── ptw32_tkAssocCreate.c │ │ │ ├── ptw32_tkAssocDestroy.c │ │ │ ├── rwlock.c │ │ │ ├── sched.c │ │ │ ├── sched.h │ │ │ ├── sched_get_priority_max.c │ │ │ ├── sched_get_priority_min.c │ │ │ ├── sched_getscheduler.c │ │ │ ├── sched_setscheduler.c │ │ │ ├── sched_yield.c │ │ │ ├── sem_close.c │ │ │ ├── sem_destroy.c │ │ │ ├── sem_getvalue.c │ │ │ ├── sem_init.c │ │ │ ├── sem_open.c │ │ │ ├── sem_post.c │ │ │ ├── sem_post_multiple.c │ │ │ ├── sem_timedwait.c │ │ │ ├── sem_trywait.c │ │ │ ├── sem_unlink.c │ │ │ ├── sem_wait.c │ │ │ ├── semaphore.c │ │ │ ├── semaphore.h │ │ │ ├── signal.c │ │ │ ├── spin.c │ │ │ ├── sync.c │ │ │ ├── tests/ │ │ │ │ ├── Bmakefile │ │ │ │ ├── ChangeLog │ │ │ │ ├── Debug.dsp │ │ │ │ ├── Debug.dsw │ │ │ │ ├── Debug.plg │ │ │ │ ├── Debug.txt │ │ │ │ ├── GNUmakefile │ │ │ │ ├── Makefile │ │ │ │ ├── README.BENCHTESTS │ │ │ │ ├── SIZES.VCE │ │ │ │ ├── Wmakefile │ │ │ │ ├── barrier1.c │ │ │ │ ├── barrier2.c │ │ │ │ ├── barrier3.c │ │ │ │ ├── barrier4.c │ │ │ │ ├── barrier5.c │ │ │ │ ├── benchlib.c │ │ │ │ ├── benchtest.h │ │ │ │ ├── benchtest1.c │ │ │ │ ├── benchtest2.c │ │ │ │ ├── benchtest3.c │ │ │ │ ├── benchtest4.c │ │ │ │ ├── benchtest5.c │ │ │ │ ├── cancel1.c │ │ │ │ ├── cancel2.c │ │ │ │ ├── cancel3.c │ │ │ │ ├── cancel4.c │ │ │ │ ├── cancel5.c │ │ │ │ ├── cancel6a.c │ │ │ │ ├── cancel6d.c │ │ │ │ ├── cancel7.c │ │ │ │ ├── cancel8.c │ │ │ │ ├── cancel9.c │ │ │ │ ├── cleanup0.c │ │ │ │ ├── cleanup1.c │ │ │ │ ├── cleanup2.c │ │ │ │ ├── cleanup3.c │ │ │ │ ├── condvar1.c │ │ │ │ ├── condvar1_1.c │ │ │ │ ├── condvar1_2.c │ │ │ │ ├── condvar2.c │ │ │ │ ├── condvar2_1.c │ │ │ │ ├── condvar3.c │ │ │ │ ├── condvar3_1.c │ │ │ │ ├── condvar3_2.c │ │ │ │ ├── condvar3_3.c │ │ │ │ ├── condvar4.c │ │ │ │ ├── condvar5.c │ │ │ │ ├── condvar6.c │ │ │ │ ├── condvar7.c │ │ │ │ ├── condvar8.c │ │ │ │ ├── condvar9.c │ │ │ │ ├── context1.c │ │ │ │ ├── count1.c │ │ │ │ ├── create1.c │ │ │ │ ├── create2.c │ │ │ │ ├── create3.c │ │ │ │ ├── delay1.c │ │ │ │ ├── delay2.c │ │ │ │ ├── detach1.c │ │ │ │ ├── equal1.c │ │ │ │ ├── errno1.c │ │ │ │ ├── exception1.c │ │ │ │ ├── exception2.c │ │ │ │ ├── exception3.c │ │ │ │ ├── exit1.c │ │ │ │ ├── exit2.c │ │ │ │ ├── exit3.c │ │ │ │ ├── exit4.c │ │ │ │ ├── exit5.c │ │ │ │ ├── eyal1.c │ │ │ │ ├── inherit1.c │ │ │ │ ├── join0.c │ │ │ │ ├── join1.c │ │ │ │ ├── join2.c │ │ │ │ ├── join3.c │ │ │ │ ├── kill1.c │ │ │ │ ├── loadfree.c │ │ │ │ ├── multiPCcaBetter.c │ │ │ │ ├── mutex1.c │ │ │ │ ├── mutex1e.c │ │ │ │ ├── mutex1n.c │ │ │ │ ├── mutex1r.c │ │ │ │ ├── mutex2.c │ │ │ │ ├── mutex2e.c │ │ │ │ ├── mutex2r.c │ │ │ │ ├── mutex3.c │ │ │ │ ├── mutex3e.c │ │ │ │ ├── mutex3r.c │ │ │ │ ├── mutex4.c │ │ │ │ ├── mutex5.c │ │ │ │ ├── mutex6.c │ │ │ │ ├── mutex6e.c │ │ │ │ ├── mutex6es.c │ │ │ │ ├── mutex6n.c │ │ │ │ ├── mutex6r.c │ │ │ │ ├── mutex6rs.c │ │ │ │ ├── mutex6s.c │ │ │ │ ├── mutex7.c │ │ │ │ ├── mutex7e.c │ │ │ │ ├── mutex7n.c │ │ │ │ ├── mutex7r.c │ │ │ │ ├── mutex8.c │ │ │ │ ├── mutex8e.c │ │ │ │ ├── mutex8n.c │ │ │ │ ├── mutex8r.c │ │ │ │ ├── once1.c │ │ │ │ ├── once2.c │ │ │ │ ├── once3.c │ │ │ │ ├── once4.c │ │ │ │ ├── priority1.c │ │ │ │ ├── priority2.c │ │ │ │ ├── readme │ │ │ │ ├── reuse1.c │ │ │ │ ├── reuse2.c │ │ │ │ ├── rwlock1.c │ │ │ │ ├── rwlock2.c │ │ │ │ ├── rwlock2_t.c │ │ │ │ ├── rwlock3.c │ │ │ │ ├── rwlock3_t.c │ │ │ │ ├── rwlock4.c │ │ │ │ ├── rwlock4_t.c │ │ │ │ ├── rwlock5.c │ │ │ │ ├── rwlock5_t.c │ │ │ │ ├── rwlock6.c │ │ │ │ ├── rwlock6_t.c │ │ │ │ ├── rwlock6_t2.c │ │ │ │ ├── rwlock7.c │ │ │ │ ├── rwlock8.c │ │ │ │ ├── self1.c │ │ │ │ ├── self2.c │ │ │ │ ├── semaphore1.c │ │ │ │ ├── semaphore2.c │ │ │ │ ├── semaphore3.c │ │ │ │ ├── semaphore4.c │ │ │ │ ├── semaphore4t.c │ │ │ │ ├── semaphore5.c │ │ │ │ ├── sizes.c │ │ │ │ ├── sizes.gc │ │ │ │ ├── sizes.gce │ │ │ │ ├── sizes.vc │ │ │ │ ├── sizes.vse │ │ │ │ ├── spin1.c │ │ │ │ ├── spin2.c │ │ │ │ ├── spin3.c │ │ │ │ ├── spin4.c │ │ │ │ ├── stress1.c │ │ │ │ ├── test.h │ │ │ │ ├── tryentercs.c │ │ │ │ ├── tryentercs2.c │ │ │ │ ├── tsd1.c │ │ │ │ ├── tsd2.c │ │ │ │ ├── valid1.c │ │ │ │ └── valid2.c │ │ │ ├── tsd.c │ │ │ ├── version.rc │ │ │ ├── version.res │ │ │ └── w32_CancelableWait.c │ │ ├── pugixml/ │ │ │ ├── CMakeLists.txt │ │ │ ├── pugiconfig.hpp │ │ │ ├── pugixml.cpp │ │ │ └── pugixml.hpp │ │ ├── rapidjson/ │ │ │ └── include/ │ │ │ └── rapidjson/ │ │ │ ├── allocators.h │ │ │ ├── cursorstreamwrapper.h │ │ │ ├── document.h │ │ │ ├── encodedstream.h │ │ │ ├── encodings.h │ │ │ ├── error/ │ │ │ │ ├── en.h │ │ │ │ └── error.h │ │ │ ├── filereadstream.h │ │ │ ├── filewritestream.h │ │ │ ├── fwd.h │ │ │ ├── internal/ │ │ │ │ ├── biginteger.h │ │ │ │ ├── clzll.h │ │ │ │ ├── diyfp.h │ │ │ │ ├── dtoa.h │ │ │ │ ├── ieee754.h │ │ │ │ ├── itoa.h │ │ │ │ ├── meta.h │ │ │ │ ├── pow10.h │ │ │ │ ├── regex.h │ │ │ │ ├── stack.h │ │ │ │ ├── strfunc.h │ │ │ │ ├── strtod.h │ │ │ │ └── swap.h │ │ │ ├── istreamwrapper.h │ │ │ ├── memorybuffer.h │ │ │ ├── memorystream.h │ │ │ ├── msinttypes/ │ │ │ │ ├── inttypes.h │ │ │ │ └── stdint.h │ │ │ ├── ostreamwrapper.h │ │ │ ├── pointer.h │ │ │ ├── prettywriter.h │ │ │ ├── rapidjson.h │ │ │ ├── reader.h │ │ │ ├── schema.h │ │ │ ├── stream.h │ │ │ ├── stringbuffer.h │ │ │ └── writer.h │ │ ├── utf8cpp/ │ │ │ ├── utf8/ │ │ │ │ ├── checked.h │ │ │ │ ├── core.h │ │ │ │ ├── cpp11.h │ │ │ │ └── unchecked.h │ │ │ └── utf8.h │ │ └── zlib/ │ │ ├── CMakeLists.txt │ │ ├── adler32.c │ │ ├── compress.c │ │ ├── crc32.c │ │ ├── crc32.h │ │ ├── crypt.h │ │ ├── deflate.c │ │ ├── deflate.h │ │ ├── gzio.c │ │ ├── infback.c │ │ ├── inffast.c │ │ ├── inffast.h │ │ ├── inffixed.h │ │ ├── inflate.c │ │ ├── inflate.h │ │ ├── inftrees.c │ │ ├── inftrees.h │ │ ├── ioapi.c │ │ ├── ioapi.h │ │ ├── trees.c │ │ ├── trees.h │ │ ├── uncompr.c │ │ ├── unzip.c │ │ ├── unzip.h │ │ ├── zconf.h │ │ ├── zconf.in.h │ │ ├── zip.c │ │ ├── zip.h │ │ ├── zlib.h │ │ ├── zutil.c │ │ └── zutil.h │ ├── Assets/ │ │ ├── Scripts/ │ │ │ ├── Component.js │ │ │ ├── Math.js │ │ │ └── o2.js │ │ └── Shaders/ │ │ ├── Default.fsh │ │ ├── Default.fsh.metal │ │ ├── Default.vsh │ │ └── Default.vsh.metal │ ├── Platforms/ │ │ ├── .lldbinit │ │ ├── Windows/ │ │ │ └── Framework.natvis │ │ └── o2_lldb_formatters.py │ └── Sources/ │ └── o2/ │ ├── Animation/ │ │ ├── Animate.cpp │ │ ├── Animate.h │ │ ├── AnimationClip.cpp │ │ ├── AnimationClip.h │ │ ├── AnimationMask.cpp │ │ ├── AnimationMask.h │ │ ├── AnimationPlayer.cpp │ │ ├── AnimationPlayer.h │ │ ├── AnimationState.cpp │ │ ├── AnimationState.h │ │ ├── AnimationStateGraph.cpp │ │ ├── AnimationStateGraph.h │ │ ├── IAnimation.cpp │ │ ├── IAnimation.h │ │ └── Tracks/ │ │ ├── AnimationColor4Track.cpp │ │ ├── AnimationColor4Track.h │ │ ├── AnimationFloatTrack.cpp │ │ ├── AnimationFloatTrack.h │ │ ├── AnimationSubTrack.cpp │ │ ├── AnimationSubTrack.h │ │ ├── AnimationTrack.cpp │ │ ├── AnimationTrack.h │ │ ├── AnimationVec2FTrack.cpp │ │ ├── AnimationVec2FTrack.h │ │ ├── IAnimationTrack.cpp │ │ └── IAnimationTrack.h │ ├── Application/ │ │ ├── Android/ │ │ │ ├── AndroidPlatform.h │ │ │ ├── ApplicationBase.h │ │ │ └── ApplicationImpl.cpp │ │ ├── Application.cpp │ │ ├── Application.h │ │ ├── Input.cpp │ │ ├── Input.h │ │ ├── Linux/ │ │ │ ├── ApplicationBase.h │ │ │ └── ApplicationImpl.cpp │ │ ├── Mac/ │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.mm │ │ │ ├── ApplicationBase.h │ │ │ ├── ApplicationImpl.mm │ │ │ ├── ApplicationPlatformWrapper.h │ │ │ ├── RendererView.h │ │ │ └── RendererView.mm │ │ ├── VKCodes.h │ │ ├── WebAssembly/ │ │ │ ├── ApplicationBase.h │ │ │ └── ApplicationImpl.cpp │ │ ├── Windows/ │ │ │ ├── ApplicationBase.h │ │ │ └── ApplicationImpl.cpp │ │ └── iOS/ │ │ ├── AppDelegate.h │ │ ├── AppDelegate.mm │ │ ├── ApplicationBase.h │ │ ├── ApplicationImpl.mm │ │ ├── ApplicationPlatformWrapper.h │ │ ├── RendererView.h │ │ └── RendererView.mm │ ├── Assets/ │ │ ├── Asset.cpp │ │ ├── Asset.h │ │ ├── AssetInfo.cpp │ │ ├── AssetInfo.h │ │ ├── AssetRef.cpp │ │ ├── AssetRef.h │ │ ├── Assets.cpp │ │ ├── Assets.h │ │ ├── AssetsTree.cpp │ │ ├── AssetsTree.h │ │ ├── Meta.cpp │ │ ├── Meta.h │ │ └── Types/ │ │ ├── ActorAsset.cpp │ │ ├── ActorAsset.h │ │ ├── AnimationAsset.cpp │ │ ├── AnimationAsset.h │ │ ├── AnimationStateGraphAsset.cpp │ │ ├── AnimationStateGraphAsset.h │ │ ├── AtlasAsset.cpp │ │ ├── AtlasAsset.h │ │ ├── BinaryAsset.cpp │ │ ├── BinaryAsset.h │ │ ├── BitmapFontAsset.cpp │ │ ├── BitmapFontAsset.h │ │ ├── DataAsset.cpp │ │ ├── DataAsset.h │ │ ├── FolderAsset.cpp │ │ ├── FolderAsset.h │ │ ├── FontAsset.cpp │ │ ├── FontAsset.h │ │ ├── FragmentShaderAsset.cpp │ │ ├── FragmentShaderAsset.h │ │ ├── ImageAsset.cpp │ │ ├── ImageAsset.h │ │ ├── JavaScriptAsset.cpp │ │ ├── JavaScriptAsset.h │ │ ├── MaterialAsset.cpp │ │ ├── MaterialAsset.h │ │ ├── SceneAsset.cpp │ │ ├── SceneAsset.h │ │ ├── ShaderAsset.cpp │ │ ├── ShaderAsset.h │ │ ├── Spine/ │ │ │ ├── SpineAsset.cpp │ │ │ ├── SpineAsset.h │ │ │ ├── SpineAtlasAsset.cpp │ │ │ └── SpineAtlasAsset.h │ │ ├── VectorFontAsset.cpp │ │ ├── VectorFontAsset.h │ │ ├── VertexShaderAsset.cpp │ │ └── VertexShaderAsset.h │ ├── Config/ │ │ ├── PhysicsConfig.cpp │ │ ├── PhysicsConfig.h │ │ ├── ProjectConfig.cpp │ │ └── ProjectConfig.h │ ├── EditorStubs.cpp │ ├── EngineSettings.cpp │ ├── EngineSettings.h │ ├── Events/ │ │ ├── ApplicationEventsListener.cpp │ │ ├── ApplicationEventsListener.h │ │ ├── CursorAreaEventsListener.cpp │ │ ├── CursorAreaEventsListener.h │ │ ├── CursorAreaEventsListenersLayer.cpp │ │ ├── CursorAreaEventsListenersLayer.h │ │ ├── CursorEventsArea.cpp │ │ ├── CursorEventsArea.h │ │ ├── DrawableCursorEventsListener.cpp │ │ ├── DrawableCursorEventsListener.h │ │ ├── EventSystem.cpp │ │ ├── EventSystem.h │ │ ├── IEventsListener.cpp │ │ ├── IEventsListener.h │ │ ├── KeyboardEventsListener.cpp │ │ ├── KeyboardEventsListener.h │ │ ├── ShortcutKeysListener.cpp │ │ └── ShortcutKeysListener.h │ ├── Integration.cpp │ ├── Integration.h │ ├── O2.h │ ├── Physics/ │ │ ├── PhysicsWorld.cpp │ │ └── PhysicsWorld.h │ ├── Render/ │ │ ├── Android/ │ │ │ ├── MaterialBase.h │ │ │ ├── MaterialImpl.cpp │ │ │ ├── OpenGL.cpp │ │ │ ├── OpenGL.h │ │ │ ├── RenderBase.h │ │ │ ├── RenderImpl.cpp │ │ │ ├── ShaderBase.h │ │ │ ├── ShaderImpl.cpp │ │ │ ├── TextureBase.h │ │ │ └── TextureImpl.cpp │ │ ├── BitmapFont.cpp │ │ ├── BitmapFont.h │ │ ├── Camera.cpp │ │ ├── Camera.h │ │ ├── Font.cpp │ │ ├── Font.h │ │ ├── IDrawable.cpp │ │ ├── IDrawable.h │ │ ├── IRectDrawable.cpp │ │ ├── IRectDrawable.h │ │ ├── Linux/ │ │ │ ├── MaterialBase.h │ │ │ ├── MaterialImpl.cpp │ │ │ ├── OpenGL.cpp │ │ │ ├── OpenGL.h │ │ │ ├── RenderBase.h │ │ │ ├── RenderImpl.cpp │ │ │ ├── ShaderBase.h │ │ │ ├── ShaderImpl.cpp │ │ │ ├── TextureBase.h │ │ │ └── TextureImpl.cpp │ │ ├── Mac/ │ │ │ ├── CMakeLists.txt │ │ │ ├── MaterialBase.h │ │ │ ├── MaterialImpl.mm │ │ │ ├── MetalWrappers.h │ │ │ ├── RenderBase.h │ │ │ ├── RenderImpl.mm │ │ │ ├── ShaderBase.h │ │ │ ├── ShaderImpl.mm │ │ │ ├── ShaderTypes.h │ │ │ ├── Shaders.metal │ │ │ ├── TextureBase.h │ │ │ └── TextureImpl.mm │ │ ├── Material.cpp │ │ ├── Material.h │ │ ├── Mesh.cpp │ │ ├── Mesh.h │ │ ├── Particles/ │ │ │ ├── Particle.h │ │ │ ├── ParticlesContainer.cpp │ │ │ ├── ParticlesContainer.h │ │ │ ├── ParticlesEffects.cpp │ │ │ ├── ParticlesEffects.h │ │ │ ├── ParticlesEmitter.cpp │ │ │ ├── ParticlesEmitter.h │ │ │ ├── ParticlesEmitterShapes.cpp │ │ │ └── ParticlesEmitterShapes.h │ │ ├── Render.cpp │ │ ├── Render.h │ │ ├── Shader.cpp │ │ ├── Shader.h │ │ ├── SkinningMesh.cpp │ │ ├── SkinningMesh.h │ │ ├── Spine/ │ │ │ ├── Spine.cpp │ │ │ ├── Spine.h │ │ │ ├── SpineManager.cpp │ │ │ └── SpineManager.h │ │ ├── Sprite.cpp │ │ ├── Sprite.h │ │ ├── Text.cpp │ │ ├── Text.h │ │ ├── Texture.cpp │ │ ├── Texture.h │ │ ├── TextureRef.cpp │ │ ├── TextureRef.h │ │ ├── TextureSource.cpp │ │ ├── TextureSource.h │ │ ├── VectorFont.cpp │ │ ├── VectorFont.h │ │ ├── VectorFontEffects.cpp │ │ ├── VectorFontEffects.h │ │ ├── WebAssembly/ │ │ │ ├── MaterialBase.h │ │ │ ├── MaterialImpl.cpp │ │ │ ├── OpenGL.cpp │ │ │ ├── OpenGL.h │ │ │ ├── RenderBase.h │ │ │ ├── RenderImpl.cpp │ │ │ ├── ShaderBase.h │ │ │ ├── ShaderImpl.cpp │ │ │ ├── TextureBase.h │ │ │ └── TextureImpl.cpp │ │ ├── Windows/ │ │ │ ├── MaterialBase.h │ │ │ ├── MaterialImpl.cpp │ │ │ ├── OpenGL.cpp │ │ │ ├── OpenGL.h │ │ │ ├── RenderBase.h │ │ │ ├── RenderImpl.cpp │ │ │ ├── ShaderBase.h │ │ │ ├── ShaderImpl.cpp │ │ │ ├── TextureBase.h │ │ │ └── TextureImpl.cpp │ │ └── iOS/ │ │ ├── CMakeLists.txt │ │ ├── MaterialBase.h │ │ ├── MaterialImpl.mm │ │ ├── MetalWrappers.h │ │ ├── RenderBase.h │ │ ├── RenderImpl.mm │ │ ├── ShaderBase.h │ │ ├── ShaderImpl.mm │ │ ├── ShaderTypes.h │ │ ├── Shaders.metal │ │ ├── TextureBase.h │ │ └── TextureImpl.mm │ ├── Scene/ │ │ ├── Actor.cpp │ │ ├── Actor.h │ │ ├── ActorCreationMode.cpp │ │ ├── ActorCreationMode.h │ │ ├── ActorEditor.cpp │ │ ├── ActorLinkRef.cpp │ │ ├── ActorLinkRef.h │ │ ├── ActorRefResolver.cpp │ │ ├── ActorRefResolver.h │ │ ├── ActorTransform.cpp │ │ ├── ActorTransform.h │ │ ├── CameraActor.cpp │ │ ├── CameraActor.h │ │ ├── Component.cpp │ │ ├── Component.h │ │ ├── ComponentLinkRef.cpp │ │ ├── ComponentLinkRef.h │ │ ├── Components/ │ │ │ ├── AnimationComponent.cpp │ │ │ ├── AnimationComponent.h │ │ │ ├── AnimationStateGraphComponent.cpp │ │ │ ├── AnimationStateGraphComponent.h │ │ │ ├── EditorTestComponent.cpp │ │ │ ├── EditorTestComponent.h │ │ │ ├── ImageComponent.cpp │ │ │ ├── ImageComponent.h │ │ │ ├── MeshComponent.cpp │ │ │ ├── MeshComponent.h │ │ │ ├── ParticlesEmitterComponent.cpp │ │ │ ├── ParticlesEmitterComponent.h │ │ │ ├── ScissorClippingComponent.cpp │ │ │ ├── ScissorClippingComponent.h │ │ │ ├── ScriptableComponent.cpp │ │ │ ├── ScriptableComponent.h │ │ │ ├── SkinningMeshBoneComponent.cpp │ │ │ ├── SkinningMeshBoneComponent.h │ │ │ ├── SkinningMeshComponent.cpp │ │ │ ├── SkinningMeshComponent.h │ │ │ ├── SpineComponent.cpp │ │ │ ├── SpineComponent.h │ │ │ ├── TextSplitterComponent.cpp │ │ │ ├── TextSplitterComponent.h │ │ │ ├── TextSymbolComponent.cpp │ │ │ └── TextSymbolComponent.h │ │ ├── ISceneDrawable.cpp │ │ ├── ISceneDrawable.h │ │ ├── Physics/ │ │ │ ├── BoxCollider.cpp │ │ │ ├── BoxCollider.h │ │ │ ├── CircleCollider.cpp │ │ │ ├── CircleCollider.h │ │ │ ├── ICollider.cpp │ │ │ ├── ICollider.h │ │ │ ├── RigidBody.cpp │ │ │ ├── RigidBody.h │ │ │ ├── SplineCollider.cpp │ │ │ └── SplineCollider.h │ │ ├── Scene.cpp │ │ ├── Scene.h │ │ ├── SceneLayer.cpp │ │ ├── SceneLayer.h │ │ ├── SceneLayerRef.cpp │ │ ├── SceneLayerRef.h │ │ ├── SceneLayersList.cpp │ │ ├── SceneLayersList.h │ │ ├── Tags.cpp │ │ ├── Tags.h │ │ └── UI/ │ │ ├── UIManager.cpp │ │ ├── UIManager.h │ │ ├── Widget.cpp │ │ ├── Widget.h │ │ ├── WidgetLayer.cpp │ │ ├── WidgetLayer.h │ │ ├── WidgetLayerLayout.cpp │ │ ├── WidgetLayerLayout.h │ │ ├── WidgetLayout.cpp │ │ ├── WidgetLayout.h │ │ ├── WidgetState.cpp │ │ ├── WidgetState.h │ │ └── Widgets/ │ │ ├── Button.cpp │ │ ├── Button.h │ │ ├── ContextMenu.cpp │ │ ├── ContextMenu.h │ │ ├── CustomDropDown.cpp │ │ ├── CustomDropDown.h │ │ ├── CustomList.cpp │ │ ├── CustomList.h │ │ ├── DropDown.cpp │ │ ├── DropDown.h │ │ ├── EditBox.cpp │ │ ├── EditBox.h │ │ ├── EditBoxDropDown.cpp │ │ ├── EditBoxDropDown.h │ │ ├── GridLayout.cpp │ │ ├── GridLayout.h │ │ ├── GridLayoutScrollArea.cpp │ │ ├── GridLayoutScrollArea.h │ │ ├── HorizontalLayout.cpp │ │ ├── HorizontalLayout.h │ │ ├── HorizontalProgress.cpp │ │ ├── HorizontalProgress.h │ │ ├── HorizontalScrollBar.cpp │ │ ├── HorizontalScrollBar.h │ │ ├── Image.cpp │ │ ├── Image.h │ │ ├── Label.cpp │ │ ├── Label.h │ │ ├── List.cpp │ │ ├── List.h │ │ ├── LongList.cpp │ │ ├── LongList.h │ │ ├── MenuPanel.cpp │ │ ├── MenuPanel.h │ │ ├── PopupWidget.cpp │ │ ├── PopupWidget.h │ │ ├── ScrollArea.cpp │ │ ├── ScrollArea.h │ │ ├── Spoiler.cpp │ │ ├── Spoiler.h │ │ ├── Toggle.cpp │ │ ├── Toggle.h │ │ ├── Tree.cpp │ │ ├── Tree.h │ │ ├── VerticalLayout.cpp │ │ ├── VerticalLayout.h │ │ ├── VerticalProgress.cpp │ │ ├── VerticalProgress.h │ │ ├── VerticalScrollBar.cpp │ │ ├── VerticalScrollBar.h │ │ ├── Window.cpp │ │ └── Window.h │ ├── Scripts/ │ │ ├── JerryScript/ │ │ │ ├── ScriptEngineBase.h │ │ │ ├── ScriptEngineImpl.cpp │ │ │ ├── ScriptValueBase.h │ │ │ ├── ScriptValueContainerAllocator.cpp │ │ │ ├── ScriptValueContainerAllocator.h │ │ │ ├── ScriptValueConverters.h │ │ │ ├── ScriptValueImpl.cpp │ │ │ └── ScriptValueImpl.h │ │ ├── ScriptEngine.cpp │ │ ├── ScriptEngine.h │ │ ├── ScriptValue.cpp │ │ ├── ScriptValue.h │ │ ├── ScriptValueDef.cpp │ │ └── ScriptValueDef.h │ ├── Utils/ │ │ ├── Basic/ │ │ │ ├── ICloneable.h │ │ │ ├── IDynamic.h │ │ │ ├── IObject.h │ │ │ └── ITree.h │ │ ├── Bitmap/ │ │ │ ├── Bitmap.cpp │ │ │ ├── Bitmap.h │ │ │ ├── PngFormat.cpp │ │ │ └── PngFormat.h │ │ ├── Debug/ │ │ │ ├── Assert.cpp │ │ │ ├── Assert.h │ │ │ ├── Debug.cpp │ │ │ ├── Debug.h │ │ │ ├── Log/ │ │ │ │ ├── ConsoleLogStream.cpp │ │ │ │ ├── ConsoleLogStream.h │ │ │ │ ├── FileLogStream.cpp │ │ │ │ ├── FileLogStream.h │ │ │ │ ├── LogStream.cpp │ │ │ │ └── LogStream.h │ │ │ ├── Profiling/ │ │ │ │ ├── SimpleProfiler.cpp │ │ │ │ └── SimpleProfiler.h │ │ │ ├── StackTrace.cpp │ │ │ └── StackTrace.h │ │ ├── Editor/ │ │ │ ├── ActorDifferences.cpp │ │ │ ├── ActorDifferences.h │ │ │ ├── AssetEditablePreview.h │ │ │ ├── Attributes/ │ │ │ │ ├── AnimatableAttribute.h │ │ │ │ ├── DefaultTypeAttribute.h │ │ │ │ ├── DontDeleteAttribute.h │ │ │ │ ├── EditorPropertyAttribute.h │ │ │ │ ├── ExpandedByDefaultAttribute.h │ │ │ │ ├── GroupAttribute.h │ │ │ │ ├── InvokeOnChangeAttribute.h │ │ │ │ ├── ItemsSourceAttribute.h │ │ │ │ ├── NameAttribute.h │ │ │ │ ├── NoHeaderAttribute.h │ │ │ │ ├── PrototypeDeltaSearchAttribute.h │ │ │ │ ├── RangeAttribute.h │ │ │ │ └── ScriptableAttribute.h │ │ │ ├── DragAndDrop.cpp │ │ │ ├── DragAndDrop.h │ │ │ ├── DragHandle.cpp │ │ │ ├── DragHandle.h │ │ │ ├── EditorScope.cpp │ │ │ ├── EditorScope.h │ │ │ ├── FrameHandles.cpp │ │ │ ├── FrameHandles.h │ │ │ ├── SceneEditableObject.cpp │ │ │ └── SceneEditableObject.h │ │ ├── FileSystem/ │ │ │ ├── File.cpp │ │ │ ├── File.h │ │ │ ├── FileInfo.cpp │ │ │ ├── FileInfo.h │ │ │ ├── FileSystem.cpp │ │ │ └── FileSystem.h │ │ ├── Function/ │ │ │ ├── ActorSubscription.cpp │ │ │ ├── ActorSubscription.h │ │ │ ├── Function.h │ │ │ ├── FunctionDataValueConverter.h │ │ │ ├── ISerializableFunction.h │ │ │ ├── SerializableFunction.h │ │ │ └── Subscription.h │ │ ├── Math/ │ │ │ ├── ApproximationValue.h │ │ │ ├── Basis.h │ │ │ ├── Border.h │ │ │ ├── Color.cpp │ │ │ ├── Color.h │ │ │ ├── ColorGradient.cpp │ │ │ ├── ColorGradient.h │ │ │ ├── Curve.cpp │ │ │ ├── Curve.h │ │ │ ├── Geometry.cpp │ │ │ ├── Geometry.h │ │ │ ├── Interpolation.h │ │ │ ├── Intersection.cpp │ │ │ ├── Intersection.h │ │ │ ├── Layout.cpp │ │ │ ├── Layout.h │ │ │ ├── Math.cpp │ │ │ ├── Math.h │ │ │ ├── Rect.h │ │ │ ├── Spline.cpp │ │ │ ├── Spline.h │ │ │ ├── Transform.cpp │ │ │ ├── Transform.h │ │ │ ├── Vector2.h │ │ │ ├── Vertex.cpp │ │ │ └── Vertex.h │ │ ├── Memory/ │ │ │ ├── Allocators/ │ │ │ │ ├── ChunkPoolAllocator.cpp │ │ │ │ ├── ChunkPoolAllocator.h │ │ │ │ ├── DefaultAllocator.cpp │ │ │ │ ├── DefaultAllocator.h │ │ │ │ ├── IAllocator.h │ │ │ │ ├── LinearAllocator.cpp │ │ │ │ ├── LinearAllocator.h │ │ │ │ ├── StackAllocator.cpp │ │ │ │ └── StackAllocator.h │ │ │ ├── MemoryAnalyzeableObject.cpp │ │ │ ├── MemoryAnalyzeableObject.h │ │ │ ├── MemoryAnalyzer.cpp │ │ │ ├── MemoryAnalyzer.h │ │ │ ├── MemoryManager.cpp │ │ │ └── MemoryManager.h │ │ ├── Property.h │ │ ├── Reflection/ │ │ │ ├── Attributes.h │ │ │ ├── BaseTypeProcessor.h │ │ │ ├── Enum.h │ │ │ ├── FieldInfo.cpp │ │ │ ├── FieldInfo.h │ │ │ ├── FunctionInfo.cpp │ │ │ ├── FunctionInfo.h │ │ │ ├── Reflection.cpp │ │ │ ├── Reflection.h │ │ │ ├── Type.cpp │ │ │ ├── Type.h │ │ │ ├── TypeSerializer.h │ │ │ └── TypeTraits.h │ │ ├── Serialization/ │ │ │ ├── DataValue.cpp │ │ │ ├── DataValue.h │ │ │ ├── DataValueConverters.h │ │ │ ├── JsonDataFormat.cpp │ │ │ ├── JsonDataFormat.h │ │ │ ├── Serializable.cpp │ │ │ ├── Serializable.h │ │ │ ├── SerializeFieldProcessors.h │ │ │ ├── XmlDataFormat.cpp │ │ │ └── XmlDataFormat.h │ │ ├── Singleton.cpp │ │ ├── Singleton.h │ │ ├── StringUtils.cpp │ │ ├── StringUtils.h │ │ ├── System/ │ │ │ ├── Clipboard.cpp │ │ │ ├── Clipboard.h │ │ │ ├── CommandLineOptions.cpp │ │ │ ├── CommandLineOptions.h │ │ │ ├── ShortcutKeys.cpp │ │ │ ├── ShortcutKeys.h │ │ │ └── Time/ │ │ │ ├── Time.cpp │ │ │ ├── Time.h │ │ │ ├── TimeStamp.cpp │ │ │ ├── TimeStamp.h │ │ │ ├── Timer.cpp │ │ │ └── Timer.h │ │ ├── Tasks/ │ │ │ ├── Task.cpp │ │ │ ├── Task.h │ │ │ ├── TaskManager.cpp │ │ │ └── TaskManager.h │ │ ├── Tools/ │ │ │ ├── KeySearch.h │ │ │ ├── RectPacker.cpp │ │ │ └── RectPacker.h │ │ ├── Types/ │ │ │ ├── CommonTypes.cpp │ │ │ ├── CommonTypes.h │ │ │ ├── Containers/ │ │ │ │ ├── Map.h │ │ │ │ ├── Pair.h │ │ │ │ ├── Pool.h │ │ │ │ └── Vector.h │ │ │ ├── LinkRef.h │ │ │ ├── Ref.cpp │ │ │ ├── Ref.h │ │ │ ├── String.h │ │ │ ├── StringDef.h │ │ │ ├── StringImpl.h │ │ │ ├── UID.cpp │ │ │ ├── UID.h │ │ │ ├── Variant.h │ │ │ └── WeakRef.h │ │ ├── ValueProxy.cpp │ │ └── ValueProxy.h │ ├── o2Framework.cpp │ ├── replace_tabs.py │ ├── stdafx.cpp │ └── stdafx.h ├── LICENSE ├── README.md ├── ReplaceTabsToSpaces.py ├── ScriptUtils/ │ └── ReplaceTabsToSpaces.py ├── Tests/ │ ├── CMakeLists.txt │ └── Sources/ │ ├── TestsMain.cpp │ ├── o2Tests.cpp │ └── tests/ │ ├── ScriptValueTest.cpp │ ├── TestScriptObject.cpp │ ├── TestScriptObject.h │ └── Vec2FTest.cpp ├── Tools/ │ ├── rasterize_svg_to_png.py │ └── requirements_rasterize.txt ├── UI/ │ ├── Photoshop/ │ │ ├── CurveHandle.psd │ │ └── CurveSupportHandle.psd │ └── UI4.ai ├── settings.vssettings └── settings2.vssettings ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ # Auto detect text files and perform LF normalization * text=auto # Custom for Visual Studio *.cs diff=csharp *.sln merge=union *.csproj merge=union *.vbproj merge=union *.fsproj merge=union *.dbproj merge=union # Standard to msysgit *.doc diff=astextplain *.DOC diff=astextplain *.docx diff=astextplain *.DOCX diff=astextplain *.dot diff=astextplain *.DOT diff=astextplain *.pdf diff=astextplain *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain ================================================ FILE: .gitignore ================================================ /Framework/Platforms/Windows/Framework.vcxproj.user /CodeTool/.vs /Editor/Platforms/Windows/Editor.vcxproj.user /Framework/Platforms/Windows/3rdPartyLibs.vcxproj.user /CodeTool/x64 /CodeTool/build /CodeTool/Bin/*.pdb /CodeTool/Bin/*.iobj /CodeTool/Bin/*.ipdb /CodeTool/CodeTool.vcxproj.user /Framework/Sources/o2/CodeToolCache.xml /Editor/Sources/CodeToolCache.xml *.DS_Store Editor/Platforms/Mac/build Framework/Platforms/Mac/build Editor/Platforms/Mac/build Framework/Platforms/Mac/3rdPartyLibs.xcodeproj/xcuserdata Framework/Platforms/Mac/build Editor/Sources/o2Editor/CodeToolCache.xml CodeTool/Bin/o2CodeTool.exe AssetsBuildTool/Sources/CodeToolCache.xml Editor/Assets/Editor UI styles/rebuildDate.json CodeTool/Bin Framework/Platforms/__pycache__ Editor/Assets/Editor UI styles .cache build Tests/Sources/CodeToolCache.xml ================================================ FILE: .gitmodules ================================================ [submodule "Framework/3rdPartyLibs/tracy"] path = Framework/3rdPartyLibs/tracy url = https://github.com/wolfpld/tracy [submodule "Framework/3rdPartyLibs/boost/stacktrace"] path = Framework/3rdPartyLibs/boost/stacktrace url = https://github.com/boostorg/stacktrace.git [submodule "Framework/3rdPartyLibs/boost/config"] path = Framework/3rdPartyLibs/boost/config url = https://github.com/boostorg/config.git [submodule "Framework/3rdPartyLibs/boost/container_hash"] path = Framework/3rdPartyLibs/boost/container_hash url = https://github.com/boostorg/container_hash.git [submodule "Framework/3rdPartyLibs/boost/core"] path = Framework/3rdPartyLibs/boost/core url = https://github.com/boostorg/core.git [submodule "Framework/3rdPartyLibs/boost/predef"] path = Framework/3rdPartyLibs/boost/predef url = https://github.com/boostorg/predef.git [submodule "Framework/3rdPartyLibs/boost/winapi"] path = Framework/3rdPartyLibs/boost/winapi url = https://github.com/boostorg/winapi.git [submodule "Framework/3rdPartyLibs/boost/describe"] path = Framework/3rdPartyLibs/boost/describe url = https://github.com/boostorg/describe.git [submodule "Framework/3rdPartyLibs/boost/mp11"] path = Framework/3rdPartyLibs/boost/mp11 url = https://github.com/boostorg/mp11.git [submodule "Framework/3rdPartyLibs/boost/assert"] path = Framework/3rdPartyLibs/boost/assert url = https://github.com/boostorg/assert.git [submodule "Framework/3rdPartyLibs/boost/static_assert"] path = Framework/3rdPartyLibs/boost/static_assert url = https://github.com/boostorg/static_assert.git [submodule "Framework/3rdPartyLibs/boost/throw_exception"] path = Framework/3rdPartyLibs/boost/throw_exception url = https://github.com/boostorg/throw_exception.git ================================================ FILE: AssetsBuildTool/CMakeLists.txt ================================================ add_library(o2AssetsBuilder STATIC) add_compile_definitions(${O2_COMPILE_DEFINITIONS_EXPORT}) file(GLOB_RECURSE o2AssetsBuilder_SOURCES "Sources/*.cpp" "Sources/*.h" ) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${o2AssetsBuilder_SOURCES}) target_include_directories(o2AssetsBuilder PUBLIC "Sources") target_sources(o2AssetsBuilder PRIVATE ${o2AssetsBuilder_SOURCES}) target_link_libraries(o2AssetsBuilder PUBLIC o2Framework ) if(WIN32) add_custom_command(TARGET o2AssetsBuilder PRE_BUILD COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../CodeTool/Bin/o2CodeTool -project AssetsBuildTool -sources "${CMAKE_CURRENT_SOURCE_DIR}/Sources" -parent_projects "${CMAKE_CURRENT_SOURCE_DIR}/../Framework/Sources/o2/CodeToolCache.xml" COMMENT "Run CodeTool:" "-project AssetsBuildTool " "-sources \"${CMAKE_CURRENT_SOURCE_DIR}/Sources\" " "-parent_projects \"${CMAKE_CURRENT_SOURCE_DIR}/../Framework/Sources/o2/CodeToolCache.xml\"") endif() add_dependencies(o2AssetsBuilder o2Framework) if(MSVC) target_compile_options(o2AssetsBuilder PUBLIC ${O2_MSVC_MP_FLAG} "/Zc:__cplusplus") elseif (UNIX) target_compile_options(o2AssetsBuilder PUBLIC ${DEMO_WARNING_OPTION} -Wno-pedantic) endif() ================================================ FILE: AssetsBuildTool/Sources/AssetsBuildTool.cpp ================================================ extern void __RegisterClass__o2__AtlasAssetConverter(); extern void __RegisterClass__o2__AtlasAssetConverter__Image(); extern void __RegisterClass__o2__FolderAssetConverter(); extern void __RegisterClass__o2__IAssetConverter(); extern void __RegisterClass__o2__ImageAssetConverter(); extern void __RegisterClass__o2__StdAssetConverter(); extern void __RegisterClass__o2__ImageCompressor__Config(); extern void InitializeTypesAssetsBuildTool() { __RegisterClass__o2__AtlasAssetConverter(); __RegisterClass__o2__AtlasAssetConverter__Image(); __RegisterClass__o2__FolderAssetConverter(); __RegisterClass__o2__IAssetConverter(); __RegisterClass__o2__ImageAssetConverter(); __RegisterClass__o2__StdAssetConverter(); __RegisterClass__o2__ImageCompressor__Config(); } ================================================ FILE: AssetsBuildTool/Sources/o2AssetBuilder/AssetsBuilder.cpp ================================================ #include "o2/stdafx.h" #include "AssetsBuilder.h" #include "o2/Assets/Assets.h" #include "o2/Assets/Types/AtlasAsset.h" #include "o2/Assets/Types/DataAsset.h" #include "o2/Assets/Types/FolderAsset.h" #include "o2/Assets/Types/SceneAsset.h" #include "o2/Utils/Debug/Debug.h" #include "o2/Utils/Debug/Log/LogStream.h" #include "o2/Utils/FileSystem/FileSystem.h" #include "o2/Utils/System/Time/Timer.h" #include "o2AssetBuilder/ImageCompressor.h" namespace o2 { AssetsBuilder::AssetsBuilder() { srand((UInt)time(NULL)); mLog = mmake("Assets builder"); o2Debug.GetLog()->BindStream(mLog); InitializeConverters(); } AssetsBuilder::~AssetsBuilder() { } const Vector& AssetsBuilder::BuildAssets(Platform platform, const String& assetsPath, const String& builtAssetsPath, const String& dataAssetsTreePath, const String& compressorConfig, bool forcible /*= false*/) { mPlatform = platform; mSourceAssetsPath = assetsPath; mBuiltAssetsPath = builtAssetsPath; mBuiltAssetsTreePath = dataAssetsTreePath; ImageCompressor::LoadConfig(compressorConfig); mLog->Out("Started assets building from: " + mSourceAssetsPath + " to: " + mBuiltAssetsPath); Timer timer; if (forcible) RemoveBuiltAssets(); FolderInfo folderInfo = o2FileSystem.GetFolderInfo(mSourceAssetsPath); folderInfo.ClampPathNames(); ProcessMissingMetasCreation(folderInfo); mSourceAssetsTree = mmake(); mSourceAssetsTree->assetsPath = assetsPath; mSourceAssetsTree->log = mLog; mSourceAssetsTree->Build(folderInfo); DataDocument builtAssetsTreeDoc; builtAssetsTreeDoc.LoadFromFile(mBuiltAssetsTreePath); mBuiltAssetsTree = mmake(); mBuiltAssetsTree->Deserialize(builtAssetsTreeDoc); mBuiltAssetsTree->log = mLog; ProcessRemovedAssets(); ProcessNewAssets(); ProcessModifiedAssets(); ConvertersPostProcess(); if (!mModifiedAssets.IsEmpty()) { mBuiltAssetsTree->assetsPath = mSourceAssetsPath; mBuiltAssetsTree->builtAssetsPath = mBuiltAssetsPath; o2FileSystem.WriteFile(mBuiltAssetsTreePath, mBuiltAssetsTree->SerializeToString()); } mLog->Out("Assets builder: Completed. Source: " + mSourceAssetsPath + ", Target: " + mBuiltAssetsPath + ", Time: " + (String)timer.GetDeltaTime() + " seconds"); return mModifiedAssets; } const String& AssetsBuilder::GetSourceAssetsPath() const { return mSourceAssetsPath; } const String& AssetsBuilder::GetBuiltAssetsPath() const { return mBuiltAssetsPath; } Platform AssetsBuilder::GetPlatform() const { return mPlatform; } void AssetsBuilder::InitializeConverters() { auto converterTypes = TypeOf(IAssetConverter).GetDerivedTypes(); for (auto converterType : converterTypes) { IAssetConverter* converter = (IAssetConverter*)converterType->CreateSample(); converter->SetAssetsBuilder(this); auto availableAssetTypes = converter->GetProcessingAssetsTypes(); for (auto tp : availableAssetTypes) mAssetConverters.Add(tp, converter); } mStdAssetConverter.SetAssetsBuilder(this); } void AssetsBuilder::RemoveBuiltAssets() { o2FileSystem.FileDelete(mBuiltAssetsTreePath); o2FileSystem.FolderRemove(mBuiltAssetsPath); o2FileSystem.FolderCreate(mBuiltAssetsPath); } void AssetsBuilder::ProcessMissingMetasCreation(FolderInfo& folder) { for (auto fileInfo : folder.files) { if (fileInfo.path.EndsWith(".meta")) { String metaFullPath = mSourceAssetsPath + fileInfo.path; String assetForMeta = o2FileSystem.GetFileNameWithoutExtension(metaFullPath); bool isExistAssetForMeta = o2FileSystem.IsFileExist(assetForMeta) || o2FileSystem.IsFolderExist(assetForMeta); if (!isExistAssetForMeta) { mLog->Warning("Missing asset for meta: " + fileInfo.path + " - removing meta"); o2FileSystem.FileDelete(metaFullPath); } } else { String assetFullPath = mSourceAssetsPath + fileInfo.path; String metaFullPath = assetFullPath + ".meta"; bool isExistMetaForAsset = o2FileSystem.IsFileExist(metaFullPath); if (!isExistMetaForAsset) { auto assetType = Assets::GetAssetTypeByExtension(o2FileSystem.GetFileExtension(fileInfo.path)); GenerateMeta(*assetType, metaFullPath); } } } for (auto subFolder : folder.folders) { String subFolderPath = subFolder.path; subFolderPath.Erase(subFolderPath.Length() - 1); String folderFullPath = mSourceAssetsPath + subFolderPath; String metaFullPath = folderFullPath + ".meta"; bool isExistMetaForFolder = o2FileSystem.IsFileExist(metaFullPath); if (!isExistMetaForFolder) { auto& assetType = TypeOf(FolderAsset); GenerateMeta(assetType, metaFullPath); } ProcessMissingMetasCreation(subFolder); } } void AssetsBuilder::ProcessRemovedAssets() { const Type* folderTypeId = &TypeOf(FolderAsset); mBuiltAssetsTree->SortAssetsInverse(); // in first pass processing files, in second - folders for (int pass = 0; pass < 2; pass++) { for (auto builtAssetInfoIt = mBuiltAssetsTree->allAssets.Begin(); builtAssetInfoIt != mBuiltAssetsTree->allAssets.End(); ) { auto builtAssetInfo = (*builtAssetInfoIt).Lock(); bool isFolder = builtAssetInfo->meta->GetAssetType() == folderTypeId; bool skip = pass == 0 ? isFolder : !isFolder; if (skip) { ++builtAssetInfoIt; continue; } auto fnd = mSourceAssetsTree->allAssetsByUID.find(builtAssetInfo->meta->ID()); bool needRemove = fnd == mSourceAssetsTree->allAssetsByUID.end(); if (!needRemove) { ++builtAssetInfoIt; continue; } GetAssetConverter(builtAssetInfo->meta->GetAssetType())->RemoveAsset(*builtAssetInfo); mModifiedAssets.Add(builtAssetInfo->meta->ID()); mLog->OutStr("Removed asset: " + builtAssetInfo->path); mBuiltAssetsTree->allAssetsByUID.Remove(builtAssetInfo->meta->ID()); mBuiltAssetsTree->allAssetsByPath.Remove(builtAssetInfo->path); builtAssetInfoIt = mBuiltAssetsTree->allAssets.Remove(builtAssetInfoIt); if (builtAssetInfo->parent) builtAssetInfo->parent.Lock()->RemoveChild(builtAssetInfo); else mBuiltAssetsTree->rootAssets.Remove(builtAssetInfo); } } } void AssetsBuilder::ProcessModifiedAssets() { const Type* folderType = &TypeOf(FolderAsset); mSourceAssetsTree->SortAssets(); // in first pass processing folders, in second - files for (int pass = 0; pass < 2; pass++) { for (auto sourceAssetInfoWeak : mSourceAssetsTree->allAssets) { auto sourceAssetInfo = sourceAssetInfoWeak.Lock(); if (!sourceAssetInfo->meta) continue; bool isFolder = sourceAssetInfo->meta->GetAssetType() == folderType; bool skip = pass == 0 ? !isFolder : isFolder; if (skip) continue; WeakRef builtAssetInfoWeak; if (mBuiltAssetsTree->allAssetsByUID.TryGetValue(sourceAssetInfo->meta->ID(), builtAssetInfoWeak)) { auto builtAssetInfo = builtAssetInfoWeak.Lock(); if (sourceAssetInfo->path == builtAssetInfo->path) { if (sourceAssetInfo->editTime != builtAssetInfo->editTime || !sourceAssetInfo->meta->IsEqual(builtAssetInfo->meta.Get())) { GetAssetConverter(sourceAssetInfo->meta->GetAssetType())->ConvertAsset(*sourceAssetInfo); mModifiedAssets.Add(sourceAssetInfo->meta->ID()); builtAssetInfo->editTime = sourceAssetInfo->editTime; builtAssetInfo->meta = sourceAssetInfo->meta->CloneAsRef(); mLog->Out("Modified asset: " + sourceAssetInfo->path); } } else { if (sourceAssetInfo->editTime != builtAssetInfo->editTime || !sourceAssetInfo->meta->IsEqual(builtAssetInfo->meta.Get())) { GetAssetConverter(builtAssetInfo->meta->GetAssetType())->RemoveAsset(*builtAssetInfo); mBuiltAssetsTree->RemoveAsset(builtAssetInfo); mLog->Out("Modified and moved to " + sourceAssetInfo->path + " asset: " + builtAssetInfo->path); builtAssetInfo->path = sourceAssetInfo->path; builtAssetInfo->editTime = sourceAssetInfo->editTime; builtAssetInfo->meta = sourceAssetInfo->meta->CloneAsRef(); GetAssetConverter(sourceAssetInfo->meta->GetAssetType())->ConvertAsset(*sourceAssetInfo); mModifiedAssets.Add(sourceAssetInfo->meta->ID()); mBuiltAssetsTree->AddAsset(builtAssetInfo); } else { GetAssetConverter(sourceAssetInfo->meta->GetAssetType())->MoveAsset(*builtAssetInfo, *sourceAssetInfo); mLog->Out("Moved asset from " + builtAssetInfo->path + " to " + sourceAssetInfo->path); mBuiltAssetsTree->RemoveAsset(builtAssetInfo); builtAssetInfo->path = sourceAssetInfo->path; builtAssetInfo->editTime = sourceAssetInfo->editTime; builtAssetInfo->meta = sourceAssetInfo->meta->CloneAsRef(); mModifiedAssets.Add(sourceAssetInfo->meta->ID()); mBuiltAssetsTree->AddAsset(builtAssetInfo); } } } } } } void AssetsBuilder::ProcessNewAssets() { const Type* folderType = &TypeOf(FolderAsset); mSourceAssetsTree->SortAssets(); // in first pass processing folders, in second - files for (int pass = 0; pass < 2; pass++) { for (auto sourceAssetInfoIt = mSourceAssetsTree->allAssets.Begin(); sourceAssetInfoIt != mSourceAssetsTree->allAssets.End(); ++sourceAssetInfoIt) { auto sourceAssetInfo = (*sourceAssetInfoIt).Lock(); if (!sourceAssetInfo->meta) continue; bool isFolder = sourceAssetInfo->meta->GetAssetType() == folderType; bool skip = pass == 0 ? !isFolder : isFolder; if (skip) continue; auto fnd = mBuiltAssetsTree->allAssetsByUID.find(sourceAssetInfo->meta->ID()); bool isNew = fnd == mBuiltAssetsTree->allAssetsByUID.end(); if (!isNew) continue; GetAssetConverter(sourceAssetInfo->meta->GetAssetType())->ConvertAsset(*sourceAssetInfo); mModifiedAssets.Add(sourceAssetInfo->meta->ID()); mLog->Out("New asset: " + sourceAssetInfo->path); Ref newBuiltAsset = mmake(); newBuiltAsset->path = sourceAssetInfo->path; newBuiltAsset->editTime = sourceAssetInfo->editTime; newBuiltAsset->meta = sourceAssetInfo->meta->CloneAsRef(); mBuiltAssetsTree->AddAsset(newBuiltAsset); } } } void AssetsBuilder::ConvertersPostProcess() { for (auto it = mAssetConverters.Begin(); it != mAssetConverters.End(); ++it) mModifiedAssets.Add(it->second->AssetsPostProcess()); mModifiedAssets.Add(mStdAssetConverter.AssetsPostProcess()); } void AssetsBuilder::GenerateMeta(const Type& assetType, const String& metaFullPath) { auto assetTypeSample = (Asset*)assetType.CreateSample(); auto assetTypeSampleMeta = assetTypeSample->GetMeta(); DataDocument metaData; metaData = assetTypeSampleMeta; metaData["Value"]["mId"] = UID(); metaData.SaveToFile(metaFullPath); delete assetTypeSample; } IAssetConverter* AssetsBuilder::GetAssetConverter(const Type* assetType) { if (mAssetConverters.ContainsKey(assetType)) return mAssetConverters[assetType]; return &mStdAssetConverter; } } ================================================ FILE: AssetsBuildTool/Sources/o2AssetBuilder/AssetsBuilder.h ================================================ #pragma once #include "o2/Assets/Asset.h" #include "o2/Assets/AssetInfo.h" #include "o2/Assets/AssetsTree.h" #include "o2/Utils/Types/String.h" #include "o2AssetBuilder/Converters/StdAssetConverter.h" namespace o2 { class FolderInfo; class IAssetConverter; // ------------- // Asset builder // ------------- class AssetsBuilder { public: // Default constructor AssetsBuilder(); // Destructor ~AssetsBuilder(); // Builds asset from assets path to dataAssetsPath. Removes all built assets if forcible is true const Vector& BuildAssets(Platform platform, const String& assetsPath, const String& dataAssetsPath, const String& dataAssetsTreePath, const String& compressorConfig, bool forcible = false); // Returns source assets path in building const String& GetSourceAssetsPath() const; // Returns built assets path in building const String& GetBuiltAssetsPath() const; // Returns current platform Platform GetPlatform() const; protected: Ref mLog; // Asset builder log stream Platform mPlatform; // Current platform String mSourceAssetsPath; // Source assets path Ref mSourceAssetsTree; // Source assets tree String mBuiltAssetsPath; // Built assets path String mBuiltAssetsTreePath; // Built assets tree data path Ref mBuiltAssetsTree; // Built assets tree Vector mModifiedAssets; // Modified assets infos Map mAssetConverters; // Assets converters by type StdAssetConverter mStdAssetConverter; // Standard assets converter protected: // Initializes converters void InitializeConverters(); // Removes all built assets void RemoveBuiltAssets(); // Searching and removing assets void ProcessRemovedAssets(); // Searching modified and moved assets void ProcessModifiedAssets(); // Searches new assets void ProcessNewAssets(); // Launches converters post process void ConvertersPostProcess(); // Processes folder for missing metas void ProcessMissingMetasCreation(FolderInfo& folder); // Generates meta information file for asset void GenerateMeta(const Type& assetType, const String& metaFullPath); // Returns assets converter by asset type IAssetConverter* GetAssetConverter(const Type* assetType); friend class AtlasAssetConverter; }; } ================================================ FILE: AssetsBuildTool/Sources/o2AssetBuilder/AssetsBuilderRunner.cpp ================================================ #include "o2/O2.h" #include "o2AssetBuilder/AssetsBuilder.h" #include "o2/Utils/System/CommandLineOptions.h" using namespace o2; extern void InitializeTypesGameLib(); extern void InitializeTypesAssetsBuildTool(); int main(int argc, char* argv[]) { INITIALIZE_O2; InitializeTypesGameLib(); InitializeTypesAssetsBuildTool(); const auto platformKey = "-platform"; const auto sourceDirKey = "-source"; const auto targetDirKey = "-target"; const auto targetAssetsTreeKey = "-target-tree"; const auto compressorConfigPathKey = "-compressor-config"; const auto forcibleKey = "-forcible"; Map options = CommandLineOptions::Parse(argc, argv); Platform platform = Platform::Windows; if (options.ContainsKey(platformKey)) platform = Reflection::Instance().GetEnumValue(options[platformKey]); else { std::cout << "Platform must be specified via " << platformKey << std::endl; return -1; } String sourceDir; if (options.ContainsKey(sourceDirKey)) sourceDir = options[sourceDirKey]; else { std::cout << "Source assets directory must be specified via " << sourceDirKey << std::endl; return -1; } String targetDir; if (options.ContainsKey(targetDirKey)) targetDir = options[targetDirKey]; else { std::cout << "Target built assets directory must be specified via " << targetDirKey << std::endl; return -1; } String targetTreeDir; if (options.ContainsKey(targetAssetsTreeKey)) targetTreeDir = options[targetAssetsTreeKey]; else { std::cout << "Target built assets tree path must be specified via " << targetAssetsTreeKey << std::endl; return -1; } String compressorConfigPath; if (options.ContainsKey(compressorConfigPathKey)) compressorConfigPath = options[compressorConfigPathKey]; else { std::cout << "Images compressor config path must be specified via " << compressorConfigPathKey << std::endl; return -1; } bool forcible = false; if (options.ContainsKey(forcibleKey)) forcible = (bool)options[forcibleKey]; AssetsBuilder builder; builder.BuildAssets(platform, sourceDir, targetDir, targetTreeDir, compressorConfigPath, forcible); return 0; } ================================================ FILE: AssetsBuildTool/Sources/o2AssetBuilder/Converters/AtlasAssetConverter.cpp ================================================ #include "o2/stdafx.h" #include "AtlasAssetConverter.h" #include "o2/Assets/Types/AtlasAsset.h" #include "o2/Assets/Types/ImageAsset.h" #include "o2/Assets/Assets.h" #include "o2/Utils/Bitmap/Bitmap.h" #include "o2/Utils/Debug/Log/LogStream.h" #include "o2/Utils/FileSystem/FileSystem.h" #include "o2AssetBuilder/ImageCompressor.h" namespace o2 { Vector AtlasAssetConverter::GetProcessingAssetsTypes() const { Vector res; res.Add(&TypeOf(AtlasAsset)); return res; } void AtlasAssetConverter::ConvertAsset(const AssetInfo& node) { String sourceAssetPath = mAssetsBuilder->GetSourceAssetsPath() + node.path; String buildedAssetPath = mAssetsBuilder->GetBuiltAssetsPath() + node.path; if (!o2FileSystem.IsFileExist(buildedAssetPath)) o2FileSystem.WriteFile(buildedAssetPath, ""); } void AtlasAssetConverter::RemoveAsset(const AssetInfo& node) { String buildedAssetPath = mAssetsBuilder->GetBuiltAssetsPath() + node.path; DataDocument atlasData; atlasData.LoadFromFile(buildedAssetPath); int pagesCount = atlasData["mPages"].GetMembersCount(); for (int i = 0; i < pagesCount; i++) o2FileSystem.FileDelete(buildedAssetPath + (String)i + ".png"); o2FileSystem.FileDelete(buildedAssetPath); } void AtlasAssetConverter::MoveAsset(const AssetInfo& nodeFrom, const AssetInfo& nodeTo) { String fullPathFrom = mAssetsBuilder->GetBuiltAssetsPath() + nodeFrom.path; String fullPathTo = mAssetsBuilder->GetBuiltAssetsPath() + nodeTo.path; DataDocument atlasData; atlasData.LoadFromFile(fullPathFrom); int pagesCount = atlasData["mPages"].GetMembersCount(); for (int i = 0; i < pagesCount; i++) o2FileSystem.FileMove(fullPathFrom + (String)i + ".png", fullPathTo + (String)i + ".png"); o2FileSystem.FileMove(fullPathFrom, fullPathTo); } Vector AtlasAssetConverter::AssetsPostProcess() { return CheckRebuildingAtlases(); } void AtlasAssetConverter::Reset() {} Vector AtlasAssetConverter::CheckRebuildingAtlases() { Vector res; const Type* atlasAssetType = &TypeOf(AtlasAsset); for (auto& info : mAssetsBuilder->mBuiltAssetsTree->allAssets) { auto infoStrong = info.Lock(); if (infoStrong->meta->GetAssetType() == atlasAssetType) { if (CheckAtlasRebuilding(infoStrong)) res.Add(infoStrong->meta->ID()); } } return res; } bool AtlasAssetConverter::CheckAtlasRebuilding(const Ref& atlasInfo) { DataDocument atlasData; atlasData.LoadFromFile(mAssetsBuilder->mBuiltAssetsPath + atlasInfo->path); Vector lastImages; lastImages = atlasData["mImages"]; Vector currentImages; const Type* imageType = &TypeOf(ImageAsset); const UID& atlasId = atlasInfo->meta->ID(); for (auto& assetInfo : mAssetsBuilder->mBuiltAssetsTree->allAssets) { auto assetInfoStrong = assetInfo.Lock(); if (assetInfoStrong->meta->GetAssetType() == imageType) { Ref imageMeta = DynamicCast(assetInfoStrong->meta); if (imageMeta->atlasId == atlasId) currentImages.Add(Image(imageMeta->ID(), assetInfoStrong->editTime)); } } bool isModified = mAssetsBuilder->mModifiedAssets.Contains(atlasInfo->meta->ID()); if (isModified || ImagesListChanged(currentImages, lastImages)) { RebuildAtlas(atlasInfo, currentImages); return true; } return false; } bool AtlasAssetConverter::ImagesListChanged(Vector& currentImages, Vector& lastImages) { if (currentImages.Count() != lastImages.Count()) return true; for (auto lastImg : lastImages) { bool found = false; for (auto curImg : currentImages) { if (lastImg.id == curImg.id) { if (lastImg.time != curImg.time) { return true; } else { found = true; break; } } } if (!found) return true; } for (auto curImg : currentImages) { if (mAssetsBuilder->mModifiedAssets.Contains(curImg.id)) return true; } return false; } void AtlasAssetConverter::RebuildAtlas(const Ref& atlasInfo, Vector& images) { auto meta = DynamicCast(atlasInfo->meta)->GetResultPlatformMeta(mAssetsBuilder->GetPlatform()); RectsPacker packer(meta.maxSize); float imagesBorder = (float)meta.border; // Initialize pack images Vector packImages; for (auto img : images) { // Find image info WeakRef imgInfo; mAssetsBuilder->mBuiltAssetsTree->allAssetsByUID.TryGetValue(img.id, imgInfo); if (!imgInfo) { mAssetsBuilder->mLog->Error("Can't find asset info by id: " + (String)img.id); continue; } auto imgInfoStong = imgInfo.Lock(); String assetFullPath = mAssetsBuilder->GetSourceAssetsPath() + imgInfoStong->path; // Load bitmap auto bitmap = mmake(); if (!bitmap->Load(assetFullPath)) { mAssetsBuilder->mLog->Error("Can't load bitmap for image asset: " + imgInfoStong->path); continue; } // Create packing rect auto packRect = packer.AddRect(bitmap->GetSize() + Vec2F(imagesBorder*2.0f, imagesBorder*2.0f)); ImagePackDef imagePackDef; imagePackDef.assetInfo = imgInfoStong; imagePackDef.bitmap = bitmap; imagePackDef.packRect = packRect; packImages.Add(imagePackDef); } // Try to pack if (!packer.Pack()) { mAssetsBuilder->mLog->Warning("Atlas " + atlasInfo->path + " packing failed"); return; } else mAssetsBuilder->mLog->Out("Atlas " + atlasInfo->path + " successfully packed"); // Initialize bitmaps and pages int pagesCount = packer.GetPagesCount(); Vector> resAtlasBitmaps; Vector resAtlasPages; for (int i = 0; i < pagesCount; i++) { AtlasAsset::Page atlasPage; atlasPage.mId = i; atlasPage.mSize = packer.GetMaxSize(); resAtlasPages.Add(atlasPage); auto newBitmap = mmake(PixelFormat::R8G8B8A8, packer.GetMaxSize()); newBitmap->Fill(Color4(255, 255, 255, 0)); resAtlasBitmaps.Add(newBitmap); } // Save image assets data and fill pages for (auto imgDef : packImages) { imgDef.packRect->rect.left += imagesBorder; imgDef.packRect->rect.right -= imagesBorder; imgDef.packRect->rect.top -= imagesBorder; imgDef.packRect->rect.bottom += imagesBorder; resAtlasBitmaps[imgDef.packRect->page]->CopyImage(*imgDef.bitmap, imgDef.packRect->rect.LeftBottom()); resAtlasPages[imgDef.packRect->page].mImagesRects.Add(imgDef.assetInfo.Lock()->meta->ID(), imgDef.packRect->rect); SaveImageAsset(imgDef); } // Save pages bitmaps for (int i = 0; i < pagesCount; i++) { String builtPath = mAssetsBuilder->GetBuiltAssetsPath() + atlasInfo->path + (String)i; resAtlasBitmaps[i]->Save(builtPath + ".png", Bitmap::ImageType::Png); ImageCompressor::CompressImage(builtPath + ".png", builtPath, meta.format, 100); } // Save atlas data String atlasFullPath = mAssetsBuilder->GetSourceAssetsPath() + atlasInfo->path; String atlasFullBuiltPath = mAssetsBuilder->GetBuiltAssetsPath() + atlasInfo->path; DataDocument atlasData; atlasData.LoadFromFile(atlasFullPath); atlasData["mPages"] = resAtlasPages; atlasData["mImages"] = images; atlasData.SaveToFile(atlasFullPath); atlasData.SaveToFile(atlasFullBuiltPath); atlasInfo->editTime = o2FileSystem.GetFileInfo(atlasFullPath).editDate; } void AtlasAssetConverter::SaveImageAsset(ImagePackDef& imgDef) { DataDocument imgData; imgData["mAtlasPage"] = imgDef.packRect->page; imgData["mSourceRect"] = (RectI)(imgDef.packRect->rect); String imageFullPath = mAssetsBuilder->GetBuiltAssetsPath() + imgDef.assetInfo.Lock()->path; imgData.SaveToFile(imageFullPath); DataDocument metaData; metaData = imgDef.assetInfo.Lock()->meta; metaData.SaveToFile(mAssetsBuilder->GetSourceAssetsPath() + imgDef.assetInfo.Lock()->path + ".meta"); } AtlasAssetConverter::Image::Image(const UID& id, const TimeStamp& time): id(id), time(time) {} bool AtlasAssetConverter::Image::operator==(const Image& other) const { return id == other.id; } bool AtlasAssetConverter::ImagePackDef::operator==(const ImagePackDef& other) const { return assetInfo == other.assetInfo && bitmap == other.bitmap && packRect == other.packRect; } } // --- META --- DECLARE_CLASS(o2::AtlasAssetConverter, o2__AtlasAssetConverter); DECLARE_CLASS(o2::AtlasAssetConverter::Image, o2__AtlasAssetConverter__Image); // --- END META --- ================================================ FILE: AssetsBuildTool/Sources/o2AssetBuilder/Converters/AtlasAssetConverter.h ================================================ #pragma once #include "IAssetConverter.h" #include "o2/Utils/Tools/RectPacker.h" #include "o2AssetBuilder/AssetsBuilder.h" namespace o2 { class Bitmap; // ----------------- // Atlases converter // ----------------- class AtlasAssetConverter : public IAssetConverter { public: // Returns vector of processing assets types Vector GetProcessingAssetsTypes() const override; // Converts atlas by path void ConvertAsset(const AssetInfo& node) override; // Removes atlas by path void RemoveAsset(const AssetInfo& node) override; // Moves atlas void MoveAsset(const AssetInfo& nodeFrom, const AssetInfo& nodeTo) override; // Post processing atlases. Here checking atlases for rebuild Vector AssetsPostProcess() override; // Resets converter void Reset() override; IOBJECT(AtlasAssetConverter); public: // ---------------- // Atlas image info // ---------------- struct Image : public ISerializable { UID id; // Image asset id @SERIALIZABLE TimeStamp time; // Image asset edited date @SERIALIZABLE public: // Default constructor Image() {} // Constructor Image(const UID& id, const TimeStamp& time); // Check equal operator bool operator==(const Image& other) const; SERIALIZABLE(Image); }; // ------------------------ // Image packing definition // ------------------------ struct ImagePackDef { Ref bitmap; // Image bitmap pointer Ref packRect; // Image pack rectangle pointer WeakRef assetInfo; // Asset information // Check equal operator bool operator==(const ImagePackDef& other) const; }; protected: // Checks atlases for rebuilding Vector CheckRebuildingAtlases(); // Checks atlas for rebuilding bool CheckAtlasRebuilding(const Ref& atlasInfo); // Returns true if atlas needs to rebuild bool ImagesListChanged(Vector& currentImages, Vector& lastImages); // Rebuilds atlas void RebuildAtlas(const Ref& atlasInfo, Vector& images); // Saves image asset data void SaveImageAsset(ImagePackDef& imgDef); }; } // --- META --- CLASS_BASES_META(o2::AtlasAssetConverter) { BASE_CLASS(o2::IAssetConverter); } END_META; CLASS_FIELDS_META(o2::AtlasAssetConverter) { } END_META; CLASS_METHODS_META(o2::AtlasAssetConverter) { FUNCTION().PUBLIC().SIGNATURE(Vector, GetProcessingAssetsTypes); FUNCTION().PUBLIC().SIGNATURE(void, ConvertAsset, const AssetInfo&); FUNCTION().PUBLIC().SIGNATURE(void, RemoveAsset, const AssetInfo&); FUNCTION().PUBLIC().SIGNATURE(void, MoveAsset, const AssetInfo&, const AssetInfo&); FUNCTION().PUBLIC().SIGNATURE(Vector, AssetsPostProcess); FUNCTION().PUBLIC().SIGNATURE(void, Reset); FUNCTION().PROTECTED().SIGNATURE(Vector, CheckRebuildingAtlases); FUNCTION().PROTECTED().SIGNATURE(bool, CheckAtlasRebuilding, const Ref&); FUNCTION().PROTECTED().SIGNATURE(bool, ImagesListChanged, Vector&, Vector&); FUNCTION().PROTECTED().SIGNATURE(void, RebuildAtlas, const Ref&, Vector&); FUNCTION().PROTECTED().SIGNATURE(void, SaveImageAsset, ImagePackDef&); } END_META; CLASS_BASES_META(o2::AtlasAssetConverter::Image) { BASE_CLASS(o2::ISerializable); } END_META; CLASS_FIELDS_META(o2::AtlasAssetConverter::Image) { FIELD().PUBLIC().SERIALIZABLE_ATTRIBUTE().NAME(id); FIELD().PUBLIC().SERIALIZABLE_ATTRIBUTE().NAME(time); } END_META; CLASS_METHODS_META(o2::AtlasAssetConverter::Image) { FUNCTION().PUBLIC().CONSTRUCTOR(); FUNCTION().PUBLIC().CONSTRUCTOR(const UID&, const TimeStamp&); } END_META; // --- END META --- ================================================ FILE: AssetsBuildTool/Sources/o2AssetBuilder/Converters/FolderAssetConverter.cpp ================================================ #include "o2/stdafx.h" #include "FolderAssetConverter.h" #include "o2/Assets/Assets.h" #include "o2/Assets/Types/BinaryAsset.h" #include "o2/Assets/Types/FolderAsset.h" #include "o2/Utils/FileSystem/FileSystem.h" #include "o2AssetBuilder/AssetsBuilder.h" namespace o2 { Vector FolderAssetConverter::GetProcessingAssetsTypes() const { Vector res; res.Add(&TypeOf(FolderAsset)); return res; } void FolderAssetConverter::ConvertAsset(const AssetInfo& node) { String sourceAssetPath = mAssetsBuilder->GetSourceAssetsPath() + node.path; String buildedAssetPath = mAssetsBuilder->GetBuiltAssetsPath() + node.path; o2FileSystem.FolderCreate(buildedAssetPath); } void FolderAssetConverter::RemoveAsset(const AssetInfo& node) { String buildedAssetPath = mAssetsBuilder->GetBuiltAssetsPath() + node.path; o2FileSystem.FolderRemove(buildedAssetPath); } void FolderAssetConverter::MoveAsset(const AssetInfo& nodeFrom, const AssetInfo& nodeTo) { String fullPathFrom = mAssetsBuilder->GetBuiltAssetsPath() + nodeFrom.path; String fullPathTo = mAssetsBuilder->GetBuiltAssetsPath() + nodeTo.path; o2FileSystem.FolderCreate(fullPathTo); mRemovedFolders.Add(fullPathFrom); mRemovedFolders.Remove(fullPathTo); } Vector FolderAssetConverter::AssetsPostProcess() { for (auto fold : mRemovedFolders) o2FileSystem.FolderRemove(fold); return Vector(); } void FolderAssetConverter::Reset() { mRemovedFolders.Clear(); } } // --- META --- DECLARE_CLASS(o2::FolderAssetConverter, o2__FolderAssetConverter); // --- END META --- ================================================ FILE: AssetsBuildTool/Sources/o2AssetBuilder/Converters/FolderAssetConverter.h ================================================ #pragma once #include "IAssetConverter.h" namespace o2 { // ---------------- // Folder converter // ---------------- class FolderAssetConverter: public IAssetConverter { public: // Returns vector of processing assets types Vector GetProcessingAssetsTypes() const override; // Converts folder by path void ConvertAsset(const AssetInfo& node) override; // Removes folder by path void RemoveAsset(const AssetInfo& node) override; // Moves folder to new path void MoveAsset(const AssetInfo& nodeFrom, const AssetInfo& nodeTo) override; // Post processing folders Vector AssetsPostProcess() override; // Resets converter void Reset() override; IOBJECT(FolderAssetConverter); protected: Vector mRemovedFolders; // Removes folders }; } // --- META --- CLASS_BASES_META(o2::FolderAssetConverter) { BASE_CLASS(o2::IAssetConverter); } END_META; CLASS_FIELDS_META(o2::FolderAssetConverter) { FIELD().PROTECTED().NAME(mRemovedFolders); } END_META; CLASS_METHODS_META(o2::FolderAssetConverter) { FUNCTION().PUBLIC().SIGNATURE(Vector, GetProcessingAssetsTypes); FUNCTION().PUBLIC().SIGNATURE(void, ConvertAsset, const AssetInfo&); FUNCTION().PUBLIC().SIGNATURE(void, RemoveAsset, const AssetInfo&); FUNCTION().PUBLIC().SIGNATURE(void, MoveAsset, const AssetInfo&, const AssetInfo&); FUNCTION().PUBLIC().SIGNATURE(Vector, AssetsPostProcess); FUNCTION().PUBLIC().SIGNATURE(void, Reset); } END_META; // --- END META --- ================================================ FILE: AssetsBuildTool/Sources/o2AssetBuilder/Converters/IAssetConverter.cpp ================================================ #include "o2/stdafx.h" #include "IAssetConverter.h" #include "o2AssetBuilder/AssetsBuilder.h" namespace o2 { Vector IAssetConverter::GetProcessingAssetsTypes() const { return Vector(); } void IAssetConverter::ConvertAsset(const AssetInfo& node) {} void IAssetConverter::RemoveAsset(const AssetInfo& node) {} void IAssetConverter::MoveAsset(const AssetInfo& nodeFrom, const AssetInfo& nodeTo) {} Vector IAssetConverter::AssetsPostProcess() { return Vector(); } void IAssetConverter::Reset() {} void IAssetConverter::SetAssetsBuilder(AssetsBuilder* builder) { mAssetsBuilder = builder; } } // --- META --- DECLARE_CLASS(o2::IAssetConverter, o2__IAssetConverter); // --- END META --- ================================================ FILE: AssetsBuildTool/Sources/o2AssetBuilder/Converters/IAssetConverter.h ================================================ #pragma once #include "o2/Assets/AssetsTree.h" #include "o2/Utils/Basic/IObject.h" #include "o2/Utils/Memory/MemoryManager.h" #include "o2/Utils/Reflection/Type.h" namespace o2 { class AssetsBuilder; // -------------------------------------- // Asset converter interface // Converts assets with specialized types //--------------------------------------- class IAssetConverter: public IObject { public: // Virtual destructor virtual ~IAssetConverter() {} // Returns vector of processing assets types virtual Vector GetProcessingAssetsTypes() const; // Converts asset by path virtual void ConvertAsset(const AssetInfo& node); // Removes asset by path virtual void RemoveAsset(const AssetInfo& node); // Moves asset to new path virtual void MoveAsset(const AssetInfo& nodeFrom, const AssetInfo& nodeTo); // Post processing virtual Vector AssetsPostProcess(); // Resets converter virtual void Reset(); // Sets owner assets builder void SetAssetsBuilder(AssetsBuilder* builder); IOBJECT(IAssetConverter); protected: // Assets builder pointer AssetsBuilder* mAssetsBuilder = nullptr; }; } // --- META --- CLASS_BASES_META(o2::IAssetConverter) { BASE_CLASS(o2::IObject); } END_META; CLASS_FIELDS_META(o2::IAssetConverter) { FIELD().PROTECTED().DEFAULT_VALUE(nullptr).NAME(mAssetsBuilder); } END_META; CLASS_METHODS_META(o2::IAssetConverter) { FUNCTION().PUBLIC().SIGNATURE(Vector, GetProcessingAssetsTypes); FUNCTION().PUBLIC().SIGNATURE(void, ConvertAsset, const AssetInfo&); FUNCTION().PUBLIC().SIGNATURE(void, RemoveAsset, const AssetInfo&); FUNCTION().PUBLIC().SIGNATURE(void, MoveAsset, const AssetInfo&, const AssetInfo&); FUNCTION().PUBLIC().SIGNATURE(Vector, AssetsPostProcess); FUNCTION().PUBLIC().SIGNATURE(void, Reset); FUNCTION().PUBLIC().SIGNATURE(void, SetAssetsBuilder, AssetsBuilder*); } END_META; // --- END META --- ================================================ FILE: AssetsBuildTool/Sources/o2AssetBuilder/Converters/ImageAssetConverter.cpp ================================================ #include "o2/stdafx.h" #include "ImageAssetConverter.h" #include "o2/Assets/Assets.h" #include "o2/Assets/Types/ImageAsset.h" #include "o2/Utils/FileSystem/FileSystem.h" #include "o2AssetBuilder/AssetsBuilder.h" namespace o2 { Vector ImageAssetConverter::GetProcessingAssetsTypes() const { Vector res; res.Add(&TypeOf(ImageAsset)); return res; } void ImageAssetConverter::ConvertAsset(const AssetInfo& node) { String sourceAssetPath = mAssetsBuilder->GetSourceAssetsPath() + node.path; String builtAssetPath = mAssetsBuilder->GetBuiltAssetsPath() + node.path; o2FileSystem.FileCopy(sourceAssetPath, builtAssetPath); } void ImageAssetConverter::RemoveAsset(const AssetInfo& node) { String builtAssetPath = mAssetsBuilder->GetBuiltAssetsPath() + node.path; o2FileSystem.FileDelete(builtAssetPath); } void ImageAssetConverter::MoveAsset(const AssetInfo& nodeFrom, const AssetInfo& nodeTo) { String fullPathFrom = mAssetsBuilder->GetBuiltAssetsPath() + nodeFrom.path; String fullPathTo = mAssetsBuilder->GetBuiltAssetsPath() + nodeTo.path; o2FileSystem.FileMove(fullPathFrom, fullPathTo); } } // --- META --- DECLARE_CLASS(o2::ImageAssetConverter, o2__ImageAssetConverter); // --- END META --- ================================================ FILE: AssetsBuildTool/Sources/o2AssetBuilder/Converters/ImageAssetConverter.h ================================================ #pragma once #include "IAssetConverter.h" namespace o2 { // --------------------- // Image asset converter // --------------------- class ImageAssetConverter: public IAssetConverter { public: // Returns vector of processing assets types Vector GetProcessingAssetsTypes() const override; // Converts image void ConvertAsset(const AssetInfo& node) override; // Removes image void RemoveAsset(const AssetInfo& node) override; // Moves image to new path void MoveAsset(const AssetInfo& nodeFrom, const AssetInfo& nodeTo) override; IOBJECT(ImageAssetConverter); }; } // --- META --- CLASS_BASES_META(o2::ImageAssetConverter) { BASE_CLASS(o2::IAssetConverter); } END_META; CLASS_FIELDS_META(o2::ImageAssetConverter) { } END_META; CLASS_METHODS_META(o2::ImageAssetConverter) { FUNCTION().PUBLIC().SIGNATURE(Vector, GetProcessingAssetsTypes); FUNCTION().PUBLIC().SIGNATURE(void, ConvertAsset, const AssetInfo&); FUNCTION().PUBLIC().SIGNATURE(void, RemoveAsset, const AssetInfo&); FUNCTION().PUBLIC().SIGNATURE(void, MoveAsset, const AssetInfo&, const AssetInfo&); } END_META; // --- END META --- ================================================ FILE: AssetsBuildTool/Sources/o2AssetBuilder/Converters/StdAssetConverter.cpp ================================================ #include "o2/stdafx.h" #include "StdAssetConverter.h" #include "o2/Assets/Assets.h" #include "o2/Assets/Types/BinaryAsset.h" #include "o2/Assets/Types/FolderAsset.h" #include "o2/Assets/Types/ImageAsset.h" #include "o2/Utils/FileSystem/FileSystem.h" #include "o2AssetBuilder/AssetsBuilder.h" namespace o2 { Vector StdAssetConverter::GetProcessingAssetsTypes() const { Vector res; res.Add(&TypeOf(BinaryAsset)); return res; } void StdAssetConverter::ConvertAsset(const AssetInfo& node) { String sourceAssetPath = mAssetsBuilder->GetSourceAssetsPath() + node.path; String buildedAssetPath = mAssetsBuilder->GetBuiltAssetsPath() + node.path; o2FileSystem.FileCopy(sourceAssetPath, buildedAssetPath); } void StdAssetConverter::RemoveAsset(const AssetInfo& node) { String buildedAssetPath = mAssetsBuilder->GetBuiltAssetsPath() + node.path; o2FileSystem.FileDelete(buildedAssetPath); } void StdAssetConverter::MoveAsset(const AssetInfo& nodeFrom, const AssetInfo& nodeTo) { String fullPathFrom = mAssetsBuilder->GetBuiltAssetsPath() + nodeFrom.path; String fullPathTo = mAssetsBuilder->GetBuiltAssetsPath() + nodeTo.path; o2FileSystem.FileMove(fullPathFrom, fullPathTo); } } // --- META --- DECLARE_CLASS(o2::StdAssetConverter, o2__StdAssetConverter); // --- END META --- ================================================ FILE: AssetsBuildTool/Sources/o2AssetBuilder/Converters/StdAssetConverter.h ================================================ #pragma once #include "IAssetConverter.h" namespace o2 { // ----------------------------------------------------------------- // Standard assets converter. Copying file and meta without changing // ----------------------------------------------------------------- class StdAssetConverter: public IAssetConverter { public: // Returns vector of processing assets types Vector GetProcessingAssetsTypes() const override; // Copies asset void ConvertAsset(const AssetInfo& node) override; // Removes asset void RemoveAsset(const AssetInfo& node) override; // Moves asset to new path void MoveAsset(const AssetInfo& nodeFrom, const AssetInfo& nodeTo) override; IOBJECT(StdAssetConverter); }; } // --- META --- CLASS_BASES_META(o2::StdAssetConverter) { BASE_CLASS(o2::IAssetConverter); } END_META; CLASS_FIELDS_META(o2::StdAssetConverter) { } END_META; CLASS_METHODS_META(o2::StdAssetConverter) { FUNCTION().PUBLIC().SIGNATURE(Vector, GetProcessingAssetsTypes); FUNCTION().PUBLIC().SIGNATURE(void, ConvertAsset, const AssetInfo&); FUNCTION().PUBLIC().SIGNATURE(void, RemoveAsset, const AssetInfo&); FUNCTION().PUBLIC().SIGNATURE(void, MoveAsset, const AssetInfo&, const AssetInfo&); } END_META; // --- END META --- ================================================ FILE: AssetsBuildTool/Sources/o2AssetBuilder/ImageCompressor.cpp ================================================ #include "o2/stdafx.h" #include "ImageCompressor.h" #include "o2/Utils/FileSystem/FileSystem.h" namespace o2 { void ImageCompressor::CompressImage(const String& path, const String& outPath, TextureFormat format, int quality) { o2Debug.Log("Compress image from " + path + " to " + outPath + " format " + o2Reflection.GetEnumName(format)); String command = mConfig.formatCommands[::GetEnginePlatform()][format]; if (command.IsEmpty()) return; if (::GetEnginePlatform() == Platform::Windows) command = "\"" + command + "\""; command.ReplaceAll("{quality}", String(quality)); command.ReplaceAll("{input}", path); command.ReplaceAll("{output}", outPath); o2Debug.Log("Run compress command:" + command); int res = system(command.c_str()); if (res != 0) o2Debug.Log("Something wrong, non-zero result"); o2FileSystem.FileDelete(path); } void ImageCompressor::LoadConfig(const String& path) { DataDocument doc; o2Debug.Log("Load compressions config: " + path); doc.LoadFromFile(path); mConfig = doc; } void ImageCompressor::GenerateDefaultConfig() { mConfig.formatCommands = { { Platform::Windows, { { TextureFormat::DXT5, "\"../../deps/o2/AssetsBuildTool/Bin/nvcompress.exe\" -nomips -bc3 -alpha \"{input}\" \"{output}.dds\"" } } } }; DataDocument doc; doc = mConfig; doc.SaveToFile(::GetProjectRootPath() + String("deps/o2/CompressToolsConfig.json")); } ImageCompressor::Config ImageCompressor::mConfig; } // --- META --- DECLARE_CLASS(o2::ImageCompressor::Config, o2__ImageCompressor__Config); // --- END META --- ================================================ FILE: AssetsBuildTool/Sources/o2AssetBuilder/ImageCompressor.h ================================================ #pragma once #include "o2/Utils/Serialization/Serializable.h" namespace o2 { class ImageCompressor { public: // Compresses image static void CompressImage(const String& path, const String& outPath, TextureFormat format, int quality); // Loads config static void LoadConfig(const String& path); // Generates default config static void GenerateDefaultConfig(); public: // ------------------------- // Compressions tools config // ------------------------- struct Config : public ISerializable { // The format is: // path/to/executable custom parameters {quality 0-100} {input} {output} Map> formatCommands; // Texture formats compression commands @SERIALIZABLE SERIALIZABLE(Config); }; public: static Config mConfig; }; } // --- META --- CLASS_BASES_META(o2::ImageCompressor::Config) { BASE_CLASS(o2::ISerializable); } END_META; CLASS_FIELDS_META(o2::ImageCompressor::Config) { FIELD().PUBLIC().SERIALIZABLE_ATTRIBUTE().NAME(formatCommands); } END_META; CLASS_METHODS_META(o2::ImageCompressor::Config) { } END_META; // --- END META --- ================================================ FILE: CMake/CMakeDetermineMetalCompiler.cmake ================================================ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file LICENCE.txt or https://cmake.org/licensing for details. # CMakeDetermine(LANG)Compiler.cmake -> this should find the compiler for LANG and configure CMake(LANG)Compiler.cmake.in include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake) if(NOT CMAKE_Metal_COMPILER_NAMES) set(CMAKE_Metal_COMPILER_NAMES metal) endif() if("${CMAKE_GENERATOR}" STREQUAL "Xcode") set(CMAKE_Metal_COMPILER_XCODE_TYPE sourcecode.metal) execute_process(COMMAND xcrun --find metal OUTPUT_VARIABLE _xcrun_out OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_VARIABLE _xcrun_err RESULT_VARIABLE _xcrun_result ) if(_xcrun_result EQUAL 0 AND EXISTS "${_xcrun_out}") set(CMAKE_Metal_COMPILER "${_xcrun_out}") else() _cmake_find_compiler_path(Metal) endif() else() if(CMAKE_Metal_COMPILER) _cmake_find_compiler_path(Metal) else() set(CMAKE_Metal_COMPILER_INIT NOTFOUND) if(NOT $ENV{METALC} STREQUAL "") get_filename_component(CMAKE_Metal_COMPILER_INIT $ENV{METALC} PROGRAM PROGRAM_ARGS CMAKE_Metal_FLAGS_ENV_INIT) if(CMAKE_Metal_FLAGS_ENV_INIT) set(CMAKE_Metal_COMPILER_ARG1 "${CMAKE_Metal_FLAGS_ENV_INIT}" CACHE STRING "Arguments to the Metal compiler") endif() if(NOT EXISTS ${CMAKE_Metal_COMPILER_INIT}) message(FATAL_ERROR "Could not find compiler set in environment variable METALC\n$ENV{METALC}.\n${CMAKE_Metal_COMPILER_INIT}") endif() endif() if(NOT CMAKE_Metal_COMPILER_INIT) set(CMAKE_Metal_COMPILER_LIST metal ${_CMAKE_TOOLCHAIN_PREFIX}metal) endif() _cmake_find_compiler(Metal) endif() mark_as_advanced(CMAKE_Metal_COMPILER) endif() # For Metal we need to explicitly query the version. if(CMAKE_Metal_COMPILER AND NOT CMAKE_Metal_COMPILER_VERSION) execute_process( COMMAND "${CMAKE_Metal_COMPILER}" --version OUTPUT_VARIABLE output ERROR_VARIABLE output RESULT_VARIABLE result TIMEOUT 10 ) message(CONFIGURE_LOG "Running the Metal compiler: \"${CMAKE_Metal_COMPILER}\" --version\n" "${output}\n" ) if(output MATCHES [[metal version ([0-9]+\.[0-9]+(\.[0-9]+)?)]]) set(CMAKE_Metal_COMPILER_VERSION "${CMAKE_MATCH_1}") if(NOT CMAKE_Metal_COMPILER_ID) set(CMAKE_Metal_COMPILER_ID "Apple") endif() endif() endif() if(NOT _CMAKE_TOOLCHAIN_LOCATION) get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_Metal_COMPILER}" PATH) endif () set(_CMAKE_PROCESSING_LANGUAGE "Metal") include(CMakeFindBinUtils) unset(_CMAKE_PROCESSING_LANGUAGE) configure_file( ${CMAKE_CURRENT_LIST_DIR}/CMakeMetalCompiler.cmake.in ${CMAKE_PLATFORM_INFO_DIR}/CMakeMetalCompiler.cmake ) set(CMAKE_Metal_COMPILER_ENV_VAR "METALC") ================================================ FILE: CMake/CMakeMetalCompiler.cmake.in ================================================ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file LICENCE.txt or https://cmake.org/licensing for details. # CMake(LANG)Compiler.cmake.in -> used by CMakeDetermine(LANG)Compiler.cmake # This file is used to store compiler information and is copied down into try # compile directories so that try compiles do not need to re-determine and test # the LANG set(CMAKE_Metal_COMPILER "@CMAKE_Metal_COMPILER@") set(CMAKE_Metal_COMPILER_ID "@CMAKE_Metal_COMPILER_ID@") set(CMAKE_Metal_COMPILER_VERSION "@CMAKE_Metal_COMPILER_VERSION@") set(CMAKE_Metal_COMPILER_LOADED 1) set(CMAKE_Metal_COMPILER_WORKS "@CMAKE_Metal_COMPILER_WORKS@") set(CMAKE_Metal_COMPILER_ENV_VAR "METALC") set(CMAKE_Metal_COMPILER_ID_RUN "@CMAKE_Metal_COMPILER_ID_RUN@") set(CMAKE_Metal_SOURCE_FILE_EXTENSIONS metal) set(CMAKE_Metal_OUTPUT_EXTENSION ".air") set(CMAKE_STATIC_LIBRARY_PREFIX_Metal "") set(CMAKE_STATIC_LIBRARY_SUFFIX_Metal ".metal-ar") set(CMAKE_SHARED_LIBRARY_PREFIX_Metal "") set(CMAKE_SHARED_LIBRARY_SUFFIX_Metal ".metallib") set(CMAKE_SHARED_MODULE_PREFIX_Metal "") set(CMAKE_SHARED_MODULE_SUFFIX_Metal ".metallib") set(CMAKE_EXECUTABLE_SUFFIX_Metal ".metallib") ================================================ FILE: CMake/CMakeMetalInformation.cmake ================================================ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file LICENCE.txt or https://cmake.org/licensing for details. # CMake(LANG)Information.cmake -> set up rule variables for LANG : # CMAKE_(LANG)_CREATE_SHARED_LIBRARY # CMAKE_(LANG)_CREATE_SHARED_MODULE # CMAKE_(LANG)_CREATE_STATIC_LIBRARY # CMAKE_(LANG)_COMPILE_OBJECT # CMAKE_(LANG)_LINK_EXECUTABLE include(CMakeCommonLanguageInclude) set(CMAKE_Metal_FLAGS_INIT "-ffast-math") set(CMAKE_Metal_FLAGS_DEBUG_INIT "-gline-tables-only -frecord-sources") set(CMAKE_Metal_FLAGS_RELWITHDEBINFO_INIT "-gline-tables-only -frecord-sources") cmake_initialize_per_config_variable(CMAKE_Metal_FLAGS "Flags used by the Metal compiler") set(CMAKE_INCLUDE_FLAG_Metal "-I ") set(CMAKE_Metal_COMPILER_ARG1 "") set(CMAKE_Metal_DEFINE_FLAG -D) set(CMAKE_Metal_FRAMEWORK_SEARCH_FLAG "-F ") set(CMAKE_Metal_LIBRARY_PATH_FLAG "-L ") set(CMAKE_Metal_SYSROOT_FLAG "-isysroot") set(CMAKE_Metal_COMPILE_OPTIONS_TARGET "-target ") set(CMAKE_DEPFILE_FLAGS_Metal "-MMD -MT dependencies -MF ") if(CMAKE_GENERATOR MATCHES "Makefiles") set(CMAKE_Metal_DEPFILE_FORMAT gcc) set(CMAKE_Metal_DEPENDS_USE_COMPILER TRUE) endif() set(CMAKE_Metal_COMPILER_PREDEFINES_COMMAND "${CMAKE_Metal_COMPILER}") if(CMAKE_Metal_COMPILER_TARGET) list(APPEND CMAKE_Metal_COMPILER_PREDEFINES_COMMAND "-target" "${CMAKE_Metal_COMPILER_TARGET}") endif() # now define the following rule variables # CMAKE_Metal_CREATE_SHARED_LIBRARY # CMAKE_Metal_CREATE_SHARED_MODULE # CMAKE_Metal_COMPILE_OBJECT # CMAKE_Metal_LINK_EXECUTABLE # variables supplied by the generator at use time # # the target without the suffix # # # # # # Metal compiler information # # # # if(NOT CMAKE_Metal_COMPILE_OBJECT) set(CMAKE_Metal_COMPILE_OBJECT " -c -o " ) endif() if(NOT CMAKE_Metal_CREATE_SHARED_LIBRARY) set(CMAKE_Metal_CREATE_SHARED_LIBRARY " -o " ) endif() if(NOT CMAKE_Metal_CREATE_SHARED_MODULE) set(CMAKE_Metal_CREATE_SHARED_MODULE "${CMAKE_Metal_CREATE_SHARED_LIBRARY}" ) endif() if(NOT CMAKE_Metal_LINK_EXECUTABLE) # Metal shaders don't really have "executables", but we need this for the try_compile to work properly, so we'll just have it output a metallib file set(CMAKE_Metal_LINK_EXECUTABLE " -o " ) endif() set(CMAKE_Metal_INFORMATION_LOADED 1) ================================================ FILE: CMake/CMakeTestMetalCompiler.cmake ================================================ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file LICENCE.txt or https://cmake.org/licensing for details. # CMakeTest(LANG)Compiler.cmake -> test the compiler and set: # SET(CMAKE_(LANG)_COMPILER_WORKS 1 CACHE INTERNAL "") if(CMAKE_Metal_COMPILER_FORCED) # The compiler configuration was forced by the user. # Assume the user has configured all compiler information. set(CMAKE_Metal_COMPILER_WORKS TRUE) return() endif() include(CMakeTestCompilerCommon) if("${CMAKE_GENERATOR}" STREQUAL "Xcode") if(XCODE_VERSION VERSION_GREATER 7.0) set(CMAKE_Metal_COMPILER_WORKS 1) endif() endif() # This file is used by EnableLanguage in cmGlobalGenerator to # determine that that selected Metal compiler can actually compile # and link the most basic of programs. If not, a fatal error # is set and cmake stops processing commands and will not generate # any makefiles or projects. if(NOT CMAKE_Metal_COMPILER_WORKS) PrintTestCompilerStatus("Metal") __TestCompiler_setTryCompileTargetType() string(CONCAT __TestCompiler_testMetalCompilerSource "#ifndef __METAL_VERSION__\n" "# error \"The CMAKE_Metal_COMPILER is not a Metal compiler\"\n" "#endif\n" "#import \n" "using namespace metal;\n" ) # Clear result from normal variable. unset(CMAKE_Metal_COMPILER_WORKS) # Puts test result in cache variable. try_compile(CMAKE_Metal_COMPILER_WORKS SOURCE_FROM_VAR testMetalCompiler.metal __TestCompiler_testMetalCompilerSource OUTPUT_VARIABLE __CMAKE_Metal_COMPILER_OUTPUT ) unset(__TestCompiler_testMetalCompilerSource) # Move result from cache to normal variable. set(CMAKE_Metal_COMPILER_WORKS ${CMAKE_Metal_COMPILER_WORKS}) unset(CMAKE_Metal_COMPILER_WORKS CACHE) __TestCompiler_restoreTryCompileTargetType() set(METAL_TEST_WAS_RUN 1) endif() if(NOT CMAKE_Metal_COMPILER_WORKS) PrintTestCompilerResult(CHECK_FAIL "broken") string(REPLACE "\n" "\n " _output "${__CMAKE_Metal_COMPILER_OUTPUT}") message(FATAL_ERROR "The Metal compiler\n \"${CMAKE_Metal_COMPILER}\"\n" "is not able to compile a simple test program.\nIt fails " "with the following output:\n ${_output}\n\n" "CMake will not be able to correctly generate this project." ) else() if(METAL_TEST_WAS_RUN) PrintTestCompilerResult(CHECK_PASS "works") endif() # Re-configure to save learned information. configure_file( ${CMAKE_CURRENT_LIST_DIR}/CMakeMetalCompiler.cmake.in ${CMAKE_PLATFORM_INFO_DIR}/CMakeMetalCompiler.cmake @ONLY ) include(${CMAKE_PLATFORM_INFO_DIR}/CMakeMetalCompiler.cmake) endif() unset(__CMAKE_Metal_COMPILER_OUTPUT) ================================================ FILE: CMake/CheckLanguage.cmake ================================================ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file LICENCE.txt or https://cmake.org/licensing for details. #[=======================================================================[.rst: CheckLanguage ------------- Check whether a language can be enabled by the :command:`enable_language` or :command:`project` commands: .. command:: check_language .. code-block:: cmake check_language() Try enabling language ```` in a test project and record results in the cache: :variable:`CMAKE__COMPILER` If the language can be enabled, this variable is set to the compiler that was found. If the language cannot be enabled, this variable is set to ``NOTFOUND``. If this variable is already set, either explicitly or cached by a previous call, the check is skipped. :variable:`CMAKE__HOST_COMPILER` This variable is set when ```` is ``CUDA`` or ``HIP``. If the check detects an explicit host compiler that is required for compilation, this variable will be set to that compiler. If the check detects that no explicit host compiler is needed, this variable will be cleared. If this variable is already set, its value is preserved only if :variable:`CMAKE__COMPILER` is also set. Otherwise, the check runs and overwrites :variable:`CMAKE__HOST_COMPILER` with a new result. Note that :variable:`CMAKE__HOST_COMPILER` documents it should not be set without also setting :variable:`CMAKE__COMPILER` to a NVCC compiler. :variable:`CMAKE__PLATFORM ` This variable is set to the detected GPU platform when ```` is ``HIP``. If the variable is already set its value is always preserved. Only compatible values will be considered for :variable:`CMAKE__COMPILER`. For example: .. code-block:: cmake check_language(Fortran) if(CMAKE_Fortran_COMPILER) enable_language(Fortran) else() message(STATUS "No Fortran support") endif() #]=======================================================================] # This file has been modified to take into account the CMAKE_MODULES path when trying to build the test project # Ref https://gitlab.kitware.com/cmake/cmake/-/issues/26020 # This was merged in to CMake 3.30.0, so we only need this for older versions if(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.30) include(${CMAKE_ROOT}/Modules/CheckLanguage.cmake) else() include_guard(GLOBAL) block(SCOPE_FOR POLICIES) cmake_policy(SET CMP0126 NEW) macro(check_language lang) if(NOT DEFINED CMAKE_${lang}_COMPILER) set(_desc "Looking for a ${lang} compiler") message(CHECK_START "${_desc}") file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang}) set(extra_compiler_variables) if("${lang}" MATCHES "^(CUDA|HIP)$" AND NOT CMAKE_GENERATOR MATCHES "Visual Studio") set(extra_compiler_variables "set(CMAKE_${lang}_HOST_COMPILER \\\"\${CMAKE_${lang}_HOST_COMPILER}\\\")") endif() if("${lang}" STREQUAL "HIP") list(APPEND extra_compiler_variables "set(CMAKE_${lang}_PLATFORM \\\"\${CMAKE_${lang}_PLATFORM}\\\")") endif() list(TRANSFORM extra_compiler_variables PREPEND "\"") list(TRANSFORM extra_compiler_variables APPEND "\\n\"") list(JOIN extra_compiler_variables "\n " extra_compiler_variables) set(_cl_content "cmake_minimum_required(VERSION ${CMAKE_VERSION}) set(CMAKE_MODULE_PATH \"${CMAKE_MODULE_PATH}\") project(Check${lang} ${lang}) file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\" \"set(CMAKE_${lang}_COMPILER \\\"\${CMAKE_${lang}_COMPILER}\\\")\\n\" ${extra_compiler_variables} )" ) file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang}/CMakeLists.txt" "${_cl_content}") if(CMAKE_GENERATOR_INSTANCE) set(_D_CMAKE_GENERATOR_INSTANCE "-DCMAKE_GENERATOR_INSTANCE:INTERNAL=${CMAKE_GENERATOR_INSTANCE}") else() set(_D_CMAKE_GENERATOR_INSTANCE "") endif() if(CMAKE_GENERATOR MATCHES "^(Xcode$|Green Hills MULTI$|Visual Studio)") set(_D_CMAKE_MAKE_PROGRAM "") else() set(_D_CMAKE_MAKE_PROGRAM "-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}") endif() if(CMAKE_TOOLCHAIN_FILE) set(_D_CMAKE_TOOLCHAIN_FILE "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE}") else() set(_D_CMAKE_TOOLCHAIN_FILE "") endif() if(CMAKE_${lang}_PLATFORM) set(_D_CMAKE_LANG_PLATFORM "-DCMAKE_${lang}_PLATFORM:STRING=${CMAKE_${lang}_PLATFORM}") else() set(_D_CMAKE_LANG_PLATFORM "") endif() execute_process( WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang} COMMAND ${CMAKE_COMMAND} . -G ${CMAKE_GENERATOR} -A "${CMAKE_GENERATOR_PLATFORM}" -T "${CMAKE_GENERATOR_TOOLSET}" ${_D_CMAKE_GENERATOR_INSTANCE} ${_D_CMAKE_MAKE_PROGRAM} ${_D_CMAKE_TOOLCHAIN_FILE} ${_D_CMAKE_LANG_PLATFORM} OUTPUT_VARIABLE _cl_output ERROR_VARIABLE _cl_output RESULT_VARIABLE _cl_result ) include(${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang}/result.cmake OPTIONAL) if(CMAKE_${lang}_COMPILER AND "${_cl_result}" STREQUAL "0") message(CONFIGURE_LOG "${_desc} passed with the following output:\n" "${_cl_output}\n") set(_CHECK_COMPILER_STATUS CHECK_PASS) else() set(CMAKE_${lang}_COMPILER NOTFOUND) set(_CHECK_COMPILER_STATUS CHECK_FAIL) message(CONFIGURE_LOG "${_desc} failed with the following output:\n" "${_cl_output}\n") endif() message(${_CHECK_COMPILER_STATUS} "${CMAKE_${lang}_COMPILER}") set(CMAKE_${lang}_COMPILER "${CMAKE_${lang}_COMPILER}" CACHE FILEPATH "${lang} compiler") mark_as_advanced(CMAKE_${lang}_COMPILER) if(CMAKE_${lang}_HOST_COMPILER) message(STATUS "Looking for a ${lang} host compiler - ${CMAKE_${lang}_HOST_COMPILER}") set(CMAKE_${lang}_HOST_COMPILER "${CMAKE_${lang}_HOST_COMPILER}" CACHE FILEPATH "${lang} host compiler") mark_as_advanced(CMAKE_${lang}_HOST_COMPILER) endif() if(CMAKE_${lang}_PLATFORM) set(CMAKE_${lang}_PLATFORM "${CMAKE_${lang}_PLATFORM}" CACHE STRING "${lang} platform") mark_as_advanced(CMAKE_${lang}_PLATFORM) endif() endif() endmacro() endblock() endif() ================================================ FILE: CMake/MetalShaderSupport.cmake ================================================ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file LICENCE.txt or https://cmake.org/licensing for details. function(add_metal_shader_library TARGET) cmake_parse_arguments(PARSE_ARGV 1 _amsl "" "STANDARD" "" ) add_library(${TARGET} MODULE ${_amsl_UNPARSED_ARGUMENTS}) set_target_properties(${TARGET} PROPERTIES DEBUG_POSTFIX "" XCODE_PRODUCT_TYPE com.apple.product-type.metal-library XCODE_ATTRIBUTE_MTL_FAST_MATH "YES" XCODE_ATTRIBUTE_MTL_ENABLE_DEBUG_INFO[variant=Debug] "INCLUDE_SOURCE" XCODE_ATTRIBUTE_MTL_ENABLE_DEBUG_INFO[variant=RelWithDebInfo] "INCLUDE_SOURCE" XCODE_ATTRIBUTE_MTL_HEADER_SEARCH_PATHS "$(HEADER_SEARCH_PATHS)" ) if(_amsl_STANDARD AND _amsl_STANDARD MATCHES "metal([0-9]+)\.([0-9]+)") target_compile_options(${TARGET} PRIVATE "-std=${_amsl_STANDARD}" ) set_target_properties(${TARGET} PROPERTIES XCODE_ATTRIBUTE_MTL_LANGUAGE_REVISION "Metal${CMAKE_MATCH_1}${CMAKE_MATCH_2}" ) endif() endfunction() function(target_embed_metal_shader_libraries TARGET) cmake_parse_arguments(PARSE_ARGV 1 _temsl "" "" "" ) if(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.28 AND ${CMAKE_GENERATOR} STREQUAL "Xcode") set_target_properties(${TARGET} PROPERTIES XCODE_EMBED_RESOURCES "${_temsl_UNPARSED_ARGUMENTS}" ) else() foreach(SHADERLIB IN LISTS _temsl_UNPARSED_ARGUMENTS) add_dependencies(${TARGET} ${SHADERLIB}) add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "$" "$/Resources/$" VERBATIM ) endforeach() endif() endfunction() function(target_metal_shader_libraries TARGET) cmake_parse_arguments(PARSE_ARGV 1 _temsl "" "" "" ) foreach(SHADERLIB IN LISTS _temsl_UNPARSED_ARGUMENTS) add_dependencies(${TARGET} ${SHADERLIB}) add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "$" "${CMAKE_CURRENT_SOURCE_DIR}/Bin/${O2_PLATFORM}/$" VERBATIM ) endforeach() endfunction() ================================================ FILE: CMakeLists.txt ================================================ if(APPLE) project(o2 LANGUAGES C CXX OBJC OBJCXX) else() project(o2 LANGUAGES C CXX) endif() set(CMAKE_CXX_STANDARD 20) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake") if(APPLE) include(CheckLanguage) include(MetalShaderSupport) check_language(Metal) if(CMAKE_Metal_COMPILER) enable_language(Metal) else () message(FATAL_ERROR "Could not find compiler for metal") endif() endif() # Force off editor and tests for iOS if(CMAKE_SYSTEM_NAME STREQUAL "iOS") set(O2_EDITOR OFF CACHE BOOL "" FORCE) set(O2_TESTS OFF CACHE BOOL "" FORCE) endif() # Force off editor and tests for WebAssembly / Emscripten if(EMSCRIPTEN) set(O2_EDITOR OFF CACHE BOOL "" FORCE) set(O2_TESTS OFF CACHE BOOL "" FORCE) endif() # Force off editor and tests for Android if(ANDROID) set(O2_EDITOR OFF CACHE BOOL "" FORCE) set(O2_TESTS OFF CACHE BOOL "" FORCE) endif() # Options option(O2_SELFPROFILE "Enable profiling o2 benchmark." OFF) option(O2_EDITOR "Enables o2 editor." ON) option(O2_ASAN "Enables ASAN (address sanitizer)." OFF) option(O2_TRACY "Enables Tracy profiling" OFF) option(O2_MEMORY_ANALYZE "Enables memory analyzing (slows down)" OFF) option(O2_PLATFORM_INITIALIZATION_ENABLED "Enables platform initialization" ON) option(O2_ENABLE_LINK_ZLIB "Enables linking zlib library" ON) option(O2_ENABLE_LINK_LIBPNG "Enables linking libpng library" ON) option(O2_DISABLE_O2FRAMEWORK_PCH "Disables precompiled headers for o2Framework" OFF) if(MSVC AND NOT DEFINED O2_MSVC_MP_FLAG) set(O2_MSVC_MP_COUNT "" CACHE STRING "MSVC /MP process count; empty uses compiler default, 0 disables /MP") if(O2_MSVC_MP_COUNT STREQUAL "0") set(O2_MSVC_MP_FLAG "") elseif(O2_MSVC_MP_COUNT STREQUAL "") set(O2_MSVC_MP_FLAG "/MP") else() set(O2_MSVC_MP_FLAG "/MP${O2_MSVC_MP_COUNT}") endif() endif() # Common definitions set(O2_COMPILE_DEFINITIONS SCRIPTING_BACKEND_JERRYSCRIPT _CRT_SECURE_NO_WARNINGS) if (EMSCRIPTEN) list(APPEND O2_COMPILE_DEFINITIONS PLATFORM_WASM) list(APPEND O2_COMPILE_DEFINITIONS BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED) elseif (ANDROID) list(APPEND O2_COMPILE_DEFINITIONS PLATFORM_ANDROID) list(APPEND O2_COMPILE_DEFINITIONS BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED) elseif (WIN32) list(APPEND O2_COMPILE_DEFINITIONS PLATFORM_WINDOWS) elseif (CMAKE_SYSTEM_NAME STREQUAL "iOS") list(APPEND O2_COMPILE_DEFINITIONS PLATFORM_IOS) list(APPEND O2_COMPILE_DEFINITIONS BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED) elseif (APPLE) list(APPEND O2_COMPILE_DEFINITIONS PLATFORM_MAC) list(APPEND O2_COMPILE_DEFINITIONS BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED) elseif (UNIX) list(APPEND O2_COMPILE_DEFINITIONS PLATFORM_LINUX) endif() if (O2_IS_FILESYSTEM_EXPERIMENTAL) list(APPEND O2_COMPILE_DEFINITIONS O2_FILESYSTEM_EXPERIMENTAL) endif() if (O2_RENDER_API STREQUAL "gles2") list(APPEND O2_COMPILE_DEFINITIONS O2_RENDER_GLES2) list(APPEND O2_COMPILE_DEFINITIONS O2_DISABLE_PLATFORM) endif() if (O2_SELFPROFILE) list(APPEND O2_COMPILE_DEFINITIONS O2_PROFILE_STATS) endif() if (O2_EDITOR) list(APPEND O2_COMPILE_DEFINITIONS O2_EDITOR_ENABLED) endif() if (O2_TRACY) list(APPEND O2_COMPILE_DEFINITIONS TRACY_ENABLE) endif() if (O2_MEMORY_ANALYZE) list(APPEND O2_COMPILE_DEFINITIONS MEMORY_ANALYZE_ENABLE) endif() if (O2_PLATFORM_INITIALIZATION_ENABLED) list(APPEND O2_COMPILE_DEFINITIONS O2_PLATFORM_INITIALIZATION_ENABLED) endif() if (EMSCRIPTEN) set(O2_PLATFORM "WebAssembly") set(O2_PLATFORM "WebAssembly" PARENT_SCOPE) elseif (ANDROID) set(O2_PLATFORM "Android") set(O2_PLATFORM "Android" PARENT_SCOPE) elseif (CMAKE_SYSTEM_NAME STREQUAL "iOS") set(O2_PLATFORM "iOS") set(O2_PLATFORM "iOS" PARENT_SCOPE) elseif (APPLE) set(O2_PLATFORM "Mac") set(O2_PLATFORM "Mac" PARENT_SCOPE) elseif (UNIX) set(O2_PLATFORM "Linux") set(O2_PLATFORM "Linux" PARENT_SCOPE) elseif (WIN32) set(O2_PLATFORM "Windows") set(O2_PLATFORM "Windows" PARENT_SCOPE) else() message(FATAL_ERROR "Unknown platform, please set O2_PLATFORM manually") endif() set(O2_COMPILE_DEFINITIONS_EXPORT ${O2_COMPILE_DEFINITIONS} PARENT_SCOPE) # warings and errors if (MSVC) add_compile_options(/W2) if(O2_ASAN) add_compile_options(/fsanitize=address) add_compile_definitions(_DISABLE_STRING_ANNOTATION _DISABLE_VECTOR_ANNOTATION _DISABLE_ITERATOR_ANNOTATION) endif() else() set(O2_C_FLAGS "-Wall -Werror") if (EMSCRIPTEN) # Emscripten's Clang vintage varies between local dev and CI; tolerate unknown # warning flags rather than erroring out, and silence diagnostics that older # 3rd-party code in this repo trips on. set(O2_C_FLAGS "${O2_C_FLAGS} -Wno-unknown-warning-option -Wno-error=misleading-indentation -Wno-error=enum-enum-conversion -Wno-error=unterminated-string-initialization") endif() if (ANDROID) # NDK 28 Clang rejects unknown -Werror= options entirely, so we keep the # list minimal and tolerate unknown warning flags rather than erroring out. set(O2_C_FLAGS "${O2_C_FLAGS} -Wno-error=misleading-indentation -Wno-error=enum-enum-conversion -Wno-unknown-warning-option") endif() set(O2_CXX_FLAGS "-Wall -Wno-error=format -Wno-error=format-extra-args -Wno-error=conversion \ -Wno-error=incompatible-pointer-types -Wno-error=sign-conversion -Wno-error=pointer-sign \ -Wno-error=deprecated -Wno-reorder -Wno-unused-variable -Wno-unused-local-typedef \ -Wno-undefined-var-template -Wno-overloaded-virtual -Wno-deprecated-declarations \ -Wno-delete-non-abstract-non-virtual-dtor -Wno-unused-but-set-variable \ -Wno-inconsistent-missing-override -Wno-shorten-64-to-32 -Wno-switch -Wno-delete-incomplete \ -Wno-potentially-evaluated-expression -Wno-deprecated-this-capture -Wno-invalid-offsetof") set(O2_OBJCXX_FLAGS "-Wall -Wno-error=format -Wno-error=format-extra-args -Wno-error=conversion \ -Wno-error=incompatible-pointer-types -Wno-error=sign-conversion -Wno-error=pointer-sign \ -Wno-error=deprecated -Wno-reorder -Wno-unused-variable -Wno-unused-local-typedef \ -Wno-undefined-var-template -Wno-overloaded-virtual -Wno-deprecated-declarations \ -Wno-delete-non-abstract-non-virtual-dtor -Wno-unused-but-set-variable \ -Wno-inconsistent-missing-override -Wno-shorten-64-to-32 -Wno-switch -Wno-delete-incomplete \ -Wno-potentially-evaluated-expression -Wno-deprecated-this-capture -Wno-invalid-offsetof") if (EMSCRIPTEN) set(O2_CXX_FLAGS "${O2_CXX_FLAGS} -Wno-unknown-warning-option -Wno-error=missing-template-arg-list-after-template-kw -Wno-error=deprecated-declarations -Wno-error=unused-command-line-argument") endif() if (ANDROID) set(O2_CXX_FLAGS "${O2_CXX_FLAGS} -Wno-error=deprecated-declarations -Wno-error=unused-command-line-argument -Wno-unknown-warning-option") endif() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${O2_C_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${O2_CXX_FLAGS}") set(CMAKE_OBJCXX_FLAGS "${CMAKE_OBJCXX_FLAGS} ${O2_OBJCXX_FLAGS}") set(O2_C_FLAGS ${O2_C_FLAGS} PARENT_SCOPE) set(O2_CXX_FLAGS ${O2_CXX_FLAGS} PARENT_SCOPE) set(O2_OBJCXX_FLAGS ${O2_OBJCXX_FLAGS} PARENT_SCOPE) endif() # dependencies add_subdirectory(Framework/3rdPartyLibs) # code tool (native host-only — skip when cross-compiling to iOS / WebAssembly / Android) if(NOT CMAKE_SYSTEM_NAME STREQUAL "iOS" AND NOT EMSCRIPTEN AND NOT ANDROID) add_subdirectory(CodeTool) endif() # o2 copy builtin framework assets add_custom_target(o2CopyBuiltinAssets COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/Framework/Assets" "${CMAKE_CURRENT_SOURCE_DIR}/../BuiltAssets/${O2_PLATFORM}/FrameworkData" COMMENT "Copy o2 builtin assets from ${CMAKE_CURRENT_SOURCE_DIR}/Framework/Assets to ${CMAKE_CURRENT_SOURCE_DIR}/../BuiltAssets/${O2_PLATFORM}/FrameworkData" ) # o2 Framework library add_library(o2Framework STATIC) set(o2Framework_SOURCES_DIRS "Framework/Sources/*.h" "Framework/Sources/*.cpp") if (APPLE) list(APPEND o2Framework_SOURCES_DIRS "Framework/Sources/*.mm" "Framework/Sources/*.m") endif() file(GLOB_RECURSE o2Framework_SOURCES ${o2Framework_SOURCES_DIRS}) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${o2Framework_SOURCES}) set(o2Framework_INCLUDES "Framework/Sources" "Framework/3rdPartyLibs/rapidjson/include" "Framework/3rdPartyLibs/FreeType/include" "Framework/3rdPartyLibs/jerryscript/jerry-core/include" "Framework/3rdPartyLibs/jerryscript" "Framework/3rdPartyLibs/boost/stacktrace/include" "Framework/3rdPartyLibs/boost/config/include" "Framework/3rdPartyLibs/boost/predef/include" "Framework/3rdPartyLibs/boost/core/include" "Framework/3rdPartyLibs/boost/container_hash/include" "Framework/3rdPartyLibs/boost/winapi/include" "Framework/" ) target_sources(o2Framework PRIVATE ${o2Framework_SOURCES}) target_include_directories(o2Framework PUBLIC ${o2Framework_INCLUDES}) if(NOT O2_DISABLE_O2FRAMEWORK_PCH) target_precompile_headers(o2Framework PUBLIC "Framework/Sources/o2/stdafx.h") endif() target_compile_definitions(o2Framework PUBLIC ${O2_COMPILE_DEFINITIONS}) target_link_libraries(o2Framework PUBLIC Box2D FreeType pugixml jerry-core jerry-ext jerry-port-default spine-cpp ) if (O2_ENABLE_LINK_LIBPNG) target_link_libraries(o2Framework PUBLIC libpng) endif() if (O2_ENABLE_LINK_ZLIB) target_link_libraries(o2Framework PUBLIC zlib) endif() if (O2_TRACY) list(APPEND o2Framework_INCLUDES "Framework/3rdPartyLibs/tracy/public") target_link_libraries(o2Framework PUBLIC Tracy::TracyClient) endif() if (O2_MEMORY_ANALYZE) target_link_libraries(o2Framework PUBLIC boost_stacktrace_basic) if(WIN32) target_link_libraries(o2Framework PUBLIC boost_stacktrace_windbg boost_stacktrace_noop) endif() endif() if (EMSCRIPTEN) target_compile_options(o2Framework PUBLIC "-sUSE_WEBGL2=1" "-sMIN_WEBGL_VERSION=2" "-sMAX_WEBGL_VERSION=2" "-sFULL_ES3=1") target_link_options(o2Framework PUBLIC "-sUSE_WEBGL2=1" "-sMIN_WEBGL_VERSION=2" "-sMAX_WEBGL_VERSION=2" "-sFULL_ES3=1") elseif (ANDROID) find_library(ANDROID_EGL_LIB EGL) find_library(ANDROID_GLES2_LIB GLESv2) find_library(ANDROID_LOG_LIB log) find_library(ANDROID_LIB android) target_link_libraries(o2Framework PRIVATE ${ANDROID_EGL_LIB} ${ANDROID_GLES2_LIB} ${ANDROID_LOG_LIB} ${ANDROID_LIB} ) elseif (UNIX) if (NOT APPLE) find_package(X11 REQUIRED) target_link_libraries(o2Framework PUBLIC ${X11_LIBRARIES}) endif() if (O2_RENDER_API STREQUAL "gles2") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}") find_package(OpenGLES2 REQUIRED) target_link_libraries(o2Framework PRIVATE OpenGLES2::OpenGLES2) elseif(NOT APPLE) find_package(OpenGL REQUIRED COMPONENTS GLX) target_link_libraries(o2Framework PUBLIC OpenGL::GL OpenGL::GLX) elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS") find_library(METAL Metal) find_library(METALKIT MetalKit) find_library(FOUNDATION Foundation) find_library(OBJC objc) find_library(UIKIT UIKit) target_link_libraries(o2Framework PRIVATE ${METAL} ${FOUNDATION} ${OBJC} ${METALKIT} ${UIKIT} ) set(METAL_SHADERS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Framework/Sources/o2/Render/iOS") add_subdirectory(${METAL_SHADERS_DIR}) target_include_directories(o2Framework PRIVATE ${METAL_SHADERS_DIR} ) else() find_library(CORE_GRAPHICS CoreGraphics) find_library(METAL Metal) find_library(APP_KIT AppKit) find_library(METALKIT MetalKit) find_library(FOUNDATION Foundation) find_library(OBJC objc) find_library(APPLICATION_SERVICES ApplicationServices) target_link_libraries(o2Framework PRIVATE ${CORE_GRAPHICS} ${METAL} ${APP_KIT} ${FOUNDATION} ${OBJC} ${METALKIT} ${APPLICATION_SERVICES} ) set(METAL_SHADERS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Framework/Sources/o2/Render/Mac") add_subdirectory(${METAL_SHADERS_DIR}) target_include_directories(o2Framework PRIVATE ${METAL_SHADERS_DIR} ) endif() endif() if(WIN32) target_link_libraries(o2Framework PRIVATE Shlwapi.lib) target_link_libraries(o2Framework PRIVATE opengl32.lib) endif() if (UNIX) target_compile_options(o2Framework PRIVATE -Wno-pedantic) elseif(MSVC) target_compile_options(o2Framework PUBLIC ${O2_MSVC_MP_FLAG} "/Zc:__cplusplus" "/bigobj") target_sources(o2Framework PRIVATE "Framework/Platforms/Windows/Framework.natvis") endif() # Codegen (native host-only — skip under iOS / EMSCRIPTEN / Android; assume codegen was run during native build) if(NOT CMAKE_SYSTEM_NAME STREQUAL "iOS" AND NOT EMSCRIPTEN AND NOT ANDROID) add_custom_target(o2FrameworkCodegen COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/CodeTool/Bin/o2CodeTool -project o2Framework -sources "${CMAKE_CURRENT_SOURCE_DIR}/Framework/Sources/o2" COMMENT "Run CodeTool: ${CMAKE_CURRENT_SOURCE_DIR}/CodeTool/Bin/o2CodeTool -project o2Framework -sources \"${CMAKE_CURRENT_SOURCE_DIR}/Framework/Sources/o2\"" ) add_dependencies(o2FrameworkCodegen o2CodeTool) endif() # dependencies add_dependencies(o2Framework Box2D jerry-core jerry-ext jerry-port-default FreeType) if (O2_ENABLE_LINK_LIBPNG) add_dependencies(o2Framework libpng) endif() add_dependencies(o2Framework o2CopyBuiltinAssets) if(NOT CMAKE_SYSTEM_NAME STREQUAL "iOS" AND NOT EMSCRIPTEN AND NOT ANDROID) add_dependencies(o2Framework o2CodeTool) add_dependencies(o2Framework o2FrameworkCodegen) endif() # o2 Editor Library if (O2_EDITOR) add_library(o2Editor STATIC) set(o2Editor_SOURCES_DIRS "Editor/Sources/*.cpp" "Editor/Sources/*.h") if (APPLE) list(APPEND o2Editor_SOURCES_DIRS "Editor/Sources/*.mm" "Editor/Sources/*.m") endif() file(GLOB_RECURSE o2Framework_SOURCES ${o2Editor_SOURCES_DIRS}) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${o2Framework_SOURCES}) target_sources(o2Editor PRIVATE ${o2Framework_SOURCES}) target_include_directories(o2Editor PUBLIC "Editor/Sources" ${o2Framework_INCLUDES} ) target_precompile_headers(o2Editor PRIVATE "Editor/Sources/o2Editor/stdafx.h") target_compile_definitions(o2Editor PUBLIC ${O2_COMPILE_DEFINITIONS}) target_link_libraries(o2Editor PUBLIC o2Framework) if(MSVC) target_compile_options(o2Editor PRIVATE ${O2_MSVC_MP_FLAG} "/Zc:__cplusplus" "/bigobj") endif() # Codegen add_custom_target(o2EditorCodegen COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/CodeTool/Bin/o2CodeTool -project o2Editor -sources "${CMAKE_CURRENT_SOURCE_DIR}/Editor/Sources/o2Editor" -parent_projects "${CMAKE_CURRENT_SOURCE_DIR}/Framework/Sources/o2/CodeToolCache.xml" COMMENT "Run CodeTool: ${CMAKE_CURRENT_SOURCE_DIR}/CodeTool/Bin/o2CodeTool -project o2Editor -sources \"${CMAKE_CURRENT_SOURCE_DIR}/Editor/Sources/o2Editor\" -parent_projects \"${CMAKE_CURRENT_SOURCE_DIR}/Framework/Sources/o2/CodeToolCache.xml\"" ) add_dependencies(o2EditorCodegen o2CodeTool o2FrameworkCodegen) add_dependencies(o2Editor o2Framework) add_dependencies(o2Editor o2EditorCodegen) set_target_properties(o2Editor PROPERTIES FOLDER o2) set_target_properties(o2EditorCodegen PROPERTIES FOLDER o2/Codegen) endif() # assets build tool (native host-only — skip when cross-compiling to WebAssembly / Android) if(NOT EMSCRIPTEN AND NOT ANDROID) add_subdirectory(AssetsBuildTool) endif() # tests if(O2_TESTS) add_subdirectory(Tests) endif() # group in IDE set_target_properties(o2Framework PROPERTIES FOLDER o2) if(NOT CMAKE_SYSTEM_NAME STREQUAL "iOS" AND NOT EMSCRIPTEN AND NOT ANDROID) set_target_properties(o2AssetsBuilder PROPERTIES FOLDER o2) set_target_properties(o2CopyBuiltinAssets PROPERTIES FOLDER o2) set_target_properties(o2FrameworkCodegen PROPERTIES FOLDER o2/Codegen) set_target_properties(o2CodeTool PROPERTIES FOLDER o2/Codegen) endif() ================================================ FILE: CodeTool/CMakeLists.txt ================================================ file(GLOB_RECURSE o2CodeTool_SOURCES "Src/*.cpp" "Src/*.h") source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${o2CodeTool_SOURCES}) add_executable(o2CodeTool ${o2CodeTool_SOURCES} ${o2CodeTool_SOURCES}) if(MSVC) target_compile_options(o2CodeTool PUBLIC ${O2_MSVC_MP_FLAG} "/Zc:__cplusplus") elseif (UNIX) target_compile_options(o2CodeTool PUBLIC ${DEMO_WARNING_OPTION} -Wno-pedantic) endif() set(O2CODE_TOOL_BIN_OUTPUTDIR "${CMAKE_CURRENT_SOURCE_DIR}/Bin") set_target_properties(o2CodeTool PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${O2CODE_TOOL_BIN_OUTPUTDIR} RUNTIME_OUTPUT_DIRECTORY_DEBUG ${O2CODE_TOOL_BIN_OUTPUTDIR} RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${O2CODE_TOOL_BIN_OUTPUTDIR} RUNTIME_OUTPUT_DIRECTORY_RELEASE ${O2CODE_TOOL_BIN_OUTPUTDIR} RUNTIME_OUTPUT_DIRECTORY_RELEASEWITHDEBUGINFO ${O2CODE_TOOL_BIN_OUTPUTDIR} ) if(MSVC) set_property(TARGET o2CodeTool PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "$") endif() ================================================ FILE: CodeTool/Src/CodeTool.cpp ================================================ #include "CodeToolApp.h" int main(int nargs, char** agrs) { CodeToolApplication app; app.SetArguments(agrs, nargs); app.Process(); return 0; } ================================================ FILE: CodeTool/Src/CodeToolApp.cpp ================================================ #include "CodeToolApp.h" #include #include #include #include #include #include #include #undef GetClassName Timer::Timer() { Reset(); } void Timer::Reset() { mLastElapsedTime = std::chrono::steady_clock::now(); } float Timer::GetTime() //TODO maybe unused { using float_sec = std::chrono::duration; mLastElapsedTime = std::chrono::steady_clock::now(); auto res = std::chrono::time_point_cast(mLastElapsedTime); return res.time_since_epoch().count(); } float Timer::GetDeltaTime() { auto curTime = std::chrono::steady_clock::now(); std::chrono::duration res = curTime - mLastElapsedTime; mLastElapsedTime = curTime; return res.count(); } CodeToolApplication::CodeToolApplication() {} CodeToolApplication::~CodeToolApplication() {} void CodeToolApplication::SetArguments(char** args, int nargs) { auto argsMap = ParseArguments(args, nargs); mProjectName = argsMap["project"]; mSourcesPath = argsMap["sources"]; mMSVCProjectPath = argsMap["msvs_project"]; mXCodeProjectPath = argsMap["xcode_project"]; mNeedReset = argsMap.find("reset") != argsMap.end() || argsMap.find("r") != argsMap.end() || true; mVerbose = argsMap.find("verbose") != argsMap.end() || argsMap.find("v") != argsMap.end(); mCache.parentProjects = Split(argsMap["parent_projects"], ' '); } void CodeToolApplication::Process() { Timer t; LoadCache(); UpdateCodeReflection(); UpdateRegistratorsSource(); SaveCache(); UpdateProjectFilesFilter(); Log("Code reflection generated for %.3f seconds", t.GetDeltaTime()); } bool CodeToolApplication::mVerbose = true; void CodeToolApplication::Log(const char* format, ...) { va_list vlist; va_start(vlist, format); vprintf(format, vlist); va_end(vlist); } void CodeToolApplication::VerboseLog(const char* format, ...) { if (!mVerbose) return; va_list vlist; va_start(vlist, format); vprintf(format, vlist); va_end(vlist); } map CodeToolApplication::GetFolderFiles(const string& path) { map res; for (const auto& entry : filesystem::directory_iterator(path)) { if (entry.is_directory()) { auto subFolderFiles = GetFolderFiles(entry.path().string()); for (const auto& x : subFolderFiles) { res[x.first] = x.second; } } else { const string filePath = entry.path().string(); res[filePath] = GetFileEditedDate(filePath); } } return res; } time_t last_write_time_to_time_t(filesystem::file_time_type const& tp) { auto sctp = chrono::time_point_cast(tp - filesystem::file_time_type::clock::now() + chrono::system_clock::now()); return chrono::system_clock::to_time_t(sctp); } TimeStamp CodeToolApplication::GetFileEditedDate(const string& path) { const filesystem::directory_entry file{ path }; if (!file.exists()) { return TimeStamp(); } auto const& lwTime = file.last_write_time(); time_t cftime = last_write_time_to_time_t(lwTime); auto const& stLocal = std::localtime(&cftime); if (!stLocal) { return TimeStamp(); } TimeStamp res(stLocal->tm_sec, stLocal->tm_min, stLocal->tm_hour, stLocal->tm_mday, stLocal->tm_mon, stLocal->tm_year); return res; } map CodeToolApplication::ParseArguments(char** args, int nargs) { map res; string lastArgName = "unnamed"; for (int i = 0; i < nargs; i++) { if (args[i][0] == '-') { lastArgName = args[i] + 1; res[lastArgName] = ""; } else { if (res[lastArgName].empty()) res[lastArgName] = args[i]; else res[lastArgName] += string(" ") + args[i]; } } return res; } void CodeToolApplication::WriteFile(const string& path, const string& data) const { ofstream fout; fout.open(path.c_str()); if (!fout.is_open()) return; fout.write(data.c_str(), data.length()); fout.close(); } string CodeToolApplication::ReadFile(const string& path) const { ifstream fin; fin.open(path.c_str()); if (!fin.is_open()) return string(); string res = string((istreambuf_iterator(fin)), istreambuf_iterator()); fin.close(); return res; } bool CodeToolApplication::IsFileExist(const string& path) const { filesystem::directory_entry entry{ path }; if (entry.is_directory()) { return false; } return entry.exists(); } string CodeToolApplication::GetPathWithoutDirectories(const string& path) { filesystem::path p{ path }; return p.filename().string(); } string CodeToolApplication::GetParentPath(const string& path) { filesystem::path p{ path }; return p.parent_path().string(); } string CodeToolApplication::GetRelativePath(const string& from, const string& to) { return filesystem::relative(to, from).string(); } void CodeToolApplication::LoadCache() { if (mNeedReset) { for (auto& file : mCache.parentProjects) mCache.Load(file, false); return; } mCache.Load(mSourcesPath + "/" + mCachePath); } void CodeToolApplication::SaveCache() { mCache.Save(mSourcesPath + "/" + mCachePath); } void CodeToolApplication::UpdateProjectFilesFilter() { if (mMSVCProjectPath.empty()) return; pugi::xml_document doc; doc.load_file((mMSVCProjectPath + ".filters").c_str()); pugi::xml_node projectNode = doc.child("Project"); if (!projectNode) return; string MSVCProjectDir = GetParentPath(mMSVCProjectPath); vector filters; vector files; for (auto file : mSourceFiles) { string filePath = file.first; if (!EndsWith(filePath, ".h") && !EndsWith(filePath, ".cpp")) continue; for (int i = 0; i < filePath.length(); i++) { if (filePath[i] == '/') filePath[i] = '\\'; } string dir = GetRelativePath(MSVCProjectDir, GetParentPath(filePath)); while (!dir.empty() && dir[0] == '.') { auto slashPos = std::min(dir.find('/'), dir.find('\\')); if (slashPos != string::npos) dir.erase(0, slashPos + 1); else break; } if (dir.find("OSX") != string::npos) continue; if (dir.find("Android") != string::npos) continue; while (!dir.empty() && find(filters.begin(), filters.end(), dir) == filters.end()) { filters.push_back(dir); dir = GetParentPath(dir); } string relativePath = GetRelativePath(MSVCProjectDir, filePath); if (relativePath.length() > 1 && relativePath[0] == '.' && relativePath[1] == '\\') relativePath.erase(0, 2); files.push_back(relativePath); } vector oldFiltersNodes, ignoringGroups; vector oldFilters, oldFiles, newFilters, newFiles; bool projectStructureChanged = false; for (auto groupNode : projectNode) { for (auto itemNode : groupNode) { if ((string)"Filter" == itemNode.name()) { string filter = itemNode.attribute("Include").as_string(); if (find(filters.begin(), filters.end(), filter) != filters.end()) { oldFiltersNodes.push_back(itemNode); oldFilters.push_back(filter); } else { VerboseLog("Project changed: %s - removed filter\n", filter.c_str()); projectStructureChanged = true; } } else if ((string)"ClInclude" == itemNode.name() || (string)"ClCompile" == itemNode.name()) { string file = itemNode.attribute("Include").as_string(); if (find(files.begin(), files.end(), file) != files.end()) oldFiles.push_back(file); else { VerboseLog("Project changed: %s - removed file\n", file.c_str()); projectStructureChanged = true; } } else { ignoringGroups.push_back(groupNode); break; } } } for (auto& filter : filters) if (find(oldFilters.begin(), oldFilters.end(), filter) == oldFilters.end()) newFilters.push_back(filter); for (auto& file : files) if (find(oldFiles.begin(), oldFiles.end(), file) == oldFiles.end()) newFiles.push_back(file); projectStructureChanged = projectStructureChanged || !newFiles.empty() || !newFilters.empty() || mNeedReset; if (!projectStructureChanged) { VerboseLog("Project wasn't changed\n"); return; } VerboseLog("Project changed. New files:%i, new filters:%i, need reset:%s\n", newFiles.size(), newFilters.size(), (mNeedReset ? "true" : "false")); // generate new filters file pugi::xml_document newDoc; pugi::xml_node newProjectNode = newDoc.append_child("Project"); newProjectNode.append_attribute("ToolsVersion") = projectNode.attribute("ToolsVersion").as_string(); newProjectNode.append_attribute("xmlns") = projectNode.attribute("xmlns").as_string(); // filters pugi::xml_node filtersNode = newProjectNode.append_child("ItemGroup"); for (auto& oldFilterNode : oldFiltersNodes) filtersNode.append_copy(oldFilterNode); for (auto& newFilter : newFilters) filtersNode.append_child("Filter").append_attribute("Include") = newFilter.c_str(); // includes pugi::xml_node headersNode = newProjectNode.append_child("ItemGroup"); for (auto& file : files) { if (EndsWith(file, ".h")) { auto node = headersNode.append_child("ClInclude"); node.append_attribute("Include") = file.c_str(); auto slashPos = file.find('\\'); if (slashPos != string::npos) { while (file[slashPos + 1] == '.') slashPos = file.find('\\', slashPos + 1); string filter = GetParentPath(file.substr(slashPos + 1)); if (!filter.empty()) node.append_child("Filter").append_child(pugi::node_pcdata).set_value(filter.c_str()); } } } // sources pugi::xml_node sourcesNode = newProjectNode.append_child("ItemGroup"); for (auto& file : files) { if (EndsWith(file, ".cpp")) { auto node = sourcesNode.append_child("ClCompile"); node.append_attribute("Include") = file.c_str(); auto slashPos = file.find('\\'); if (slashPos != string::npos) { while (file[slashPos + 1] == '.') slashPos = file.find('\\', slashPos + 1); string filter = GetParentPath(file.substr(slashPos + 1)); if (!filter.empty()) node.append_child("Filter").append_child(pugi::node_pcdata).set_value(filter.c_str()); } } } // ignored for (auto& x : ignoringGroups) newProjectNode.append_copy(x); newDoc.save_file((mMSVCProjectPath + ".filters").c_str()); //and update project pugi::xml_document projectDoc, newProjectDoc; projectDoc.load_file(mMSVCProjectPath.c_str()); projectNode = projectDoc.child("Project"); newProjectNode = newProjectDoc.append_child("Project"); newProjectNode.append_attribute("DefaultTargets") = projectNode.attribute("DefaultTargets").as_string(); newProjectNode.append_attribute("ToolsVersion") = projectNode.attribute("ToolsVersion").as_string(); newProjectNode.append_attribute("xmlns") = projectNode.attribute("xmlns").as_string(); for (auto node : projectNode) { if ((string)"ItemGroup" != node.name() || node.attribute("Label") || (!node.child("ClInclude") && !node.child("ClCompile"))) newProjectNode.append_copy(node); } // headers pugi::xml_node newProjectHeadersGroup = newProjectNode.append_child("ItemGroup"); for (auto& file : files) { if (EndsWith(file, ".h")) newProjectHeadersGroup.append_child("ClInclude").append_attribute("Include") = file.c_str(); } // sources pugi::xml_node newProjectSourcesGroup = newProjectNode.append_child("ItemGroup"); for (auto& file : files) { if (EndsWith(file, ".cpp")) { auto clCompile = newProjectSourcesGroup.append_child("ClCompile"); clCompile.append_attribute("Include") = file.c_str(); if (EndsWith(file, "stdafx.cpp")) { auto headerDebug = clCompile.append_child("PrecompiledHeader"); headerDebug.append_child(pugi::node_pcdata).set_value("Create"); auto headerRelease = clCompile.append_child("PrecompiledHeader"); headerRelease.append_child(pugi::node_pcdata).set_value("Create"); } } } newProjectDoc.save_file(mMSVCProjectPath.c_str()); } void CodeToolApplication::UpdateCodeReflection() { mParser = new CppSyntaxParser(); // get all files in sources path mSourceFiles = GetFolderFiles(mSourcesPath); // parse all headers for (auto fileInfo : mSourceFiles) { if (!EndsWith(fileInfo.first, ".h")) continue; ParseSource(fileInfo.first, fileInfo.second); } // remove old sources from cache for (auto parseFileInfo = mCache.originalFiles.begin(); parseFileInfo != mCache.originalFiles.end();) { auto fnd = find_if(mSourceFiles.begin(), mSourceFiles.end(), [&](auto x) { return x.first == (*parseFileInfo)->GetPath(); }); if (fnd == mSourceFiles.end()) { delete* parseFileInfo; parseFileInfo = mCache.originalFiles.erase(parseFileInfo); mCache.files.erase(find(mCache.files.begin(), mCache.files.end(), *parseFileInfo)); } else ++parseFileInfo; } mCache.UpdateGlobalNamespace(); // update reflection for (auto file : mParsedFiles) UpdateSourceReflection(file); // collect enum registrator ids from all .cpp files, including hand-written // ENUM_META in @CODETOOLIGNORE sources that don't pass through the metas pipeline CollectEnumRegistrators(); // collect template-class registrator ids from orphan .cpp files (no DECLARE_CLASS // in the same TU to anchor it against linker pruning) CollectTemplateClassManualRegistrators(); delete mParser; } void CodeToolApplication::CollectEnumRegistrators() { mEnumRegistratorsList.clear(); for (auto& fileInfo : mSourceFiles) { const string& path = fileInfo.first; if (!EndsWith(path, ".cpp")) continue; string data = ReadFile(path); size_t pos = 0; while ((pos = data.find("ENUM_META(", pos)) != string::npos) { size_t start = pos + strlen("ENUM_META("); size_t end = data.find(')', start); if (end == string::npos) break; string args = data.substr(start, end - start); size_t comma = args.find(','); if (comma == string::npos) { pos = end + 1; continue; } string id = args.substr(comma + 1); // trim whitespace size_t first = id.find_first_not_of(" \t\n\r"); size_t last = id.find_last_not_of(" \t\n\r"); if (first == string::npos) { pos = end + 1; continue; } id = id.substr(first, last - first + 1); if (find(mEnumRegistratorsList.begin(), mEnumRegistratorsList.end(), id) == mEnumRegistratorsList.end()) mEnumRegistratorsList.push_back(id); pos = end + 1; } } } void CodeToolApplication::CollectTemplateClassManualRegistrators() { mTemplateClassManualRegistratorsList.clear(); const string needle = "DECLARE_TEMPLATE_CLASS_MANUAL_ID("; for (auto& fileInfo : mSourceFiles) { const string& path = fileInfo.first; if (!EndsWith(path, ".cpp")) continue; string data = ReadFile(path); size_t pos = 0; while ((pos = data.find(needle, pos)) != string::npos) { size_t start = pos + needle.length(); // scan forward tracking template-angle nesting to find the top-level comma int angle = 0; size_t commaPos = string::npos; size_t endPos = string::npos; for (size_t i = start; i < data.size(); ++i) { char c = data[i]; if (c == '<') ++angle; else if (c == '>') --angle; else if (c == ',' && angle == 0) { commaPos = i; } else if (c == ')' && angle == 0) { endPos = i; break; } } if (commaPos == string::npos || endPos == string::npos) break; string id = data.substr(commaPos + 1, endPos - commaPos - 1); size_t first = id.find_first_not_of(" \t\n\r"); size_t last = id.find_last_not_of(" \t\n\r"); if (first == string::npos) { pos = endPos + 1; continue; } id = id.substr(first, last - first + 1); if (find(mTemplateClassManualRegistratorsList.begin(), mTemplateClassManualRegistratorsList.end(), id) == mTemplateClassManualRegistratorsList.end()) mTemplateClassManualRegistratorsList.push_back(id); pos = endPos + 1; } } } void CodeToolApplication::UpdateRegistratorsSource() { string registratorSourceFileName = mProjectName + ".cpp"; string registratorSourcePath = mSourcesPath + "/" + registratorSourceFileName; string fileData; for (auto& regi : mEnumRegistratorsList) fileData += "extern void __RegisterEnum__" + regi + "();\n"; for (auto& regi : mTemplateClassManualRegistratorsList) fileData += "extern void __RegisterTemplateClass__" + regi + "();\n"; for (auto& regi : mRegistatorsList) fileData += "extern void __RegisterClass__" + regi + "();\n"; fileData += "\n\n"; fileData += "extern void InitializeTypes" + mProjectName + "()\n{\n"; for (auto& regi : mEnumRegistratorsList) fileData += " __RegisterEnum__" + regi + "();\n"; for (auto& regi : mTemplateClassManualRegistratorsList) fileData += " __RegisterTemplateClass__" + regi + "();\n"; for (auto& regi : mRegistatorsList) fileData += " __RegisterClass__" + regi + "();\n"; fileData += "}"; string oldFileData = ReadFile(registratorSourcePath); if (oldFileData != fileData) WriteFile(registratorSourcePath, fileData); } void CodeToolApplication::ParseSource(const string& path, const TimeStamp& editDate) { // check edit date for (auto cacheFile : mCache.originalFiles) { if (path == cacheFile->GetPath()) { if (editDate == cacheFile->GetLastEditedDate()) return; delete cacheFile; mCache.originalFiles.erase(find(mCache.originalFiles.begin(), mCache.originalFiles.end(), cacheFile)); mCache.files.erase(find(mCache.files.begin(), mCache.files.end(), cacheFile)); break; } } // parse source SyntaxFile* syntaxFile = new SyntaxFile(); mParser->ParseFile(*syntaxFile, path, editDate); mParsedFiles.push_back(syntaxFile); mCache.originalFiles.push_back(syntaxFile); mCache.files.push_back(syntaxFile); VerboseLog("Parsed %s\n", path.c_str()); } void CodeToolApplication::UpdateSourceReflection(SyntaxFile* file) { string cppSource, cppSourceInitial; bool cppLoaded = false; string hSource = file->GetData(); if (hSource.find("@CODETOOLIGNORE") != string::npos) return; bool hasHeaderMeta = false; bool hasSourceMeta = false; RemoveMetas(hSource, "META_TEMPLATES(", "END_META;"); RemoveMetas(hSource, "CLASS_BASES_META(", "END_META;"); RemoveMetas(hSource, "CLASS_FIELDS_META(", "END_META;"); RemoveMetas(hSource, "CLASS_METHODS_META(", "END_META;"); RemoveMetas(hSource, "DECLARE_CLASS(", ");", false); RemoveMetas(hSource, "PRE_ENUM_META(", ");", false); RemoveMetas(hSource, "// --- META ---", "// --- END META ---"); string cppSourcePath = file->GetPath().substr(0, file->GetPath().rfind('.')) + ".cpp"; SyntaxClass* baseObjectClass = (SyntaxClass*)(mCache.FindSection("o2::IObject")); auto checkCppLoad = [&]() { if (!cppLoaded) { if (IsFileExist(cppSourcePath)) { cppSource = ReadFile(cppSourcePath); cppSourceInitial = cppSource; RemoveMetas(cppSource, "ENUM_META(", "END_ENUM_META;"); RemoveMetas(cppSource, "ENUM_META_(", "END_ENUM_META;"); RemoveMetas(cppSource, "CLASS_META(", "END_META;"); RemoveMetas(cppSource, "CLASS_TEMPLATE_META(", "END_META;"); RemoveMetas(cppSource, "CLASS_BASES_META(", "END_META;"); RemoveMetas(cppSource, "CLASS_FIELDS_META(", "END_META;"); RemoveMetas(cppSource, "CLASS_METHODS_META(", "END_META;"); RemoveMetas(cppSource, "DECLARE_CLASS(", ");", false); RemoveMetas(cppSource, "PRE_ENUM_META(", ");", false); RemoveMetas(cppSource, "// --- META ---", "// --- END META ---"); } else cppSource = "#include \"" + GetPathWithoutDirectories(file->GetPath()) + "\"\n\n"; cppLoaded = true; } }; // Enums SyntaxEnumsVec allEnums = file->GetGlobalNamespace()->GetAllEnums(); SyntaxEnumsVec metaEnums; for (auto enm : allEnums) { auto owner = enm->GetOwnerSyntaxSection(); if (owner && owner->IsClass() && ((SyntaxClass*)owner)->IsTemplate()) continue; // Skip non-public enums inside classes (they can't be accessed from outside) if (owner && owner->IsClass() && enm->GetClassSection() != SyntaxProtectionSection::Public) continue; metaEnums.push_back(enm); } if (!metaEnums.empty()) checkCppLoad(); for (auto enm : metaEnums) { AddBeginMeta(hasSourceMeta, cppSource); cppSource += GetEnumMeta(enm); AddBeginMeta(hasHeaderMeta, hSource); hSource += GetEnumPreMeta(enm); VerboseLog("Generated meta for enum:%s\n", enm->GetFullName().c_str()); } // Classes auto classes = file->GetGlobalNamespace()->GetAllClasses(); for (auto cls : classes) { bool hasIObject = std::find_if(cls->GetFunctions().begin(), cls->GetFunctions().end(), [](SyntaxFunction* x) { return x->GetName() == "IOBJECT" || x->GetName() == "SERIALIZABLE" || x->GetName() == "ASSET_TYPE"; }) != cls->GetFunctions().end(); if ((!mCache.IsClassBasedOn(cls, baseObjectClass) && !cls->IsMetaClass()) || !hasIObject || cls == baseObjectClass) continue; if (!cls->IsTemplate()) { checkCppLoad(); AddBeginMeta(hasSourceMeta, cppSource); cppSource += GetClassDeclaration(cls); } AddBeginMeta(hasHeaderMeta, hSource); hSource += GetClassMeta(cls); VerboseLog("Generated meta for class:%s\n", cls->GetFullName().c_str()); } AddEndMeta(hasSourceMeta, cppSource); AddEndMeta(hasHeaderMeta, hSource); // Write if (cppLoaded && cppSource != cppSourceInitial) WriteFile(cppSourcePath, cppSource); if (hSource != file->GetData()) { WriteFile(file->GetPath(), hSource); file->mLastEditedDate = GetFileEditedDate(file->GetPath()); } VerboseLog("Reflection generated for %s\n", file->GetPath().c_str()); } void CodeToolApplication::AddBeginMeta(bool& hasMeta, string& res) { if (!hasMeta) res += "// --- META ---\n"; hasMeta = true; } void CodeToolApplication::AddEndMeta(bool hasMeta, string& res) { if (hasMeta) res += "// --- END META ---\n"; } string CodeToolApplication::GetClassDeclaration(SyntaxClass* cls) { string res = "\n"; string nspace; int nspaceDelimer = (int)cls->GetFullName().rfind("::"); if (nspaceDelimer != cls->GetFullName().npos) nspace = cls->GetFullName().substr(0, nspaceDelimer); if (cls->GetDefine()) res += "#if " + cls->GetDefine()->GetDefinition() + "\n"; string className = GetClassNormalizedTemplates(cls->GetFullName(), nspace); string classRegisterId = className; for (int i = 0; i < classRegisterId.length(); i++) { auto& c = classRegisterId[i]; if (c == '<' || c == '>' || c == ':') c = '_'; } mRegistatorsList.push_back(classRegisterId); res += "DECLARE_CLASS(" + className + ", " + classRegisterId + ");\n"; if (cls->GetDefine()) res += "#endif\n"; return res; } string CodeToolApplication::GetClassMeta(SyntaxClass* cls) { string res = "\n"; res.reserve(cls->GetData().length() * 2); string nspace; int nspaceDelimer = (int)cls->GetFullName().rfind("::"); if (nspaceDelimer != cls->GetFullName().npos) nspace = cls->GetFullName().substr(0, nspaceDelimer); string classDef; string templates; if (!cls->IsTemplate()) classDef = GetClassNormalizedTemplates(cls->GetFullName(), nspace); else AggregateTemplates(cls, templates, classDef); // defines if (cls->GetDefine()) res += "#if " + cls->GetDefine()->GetDefinition() + "\n"; // base classes res += templates; res += "CLASS_BASES_META(" + classDef + ")\n{\n"; int typedefs = 0; for (auto x : cls->GetBaseClasses()) { auto classInfo = mCache.FindSection(x.GetClassName(), nspace, false); auto className = classInfo ? classInfo->GetFullName() : x.GetClassName(); if (className.find(',') != string::npos) { typedefs++; auto newClassName = string("_tmp") + to_string(typedefs); res += string(" typedef ") + className + ' ' + newClassName + ";\n"; className = newClassName; } res += string(" BASE_CLASS(") + className + +");\n"; } res += "}\nEND_META;\n"; // fields res += templates; res += "CLASS_FIELDS_META(" + classDef + ")\n{\n"; SyntaxDefineIf* currentIf = nullptr; for (auto variable : cls->GetVariables()) { if (variable->IsStatic() || variable->GetName().empty()) continue; // try search comment SyntaxComment* synComment = cls->FindCommentNearLine(variable->GetLine()); if (synComment) { string ignore{ "@IGNORE" }; auto fnd = synComment->GetData().find(ignore); if (fnd != string::npos) { auto nextSymbol = synComment->GetData()[fnd + ignore.size()]; if (nextSymbol == ' ' || nextSymbol == '\t' || nextSymbol == '\n' || nextSymbol == '\0') continue; } } CheckIfDefines(variable, currentIf, res); res += " FIELD()"; if (variable->GetClassSection() == SyntaxProtectionSection::Public) res += ".PUBLIC()"; else if (variable->GetClassSection() == SyntaxProtectionSection::Private) res += ".PRIVATE()"; else if (variable->GetClassSection() == SyntaxProtectionSection::Protected) res += ".PROTECTED()"; res += GetAttributes(cls, variable->GetLine(), synComment); if (!variable->GetDefaultValue().empty() && variable->GetDefaultValue().find("this") == string::npos) res += ".DEFAULT_VALUE(" + variable->GetDefaultValue() + ")"; res += ".NAME(" + variable->GetName() + ");\n"; } CompleteIfDefines(currentIf, res); res += "}\nEND_META;\n"; // functions res += templates; res += "CLASS_METHODS_META(" + classDef + ")\n{\n"; int supportingTypedefsPos = (int)res.length(); vector supportingTypedefs; bool firstFunction = true; for (auto function : cls->GetFunctions()) { if (!IsFunctionReflectable(function, cls)) continue; // try search comment SyntaxComment* synComment = cls->FindCommentNearLine(function->GetLine()); if (IsIgnoreComment(synComment)) continue; if (firstFunction) { firstFunction = false; res += "\n"; } CheckIfDefines(function, currentIf, res); res += " FUNCTION()"; if (function->GetClassSection() == SyntaxProtectionSection::Public) res += ".PUBLIC()"; else if (function->GetClassSection() == SyntaxProtectionSection::Private) res += ".PRIVATE()"; else if (function->GetClassSection() == SyntaxProtectionSection::Protected) res += ".PROTECTED()"; res += GetAttributes(cls, function->GetLine(), synComment); bool isConstructor = StartsWith(cls->GetName(), function->GetName()); if (function->IsStatic()) res += ".SIGNATURE_STATIC("; else if (isConstructor) res += ".CONSTRUCTOR("; else res += ".SIGNATURE("; if (!isConstructor) { auto returnTypeName = (function->GetReturnType().IsConstant() ? "const " : "") + function->GetReturnType().GetName(); if (returnTypeName.find(',') != returnTypeName.npos) { supportingTypedefs.push_back(returnTypeName); returnTypeName = (string)"_tmp" + to_string((int)supportingTypedefs.size()); } res += returnTypeName; res += string(", ") + function->GetName(); } bool first = isConstructor; for (auto param : function->GetParameters()) { string parameterName = (param->GetVariableType().IsConstant() ? "const " : "") + param->GetVariableType().GetName(); if (parameterName.find(',') != parameterName.npos) { supportingTypedefs.push_back(parameterName); parameterName = string("_tmp") + to_string((int)supportingTypedefs.size()); } if (!first) res += string(", "); else first = false; res += parameterName; } res += ");\n"; } CompleteIfDefines(currentIf, res); // supporting typedefs if (!supportingTypedefs.empty()) { string supportingTypedefsStr = "\n"; for (int i = 0; i < supportingTypedefs.size(); i++) supportingTypedefsStr += (string)" typedef " + supportingTypedefs[i] + " _tmp" + to_string(i + 1) + ";\n"; res.insert(supportingTypedefsPos, supportingTypedefsStr); } res += "}\nEND_META;\n"; if (cls->GetDefine()) res += "#endif\n"; return res; } bool CodeToolApplication::IsIgnoreComment(SyntaxComment* synComment) { if (synComment) { auto fnd = synComment->GetData().find("@IGNORE"); if (fnd != string::npos) { auto nextSymbol = synComment->GetData()[fnd + strlen("@IGNORE")]; if (nextSymbol == ' ' || nextSymbol == '\t' || nextSymbol == '\n' || nextSymbol == '\0') return true; } } return false; } void CodeToolApplication::CheckIfDefines(ISyntaxExpression* item, SyntaxDefineIf*& prevDefine, string& data) { if (item->GetDefine() != prevDefine) { if (prevDefine) data += "#endif\n"; if (item->GetDefine()) data += "#if " + item->GetDefine()->GetDefinition() + "\n"; prevDefine = item->GetDefine(); } } void CodeToolApplication::CompleteIfDefines(SyntaxDefineIf*& prevDefine, string& data) { if (prevDefine) data += "#endif\n"; prevDefine = nullptr; } string CodeToolApplication::GetAttributes(SyntaxClass* cls, int line, SyntaxComment* synComment) { string attributes; SyntaxAttributes* synAttributes = nullptr; for (auto attr : cls->GetAttributes()) { if (attr->GetLine() == line - 1) { synAttributes = attr; break; } } if (synAttributes) { for (auto& attributeEntry : synAttributes->GetAttributesList()) { SyntaxClass* attributeClass = dynamic_cast(mCache.FindSection(attributeEntry, cls)); if (attributeClass) { if (!attributeClass->GetAttributeShortDef().empty()) attributes += string(".") + attributeClass->GetAttributeShortDef(); else attributes += string(".ATTRIBUTE(") + attributeClass->GetFullName() + ")"; } else attributes += string(".ATTRIBUTE(") + attributeEntry + ")"; } } if (synComment) { for (auto attributeClass : mCache.attributes) { auto fnd = synComment->GetData().find(attributeClass->GetAttributeCommentDef()); if (!attributeClass->GetAttributeCommentDef().empty() && fnd != string::npos) { auto nextSymbol = synComment->GetData()[fnd + attributeClass->GetAttributeCommentDef().length()]; if ((nextSymbol == ' ' || nextSymbol == '\t' || nextSymbol == '\n' || nextSymbol == '\0' || nextSymbol == '(') && synComment->GetData()[fnd - 1] == '@') { string parameters = "()"; auto parametersBegin = fnd + attributeClass->GetAttributeCommentDef().length(); if (synComment->GetData()[parametersBegin] == '(') { auto parametersEnd = synComment->GetData().find(')', parametersBegin) + 1; parameters = synComment->GetData().substr(parametersBegin, parametersEnd - parametersBegin); } if (!attributeClass->GetAttributeShortDef().empty()) attributes += string(".") + attributeClass->GetAttributeShortDef() + parameters; else attributes += string(".ATTRIBUTE(") + attributeClass->GetFullName() + parameters + ")"; } } } } return attributes; } string CodeToolApplication::GetEnumMeta(SyntaxEnum* enm) { string res; res.reserve(enm->GetEntries().size() * 15); string enumFullName = enm->GetFullName(); string enumRegisterId = enumFullName; for (int i = 0; i < enumRegisterId.length(); i++) { auto& c = enumRegisterId[i]; if (c == '<' || c == '>' || c == ':') c = '_'; } res += "\nENUM_META(" + enumFullName + ", " + enumRegisterId + ")\n{\n"; for (auto e : enm->GetEntries()) { if (!e.first.empty()) // Skip empty enum entry names res += " ENUM_ENTRY(" + e.first + ");\n"; } res += "}\nEND_ENUM_META;\n"; return res; } string CodeToolApplication::GetEnumPreMeta(SyntaxEnum* enm) { string res = "\nPRE_ENUM_META(" + enm->GetFullName() + ");\n"; return res; } void RemoveSubstrs(string& s, string const& p) { string::size_type n = p.length(); for (string::size_type i = s.find(p); i != string::npos; i = s.find(p)) s.erase(i, n); } void CodeToolApplication::AggregateTemplates(SyntaxSection* sec, string& templates, string& fullName) { if (sec->GetParentSection()) AggregateTemplates(sec->GetParentSection(), templates, fullName); if (fullName.empty()) fullName = sec->GetName(); else fullName += "::" + sec->GetName(); if (sec->IsClass()) { SyntaxClass* cls = dynamic_cast(sec); if (!cls->GetTemplateParameters().empty()) { templates += "META_TEMPLATES(" + cls->GetTemplateParameters() + ")\n"; string classTemplates = cls->GetTemplateParameters(); RemoveSubstrs(classTemplates, (std::string)"typename "); fullName += "<" + classTemplates + ">"; } } } string CodeToolApplication::GetClassNormalizedTemplates(const string& name, const string& nspace) { string fullName; int nameLenght = (int)name.length(); int fnd = 0; int lastFnd = fnd; while (fnd >= 0) { lastFnd = fnd; fnd = (int)name.find('<', fnd); if (fnd == name.npos) break; int begin = fnd + 1; int braces = 0, trBraces = 0, sqBraces = 0; for (bool stop = false; !stop && fnd < nameLenght; fnd++) { switch (name[fnd]) { case '(': braces++; break; case ')': braces--; break; case '[': sqBraces++; break; case ']': sqBraces--; break; case '<': trBraces++; break; case '>': trBraces--; if (trBraces == 0 && braces == 0 && sqBraces == 0) { stop = true; fnd--; } break; } } string templateParamsStr = name.substr(begin, fnd - begin); vector templateParams = Split(templateParamsStr, ','); fullName += name.substr(lastFnd, begin - lastFnd); bool firstParam = true; for (auto& templateParam : templateParams) { Trim(templateParam); string typename_str{ "typename " }; if (StartsWith(templateParam, typename_str)) templateParam.erase(0, typename_str.size()); if (!firstParam) fullName += ", "; else firstParam = false; auto classInfo = mCache.FindSection(templateParam, nspace); fullName += classInfo ? classInfo->GetFullName() : templateParam; } } fullName += name.substr(lastFnd); return fullName; } void CodeToolApplication::RemoveMetas(string& data, const char* keyword, const char* endword, bool allowMultiline /*= true*/) { auto isSkipingChar = [](char x) { return x == '\n' || x == '\r' || x == '\t' || x == '\0' || x == ' '; }; auto caret = data.find(keyword); while (caret != string::npos) { auto end = data.find(endword, caret); if (end == string::npos) break; while (caret > 0 && isSkipingChar(data[caret - 1])) caret--; if (caret > 0 && isSkipingChar(data[caret])) caret--; if (!allowMultiline) { string keyword_str{ keyword }; auto newLinePos = data.find("\n", caret + keyword_str.size()); if (newLinePos != string::npos && newLinePos < end) return; } string endword_str{ endword }; data.erase(caret + 1, end + endword_str.size() - caret - 1); caret = data.find(keyword); } caret = data.length(); while (caret > 0 && isSkipingChar(data[caret - 1])) caret--; data.erase(caret); data += '\n'; } bool CodeToolApplication::IsFunctionReflectable(SyntaxFunction* function, SyntaxSection* owner) const { static vector ignoringNames = { "SERIALIZABLE", "PROPERTY", "GETTER", "SETTER", "IOBJECT", "ASSET_TYPE", "ATTRIBUTE_COMMENT_DEFINITION", "ATTRIBUTE_SHORT_DEFINITION", "BASE_REF_IMPLEMETATION", "FRIEND_REF_MAKE", "CLONEABLE_REF", "REF_COUNTERABLE_IMPL" }; return !StartsWith(function->GetName(), string("~") + owner->GetName()) && function->GetName().find('~') == string::npos && function->GetName().find("operator") == function->GetName().npos && !function->IsTemplate() && find(ignoringNames.begin(), ignoringNames.end(), function->GetName()) == ignoringNames.end(); } void CodeToolCache::UpdateGlobalNamespace() { for (auto file : files) { SyntaxSection* fileGlobalNamespace = file->GetGlobalNamespace(); globalNamespace.mVariables.insert(globalNamespace.mVariables.end(), fileGlobalNamespace->mVariables.begin(), fileGlobalNamespace->mVariables.end()); globalNamespace.mFunctions.insert(globalNamespace.mFunctions.end(), fileGlobalNamespace->mFunctions.begin(), fileGlobalNamespace->mFunctions.end()); globalNamespace.mTypedefs.insert(globalNamespace.mTypedefs.end(), fileGlobalNamespace->mTypedefs.begin(), fileGlobalNamespace->mTypedefs.end()); globalNamespace.mUsingNamespaces.insert(globalNamespace.mUsingNamespaces.end(), fileGlobalNamespace->mUsingNamespaces.begin(), fileGlobalNamespace->mUsingNamespaces.end()); globalNamespace.mEnums.insert(globalNamespace.mEnums.end(), fileGlobalNamespace->mEnums.begin(), fileGlobalNamespace->mEnums.end()); for (auto childSection : fileGlobalNamespace->mSections) AppendSection(&globalNamespace, childSection); } ResolveDependencies(&globalNamespace); ResolveBaseClassDependencies(&globalNamespace); SyntaxClass* attributeClass = dynamic_cast(FindSection("o2::IAttribute")); SearchAttributes(&globalNamespace, attributeClass); } bool CodeToolCache::IsClassBasedOn(SyntaxClass* _class, SyntaxClass* baseClass) { if (!_class || !baseClass) return false; if (_class->mSourceClass) _class = _class->mSourceClass; if (_class == baseClass) return true; for (auto baseClassDef : _class->GetBaseClasses()) if (IsClassBasedOn(baseClassDef.GetClass(), baseClass)) return true; return false; } SyntaxSection* CodeToolCache::FindSection(const string& fullName, bool withTypedefs /*= true*/) { return FindSection(fullName, &globalNamespace, withTypedefs); } SyntaxSection* CodeToolCache::FindSection(const string& what, const string& where, bool withTypedefs /*= true*/) { return FindSection(what, FindSection(where), withTypedefs); } SyntaxSection* CodeToolCache::FindSection(const string& what, SyntaxSection* where, bool withTypedefs /*= true*/) { SyntaxSectionsVec passed; return FindSection(what, where, passed, withTypedefs); } SyntaxSection* CodeToolCache::FindSection(const string& what, SyntaxSection* where, SyntaxSectionsVec& processedSections, bool withTypedefs /*= true*/) { if (!where) return nullptr; if (find(processedSections.begin(), processedSections.end(), where) != processedSections.end()) return nullptr; processedSections.push_back(where); int braces = 0, trBraces = 0, sqBraces = 0; int delPos = -1; int whatLength = (int)what.length(); for (int i = 0; i < whatLength - 1; i++) { switch (what[i]) { case '(': braces++; break; case ')': braces--; break; case '<': trBraces++; break; case '>': trBraces--; break; case '[': sqBraces++; break; case ']': sqBraces--; break; } if (what[i] == ':' && what[i + 1] == ':' && braces == 0 && trBraces == 0 && sqBraces == 0) { delPos = i; break; } } string searchName; if (delPos < 0) searchName = what; else searchName = what.substr(0, delPos); int templatesPos = (int)searchName.find('<'); if (templatesPos != searchName.npos) searchName.erase(templatesPos); for (auto child : where->mSections) { if (child->mName != searchName) continue; if (delPos < 0) { if (templatesPos >= 0) { SyntaxClass* newSpecializedClass = new SyntaxClass(); newSpecializedClass->mName = what; if (child->mParentSection) { newSpecializedClass->mFullName = child->mParentSection->mFullName + "::" + what; child->mParentSection->mSections.push_back(newSpecializedClass); } else newSpecializedClass->mFullName = what; newSpecializedClass->mParentSection = child->mParentSection; newSpecializedClass->mSourceClass = (SyntaxClass*)child; return newSpecializedClass; } return child; } if (auto res = FindSection(what.substr(delPos + 2), child, processedSections)) return res; } if (auto res = FindSection(what, where->mParentSection, processedSections)) return res; if (where->IsClass()) { SyntaxClass* whereClass = dynamic_cast(where); for (auto& baseClass : whereClass->mBaseClasses) { if (baseClass.GetClass()) { if (auto res = FindSection(what, baseClass.GetClass(), processedSections)) return res; } } } if (withTypedefs) { for (auto tdef : where->mTypedefs) { if (tdef->GetNewDefName() != searchName) continue; if (delPos < 0) return tdef->GetWhat(); if (auto res = FindSection(what.substr(delPos + 2), tdef->GetWhat(), processedSections)) return res; } for (auto nspace : where->mUsingNamespaces) { if (auto res = FindSection(what, nspace->GetUsingNamespace(), processedSections)) return res; } } return nullptr; } void CodeToolCache::SearchAttributes(SyntaxSection* section, SyntaxClass* attributeClass) { for (auto childSection : section->mSections) { if (childSection->IsClass()) { SyntaxClass* childClass = dynamic_cast(childSection); if (IsClassBasedOn(childClass, attributeClass)) attributes.push_back(childClass); } SearchAttributes(childSection, attributeClass); } } void CodeToolCache::Save(const string& file) const { pugi::xml_document doc; pugi::xml_node filesNode = doc.append_child("files"); for (auto file : originalFiles) { auto file_node = filesNode.append_child("file"); file->SaveTo(file_node); } pugi::xml_node parentProjsNode = doc.append_child("parentProjects"); for (auto& proj : parentProjects) parentProjsNode.append_child("project").append_attribute("path") = proj.c_str(); doc.save_file(file.c_str()); } void CodeToolCache::Load(const string& file, bool original /*= true*/) { pugi::xml_document doc; doc.load_file(file.c_str()); pugi::xml_node filesNode = doc.child("files"); for (auto x : filesNode) { SyntaxFile* newFile = new SyntaxFile(); newFile->LoadFrom(x); files.push_back(newFile); if (original) originalFiles.push_back(newFile); } if (original) { for (auto x : parentProjects) Load(x, false); } else { pugi::xml_node parentProjsNode = doc.child("parentProjects"); for (auto x : parentProjsNode) { string path = x.attribute("path").as_string(); parentProjects.push_back(path); Load(path, false); } } } void CodeToolCache::AppendSection(SyntaxSection* currentSection, SyntaxSection* newSection) { if (newSection->IsClass()) { SyntaxClass* childClass = (SyntaxClass*)newSection; currentSection->mSections.push_back(childClass); childClass->mParentSection = currentSection; auto oldSections = newSection->mSections; newSection->mSections.clear(); for (auto childSection : oldSections) AppendSection(childClass, childSection); } else { SyntaxSection* childNamespace = nullptr; auto fnd = find_if(currentSection->mSections.begin(), currentSection->mSections.end(), [=](SyntaxSection* x) { return !x->IsClass() && x->GetName() == newSection->GetName(); }); if (fnd != currentSection->mSections.end()) childNamespace = *fnd; if (!childNamespace) { childNamespace = new SyntaxNamespace(); childNamespace->mName = newSection->mName; childNamespace->mFullName = newSection->mFullName; currentSection->mSections.push_back(childNamespace); childNamespace->mParentSection = currentSection; } childNamespace->mVariables.insert(childNamespace->mVariables.end(), newSection->mVariables.begin(), newSection->mVariables.end()); childNamespace->mFunctions.insert(childNamespace->mFunctions.end(), newSection->mFunctions.begin(), newSection->mFunctions.end()); childNamespace->mTypedefs.insert(childNamespace->mTypedefs.end(), newSection->mTypedefs.begin(), newSection->mTypedefs.end()); childNamespace->mUsingNamespaces.insert(childNamespace->mUsingNamespaces.end(), newSection->mUsingNamespaces.begin(), newSection->mUsingNamespaces.end()); childNamespace->mEnums.insert(childNamespace->mEnums.end(), newSection->mEnums.begin(), newSection->mEnums.end()); for (auto childSection : newSection->mSections) AppendSection(childNamespace, childSection); } } void CodeToolCache::ResolveDependencies(SyntaxSection* section) { for (auto tdef : section->mTypedefs) { tdef->mWhatSection = FindSection(tdef->mWhatName, section); if (!tdef->mWhatSection) CodeToolApplication::VerboseLog("Not found section for typedef: %s\n", tdef->mWhatName.c_str()); } for (auto nspace : section->mUsingNamespaces) { nspace->mUsingNamespace = FindSection(nspace->mUsingNamespaceName); if (!nspace->mUsingNamespace) CodeToolApplication::VerboseLog("Not found section for using namespace: %s\n", nspace->mUsingNamespaceName.c_str()); } auto sections = section->mSections; for (auto childSection : sections) ResolveDependencies(childSection); } void CodeToolCache::ResolveBaseClassDependencies(SyntaxSection* section) { if (section->IsClass()) { SyntaxClass* cls = (SyntaxClass*)section; for (auto& baseClass : cls->mBaseClasses) { baseClass.mClass = (SyntaxClass*)FindSection(baseClass.mClassName, section); if (!baseClass.mClass) CodeToolApplication::VerboseLog("Not found base class: %s\n", baseClass.mClassName.c_str()); } } auto sections = section->mSections; for (auto childSection : sections) ResolveBaseClassDependencies(childSection); } ================================================ FILE: CodeTool/Src/CodeToolApp.h ================================================ #pragma once #include #include "CppSyntaxParser.h" class Timer { public: // Default constructor Timer(); // Resets time void Reset(); // Returns time in seconds from last Reset() call float GetTime(); //TODO maybe unused // Returns time in seconds from last Reset() or GetElapsedTime() call float GetDeltaTime(); private: std::chrono::time_point mLastElapsedTime; }; class CodeToolCache { public: SyntaxFilesVec files; // All syntax files list, including parent projects SyntaxFilesVec originalFiles; // Original syntax files list SyntaxSection globalNamespace; // Global syntax namespace SyntaxClassesVec attributes; // Allattribute classes vector parentProjects; // Parent projects code tool caches, that used in current project // Updates global namespace void UpdateGlobalNamespace(); // Returns is class based on other class bool IsClassBasedOn(SyntaxClass* _class, SyntaxClass* baseClass); // Returns section by name in global space SyntaxSection* FindSection(const string& fullName, bool withTypedefs = true); // Returns section by name in where SyntaxSection* FindSection(const string& what, const string& where, bool withTypedefs = true); // Returns section by name in where SyntaxSection* FindSection(const string& what, SyntaxSection* where, bool withTypedefs = true); // Saves data to file void Save(const string& file) const; // Loads data from file void Load(const string& file, bool original = true); protected: void AppendSection(SyntaxSection* currentSection, SyntaxSection* newSection); void ResolveDependencies(SyntaxSection* section); void ResolveBaseClassDependencies(SyntaxSection* section); SyntaxSection* FindSection(const string& what, SyntaxSection* where, SyntaxSectionsVec& processedSections, bool withTypedefs = true); void SearchAttributes(SyntaxSection* section, SyntaxClass* attributeClass); }; // --------------------- // Code tool application // --------------------- class CodeToolApplication { public: // Default constructor. Initializes all editor components CodeToolApplication(); // Destructor ~CodeToolApplication(); // Sets arguments from main() void SetArguments(char** args, int nargs); // Generates new reflection void Process(); // Outs string to log static void Log(const char* format, ...); // Outs string to log if verbose move is enabled static void VerboseLog(const char* format, ...); protected: string mCachePath = "CodeToolCache.xml"; string mProjectName; string mSourcesPath; string mMSVCProjectPath; string mXCodeProjectPath; bool mNeedReset = true; static bool mVerbose; CppSyntaxParser* mParser; vector mParsedFiles; CodeToolCache mCache; map mSourceFiles; vector mRegistatorsList; vector mEnumRegistratorsList; vector mTemplateClassManualRegistratorsList; protected: // Returns list of all files in path and in sub paths map GetFolderFiles(const string& path); // Returns last edited date for file TimeStamp GetFileEditedDate(const string& path); // Parses startup arguments and puts into map map ParseArguments(char** args, int nargs); // Returns is file exist bool IsFileExist(const string& path) const; // Writes data to file void WriteFile(const string& path, const string& data) const; // Reads data from file string ReadFile(const string& path) const; // Returns path without parent directories string GetPathWithoutDirectories(const string& path); // Returns parent path string GetParentPath(const string& path); // Returns relative path string GetRelativePath(const string& from, const string& to); // Loads files parsing cache void LoadCache(); // Saves files parsing cache void SaveCache(); // Updates project files structure void UpdateProjectFilesFilter(); // Updates code reflection void UpdateCodeReflection(); // Scans all .cpp files for ENUM_META calls and collects REG_IDs void CollectEnumRegistrators(); // Scans all .cpp files for DECLARE_TEMPLATE_CLASS_MANUAL_ID calls and collects REG_IDs void CollectTemplateClassManualRegistrators(); // Generates classes registrators list source file void UpdateRegistratorsSource(); // Parses source file void ParseSource(const string& path, const TimeStamp& editDate); // Updates reflection for classes in source void UpdateSourceReflection(SyntaxFile* file); // Adds meta comment begin section void AddBeginMeta(bool& hasMeta, string& res); // Adds meta comment end section void AddEndMeta(bool hasMeta, string& res); // Returns class declaration meta string GetClassDeclaration(SyntaxClass* cls); // Returns class reflection meta string GetClassMeta(SyntaxClass* cls); // Returns is comment ignoring bool IsIgnoreComment(SyntaxComment* synComment); // Adds #if if required void CheckIfDefines(ISyntaxExpression* item, SyntaxDefineIf*& prevDefine, string& data); // Adds #endif if required void CompleteIfDefines(SyntaxDefineIf*& prevDefine, string& data); // Returns class field attributes string GetAttributes(SyntaxClass* cls, int line, SyntaxComment* synComment); // Return enum reflection meta string GetEnumMeta(SyntaxEnum* enm); // Return enum reflection meta for header string GetEnumPreMeta(SyntaxEnum* enm); // Builds meta templates parameters for template classes void AggregateTemplates(SyntaxSection* sec, string& templates, string& fullName); // Returns class full name with template parameters in global space string GetClassNormalizedTemplates(const string& name, const string& nspace); // Removes class metas from source void RemoveMetas(string& data, const char* keyword, const char* endword, bool allowMultiline = true); // Returns is function reflectable bool IsFunctionReflectable(SyntaxFunction* function, SyntaxSection* owner) const; }; ================================================ FILE: CodeTool/Src/CppSyntaxParser.cpp ================================================ #include "CppSyntaxParser.h" #include #include #include #include #include #include string& TrimStart(string& str, const string& chars /*= " "*/) { int l = (int)str.length(); int i = 0; for (; i < l; i++) { if (chars.find(str[i]) == string::npos) break; } str.erase(0, i); return str; } string& TrimEnd(string& str, const string& chars /*= " "*/) { int l = (int)str.length(); int i = l - 1; for (; i >= 0; i--) { if (chars.find(str[i]) == string::npos) break; } str.erase(i + 1); return str; } string& Trim(string& str, const string& chars /*= " "*/) { return TrimStart(TrimEnd(str, chars), chars); } bool StartsWith(const string& str, const string& starts) { int l1 = (int)str.length(), l2 = (int)starts.length(); if (l1 < l2) return false; for (int i = 0; i < l1 && i < l2; i++) { if (str[i] != starts[i]) return false; } return true; } bool EndsWith(const string& str, const string& ends) { int l1 = (int)str.length(), l2 = (int)ends.length(); if (l1 < l2) return false; for (int i = 0; i < l1 && i < l2; i++) { if (str[l1 - i - 1] != ends[l2 - i - 1]) return false; } return true; } void Split(const string& s, char delim, vector& elems) { stringstream ss; ss.str(s); string item; while (getline(ss, item, delim)) elems.push_back(item); } vector Split(const string& s, char delim) { vector elems; Split(s, delim, elems); return elems; } CppSyntaxParser::CppSyntaxParser() { InitializeParsers(); } CppSyntaxParser::~CppSyntaxParser() { for (auto x : mParsers) delete x; } void CppSyntaxParser::InitializeParsers() { mParsers.push_back(new ExpressionParser("namespace", &CppSyntaxParser::ParseNamespace, false, true)); mParsers.push_back(new ExpressionParser("namespace", &CppSyntaxParser::ParseNamespace, true, true)); mParsers.push_back(new ExpressionParser("//", &CppSyntaxParser::ParseComment, true, true)); mParsers.push_back(new ExpressionParser("/*", &CppSyntaxParser::ParseMultilineComment, true, true)); mParsers.push_back(new ExpressionParser("#pragma", &CppSyntaxParser::ParsePragma, false, true)); mParsers.push_back(new ExpressionParser("#include", &CppSyntaxParser::ParseInclude, false, true)); mParsers.push_back(new ExpressionParser("#define", &CppSyntaxParser::ParseDefine, true, true)); mParsers.push_back(new ExpressionParser("#undef", &CppSyntaxParser::ParseDefine, true, true)); mParsers.push_back(new ExpressionParser("#ifdef", &CppSyntaxParser::ParseIfdefMacros, true, true)); mParsers.push_back(new ExpressionParser("#if", &CppSyntaxParser::ParseIfMacros, true, true)); mParsers.push_back(new ExpressionParser("#endif", &CppSyntaxParser::ParseEndIfMacros, true, true)); mParsers.push_back(new ExpressionParser("#else", &CppSyntaxParser::ParseElseMacros, true, true)); mParsers.push_back(new ExpressionParser("#elif", &CppSyntaxParser::ParseElifMacros, true, true)); mParsers.push_back(new ExpressionParser("meta class", &CppSyntaxParser::ParseMetaClass, true, true)); mParsers.push_back(new ExpressionParser("class", &CppSyntaxParser::ParseClass, true, true)); mParsers.push_back(new ExpressionParser("struct", &CppSyntaxParser::ParseStruct, true, true)); mParsers.push_back(new ExpressionParser("template", &CppSyntaxParser::ParseTemplate, true, true)); mParsers.push_back(new ExpressionParser("typedef", &CppSyntaxParser::ParseTypedef, true, true)); mParsers.push_back(new ExpressionParser("enum", &CppSyntaxParser::ParseEnum, true, true)); mParsers.push_back(new ExpressionParser("using", &CppSyntaxParser::ParseUsing, true, true)); mParsers.push_back(new ExpressionParser("public:", &CppSyntaxParser::ParsePublicSection, true, false)); mParsers.push_back(new ExpressionParser("private:", &CppSyntaxParser::ParsePrivateSection, true, false)); mParsers.push_back(new ExpressionParser("protected:", &CppSyntaxParser::ParseProtectedSection, true, false)); mParsers.push_back(new ExpressionParser("friend", &CppSyntaxParser::ParseFriend, true, false)); mParsers.push_back(new ExpressionParser("ATTRIBUTE_COMMENT_DEFINITION", &CppSyntaxParser::ParseAttributeCommentDef, true, false)); mParsers.push_back(new ExpressionParser("ATTRIBUTE_SHORT_DEFINITION", &CppSyntaxParser::ParseAttributeShortDef, true, false)); mParsers.push_back(new ExpressionParser("ATTRIBUTES", &CppSyntaxParser::ParseAttributes, true, false)); mParsers.push_back(new ExpressionParser("PROPERTIES", &CppSyntaxParser::ParseProperties, true, false)); mParsers.push_back(new ExpressionParser("PROPERTY", &CppSyntaxParser::ParseProperty, true, false)); mParsers.push_back(new ExpressionParser("GETTER", &CppSyntaxParser::ParseGetter, true, false)); mParsers.push_back(new ExpressionParser("SETTER", &CppSyntaxParser::ParseSetter, true, false)); mParsers.push_back(new ExpressionParser("ACCESSOR", &CppSyntaxParser::ParseAccessor, true, false)); } void CppSyntaxParser::ParseFile(SyntaxFile& file, const string& filePath, const TimeStamp& fileEditDate) { file.mPath = filePath; file.mLastEditedDate = fileEditDate; ifstream fin; fin.open(filePath.c_str()); if (!fin.is_open()) return; file.mData = string((std::istreambuf_iterator(fin)), std::istreambuf_iterator()); fin.close(); if (file.mData.find("@CODETOOLIGNORE") != string::npos) return; ParseSyntaxSection(*file.mGlobalNamespace, file.mData, file, SyntaxProtectionSection::Public); } void CppSyntaxParser::ParseSyntaxSection(SyntaxSection& section, const string& source, SyntaxFile& file, SyntaxProtectionSection protectionSection) { section.mLength = (int)source.length(); section.mData = source; section.mFile = &file; string skipSymbols = " \r\n\t;"; int caret = 0; while (caret < section.mLength) { if (skipSymbols.find(source[caret]) != string::npos) { caret++; continue; } bool parsedByKeywork = false; for (auto parser : mParsers) { const char* keyWord = parser->keyWord; int i = 0; bool success = true; while (keyWord[i] != '\0') { if (source[i + caret] != keyWord[i]) { success = false; break; } i++; } if (!success) continue; ParserDelegate pd = parser->parser; (this->*pd)(section, caret, protectionSection); parsedByKeywork = true; break; } if (parsedByKeywork) continue; int blockbegin = caret; string block = ReadBlock(section.mData, caret); Trim(block, " \r\t\n"); if (block[0] == '{' && block[block.length() - 1] == '}') { block.erase(block.length() - 1, 1); block.erase(0, 1); } if (!block.empty()) TryParseBlock(section, block, blockbegin, caret, protectionSection); else caret++; } } int CppSyntaxParser::GetLineNumber(const string& data, int caret) { int res = 0; for (int i = 0; i < caret; i++) if (data[i] == '\n') res++; return res; } void CppSyntaxParser::TryParseBlock(SyntaxSection& section, const string& block, int blockBegin, int& caret, SyntaxProtectionSection& protectionSection) { if (IsFunction(block)) { auto func = ParseFunction(block, protectionSection, blockBegin, caret); func->mFile = section.mFile; func->mLine = GetLineNumber(section.mData, caret); section.mFunctions.push_back(func); } else { auto var = ParseVariable(block, protectionSection, blockBegin, caret); var->mFile = section.mFile; var->mLine = GetLineNumber(section.mData, caret); section.mVariables.push_back(var); } } bool CppSyntaxParser::IsFunction(const string& data) { int locCaret = 0; bool isFunction = false; string firstWord = ReadWord(data, locCaret, " \n\r(){}[]"); if (firstWord.empty()) return false; if (firstWord == "virtual") firstWord = ReadWord(data, locCaret, " \n\r(){}[]"); if (firstWord == "static") firstWord = ReadWord(data, locCaret, " \n\r(){}[]"); if (firstWord == "typename") firstWord = ReadWord(data, locCaret, " \n\r(){}[]"); if (firstWord == "inline") firstWord = ReadWord(data, locCaret, " \n\r(){}[]"); if (firstWord == "explicit") firstWord = ReadWord(data, locCaret, " \n\r(){}[]"); if (GetNextSymbol(data, locCaret, " \n\r\t") == '(') { string braces = ReadBraces(data, locCaret); Trim(braces, " \n\t\r()"); int tmpCaret = 0; string word = ReadWord(braces, tmpCaret); isFunction = GetNextSymbol(braces, tmpCaret, " \n\r\t") != ':'; if (!isFunction && StartsWith(braces, "std")) isFunction = true; } else { if (firstWord == "const") ReadWord(data, locCaret, " \n\r(){}[]"); if (firstWord == "operator") ReadWord(data, locCaret, " \n\r(){}[]"); string thirdWord = ReadWord(data, locCaret, " \n\r(){}[]<>-"); if (thirdWord == "operator") thirdWord = ReadWord(data, locCaret, " \n\r(){}", "\n\r", true, true, false); if (GetNextSymbol(data, locCaret, " \n\r\t") == '(') isFunction = true; } return isFunction; } SyntaxVariable* CppSyntaxParser::ParseVariable(const string& data, SyntaxProtectionSection& protectionSection, int begin, int end) { SyntaxVariable* res = new SyntaxVariable(); res->mBegin = begin; res->mLength = end - begin; res->mData = data; if (mCurrentDefine) res->mDefine = mCurrentDefine; int caret = 0; string typeWord = ReadWord(data, caret, " \n\r(){}[]"); string typeDefinition = typeWord; if (typeWord == "static") { typeWord = ReadWord(data, caret, " \n\r(){}[]"); typeDefinition += " " + typeWord; res->mIsStatic = true; } if (typeWord == "const") { typeWord = ReadWord(data, caret, " \n\r(){}[]"); res->mType.mIsContant = true; typeDefinition += " " + typeWord; } if (typeWord == "mutable") { typeWord = ReadWord(data, caret, " \n\r(){}[]"); res->mType.mIsMutable = true; typeDefinition += " " + typeWord; } if (!typeWord.empty() && typeWord[typeWord.length() - 1] == '&') res->mType.mIsReference = true; if (!typeWord.empty() && typeWord[typeWord.length() - 1] == '*') res->mType.mIsPointer = true; res->mType.mName = typeWord; res->mClassSection = protectionSection; if (GetNextSymbol(data, caret, " \n\r\t") == '(') { string bracesRaw = ReadBraces(data, caret); string braces = Trim(bracesRaw, " \r\t\t()"); string nextBracesRaw = ReadBraces(data, caret); string nextBraces = Trim(nextBracesRaw, " \r\t\t()"); int tmpCaret = 0; string bracesFirst = ReadWord(braces, tmpCaret); if (braces[tmpCaret] == '*') { tmpCaret += 3; res->mName = braces.substr(tmpCaret); res->mType.mName += " (" + bracesFirst + "*)(" + nextBraces + ")"; } } else { string nextWord = ReadWord(data, caret, " (){}[]"); if (nextWord == "const") res->mName = ReadWord(data, caret, " (){}[]"); else res->mName = nextWord; nextWord = ReadWord(data, caret, " (){}[]"); if (nextWord == "=") res->mDefaultValue = ReadWord(data, caret, ";"); } return res; } SyntaxFunction* CppSyntaxParser::ParseFunction(const string& data, SyntaxProtectionSection& protectionSection, int begin, int end) { SyntaxFunction* res = new SyntaxFunction(); res->mBegin = begin; res->mLength = end - begin; res->mData = data; if (mCurrentDefine) res->mDefine = mCurrentDefine; res->mClassSection = protectionSection; int caret = 0; string typeWord = ReadWord(data, caret, " \n\r(){}[]"); if (typeWord == "virtual") { res->mIsVirtual = true; typeWord = ReadWord(data, caret, " \n\r(){}[]"); } if (typeWord == "static") { res->mIsStatic = true; typeWord = ReadWord(data, caret, " \n\r(){}[]"); } if (typeWord == "inline") typeWord = ReadWord(data, caret, " \n\r(){}[]"); if (typeWord == "typename") typeWord = ReadWord(data, caret, " \n\r(){}[]"); if (typeWord == "explicit") typeWord = ReadWord(data, caret, " \n\r(){}[]"); if (typeWord == "operator") { string nextWord = ReadWord(data, caret, " \n\r(){}[]"); res->mName = typeWord + nextWord; res->mReturnType.mName = "void"; } else { if (GetNextSymbol(data, caret, " \n\r\t") == '(') { res->mName = typeWord; res->mReturnType.mName = "void"; } else { string typeDefinition = typeWord; if (typeWord == "const") { typeWord = ReadWord(data, caret, " \n\r(){}[]"); res->mReturnType.mIsContant = true; typeDefinition += " " + typeWord; } if (!typeWord.empty() && typeWord[typeWord.length() - 1] == '&') res->mReturnType.mIsReference = true; if (!typeWord.empty() && typeWord[typeWord.length() - 1] == '*') res->mReturnType.mIsPointer = true; res->mReturnType.mName = typeWord; res->mName = ReadWord(data, caret, " \n\r(){}[]"); if (res->mName == "operator") res->mName += " " + ReadWord(data, caret, " \n\r(){}"); } } string braces = ReadBraces(data, caret); string paramsStr = Trim(braces, " \n\r\t"); string afterParamWord = ReadWord(data, caret); if (afterParamWord == "const") res->mIsContstant = true; if (!paramsStr.empty()) { auto paramsArr = Split(paramsStr, ','); for (auto& prm : paramsArr) { Trim(prm, " \r\n\t"); SyntaxProtectionSection tempProtectSection = SyntaxProtectionSection::Public; res->mParameters.push_back(ParseVariable(prm, tempProtectSection, begin, end)); } } return res; } void CppSyntaxParser::ParseNamespace(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { int begin = caret; caret += (int)strlen("namespace"); string namespaceName = ReadWord(section.mData, caret); string blockRaw = ReadBlock(section.mData, caret); string block = Trim(blockRaw, " \r\t\n"); SyntaxNamespace* newNamespace = new SyntaxNamespace(); newNamespace->mBegin = begin; newNamespace->mLength = caret - begin; newNamespace->mLine = GetLineNumber(section.mData, caret); string blockSubstr = block.substr(1, block.length() - 1); newNamespace->mData = Trim(blockSubstr, " \r\t\n"); newNamespace->mName = namespaceName; newNamespace->mFullName = section.mFullName.empty() ? namespaceName : section.mFullName + "::" + namespaceName; newNamespace->mFile = section.mFile; newNamespace->mParentSection = §ion; section.mSections.push_back(newNamespace); ParseSyntaxSection(*newNamespace, newNamespace->mData, *section.mFile, SyntaxProtectionSection::Public); } void CppSyntaxParser::ParseComment(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { int begin = caret; caret += (int)strlen("//"); SyntaxComment* comment = new SyntaxComment(); int dataLength = (int)section.mData.length(); string skipSymbols = " \r\t;"; int tmpCaret = caret; bool first = true; int line = 0; do { caret = tmpCaret; if (!first) { caret += 2; comment->mData += '\n'; } string buffRaw = ReadWord(section.mData, caret, "\n", ""); string buff = Trim(buffRaw, " \r"); comment->mData += buff; line = GetLineNumber(section.mData, caret); tmpCaret = caret + 1; for (; tmpCaret < dataLength; tmpCaret++) { if (skipSymbols.find(section.mData[tmpCaret]) == string::npos) break; } if (first) first = false; } while (tmpCaret < dataLength - 2 && section.mData[tmpCaret] == '/' && section.mData[tmpCaret + 1] == '/'); caret = tmpCaret; comment->mBegin = begin; comment->mLength = caret - begin; comment->mFile = section.mFile; comment->mLine = line; section.mComments.push_back(comment); } void CppSyntaxParser::ParseMultilineComment(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { int begin = caret; caret += (int)strlen("/*"); int end = (int)section.mData.find("*/", caret); caret = end; SyntaxComment* comment = new SyntaxComment(); string sub = section.mData.substr(begin + 2, end - 4 - begin); comment->mData = Trim(sub, " \r\t\n"); comment->mBegin = begin; comment->mLength = caret - begin; comment->mFile = section.mFile; section.mComments.push_back(comment); } void CppSyntaxParser::ParsePragma(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { caret += (int)strlen("#pragma"); ReadWord(section.mData, caret, "\n", ""); } void CppSyntaxParser::ParseInclude(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { caret += (int)strlen("#include"); ReadWord(section.mData, caret, "\n", ""); } void CppSyntaxParser::ParseDefine(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { caret += (int)strlen("#define"); ReadWord(section.mData, caret, "\n", ""); } void CppSyntaxParser::ParseUndef(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { caret += (int)strlen("#undef"); ReadWord(section.mData, caret, "\n", ""); } void CppSyntaxParser::ParseIfdefMacros(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { caret += (int)strlen("#ifdef"); SyntaxDefineIf* newDefine = new SyntaxDefineIf(); newDefine->mDefintion = "defined " + ReadWord(section.mData, caret, "\n", ""); section.mDefines.push_back(newDefine); mCurrentDefine = newDefine; } void CppSyntaxParser::ParseIfMacros(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { caret += (int)strlen("#if"); SyntaxDefineIf* newDefine = new SyntaxDefineIf(); newDefine->mDefintion = ReadWord(section.mData, caret, "\n", ""); section.mDefines.push_back(newDefine); mCurrentDefine = newDefine; } void CppSyntaxParser::ParseEndIfMacros(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { caret += (int)strlen("#endif"); ReadWord(section.mData, caret, "\n", ""); mCurrentDefine = nullptr; } void CppSyntaxParser::ParseElifMacros(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { caret += (int)strlen("#elif"); SyntaxDefineIf* newDefine = new SyntaxDefineIf(); newDefine->mDefintion = ReadWord(section.mData, caret, "\n", ""); section.mDefines.push_back(newDefine); mCurrentDefine = newDefine; } void CppSyntaxParser::ParseElseMacros(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { caret += (int)strlen("#else"); ReadWord(section.mData, caret, "\n", ""); if (mCurrentDefine) { SyntaxDefineIf* newDefine = new SyntaxDefineIf(); newDefine->mDefintion = "!(" + mCurrentDefine->mDefintion + ")"; section.mDefines.push_back(newDefine); mCurrentDefine = newDefine; } } void CppSyntaxParser::ParseMetaClass(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { ParseClassOrStruct(section, caret, protectionSection, true, true, ""); } void CppSyntaxParser::ParseClass(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { ParseClassOrStruct(section, caret, protectionSection, true, false, ""); } void CppSyntaxParser::ParseStruct(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { ParseClassOrStruct(section, caret, protectionSection, false, false, ""); } void CppSyntaxParser::ParseClassOrStruct(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection, bool isClass, bool isMeta, const string& templates) { int begin = caret; if (isMeta) caret += (int)strlen("meta"); if (isClass) caret += (int)strlen("class"); else caret += (int)strlen("struct"); string className = ReadWord(section.mData, caret, " \n\t\r:;/"); string afterNameRaw = ReadWord(section.mData, caret, ";{/"); string afterName = Trim(afterNameRaw, " :\r\n\t"); string shortClassName = className; className = section.mFullName.empty() ? className : section.mFullName + "::" + className; SyntaxClass* newClass = new SyntaxClass(); newClass->mBegin = begin; newClass->mLength = caret - begin; newClass->mLine = GetLineNumber(section.mData, caret); newClass->mData = section.mData.substr(begin, caret - begin); newClass->mName = shortClassName; newClass->mFullName = className; newClass->mFile = section.mFile; newClass->mParentSection = §ion; newClass->mClassSection = protectionSection; newClass->mTemplateParameters = templates; if (mCurrentDefine) newClass->mDefine = mCurrentDefine; if (!afterName.empty()) { auto baseClasses = Split(afterName, ','); for (auto& baseClass : baseClasses) { Trim(baseClass); int spacePos = (int)baseClass.find(' '); if (spacePos == baseClass.npos) newClass->mBaseClasses.push_back(SyntaxClassInheritance(baseClass, SyntaxProtectionSection::Private)); else { if (StartsWith(baseClass, "virtual")) { baseClass.erase(0, strlen("virtual") + 1); spacePos = (int)baseClass.find(' '); } string sectionTypeName = baseClass.substr(0, spacePos); string baseClassName = baseClass.substr(spacePos + 1); if (StartsWith(baseClassName, "virtual")) baseClassName.erase(0, strlen("virtual") + 1); SyntaxProtectionSection sectionType = SyntaxProtectionSection::Private; if (sectionTypeName == "public") sectionType = SyntaxProtectionSection::Public; else if (sectionTypeName == "protected") sectionType = SyntaxProtectionSection::Protected; newClass->mBaseClasses.push_back(SyntaxClassInheritance(baseClassName, sectionType)); } } } int dataLength = (int)section.mData.length(); if (caret < dataLength && section.mData[caret] == '/') { string comment = ReadWord(section.mData, caret, "\n"); ReadWord(section.mData, caret, ";{/"); } if (caret < dataLength && section.mData[caret] == '{') { string block = ReadBlock(section.mData, caret); newClass->mData = Trim(block, "{} \n\r\t"); section.mSections.push_back(newClass); // For class, default protection is Private; for struct, it's Public SyntaxProtectionSection initialProtection = isClass ? SyntaxProtectionSection::Private : SyntaxProtectionSection::Public; ParseSyntaxSection(*newClass, newClass->mData, *newClass->mFile, initialProtection); } } void CppSyntaxParser::ParseTemplate(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { caret += (int)strlen("template"); int dataLen = (int)section.mData.length(); for (; caret < dataLen; caret++) if (section.mData[caret] == '<') break; caret++; int braces = 1; int begin = caret; for (; caret < dataLen; caret++) { if (section.mData[caret] == '<') braces++; if (section.mData[caret] == '>') { braces--; if (braces == 0) break; } } string tempInside = section.mData.substr(begin, caret - begin); int tmpCaret = caret + 1; string blockRaw = ReadBlock(section.mData, tmpCaret); string block = Trim(blockRaw, " \n\r\t"); if (StartsWith(block, "class")) { caret = (int)section.mData.find("class", caret + 1); ParseClassOrStruct(section, caret, protectionSection, true, false, tempInside); } else if (StartsWith(block, "struct")) { caret = (int)section.mData.find("struct", caret + 1); ParseClassOrStruct(section, caret, protectionSection, false, false, tempInside); } else if (StartsWith(block, "metaclass")) { caret = (int)section.mData.find("metaclass", caret + 1); ParseClassOrStruct(section, caret, protectionSection, true, true, tempInside); } else if (StartsWith(block, "friend")) { caret = (int)section.mData.find("friend", caret + 1); ParseFriend(section, caret, protectionSection); } else if (IsFunction(block)) { auto func = ParseFunction(block, protectionSection, 0, (int)block.length()); func->mTemplates = tempInside; func->mFile = section.mFile; func->mLine = GetLineNumber(section.mData, caret); section.mFunctions.push_back(func); caret = tmpCaret; } else caret = tmpCaret; } void CppSyntaxParser::ParseTypedef(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { int begin = caret; caret += (int)strlen("typedef"); string word = ReadWord(section.mData, caret, ";"); string temp = Trim(word, " \r\n\t"); int lastSpace = (int)temp.rfind(' '); string valueRaw = temp.substr(0, lastSpace); string value = Trim(valueRaw, " \r\t\n"); string nameRaw = temp.substr(lastSpace + 1); string name = Trim(nameRaw, " \r\t\n;"); if (StartsWith(value, "typename")) value.erase(0, strlen("typename ")); SyntaxTypedef* synTypedef = new SyntaxTypedef(); synTypedef->mBegin = begin; synTypedef->mLength = caret - begin; synTypedef->mLine = GetLineNumber(section.mData, caret); synTypedef->mData = section.mData.substr(begin, caret - begin); synTypedef->mWhatName = value; synTypedef->mNewDefName = name; section.mTypedefs.push_back(synTypedef); } void CppSyntaxParser::ParseEnum(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { int begin = caret; caret += (int)strlen("enum"); string name = ReadWord(section.mData, caret); if (name == "class") name = ReadWord(section.mData, caret); string blockRaw = ReadBlock(section.mData, caret); string block = Trim(blockRaw, " {}\r\t\n"); RemoveComments(block); auto content = Split(block, ','); SyntaxEnum* newEnum = new SyntaxEnum(); newEnum->mBegin = begin; newEnum->mLength = caret - begin; newEnum->mLine = GetLineNumber(section.mData, caret); newEnum->mData = section.mData.substr(begin, caret - begin); newEnum->mName = name; newEnum->mFullName = section.GetFullName().empty() ? name : section.GetFullName() + "::" + name; newEnum->mFile = section.mFile; newEnum->mOwnerSection = §ion; newEnum->mClassSection = protectionSection; for (auto& x : content) { Trim(x, " \n\t\r"); string name, value; int valuePos = (int)x.find('='); if (valuePos != x.npos) { string sub = x.substr(0, valuePos); name = Trim(sub, " \n\t\r"); string sub2 = x.substr(valuePos + 1); value = Trim(sub2, " \n\t\r"); } else name = x; newEnum->mEntries[name] = value; } section.mEnums.push_back(newEnum); } void CppSyntaxParser::ParseUsing(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { int begin = caret; caret += (int)strlen("using"); int tmpCaret = caret; string allWord = ReadWord(section.mData, tmpCaret, ";"); if (allWord.find(':') != string::npos) { caret = tmpCaret + 1; return; } ReadWord(section.mData, caret); string word = ReadWord(section.mData, caret); string name = Trim(word, " \r\n;"); SyntaxUsingNamespace* newUsing = new SyntaxUsingNamespace(); newUsing->mBegin = begin; newUsing->mLength = caret - begin; newUsing->mLine = GetLineNumber(section.mData, caret); newUsing->mData = section.mData.substr(begin, caret - caret); newUsing->mUsingNamespaceName = name; section.mUsingNamespaces.push_back(newUsing); } void CppSyntaxParser::ParsePublicSection(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { caret += (int)strlen("public:"); protectionSection = SyntaxProtectionSection::Public; } void CppSyntaxParser::ParsePrivateSection(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { caret += (int)strlen("private:"); protectionSection = SyntaxProtectionSection::Private; } void CppSyntaxParser::ParseProtectedSection(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { caret += (int)strlen("protected:"); protectionSection = SyntaxProtectionSection::Protected; } void CppSyntaxParser::ParseFriend(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { caret += (int)strlen("friend"); ReadWord(section.mData, caret, " \n\r\t"); ReadWord(section.mData, caret, " \n\r\t"); } void CppSyntaxParser::ParseAttributeCommentDef(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { SyntaxClass* classSection = dynamic_cast(§ion); caret += (int)strlen("ATTRIBUTE_COMMENT_DEFINITION"); caret = (int)section.mData.find('"', caret) + 1; int begin = caret; caret = (int)section.mData.find('"', caret); classSection->mAttributeCommentDef = section.mData.substr(begin, caret - begin); caret = (int)section.mData.find(';', caret) + 1; } void CppSyntaxParser::ParseAttributeShortDef(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { SyntaxClass* classSection = dynamic_cast(§ion); caret += (int)strlen("ATTRIBUTE_SHORT_DEFINITION"); caret = (int)section.mData.find('"', caret) + 1; int begin = caret; caret = (int)section.mData.find('"', caret); classSection->mAttributeShortDef = section.mData.substr(begin, caret - begin); caret = (int)section.mData.find(';', caret) + 1; } void CppSyntaxParser::ParseAttributes(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { int begin = caret; caret += (int)strlen("ATTRIBUTES"); caret = (int)section.mData.find('(', caret) + 1; string bracesRaw = ReadBraces(section.mData, caret); string braces = Trim(bracesRaw, " \n\r\t()"); caret = (int)section.mData.find(';', caret); vector separated = Split(braces, ','); for (auto& x : separated) Trim(x, " \n\r\t,"); SyntaxAttributes* attributes = new SyntaxAttributes(); attributes->mBegin = begin; attributes->mLength = caret - begin; attributes->mLine = GetLineNumber(section.mData, caret); attributes->mData = section.mData.substr(begin, caret - caret); attributes->mAttributesList = separated; section.mAttributes.push_back(attributes); } void CppSyntaxParser::ParseProperties(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { caret += (int)strlen("PROPERTIES"); caret = (int)section.mData.find('(', caret); string bracesRaw = ReadBraces(section.mData, caret); string braces = Trim(bracesRaw, " \n\r\t()"); caret = (int)section.mData.find(';', caret); } void CppSyntaxParser::ParseProperty(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { int begin = caret; caret += (int)strlen("PROPERTY"); caret = (int)section.mData.find('(', caret); string bracesRaw = ReadBraces(section.mData, caret); string braces = Trim(bracesRaw, " \n\r\t()"); caret = (int)section.mData.find(';', caret); vector separated = Split(braces, ','); for (auto& x : separated) Trim(x, " \n\r\t,"); SyntaxVariable* res = new SyntaxVariable(); res->mBegin = begin; res->mLength = caret - begin; res->mData = section.mData.substr(begin, caret - caret); res->mLine = GetLineNumber(section.mData, caret); res->mName = separated[1]; res->mType.mName = separated[0]; if (mCurrentDefine) res->mDefine = mCurrentDefine; section.mVariables.push_back(res); } void CppSyntaxParser::ParseGetter(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { int begin = caret; caret += (int)strlen("GETTER"); caret = (int)section.mData.find('(', caret); string bracesRaw = ReadBraces(section.mData, caret); ReadBraces(section.mData, caret); string braces = Trim(bracesRaw, " \n\r\t()"); caret = (int)section.mData.find(';', caret); vector separated = Split(braces, ','); for (auto& x : separated) Trim(x, " \n\r\t,"); SyntaxVariable* res = new SyntaxVariable(); res->mBegin = begin; res->mLength = caret - begin; res->mData = section.mData.substr(begin, caret - caret); res->mLine = GetLineNumber(section.mData, caret); res->mName = separated[1]; res->mType.mName = separated[0]; if (mCurrentDefine) res->mDefine = mCurrentDefine; section.mVariables.push_back(res); } void CppSyntaxParser::ParseSetter(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { int begin = caret; caret += (int)strlen("SETTER"); caret = (int)section.mData.find('(', caret); string bracesRaw = ReadBraces(section.mData, caret); string braces = Trim(bracesRaw, " \n\r\t()"); caret = (int)section.mData.find(';', caret); vector separated = Split(braces, ','); for (auto& x : separated) Trim(x, " \n\r\t,"); SyntaxVariable* res = new SyntaxVariable(); res->mBegin = begin; res->mLength = caret - begin; res->mData = section.mData.substr(begin, caret - caret); res->mLine = GetLineNumber(section.mData, caret); res->mName = separated[1]; res->mType.mName = separated[0]; if (mCurrentDefine) res->mDefine = mCurrentDefine; section.mVariables.push_back(res); } void CppSyntaxParser::ParseAccessor(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection) { int begin = caret; caret += (int)strlen("ACCESSOR"); caret = (int)section.mData.find('(', caret); string bracesRaw = ReadBraces(section.mData, caret); string braces = Trim(bracesRaw, " \n\r\t()"); caret = (int)section.mData.find(';', caret); vector separated = Split(braces, ','); for (auto& x : separated) Trim(x, " \n\r\t,"); SyntaxVariable* res = new SyntaxVariable(); res->mBegin = begin; res->mLength = caret - begin; res->mData = section.mData.substr(begin, caret - caret); res->mLine = GetLineNumber(section.mData, caret); res->mName = separated[1]; res->mType.mName = separated[0]; if (mCurrentDefine) res->mDefine = mCurrentDefine; section.mVariables.push_back(res); } string CppSyntaxParser::ReadWord(const string& data, int& caret, const char* breakSymbols /*= " \n\r(){}.,;+-* /=@!|&*:~\\"*/, const char* skipSymbols /*= " \n\r"*/, bool checkBraces /*= true*/, bool checkFgBraces /*= true*/, bool checkTrBraces /*= true*/) { string res = ""; int braces = 0, sqBraces = 0, trBraces = 0, fgBraces = 0; int dataLen = (int)data.length(); for (; caret < dataLen; caret++) { int i = 0; bool stop = true; char s = data[caret]; while (skipSymbols[i] != '\0') { if (skipSymbols[i] == s) { stop = false; break; } i++; } if (stop) break; } for (; caret < dataLen; caret++) { int i = 0; bool stop = false; char s = data[caret]; if ((fgBraces == 0 || !checkFgBraces) && (braces == 0 || !checkBraces) && (trBraces == 0 || !checkTrBraces)) { while (breakSymbols[i] != '\0') { if (breakSymbols[i] == s) { stop = true; break; } i++; } if (stop) break; } switch (s) { case '{': fgBraces++; break; case '}': fgBraces--; if (fgBraces < 0) fgBraces = 0; break; case ')': braces--; if (braces < 0) braces = 0; break; case '(': braces++; break; case '[': sqBraces++; break; case ']': sqBraces--; if (sqBraces < 0) sqBraces = 0; break; case '<': trBraces++; break; case '>': trBraces--; if (trBraces < 0) trBraces = 0; break; } res += s; } return res; } string CppSyntaxParser::ReadBlock(const string& data, int& caret) { int begin = caret; int braces = 0, fgBraces = 0, sqBraces = 0, trBraces = 0; bool isInstring = false; int dataLen = (int)data.length(); for (; caret < dataLen; caret++) { if (data[caret] == '{') break; if (data[caret] == ';') return data.substr(begin, caret - begin); } caret++; fgBraces++; bool complete = false; for (; caret < dataLen && !complete; caret++) { if (isInstring) { if (data[caret] == '"' && data[caret - 1] != '\\') isInstring = false; continue; } switch (data[caret]) { case '{': fgBraces++; break; case '}': fgBraces--; if (fgBraces == 0 && braces == 0 && sqBraces == 0) complete = true; break; case ')': braces--; break; case '(': braces++; break; case '[': sqBraces++; break; case ']': sqBraces--; break; case '<': trBraces++; break; case '>': trBraces--; break; case '"': isInstring = true; break; } } return data.substr(begin, min(caret, dataLen - 1) - begin); } string CppSyntaxParser::ReadBraces(const string& data, int& caret) { int begin = caret; int braces = 0, fgBraces = 0, sqBraces = 0, trBraces = 0; bool isInstring = false; int dataLen = (int)data.length(); for (; caret < dataLen; caret++) { if (data[caret] == '(') break; if (data[caret] == ';') return data.substr(begin, caret - begin); } caret++; braces++; bool complete = false; for (; caret < dataLen && !complete; caret++) { if (isInstring) { if (data[caret] == '"' && data[caret - 1] != '\\') isInstring = false; continue; } switch (data[caret]) { case '}': fgBraces--; break; case '{': fgBraces++; break; case '[': sqBraces++; break; case ']': sqBraces--; break; case '<': trBraces++; break; case '>': trBraces--; break; case '(': braces++; break; case ')': braces--; if (fgBraces == 0 && braces == 0 && sqBraces == 0 && trBraces == 0) complete = true; break; case '"': isInstring = true; break; } } string res = data.substr(begin, min(caret, dataLen) - begin); int resLen = (int)res.length(); if (!res.empty() && res[resLen - 1] == ')') res.erase(resLen - 1, 1); if (!res.empty() && res[0] == '(') res.erase(0, 1); return res; } char CppSyntaxParser::GetNextSymbol(const string& data, int begin, const char* skipSymbols /*= " \n\r\t()[]{}"*/) { int dataLen = (int)data.length(); for (; begin < dataLen; begin++) { int i = 0; bool stop = true; char s = data[begin]; while (skipSymbols[i] != '\0') { if (skipSymbols[i] == s) { stop = false; break; } i++; } if (stop) return s; } return '\0'; } vector CppSyntaxParser::Split(const string& data, char splitSymbol) { vector res; int braces = 0, sqBraces = 0, trBraces = 0, fgBraces = 0; int dataLen = (int)data.length(); int lastSplit = 0; for (int i = 0; i < dataLen; i++) { switch (data[i]) { case '{': fgBraces++; break; case '}': fgBraces--; break; case '(': braces++; break; case ')': braces--; break; case '<': trBraces++; break; case '>': trBraces--; break; case '[': sqBraces++; break; case ']': sqBraces--; break; } if (braces == 0 && sqBraces == 0 && trBraces == 0 && fgBraces == 0 && data[i] == splitSymbol) { res.push_back(data.substr(lastSplit, i - lastSplit)); lastSplit = i + 1; } } res.push_back(data.substr(lastSplit)); return res; } void CppSyntaxParser::RemoveComments(string& input) { size_t p; do { p = input.find("/*"); if (p == string::npos) break; size_t end = input.find("*/", p); if (end == string::npos) end = input.length(); else end += 2; input.erase(p, end - p); } while (p != string::npos); do { p = input.find("//"); if (p == string::npos) break; size_t end = input.find('\n', p); if (end == string::npos) end = input.length(); else end++; input.erase(p, end - p); } while (p != string::npos); } CppSyntaxParser::ExpressionParser::ExpressionParser(const char* keyWord, ParserDelegate parser, bool isPossibleInClass /*= true*/, bool isPossibleInNamespace /*= true*/) : keyWord(keyWord), parser(parser), isPossibleInClass(isPossibleInClass), isPossibleInNamespace(isPossibleInNamespace) {} ================================================ FILE: CodeTool/Src/CppSyntaxParser.h ================================================ #pragma once #include "SyntaxTree.h" bool EndsWith(const string& str, const string& ends); bool StartsWith(const string& str, const string& starts); string& Trim(string& str, const string& chars = " "); string& TrimEnd(string& str, const string& chars = " "); string& TrimStart(string& str, const string& chars = " "); void Split(const string& s, char delim, vector& elems); vector Split(const string& s, char delim); class CppSyntaxParser { public: CppSyntaxParser(); ~CppSyntaxParser(); void ParseFile(SyntaxFile& file, const string& filePath, const TimeStamp& fileEditDate); protected: typedef void(CppSyntaxParser::* ParserDelegate)(SyntaxSection&, int&, SyntaxProtectionSection&); struct ExpressionParser { const char* keyWord = nullptr; bool isPossibleInClass = true; bool isPossibleInNamespace = true; ParserDelegate parser; ExpressionParser() {} ExpressionParser(const char* keyWord, ParserDelegate parser, bool isPossibleInClass = true, bool isPossibleInNamespace = true); }; typedef vector ParsersVec; protected: string mSourcesPath; ParsersVec mParsers; SyntaxDefineIf* mCurrentDefine = nullptr; protected: void InitializeParsers(); void ParseSyntaxSection(SyntaxSection& section, const string& source, SyntaxFile& file, SyntaxProtectionSection protectionSection); int GetLineNumber(const string& data, int caret); string ReadWord(const string& data, int& caret, const char* breakSymbols = " \n\r(){}.,;+-*/=@!|&*:~\\", const char* skipSymbols = " \n\r", bool checkBraces = true, bool checkFgBraces = true, bool checkTrBraces = true); string ReadBlock(const string& data, int& caret); string ReadBraces(const string& data, int& caret); char GetNextSymbol(const string& data, int begin, const char* skipSymbols = " \n\r\t()[]{}"); vector Split(const string& data, char splitSymbol); void RemoveComments(string& input); void TryParseBlock(SyntaxSection& section, const string& block, int blockBegin, int& caret, SyntaxProtectionSection& protectionSection); bool IsFunction(const string& data); SyntaxVariable* ParseVariable(const string& data, SyntaxProtectionSection& protectionSection, int begin, int end); SyntaxFunction* ParseFunction(const string& data, SyntaxProtectionSection& protectionSection, int begin, int end); void ParseNamespace(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseComment(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseMultilineComment(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParsePragma(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseInclude(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseDefine(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseUndef(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseIfdefMacros(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseIfMacros(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseEndIfMacros(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseElifMacros(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseElseMacros(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseMetaClass(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseClass(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseStruct(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseClassOrStruct(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection, bool isClass, bool isMeta, const string& templates); void ParseTemplate(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseTypedef(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseEnum(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseUsing(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParsePublicSection(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParsePrivateSection(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseProtectedSection(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseFriend(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseAttributeCommentDef(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseAttributeShortDef(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseAttributes(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseProperties(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseProperty(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseGetter(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseSetter(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); void ParseAccessor(SyntaxSection& section, int& caret, SyntaxProtectionSection& protectionSection); }; ================================================ FILE: CodeTool/Src/SyntaxTree.cpp ================================================ #include "SyntaxTree.h" #include SyntaxFile::SyntaxFile(): mGlobalNamespace(new SyntaxNamespace()) {} SyntaxFile::~SyntaxFile() { delete mGlobalNamespace; } const string& SyntaxFile::GetPath() const { return mPath; } const string& SyntaxFile::GetData() const { return mData; } const TimeStamp& SyntaxFile::GetLastEditedDate() const { return mLastEditedDate; } SyntaxNamespace* SyntaxFile::GetGlobalNamespace() const { return mGlobalNamespace; } void SyntaxFile::SaveTo(pugi::xml_node& node) const { node.append_attribute("path") = mPath.c_str(); auto date = node.append_child("date"); mLastEditedDate.SaveTo(date); auto globalNamespace = node.append_child("globalNamespace"); mGlobalNamespace->SaveTo(globalNamespace); } void SyntaxFile::LoadFrom(const pugi::xml_node& node) { mPath = node.attribute("path").as_string(); mLastEditedDate.LoadFrom(node.child("date")); delete mGlobalNamespace; mGlobalNamespace = new SyntaxNamespace(); mGlobalNamespace->LoadFrom(node.child("globalNamespace")); } int ISyntaxExpression::GetBegin() const { return mBegin; } int ISyntaxExpression::GetLength() const { return mLength; } int ISyntaxExpression::GetEnd() const { return mBegin + mLength; } int ISyntaxExpression::GetLine() const { return mLine; } const string& ISyntaxExpression::GetData() const { return mData; } SyntaxFile* ISyntaxExpression::GetOwnerFile() const { return mFile; } SyntaxDefineIf* ISyntaxExpression::GetDefine() const { return mDefine; } SyntaxSection::SyntaxSection() {} SyntaxSection::~SyntaxSection() { // for (auto x : mFunctions) // delete x; // // for (auto x : mVariables) // delete x; // // for (auto x : mEnums) // delete x; // // for (auto x : mSections) // delete x; // // for (auto x : mComments) // delete x; // // for (auto x : mTypedefs) // delete x; // // for (auto x : mUsingNamespaces) // delete x; // // for (auto x : mDefines) // delete x; } SyntaxSection* SyntaxSection::GetParentSection() const { return mParentSection; } const string& SyntaxSection::GetName() const { return mName; } const string& SyntaxSection::GetFullName() const { return mFullName; } const SyntaxFunctionsVec& SyntaxSection::GetFunctions() const { return mFunctions; } const SyntaxVariablesVec& SyntaxSection::GetVariables() const { return mVariables; } const SyntaxSectionsVec& SyntaxSection::GetSections() const { return mSections; } const SyntaxEnumsVec& SyntaxSection::GetEnums() const { return mEnums; } const SyntaxTypedefsVec& SyntaxSection::GetTypedefs() const { return mTypedefs; } const SyntaxUsingNamespacesVec& SyntaxSection::GetUsingNamespaces() const { return mUsingNamespaces; } const SyntaxCommentsVec& SyntaxSection::GetComments() const { return mComments; } SyntaxComment* SyntaxSection::FindCommentNearLine(int line) const { SyntaxComment* synComment = nullptr; for (auto comment : mComments) { // comment is on same line as variable if (comment->GetLine() == line) { synComment = comment; break; } // comment is on up line to variable if (comment->GetLine() == line - 1) { // check other variable on this line bool success = true; for (auto v :mVariables) { if (v->GetLine() == comment->GetLine()) { success = false; break; } } if (success) { synComment = comment; break; } } } return synComment; } SyntaxSectionsVec SyntaxSection::GetAllSections() const { SyntaxSectionsVec res = mSections; for (auto x : mSections) { for (auto y : x->GetAllSections()) res.push_back(y); } return res; } SyntaxClassesVec SyntaxSection::GetAllClasses() const { SyntaxClassesVec res; for (auto x : mSections) { if (x->IsClass()) res.push_back(dynamic_cast(x)); } for (auto x : mSections) { for (auto y : x->GetAllClasses()) res.push_back(y); } return res; } SyntaxEnumsVec SyntaxSection::GetAllEnums() const { SyntaxEnumsVec res = mEnums; for (auto x : mSections) { for (auto y : x->GetAllEnums()) res.push_back(y); } return res; } bool SyntaxSection::IsClass() const { return false; } const SyntaxAttributesVec& SyntaxSection::GetAttributes() const { return mAttributes; } void SyntaxSection::SaveTo(pugi::xml_node& node) const { node.append_attribute("name") = mName.c_str(); node.append_attribute("fullname") = mFullName.c_str(); pugi::xml_node sectionsNode = node.append_child("sections"); for (auto x : mSections) { auto section = sectionsNode.append_child("section"); x->SaveTo(section); } pugi::xml_node typedefsNode = node.append_child("typedefs"); for (auto x : mTypedefs) { auto td = typedefsNode.append_child("typedef"); x->SaveTo(td); } pugi::xml_node usingsNode = node.append_child("usings"); for (auto x : mUsingNamespaces) { auto td = usingsNode.append_child("typedef"); x->SaveTo(td); } } void SyntaxSection::LoadFrom(const pugi::xml_node& node) { mName = node.attribute("name").as_string(); mFullName = node.attribute("fullname").as_string(); pugi::xml_node sectionsNode = node.child("sections"); for (auto node:sectionsNode) { if (node.type() != pugi::node_element) continue; SyntaxSection* newSection; if (node.attribute("isClass")) newSection = new SyntaxClass(); else newSection = new SyntaxNamespace(); newSection->LoadFrom(node); newSection->mParentSection = this; mSections.push_back(newSection); } pugi::xml_node typedefsNode = node.child("typedefs"); for (auto node:typedefsNode) { if (node.type() != pugi::node_element) continue; SyntaxTypedef* newTypedef = new SyntaxTypedef(); newTypedef->LoadFrom(node); mTypedefs.push_back(newTypedef); } pugi::xml_node usingsNode = node.child("usings"); for (auto node:usingsNode) { if (node.type() != pugi::node_element) continue; SyntaxUsingNamespace* newUsing = new SyntaxUsingNamespace(); newUsing->LoadFrom(node); mUsingNamespaces.push_back(newUsing); } } SyntaxNamespace::SyntaxNamespace() {} const SyntaxFunctionsVec& SyntaxClass::GetFunctions() const { if (mSourceClass) return mSourceClass->GetFunctions(); return SyntaxSection::GetFunctions(); } const SyntaxVariablesVec& SyntaxClass::GetVariables() const { if (mSourceClass) return mSourceClass->GetVariables(); return SyntaxSection::GetVariables(); } const SyntaxSectionsVec& SyntaxClass::GetSections() const { if (mSourceClass) return mSourceClass->GetSections(); return SyntaxSection::GetSections(); } const SyntaxEnumsVec& SyntaxClass::GetEnums() const { if (mSourceClass) return mSourceClass->GetEnums(); return SyntaxSection::GetEnums(); } const SyntaxTypedefsVec& SyntaxClass::GetTypedefs() const { if (mSourceClass) return mSourceClass->GetTypedefs(); return SyntaxSection::GetTypedefs(); } const SyntaxUsingNamespacesVec& SyntaxClass::GetUsingNamespaces() const { if (mSourceClass) return mSourceClass->GetUsingNamespaces(); return SyntaxSection::GetUsingNamespaces(); } SyntaxSectionsVec SyntaxClass::GetAllSections() const { if (mSourceClass) return mSourceClass->GetAllSections(); return SyntaxSection::GetAllSections(); } SyntaxClassesVec SyntaxClass::GetAllClasses() const { if (mSourceClass) return mSourceClass->GetAllClasses(); return SyntaxSection::GetAllClasses(); } bool SyntaxClass::IsClass() const { return true; } const SyntaxClassInheritancsVec& SyntaxClass::GetBaseClasses() const { return mBaseClasses; } bool SyntaxClass::IsTemplate() const { if (!mTemplateParameters.empty()) return true; if (mParentSection) { SyntaxClass* cls = dynamic_cast(mParentSection); return cls && cls->IsTemplate(); } return false; } bool SyntaxClass::IsMetaClass() const { return mIsMeta; } const string& SyntaxClass::GetTemplateParameters() const { return mTemplateParameters; } SyntaxProtectionSection SyntaxClass::GetClassSection() const { return mClassSection; } const string& SyntaxClass::GetAttributeCommentDef() const { return mAttributeCommentDef; } const string& SyntaxClass::GetAttributeShortDef() const { return mAttributeShortDef; } const SyntaxAttributesVec& SyntaxClass::GetAttributes() const { if (mSourceClass) return mSourceClass->GetAttributes(); return SyntaxSection::GetAttributes(); } void SyntaxClass::SaveTo(pugi::xml_node& node) const { SyntaxSection::SaveTo(node); node.append_attribute("isClass") = true; node.append_attribute("isMeta") = mIsMeta; node.append_attribute("templates") = mTemplateParameters.c_str(); node.append_attribute("protection") = (int)mClassSection; node.append_attribute("attributeCommentDef") = mAttributeCommentDef.c_str(); node.append_attribute("attributeShortDef") = mAttributeShortDef.c_str(); pugi::xml_node baseClassesNode = node.append_child("baseClasses"); for (auto& x : mBaseClasses) { auto nc = baseClassesNode.append_child("class"); x.SaveTo(nc); } } void SyntaxClass::LoadFrom(const pugi::xml_node& node) { SyntaxSection::LoadFrom(node); mIsMeta = node.attribute("isMeta").as_bool(); mTemplateParameters = node.attribute("templates").as_string(); mClassSection = (SyntaxProtectionSection)node.attribute("protection").as_int(); mAttributeCommentDef = node.attribute("attributeCommentDef").as_string(); mAttributeShortDef = node.attribute("attributeShortDef").as_string(); pugi::xml_node baseClassesNode = node.child("baseClasses"); for (auto node : baseClassesNode) { SyntaxClassInheritance x; x.LoadFrom(node); mBaseClasses.push_back(x); } } const string& SyntaxType::GetName() const { return mName; } bool SyntaxType::IsConstant() const { return mIsContant; } bool SyntaxType::IsReference() const { return mIsReference; } bool SyntaxType::IsPointer() const { return mIsPointer; } const SyntaxType& SyntaxVariable::GetVariableType() const { return mType; } const string& SyntaxVariable::GetName() const { return mName; } const std::string& SyntaxVariable::GetDefaultValue() const { return mDefaultValue; } SyntaxProtectionSection SyntaxVariable::GetClassSection() const { return mClassSection; } bool SyntaxVariable::IsStatic() const { return mIsStatic; } SyntaxFunction::SyntaxFunction() {} SyntaxFunction::~SyntaxFunction() { for (auto x : mParameters) delete x; } const SyntaxType& SyntaxFunction::GetReturnType() const { return mReturnType; } const string& SyntaxFunction::GetName() const { return mName; } const SyntaxVariablesVec& SyntaxFunction::GetParameters() const { return mParameters; } SyntaxProtectionSection SyntaxFunction::GetClassSection() const { return mClassSection; } bool SyntaxFunction::IsTemplate() const { return !mTemplates.empty(); } const string& SyntaxFunction::GetTemplates() const { return mTemplates; } bool SyntaxFunction::IsStatic() const { return mIsStatic; } const string& SyntaxEnum::GetName() const { return mName; } const string& SyntaxEnum::GetFullName() const { return mFullName; } const StringStringDict& SyntaxEnum::GetEntries() const { return mEntries; } SyntaxProtectionSection SyntaxEnum::GetClassSection() const { return mClassSection; } SyntaxSection* SyntaxEnum::GetOwnerSyntaxSection() const { return mOwnerSection; } SyntaxClassInheritance::SyntaxClassInheritance(const string& className, SyntaxProtectionSection type): mClassName(className), mInheritanceType(type) {} const string& SyntaxClassInheritance::GetClassName() const { return mClassName; } SyntaxClass* SyntaxClassInheritance::GetClass() { return mClass; } SyntaxProtectionSection SyntaxClassInheritance::GetInheritanceType() const { return mInheritanceType; } void SyntaxClassInheritance::SaveTo(pugi::xml_node& node) const { node.append_attribute("name") = mClassName.c_str(); node.append_attribute("protection") = (int)mInheritanceType; } void SyntaxClassInheritance::LoadFrom(const pugi::xml_node& node) { mClassName = node.attribute("name").as_string(); mInheritanceType = (SyntaxProtectionSection)node.attribute("protection").as_int(); } bool SyntaxClassInheritance::operator==(const SyntaxClassInheritance& other) const { return mInheritanceType == other.mInheritanceType && mClassName == other.mClassName; } const string& SyntaxUsingNamespace::GetUsingNamespaceName() const { return mUsingNamespaceName; } SyntaxSection* SyntaxUsingNamespace::GetUsingNamespace() const { return mUsingNamespace; } void SyntaxUsingNamespace::SaveTo(pugi::xml_node& node) const { node.append_attribute("name") = mUsingNamespaceName.c_str(); } void SyntaxUsingNamespace::LoadFrom(const pugi::xml_node& node) { mUsingNamespaceName = node.attribute("name").as_string(); } const string& SyntaxTypedef::GetWhatName() const { return mWhatName; } const string& SyntaxTypedef::GetNewDefName() const { return mNewDefName; } SyntaxSection* SyntaxTypedef::GetWhat() const { return mWhatSection; } SyntaxSection* SyntaxTypedef::GetNewDef() const { return mWhatSection; } void SyntaxTypedef::SaveTo(pugi::xml_node& node) const { node.append_attribute("what") = mWhatName.c_str(); node.append_attribute("newDef") = mNewDefName.c_str(); } void SyntaxTypedef::LoadFrom(const pugi::xml_node& node) { mWhatName = node.attribute("what").as_string(); mNewDefName = node.attribute("newDef").as_string(); } TimeStamp::TimeStamp(int seconds /*= 0*/, int minutes /*= 0*/, int hours /*= 0*/, int days /*= 0*/, int months /*= 0*/, int years /*= 0*/): second(seconds), minute(minutes), hour(hours), day(days), month(months), year(years) {} void TimeStamp::SaveTo(pugi::xml_node& node) const { node.append_attribute("year") = year; node.append_attribute("month") = month; node.append_attribute("day") = day; node.append_attribute("hour") = hour; node.append_attribute("minute") = minute; node.append_attribute("second") = second; } void TimeStamp::LoadFrom(const pugi::xml_node& node) { year = node.attribute("year").as_int(); month = node.attribute("month").as_int(); day = node.attribute("day").as_int(); hour = node.attribute("hour").as_int(); minute = node.attribute("minute").as_int(); second = node.attribute("second").as_int(); } bool TimeStamp::operator!=(const TimeStamp& wt) const { return !(*this == wt); } bool TimeStamp::operator==(const TimeStamp& wt) const { return second == wt.second && minute == wt.minute && hour == wt.hour && day == wt.day && month == wt.month && year == wt.year; } const vector& SyntaxAttributes::GetAttributesList() const { return mAttributesList; } const std::string& SyntaxDefineIf::GetDefinition() const { return mDefintion; } ================================================ FILE: CodeTool/Src/SyntaxTree.h ================================================ #pragma once #include #include #include #include "pugixml/pugixml.hpp" #undef GetClassName using namespace std; class SyntaxAttributes; class SyntaxClass; class SyntaxClassInheritance; class SyntaxComment; class SyntaxEnum; class SyntaxFile; class SyntaxFunction; class SyntaxNamespace; class SyntaxSection; class SyntaxType; class SyntaxTypedef; class SyntaxUsingNamespace; class SyntaxVariable; class SyntaxDefineIf; typedef map StringStringDict; typedef vector SyntaxAttributesVec; typedef vector SyntaxClassesVec; typedef vector SyntaxCommentsVec; typedef vector SyntaxEnumsVec; typedef vector SyntaxFilesVec; typedef vector SyntaxFunctionsVec; typedef vector SyntaxSectionsVec; typedef vector SyntaxTypedefsVec; typedef vector SyntaxUsingNamespacesVec; typedef vector SyntaxVariablesVec; typedef vector SyntaxDefinesVec; typedef vector StringsVec; enum class SyntaxProtectionSection { Public, Private, Protected }; // Date time stamp struct TimeStamp { int year, month, day, hour, minute, second; TimeStamp(int seconds = 0, int minutes = 0, int hours = 0, int days = 0, int months = 0, int years = 0); bool operator==(const TimeStamp& wt) const; bool operator!=(const TimeStamp& wt) const; // Saves data to xml node void SaveTo(pugi::xml_node& node) const; // Loads data from xml node void LoadFrom(const pugi::xml_node& node); }; // Abstract syntax tree file class SyntaxFile { public: // Default constructor SyntaxFile(); // Destructor ~SyntaxFile(); // Returns file path const string& GetPath() const; // Returns file's data const string& GetData() const; // Returns file last edit date const TimeStamp& GetLastEditedDate() const; // Returns global syntax namespace in this file SyntaxNamespace* GetGlobalNamespace() const; // Saves data to xml node void SaveTo(pugi::xml_node& node) const; // Loads data from xml node void LoadFrom(const pugi::xml_node& node); protected: string mPath; // File path string mData; // File data TimeStamp mLastEditedDate; // Last file edited date SyntaxNamespace* mGlobalNamespace = nullptr; // Global syntax namespace in file friend class CppSyntaxParser; friend class CodeToolApplication; }; // Syntax expression base class ISyntaxExpression { public: // Returns start of expression in owner file data int GetBegin() const; // Returns length of expression text int GetLength() const; // Returns end of expression int GetEnd() const; // Returns line of expression int GetLine() const; // Returns expression text const string& GetData() const; // Returns pointer to owner file SyntaxFile* GetOwnerFile() const; // Returns pointer to owner define SyntaxDefineIf* GetDefine() const; protected: int mBegin = 0; // Data begin position int mLength = 0; // Data length int mLine = 0; // Data line number string mData; // Expression text SyntaxFile* mFile = nullptr; // Owner file SyntaxDefineIf* mDefine = nullptr; // Owner define friend class CppSyntaxParser; }; // Syntax single/multiline comment class SyntaxComment: public ISyntaxExpression { }; // Syntax using namespace ... class SyntaxUsingNamespace: public ISyntaxExpression { public: // Returns using namespace name const string& GetUsingNamespaceName() const; // Returns using namespace (if found) SyntaxSection* GetUsingNamespace() const; // Saves data to xml node void SaveTo(pugi::xml_node& node) const; // Loads data from xml node void LoadFrom(const pugi::xml_node& node); protected: string mUsingNamespaceName; // Using namespace name SyntaxSection* mUsingNamespace = nullptr; // Using namespace (if found) friend class CodeToolCache; friend class CppSyntaxParser; }; // Syntax typedef X Y; class SyntaxTypedef: public ISyntaxExpression { public: // Returns what was defined (X) const string& GetWhatName() const; // Returns new defined name (Y) const string& GetNewDefName() const; // Returns what was defined (X) SyntaxSection* GetWhat() const; // Returns new defined name (Y) SyntaxSection* GetNewDef() const; // Saves data to xml node void SaveTo(pugi::xml_node& node) const; // Loads data from xml node void LoadFrom(const pugi::xml_node& node); protected: string mWhatName; // What was used to defined name (X) string mNewDefName; // What was new defined name (Y) SyntaxSection* mWhatSection = nullptr; // What section used to define (X) friend class CodeToolCache; friend class CppSyntaxParser; }; // Syntax names section, base for namespaces or classes class SyntaxSection: public ISyntaxExpression { public: // Default constructor SyntaxSection(); // Destructor ~SyntaxSection(); // Returns parent section virtual SyntaxSection* GetParentSection() const; // Returns section name virtual const string& GetName() const; // Returns full section name including all parent names (something like A::B::C) virtual const string& GetFullName() const; // Returns array of functions virtual const SyntaxFunctionsVec& GetFunctions() const; // Returns array of variables virtual const SyntaxVariablesVec& GetVariables() const; // Returns nested sections virtual const SyntaxSectionsVec& GetSections() const; // Returns nested enums virtual const SyntaxEnumsVec& GetEnums() const; // Returns typedefs defined in this section virtual const SyntaxTypedefsVec& GetTypedefs() const; // Returns using namespaces in this section virtual const SyntaxUsingNamespacesVec& GetUsingNamespaces() const; // Returns comment in section virtual const SyntaxCommentsVec& GetComments() const; // Returns comment above or on this line SyntaxComment* FindCommentNearLine(int line) const; // Returns all inside sections virtual SyntaxSectionsVec GetAllSections() const; // Returns all inside classes virtual SyntaxClassesVec GetAllClasses() const; // Returns all enums virtual SyntaxEnumsVec GetAllEnums() const; // Returns is this section is class virtual bool IsClass() const; // Returns attributes definitions virtual const SyntaxAttributesVec& GetAttributes() const; // Saves data to xml node virtual void SaveTo(pugi::xml_node& node) const; // Loads data from xml node virtual void LoadFrom(const pugi::xml_node& node); protected: string mName; // Short name of section string mFullName; // Full name of section with all parents names SyntaxSection* mParentSection = nullptr; // Pointer to parent section (nullptr of section is global) SyntaxFunctionsVec mFunctions; // List of functions SyntaxVariablesVec mVariables; // List of variables SyntaxSectionsVec mSections; // List of nested sections (classes or namespaces) SyntaxEnumsVec mEnums; // List of enum SyntaxCommentsVec mComments; // List of comments SyntaxTypedefsVec mTypedefs; // List of typedefs SyntaxUsingNamespacesVec mUsingNamespaces; // List of using namespaces SyntaxAttributesVec mAttributes; // List of attributes SyntaxDefinesVec mDefines; // List of defines friend class CodeToolCache; friend class CppSyntaxParser; }; // Syntax namespace class SyntaxNamespace: public SyntaxSection { public: SyntaxNamespace(); friend class CodeToolCache; friend class CppSyntaxParser; }; // Syntax class inheritance definition class SyntaxClassInheritance: public ISyntaxExpression { public: // Default constructor SyntaxClassInheritance() {} // Constructor by class name and inheritance protection type SyntaxClassInheritance(const string& className, SyntaxProtectionSection type); // Returns class name const string& GetClassName() const; // Returns class SyntaxClass* GetClass(); // Returns class inheritance protection type SyntaxProtectionSection GetInheritanceType() const; // Check equality operator bool operator==(const SyntaxClassInheritance& other) const; // Saves data to xml node void SaveTo(pugi::xml_node& node) const; // Loads data from xml node void LoadFrom(const pugi::xml_node& node); protected: string mClassName; // Inheritance class name SyntaxClass* mClass = nullptr; // Inheritance class (if found) SyntaxProtectionSection mInheritanceType; // Inheritance protection type friend class CodeToolCache; friend class CppSyntaxParser; }; typedef vector SyntaxClassInheritancsVec; // Syntax class or struct class SyntaxClass: public SyntaxSection { public: // Returns array of functions const SyntaxFunctionsVec& GetFunctions() const; // Returns array of variables const SyntaxVariablesVec& GetVariables() const; // Returns nested sections const SyntaxSectionsVec& GetSections() const; // Returns nested enums const SyntaxEnumsVec& GetEnums() const; // Returns typedefs defined in this section const SyntaxTypedefsVec& GetTypedefs() const; // Returns using namespaces in this section const SyntaxUsingNamespacesVec& GetUsingNamespaces() const; // Returns all inside sections SyntaxSectionsVec GetAllSections() const; // Returns all inside classes SyntaxClassesVec GetAllClasses() const; // Returns is this section is class bool IsClass() const; // Returns base classes const SyntaxClassInheritancsVec& GetBaseClasses() const; // Returns is class template bool IsTemplate() const; // Returns is class meta (defined as "meta class name { ... };") bool IsMetaClass() const; // Returns template parameters (if exist) const string& GetTemplateParameters() const; // Returns parent class protection section SyntaxProtectionSection GetClassSection() const; // Returns comment definition for attribute (empty for not attribute classes) const string& GetAttributeCommentDef() const; // Returns short definition for attribute (empty for not attribute classes) const string& GetAttributeShortDef() const; // Returns attributes definitions const SyntaxAttributesVec& GetAttributes() const; // Saves data to xml node void SaveTo(pugi::xml_node& node) const; // Loads data from xml node void LoadFrom(const pugi::xml_node& node); protected: SyntaxClassInheritancsVec mBaseClasses; // Base classe string mTemplateParameters; // Template parameters (empty if class isn't template) bool mIsMeta = false; // Is class meta (defined as "meta class name { ... };") SyntaxProtectionSection mClassSection = SyntaxProtectionSection::Public; // protection section of parent class SyntaxClass* mSourceClass = nullptr; // Source class for template specialized classes string mAttributeCommentDef; // Attribute comment definition string mAttributeShortDef; // Attribute short definition friend class CodeToolCache; friend class CppSyntaxParser; }; // Syntax attributes list class SyntaxAttributes: public ISyntaxExpression { public: // Returns list of attributes const vector& GetAttributesList() const; protected: vector mAttributesList; friend class CodeToolCache; friend class CppSyntaxParser; }; // Syntax variable type class SyntaxType: public ISyntaxExpression { public: // Returns name of type const string& GetName() const; // Returns is type is constant bool IsConstant() const; // Returns is type is reference bool IsReference() const; // Returns is type is pointer bool IsPointer() const; protected: string mName; bool mIsContant = false; bool mIsReference = false; bool mIsPointer = false; bool mIsMutable = false; friend class CppSyntaxParser; }; // Syntax variable class SyntaxVariable: public ISyntaxExpression { public: // Returns type of variable const SyntaxType& GetVariableType() const; // Returns name of variable const string& GetName() const; // Returns default value const string& GetDefaultValue() const; // Returns class definition section SyntaxProtectionSection GetClassSection() const; // Returns is variable is static bool IsStatic() const; protected: SyntaxType mType; // Type of variable string mName; // Name of variable string mDefaultValue; // Default variable value SyntaxProtectionSection mClassSection = SyntaxProtectionSection::Public; // Protection section bool mIsStatic = false; // Is variable static friend class CppSyntaxParser; }; // Syntax function class SyntaxFunction: public ISyntaxExpression { public: // Default constructor SyntaxFunction(); // Destructor ~SyntaxFunction(); // Returns function's returning type const SyntaxType& GetReturnType() const; // Returns name of function const string& GetName() const; // Returns list of function's parameters const SyntaxVariablesVec& GetParameters() const; // Returns protection section SyntaxProtectionSection GetClassSection() const; // Returns is function template bool IsTemplate() const; // Returns function templates (if have) const string& GetTemplates() const; // Returns is function static bool IsStatic() const; protected: SyntaxType mReturnType; // Returning type string mTemplates; // Function templates string mName; // Name of function SyntaxVariablesVec mParameters; // List of parameters SyntaxProtectionSection mClassSection = SyntaxProtectionSection::Public; // Protection Section bool mIsStatic = false; // Is function static bool mIsVirtual = false; // Is function virtual bool mIsContstant = false; // Is function constant friend class CppSyntaxParser; }; // Syntax enum class SyntaxEnum: public ISyntaxExpression { public: // Returns name of enum const string& GetName() const; // Returns full name of enum with all parent spaces names const string& GetFullName() const; // Returns enum entries const StringStringDict& GetEntries() const; // Returns protection section SyntaxProtectionSection GetClassSection() const; // Returns owner syntax section SyntaxSection* GetOwnerSyntaxSection() const; protected: string mName; // Name of enum string mFullName; // Full enum name with all parent spaces names StringStringDict mEntries; // Entries of enum SyntaxSection* mOwnerSection = nullptr; // Owner syntax section SyntaxProtectionSection mClassSection = SyntaxProtectionSection::Public; friend class CppSyntaxParser; }; // Syntax #define class SyntaxDefineIf : public ISyntaxExpression { public: const string& GetDefinition() const; protected: string mDefintion; // Definition statement after #define friend class CppSyntaxParser; }; ================================================ FILE: CodeTool/Src/pugixml/pugiconfig.hpp ================================================ /* * pugixml parser - version 1.6 * -------------------------------------------------------- * Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at http://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end * of this file. * * This work is based on the pugxml parser, which is: * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) */ #ifndef HEADER_PUGICONFIG_HPP #define HEADER_PUGICONFIG_HPP // Uncomment this to enable wchar_t mode //#define PUGIXML_WCHAR_MODE // Uncomment this to disable XPath // #define PUGIXML_NO_XPATH // Uncomment this to disable STL // #define PUGIXML_NO_STL // Uncomment this to disable exceptions // #define PUGIXML_NO_EXCEPTIONS // Set this to control attributes for public classes/functions, i.e.: // #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL // #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL // #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall // In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead // Tune these constants to adjust memory-related behavior // #define PUGIXML_MEMORY_PAGE_SIZE 32768 // #define PUGIXML_MEMORY_OUTPUT_STACK 10240 // #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096 // Uncomment this to switch to header-only version // #define PUGIXML_HEADER_ONLY // Uncomment this to enable long long support // #define PUGIXML_HAS_LONG_LONG #endif /* * Copyright (c) 2006-2015 Arseny Kapoulkine * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ ================================================ FILE: CodeTool/Src/pugixml/pugixml.cpp ================================================ /* * pugixml parser - version 1.6 * -------------------------------------------------------- * Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at http://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end * of this file. * * This work is based on the pugxml parser, which is: * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) */ #ifndef SOURCE_PUGIXML_CPP #define SOURCE_PUGIXML_CPP #include "pugixml.hpp" #include #include #include #include #ifdef PUGIXML_WCHAR_MODE # include #endif #ifndef PUGIXML_NO_XPATH # include # include # ifdef PUGIXML_NO_EXCEPTIONS # include # endif #endif #ifndef PUGIXML_NO_STL # include # include # include #endif // For placement new #include #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4127) // conditional expression is constant # pragma warning(disable: 4324) // structure was padded due to __declspec(align()) # pragma warning(disable: 4611) // interaction between '_setjmp' and C++ object destruction is non-portable # pragma warning(disable: 4702) // unreachable code # pragma warning(disable: 4996) // this function or variable may be unsafe # pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged #endif #ifdef __INTEL_COMPILER # pragma warning(disable: 177) // function was declared but never referenced # pragma warning(disable: 279) // controlling expression is constant # pragma warning(disable: 1478 1786) // function was declared "deprecated" # pragma warning(disable: 1684) // conversion from pointer to same-sized integral type #endif #if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY) # pragma warn -8080 // symbol is declared but never used; disabling this inside push/pop bracket does not make the warning go away #endif #ifdef __BORLANDC__ # pragma option push # pragma warn -8008 // condition is always false # pragma warn -8066 // unreachable code #endif #ifdef __SNC__ // Using diag_push/diag_pop does not disable the warnings inside templates due to a compiler bug # pragma diag_suppress=178 // function was declared but never referenced # pragma diag_suppress=237 // controlling expression is constant #endif // Inlining controls #if defined(_MSC_VER) && _MSC_VER >= 1300 # define PUGI__NO_INLINE __declspec(noinline) #elif defined(__GNUC__) # define PUGI__NO_INLINE __attribute__((noinline)) #else # define PUGI__NO_INLINE #endif // Branch weight controls #if defined(__GNUC__) # define PUGI__UNLIKELY(cond) __builtin_expect(cond, 0) #else # define PUGI__UNLIKELY(cond) (cond) #endif // Simple static assertion #define PUGI__STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; } // Digital Mars C++ bug workaround for passing char loaded from memory via stack #ifdef __DMC__ # define PUGI__DMC_VOLATILE volatile #else # define PUGI__DMC_VOLATILE #endif // Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy because some compilers don't have it at all) #if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST) using std::memcpy; using std::memmove; #endif // In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features #if defined(_MSC_VER) && !defined(__S3E__) # define PUGI__MSVC_CRT_VERSION _MSC_VER #endif #ifdef PUGIXML_HEADER_ONLY # define PUGI__NS_BEGIN namespace pugi { namespace impl { # define PUGI__NS_END } } # define PUGI__FN inline # define PUGI__FN_NO_INLINE inline #else # if defined(_MSC_VER) && _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces # define PUGI__NS_BEGIN namespace pugi { namespace impl { # define PUGI__NS_END } } # else # define PUGI__NS_BEGIN namespace pugi { namespace impl { namespace { # define PUGI__NS_END } } } # endif # define PUGI__FN # define PUGI__FN_NO_INLINE PUGI__NO_INLINE #endif // uintptr_t #if !defined(_MSC_VER) || _MSC_VER >= 1600 # include #else # ifndef _UINTPTR_T_DEFINED // No native uintptr_t in MSVC6 and in some WinCE versions typedef size_t uintptr_t; #define _UINTPTR_T_DEFINED # endif PUGI__NS_BEGIN typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; PUGI__NS_END #endif // Memory allocation PUGI__NS_BEGIN PUGI__FN void* default_allocate(size_t size) { return malloc(size); } PUGI__FN void default_deallocate(void* ptr) { free(ptr); } template struct xml_memory_management_function_storage { static allocation_function allocate; static deallocation_function deallocate; }; // Global allocation functions are stored in class statics so that in header mode linker deduplicates them // Without a template<> we'll get multiple definitions of the same static template allocation_function xml_memory_management_function_storage::allocate = default_allocate; template deallocation_function xml_memory_management_function_storage::deallocate = default_deallocate; typedef xml_memory_management_function_storage xml_memory; PUGI__NS_END // String utilities PUGI__NS_BEGIN // Get string length PUGI__FN size_t strlength(const char_t* s) { assert(s); #ifdef PUGIXML_WCHAR_MODE return wcslen(s); #else return strlen(s); #endif } // Compare two strings PUGI__FN bool strequal(const char_t* src, const char_t* dst) { assert(src && dst); #ifdef PUGIXML_WCHAR_MODE return wcscmp(src, dst) == 0; #else return strcmp(src, dst) == 0; #endif } // Compare lhs with [rhs_begin, rhs_end) PUGI__FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count) { for (size_t i = 0; i < count; ++i) if (lhs[i] != rhs[i]) return false; return lhs[count] == 0; } // Get length of wide string, even if CRT lacks wide character support PUGI__FN size_t strlength_wide(const wchar_t* s) { assert(s); #ifdef PUGIXML_WCHAR_MODE return wcslen(s); #else const wchar_t* end = s; while (*end) end++; return static_cast(end - s); #endif } #ifdef PUGIXML_WCHAR_MODE // Convert string to wide string, assuming all symbols are ASCII PUGI__FN void widen_ascii(wchar_t* dest, const char* source) { for (const char* i = source; *i; ++i) *dest++ = *i; *dest = 0; } #endif PUGI__NS_END #if !defined(PUGIXML_NO_STL) || !defined(PUGIXML_NO_XPATH) // auto_ptr-like buffer holder for exception recovery PUGI__NS_BEGIN struct buffer_holder { void* data; void (*deleter)(void*); buffer_holder(void* data_, void (*deleter_)(void*)): data(data_), deleter(deleter_) { } ~buffer_holder() { if (data) deleter(data); } void* release() { void* result = data; data = 0; return result; } }; PUGI__NS_END #endif PUGI__NS_BEGIN static const size_t xml_memory_page_size = #ifdef PUGIXML_MEMORY_PAGE_SIZE PUGIXML_MEMORY_PAGE_SIZE #else 32768 #endif ; static const uintptr_t xml_memory_page_alignment = 64; static const uintptr_t xml_memory_page_pointer_mask = ~(xml_memory_page_alignment - 1); static const uintptr_t xml_memory_page_contents_shared_mask = 32; static const uintptr_t xml_memory_page_name_allocated_mask = 16; static const uintptr_t xml_memory_page_value_allocated_mask = 8; static const uintptr_t xml_memory_page_type_mask = 7; static const uintptr_t xml_memory_page_name_allocated_or_shared_mask = xml_memory_page_name_allocated_mask | xml_memory_page_contents_shared_mask; static const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask; #define PUGI__NODETYPE(n) static_cast(((n)->header & impl::xml_memory_page_type_mask) + 1) struct xml_allocator; struct xml_memory_page { static xml_memory_page* construct(void* memory) { xml_memory_page* result = static_cast(memory); result->allocator = 0; result->prev = 0; result->next = 0; result->busy_size = 0; result->freed_size = 0; return result; } xml_allocator* allocator; xml_memory_page* prev; xml_memory_page* next; size_t busy_size; size_t freed_size; }; struct xml_memory_string_header { uint16_t page_offset; // offset from page->data uint16_t full_size; // 0 if string occupies whole page }; struct xml_allocator { xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size) { } xml_memory_page* allocate_page(size_t data_size) { size_t size = sizeof(xml_memory_page) + data_size; // allocate block with some alignment, leaving memory for worst-case padding void* memory = xml_memory::allocate(size + xml_memory_page_alignment); if (!memory) return 0; // align to next page boundary (note: this guarantees at least 1 usable byte before the page) char* page_memory = reinterpret_cast((reinterpret_cast(memory) + xml_memory_page_alignment) & ~(xml_memory_page_alignment - 1)); // prepare page structure xml_memory_page* page = xml_memory_page::construct(page_memory); assert(page); page->allocator = _root->allocator; // record the offset for freeing the memory block assert(page_memory > memory && page_memory - static_cast(memory) <= 127); page_memory[-1] = static_cast(page_memory - static_cast(memory)); return page; } static void deallocate_page(xml_memory_page* page) { char* page_memory = reinterpret_cast(page); xml_memory::deallocate(page_memory - page_memory[-1]); } void* allocate_memory_oob(size_t size, xml_memory_page*& out_page); void* allocate_memory(size_t size, xml_memory_page*& out_page) { if (_busy_size + size > xml_memory_page_size) return allocate_memory_oob(size, out_page); void* buf = reinterpret_cast(_root) + sizeof(xml_memory_page) + _busy_size; _busy_size += size; out_page = _root; return buf; } void deallocate_memory(void* ptr, size_t size, xml_memory_page* page) { if (page == _root) page->busy_size = _busy_size; assert(ptr >= reinterpret_cast(page) + sizeof(xml_memory_page) && ptr < reinterpret_cast(page) + sizeof(xml_memory_page) + page->busy_size); (void)!ptr; page->freed_size += size; assert(page->freed_size <= page->busy_size); if (page->freed_size == page->busy_size) { if (page->next == 0) { assert(_root == page); // top page freed, just reset sizes page->busy_size = page->freed_size = 0; _busy_size = 0; } else { assert(_root != page); assert(page->prev); // remove from the list page->prev->next = page->next; page->next->prev = page->prev; // deallocate deallocate_page(page); } } } char_t* allocate_string(size_t length) { static const size_t max_encoded_offset = (1 << 16) * sizeof(void*); PUGI__STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset); // allocate memory for string and header block size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t); // round size up to pointer alignment boundary size_t full_size = (size + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1); xml_memory_page* page; xml_memory_string_header* header = static_cast(allocate_memory(full_size, page)); if (!header) return 0; // setup header ptrdiff_t page_offset = reinterpret_cast(header) - reinterpret_cast(page) - sizeof(xml_memory_page); assert(page_offset % sizeof(void*) == 0); assert(page_offset >= 0 && static_cast(page_offset) < max_encoded_offset); header->page_offset = static_cast(static_cast(page_offset) / sizeof(void*)); // full_size == 0 for large strings that occupy the whole page assert(full_size % sizeof(void*) == 0); assert(full_size < max_encoded_offset || (page->busy_size == full_size && page_offset == 0)); header->full_size = static_cast(full_size < max_encoded_offset ? full_size / sizeof(void*) : 0); // round-trip through void* to avoid 'cast increases required alignment of target type' warning // header is guaranteed a pointer-sized alignment, which should be enough for char_t return static_cast(static_cast(header + 1)); } void deallocate_string(char_t* string) { // this function casts pointers through void* to avoid 'cast increases required alignment of target type' warnings // we're guaranteed the proper (pointer-sized) alignment on the input string if it was allocated via allocate_string // get header xml_memory_string_header* header = static_cast(static_cast(string)) - 1; assert(header); // deallocate size_t page_offset = sizeof(xml_memory_page) + header->page_offset * sizeof(void*); xml_memory_page* page = reinterpret_cast(static_cast(reinterpret_cast(header) - page_offset)); // if full_size == 0 then this string occupies the whole page size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size * sizeof(void*); deallocate_memory(header, full_size, page); } xml_memory_page* _root; size_t _busy_size; }; PUGI__FN_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page) { const size_t large_allocation_threshold = xml_memory_page_size / 4; xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size); out_page = page; if (!page) return 0; if (size <= large_allocation_threshold) { _root->busy_size = _busy_size; // insert page at the end of linked list page->prev = _root; _root->next = page; _root = page; _busy_size = size; } else { // insert page before the end of linked list, so that it is deleted as soon as possible // the last page is not deleted even if it's empty (see deallocate_memory) assert(_root->prev); page->prev = _root->prev; page->next = _root; _root->prev->next = page; _root->prev = page; } // allocate inside page page->busy_size = size; return reinterpret_cast(page) + sizeof(xml_memory_page); } PUGI__NS_END namespace pugi { /// A 'name=value' XML attribute structure. struct xml_attribute_struct { /// Default ctor xml_attribute_struct(impl::xml_memory_page* page): header(reinterpret_cast(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0) { } uintptr_t header; char_t* name; ///< Pointer to attribute name. char_t* value; ///< Pointer to attribute value. xml_attribute_struct* prev_attribute_c; ///< Previous attribute (cyclic list) xml_attribute_struct* next_attribute; ///< Next attribute }; /// An XML document tree node. struct xml_node_struct { /// Default ctor /// \param type - node type xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(reinterpret_cast(page) | (type - 1)), parent(0), name(0), value(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0) { } uintptr_t header; xml_node_struct* parent; ///< Pointer to parent char_t* name; ///< Pointer to element name. char_t* value; ///< Pointer to any associated string data. xml_node_struct* first_child; ///< First child xml_node_struct* prev_sibling_c; ///< Left brother (cyclic list) xml_node_struct* next_sibling; ///< Right brother xml_attribute_struct* first_attribute; ///< First attribute }; } PUGI__NS_BEGIN struct xml_extra_buffer { char_t* buffer; xml_extra_buffer* next; }; struct xml_document_struct: public xml_node_struct, public xml_allocator { xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0), extra_buffers(0) { } const char_t* buffer; xml_extra_buffer* extra_buffers; }; inline xml_allocator& get_allocator(const xml_node_struct* node) { assert(node); return *reinterpret_cast(node->header & xml_memory_page_pointer_mask)->allocator; } template inline xml_document_struct& get_document(const Object* object) { assert(object); return *static_cast(reinterpret_cast(object->header & xml_memory_page_pointer_mask)->allocator); } PUGI__NS_END // Low-level DOM operations PUGI__NS_BEGIN inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc) { xml_memory_page* page; void* memory = alloc.allocate_memory(sizeof(xml_attribute_struct), page); return new (memory) xml_attribute_struct(page); } inline xml_node_struct* allocate_node(xml_allocator& alloc, xml_node_type type) { xml_memory_page* page; void* memory = alloc.allocate_memory(sizeof(xml_node_struct), page); return new (memory) xml_node_struct(page, type); } inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc) { uintptr_t header = a->header; if (header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(a->name); if (header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(a->value); alloc.deallocate_memory(a, sizeof(xml_attribute_struct), reinterpret_cast(header & xml_memory_page_pointer_mask)); } inline void destroy_node(xml_node_struct* n, xml_allocator& alloc) { uintptr_t header = n->header; if (header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(n->name); if (header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(n->value); for (xml_attribute_struct* attr = n->first_attribute; attr; ) { xml_attribute_struct* next = attr->next_attribute; destroy_attribute(attr, alloc); attr = next; } for (xml_node_struct* child = n->first_child; child; ) { xml_node_struct* next = child->next_sibling; destroy_node(child, alloc); child = next; } alloc.deallocate_memory(n, sizeof(xml_node_struct), reinterpret_cast(header & xml_memory_page_pointer_mask)); } inline void append_node(xml_node_struct* child, xml_node_struct* node) { child->parent = node; xml_node_struct* head = node->first_child; if (head) { xml_node_struct* tail = head->prev_sibling_c; tail->next_sibling = child; child->prev_sibling_c = tail; head->prev_sibling_c = child; } else { node->first_child = child; child->prev_sibling_c = child; } } inline void prepend_node(xml_node_struct* child, xml_node_struct* node) { child->parent = node; xml_node_struct* head = node->first_child; if (head) { child->prev_sibling_c = head->prev_sibling_c; head->prev_sibling_c = child; } else child->prev_sibling_c = child; child->next_sibling = head; node->first_child = child; } inline void insert_node_after(xml_node_struct* child, xml_node_struct* node) { xml_node_struct* parent = node->parent; child->parent = parent; if (node->next_sibling) node->next_sibling->prev_sibling_c = child; else parent->first_child->prev_sibling_c = child; child->next_sibling = node->next_sibling; child->prev_sibling_c = node; node->next_sibling = child; } inline void insert_node_before(xml_node_struct* child, xml_node_struct* node) { xml_node_struct* parent = node->parent; child->parent = parent; if (node->prev_sibling_c->next_sibling) node->prev_sibling_c->next_sibling = child; else parent->first_child = child; child->prev_sibling_c = node->prev_sibling_c; child->next_sibling = node; node->prev_sibling_c = child; } inline void remove_node(xml_node_struct* node) { xml_node_struct* parent = node->parent; if (node->next_sibling) node->next_sibling->prev_sibling_c = node->prev_sibling_c; else parent->first_child->prev_sibling_c = node->prev_sibling_c; if (node->prev_sibling_c->next_sibling) node->prev_sibling_c->next_sibling = node->next_sibling; else parent->first_child = node->next_sibling; node->parent = 0; node->prev_sibling_c = 0; node->next_sibling = 0; } inline void append_attribute(xml_attribute_struct* attr, xml_node_struct* node) { xml_attribute_struct* head = node->first_attribute; if (head) { xml_attribute_struct* tail = head->prev_attribute_c; tail->next_attribute = attr; attr->prev_attribute_c = tail; head->prev_attribute_c = attr; } else { node->first_attribute = attr; attr->prev_attribute_c = attr; } } inline void prepend_attribute(xml_attribute_struct* attr, xml_node_struct* node) { xml_attribute_struct* head = node->first_attribute; if (head) { attr->prev_attribute_c = head->prev_attribute_c; head->prev_attribute_c = attr; } else attr->prev_attribute_c = attr; attr->next_attribute = head; node->first_attribute = attr; } inline void insert_attribute_after(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node) { if (place->next_attribute) place->next_attribute->prev_attribute_c = attr; else node->first_attribute->prev_attribute_c = attr; attr->next_attribute = place->next_attribute; attr->prev_attribute_c = place; place->next_attribute = attr; } inline void insert_attribute_before(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node) { if (place->prev_attribute_c->next_attribute) place->prev_attribute_c->next_attribute = attr; else node->first_attribute = attr; attr->prev_attribute_c = place->prev_attribute_c; attr->next_attribute = place; place->prev_attribute_c = attr; } inline void remove_attribute(xml_attribute_struct* attr, xml_node_struct* node) { if (attr->next_attribute) attr->next_attribute->prev_attribute_c = attr->prev_attribute_c; else node->first_attribute->prev_attribute_c = attr->prev_attribute_c; if (attr->prev_attribute_c->next_attribute) attr->prev_attribute_c->next_attribute = attr->next_attribute; else node->first_attribute = attr->next_attribute; attr->prev_attribute_c = 0; attr->next_attribute = 0; } PUGI__FN_NO_INLINE xml_node_struct* append_new_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element) { xml_node_struct* child = allocate_node(alloc, type); if (!child) return 0; append_node(child, node); return child; } PUGI__FN_NO_INLINE xml_attribute_struct* append_new_attribute(xml_node_struct* node, xml_allocator& alloc) { xml_attribute_struct* attr = allocate_attribute(alloc); if (!attr) return 0; append_attribute(attr, node); return attr; } PUGI__NS_END // Helper classes for code generation PUGI__NS_BEGIN struct opt_false { enum { value = 0 }; }; struct opt_true { enum { value = 1 }; }; PUGI__NS_END // Unicode utilities PUGI__NS_BEGIN inline uint16_t endian_swap(uint16_t value) { return static_cast(((value & 0xff) << 8) | (value >> 8)); } inline uint32_t endian_swap(uint32_t value) { return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24); } struct utf8_counter { typedef size_t value_type; static value_type low(value_type result, uint32_t ch) { // U+0000..U+007F if (ch < 0x80) return result + 1; // U+0080..U+07FF else if (ch < 0x800) return result + 2; // U+0800..U+FFFF else return result + 3; } static value_type high(value_type result, uint32_t) { // U+10000..U+10FFFF return result + 4; } }; struct utf8_writer { typedef uint8_t* value_type; static value_type low(value_type result, uint32_t ch) { // U+0000..U+007F if (ch < 0x80) { *result = static_cast(ch); return result + 1; } // U+0080..U+07FF else if (ch < 0x800) { result[0] = static_cast(0xC0 | (ch >> 6)); result[1] = static_cast(0x80 | (ch & 0x3F)); return result + 2; } // U+0800..U+FFFF else { result[0] = static_cast(0xE0 | (ch >> 12)); result[1] = static_cast(0x80 | ((ch >> 6) & 0x3F)); result[2] = static_cast(0x80 | (ch & 0x3F)); return result + 3; } } static value_type high(value_type result, uint32_t ch) { // U+10000..U+10FFFF result[0] = static_cast(0xF0 | (ch >> 18)); result[1] = static_cast(0x80 | ((ch >> 12) & 0x3F)); result[2] = static_cast(0x80 | ((ch >> 6) & 0x3F)); result[3] = static_cast(0x80 | (ch & 0x3F)); return result + 4; } static value_type any(value_type result, uint32_t ch) { return (ch < 0x10000) ? low(result, ch) : high(result, ch); } }; struct utf16_counter { typedef size_t value_type; static value_type low(value_type result, uint32_t) { return result + 1; } static value_type high(value_type result, uint32_t) { return result + 2; } }; struct utf16_writer { typedef uint16_t* value_type; static value_type low(value_type result, uint32_t ch) { *result = static_cast(ch); return result + 1; } static value_type high(value_type result, uint32_t ch) { uint32_t msh = static_cast(ch - 0x10000) >> 10; uint32_t lsh = static_cast(ch - 0x10000) & 0x3ff; result[0] = static_cast(0xD800 + msh); result[1] = static_cast(0xDC00 + lsh); return result + 2; } static value_type any(value_type result, uint32_t ch) { return (ch < 0x10000) ? low(result, ch) : high(result, ch); } }; struct utf32_counter { typedef size_t value_type; static value_type low(value_type result, uint32_t) { return result + 1; } static value_type high(value_type result, uint32_t) { return result + 1; } }; struct utf32_writer { typedef uint32_t* value_type; static value_type low(value_type result, uint32_t ch) { *result = ch; return result + 1; } static value_type high(value_type result, uint32_t ch) { *result = ch; return result + 1; } static value_type any(value_type result, uint32_t ch) { *result = ch; return result + 1; } }; struct latin1_writer { typedef uint8_t* value_type; static value_type low(value_type result, uint32_t ch) { *result = static_cast(ch > 255 ? '?' : ch); return result + 1; } static value_type high(value_type result, uint32_t ch) { (void)ch; *result = '?'; return result + 1; } }; template struct wchar_selector; template <> struct wchar_selector<2> { typedef uint16_t type; typedef utf16_counter counter; typedef utf16_writer writer; }; template <> struct wchar_selector<4> { typedef uint32_t type; typedef utf32_counter counter; typedef utf32_writer writer; }; typedef wchar_selector::counter wchar_counter; typedef wchar_selector::writer wchar_writer; template struct utf_decoder { static inline typename Traits::value_type decode_utf8_block(const uint8_t* data, size_t size, typename Traits::value_type result) { const uint8_t utf8_byte_mask = 0x3f; while (size) { uint8_t lead = *data; // 0xxxxxxx -> U+0000..U+007F if (lead < 0x80) { result = Traits::low(result, lead); data += 1; size -= 1; // process aligned single-byte (ascii) blocks if ((reinterpret_cast(data) & 3) == 0) { // round-trip through void* to silence 'cast increases required alignment of target type' warnings while (size >= 4 && (*static_cast(static_cast(data)) & 0x80808080) == 0) { result = Traits::low(result, data[0]); result = Traits::low(result, data[1]); result = Traits::low(result, data[2]); result = Traits::low(result, data[3]); data += 4; size -= 4; } } } // 110xxxxx -> U+0080..U+07FF else if (static_cast(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80) { result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask)); data += 2; size -= 2; } // 1110xxxx -> U+0800-U+FFFF else if (static_cast(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80) { result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask)); data += 3; size -= 3; } // 11110xxx -> U+10000..U+10FFFF else if (static_cast(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80) { result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask)); data += 4; size -= 4; } // 10xxxxxx or 11111xxx -> invalid else { data += 1; size -= 1; } } return result; } static inline typename Traits::value_type decode_utf16_block(const uint16_t* data, size_t size, typename Traits::value_type result) { const uint16_t* end = data + size; while (data < end) { unsigned int lead = opt_swap::value ? endian_swap(*data) : *data; // U+0000..U+D7FF if (lead < 0xD800) { result = Traits::low(result, lead); data += 1; } // U+E000..U+FFFF else if (static_cast(lead - 0xE000) < 0x2000) { result = Traits::low(result, lead); data += 1; } // surrogate pair lead else if (static_cast(lead - 0xD800) < 0x400 && data + 1 < end) { uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1]; if (static_cast(next - 0xDC00) < 0x400) { result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff)); data += 2; } else { data += 1; } } else { data += 1; } } return result; } static inline typename Traits::value_type decode_utf32_block(const uint32_t* data, size_t size, typename Traits::value_type result) { const uint32_t* end = data + size; while (data < end) { uint32_t lead = opt_swap::value ? endian_swap(*data) : *data; // U+0000..U+FFFF if (lead < 0x10000) { result = Traits::low(result, lead); data += 1; } // U+10000..U+10FFFF else { result = Traits::high(result, lead); data += 1; } } return result; } static inline typename Traits::value_type decode_latin1_block(const uint8_t* data, size_t size, typename Traits::value_type result) { for (size_t i = 0; i < size; ++i) { result = Traits::low(result, data[i]); } return result; } static inline typename Traits::value_type decode_wchar_block_impl(const uint16_t* data, size_t size, typename Traits::value_type result) { return decode_utf16_block(data, size, result); } static inline typename Traits::value_type decode_wchar_block_impl(const uint32_t* data, size_t size, typename Traits::value_type result) { return decode_utf32_block(data, size, result); } static inline typename Traits::value_type decode_wchar_block(const wchar_t* data, size_t size, typename Traits::value_type result) { return decode_wchar_block_impl(reinterpret_cast::type*>(data), size, result); } }; template PUGI__FN void convert_utf_endian_swap(T* result, const T* data, size_t length) { for (size_t i = 0; i < length; ++i) result[i] = endian_swap(data[i]); } #ifdef PUGIXML_WCHAR_MODE PUGI__FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length) { for (size_t i = 0; i < length; ++i) result[i] = static_cast(endian_swap(static_cast::type>(data[i]))); } #endif PUGI__NS_END PUGI__NS_BEGIN enum chartype_t { ct_parse_pcdata = 1, // \0, &, \r, < ct_parse_attr = 2, // \0, &, \r, ', " ct_parse_attr_ws = 4, // \0, &, \r, ', ", \n, tab ct_space = 8, // \r, \n, space, tab ct_parse_cdata = 16, // \0, ], >, \r ct_parse_comment = 32, // \0, -, >, \r ct_symbol = 64, // Any symbol > 127, a-z, A-Z, 0-9, _, :, -, . ct_start_symbol = 128 // Any symbol > 127, a-z, A-Z, _, : }; static const unsigned char chartype_table[256] = { 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0, // 0-15 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31 8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0, // 32-47 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0, // 48-63 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 64-79 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192, // 80-95 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 96-111 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0, // 112-127 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 128+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192 }; enum chartypex_t { ctx_special_pcdata = 1, // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, > ctx_special_attr = 2, // Any symbol >= 0 and < 32 (except \t), &, <, >, " ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _ ctx_digit = 8, // 0-9 ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, . }; static const unsigned char chartypex_table[256] = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3, // 0-15 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 16, 16, 0, // 32-47 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 3, 0, // 48-63 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 64-79 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 20, // 80-95 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 96-111 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, // 112-127 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 128+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 }; #ifdef PUGIXML_WCHAR_MODE #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast(c) < 128 ? table[static_cast(c)] : table[128]) & (ct)) #else #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast(c)] & (ct)) #endif #define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table) #define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table) PUGI__FN bool is_little_endian() { unsigned int ui = 1; return *reinterpret_cast(&ui) == 1; } PUGI__FN xml_encoding get_wchar_encoding() { PUGI__STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); if (sizeof(wchar_t) == 2) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; else return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; } PUGI__FN xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) { // look for BOM in first few bytes if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be; if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le; if (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be; if (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le; if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf) return encoding_utf8; // look for <, (contents); PUGI__DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3]; return guess_buffer_encoding(d0, d1, d2, d3); } PUGI__FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) { size_t length = size / sizeof(char_t); if (is_mutable) { out_buffer = static_cast(const_cast(contents)); out_length = length; } else { char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; if (contents) memcpy(buffer, contents, length * sizeof(char_t)); else assert(length == 0); buffer[length] = 0; out_buffer = buffer; out_length = length + 1; } return true; } #ifdef PUGIXML_WCHAR_MODE PUGI__FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re) { return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) || (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be); } PUGI__FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) { const char_t* data = static_cast(contents); size_t length = size / sizeof(char_t); if (is_mutable) { char_t* buffer = const_cast(data); convert_wchar_endian_swap(buffer, data, length); out_buffer = buffer; out_length = length; } else { char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; convert_wchar_endian_swap(buffer, data, length); buffer[length] = 0; out_buffer = buffer; out_length = length + 1; } return true; } PUGI__FN bool convert_buffer_utf8(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size) { const uint8_t* data = static_cast(contents); size_t data_length = size; // first pass: get length in wchar_t units size_t length = utf_decoder::decode_utf8_block(data, data_length, 0); // allocate buffer of suitable length char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; // second pass: convert utf8 input to wchar_t wchar_writer::value_type obegin = reinterpret_cast(buffer); wchar_writer::value_type oend = utf_decoder::decode_utf8_block(data, data_length, obegin); assert(oend == obegin + length); *oend = 0; out_buffer = buffer; out_length = length + 1; return true; } template PUGI__FN bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) { const uint16_t* data = static_cast(contents); size_t data_length = size / sizeof(uint16_t); // first pass: get length in wchar_t units size_t length = utf_decoder::decode_utf16_block(data, data_length, 0); // allocate buffer of suitable length char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; // second pass: convert utf16 input to wchar_t wchar_writer::value_type obegin = reinterpret_cast(buffer); wchar_writer::value_type oend = utf_decoder::decode_utf16_block(data, data_length, obegin); assert(oend == obegin + length); *oend = 0; out_buffer = buffer; out_length = length + 1; return true; } template PUGI__FN bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) { const uint32_t* data = static_cast(contents); size_t data_length = size / sizeof(uint32_t); // first pass: get length in wchar_t units size_t length = utf_decoder::decode_utf32_block(data, data_length, 0); // allocate buffer of suitable length char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; // second pass: convert utf32 input to wchar_t wchar_writer::value_type obegin = reinterpret_cast(buffer); wchar_writer::value_type oend = utf_decoder::decode_utf32_block(data, data_length, obegin); assert(oend == obegin + length); *oend = 0; out_buffer = buffer; out_length = length + 1; return true; } PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size) { const uint8_t* data = static_cast(contents); size_t data_length = size; // get length in wchar_t units size_t length = data_length; // allocate buffer of suitable length char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; // convert latin1 input to wchar_t wchar_writer::value_type obegin = reinterpret_cast(buffer); wchar_writer::value_type oend = utf_decoder::decode_latin1_block(data, data_length, obegin); assert(oend == obegin + length); *oend = 0; out_buffer = buffer; out_length = length + 1; return true; } PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) { // get native encoding xml_encoding wchar_encoding = get_wchar_encoding(); // fast path: no conversion required if (encoding == wchar_encoding) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); // only endian-swapping is required if (need_endian_swap_utf(encoding, wchar_encoding)) return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable); // source encoding is utf8 if (encoding == encoding_utf8) return convert_buffer_utf8(out_buffer, out_length, contents, size); // source encoding is utf16 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; return (native_encoding == encoding) ? convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) : convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true()); } // source encoding is utf32 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; return (native_encoding == encoding) ? convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); } // source encoding is latin1 if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size); assert(!"Invalid encoding"); return false; } #else template PUGI__FN bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) { const uint16_t* data = static_cast(contents); size_t data_length = size / sizeof(uint16_t); // first pass: get length in utf8 units size_t length = utf_decoder::decode_utf16_block(data, data_length, 0); // allocate buffer of suitable length char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; // second pass: convert utf16 input to utf8 uint8_t* obegin = reinterpret_cast(buffer); uint8_t* oend = utf_decoder::decode_utf16_block(data, data_length, obegin); assert(oend == obegin + length); *oend = 0; out_buffer = buffer; out_length = length + 1; return true; } template PUGI__FN bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) { const uint32_t* data = static_cast(contents); size_t data_length = size / sizeof(uint32_t); // first pass: get length in utf8 units size_t length = utf_decoder::decode_utf32_block(data, data_length, 0); // allocate buffer of suitable length char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; // second pass: convert utf32 input to utf8 uint8_t* obegin = reinterpret_cast(buffer); uint8_t* oend = utf_decoder::decode_utf32_block(data, data_length, obegin); assert(oend == obegin + length); *oend = 0; out_buffer = buffer; out_length = length + 1; return true; } PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size) { for (size_t i = 0; i < size; ++i) if (data[i] > 127) return i; return size; } PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) { const uint8_t* data = static_cast(contents); size_t data_length = size; // get size of prefix that does not need utf8 conversion size_t prefix_length = get_latin1_7bit_prefix_length(data, data_length); assert(prefix_length <= data_length); const uint8_t* postfix = data + prefix_length; size_t postfix_length = data_length - prefix_length; // if no conversion is needed, just return the original buffer if (postfix_length == 0) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); // first pass: get length in utf8 units size_t length = prefix_length + utf_decoder::decode_latin1_block(postfix, postfix_length, 0); // allocate buffer of suitable length char_t* buffer = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!buffer) return false; // second pass: convert latin1 input to utf8 memcpy(buffer, data, prefix_length); uint8_t* obegin = reinterpret_cast(buffer); uint8_t* oend = utf_decoder::decode_latin1_block(postfix, postfix_length, obegin + prefix_length); assert(oend == obegin + length); *oend = 0; out_buffer = buffer; out_length = length + 1; return true; } PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) { // fast path: no conversion required if (encoding == encoding_utf8) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); // source encoding is utf16 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; return (native_encoding == encoding) ? convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) : convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true()); } // source encoding is utf32 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) { xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; return (native_encoding == encoding) ? convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); } // source encoding is latin1 if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable); assert(!"Invalid encoding"); return false; } #endif PUGI__FN size_t as_utf8_begin(const wchar_t* str, size_t length) { // get length in utf8 characters return utf_decoder::decode_wchar_block(str, length, 0); } PUGI__FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length) { // convert to utf8 uint8_t* begin = reinterpret_cast(buffer); uint8_t* end = utf_decoder::decode_wchar_block(str, length, begin); assert(begin + size == end); (void)!end; // zero-terminate buffer[size] = 0; } #ifndef PUGIXML_NO_STL PUGI__FN std::string as_utf8_impl(const wchar_t* str, size_t length) { // first pass: get length in utf8 characters size_t size = as_utf8_begin(str, length); // allocate resulting string std::string result; result.resize(size); // second pass: convert to utf8 if (size > 0) as_utf8_end(&result[0], size, str, length); return result; } PUGI__FN std::basic_string as_wide_impl(const char* str, size_t size) { const uint8_t* data = reinterpret_cast(str); // first pass: get length in wchar_t units size_t length = utf_decoder::decode_utf8_block(data, size, 0); // allocate resulting string std::basic_string result; result.resize(length); // second pass: convert to wchar_t if (length > 0) { wchar_writer::value_type begin = reinterpret_cast(&result[0]); wchar_writer::value_type end = utf_decoder::decode_utf8_block(data, size, begin); assert(begin + length == end); (void)!end; } return result; } #endif inline bool strcpy_insitu_allow(size_t length, uintptr_t header, uintptr_t header_mask, char_t* target) { // never reuse shared memory if (header & xml_memory_page_contents_shared_mask) return false; size_t target_length = strlength(target); // always reuse document buffer memory if possible if ((header & header_mask) == 0) return target_length >= length; // reuse heap memory if waste is not too great const size_t reuse_threshold = 32; return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2); } PUGI__FN bool strcpy_insitu(char_t*& dest, uintptr_t& header, uintptr_t header_mask, const char_t* source) { assert(header); size_t source_length = strlength(source); if (source_length == 0) { // empty string and null pointer are equivalent, so just deallocate old memory xml_allocator* alloc = reinterpret_cast(header & xml_memory_page_pointer_mask)->allocator; if (header & header_mask) alloc->deallocate_string(dest); // mark the string as not allocated dest = 0; header &= ~header_mask; return true; } else if (dest && strcpy_insitu_allow(source_length, header, header_mask, dest)) { // we can reuse old buffer, so just copy the new data (including zero terminator) memcpy(dest, source, (source_length + 1) * sizeof(char_t)); return true; } else { xml_allocator* alloc = reinterpret_cast(header & xml_memory_page_pointer_mask)->allocator; // allocate new buffer char_t* buf = alloc->allocate_string(source_length + 1); if (!buf) return false; // copy the string (including zero terminator) memcpy(buf, source, (source_length + 1) * sizeof(char_t)); // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures) if (header & header_mask) alloc->deallocate_string(dest); // the string is now allocated, so set the flag dest = buf; header |= header_mask; return true; } } struct gap { char_t* end; size_t size; gap(): end(0), size(0) { } // Push new gap, move s count bytes further (skipping the gap). // Collapse previous gap. void push(char_t*& s, size_t count) { if (end) // there was a gap already; collapse it { // Move [old_gap_end, new_gap_start) to [old_gap_start, ...) assert(s >= end); memmove(end - size, end, reinterpret_cast(s) - reinterpret_cast(end)); } s += count; // end of current gap // "merge" two gaps end = s; size += count; } // Collapse all gaps, return past-the-end pointer char_t* flush(char_t* s) { if (end) { // Move [old_gap_end, current_pos) to [old_gap_start, ...) assert(s >= end); memmove(end - size, end, reinterpret_cast(s) - reinterpret_cast(end)); return s - size; } else return s; } }; PUGI__FN char_t* strconv_escape(char_t* s, gap& g) { char_t* stre = s + 1; switch (*stre) { case '#': // &#... { unsigned int ucsc = 0; if (stre[1] == 'x') // &#x... (hex code) { stre += 2; char_t ch = *stre; if (ch == ';') return stre; for (;;) { if (static_cast(ch - '0') <= 9) ucsc = 16 * ucsc + (ch - '0'); else if (static_cast((ch | ' ') - 'a') <= 5) ucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10); else if (ch == ';') break; else // cancel return stre; ch = *++stre; } ++stre; } else // &#... (dec code) { char_t ch = *++stre; if (ch == ';') return stre; for (;;) { if (static_cast(static_cast(ch) - '0') <= 9) ucsc = 10 * ucsc + (ch - '0'); else if (ch == ';') break; else // cancel return stre; ch = *++stre; } ++stre; } #ifdef PUGIXML_WCHAR_MODE s = reinterpret_cast(wchar_writer::any(reinterpret_cast(s), ucsc)); #else s = reinterpret_cast(utf8_writer::any(reinterpret_cast(s), ucsc)); #endif g.push(s, stre - s); return stre; } case 'a': // &a { ++stre; if (*stre == 'm') // &am { if (*++stre == 'p' && *++stre == ';') // & { *s++ = '&'; ++stre; g.push(s, stre - s); return stre; } } else if (*stre == 'p') // &ap { if (*++stre == 'o' && *++stre == 's' && *++stre == ';') // ' { *s++ = '\''; ++stre; g.push(s, stre - s); return stre; } } break; } case 'g': // &g { if (*++stre == 't' && *++stre == ';') // > { *s++ = '>'; ++stre; g.push(s, stre - s); return stre; } break; } case 'l': // &l { if (*++stre == 't' && *++stre == ';') // < { *s++ = '<'; ++stre; g.push(s, stre - s); return stre; } break; } case 'q': // &q { if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // " { *s++ = '"'; ++stre; g.push(s, stre - s); return stre; } break; } default: break; } return stre; } // Parser utilities #define PUGI__ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e))) #define PUGI__SKIPWS() { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; } #define PUGI__OPTSET(OPT) ( optmsk & (OPT) ) #define PUGI__PUSHNODE(TYPE) { cursor = append_new_node(cursor, alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); } #define PUGI__POPNODE() { cursor = cursor->parent; } #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; } #define PUGI__SCANWHILE(X) { while (X) ++s; } #define PUGI__SCANWHILE_UNROLL(X) { for (;;) { char_t ss = s[0]; if (PUGI__UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI__UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI__UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI__UNLIKELY(!(X))) { s += 3; break; } s += 4; } } #define PUGI__ENDSEG() { ch = *s; *s = 0; ++s; } #define PUGI__THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast(0) #define PUGI__CHECK_ERROR(err, m) { if (*s == 0) PUGI__THROW_ERROR(err, m); } PUGI__FN char_t* strconv_comment(char_t* s, char_t endch) { gap g; while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_comment)); if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair { *s++ = '\n'; // replace first one with 0x0a if (*s == '\n') g.push(s, 1); } else if (s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')) // comment ends here { *g.flush(s) = 0; return s + (s[2] == '>' ? 3 : 2); } else if (*s == 0) { return 0; } else ++s; } } PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch) { gap g; while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_cdata)); if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair { *s++ = '\n'; // replace first one with 0x0a if (*s == '\n') g.push(s, 1); } else if (s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')) // CDATA ends here { *g.flush(s) = 0; return s + 1; } else if (*s == 0) { return 0; } else ++s; } } typedef char_t* (*strconv_pcdata_t)(char_t*); template struct strconv_pcdata_impl { static char_t* parse(char_t* s) { gap g; char_t* begin = s; while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_pcdata)); if (*s == '<') // PCDATA ends here { char_t* end = g.flush(s); if (opt_trim::value) while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space)) --end; *end = 0; return s + 1; } else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair { *s++ = '\n'; // replace first one with 0x0a if (*s == '\n') g.push(s, 1); } else if (opt_escape::value && *s == '&') { s = strconv_escape(s, g); } else if (*s == 0) { char_t* end = g.flush(s); if (opt_trim::value) while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space)) --end; *end = 0; return s; } else ++s; } } }; PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask) { PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800); switch (((optmask >> 4) & 3) | ((optmask >> 9) & 4)) // get bitmask for flags (eol escapes trim) { case 0: return strconv_pcdata_impl::parse; case 1: return strconv_pcdata_impl::parse; case 2: return strconv_pcdata_impl::parse; case 3: return strconv_pcdata_impl::parse; case 4: return strconv_pcdata_impl::parse; case 5: return strconv_pcdata_impl::parse; case 6: return strconv_pcdata_impl::parse; case 7: return strconv_pcdata_impl::parse; default: assert(false); return 0; // should not get here } } typedef char_t* (*strconv_attribute_t)(char_t*, char_t); template struct strconv_attribute_impl { static char_t* parse_wnorm(char_t* s, char_t end_quote) { gap g; // trim leading whitespaces if (PUGI__IS_CHARTYPE(*s, ct_space)) { char_t* str = s; do ++str; while (PUGI__IS_CHARTYPE(*str, ct_space)); g.push(s, str - s); } while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws | ct_space)); if (*s == end_quote) { char_t* str = g.flush(s); do *str-- = 0; while (PUGI__IS_CHARTYPE(*str, ct_space)); return s + 1; } else if (PUGI__IS_CHARTYPE(*s, ct_space)) { *s++ = ' '; if (PUGI__IS_CHARTYPE(*s, ct_space)) { char_t* str = s + 1; while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str; g.push(s, str - s); } } else if (opt_escape::value && *s == '&') { s = strconv_escape(s, g); } else if (!*s) { return 0; } else ++s; } } static char_t* parse_wconv(char_t* s, char_t end_quote) { gap g; while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws)); if (*s == end_quote) { *g.flush(s) = 0; return s + 1; } else if (PUGI__IS_CHARTYPE(*s, ct_space)) { if (*s == '\r') { *s++ = ' '; if (*s == '\n') g.push(s, 1); } else *s++ = ' '; } else if (opt_escape::value && *s == '&') { s = strconv_escape(s, g); } else if (!*s) { return 0; } else ++s; } } static char_t* parse_eol(char_t* s, char_t end_quote) { gap g; while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); if (*s == end_quote) { *g.flush(s) = 0; return s + 1; } else if (*s == '\r') { *s++ = '\n'; if (*s == '\n') g.push(s, 1); } else if (opt_escape::value && *s == '&') { s = strconv_escape(s, g); } else if (!*s) { return 0; } else ++s; } } static char_t* parse_simple(char_t* s, char_t end_quote) { gap g; while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); if (*s == end_quote) { *g.flush(s) = 0; return s + 1; } else if (opt_escape::value && *s == '&') { s = strconv_escape(s, g); } else if (!*s) { return 0; } else ++s; } } }; PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask) { PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80); switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes) { case 0: return strconv_attribute_impl::parse_simple; case 1: return strconv_attribute_impl::parse_simple; case 2: return strconv_attribute_impl::parse_eol; case 3: return strconv_attribute_impl::parse_eol; case 4: return strconv_attribute_impl::parse_wconv; case 5: return strconv_attribute_impl::parse_wconv; case 6: return strconv_attribute_impl::parse_wconv; case 7: return strconv_attribute_impl::parse_wconv; case 8: return strconv_attribute_impl::parse_wnorm; case 9: return strconv_attribute_impl::parse_wnorm; case 10: return strconv_attribute_impl::parse_wnorm; case 11: return strconv_attribute_impl::parse_wnorm; case 12: return strconv_attribute_impl::parse_wnorm; case 13: return strconv_attribute_impl::parse_wnorm; case 14: return strconv_attribute_impl::parse_wnorm; case 15: return strconv_attribute_impl::parse_wnorm; default: assert(false); return 0; // should not get here } } inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0) { xml_parse_result result; result.status = status; result.offset = offset; return result; } struct xml_parser { xml_allocator alloc; char_t* error_offset; xml_parse_status error_status; xml_parser(const xml_allocator& alloc_): alloc(alloc_), error_offset(0), error_status(status_ok) { } // DOCTYPE consists of nested sections of the following possible types: // , , "...", '...' // // // First group can not contain nested groups // Second group can contain nested groups of the same type // Third group can contain all other groups char_t* parse_doctype_primitive(char_t* s) { if (*s == '"' || *s == '\'') { // quoted string char_t ch = *s++; PUGI__SCANFOR(*s == ch); if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); s++; } else if (s[0] == '<' && s[1] == '?') { // s += 2; PUGI__SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); s += 2; } else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-') { s += 4; PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); s += 3; } else PUGI__THROW_ERROR(status_bad_doctype, s); return s; } char_t* parse_doctype_ignore(char_t* s) { size_t depth = 0; assert(s[0] == '<' && s[1] == '!' && s[2] == '['); s += 3; while (*s) { if (s[0] == '<' && s[1] == '!' && s[2] == '[') { // nested ignore section s += 3; depth++; } else if (s[0] == ']' && s[1] == ']' && s[2] == '>') { // ignore section end s += 3; if (depth == 0) return s; depth--; } else s++; } PUGI__THROW_ERROR(status_bad_doctype, s); } char_t* parse_doctype_group(char_t* s, char_t endch) { size_t depth = 0; assert((s[0] == '<' || s[0] == 0) && s[1] == '!'); s += 2; while (*s) { if (s[0] == '<' && s[1] == '!' && s[2] != '-') { if (s[2] == '[') { // ignore s = parse_doctype_ignore(s); if (!s) return s; } else { // some control group s += 2; depth++; } } else if (s[0] == '<' || s[0] == '"' || s[0] == '\'') { // unknown tag (forbidden), or some primitive group s = parse_doctype_primitive(s); if (!s) return s; } else if (*s == '>') { if (depth == 0) return s; depth--; s++; } else s++; } if (depth != 0 || endch != '>') PUGI__THROW_ERROR(status_bad_doctype, s); return s; } char_t* parse_exclamation(char_t* s, xml_node_struct* cursor, unsigned int optmsk, char_t endch) { // parse node contents, starting with exclamation mark ++s; if (*s == '-') // 'value = s; // Save the offset. } if (PUGI__OPTSET(parse_eol) && PUGI__OPTSET(parse_comments)) { s = strconv_comment(s, endch); if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value); } else { // Scan for terminating '-->'. PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')); PUGI__CHECK_ERROR(status_bad_comment, s); if (PUGI__OPTSET(parse_comments)) *s = 0; // Zero-terminate this segment at the first terminating '-'. s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'. } } else PUGI__THROW_ERROR(status_bad_comment, s); } else if (*s == '[') { // 'value = s; // Save the offset. if (PUGI__OPTSET(parse_eol)) { s = strconv_cdata(s, endch); if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value); } else { // Scan for terminating ']]>'. PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')); PUGI__CHECK_ERROR(status_bad_cdata, s); *s++ = 0; // Zero-terminate this segment. } } else // Flagged for discard, but we still have to scan for the terminator. { // Scan for terminating ']]>'. PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')); PUGI__CHECK_ERROR(status_bad_cdata, s); ++s; } s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'. } else PUGI__THROW_ERROR(status_bad_cdata, s); } else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && PUGI__ENDSWITH(s[6], 'E')) { s -= 2; if (cursor->parent) PUGI__THROW_ERROR(status_bad_doctype, s); char_t* mark = s + 9; s = parse_doctype_group(s, endch); if (!s) return s; assert((*s == 0 && endch == '>') || *s == '>'); if (*s) *s++ = 0; if (PUGI__OPTSET(parse_doctype)) { while (PUGI__IS_CHARTYPE(*mark, ct_space)) ++mark; PUGI__PUSHNODE(node_doctype); cursor->value = mark; } } else if (*s == 0 && endch == '-') PUGI__THROW_ERROR(status_bad_comment, s); else if (*s == 0 && endch == '[') PUGI__THROW_ERROR(status_bad_cdata, s); else PUGI__THROW_ERROR(status_unrecognized_tag, s); return s; } char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor, unsigned int optmsk, char_t endch) { // load into registers xml_node_struct* cursor = ref_cursor; char_t ch = 0; // parse node contents, starting with question mark ++s; // read PI target char_t* target = s; if (!PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_pi, s); PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); PUGI__CHECK_ERROR(status_bad_pi, s); // determine node type; stricmp / strcasecmp is not portable bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s; if (declaration ? PUGI__OPTSET(parse_declaration) : PUGI__OPTSET(parse_pi)) { if (declaration) { // disallow non top-level declarations if (cursor->parent) PUGI__THROW_ERROR(status_bad_pi, s); PUGI__PUSHNODE(node_declaration); } else { PUGI__PUSHNODE(node_pi); } cursor->name = target; PUGI__ENDSEG(); // parse value/attributes if (ch == '?') { // empty node if (!PUGI__ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_pi, s); s += (*s == '>'); PUGI__POPNODE(); } else if (PUGI__IS_CHARTYPE(ch, ct_space)) { PUGI__SKIPWS(); // scan for tag end char_t* value = s; PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>')); PUGI__CHECK_ERROR(status_bad_pi, s); if (declaration) { // replace ending ? with / so that 'element' terminates properly *s = '/'; // we exit from this function with cursor at node_declaration, which is a signal to parse() to go to LOC_ATTRIBUTES s = value; } else { // store value and step over > cursor->value = value; PUGI__POPNODE(); PUGI__ENDSEG(); s += (*s == '>'); } } else PUGI__THROW_ERROR(status_bad_pi, s); } else { // scan for tag end PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>')); PUGI__CHECK_ERROR(status_bad_pi, s); s += (s[1] == '>' ? 2 : 1); } // store from registers ref_cursor = cursor; return s; } char_t* parse_tree(char_t* s, xml_node_struct* root, unsigned int optmsk, char_t endch) { strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk); strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk); char_t ch = 0; xml_node_struct* cursor = root; char_t* mark = s; while (*s != 0) { if (*s == '<') { ++s; LOC_TAG: if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // '<#...' { PUGI__PUSHNODE(node_element); // Append a new node to the tree. cursor->name = s; PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. PUGI__ENDSEG(); // Save char in 'ch', terminate & step over. if (ch == '>') { // end of tag } else if (PUGI__IS_CHARTYPE(ch, ct_space)) { LOC_ATTRIBUTES: while (true) { PUGI__SKIPWS(); // Eat any whitespace. if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #... { xml_attribute_struct* a = append_new_attribute(cursor, alloc); // Make space for this attribute. if (!a) PUGI__THROW_ERROR(status_out_of_memory, s); a->name = s; // Save the offset. PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. PUGI__ENDSEG(); // Save char in 'ch', terminate & step over. if (PUGI__IS_CHARTYPE(ch, ct_space)) { PUGI__SKIPWS(); // Eat any whitespace. ch = *s; ++s; } if (ch == '=') // '<... #=...' { PUGI__SKIPWS(); // Eat any whitespace. if (*s == '"' || *s == '\'') // '<... #="...' { ch = *s; // Save quote char to avoid breaking on "''" -or- '""'. ++s; // Step over the quote. a->value = s; // Save the offset. s = strconv_attribute(s, ch); if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value); // After this line the loop continues from the start; // Whitespaces, / and > are ok, symbols and EOF are wrong, // everything else will be detected if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_attribute, s); } else PUGI__THROW_ERROR(status_bad_attribute, s); } else PUGI__THROW_ERROR(status_bad_attribute, s); } else if (*s == '/') { ++s; if (*s == '>') { PUGI__POPNODE(); s++; break; } else if (*s == 0 && endch == '>') { PUGI__POPNODE(); break; } else PUGI__THROW_ERROR(status_bad_start_element, s); } else if (*s == '>') { ++s; break; } else if (*s == 0 && endch == '>') { break; } else PUGI__THROW_ERROR(status_bad_start_element, s); } // !!! } else if (ch == '/') // '<#.../' { if (!PUGI__ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_start_element, s); PUGI__POPNODE(); // Pop. s += (*s == '>'); } else if (ch == 0) { // we stepped over null terminator, backtrack & handle closing tag --s; if (endch != '>') PUGI__THROW_ERROR(status_bad_start_element, s); } else PUGI__THROW_ERROR(status_bad_start_element, s); } else if (*s == '/') { ++s; char_t* name = cursor->name; if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, s); while (PUGI__IS_CHARTYPE(*s, ct_symbol)) { if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, s); } if (*name) { if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s); else PUGI__THROW_ERROR(status_end_element_mismatch, s); } PUGI__POPNODE(); // Pop. PUGI__SKIPWS(); if (*s == 0) { if (endch != '>') PUGI__THROW_ERROR(status_bad_end_element, s); } else { if (*s != '>') PUGI__THROW_ERROR(status_bad_end_element, s); ++s; } } else if (*s == '?') // 'first_child) continue; } } if (!PUGI__OPTSET(parse_trim_pcdata)) s = mark; if (cursor->parent || PUGI__OPTSET(parse_fragment)) { PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree. cursor->value = s; // Save the offset. s = strconv_pcdata(s); PUGI__POPNODE(); // Pop since this is a standalone. if (!*s) break; } else { PUGI__SCANFOR(*s == '<'); // '...<' if (!*s) break; ++s; } // We're after '<' goto LOC_TAG; } } // check that last tag is closed if (cursor != root) PUGI__THROW_ERROR(status_end_element_mismatch, s); return s; } #ifdef PUGIXML_WCHAR_MODE static char_t* parse_skip_bom(char_t* s) { unsigned int bom = 0xfeff; return (s[0] == static_cast(bom)) ? s + 1 : s; } #else static char_t* parse_skip_bom(char_t* s) { return (s[0] == '\xef' && s[1] == '\xbb' && s[2] == '\xbf') ? s + 3 : s; } #endif static bool has_element_node_siblings(xml_node_struct* node) { while (node) { if (PUGI__NODETYPE(node) == node_element) return true; node = node->next_sibling; } return false; } static xml_parse_result parse(char_t* buffer, size_t length, xml_document_struct* xmldoc, xml_node_struct* root, unsigned int optmsk) { // allocator object is a part of document object xml_allocator& alloc_ = *static_cast(xmldoc); // early-out for empty documents if (length == 0) return make_parse_result(PUGI__OPTSET(parse_fragment) ? status_ok : status_no_document_element); // get last child of the root before parsing xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c : 0; // create parser on stack xml_parser parser(alloc_); // save last character and make buffer zero-terminated (speeds up parsing) char_t endch = buffer[length - 1]; buffer[length - 1] = 0; // skip BOM to make sure it does not end up as part of parse output char_t* buffer_data = parse_skip_bom(buffer); // perform actual parsing parser.parse_tree(buffer_data, root, optmsk, endch); // update allocator state alloc_ = parser.alloc; xml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0); assert(result.offset >= 0 && static_cast(result.offset) <= length); if (result) { // since we removed last character, we have to handle the only possible false positive (stray <) if (endch == '<') return make_parse_result(status_unrecognized_tag, length - 1); // check if there are any element nodes parsed xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling : root->first_child; if (!PUGI__OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed)) return make_parse_result(status_no_document_element, length - 1); } else { // roll back offset if it occurs on a null terminator in the source buffer if (result.offset > 0 && static_cast(result.offset) == length - 1 && endch == 0) result.offset--; } return result; } }; // Output facilities PUGI__FN xml_encoding get_write_native_encoding() { #ifdef PUGIXML_WCHAR_MODE return get_wchar_encoding(); #else return encoding_utf8; #endif } PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding) { // replace wchar encoding with utf implementation if (encoding == encoding_wchar) return get_wchar_encoding(); // replace utf16 encoding with utf16 with specific endianness if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; // replace utf32 encoding with utf32 with specific endianness if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; // only do autodetection if no explicit encoding is requested if (encoding != encoding_auto) return encoding; // assume utf8 encoding return encoding_utf8; } #ifdef PUGIXML_WCHAR_MODE PUGI__FN size_t get_valid_length(const char_t* data, size_t length) { if (length < 1) return 0; // discard last character if it's the lead of a surrogate pair return (sizeof(wchar_t) == 2 && static_cast(static_cast(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length; } PUGI__FN size_t convert_buffer_output(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding) { // only endian-swapping is required if (need_endian_swap_utf(encoding, get_wchar_encoding())) { convert_wchar_endian_swap(r_char, data, length); return length * sizeof(char_t); } // convert to utf8 if (encoding == encoding_utf8) { uint8_t* dest = r_u8; uint8_t* end = utf_decoder::decode_wchar_block(data, length, dest); return static_cast(end - dest); } // convert to utf16 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) { uint16_t* dest = r_u16; // convert to native utf16 uint16_t* end = utf_decoder::decode_wchar_block(data, length, dest); // swap if necessary xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); return static_cast(end - dest) * sizeof(uint16_t); } // convert to utf32 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) { uint32_t* dest = r_u32; // convert to native utf32 uint32_t* end = utf_decoder::decode_wchar_block(data, length, dest); // swap if necessary xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); return static_cast(end - dest) * sizeof(uint32_t); } // convert to latin1 if (encoding == encoding_latin1) { uint8_t* dest = r_u8; uint8_t* end = utf_decoder::decode_wchar_block(data, length, dest); return static_cast(end - dest); } assert(!"Invalid encoding"); return 0; } #else PUGI__FN size_t get_valid_length(const char_t* data, size_t length) { if (length < 5) return 0; for (size_t i = 1; i <= 4; ++i) { uint8_t ch = static_cast(data[length - i]); // either a standalone character or a leading one if ((ch & 0xc0) != 0x80) return length - i; } // there are four non-leading characters at the end, sequence tail is broken so might as well process the whole chunk return length; } PUGI__FN size_t convert_buffer_output(char_t* /* r_char */, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding) { if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) { uint16_t* dest = r_u16; // convert to native utf16 uint16_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); // swap if necessary xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); return static_cast(end - dest) * sizeof(uint16_t); } if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) { uint32_t* dest = r_u32; // convert to native utf32 uint32_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); // swap if necessary xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); return static_cast(end - dest) * sizeof(uint32_t); } if (encoding == encoding_latin1) { uint8_t* dest = r_u8; uint8_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); return static_cast(end - dest); } assert(!"Invalid encoding"); return 0; } #endif class xml_buffered_writer { xml_buffered_writer(const xml_buffered_writer&); xml_buffered_writer& operator=(const xml_buffered_writer&); public: xml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding)) { PUGI__STATIC_ASSERT(bufcapacity >= 8); } ~xml_buffered_writer() { flush(); } size_t flush() { flush(buffer, bufsize); bufsize = 0; return 0; } void flush(const char_t* data, size_t size) { if (size == 0) return; // fast path, just write data if (encoding == get_write_native_encoding()) writer.write(data, size * sizeof(char_t)); else { // convert chunk size_t result = convert_buffer_output(scratch.data_char, scratch.data_u8, scratch.data_u16, scratch.data_u32, data, size, encoding); assert(result <= sizeof(scratch)); // write data writer.write(scratch.data_u8, result); } } void write_direct(const char_t* data, size_t length) { // flush the remaining buffer contents flush(); // handle large chunks if (length > bufcapacity) { if (encoding == get_write_native_encoding()) { // fast path, can just write data chunk writer.write(data, length * sizeof(char_t)); return; } // need to convert in suitable chunks while (length > bufcapacity) { // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary) size_t chunk_size = get_valid_length(data, bufcapacity); assert(chunk_size); // convert chunk and write flush(data, chunk_size); // iterate data += chunk_size; length -= chunk_size; } // small tail is copied below bufsize = 0; } memcpy(buffer + bufsize, data, length * sizeof(char_t)); bufsize += length; } void write_buffer(const char_t* data, size_t length) { size_t offset = bufsize; if (offset + length <= bufcapacity) { memcpy(buffer + offset, data, length * sizeof(char_t)); bufsize = offset + length; } else { write_direct(data, length); } } void write_string(const char_t* data) { // write the part of the string that fits in the buffer size_t offset = bufsize; while (*data && offset < bufcapacity) buffer[offset++] = *data++; // write the rest if (offset < bufcapacity) { bufsize = offset; } else { // backtrack a bit if we have split the codepoint size_t length = offset - bufsize; size_t extra = length - get_valid_length(data - length, length); bufsize = offset - extra; write_direct(data - extra, strlength(data) + extra); } } void write(char_t d0) { size_t offset = bufsize; if (offset > bufcapacity - 1) offset = flush(); buffer[offset + 0] = d0; bufsize = offset + 1; } void write(char_t d0, char_t d1) { size_t offset = bufsize; if (offset > bufcapacity - 2) offset = flush(); buffer[offset + 0] = d0; buffer[offset + 1] = d1; bufsize = offset + 2; } void write(char_t d0, char_t d1, char_t d2) { size_t offset = bufsize; if (offset > bufcapacity - 3) offset = flush(); buffer[offset + 0] = d0; buffer[offset + 1] = d1; buffer[offset + 2] = d2; bufsize = offset + 3; } void write(char_t d0, char_t d1, char_t d2, char_t d3) { size_t offset = bufsize; if (offset > bufcapacity - 4) offset = flush(); buffer[offset + 0] = d0; buffer[offset + 1] = d1; buffer[offset + 2] = d2; buffer[offset + 3] = d3; bufsize = offset + 4; } void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4) { size_t offset = bufsize; if (offset > bufcapacity - 5) offset = flush(); buffer[offset + 0] = d0; buffer[offset + 1] = d1; buffer[offset + 2] = d2; buffer[offset + 3] = d3; buffer[offset + 4] = d4; bufsize = offset + 5; } void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5) { size_t offset = bufsize; if (offset > bufcapacity - 6) offset = flush(); buffer[offset + 0] = d0; buffer[offset + 1] = d1; buffer[offset + 2] = d2; buffer[offset + 3] = d3; buffer[offset + 4] = d4; buffer[offset + 5] = d5; bufsize = offset + 6; } // utf8 maximum expansion: x4 (-> utf32) // utf16 maximum expansion: x2 (-> utf32) // utf32 maximum expansion: x1 enum { bufcapacitybytes = #ifdef PUGIXML_MEMORY_OUTPUT_STACK PUGIXML_MEMORY_OUTPUT_STACK #else 10240 #endif , bufcapacity = bufcapacitybytes / (sizeof(char_t) + 4) }; char_t buffer[bufcapacity]; union { uint8_t data_u8[4 * bufcapacity]; uint16_t data_u16[2 * bufcapacity]; uint32_t data_u32[bufcapacity]; char_t data_char[bufcapacity]; } scratch; xml_writer& writer; size_t bufsize; xml_encoding encoding; }; PUGI__FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type) { while (*s) { const char_t* prev = s; // While *s is a usual symbol PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPEX(ss, type)); writer.write_buffer(prev, static_cast(s - prev)); switch (*s) { case 0: break; case '&': writer.write('&', 'a', 'm', 'p', ';'); ++s; break; case '<': writer.write('&', 'l', 't', ';'); ++s; break; case '>': writer.write('&', 'g', 't', ';'); ++s; break; case '"': writer.write('&', 'q', 'u', 'o', 't', ';'); ++s; break; default: // s is not a usual symbol { unsigned int ch = static_cast(*s++); assert(ch < 32); writer.write('&', '#', static_cast((ch / 10) + '0'), static_cast((ch % 10) + '0'), ';'); } } } } PUGI__FN void text_output(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags) { if (flags & format_no_escapes) writer.write_string(s); else text_output_escaped(writer, s, type); } PUGI__FN void text_output_cdata(xml_buffered_writer& writer, const char_t* s) { do { writer.write('<', '!', '[', 'C', 'D'); writer.write('A', 'T', 'A', '['); const char_t* prev = s; // look for ]]> sequence - we can't output it as is since it terminates CDATA while (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>')) ++s; // skip ]] if we stopped at ]]>, > will go to the next CDATA section if (*s) s += 2; writer.write_buffer(prev, static_cast(s - prev)); writer.write(']', ']', '>'); } while (*s); } PUGI__FN void text_output_indent(xml_buffered_writer& writer, const char_t* indent, size_t indent_length, unsigned int depth) { switch (indent_length) { case 1: { for (unsigned int i = 0; i < depth; ++i) writer.write(indent[0]); break; } case 2: { for (unsigned int i = 0; i < depth; ++i) writer.write(indent[0], indent[1]); break; } case 3: { for (unsigned int i = 0; i < depth; ++i) writer.write(indent[0], indent[1], indent[2]); break; } case 4: { for (unsigned int i = 0; i < depth; ++i) writer.write(indent[0], indent[1], indent[2], indent[3]); break; } default: { for (unsigned int i = 0; i < depth; ++i) writer.write_buffer(indent, indent_length); } } } PUGI__FN void node_output_comment(xml_buffered_writer& writer, const char_t* s) { writer.write('<', '!', '-', '-'); while (*s) { const char_t* prev = s; // look for -\0 or -- sequence - we can't output it since -- is illegal in comment body while (*s && !(s[0] == '-' && (s[1] == '-' || s[1] == 0))) ++s; writer.write_buffer(prev, static_cast(s - prev)); if (*s) { assert(*s == '-'); writer.write('-', ' '); ++s; } } writer.write('-', '-', '>'); } PUGI__FN void node_output_pi_value(xml_buffered_writer& writer, const char_t* s) { while (*s) { const char_t* prev = s; // look for ?> sequence - we can't output it since ?> terminates PI while (*s && !(s[0] == '?' && s[1] == '>')) ++s; writer.write_buffer(prev, static_cast(s - prev)); if (*s) { assert(s[0] == '?' && s[1] == '>'); writer.write('?', ' ', '>'); s += 2; } } } PUGI__FN void node_output_attributes(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags) { const char_t* default_name = PUGIXML_TEXT(":anonymous"); for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute) { writer.write(' '); writer.write_string(a->name ? a->name : default_name); writer.write('=', '"'); if (a->value) text_output(writer, a->value, ctx_special_attr, flags); writer.write('"'); } } PUGI__FN bool node_output_start(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags) { const char_t* default_name = PUGIXML_TEXT(":anonymous"); const char_t* name = node->name ? node->name : default_name; writer.write('<'); writer.write_string(name); if (node->first_attribute) node_output_attributes(writer, node, flags); if (!node->first_child) { writer.write(' ', '/', '>'); return false; } else { writer.write('>'); return true; } } PUGI__FN void node_output_end(xml_buffered_writer& writer, xml_node_struct* node) { const char_t* default_name = PUGIXML_TEXT(":anonymous"); const char_t* name = node->name ? node->name : default_name; writer.write('<', '/'); writer.write_string(name); writer.write('>'); } PUGI__FN void node_output_simple(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags) { const char_t* default_name = PUGIXML_TEXT(":anonymous"); switch (PUGI__NODETYPE(node)) { case node_pcdata: text_output(writer, node->value ? node->value : PUGIXML_TEXT(""), ctx_special_pcdata, flags); break; case node_cdata: text_output_cdata(writer, node->value ? node->value : PUGIXML_TEXT("")); break; case node_comment: node_output_comment(writer, node->value ? node->value : PUGIXML_TEXT("")); break; case node_pi: writer.write('<', '?'); writer.write_string(node->name ? node->name : default_name); if (node->value) { writer.write(' '); node_output_pi_value(writer, node->value); } writer.write('?', '>'); break; case node_declaration: writer.write('<', '?'); writer.write_string(node->name ? node->name : default_name); node_output_attributes(writer, node, flags); writer.write('?', '>'); break; case node_doctype: writer.write('<', '!', 'D', 'O', 'C'); writer.write('T', 'Y', 'P', 'E'); if (node->value) { writer.write(' '); writer.write_string(node->value); } writer.write('>'); break; default: assert(!"Invalid node type"); } } enum indent_flags_t { indent_newline = 1, indent_indent = 2 }; PUGI__FN void node_output(xml_buffered_writer& writer, xml_node_struct* root, const char_t* indent, unsigned int flags, unsigned int depth) { size_t indent_length = ((flags & (format_indent | format_raw)) == format_indent) ? strlength(indent) : 0; unsigned int indent_flags = indent_indent; xml_node_struct* node = root; do { assert(node); // begin writing current node if (PUGI__NODETYPE(node) == node_pcdata || PUGI__NODETYPE(node) == node_cdata) { node_output_simple(writer, node, flags); indent_flags = 0; } else { if ((indent_flags & indent_newline) && (flags & format_raw) == 0) writer.write('\n'); if ((indent_flags & indent_indent) && indent_length) text_output_indent(writer, indent, indent_length, depth); if (PUGI__NODETYPE(node) == node_element) { indent_flags = indent_newline | indent_indent; if (node_output_start(writer, node, flags)) { node = node->first_child; depth++; continue; } } else if (PUGI__NODETYPE(node) == node_document) { indent_flags = indent_indent; if (node->first_child) { node = node->first_child; continue; } } else { node_output_simple(writer, node, flags); indent_flags = indent_newline | indent_indent; } } // continue to the next node while (node != root) { if (node->next_sibling) { node = node->next_sibling; break; } node = node->parent; // write closing node if (PUGI__NODETYPE(node) == node_element) { depth--; if ((indent_flags & indent_newline) && (flags & format_raw) == 0) writer.write('\n'); if ((indent_flags & indent_indent) && indent_length) text_output_indent(writer, indent, indent_length, depth); node_output_end(writer, node); indent_flags = indent_newline | indent_indent; } } } while (node != root); if ((indent_flags & indent_newline) && (flags & format_raw) == 0) writer.write('\n'); } PUGI__FN bool has_declaration(xml_node_struct* node) { for (xml_node_struct* child = node->first_child; child; child = child->next_sibling) { xml_node_type type = PUGI__NODETYPE(child); if (type == node_declaration) return true; if (type == node_element) return false; } return false; } PUGI__FN bool is_attribute_of(xml_attribute_struct* attr, xml_node_struct* node) { for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute) if (a == attr) return true; return false; } PUGI__FN bool allow_insert_attribute(xml_node_type parent) { return parent == node_element || parent == node_declaration; } PUGI__FN bool allow_insert_child(xml_node_type parent, xml_node_type child) { if (parent != node_document && parent != node_element) return false; if (child == node_document || child == node_null) return false; if (parent != node_document && (child == node_declaration || child == node_doctype)) return false; return true; } PUGI__FN bool allow_move(xml_node parent, xml_node child) { // check that child can be a child of parent if (!allow_insert_child(parent.type(), child.type())) return false; // check that node is not moved between documents if (parent.root() != child.root()) return false; // check that new parent is not in the child subtree xml_node cur = parent; while (cur) { if (cur == child) return false; cur = cur.parent(); } return true; } PUGI__FN void node_copy_string(char_t*& dest, uintptr_t& header, uintptr_t header_mask, char_t* source, uintptr_t& source_header, xml_allocator* alloc) { assert(!dest && (header & header_mask) == 0); if (source) { if (alloc && (source_header & header_mask) == 0) { dest = source; // since strcpy_insitu can reuse document buffer memory we need to mark both source and dest as shared header |= xml_memory_page_contents_shared_mask; source_header |= xml_memory_page_contents_shared_mask; } else strcpy_insitu(dest, header, header_mask, source); } } PUGI__FN void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn, xml_allocator* shared_alloc) { node_copy_string(dn->name, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->header, shared_alloc); node_copy_string(dn->value, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->header, shared_alloc); for (xml_attribute_struct* sa = sn->first_attribute; sa; sa = sa->next_attribute) { xml_attribute_struct* da = append_new_attribute(dn, get_allocator(dn)); if (da) { node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc); node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc); } } } PUGI__FN void node_copy_tree(xml_node_struct* dn, xml_node_struct* sn) { xml_allocator& alloc = get_allocator(dn); xml_allocator* shared_alloc = (&alloc == &get_allocator(sn)) ? &alloc : 0; node_copy_contents(dn, sn, shared_alloc); xml_node_struct* dit = dn; xml_node_struct* sit = sn->first_child; while (sit && sit != sn) { if (sit != dn) { xml_node_struct* copy = append_new_node(dit, alloc, PUGI__NODETYPE(sit)); if (copy) { node_copy_contents(copy, sit, shared_alloc); if (sit->first_child) { dit = copy; sit = sit->first_child; continue; } } } // continue to the next node do { if (sit->next_sibling) { sit = sit->next_sibling; break; } sit = sit->parent; dit = dit->parent; } while (sit != sn); } } inline bool is_text_node(xml_node_struct* node) { xml_node_type type = PUGI__NODETYPE(node); return type == node_pcdata || type == node_cdata; } // get value with conversion functions PUGI__FN int get_integer_base(const char_t* value) { const char_t* s = value; while (PUGI__IS_CHARTYPE(*s, ct_space)) s++; if (*s == '-') s++; return (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10; } PUGI__FN int get_value_int(const char_t* value, int def) { if (!value) return def; int base = get_integer_base(value); #ifdef PUGIXML_WCHAR_MODE return static_cast(wcstol(value, 0, base)); #else return static_cast(strtol(value, 0, base)); #endif } PUGI__FN unsigned int get_value_uint(const char_t* value, unsigned int def) { if (!value) return def; int base = get_integer_base(value); #ifdef PUGIXML_WCHAR_MODE return static_cast(wcstoul(value, 0, base)); #else return static_cast(strtoul(value, 0, base)); #endif } PUGI__FN double get_value_double(const char_t* value, double def) { if (!value) return def; #ifdef PUGIXML_WCHAR_MODE return wcstod(value, 0); #else return strtod(value, 0); #endif } PUGI__FN float get_value_float(const char_t* value, float def) { if (!value) return def; #ifdef PUGIXML_WCHAR_MODE return static_cast(wcstod(value, 0)); #else return static_cast(strtod(value, 0)); #endif } PUGI__FN bool get_value_bool(const char_t* value, bool def) { if (!value) return def; // only look at first char char_t first = *value; // 1*, t* (true), T* (True), y* (yes), Y* (YES) return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y'); } #ifdef PUGIXML_HAS_LONG_LONG PUGI__FN long long get_value_llong(const char_t* value, long long def) { if (!value) return def; int base = get_integer_base(value); #ifdef PUGIXML_WCHAR_MODE #ifdef PUGI__MSVC_CRT_VERSION return _wcstoi64(value, 0, base); #else return wcstoll(value, 0, base); #endif #else #ifdef PUGI__MSVC_CRT_VERSION return _strtoi64(value, 0, base); #else return strtoll(value, 0, base); #endif #endif } PUGI__FN unsigned long long get_value_ullong(const char_t* value, unsigned long long def) { if (!value) return def; int base = get_integer_base(value); #ifdef PUGIXML_WCHAR_MODE #ifdef PUGI__MSVC_CRT_VERSION return _wcstoui64(value, 0, base); #else return wcstoull(value, 0, base); #endif #else #ifdef PUGI__MSVC_CRT_VERSION return _strtoui64(value, 0, base); #else return strtoull(value, 0, base); #endif #endif } #endif // set value with conversion functions PUGI__FN bool set_value_buffer(char_t*& dest, uintptr_t& header, uintptr_t header_mask, char (&buf)[128]) { #ifdef PUGIXML_WCHAR_MODE char_t wbuf[128]; impl::widen_ascii(wbuf, buf); return strcpy_insitu(dest, header, header_mask, wbuf); #else return strcpy_insitu(dest, header, header_mask, buf); #endif } PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, int value) { char buf[128]; sprintf(buf, "%d", value); return set_value_buffer(dest, header, header_mask, buf); } PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, unsigned int value) { char buf[128]; sprintf(buf, "%u", value); return set_value_buffer(dest, header, header_mask, buf); } PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, float value) { char buf[128]; sprintf(buf, "%.9g", value); return set_value_buffer(dest, header, header_mask, buf); } PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, double value) { char buf[128]; sprintf(buf, "%.17g", value); return set_value_buffer(dest, header, header_mask, buf); } PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, bool value) { return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); } #ifdef PUGIXML_HAS_LONG_LONG PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, long long value) { char buf[128]; sprintf(buf, "%lld", value); return set_value_buffer(dest, header, header_mask, buf); } PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, unsigned long long value) { char buf[128]; sprintf(buf, "%llu", value); return set_value_buffer(dest, header, header_mask, buf); } #endif // we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick PUGI__FN xml_parse_status get_file_size(FILE* file, size_t& out_result) { #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE) // there are 64-bit versions of fseek/ftell, let's use them typedef __int64 length_type; _fseeki64(file, 0, SEEK_END); length_type length = _ftelli64(file); _fseeki64(file, 0, SEEK_SET); #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR)) // there are 64-bit versions of fseek/ftell, let's use them typedef off64_t length_type; fseeko64(file, 0, SEEK_END); length_type length = ftello64(file); fseeko64(file, 0, SEEK_SET); #else // if this is a 32-bit OS, long is enough; if this is a unix system, long is 64-bit, which is enough; otherwise we can't do anything anyway. typedef long length_type; fseek(file, 0, SEEK_END); length_type length = ftell(file); fseek(file, 0, SEEK_SET); #endif // check for I/O errors if (length < 0) return status_io_error; // check for overflow size_t result = static_cast(length); if (static_cast(result) != length) return status_out_of_memory; // finalize out_result = result; return status_ok; } PUGI__FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding) { // We only need to zero-terminate if encoding conversion does not do it for us #ifdef PUGIXML_WCHAR_MODE xml_encoding wchar_encoding = get_wchar_encoding(); if (encoding == wchar_encoding || need_endian_swap_utf(encoding, wchar_encoding)) { size_t length = size / sizeof(char_t); static_cast(buffer)[length] = 0; return (length + 1) * sizeof(char_t); } #else if (encoding == encoding_utf8) { static_cast(buffer)[size] = 0; return size + 1; } #endif return size; } PUGI__FN xml_parse_result load_file_impl(xml_document& doc, FILE* file, unsigned int options, xml_encoding encoding) { if (!file) return make_parse_result(status_file_not_found); // get file size (can result in I/O errors) size_t size = 0; xml_parse_status size_status = get_file_size(file, size); if (size_status != status_ok) { fclose(file); return make_parse_result(size_status); } size_t max_suffix_size = sizeof(char_t); // allocate buffer for the whole file char* contents = static_cast(xml_memory::allocate(size + max_suffix_size)); if (!contents) { fclose(file); return make_parse_result(status_out_of_memory); } // read file in memory size_t read_size = fread(contents, 1, size, file); fclose(file); if (read_size != size) { xml_memory::deallocate(contents); return make_parse_result(status_io_error); } xml_encoding real_encoding = get_buffer_encoding(encoding, contents, size); return doc.load_buffer_inplace_own(contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding); } #ifndef PUGIXML_NO_STL template struct xml_stream_chunk { static xml_stream_chunk* create() { void* memory = xml_memory::allocate(sizeof(xml_stream_chunk)); return new (memory) xml_stream_chunk(); } static void destroy(void* ptr) { xml_stream_chunk* chunk = static_cast(ptr); // free chunk chain while (chunk) { xml_stream_chunk* next_ = chunk->next; xml_memory::deallocate(chunk); chunk = next_; } } xml_stream_chunk(): next(0), size(0) { } xml_stream_chunk* next; size_t size; T data[xml_memory_page_size / sizeof(T)]; }; template PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream& stream, void** out_buffer, size_t* out_size) { buffer_holder chunks(0, xml_stream_chunk::destroy); // read file to a chunk list size_t total = 0; xml_stream_chunk* last = 0; while (!stream.eof()) { // allocate new chunk xml_stream_chunk* chunk = xml_stream_chunk::create(); if (!chunk) return status_out_of_memory; // append chunk to list if (last) last = last->next = chunk; else chunks.data = last = chunk; // read data to chunk stream.read(chunk->data, static_cast(sizeof(chunk->data) / sizeof(T))); chunk->size = static_cast(stream.gcount()) * sizeof(T); // read may set failbit | eofbit in case gcount() is less than read length, so check for other I/O errors if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error; // guard against huge files (chunk size is small enough to make this overflow check work) if (total + chunk->size < total) return status_out_of_memory; total += chunk->size; } size_t max_suffix_size = sizeof(char_t); // copy chunk list to a contiguous buffer char* buffer = static_cast(xml_memory::allocate(total + max_suffix_size)); if (!buffer) return status_out_of_memory; char* write = buffer; for (xml_stream_chunk* chunk = static_cast*>(chunks.data); chunk; chunk = chunk->next) { assert(write + chunk->size <= buffer + total); memcpy(write, chunk->data, chunk->size); write += chunk->size; } assert(write == buffer + total); // return buffer *out_buffer = buffer; *out_size = total; return status_ok; } template PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream& stream, void** out_buffer, size_t* out_size) { // get length of remaining data in stream typename std::basic_istream::pos_type pos = stream.tellg(); stream.seekg(0, std::ios::end); std::streamoff length = stream.tellg() - pos; stream.seekg(pos); if (stream.fail() || pos < 0) return status_io_error; // guard against huge files size_t read_length = static_cast(length); if (static_cast(read_length) != length || length < 0) return status_out_of_memory; size_t max_suffix_size = sizeof(char_t); // read stream data into memory (guard against stream exceptions with buffer holder) buffer_holder buffer(xml_memory::allocate(read_length * sizeof(T) + max_suffix_size), xml_memory::deallocate); if (!buffer.data) return status_out_of_memory; stream.read(static_cast(buffer.data), static_cast(read_length)); // read may set failbit | eofbit in case gcount() is less than read_length (i.e. line ending conversion), so check for other I/O errors if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error; // return buffer size_t actual_length = static_cast(stream.gcount()); assert(actual_length <= read_length); *out_buffer = buffer.release(); *out_size = actual_length * sizeof(T); return status_ok; } template PUGI__FN xml_parse_result load_stream_impl(xml_document& doc, std::basic_istream& stream, unsigned int options, xml_encoding encoding) { void* buffer = 0; size_t size = 0; xml_parse_status status = status_ok; // if stream has an error bit set, bail out (otherwise tellg() can fail and we'll clear error bits) if (stream.fail()) return make_parse_result(status_io_error); // load stream to memory (using seek-based implementation if possible, since it's faster and takes less memory) if (stream.tellg() < 0) { stream.clear(); // clear error flags that could be set by a failing tellg status = load_stream_data_noseek(stream, &buffer, &size); } else status = load_stream_data_seek(stream, &buffer, &size); if (status != status_ok) return make_parse_result(status); xml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size); return doc.load_buffer_inplace_own(buffer, zero_terminate_buffer(buffer, size, real_encoding), options, real_encoding); } #endif #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR))) PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) { return _wfopen(path, mode); } #else PUGI__FN char* convert_path_heap(const wchar_t* str) { assert(str); // first pass: get length in utf8 characters size_t length = strlength_wide(str); size_t size = as_utf8_begin(str, length); // allocate resulting string char* result = static_cast(xml_memory::allocate(size + 1)); if (!result) return 0; // second pass: convert to utf8 as_utf8_end(result, size, str, length); return result; } PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) { // there is no standard function to open wide paths, so our best bet is to try utf8 path char* path_utf8 = convert_path_heap(path); if (!path_utf8) return 0; // convert mode to ASCII (we mirror _wfopen interface) char mode_ascii[4] = {0}; for (size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast(mode[i]); // try to open the utf8 path FILE* result = fopen(path_utf8, mode_ascii); // free dummy buffer xml_memory::deallocate(path_utf8); return result; } #endif PUGI__FN bool save_file_impl(const xml_document& doc, FILE* file, const char_t* indent, unsigned int flags, xml_encoding encoding) { if (!file) return false; xml_writer_file writer(file); doc.save(writer, indent, flags, encoding); int result = ferror(file); fclose(file); return result == 0; } PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root, void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t** out_buffer) { // check input buffer if (!contents && size) return make_parse_result(status_io_error); // get actual encoding xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size); // get private buffer char_t* buffer = 0; size_t length = 0; if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory); // delete original buffer if we performed a conversion if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents); // store buffer for offset_debug doc->buffer = buffer; // parse xml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options); // remember encoding res.encoding = buffer_encoding; // grab onto buffer if it's our buffer, user is responsible for deallocating contents himself if (own || buffer != contents) *out_buffer = buffer; return res; } PUGI__NS_END namespace pugi { PUGI__FN xml_writer_file::xml_writer_file(void* file_): file(file_) { } PUGI__FN void xml_writer_file::write(const void* data, size_t size) { size_t result = fwrite(data, 1, size, static_cast(file)); (void)!result; // unfortunately we can't do proper error handling here } #ifndef PUGIXML_NO_STL PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream >& stream): narrow_stream(&stream), wide_stream(0) { } PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream >& stream): narrow_stream(0), wide_stream(&stream) { } PUGI__FN void xml_writer_stream::write(const void* data, size_t size) { if (narrow_stream) { assert(!wide_stream); narrow_stream->write(reinterpret_cast(data), static_cast(size)); } else { assert(wide_stream); assert(size % sizeof(wchar_t) == 0); wide_stream->write(reinterpret_cast(data), static_cast(size / sizeof(wchar_t))); } } #endif PUGI__FN xml_tree_walker::xml_tree_walker(): _depth(0) { } PUGI__FN xml_tree_walker::~xml_tree_walker() { } PUGI__FN int xml_tree_walker::depth() const { return _depth; } PUGI__FN bool xml_tree_walker::begin(xml_node&) { return true; } PUGI__FN bool xml_tree_walker::end(xml_node&) { return true; } PUGI__FN xml_attribute::xml_attribute(): _attr(0) { } PUGI__FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr) { } PUGI__FN static void unspecified_bool_xml_attribute(xml_attribute***) { } PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type() const { return _attr ? unspecified_bool_xml_attribute : 0; } PUGI__FN bool xml_attribute::operator!() const { return !_attr; } PUGI__FN bool xml_attribute::operator==(const xml_attribute& r) const { return (_attr == r._attr); } PUGI__FN bool xml_attribute::operator!=(const xml_attribute& r) const { return (_attr != r._attr); } PUGI__FN bool xml_attribute::operator<(const xml_attribute& r) const { return (_attr < r._attr); } PUGI__FN bool xml_attribute::operator>(const xml_attribute& r) const { return (_attr > r._attr); } PUGI__FN bool xml_attribute::operator<=(const xml_attribute& r) const { return (_attr <= r._attr); } PUGI__FN bool xml_attribute::operator>=(const xml_attribute& r) const { return (_attr >= r._attr); } PUGI__FN xml_attribute xml_attribute::next_attribute() const { return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute(); } PUGI__FN xml_attribute xml_attribute::previous_attribute() const { return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute(); } PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const { return (_attr && _attr->value) ? _attr->value : def; } PUGI__FN int xml_attribute::as_int(int def) const { return impl::get_value_int(_attr ? _attr->value : 0, def); } PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const { return impl::get_value_uint(_attr ? _attr->value : 0, def); } PUGI__FN double xml_attribute::as_double(double def) const { return impl::get_value_double(_attr ? _attr->value : 0, def); } PUGI__FN float xml_attribute::as_float(float def) const { return impl::get_value_float(_attr ? _attr->value : 0, def); } PUGI__FN bool xml_attribute::as_bool(bool def) const { return impl::get_value_bool(_attr ? _attr->value : 0, def); } #ifdef PUGIXML_HAS_LONG_LONG PUGI__FN long long xml_attribute::as_llong(long long def) const { return impl::get_value_llong(_attr ? _attr->value : 0, def); } PUGI__FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const { return impl::get_value_ullong(_attr ? _attr->value : 0, def); } #endif PUGI__FN bool xml_attribute::empty() const { return !_attr; } PUGI__FN const char_t* xml_attribute::name() const { return (_attr && _attr->name) ? _attr->name : PUGIXML_TEXT(""); } PUGI__FN const char_t* xml_attribute::value() const { return (_attr && _attr->value) ? _attr->value : PUGIXML_TEXT(""); } PUGI__FN size_t xml_attribute::hash_value() const { return static_cast(reinterpret_cast(_attr) / sizeof(xml_attribute_struct)); } PUGI__FN xml_attribute_struct* xml_attribute::internal_object() const { return _attr; } PUGI__FN xml_attribute& xml_attribute::operator=(const char_t* rhs) { set_value(rhs); return *this; } PUGI__FN xml_attribute& xml_attribute::operator=(int rhs) { set_value(rhs); return *this; } PUGI__FN xml_attribute& xml_attribute::operator=(unsigned int rhs) { set_value(rhs); return *this; } PUGI__FN xml_attribute& xml_attribute::operator=(double rhs) { set_value(rhs); return *this; } PUGI__FN xml_attribute& xml_attribute::operator=(float rhs) { set_value(rhs); return *this; } PUGI__FN xml_attribute& xml_attribute::operator=(bool rhs) { set_value(rhs); return *this; } #ifdef PUGIXML_HAS_LONG_LONG PUGI__FN xml_attribute& xml_attribute::operator=(long long rhs) { set_value(rhs); return *this; } PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long long rhs) { set_value(rhs); return *this; } #endif PUGI__FN bool xml_attribute::set_name(const char_t* rhs) { if (!_attr) return false; return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs); } PUGI__FN bool xml_attribute::set_value(const char_t* rhs) { if (!_attr) return false; return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); } PUGI__FN bool xml_attribute::set_value(int rhs) { if (!_attr) return false; return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); } PUGI__FN bool xml_attribute::set_value(unsigned int rhs) { if (!_attr) return false; return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); } PUGI__FN bool xml_attribute::set_value(double rhs) { if (!_attr) return false; return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); } PUGI__FN bool xml_attribute::set_value(float rhs) { if (!_attr) return false; return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); } PUGI__FN bool xml_attribute::set_value(bool rhs) { if (!_attr) return false; return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); } #ifdef PUGIXML_HAS_LONG_LONG PUGI__FN bool xml_attribute::set_value(long long rhs) { if (!_attr) return false; return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); } PUGI__FN bool xml_attribute::set_value(unsigned long long rhs) { if (!_attr) return false; return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); } #endif #ifdef __BORLANDC__ PUGI__FN bool operator&&(const xml_attribute& lhs, bool rhs) { return (bool)lhs && rhs; } PUGI__FN bool operator||(const xml_attribute& lhs, bool rhs) { return (bool)lhs || rhs; } #endif PUGI__FN xml_node::xml_node(): _root(0) { } PUGI__FN xml_node::xml_node(xml_node_struct* p): _root(p) { } PUGI__FN static void unspecified_bool_xml_node(xml_node***) { } PUGI__FN xml_node::operator xml_node::unspecified_bool_type() const { return _root ? unspecified_bool_xml_node : 0; } PUGI__FN bool xml_node::operator!() const { return !_root; } PUGI__FN xml_node::iterator xml_node::begin() const { return iterator(_root ? _root->first_child : 0, _root); } PUGI__FN xml_node::iterator xml_node::end() const { return iterator(0, _root); } PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin() const { return attribute_iterator(_root ? _root->first_attribute : 0, _root); } PUGI__FN xml_node::attribute_iterator xml_node::attributes_end() const { return attribute_iterator(0, _root); } PUGI__FN xml_object_range xml_node::children() const { return xml_object_range(begin(), end()); } PUGI__FN xml_object_range xml_node::children(const char_t* name_) const { return xml_object_range(xml_named_node_iterator(child(name_)._root, _root, name_), xml_named_node_iterator(0, _root, name_)); } PUGI__FN xml_object_range xml_node::attributes() const { return xml_object_range(attributes_begin(), attributes_end()); } PUGI__FN bool xml_node::operator==(const xml_node& r) const { return (_root == r._root); } PUGI__FN bool xml_node::operator!=(const xml_node& r) const { return (_root != r._root); } PUGI__FN bool xml_node::operator<(const xml_node& r) const { return (_root < r._root); } PUGI__FN bool xml_node::operator>(const xml_node& r) const { return (_root > r._root); } PUGI__FN bool xml_node::operator<=(const xml_node& r) const { return (_root <= r._root); } PUGI__FN bool xml_node::operator>=(const xml_node& r) const { return (_root >= r._root); } PUGI__FN bool xml_node::empty() const { return !_root; } PUGI__FN const char_t* xml_node::name() const { return (_root && _root->name) ? _root->name : PUGIXML_TEXT(""); } PUGI__FN xml_node_type xml_node::type() const { return _root ? PUGI__NODETYPE(_root) : node_null; } PUGI__FN const char_t* xml_node::value() const { return (_root && _root->value) ? _root->value : PUGIXML_TEXT(""); } PUGI__FN xml_node xml_node::child(const char_t* name_) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) if (i->name && impl::strequal(name_, i->name)) return xml_node(i); return xml_node(); } PUGI__FN xml_attribute xml_node::attribute(const char_t* name_) const { if (!_root) return xml_attribute(); for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) if (i->name && impl::strequal(name_, i->name)) return xml_attribute(i); return xml_attribute(); } PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) if (i->name && impl::strequal(name_, i->name)) return xml_node(i); return xml_node(); } PUGI__FN xml_node xml_node::next_sibling() const { return _root ? xml_node(_root->next_sibling) : xml_node(); } PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) if (i->name && impl::strequal(name_, i->name)) return xml_node(i); return xml_node(); } PUGI__FN xml_node xml_node::previous_sibling() const { if (!_root) return xml_node(); if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c); else return xml_node(); } PUGI__FN xml_node xml_node::parent() const { return _root ? xml_node(_root->parent) : xml_node(); } PUGI__FN xml_node xml_node::root() const { return _root ? xml_node(&impl::get_document(_root)) : xml_node(); } PUGI__FN xml_text xml_node::text() const { return xml_text(_root); } PUGI__FN const char_t* xml_node::child_value() const { if (!_root) return PUGIXML_TEXT(""); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) if (i->value && impl::is_text_node(i)) return i->value; return PUGIXML_TEXT(""); } PUGI__FN const char_t* xml_node::child_value(const char_t* name_) const { return child(name_).child_value(); } PUGI__FN xml_attribute xml_node::first_attribute() const { return _root ? xml_attribute(_root->first_attribute) : xml_attribute(); } PUGI__FN xml_attribute xml_node::last_attribute() const { return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute(); } PUGI__FN xml_node xml_node::first_child() const { return _root ? xml_node(_root->first_child) : xml_node(); } PUGI__FN xml_node xml_node::last_child() const { return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node(); } PUGI__FN bool xml_node::set_name(const char_t* rhs) { switch (type()) { case node_pi: case node_declaration: case node_element: return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs); default: return false; } } PUGI__FN bool xml_node::set_value(const char_t* rhs) { switch (type()) { case node_pi: case node_cdata: case node_pcdata: case node_comment: case node_doctype: return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs); default: return false; } } PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root))); if (!a) return xml_attribute(); impl::append_attribute(a._attr, _root); a.set_name(name_); return a; } PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root))); if (!a) return xml_attribute(); impl::prepend_attribute(a._attr, _root); a.set_name(name_); return a; } PUGI__FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root))); if (!a) return xml_attribute(); impl::insert_attribute_after(a._attr, attr._attr, _root); a.set_name(name_); return a; } PUGI__FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root))); if (!a) return xml_attribute(); impl::insert_attribute_before(a._attr, attr._attr, _root); a.set_name(name_); return a; } PUGI__FN xml_attribute xml_node::append_copy(const xml_attribute& proto) { if (!proto) return xml_attribute(); xml_attribute result = append_attribute(proto.name()); result.set_value(proto.value()); return result; } PUGI__FN xml_attribute xml_node::prepend_copy(const xml_attribute& proto) { if (!proto) return xml_attribute(); xml_attribute result = prepend_attribute(proto.name()); result.set_value(proto.value()); return result; } PUGI__FN xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr) { if (!proto) return xml_attribute(); xml_attribute result = insert_attribute_after(proto.name(), attr); result.set_value(proto.value()); return result; } PUGI__FN xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr) { if (!proto) return xml_attribute(); xml_attribute result = insert_attribute_before(proto.name(), attr); result.set_value(proto.value()); return result; } PUGI__FN xml_node xml_node::append_child(xml_node_type type_) { if (!impl::allow_insert_child(type(), type_)) return xml_node(); xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); if (!n) return xml_node(); impl::append_node(n._root, _root); if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); return n; } PUGI__FN xml_node xml_node::prepend_child(xml_node_type type_) { if (!impl::allow_insert_child(type(), type_)) return xml_node(); xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); if (!n) return xml_node(); impl::prepend_node(n._root, _root); if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); return n; } PUGI__FN xml_node xml_node::insert_child_before(xml_node_type type_, const xml_node& node) { if (!impl::allow_insert_child(type(), type_)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); if (!n) return xml_node(); impl::insert_node_before(n._root, node._root); if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); return n; } PUGI__FN xml_node xml_node::insert_child_after(xml_node_type type_, const xml_node& node) { if (!impl::allow_insert_child(type(), type_)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); if (!n) return xml_node(); impl::insert_node_after(n._root, node._root); if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); return n; } PUGI__FN xml_node xml_node::append_child(const char_t* name_) { xml_node result = append_child(node_element); result.set_name(name_); return result; } PUGI__FN xml_node xml_node::prepend_child(const char_t* name_) { xml_node result = prepend_child(node_element); result.set_name(name_); return result; } PUGI__FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node) { xml_node result = insert_child_after(node_element, node); result.set_name(name_); return result; } PUGI__FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node) { xml_node result = insert_child_before(node_element, node); result.set_name(name_); return result; } PUGI__FN xml_node xml_node::append_copy(const xml_node& proto) { xml_node_type type_ = proto.type(); if (!impl::allow_insert_child(type(), type_)) return xml_node(); xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); if (!n) return xml_node(); impl::append_node(n._root, _root); impl::node_copy_tree(n._root, proto._root); return n; } PUGI__FN xml_node xml_node::prepend_copy(const xml_node& proto) { xml_node_type type_ = proto.type(); if (!impl::allow_insert_child(type(), type_)) return xml_node(); xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); if (!n) return xml_node(); impl::prepend_node(n._root, _root); impl::node_copy_tree(n._root, proto._root); return n; } PUGI__FN xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node) { xml_node_type type_ = proto.type(); if (!impl::allow_insert_child(type(), type_)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); if (!n) return xml_node(); impl::insert_node_after(n._root, node._root); impl::node_copy_tree(n._root, proto._root); return n; } PUGI__FN xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node) { xml_node_type type_ = proto.type(); if (!impl::allow_insert_child(type(), type_)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); if (!n) return xml_node(); impl::insert_node_before(n._root, node._root); impl::node_copy_tree(n._root, proto._root); return n; } PUGI__FN xml_node xml_node::append_move(const xml_node& moved) { if (!impl::allow_move(*this, moved)) return xml_node(); // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; impl::remove_node(moved._root); impl::append_node(moved._root, _root); return moved; } PUGI__FN xml_node xml_node::prepend_move(const xml_node& moved) { if (!impl::allow_move(*this, moved)) return xml_node(); // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; impl::remove_node(moved._root); impl::prepend_node(moved._root, _root); return moved; } PUGI__FN xml_node xml_node::insert_move_after(const xml_node& moved, const xml_node& node) { if (!impl::allow_move(*this, moved)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); if (moved._root == node._root) return xml_node(); // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; impl::remove_node(moved._root); impl::insert_node_after(moved._root, node._root); return moved; } PUGI__FN xml_node xml_node::insert_move_before(const xml_node& moved, const xml_node& node) { if (!impl::allow_move(*this, moved)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); if (moved._root == node._root) return xml_node(); // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; impl::remove_node(moved._root); impl::insert_node_before(moved._root, node._root); return moved; } PUGI__FN bool xml_node::remove_attribute(const char_t* name_) { return remove_attribute(attribute(name_)); } PUGI__FN bool xml_node::remove_attribute(const xml_attribute& a) { if (!_root || !a._attr) return false; if (!impl::is_attribute_of(a._attr, _root)) return false; impl::remove_attribute(a._attr, _root); impl::destroy_attribute(a._attr, impl::get_allocator(_root)); return true; } PUGI__FN bool xml_node::remove_child(const char_t* name_) { return remove_child(child(name_)); } PUGI__FN bool xml_node::remove_child(const xml_node& n) { if (!_root || !n._root || n._root->parent != _root) return false; impl::remove_node(n._root); impl::destroy_node(n._root, impl::get_allocator(_root)); return true; } PUGI__FN xml_parse_result xml_node::append_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) { // append_buffer is only valid for elements/documents if (!impl::allow_insert_child(type(), node_element)) return impl::make_parse_result(status_append_invalid_root); // get document node impl::xml_document_struct* doc = &impl::get_document(_root); // disable document_buffer_order optimization since in a document with multiple buffers comparing buffer pointers does not make sense doc->header |= impl::xml_memory_page_contents_shared_mask; // get extra buffer element (we'll store the document fragment buffer there so that we can deallocate it later) impl::xml_memory_page* page = 0; impl::xml_extra_buffer* extra = static_cast(doc->allocate_memory(sizeof(impl::xml_extra_buffer), page)); (void)page; if (!extra) return impl::make_parse_result(status_out_of_memory); // save name; name of the root has to be NULL before parsing - otherwise closing node mismatches will not be detected at the top level char_t* rootname = _root->name; _root->name = 0; // parse char_t* buffer = 0; xml_parse_result res = impl::load_buffer_impl(doc, _root, const_cast(contents), size, options, encoding, false, false, &buffer); // restore name _root->name = rootname; // add extra buffer to the list extra->buffer = buffer; extra->next = doc->extra_buffers; doc->extra_buffers = extra; return res; } PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) if (i->name && impl::strequal(name_, i->name)) { for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value : PUGIXML_TEXT(""))) return xml_node(i); } return xml_node(); } PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value : PUGIXML_TEXT(""))) return xml_node(i); return xml_node(); } #ifndef PUGIXML_NO_STL PUGI__FN string_t xml_node::path(char_t delimiter) const { xml_node cursor = *this; // Make a copy. string_t result = cursor.name(); while (cursor.parent()) { cursor = cursor.parent(); string_t temp = cursor.name(); temp += delimiter; temp += result; result.swap(temp); } return result; } #endif PUGI__FN xml_node xml_node::first_element_by_path(const char_t* path_, char_t delimiter) const { xml_node found = *this; // Current search context. if (!_root || !path_ || !path_[0]) return found; if (path_[0] == delimiter) { // Absolute path; e.g. '/foo/bar' found = found.root(); ++path_; } const char_t* path_segment = path_; while (*path_segment == delimiter) ++path_segment; const char_t* path_segment_end = path_segment; while (*path_segment_end && *path_segment_end != delimiter) ++path_segment_end; if (path_segment == path_segment_end) return found; const char_t* next_segment = path_segment_end; while (*next_segment == delimiter) ++next_segment; if (*path_segment == '.' && path_segment + 1 == path_segment_end) return found.first_element_by_path(next_segment, delimiter); else if (*path_segment == '.' && *(path_segment+1) == '.' && path_segment + 2 == path_segment_end) return found.parent().first_element_by_path(next_segment, delimiter); else { for (xml_node_struct* j = found._root->first_child; j; j = j->next_sibling) { if (j->name && impl::strequalrange(j->name, path_segment, static_cast(path_segment_end - path_segment))) { xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter); if (subsearch) return subsearch; } } return xml_node(); } } PUGI__FN bool xml_node::traverse(xml_tree_walker& walker) { walker._depth = -1; xml_node arg_begin = *this; if (!walker.begin(arg_begin)) return false; xml_node cur = first_child(); if (cur) { ++walker._depth; do { xml_node arg_for_each = cur; if (!walker.for_each(arg_for_each)) return false; if (cur.first_child()) { ++walker._depth; cur = cur.first_child(); } else if (cur.next_sibling()) cur = cur.next_sibling(); else { // Borland C++ workaround while (!cur.next_sibling() && cur != *this && !cur.parent().empty()) { --walker._depth; cur = cur.parent(); } if (cur != *this) cur = cur.next_sibling(); } } while (cur && cur != *this); } assert(walker._depth == -1); xml_node arg_end = *this; return walker.end(arg_end); } PUGI__FN size_t xml_node::hash_value() const { return static_cast(reinterpret_cast(_root) / sizeof(xml_node_struct)); } PUGI__FN xml_node_struct* xml_node::internal_object() const { return _root; } PUGI__FN void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const { if (!_root) return; impl::xml_buffered_writer buffered_writer(writer, encoding); impl::node_output(buffered_writer, _root, indent, flags, depth); } #ifndef PUGIXML_NO_STL PUGI__FN void xml_node::print(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const { xml_writer_stream writer(stream); print(writer, indent, flags, encoding, depth); } PUGI__FN void xml_node::print(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, unsigned int depth) const { xml_writer_stream writer(stream); print(writer, indent, flags, encoding_wchar, depth); } #endif PUGI__FN ptrdiff_t xml_node::offset_debug() const { if (!_root) return -1; impl::xml_document_struct& doc = impl::get_document(_root); // we can determine the offset reliably only if there is exactly once parse buffer if (!doc.buffer || doc.extra_buffers) return -1; switch (type()) { case node_document: return 0; case node_element: case node_declaration: case node_pi: return _root->name && (_root->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0 ? _root->name - doc.buffer : -1; case node_pcdata: case node_cdata: case node_comment: case node_doctype: return _root->value && (_root->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0 ? _root->value - doc.buffer : -1; default: return -1; } } #ifdef __BORLANDC__ PUGI__FN bool operator&&(const xml_node& lhs, bool rhs) { return (bool)lhs && rhs; } PUGI__FN bool operator||(const xml_node& lhs, bool rhs) { return (bool)lhs || rhs; } #endif PUGI__FN xml_text::xml_text(xml_node_struct* root): _root(root) { } PUGI__FN xml_node_struct* xml_text::_data() const { if (!_root || impl::is_text_node(_root)) return _root; for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling) if (impl::is_text_node(node)) return node; return 0; } PUGI__FN xml_node_struct* xml_text::_data_new() { xml_node_struct* d = _data(); if (d) return d; return xml_node(_root).append_child(node_pcdata).internal_object(); } PUGI__FN xml_text::xml_text(): _root(0) { } PUGI__FN static void unspecified_bool_xml_text(xml_text***) { } PUGI__FN xml_text::operator xml_text::unspecified_bool_type() const { return _data() ? unspecified_bool_xml_text : 0; } PUGI__FN bool xml_text::operator!() const { return !_data(); } PUGI__FN bool xml_text::empty() const { return _data() == 0; } PUGI__FN const char_t* xml_text::get() const { xml_node_struct* d = _data(); return (d && d->value) ? d->value : PUGIXML_TEXT(""); } PUGI__FN const char_t* xml_text::as_string(const char_t* def) const { xml_node_struct* d = _data(); return (d && d->value) ? d->value : def; } PUGI__FN int xml_text::as_int(int def) const { xml_node_struct* d = _data(); return impl::get_value_int(d ? d->value : 0, def); } PUGI__FN unsigned int xml_text::as_uint(unsigned int def) const { xml_node_struct* d = _data(); return impl::get_value_uint(d ? d->value : 0, def); } PUGI__FN double xml_text::as_double(double def) const { xml_node_struct* d = _data(); return impl::get_value_double(d ? d->value : 0, def); } PUGI__FN float xml_text::as_float(float def) const { xml_node_struct* d = _data(); return impl::get_value_float(d ? d->value : 0, def); } PUGI__FN bool xml_text::as_bool(bool def) const { xml_node_struct* d = _data(); return impl::get_value_bool(d ? d->value : 0, def); } #ifdef PUGIXML_HAS_LONG_LONG PUGI__FN long long xml_text::as_llong(long long def) const { xml_node_struct* d = _data(); return impl::get_value_llong(d ? d->value : 0, def); } PUGI__FN unsigned long long xml_text::as_ullong(unsigned long long def) const { xml_node_struct* d = _data(); return impl::get_value_ullong(d ? d->value : 0, def); } #endif PUGI__FN bool xml_text::set(const char_t* rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; } PUGI__FN bool xml_text::set(int rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; } PUGI__FN bool xml_text::set(unsigned int rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; } PUGI__FN bool xml_text::set(float rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; } PUGI__FN bool xml_text::set(double rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; } PUGI__FN bool xml_text::set(bool rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; } #ifdef PUGIXML_HAS_LONG_LONG PUGI__FN bool xml_text::set(long long rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; } PUGI__FN bool xml_text::set(unsigned long long rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; } #endif PUGI__FN xml_text& xml_text::operator=(const char_t* rhs) { set(rhs); return *this; } PUGI__FN xml_text& xml_text::operator=(int rhs) { set(rhs); return *this; } PUGI__FN xml_text& xml_text::operator=(unsigned int rhs) { set(rhs); return *this; } PUGI__FN xml_text& xml_text::operator=(double rhs) { set(rhs); return *this; } PUGI__FN xml_text& xml_text::operator=(float rhs) { set(rhs); return *this; } PUGI__FN xml_text& xml_text::operator=(bool rhs) { set(rhs); return *this; } #ifdef PUGIXML_HAS_LONG_LONG PUGI__FN xml_text& xml_text::operator=(long long rhs) { set(rhs); return *this; } PUGI__FN xml_text& xml_text::operator=(unsigned long long rhs) { set(rhs); return *this; } #endif PUGI__FN xml_node xml_text::data() const { return xml_node(_data()); } #ifdef __BORLANDC__ PUGI__FN bool operator&&(const xml_text& lhs, bool rhs) { return (bool)lhs && rhs; } PUGI__FN bool operator||(const xml_text& lhs, bool rhs) { return (bool)lhs || rhs; } #endif PUGI__FN xml_node_iterator::xml_node_iterator() { } PUGI__FN xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent()) { } PUGI__FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) { } PUGI__FN bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const { return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; } PUGI__FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const { return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; } PUGI__FN xml_node& xml_node_iterator::operator*() const { assert(_wrap._root); return _wrap; } PUGI__FN xml_node* xml_node_iterator::operator->() const { assert(_wrap._root); return const_cast(&_wrap); // BCC32 workaround } PUGI__FN const xml_node_iterator& xml_node_iterator::operator++() { assert(_wrap._root); _wrap._root = _wrap._root->next_sibling; return *this; } PUGI__FN xml_node_iterator xml_node_iterator::operator++(int) { xml_node_iterator temp = *this; ++*this; return temp; } PUGI__FN const xml_node_iterator& xml_node_iterator::operator--() { _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child(); return *this; } PUGI__FN xml_node_iterator xml_node_iterator::operator--(int) { xml_node_iterator temp = *this; --*this; return temp; } PUGI__FN xml_attribute_iterator::xml_attribute_iterator() { } PUGI__FN xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent) { } PUGI__FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) { } PUGI__FN bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const { return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root; } PUGI__FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const { return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root; } PUGI__FN xml_attribute& xml_attribute_iterator::operator*() const { assert(_wrap._attr); return _wrap; } PUGI__FN xml_attribute* xml_attribute_iterator::operator->() const { assert(_wrap._attr); return const_cast(&_wrap); // BCC32 workaround } PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator++() { assert(_wrap._attr); _wrap._attr = _wrap._attr->next_attribute; return *this; } PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator++(int) { xml_attribute_iterator temp = *this; ++*this; return temp; } PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator--() { _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute(); return *this; } PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator--(int) { xml_attribute_iterator temp = *this; --*this; return temp; } PUGI__FN xml_named_node_iterator::xml_named_node_iterator(): _name(0) { } PUGI__FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, const char_t* name): _wrap(node), _parent(node.parent()), _name(name) { } PUGI__FN xml_named_node_iterator::xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name): _wrap(ref), _parent(parent), _name(name) { } PUGI__FN bool xml_named_node_iterator::operator==(const xml_named_node_iterator& rhs) const { return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; } PUGI__FN bool xml_named_node_iterator::operator!=(const xml_named_node_iterator& rhs) const { return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; } PUGI__FN xml_node& xml_named_node_iterator::operator*() const { assert(_wrap._root); return _wrap; } PUGI__FN xml_node* xml_named_node_iterator::operator->() const { assert(_wrap._root); return const_cast(&_wrap); // BCC32 workaround } PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator++() { assert(_wrap._root); _wrap = _wrap.next_sibling(_name); return *this; } PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator++(int) { xml_named_node_iterator temp = *this; ++*this; return temp; } PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator--() { if (_wrap._root) _wrap = _wrap.previous_sibling(_name); else { _wrap = _parent.last_child(); if (!impl::strequal(_wrap.name(), _name)) _wrap = _wrap.previous_sibling(_name); } return *this; } PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator--(int) { xml_named_node_iterator temp = *this; --*this; return temp; } PUGI__FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto) { } PUGI__FN xml_parse_result::operator bool() const { return status == status_ok; } PUGI__FN const char* xml_parse_result::description() const { switch (status) { case status_ok: return "No error"; case status_file_not_found: return "File was not found"; case status_io_error: return "Error reading from file/stream"; case status_out_of_memory: return "Could not allocate memory"; case status_internal_error: return "Internal error occurred"; case status_unrecognized_tag: return "Could not determine tag type"; case status_bad_pi: return "Error parsing document declaration/processing instruction"; case status_bad_comment: return "Error parsing comment"; case status_bad_cdata: return "Error parsing CDATA section"; case status_bad_doctype: return "Error parsing document type declaration"; case status_bad_pcdata: return "Error parsing PCDATA section"; case status_bad_start_element: return "Error parsing start element tag"; case status_bad_attribute: return "Error parsing element attribute"; case status_bad_end_element: return "Error parsing end element tag"; case status_end_element_mismatch: return "Start-end tags mismatch"; case status_append_invalid_root: return "Unable to append nodes: root is not an element or document"; case status_no_document_element: return "No document element found"; default: return "Unknown error"; } } PUGI__FN xml_document::xml_document(): _buffer(0) { create(); } PUGI__FN xml_document::~xml_document() { destroy(); } PUGI__FN void xml_document::reset() { destroy(); create(); } PUGI__FN void xml_document::reset(const xml_document& proto) { reset(); for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling()) append_copy(cur); } PUGI__FN void xml_document::create() { assert(!_root); // initialize sentinel page PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + impl::xml_memory_page_alignment - sizeof(void*) <= sizeof(_memory)); // align upwards to page boundary void* page_memory = reinterpret_cast((reinterpret_cast(_memory) + (impl::xml_memory_page_alignment - 1)) & ~(impl::xml_memory_page_alignment - 1)); // prepare page structure impl::xml_memory_page* page = impl::xml_memory_page::construct(page_memory); assert(page); page->busy_size = impl::xml_memory_page_size; // allocate new root _root = new (reinterpret_cast(page) + sizeof(impl::xml_memory_page)) impl::xml_document_struct(page); _root->prev_sibling_c = _root; // setup sentinel page page->allocator = static_cast(_root); // verify the document allocation assert(reinterpret_cast(_root) + sizeof(impl::xml_document_struct) <= _memory + sizeof(_memory)); } PUGI__FN void xml_document::destroy() { assert(_root); // destroy static storage if (_buffer) { impl::xml_memory::deallocate(_buffer); _buffer = 0; } // destroy extra buffers (note: no need to destroy linked list nodes, they're allocated using document allocator) for (impl::xml_extra_buffer* extra = static_cast(_root)->extra_buffers; extra; extra = extra->next) { if (extra->buffer) impl::xml_memory::deallocate(extra->buffer); } // destroy dynamic storage, leave sentinel page (it's in static memory) impl::xml_memory_page* root_page = reinterpret_cast(_root->header & impl::xml_memory_page_pointer_mask); assert(root_page && !root_page->prev); assert(reinterpret_cast(root_page) >= _memory && reinterpret_cast(root_page) < _memory + sizeof(_memory)); for (impl::xml_memory_page* page = root_page->next; page; ) { impl::xml_memory_page* next = page->next; impl::xml_allocator::deallocate_page(page); page = next; } _root = 0; } #ifndef PUGIXML_NO_STL PUGI__FN xml_parse_result xml_document::load(std::basic_istream >& stream, unsigned int options, xml_encoding encoding) { reset(); return impl::load_stream_impl(*this, stream, options, encoding); } PUGI__FN xml_parse_result xml_document::load(std::basic_istream >& stream, unsigned int options) { reset(); return impl::load_stream_impl(*this, stream, options, encoding_wchar); } #endif PUGI__FN xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options) { // Force native encoding (skip autodetection) #ifdef PUGIXML_WCHAR_MODE xml_encoding encoding = encoding_wchar; #else xml_encoding encoding = encoding_utf8; #endif return load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding); } PUGI__FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options) { return load_string(contents, options); } PUGI__FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding) { reset(); FILE* file = fopen(path_, "rb"); return impl::load_file_impl(*this, file, options, encoding); } PUGI__FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding) { reset(); FILE* file = impl::open_file_wide(path_, L"rb"); return impl::load_file_impl(*this, file, options, encoding); } PUGI__FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) { reset(); return impl::load_buffer_impl(static_cast(_root), _root, const_cast(contents), size, options, encoding, false, false, &_buffer); } PUGI__FN xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding) { reset(); return impl::load_buffer_impl(static_cast(_root), _root, contents, size, options, encoding, true, false, &_buffer); } PUGI__FN xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding) { reset(); return impl::load_buffer_impl(static_cast(_root), _root, contents, size, options, encoding, true, true, &_buffer); } PUGI__FN void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const { impl::xml_buffered_writer buffered_writer(writer, encoding); if ((flags & format_write_bom) && encoding != encoding_latin1) { // BOM always represents the codepoint U+FEFF, so just write it in native encoding #ifdef PUGIXML_WCHAR_MODE unsigned int bom = 0xfeff; buffered_writer.write(static_cast(bom)); #else buffered_writer.write('\xef', '\xbb', '\xbf'); #endif } if (!(flags & format_no_declaration) && !impl::has_declaration(_root)) { buffered_writer.write_string(PUGIXML_TEXT("'); if (!(flags & format_raw)) buffered_writer.write('\n'); } impl::node_output(buffered_writer, _root, indent, flags, 0); } #ifndef PUGIXML_NO_STL PUGI__FN void xml_document::save(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const { xml_writer_stream writer(stream); save(writer, indent, flags, encoding); } PUGI__FN void xml_document::save(std::basic_ostream >& stream, const char_t* indent, unsigned int flags) const { xml_writer_stream writer(stream); save(writer, indent, flags, encoding_wchar); } #endif PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const { FILE* file = fopen(path_, (flags & format_save_file_text) ? "w" : "wb"); return impl::save_file_impl(*this, file, indent, flags, encoding); } PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const { FILE* file = impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"); return impl::save_file_impl(*this, file, indent, flags, encoding); } PUGI__FN xml_node xml_document::document_element() const { assert(_root); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) if (PUGI__NODETYPE(i) == node_element) return xml_node(i); return xml_node(); } #ifndef PUGIXML_NO_STL PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str) { assert(str); return impl::as_utf8_impl(str, impl::strlength_wide(str)); } PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string& str) { return impl::as_utf8_impl(str.c_str(), str.size()); } PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const char* str) { assert(str); return impl::as_wide_impl(str, strlen(str)); } PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const std::string& str) { return impl::as_wide_impl(str.c_str(), str.size()); } #endif PUGI__FN void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate) { impl::xml_memory::allocate = allocate; impl::xml_memory::deallocate = deallocate; } PUGI__FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function() { return impl::xml_memory::allocate; } PUGI__FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function() { return impl::xml_memory::deallocate; } } #if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) namespace std { // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&) { return std::bidirectional_iterator_tag(); } PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&) { return std::bidirectional_iterator_tag(); } PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator&) { return std::bidirectional_iterator_tag(); } } #endif #if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) namespace std { // Workarounds for (non-standard) iterator category detection PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator&) { return std::bidirectional_iterator_tag(); } PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator&) { return std::bidirectional_iterator_tag(); } PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_named_node_iterator&) { return std::bidirectional_iterator_tag(); } } #endif #ifndef PUGIXML_NO_XPATH // STL replacements PUGI__NS_BEGIN struct equal_to { template bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; } }; struct not_equal_to { template bool operator()(const T& lhs, const T& rhs) const { return lhs != rhs; } }; struct less { template bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; } }; struct less_equal { template bool operator()(const T& lhs, const T& rhs) const { return lhs <= rhs; } }; template void swap(T& lhs, T& rhs) { T temp = lhs; lhs = rhs; rhs = temp; } template I min_element(I begin, I end, const Pred& pred) { I result = begin; for (I it = begin + 1; it != end; ++it) if (pred(*it, *result)) result = it; return result; } template void reverse(I begin, I end) { while (end - begin > 1) swap(*begin++, *--end); } template I unique(I begin, I end) { // fast skip head while (end - begin > 1 && *begin != *(begin + 1)) begin++; if (begin == end) return begin; // last written element I write = begin++; // merge unique elements while (begin != end) { if (*begin != *write) *++write = *begin++; else begin++; } // past-the-end (write points to live element) return write + 1; } template void copy_backwards(I begin, I end, I target) { while (begin != end) *--target = *--end; } template void insertion_sort(I begin, I end, const Pred& pred, T*) { assert(begin != end); for (I it = begin + 1; it != end; ++it) { T val = *it; if (pred(val, *begin)) { // move to front copy_backwards(begin, it, it + 1); *begin = val; } else { I hole = it; // move hole backwards while (pred(val, *(hole - 1))) { *hole = *(hole - 1); hole--; } // fill hole with element *hole = val; } } } // std variant for elements with == template void partition(I begin, I middle, I end, const Pred& pred, I* out_eqbeg, I* out_eqend) { I eqbeg = middle, eqend = middle + 1; // expand equal range while (eqbeg != begin && *(eqbeg - 1) == *eqbeg) --eqbeg; while (eqend != end && *eqend == *eqbeg) ++eqend; // process outer elements I ltend = eqbeg, gtbeg = eqend; for (;;) { // find the element from the right side that belongs to the left one for (; gtbeg != end; ++gtbeg) if (!pred(*eqbeg, *gtbeg)) { if (*gtbeg == *eqbeg) swap(*gtbeg, *eqend++); else break; } // find the element from the left side that belongs to the right one for (; ltend != begin; --ltend) if (!pred(*(ltend - 1), *eqbeg)) { if (*eqbeg == *(ltend - 1)) swap(*(ltend - 1), *--eqbeg); else break; } // scanned all elements if (gtbeg == end && ltend == begin) { *out_eqbeg = eqbeg; *out_eqend = eqend; return; } // make room for elements by moving equal area if (gtbeg == end) { if (--ltend != --eqbeg) swap(*ltend, *eqbeg); swap(*eqbeg, *--eqend); } else if (ltend == begin) { if (eqend != gtbeg) swap(*eqbeg, *eqend); ++eqend; swap(*gtbeg++, *eqbeg++); } else swap(*gtbeg++, *--ltend); } } template void median3(I first, I middle, I last, const Pred& pred) { if (pred(*middle, *first)) swap(*middle, *first); if (pred(*last, *middle)) swap(*last, *middle); if (pred(*middle, *first)) swap(*middle, *first); } template void median(I first, I middle, I last, const Pred& pred) { if (last - first <= 40) { // median of three for small chunks median3(first, middle, last, pred); } else { // median of nine size_t step = (last - first + 1) / 8; median3(first, first + step, first + 2 * step, pred); median3(middle - step, middle, middle + step, pred); median3(last - 2 * step, last - step, last, pred); median3(first + step, middle, last - step, pred); } } template void sort(I begin, I end, const Pred& pred) { // sort large chunks while (end - begin > 32) { // find median element I middle = begin + (end - begin) / 2; median(begin, middle, end - 1, pred); // partition in three chunks (< = >) I eqbeg, eqend; partition(begin, middle, end, pred, &eqbeg, &eqend); // loop on larger half if (eqbeg - begin > end - eqend) { sort(eqend, end, pred); end = eqbeg; } else { sort(begin, eqbeg, pred); begin = eqend; } } // insertion sort small chunk if (begin != end) insertion_sort(begin, end, pred, &*begin); } PUGI__NS_END // Allocator used for AST and evaluation stacks PUGI__NS_BEGIN struct xpath_memory_block { xpath_memory_block* next; size_t capacity; char data[ #ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE PUGIXML_MEMORY_XPATH_PAGE_SIZE #else 4096 #endif ]; }; class xpath_allocator { xpath_memory_block* _root; size_t _root_size; public: #ifdef PUGIXML_NO_EXCEPTIONS jmp_buf* error_handler; #endif xpath_allocator(xpath_memory_block* root, size_t root_size = 0): _root(root), _root_size(root_size) { #ifdef PUGIXML_NO_EXCEPTIONS error_handler = 0; #endif } void* allocate_nothrow(size_t size) { // align size so that we're able to store pointers in subsequent blocks size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); if (_root_size + size <= _root->capacity) { void* buf = _root->data + _root_size; _root_size += size; return buf; } else { // make sure we have at least 1/4th of the page free after allocation to satisfy subsequent allocation requests size_t block_capacity_base = sizeof(_root->data); size_t block_capacity_req = size + block_capacity_base / 4; size_t block_capacity = (block_capacity_base > block_capacity_req) ? block_capacity_base : block_capacity_req; size_t block_size = block_capacity + offsetof(xpath_memory_block, data); xpath_memory_block* block = static_cast(xml_memory::allocate(block_size)); if (!block) return 0; block->next = _root; block->capacity = block_capacity; _root = block; _root_size = size; return block->data; } } void* allocate(size_t size) { void* result = allocate_nothrow(size); if (!result) { #ifdef PUGIXML_NO_EXCEPTIONS assert(error_handler); longjmp(*error_handler, 1); #else throw std::bad_alloc(); #endif } return result; } void* reallocate(void* ptr, size_t old_size, size_t new_size) { // align size so that we're able to store pointers in subsequent blocks old_size = (old_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); new_size = (new_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); // we can only reallocate the last object assert(ptr == 0 || static_cast(ptr) + old_size == _root->data + _root_size); // adjust root size so that we have not allocated the object at all bool only_object = (_root_size == old_size); if (ptr) _root_size -= old_size; // allocate a new version (this will obviously reuse the memory if possible) void* result = allocate(new_size); assert(result); // we have a new block if (result != ptr && ptr) { // copy old data assert(new_size >= old_size); memcpy(result, ptr, old_size); // free the previous page if it had no other objects if (only_object) { assert(_root->data == result); assert(_root->next); xpath_memory_block* next = _root->next->next; if (next) { // deallocate the whole page, unless it was the first one xml_memory::deallocate(_root->next); _root->next = next; } } } return result; } void revert(const xpath_allocator& state) { // free all new pages xpath_memory_block* cur = _root; while (cur != state._root) { xpath_memory_block* next = cur->next; xml_memory::deallocate(cur); cur = next; } // restore state _root = state._root; _root_size = state._root_size; } void release() { xpath_memory_block* cur = _root; assert(cur); while (cur->next) { xpath_memory_block* next = cur->next; xml_memory::deallocate(cur); cur = next; } } }; struct xpath_allocator_capture { xpath_allocator_capture(xpath_allocator* alloc): _target(alloc), _state(*alloc) { } ~xpath_allocator_capture() { _target->revert(_state); } xpath_allocator* _target; xpath_allocator _state; }; struct xpath_stack { xpath_allocator* result; xpath_allocator* temp; }; struct xpath_stack_data { xpath_memory_block blocks[2]; xpath_allocator result; xpath_allocator temp; xpath_stack stack; #ifdef PUGIXML_NO_EXCEPTIONS jmp_buf error_handler; #endif xpath_stack_data(): result(blocks + 0), temp(blocks + 1) { blocks[0].next = blocks[1].next = 0; blocks[0].capacity = blocks[1].capacity = sizeof(blocks[0].data); stack.result = &result; stack.temp = &temp; #ifdef PUGIXML_NO_EXCEPTIONS result.error_handler = temp.error_handler = &error_handler; #endif } ~xpath_stack_data() { result.release(); temp.release(); } }; PUGI__NS_END // String class PUGI__NS_BEGIN class xpath_string { const char_t* _buffer; bool _uses_heap; size_t _length_heap; static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc) { char_t* result = static_cast(alloc->allocate((length + 1) * sizeof(char_t))); assert(result); memcpy(result, string, length * sizeof(char_t)); result[length] = 0; return result; } xpath_string(const char_t* buffer, bool uses_heap_, size_t length_heap): _buffer(buffer), _uses_heap(uses_heap_), _length_heap(length_heap) { } public: static xpath_string from_const(const char_t* str) { return xpath_string(str, false, 0); } static xpath_string from_heap_preallocated(const char_t* begin, const char_t* end) { assert(begin <= end && *end == 0); return xpath_string(begin, true, static_cast(end - begin)); } static xpath_string from_heap(const char_t* begin, const char_t* end, xpath_allocator* alloc) { assert(begin <= end); size_t length = static_cast(end - begin); return length == 0 ? xpath_string() : xpath_string(duplicate_string(begin, length, alloc), true, length); } xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false), _length_heap(0) { } void append(const xpath_string& o, xpath_allocator* alloc) { // skip empty sources if (!*o._buffer) return; // fast append for constant empty target and constant source if (!*_buffer && !_uses_heap && !o._uses_heap) { _buffer = o._buffer; } else { // need to make heap copy size_t target_length = length(); size_t source_length = o.length(); size_t result_length = target_length + source_length; // allocate new buffer char_t* result = static_cast(alloc->reallocate(_uses_heap ? const_cast(_buffer) : 0, (target_length + 1) * sizeof(char_t), (result_length + 1) * sizeof(char_t))); assert(result); // append first string to the new buffer in case there was no reallocation if (!_uses_heap) memcpy(result, _buffer, target_length * sizeof(char_t)); // append second string to the new buffer memcpy(result + target_length, o._buffer, source_length * sizeof(char_t)); result[result_length] = 0; // finalize _buffer = result; _uses_heap = true; _length_heap = result_length; } } const char_t* c_str() const { return _buffer; } size_t length() const { return _uses_heap ? _length_heap : strlength(_buffer); } char_t* data(xpath_allocator* alloc) { // make private heap copy if (!_uses_heap) { size_t length_ = strlength(_buffer); _buffer = duplicate_string(_buffer, length_, alloc); _uses_heap = true; _length_heap = length_; } return const_cast(_buffer); } bool empty() const { return *_buffer == 0; } bool operator==(const xpath_string& o) const { return strequal(_buffer, o._buffer); } bool operator!=(const xpath_string& o) const { return !strequal(_buffer, o._buffer); } bool uses_heap() const { return _uses_heap; } }; PUGI__NS_END PUGI__NS_BEGIN PUGI__FN bool starts_with(const char_t* string, const char_t* pattern) { while (*pattern && *string == *pattern) { string++; pattern++; } return *pattern == 0; } PUGI__FN const char_t* find_char(const char_t* s, char_t c) { #ifdef PUGIXML_WCHAR_MODE return wcschr(s, c); #else return strchr(s, c); #endif } PUGI__FN const char_t* find_substring(const char_t* s, const char_t* p) { #ifdef PUGIXML_WCHAR_MODE // MSVC6 wcsstr bug workaround (if s is empty it always returns 0) return (*p == 0) ? s : wcsstr(s, p); #else return strstr(s, p); #endif } // Converts symbol to lower case, if it is an ASCII one PUGI__FN char_t tolower_ascii(char_t ch) { return static_cast(ch - 'A') < 26 ? static_cast(ch | ' ') : ch; } PUGI__FN xpath_string string_value(const xpath_node& na, xpath_allocator* alloc) { if (na.attribute()) return xpath_string::from_const(na.attribute().value()); else { xml_node n = na.node(); switch (n.type()) { case node_pcdata: case node_cdata: case node_comment: case node_pi: return xpath_string::from_const(n.value()); case node_document: case node_element: { xpath_string result; xml_node cur = n.first_child(); while (cur && cur != n) { if (cur.type() == node_pcdata || cur.type() == node_cdata) result.append(xpath_string::from_const(cur.value()), alloc); if (cur.first_child()) cur = cur.first_child(); else if (cur.next_sibling()) cur = cur.next_sibling(); else { while (!cur.next_sibling() && cur != n) cur = cur.parent(); if (cur != n) cur = cur.next_sibling(); } } return result; } default: return xpath_string(); } } } PUGI__FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn) { assert(ln->parent == rn->parent); // there is no common ancestor (the shared parent is null), nodes are from different documents if (!ln->parent) return ln < rn; // determine sibling order xml_node_struct* ls = ln; xml_node_struct* rs = rn; while (ls && rs) { if (ls == rn) return true; if (rs == ln) return false; ls = ls->next_sibling; rs = rs->next_sibling; } // if rn sibling chain ended ln must be before rn return !rs; } PUGI__FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn) { // find common ancestor at the same depth, if any xml_node_struct* lp = ln; xml_node_struct* rp = rn; while (lp && rp && lp->parent != rp->parent) { lp = lp->parent; rp = rp->parent; } // parents are the same! if (lp && rp) return node_is_before_sibling(lp, rp); // nodes are at different depths, need to normalize heights bool left_higher = !lp; while (lp) { lp = lp->parent; ln = ln->parent; } while (rp) { rp = rp->parent; rn = rn->parent; } // one node is the ancestor of the other if (ln == rn) return left_higher; // find common ancestor... again while (ln->parent != rn->parent) { ln = ln->parent; rn = rn->parent; } return node_is_before_sibling(ln, rn); } PUGI__FN bool node_is_ancestor(xml_node_struct* parent, xml_node_struct* node) { while (node && node != parent) node = node->parent; return parent && node == parent; } PUGI__FN const void* document_buffer_order(const xpath_node& xnode) { xml_node_struct* node = xnode.node().internal_object(); if (node) { if ((get_document(node).header & xml_memory_page_contents_shared_mask) == 0) { if (node->name && (node->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return node->name; if (node->value && (node->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return node->value; } return 0; } xml_attribute_struct* attr = xnode.attribute().internal_object(); if (attr) { if ((get_document(attr).header & xml_memory_page_contents_shared_mask) == 0) { if ((attr->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return attr->name; if ((attr->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return attr->value; } return 0; } return 0; } struct document_order_comparator { bool operator()(const xpath_node& lhs, const xpath_node& rhs) const { // optimized document order based check const void* lo = document_buffer_order(lhs); const void* ro = document_buffer_order(rhs); if (lo && ro) return lo < ro; // slow comparison xml_node ln = lhs.node(), rn = rhs.node(); // compare attributes if (lhs.attribute() && rhs.attribute()) { // shared parent if (lhs.parent() == rhs.parent()) { // determine sibling order for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute()) if (a == rhs.attribute()) return true; return false; } // compare attribute parents ln = lhs.parent(); rn = rhs.parent(); } else if (lhs.attribute()) { // attributes go after the parent element if (lhs.parent() == rhs.node()) return false; ln = lhs.parent(); } else if (rhs.attribute()) { // attributes go after the parent element if (rhs.parent() == lhs.node()) return true; rn = rhs.parent(); } if (ln == rn) return false; if (!ln || !rn) return ln < rn; return node_is_before(ln.internal_object(), rn.internal_object()); } }; struct duplicate_comparator { bool operator()(const xpath_node& lhs, const xpath_node& rhs) const { if (lhs.attribute()) return rhs.attribute() ? lhs.attribute() < rhs.attribute() : true; else return rhs.attribute() ? false : lhs.node() < rhs.node(); } }; PUGI__FN double gen_nan() { #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24)) union { float f; uint32_t i; } u[sizeof(float) == sizeof(uint32_t) ? 1 : -1]; u[0].i = 0x7fc00000; return u[0].f; #else // fallback const volatile double zero = 0.0; return zero / zero; #endif } PUGI__FN bool is_nan(double value) { #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) return !!_isnan(value); #elif defined(fpclassify) && defined(FP_NAN) return fpclassify(value) == FP_NAN; #else // fallback const volatile double v = value; return v != v; #endif } PUGI__FN const char_t* convert_number_to_string_special(double value) { #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0; if (_isnan(value)) return PUGIXML_TEXT("NaN"); return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); #elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO) switch (fpclassify(value)) { case FP_NAN: return PUGIXML_TEXT("NaN"); case FP_INFINITE: return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); case FP_ZERO: return PUGIXML_TEXT("0"); default: return 0; } #else // fallback const volatile double v = value; if (v == 0) return PUGIXML_TEXT("0"); if (v != v) return PUGIXML_TEXT("NaN"); if (v * 2 == v) return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); return 0; #endif } PUGI__FN bool convert_number_to_boolean(double value) { return (value != 0 && !is_nan(value)); } PUGI__FN void truncate_zeros(char* begin, char* end) { while (begin != end && end[-1] == '0') end--; *end = 0; } // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE) PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) { // get base values int sign, exponent; _ecvt_s(buffer, buffer_size, value, DBL_DIG + 1, &exponent, &sign); // truncate redundant zeros truncate_zeros(buffer, buffer + strlen(buffer)); // fill results *out_mantissa = buffer; *out_exponent = exponent; } #else PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) { // get a scientific notation value with IEEE DBL_DIG decimals sprintf(buffer, "%.*e", DBL_DIG, value); assert(strlen(buffer) < buffer_size); (void)!buffer_size; // get the exponent (possibly negative) char* exponent_string = strchr(buffer, 'e'); assert(exponent_string); int exponent = atoi(exponent_string + 1); // extract mantissa string: skip sign char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer; assert(mantissa[0] != '0' && mantissa[1] == '.'); // divide mantissa by 10 to eliminate integer part mantissa[1] = mantissa[0]; mantissa++; exponent++; // remove extra mantissa digits and zero-terminate mantissa truncate_zeros(mantissa, exponent_string); // fill results *out_mantissa = mantissa; *out_exponent = exponent; } #endif PUGI__FN xpath_string convert_number_to_string(double value, xpath_allocator* alloc) { // try special number conversion const char_t* special = convert_number_to_string_special(value); if (special) return xpath_string::from_const(special); // get mantissa + exponent form char mantissa_buffer[32]; char* mantissa; int exponent; convert_number_to_mantissa_exponent(value, mantissa_buffer, sizeof(mantissa_buffer), &mantissa, &exponent); // allocate a buffer of suitable length for the number size_t result_size = strlen(mantissa_buffer) + (exponent > 0 ? exponent : -exponent) + 4; char_t* result = static_cast(alloc->allocate(sizeof(char_t) * result_size)); assert(result); // make the number! char_t* s = result; // sign if (value < 0) *s++ = '-'; // integer part if (exponent <= 0) { *s++ = '0'; } else { while (exponent > 0) { assert(*mantissa == 0 || static_cast(static_cast(*mantissa) - '0') <= 9); *s++ = *mantissa ? *mantissa++ : '0'; exponent--; } } // fractional part if (*mantissa) { // decimal point *s++ = '.'; // extra zeroes from negative exponent while (exponent < 0) { *s++ = '0'; exponent++; } // extra mantissa digits while (*mantissa) { assert(static_cast(*mantissa - '0') <= 9); *s++ = *mantissa++; } } // zero-terminate assert(s < result + result_size); *s = 0; return xpath_string::from_heap_preallocated(result, s); } PUGI__FN bool check_string_to_number_format(const char_t* string) { // parse leading whitespace while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string; // parse sign if (*string == '-') ++string; if (!*string) return false; // if there is no integer part, there should be a decimal part with at least one digit if (!PUGI__IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI__IS_CHARTYPEX(string[1], ctx_digit))) return false; // parse integer part while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string; // parse decimal part if (*string == '.') { ++string; while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string; } // parse trailing whitespace while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string; return *string == 0; } PUGI__FN double convert_string_to_number(const char_t* string) { // check string format if (!check_string_to_number_format(string)) return gen_nan(); // parse string #ifdef PUGIXML_WCHAR_MODE return wcstod(string, 0); #else return atof(string); #endif } PUGI__FN bool convert_string_to_number_scratch(char_t (&buffer)[32], const char_t* begin, const char_t* end, double* out_result) { size_t length = static_cast(end - begin); char_t* scratch = buffer; if (length >= sizeof(buffer) / sizeof(buffer[0])) { // need to make dummy on-heap copy scratch = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!scratch) return false; } // copy string to zero-terminated buffer and perform conversion memcpy(scratch, begin, length * sizeof(char_t)); scratch[length] = 0; *out_result = convert_string_to_number(scratch); // free dummy buffer if (scratch != buffer) xml_memory::deallocate(scratch); return true; } PUGI__FN double round_nearest(double value) { return floor(value + 0.5); } PUGI__FN double round_nearest_nzero(double value) { // same as round_nearest, but returns -0 for [-0.5, -0] // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0) return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5); } PUGI__FN const char_t* qualified_name(const xpath_node& node) { return node.attribute() ? node.attribute().name() : node.node().name(); } PUGI__FN const char_t* local_name(const xpath_node& node) { const char_t* name = qualified_name(node); const char_t* p = find_char(name, ':'); return p ? p + 1 : name; } struct namespace_uri_predicate { const char_t* prefix; size_t prefix_length; namespace_uri_predicate(const char_t* name) { const char_t* pos = find_char(name, ':'); prefix = pos ? name : 0; prefix_length = pos ? static_cast(pos - name) : 0; } bool operator()(xml_attribute a) const { const char_t* name = a.name(); if (!starts_with(name, PUGIXML_TEXT("xmlns"))) return false; return prefix ? name[5] == ':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0; } }; PUGI__FN const char_t* namespace_uri(xml_node node) { namespace_uri_predicate pred = node.name(); xml_node p = node; while (p) { xml_attribute a = p.find_attribute(pred); if (a) return a.value(); p = p.parent(); } return PUGIXML_TEXT(""); } PUGI__FN const char_t* namespace_uri(xml_attribute attr, xml_node parent) { namespace_uri_predicate pred = attr.name(); // Default namespace does not apply to attributes if (!pred.prefix) return PUGIXML_TEXT(""); xml_node p = parent; while (p) { xml_attribute a = p.find_attribute(pred); if (a) return a.value(); p = p.parent(); } return PUGIXML_TEXT(""); } PUGI__FN const char_t* namespace_uri(const xpath_node& node) { return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node()); } PUGI__FN char_t* normalize_space(char_t* buffer) { char_t* write = buffer; for (char_t* it = buffer; *it; ) { char_t ch = *it++; if (PUGI__IS_CHARTYPE(ch, ct_space)) { // replace whitespace sequence with single space while (PUGI__IS_CHARTYPE(*it, ct_space)) it++; // avoid leading spaces if (write != buffer) *write++ = ' '; } else *write++ = ch; } // remove trailing space if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space)) write--; // zero-terminate *write = 0; return write; } PUGI__FN char_t* translate(char_t* buffer, const char_t* from, const char_t* to, size_t to_length) { char_t* write = buffer; while (*buffer) { PUGI__DMC_VOLATILE char_t ch = *buffer++; const char_t* pos = find_char(from, ch); if (!pos) *write++ = ch; // do not process else if (static_cast(pos - from) < to_length) *write++ = to[pos - from]; // replace } // zero-terminate *write = 0; return write; } PUGI__FN unsigned char* translate_table_generate(xpath_allocator* alloc, const char_t* from, const char_t* to) { unsigned char table[128] = {0}; while (*from) { unsigned int fc = static_cast(*from); unsigned int tc = static_cast(*to); if (fc >= 128 || tc >= 128) return 0; // code=128 means "skip character" if (!table[fc]) table[fc] = static_cast(tc ? tc : 128); from++; if (tc) to++; } for (int i = 0; i < 128; ++i) if (!table[i]) table[i] = static_cast(i); void* result = alloc->allocate_nothrow(sizeof(table)); if (result) { memcpy(result, table, sizeof(table)); } return static_cast(result); } PUGI__FN char_t* translate_table(char_t* buffer, const unsigned char* table) { char_t* write = buffer; while (*buffer) { char_t ch = *buffer++; unsigned int index = static_cast(ch); if (index < 128) { unsigned char code = table[index]; // code=128 means "skip character" (table size is 128 so 128 can be a special value) // this code skips these characters without extra branches *write = static_cast(code); write += 1 - (code >> 7); } else { *write++ = ch; } } // zero-terminate *write = 0; return write; } inline bool is_xpath_attribute(const char_t* name) { return !(starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':')); } struct xpath_variable_boolean: xpath_variable { xpath_variable_boolean(): value(false) { } bool value; char_t name[1]; }; struct xpath_variable_number: xpath_variable { xpath_variable_number(): value(0) { } double value; char_t name[1]; }; struct xpath_variable_string: xpath_variable { xpath_variable_string(): value(0) { } ~xpath_variable_string() { if (value) xml_memory::deallocate(value); } char_t* value; char_t name[1]; }; struct xpath_variable_node_set: xpath_variable { xpath_node_set value; char_t name[1]; }; static const xpath_node_set dummy_node_set; PUGI__FN unsigned int hash_string(const char_t* str) { // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time) unsigned int result = 0; while (*str) { result += static_cast(*str++); result += result << 10; result ^= result >> 6; } result += result << 3; result ^= result >> 11; result += result << 15; return result; } template PUGI__FN T* new_xpath_variable(const char_t* name) { size_t length = strlength(name); if (length == 0) return 0; // empty variable names are invalid // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters void* memory = xml_memory::allocate(sizeof(T) + length * sizeof(char_t)); if (!memory) return 0; T* result = new (memory) T(); memcpy(result->name, name, (length + 1) * sizeof(char_t)); return result; } PUGI__FN xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name) { switch (type) { case xpath_type_node_set: return new_xpath_variable(name); case xpath_type_number: return new_xpath_variable(name); case xpath_type_string: return new_xpath_variable(name); case xpath_type_boolean: return new_xpath_variable(name); default: return 0; } } template PUGI__FN void delete_xpath_variable(T* var) { var->~T(); xml_memory::deallocate(var); } PUGI__FN void delete_xpath_variable(xpath_value_type type, xpath_variable* var) { switch (type) { case xpath_type_node_set: delete_xpath_variable(static_cast(var)); break; case xpath_type_number: delete_xpath_variable(static_cast(var)); break; case xpath_type_string: delete_xpath_variable(static_cast(var)); break; case xpath_type_boolean: delete_xpath_variable(static_cast(var)); break; default: assert(!"Invalid variable type"); } } PUGI__FN xpath_variable* get_variable_scratch(char_t (&buffer)[32], xpath_variable_set* set, const char_t* begin, const char_t* end) { size_t length = static_cast(end - begin); char_t* scratch = buffer; if (length >= sizeof(buffer) / sizeof(buffer[0])) { // need to make dummy on-heap copy scratch = static_cast(xml_memory::allocate((length + 1) * sizeof(char_t))); if (!scratch) return 0; } // copy string to zero-terminated buffer and perform lookup memcpy(scratch, begin, length * sizeof(char_t)); scratch[length] = 0; xpath_variable* result = set->get(scratch); // free dummy buffer if (scratch != buffer) xml_memory::deallocate(scratch); return result; } PUGI__NS_END // Internal node set class PUGI__NS_BEGIN PUGI__FN xpath_node_set::type_t xpath_get_order(const xpath_node* begin, const xpath_node* end) { if (end - begin < 2) return xpath_node_set::type_sorted; document_order_comparator cmp; bool first = cmp(begin[0], begin[1]); for (const xpath_node* it = begin + 1; it + 1 < end; ++it) if (cmp(it[0], it[1]) != first) return xpath_node_set::type_unsorted; return first ? xpath_node_set::type_sorted : xpath_node_set::type_sorted_reverse; } PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev) { xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted; if (type == xpath_node_set::type_unsorted) { xpath_node_set::type_t sorted = xpath_get_order(begin, end); if (sorted == xpath_node_set::type_unsorted) { sort(begin, end, document_order_comparator()); type = xpath_node_set::type_sorted; } else type = sorted; } if (type != order) reverse(begin, end); return order; } PUGI__FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type) { if (begin == end) return xpath_node(); switch (type) { case xpath_node_set::type_sorted: return *begin; case xpath_node_set::type_sorted_reverse: return *(end - 1); case xpath_node_set::type_unsorted: return *min_element(begin, end, document_order_comparator()); default: assert(!"Invalid node set type"); return xpath_node(); } } class xpath_node_set_raw { xpath_node_set::type_t _type; xpath_node* _begin; xpath_node* _end; xpath_node* _eos; public: xpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0) { } xpath_node* begin() const { return _begin; } xpath_node* end() const { return _end; } bool empty() const { return _begin == _end; } size_t size() const { return static_cast(_end - _begin); } xpath_node first() const { return xpath_first(_begin, _end, _type); } void push_back_grow(const xpath_node& node, xpath_allocator* alloc); void push_back(const xpath_node& node, xpath_allocator* alloc) { if (_end != _eos) *_end++ = node; else push_back_grow(node, alloc); } void append(const xpath_node* begin_, const xpath_node* end_, xpath_allocator* alloc) { if (begin_ == end_) return; size_t size_ = static_cast(_end - _begin); size_t capacity = static_cast(_eos - _begin); size_t count = static_cast(end_ - begin_); if (size_ + count > capacity) { // reallocate the old array or allocate a new one xpath_node* data = static_cast(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size_ + count) * sizeof(xpath_node))); assert(data); // finalize _begin = data; _end = data + size_; _eos = data + size_ + count; } memcpy(_end, begin_, count * sizeof(xpath_node)); _end += count; } void sort_do() { _type = xpath_sort(_begin, _end, _type, false); } void truncate(xpath_node* pos) { assert(_begin <= pos && pos <= _end); _end = pos; } void remove_duplicates() { if (_type == xpath_node_set::type_unsorted) sort(_begin, _end, duplicate_comparator()); _end = unique(_begin, _end); } xpath_node_set::type_t type() const { return _type; } void set_type(xpath_node_set::type_t value) { _type = value; } }; PUGI__FN_NO_INLINE void xpath_node_set_raw::push_back_grow(const xpath_node& node, xpath_allocator* alloc) { size_t capacity = static_cast(_eos - _begin); // get new capacity (1.5x rule) size_t new_capacity = capacity + capacity / 2 + 1; // reallocate the old array or allocate a new one xpath_node* data = static_cast(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node))); assert(data); // finalize _begin = data; _end = data + capacity; _eos = data + new_capacity; // push *_end++ = node; } PUGI__NS_END PUGI__NS_BEGIN struct xpath_context { xpath_node n; size_t position, size; xpath_context(const xpath_node& n_, size_t position_, size_t size_): n(n_), position(position_), size(size_) { } }; enum lexeme_t { lex_none = 0, lex_equal, lex_not_equal, lex_less, lex_greater, lex_less_or_equal, lex_greater_or_equal, lex_plus, lex_minus, lex_multiply, lex_union, lex_var_ref, lex_open_brace, lex_close_brace, lex_quoted_string, lex_number, lex_slash, lex_double_slash, lex_open_square_brace, lex_close_square_brace, lex_string, lex_comma, lex_axis_attribute, lex_dot, lex_double_dot, lex_double_colon, lex_eof }; struct xpath_lexer_string { const char_t* begin; const char_t* end; xpath_lexer_string(): begin(0), end(0) { } bool operator==(const char_t* other) const { size_t length = static_cast(end - begin); return strequalrange(other, begin, length); } }; class xpath_lexer { const char_t* _cur; const char_t* _cur_lexeme_pos; xpath_lexer_string _cur_lexeme_contents; lexeme_t _cur_lexeme; public: explicit xpath_lexer(const char_t* query): _cur(query) { next(); } const char_t* state() const { return _cur; } void next() { const char_t* cur = _cur; while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur; // save lexeme position for error reporting _cur_lexeme_pos = cur; switch (*cur) { case 0: _cur_lexeme = lex_eof; break; case '>': if (*(cur+1) == '=') { cur += 2; _cur_lexeme = lex_greater_or_equal; } else { cur += 1; _cur_lexeme = lex_greater; } break; case '<': if (*(cur+1) == '=') { cur += 2; _cur_lexeme = lex_less_or_equal; } else { cur += 1; _cur_lexeme = lex_less; } break; case '!': if (*(cur+1) == '=') { cur += 2; _cur_lexeme = lex_not_equal; } else { _cur_lexeme = lex_none; } break; case '=': cur += 1; _cur_lexeme = lex_equal; break; case '+': cur += 1; _cur_lexeme = lex_plus; break; case '-': cur += 1; _cur_lexeme = lex_minus; break; case '*': cur += 1; _cur_lexeme = lex_multiply; break; case '|': cur += 1; _cur_lexeme = lex_union; break; case '$': cur += 1; if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol)) { _cur_lexeme_contents.begin = cur; while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; if (cur[0] == ':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // qname { cur++; // : while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; } _cur_lexeme_contents.end = cur; _cur_lexeme = lex_var_ref; } else { _cur_lexeme = lex_none; } break; case '(': cur += 1; _cur_lexeme = lex_open_brace; break; case ')': cur += 1; _cur_lexeme = lex_close_brace; break; case '[': cur += 1; _cur_lexeme = lex_open_square_brace; break; case ']': cur += 1; _cur_lexeme = lex_close_square_brace; break; case ',': cur += 1; _cur_lexeme = lex_comma; break; case '/': if (*(cur+1) == '/') { cur += 2; _cur_lexeme = lex_double_slash; } else { cur += 1; _cur_lexeme = lex_slash; } break; case '.': if (*(cur+1) == '.') { cur += 2; _cur_lexeme = lex_double_dot; } else if (PUGI__IS_CHARTYPEX(*(cur+1), ctx_digit)) { _cur_lexeme_contents.begin = cur; // . ++cur; while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; _cur_lexeme_contents.end = cur; _cur_lexeme = lex_number; } else { cur += 1; _cur_lexeme = lex_dot; } break; case '@': cur += 1; _cur_lexeme = lex_axis_attribute; break; case '"': case '\'': { char_t terminator = *cur; ++cur; _cur_lexeme_contents.begin = cur; while (*cur && *cur != terminator) cur++; _cur_lexeme_contents.end = cur; if (!*cur) _cur_lexeme = lex_none; else { cur += 1; _cur_lexeme = lex_quoted_string; } break; } case ':': if (*(cur+1) == ':') { cur += 2; _cur_lexeme = lex_double_colon; } else { _cur_lexeme = lex_none; } break; default: if (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) { _cur_lexeme_contents.begin = cur; while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; if (*cur == '.') { cur++; while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; } _cur_lexeme_contents.end = cur; _cur_lexeme = lex_number; } else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol)) { _cur_lexeme_contents.begin = cur; while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; if (cur[0] == ':') { if (cur[1] == '*') // namespace test ncname:* { cur += 2; // :* } else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname { cur++; // : while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; } } _cur_lexeme_contents.end = cur; _cur_lexeme = lex_string; } else { _cur_lexeme = lex_none; } } _cur = cur; } lexeme_t current() const { return _cur_lexeme; } const char_t* current_pos() const { return _cur_lexeme_pos; } const xpath_lexer_string& contents() const { assert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string); return _cur_lexeme_contents; } }; enum ast_type_t { ast_unknown, ast_op_or, // left or right ast_op_and, // left and right ast_op_equal, // left = right ast_op_not_equal, // left != right ast_op_less, // left < right ast_op_greater, // left > right ast_op_less_or_equal, // left <= right ast_op_greater_or_equal, // left >= right ast_op_add, // left + right ast_op_subtract, // left - right ast_op_multiply, // left * right ast_op_divide, // left / right ast_op_mod, // left % right ast_op_negate, // left - right ast_op_union, // left | right ast_predicate, // apply predicate to set; next points to next predicate ast_filter, // select * from left where right ast_string_constant, // string constant ast_number_constant, // number constant ast_variable, // variable ast_func_last, // last() ast_func_position, // position() ast_func_count, // count(left) ast_func_id, // id(left) ast_func_local_name_0, // local-name() ast_func_local_name_1, // local-name(left) ast_func_namespace_uri_0, // namespace-uri() ast_func_namespace_uri_1, // namespace-uri(left) ast_func_name_0, // name() ast_func_name_1, // name(left) ast_func_string_0, // string() ast_func_string_1, // string(left) ast_func_concat, // concat(left, right, siblings) ast_func_starts_with, // starts_with(left, right) ast_func_contains, // contains(left, right) ast_func_substring_before, // substring-before(left, right) ast_func_substring_after, // substring-after(left, right) ast_func_substring_2, // substring(left, right) ast_func_substring_3, // substring(left, right, third) ast_func_string_length_0, // string-length() ast_func_string_length_1, // string-length(left) ast_func_normalize_space_0, // normalize-space() ast_func_normalize_space_1, // normalize-space(left) ast_func_translate, // translate(left, right, third) ast_func_boolean, // boolean(left) ast_func_not, // not(left) ast_func_true, // true() ast_func_false, // false() ast_func_lang, // lang(left) ast_func_number_0, // number() ast_func_number_1, // number(left) ast_func_sum, // sum(left) ast_func_floor, // floor(left) ast_func_ceiling, // ceiling(left) ast_func_round, // round(left) ast_step, // process set left with step ast_step_root, // select root node ast_opt_translate_table, // translate(left, right, third) where right/third are constants ast_opt_compare_attribute // @name = 'string' }; enum axis_t { axis_ancestor, axis_ancestor_or_self, axis_attribute, axis_child, axis_descendant, axis_descendant_or_self, axis_following, axis_following_sibling, axis_namespace, axis_parent, axis_preceding, axis_preceding_sibling, axis_self }; enum nodetest_t { nodetest_none, nodetest_name, nodetest_type_node, nodetest_type_comment, nodetest_type_pi, nodetest_type_text, nodetest_pi, nodetest_all, nodetest_all_in_namespace }; enum predicate_t { predicate_default, predicate_posinv, predicate_constant, predicate_constant_one }; enum nodeset_eval_t { nodeset_eval_all, nodeset_eval_any, nodeset_eval_first }; template struct axis_to_type { static const axis_t axis; }; template const axis_t axis_to_type::axis = N; class xpath_ast_node { private: // node type char _type; char _rettype; // for ast_step char _axis; // for ast_step/ast_predicate/ast_filter char _test; // tree node structure xpath_ast_node* _left; xpath_ast_node* _right; xpath_ast_node* _next; union { // value for ast_string_constant const char_t* string; // value for ast_number_constant double number; // variable for ast_variable xpath_variable* variable; // node test for ast_step (node name/namespace/node type/pi target) const char_t* nodetest; // table for ast_opt_translate_table const unsigned char* table; } _data; xpath_ast_node(const xpath_ast_node&); xpath_ast_node& operator=(const xpath_ast_node&); template static bool compare_eq(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) { xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); if (lt != xpath_type_node_set && rt != xpath_type_node_set) { if (lt == xpath_type_boolean || rt == xpath_type_boolean) return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack)); else if (lt == xpath_type_number || rt == xpath_type_number) return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); else if (lt == xpath_type_string || rt == xpath_type_string) { xpath_allocator_capture cr(stack.result); xpath_string ls = lhs->eval_string(c, stack); xpath_string rs = rhs->eval_string(c, stack); return comp(ls, rs); } } else if (lt == xpath_type_node_set && rt == xpath_type_node_set) { xpath_allocator_capture cr(stack.result); xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all); xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { xpath_allocator_capture cri(stack.result); if (comp(string_value(*li, stack.result), string_value(*ri, stack.result))) return true; } return false; } else { if (lt == xpath_type_node_set) { swap(lhs, rhs); swap(lt, rt); } if (lt == xpath_type_boolean) return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack)); else if (lt == xpath_type_number) { xpath_allocator_capture cr(stack.result); double l = lhs->eval_number(c, stack); xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { xpath_allocator_capture cri(stack.result); if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) return true; } return false; } else if (lt == xpath_type_string) { xpath_allocator_capture cr(stack.result); xpath_string l = lhs->eval_string(c, stack); xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { xpath_allocator_capture cri(stack.result); if (comp(l, string_value(*ri, stack.result))) return true; } return false; } } assert(!"Wrong types"); return false; } static bool eval_once(xpath_node_set::type_t type, nodeset_eval_t eval) { return type == xpath_node_set::type_sorted ? eval != nodeset_eval_all : eval == nodeset_eval_any; } template static bool compare_rel(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) { xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); if (lt != xpath_type_node_set && rt != xpath_type_node_set) return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); else if (lt == xpath_type_node_set && rt == xpath_type_node_set) { xpath_allocator_capture cr(stack.result); xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all); xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) { xpath_allocator_capture cri(stack.result); double l = convert_string_to_number(string_value(*li, stack.result).c_str()); for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { xpath_allocator_capture crii(stack.result); if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) return true; } } return false; } else if (lt != xpath_type_node_set && rt == xpath_type_node_set) { xpath_allocator_capture cr(stack.result); double l = lhs->eval_number(c, stack); xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) { xpath_allocator_capture cri(stack.result); if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) return true; } return false; } else if (lt == xpath_type_node_set && rt != xpath_type_node_set) { xpath_allocator_capture cr(stack.result); xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all); double r = rhs->eval_number(c, stack); for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) { xpath_allocator_capture cri(stack.result); if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r)) return true; } return false; } else { assert(!"Wrong types"); return false; } } static void apply_predicate_boolean(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once) { assert(ns.size() >= first); assert(expr->rettype() != xpath_type_number); size_t i = 1; size_t size = ns.size() - first; xpath_node* last = ns.begin() + first; // remove_if... or well, sort of for (xpath_node* it = last; it != ns.end(); ++it, ++i) { xpath_context c(*it, i, size); if (expr->eval_boolean(c, stack)) { *last++ = *it; if (once) break; } } ns.truncate(last); } static void apply_predicate_number(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once) { assert(ns.size() >= first); assert(expr->rettype() == xpath_type_number); size_t i = 1; size_t size = ns.size() - first; xpath_node* last = ns.begin() + first; // remove_if... or well, sort of for (xpath_node* it = last; it != ns.end(); ++it, ++i) { xpath_context c(*it, i, size); if (expr->eval_number(c, stack) == i) { *last++ = *it; if (once) break; } } ns.truncate(last); } static void apply_predicate_number_const(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack) { assert(ns.size() >= first); assert(expr->rettype() == xpath_type_number); size_t size = ns.size() - first; xpath_node* last = ns.begin() + first; xpath_context c(xpath_node(), 1, size); double er = expr->eval_number(c, stack); if (er >= 1.0 && er <= size) { size_t eri = static_cast(er); if (er == eri) { xpath_node r = last[eri - 1]; *last++ = r; } } ns.truncate(last); } void apply_predicate(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, bool once) { if (ns.size() == first) return; assert(_type == ast_filter || _type == ast_predicate); if (_test == predicate_constant || _test == predicate_constant_one) apply_predicate_number_const(ns, first, _right, stack); else if (_right->rettype() == xpath_type_number) apply_predicate_number(ns, first, _right, stack, once); else apply_predicate_boolean(ns, first, _right, stack, once); } void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, nodeset_eval_t eval) { if (ns.size() == first) return; bool last_once = eval_once(ns.type(), eval); for (xpath_ast_node* pred = _right; pred; pred = pred->_next) pred->apply_predicate(ns, first, stack, !pred->_next && last_once); } bool step_push(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* parent, xpath_allocator* alloc) { assert(a); const char_t* name = a->name ? a->name : PUGIXML_TEXT(""); switch (_test) { case nodetest_name: if (strequal(name, _data.nodetest) && is_xpath_attribute(name)) { ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); return true; } break; case nodetest_type_node: case nodetest_all: if (is_xpath_attribute(name)) { ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); return true; } break; case nodetest_all_in_namespace: if (starts_with(name, _data.nodetest) && is_xpath_attribute(name)) { ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); return true; } break; default: ; } return false; } bool step_push(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc) { assert(n); xml_node_type type = PUGI__NODETYPE(n); switch (_test) { case nodetest_name: if (type == node_element && n->name && strequal(n->name, _data.nodetest)) { ns.push_back(xml_node(n), alloc); return true; } break; case nodetest_type_node: ns.push_back(xml_node(n), alloc); return true; case nodetest_type_comment: if (type == node_comment) { ns.push_back(xml_node(n), alloc); return true; } break; case nodetest_type_text: if (type == node_pcdata || type == node_cdata) { ns.push_back(xml_node(n), alloc); return true; } break; case nodetest_type_pi: if (type == node_pi) { ns.push_back(xml_node(n), alloc); return true; } break; case nodetest_pi: if (type == node_pi && n->name && strequal(n->name, _data.nodetest)) { ns.push_back(xml_node(n), alloc); return true; } break; case nodetest_all: if (type == node_element) { ns.push_back(xml_node(n), alloc); return true; } break; case nodetest_all_in_namespace: if (type == node_element && n->name && starts_with(n->name, _data.nodetest)) { ns.push_back(xml_node(n), alloc); return true; } break; default: assert(!"Unknown axis"); } return false; } template void step_fill(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc, bool once, T) { const axis_t axis = T::axis; switch (axis) { case axis_attribute: { for (xml_attribute_struct* a = n->first_attribute; a; a = a->next_attribute) if (step_push(ns, a, n, alloc) & once) return; break; } case axis_child: { for (xml_node_struct* c = n->first_child; c; c = c->next_sibling) if (step_push(ns, c, alloc) & once) return; break; } case axis_descendant: case axis_descendant_or_self: { if (axis == axis_descendant_or_self) if (step_push(ns, n, alloc) & once) return; xml_node_struct* cur = n->first_child; while (cur) { if (step_push(ns, cur, alloc) & once) return; if (cur->first_child) cur = cur->first_child; else { while (!cur->next_sibling) { cur = cur->parent; if (cur == n) return; } cur = cur->next_sibling; } } break; } case axis_following_sibling: { for (xml_node_struct* c = n->next_sibling; c; c = c->next_sibling) if (step_push(ns, c, alloc) & once) return; break; } case axis_preceding_sibling: { for (xml_node_struct* c = n->prev_sibling_c; c->next_sibling; c = c->prev_sibling_c) if (step_push(ns, c, alloc) & once) return; break; } case axis_following: { xml_node_struct* cur = n; // exit from this node so that we don't include descendants while (!cur->next_sibling) { cur = cur->parent; if (!cur) return; } cur = cur->next_sibling; while (cur) { if (step_push(ns, cur, alloc) & once) return; if (cur->first_child) cur = cur->first_child; else { while (!cur->next_sibling) { cur = cur->parent; if (!cur) return; } cur = cur->next_sibling; } } break; } case axis_preceding: { xml_node_struct* cur = n; // exit from this node so that we don't include descendants while (!cur->prev_sibling_c->next_sibling) { cur = cur->parent; if (!cur) return; } cur = cur->prev_sibling_c; while (cur) { if (cur->first_child) cur = cur->first_child->prev_sibling_c; else { // leaf node, can't be ancestor if (step_push(ns, cur, alloc) & once) return; while (!cur->prev_sibling_c->next_sibling) { cur = cur->parent; if (!cur) return; if (!node_is_ancestor(cur, n)) if (step_push(ns, cur, alloc) & once) return; } cur = cur->prev_sibling_c; } } break; } case axis_ancestor: case axis_ancestor_or_self: { if (axis == axis_ancestor_or_self) if (step_push(ns, n, alloc) & once) return; xml_node_struct* cur = n->parent; while (cur) { if (step_push(ns, cur, alloc) & once) return; cur = cur->parent; } break; } case axis_self: { step_push(ns, n, alloc); break; } case axis_parent: { if (n->parent) step_push(ns, n->parent, alloc); break; } default: assert(!"Unimplemented axis"); } } template void step_fill(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* p, xpath_allocator* alloc, bool once, T v) { const axis_t axis = T::axis; switch (axis) { case axis_ancestor: case axis_ancestor_or_self: { if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test if (step_push(ns, a, p, alloc) & once) return; xml_node_struct* cur = p; while (cur) { if (step_push(ns, cur, alloc) & once) return; cur = cur->parent; } break; } case axis_descendant_or_self: case axis_self: { if (_test == nodetest_type_node) // reject attributes based on principal node type test step_push(ns, a, p, alloc); break; } case axis_following: { xml_node_struct* cur = p; while (cur) { if (cur->first_child) cur = cur->first_child; else { while (!cur->next_sibling) { cur = cur->parent; if (!cur) return; } cur = cur->next_sibling; } if (step_push(ns, cur, alloc) & once) return; } break; } case axis_parent: { step_push(ns, p, alloc); break; } case axis_preceding: { // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding step_fill(ns, p, alloc, once, v); break; } default: assert(!"Unimplemented axis"); } } template void step_fill(xpath_node_set_raw& ns, const xpath_node& xn, xpath_allocator* alloc, bool once, T v) { const axis_t axis = T::axis; const bool axis_has_attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self); if (xn.node()) step_fill(ns, xn.node().internal_object(), alloc, once, v); else if (axis_has_attributes && xn.attribute() && xn.parent()) step_fill(ns, xn.attribute().internal_object(), xn.parent().internal_object(), alloc, once, v); } template xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval, T v) { const axis_t axis = T::axis; const bool axis_reverse = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling); const xpath_node_set::type_t axis_type = axis_reverse ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted; bool once = (axis == axis_attribute && _test == nodetest_name) || (!_right && eval_once(axis_type, eval)) || (_right && !_right->_next && _right->_test == predicate_constant_one); xpath_node_set_raw ns; ns.set_type(axis_type); if (_left) { xpath_node_set_raw s = _left->eval_node_set(c, stack, nodeset_eval_all); // self axis preserves the original order if (axis == axis_self) ns.set_type(s.type()); for (const xpath_node* it = s.begin(); it != s.end(); ++it) { size_t size = ns.size(); // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted); step_fill(ns, *it, stack.result, once, v); if (_right) apply_predicates(ns, size, stack, eval); } } else { step_fill(ns, c.n, stack.result, once, v); if (_right) apply_predicates(ns, 0, stack, eval); } // child, attribute and self axes always generate unique set of nodes // for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the same node twice if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted) ns.remove_duplicates(); return ns; } public: xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value): _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) { assert(type == ast_string_constant); _data.string = value; } xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value): _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) { assert(type == ast_number_constant); _data.number = value; } xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value): _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) { assert(type == ast_variable); _data.variable = value; } xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = 0, xpath_ast_node* right = 0): _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0) { } xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents): _type(static_cast(type)), _rettype(xpath_type_node_set), _axis(static_cast(axis)), _test(static_cast(test)), _left(left), _right(0), _next(0) { assert(type == ast_step); _data.nodetest = contents; } xpath_ast_node(ast_type_t type, xpath_ast_node* left, xpath_ast_node* right, predicate_t test): _type(static_cast(type)), _rettype(xpath_type_node_set), _axis(0), _test(static_cast(test)), _left(left), _right(right), _next(0) { assert(type == ast_filter || type == ast_predicate); } void set_next(xpath_ast_node* value) { _next = value; } void set_right(xpath_ast_node* value) { _right = value; } bool eval_boolean(const xpath_context& c, const xpath_stack& stack) { switch (_type) { case ast_op_or: return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack); case ast_op_and: return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack); case ast_op_equal: return compare_eq(_left, _right, c, stack, equal_to()); case ast_op_not_equal: return compare_eq(_left, _right, c, stack, not_equal_to()); case ast_op_less: return compare_rel(_left, _right, c, stack, less()); case ast_op_greater: return compare_rel(_right, _left, c, stack, less()); case ast_op_less_or_equal: return compare_rel(_left, _right, c, stack, less_equal()); case ast_op_greater_or_equal: return compare_rel(_right, _left, c, stack, less_equal()); case ast_func_starts_with: { xpath_allocator_capture cr(stack.result); xpath_string lr = _left->eval_string(c, stack); xpath_string rr = _right->eval_string(c, stack); return starts_with(lr.c_str(), rr.c_str()); } case ast_func_contains: { xpath_allocator_capture cr(stack.result); xpath_string lr = _left->eval_string(c, stack); xpath_string rr = _right->eval_string(c, stack); return find_substring(lr.c_str(), rr.c_str()) != 0; } case ast_func_boolean: return _left->eval_boolean(c, stack); case ast_func_not: return !_left->eval_boolean(c, stack); case ast_func_true: return true; case ast_func_false: return false; case ast_func_lang: { if (c.n.attribute()) return false; xpath_allocator_capture cr(stack.result); xpath_string lang = _left->eval_string(c, stack); for (xml_node n = c.n.node(); n; n = n.parent()) { xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang")); if (a) { const char_t* value = a.value(); // strnicmp / strncasecmp is not portable for (const char_t* lit = lang.c_str(); *lit; ++lit) { if (tolower_ascii(*lit) != tolower_ascii(*value)) return false; ++value; } return *value == 0 || *value == '-'; } } return false; } case ast_opt_compare_attribute: { const char_t* value = (_right->_type == ast_string_constant) ? _right->_data.string : _right->_data.variable->get_string(); xml_attribute attr = c.n.node().attribute(_left->_data.nodetest); return attr && strequal(attr.value(), value) && is_xpath_attribute(attr.name()); } case ast_variable: { assert(_rettype == _data.variable->type()); if (_rettype == xpath_type_boolean) return _data.variable->get_boolean(); // fallthrough to type conversion } default: { switch (_rettype) { case xpath_type_number: return convert_number_to_boolean(eval_number(c, stack)); case xpath_type_string: { xpath_allocator_capture cr(stack.result); return !eval_string(c, stack).empty(); } case xpath_type_node_set: { xpath_allocator_capture cr(stack.result); return !eval_node_set(c, stack, nodeset_eval_any).empty(); } default: assert(!"Wrong expression for return type boolean"); return false; } } } } double eval_number(const xpath_context& c, const xpath_stack& stack) { switch (_type) { case ast_op_add: return _left->eval_number(c, stack) + _right->eval_number(c, stack); case ast_op_subtract: return _left->eval_number(c, stack) - _right->eval_number(c, stack); case ast_op_multiply: return _left->eval_number(c, stack) * _right->eval_number(c, stack); case ast_op_divide: return _left->eval_number(c, stack) / _right->eval_number(c, stack); case ast_op_mod: return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack)); case ast_op_negate: return -_left->eval_number(c, stack); case ast_number_constant: return _data.number; case ast_func_last: return static_cast(c.size); case ast_func_position: return static_cast(c.position); case ast_func_count: { xpath_allocator_capture cr(stack.result); return static_cast(_left->eval_node_set(c, stack, nodeset_eval_all).size()); } case ast_func_string_length_0: { xpath_allocator_capture cr(stack.result); return static_cast(string_value(c.n, stack.result).length()); } case ast_func_string_length_1: { xpath_allocator_capture cr(stack.result); return static_cast(_left->eval_string(c, stack).length()); } case ast_func_number_0: { xpath_allocator_capture cr(stack.result); return convert_string_to_number(string_value(c.n, stack.result).c_str()); } case ast_func_number_1: return _left->eval_number(c, stack); case ast_func_sum: { xpath_allocator_capture cr(stack.result); double r = 0; xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_all); for (const xpath_node* it = ns.begin(); it != ns.end(); ++it) { xpath_allocator_capture cri(stack.result); r += convert_string_to_number(string_value(*it, stack.result).c_str()); } return r; } case ast_func_floor: { double r = _left->eval_number(c, stack); return r == r ? floor(r) : r; } case ast_func_ceiling: { double r = _left->eval_number(c, stack); return r == r ? ceil(r) : r; } case ast_func_round: return round_nearest_nzero(_left->eval_number(c, stack)); case ast_variable: { assert(_rettype == _data.variable->type()); if (_rettype == xpath_type_number) return _data.variable->get_number(); // fallthrough to type conversion } default: { switch (_rettype) { case xpath_type_boolean: return eval_boolean(c, stack) ? 1 : 0; case xpath_type_string: { xpath_allocator_capture cr(stack.result); return convert_string_to_number(eval_string(c, stack).c_str()); } case xpath_type_node_set: { xpath_allocator_capture cr(stack.result); return convert_string_to_number(eval_string(c, stack).c_str()); } default: assert(!"Wrong expression for return type number"); return 0; } } } } xpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack) { assert(_type == ast_func_concat); xpath_allocator_capture ct(stack.temp); // count the string number size_t count = 1; for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++; // gather all strings xpath_string static_buffer[4]; xpath_string* buffer = static_buffer; // allocate on-heap for large concats if (count > sizeof(static_buffer) / sizeof(static_buffer[0])) { buffer = static_cast(stack.temp->allocate(count * sizeof(xpath_string))); assert(buffer); } // evaluate all strings to temporary stack xpath_stack swapped_stack = {stack.temp, stack.result}; buffer[0] = _left->eval_string(c, swapped_stack); size_t pos = 1; for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack); assert(pos == count); // get total length size_t length = 0; for (size_t i = 0; i < count; ++i) length += buffer[i].length(); // create final string char_t* result = static_cast(stack.result->allocate((length + 1) * sizeof(char_t))); assert(result); char_t* ri = result; for (size_t j = 0; j < count; ++j) for (const char_t* bi = buffer[j].c_str(); *bi; ++bi) *ri++ = *bi; *ri = 0; return xpath_string::from_heap_preallocated(result, ri); } xpath_string eval_string(const xpath_context& c, const xpath_stack& stack) { switch (_type) { case ast_string_constant: return xpath_string::from_const(_data.string); case ast_func_local_name_0: { xpath_node na = c.n; return xpath_string::from_const(local_name(na)); } case ast_func_local_name_1: { xpath_allocator_capture cr(stack.result); xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); xpath_node na = ns.first(); return xpath_string::from_const(local_name(na)); } case ast_func_name_0: { xpath_node na = c.n; return xpath_string::from_const(qualified_name(na)); } case ast_func_name_1: { xpath_allocator_capture cr(stack.result); xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); xpath_node na = ns.first(); return xpath_string::from_const(qualified_name(na)); } case ast_func_namespace_uri_0: { xpath_node na = c.n; return xpath_string::from_const(namespace_uri(na)); } case ast_func_namespace_uri_1: { xpath_allocator_capture cr(stack.result); xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); xpath_node na = ns.first(); return xpath_string::from_const(namespace_uri(na)); } case ast_func_string_0: return string_value(c.n, stack.result); case ast_func_string_1: return _left->eval_string(c, stack); case ast_func_concat: return eval_string_concat(c, stack); case ast_func_substring_before: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_string s = _left->eval_string(c, swapped_stack); xpath_string p = _right->eval_string(c, swapped_stack); const char_t* pos = find_substring(s.c_str(), p.c_str()); return pos ? xpath_string::from_heap(s.c_str(), pos, stack.result) : xpath_string(); } case ast_func_substring_after: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_string s = _left->eval_string(c, swapped_stack); xpath_string p = _right->eval_string(c, swapped_stack); const char_t* pos = find_substring(s.c_str(), p.c_str()); if (!pos) return xpath_string(); const char_t* rbegin = pos + p.length(); const char_t* rend = s.c_str() + s.length(); return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin); } case ast_func_substring_2: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_string s = _left->eval_string(c, swapped_stack); size_t s_length = s.length(); double first = round_nearest(_right->eval_number(c, stack)); if (is_nan(first)) return xpath_string(); // NaN else if (first >= s_length + 1) return xpath_string(); size_t pos = first < 1 ? 1 : static_cast(first); assert(1 <= pos && pos <= s_length + 1); const char_t* rbegin = s.c_str() + (pos - 1); const char_t* rend = s.c_str() + s.length(); return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin); } case ast_func_substring_3: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_string s = _left->eval_string(c, swapped_stack); size_t s_length = s.length(); double first = round_nearest(_right->eval_number(c, stack)); double last = first + round_nearest(_right->_next->eval_number(c, stack)); if (is_nan(first) || is_nan(last)) return xpath_string(); else if (first >= s_length + 1) return xpath_string(); else if (first >= last) return xpath_string(); else if (last < 1) return xpath_string(); size_t pos = first < 1 ? 1 : static_cast(first); size_t end = last >= s_length + 1 ? s_length + 1 : static_cast(last); assert(1 <= pos && pos <= end && end <= s_length + 1); const char_t* rbegin = s.c_str() + (pos - 1); const char_t* rend = s.c_str() + (end - 1); return (end == s_length + 1 && !s.uses_heap()) ? xpath_string::from_const(rbegin) : xpath_string::from_heap(rbegin, rend, stack.result); } case ast_func_normalize_space_0: { xpath_string s = string_value(c.n, stack.result); char_t* begin = s.data(stack.result); char_t* end = normalize_space(begin); return xpath_string::from_heap_preallocated(begin, end); } case ast_func_normalize_space_1: { xpath_string s = _left->eval_string(c, stack); char_t* begin = s.data(stack.result); char_t* end = normalize_space(begin); return xpath_string::from_heap_preallocated(begin, end); } case ast_func_translate: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_string s = _left->eval_string(c, stack); xpath_string from = _right->eval_string(c, swapped_stack); xpath_string to = _right->_next->eval_string(c, swapped_stack); char_t* begin = s.data(stack.result); char_t* end = translate(begin, from.c_str(), to.c_str(), to.length()); return xpath_string::from_heap_preallocated(begin, end); } case ast_opt_translate_table: { xpath_string s = _left->eval_string(c, stack); char_t* begin = s.data(stack.result); char_t* end = translate_table(begin, _data.table); return xpath_string::from_heap_preallocated(begin, end); } case ast_variable: { assert(_rettype == _data.variable->type()); if (_rettype == xpath_type_string) return xpath_string::from_const(_data.variable->get_string()); // fallthrough to type conversion } default: { switch (_rettype) { case xpath_type_boolean: return xpath_string::from_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); case xpath_type_number: return convert_number_to_string(eval_number(c, stack), stack.result); case xpath_type_node_set: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_node_set_raw ns = eval_node_set(c, swapped_stack, nodeset_eval_first); return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result); } default: assert(!"Wrong expression for return type string"); return xpath_string(); } } } } xpath_node_set_raw eval_node_set(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval) { switch (_type) { case ast_op_union: { xpath_allocator_capture cr(stack.temp); xpath_stack swapped_stack = {stack.temp, stack.result}; xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack, eval); xpath_node_set_raw rs = _right->eval_node_set(c, stack, eval); // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother rs.set_type(xpath_node_set::type_unsorted); rs.append(ls.begin(), ls.end(), stack.result); rs.remove_duplicates(); return rs; } case ast_filter: { xpath_node_set_raw set = _left->eval_node_set(c, stack, _test == predicate_constant_one ? nodeset_eval_first : nodeset_eval_all); // either expression is a number or it contains position() call; sort by document order if (_test != predicate_posinv) set.sort_do(); bool once = eval_once(set.type(), eval); apply_predicate(set, 0, stack, once); return set; } case ast_func_id: return xpath_node_set_raw(); case ast_step: { switch (_axis) { case axis_ancestor: return step_do(c, stack, eval, axis_to_type()); case axis_ancestor_or_self: return step_do(c, stack, eval, axis_to_type()); case axis_attribute: return step_do(c, stack, eval, axis_to_type()); case axis_child: return step_do(c, stack, eval, axis_to_type()); case axis_descendant: return step_do(c, stack, eval, axis_to_type()); case axis_descendant_or_self: return step_do(c, stack, eval, axis_to_type()); case axis_following: return step_do(c, stack, eval, axis_to_type()); case axis_following_sibling: return step_do(c, stack, eval, axis_to_type()); case axis_namespace: // namespaced axis is not supported return xpath_node_set_raw(); case axis_parent: return step_do(c, stack, eval, axis_to_type()); case axis_preceding: return step_do(c, stack, eval, axis_to_type()); case axis_preceding_sibling: return step_do(c, stack, eval, axis_to_type()); case axis_self: return step_do(c, stack, eval, axis_to_type()); default: assert(!"Unknown axis"); return xpath_node_set_raw(); } } case ast_step_root: { assert(!_right); // root step can't have any predicates xpath_node_set_raw ns; ns.set_type(xpath_node_set::type_sorted); if (c.n.node()) ns.push_back(c.n.node().root(), stack.result); else if (c.n.attribute()) ns.push_back(c.n.parent().root(), stack.result); return ns; } case ast_variable: { assert(_rettype == _data.variable->type()); if (_rettype == xpath_type_node_set) { const xpath_node_set& s = _data.variable->get_node_set(); xpath_node_set_raw ns; ns.set_type(s.type()); ns.append(s.begin(), s.end(), stack.result); return ns; } // fallthrough to type conversion } default: assert(!"Wrong expression for return type node set"); return xpath_node_set_raw(); } } void optimize(xpath_allocator* alloc) { if (_left) _left->optimize(alloc); if (_right) _right->optimize(alloc); if (_next) _next->optimize(alloc); // Rewrite [position()=expr] with [expr] // Note that this step has to go before classification to recognize [position()=1] if ((_type == ast_filter || _type == ast_predicate) && _right->_type == ast_op_equal && _right->_left->_type == ast_func_position && _right->_right->_rettype == xpath_type_number) { _right = _right->_right; } // Classify filter/predicate ops to perform various optimizations during evaluation if (_type == ast_filter || _type == ast_predicate) { assert(_test == predicate_default); if (_right->_type == ast_number_constant && _right->_data.number == 1.0) _test = predicate_constant_one; else if (_right->_rettype == xpath_type_number && (_right->_type == ast_number_constant || _right->_type == ast_variable || _right->_type == ast_func_last)) _test = predicate_constant; else if (_right->_rettype != xpath_type_number && _right->is_posinv_expr()) _test = predicate_posinv; } // Rewrite descendant-or-self::node()/child::foo with descendant::foo // The former is a full form of //foo, the latter is much faster since it executes the node test immediately // Do a similar kind of rewrite for self/descendant/descendant-or-self axes // Note that we only rewrite positionally invariant steps (//foo[1] != /descendant::foo[1]) if (_type == ast_step && (_axis == axis_child || _axis == axis_self || _axis == axis_descendant || _axis == axis_descendant_or_self) && _left && _left->_type == ast_step && _left->_axis == axis_descendant_or_self && _left->_test == nodetest_type_node && !_left->_right && is_posinv_step()) { if (_axis == axis_child || _axis == axis_descendant) _axis = axis_descendant; else _axis = axis_descendant_or_self; _left = _left->_left; } // Use optimized lookup table implementation for translate() with constant arguments if (_type == ast_func_translate && _right->_type == ast_string_constant && _right->_next->_type == ast_string_constant) { unsigned char* table = translate_table_generate(alloc, _right->_data.string, _right->_next->_data.string); if (table) { _type = ast_opt_translate_table; _data.table = table; } } // Use optimized path for @attr = 'value' or @attr = $value if (_type == ast_op_equal && _left->_type == ast_step && _left->_axis == axis_attribute && _left->_test == nodetest_name && !_left->_left && !_left->_right && (_right->_type == ast_string_constant || (_right->_type == ast_variable && _right->_rettype == xpath_type_string))) { _type = ast_opt_compare_attribute; } } bool is_posinv_expr() const { switch (_type) { case ast_func_position: case ast_func_last: return false; case ast_string_constant: case ast_number_constant: case ast_variable: return true; case ast_step: case ast_step_root: return true; case ast_predicate: case ast_filter: return true; default: if (_left && !_left->is_posinv_expr()) return false; for (xpath_ast_node* n = _right; n; n = n->_next) if (!n->is_posinv_expr()) return false; return true; } } bool is_posinv_step() const { assert(_type == ast_step); for (xpath_ast_node* n = _right; n; n = n->_next) { assert(n->_type == ast_predicate); if (n->_test != predicate_posinv) return false; } return true; } xpath_value_type rettype() const { return static_cast(_rettype); } }; struct xpath_parser { xpath_allocator* _alloc; xpath_lexer _lexer; const char_t* _query; xpath_variable_set* _variables; xpath_parse_result* _result; char_t _scratch[32]; #ifdef PUGIXML_NO_EXCEPTIONS jmp_buf _error_handler; #endif void throw_error(const char* message) { _result->error = message; _result->offset = _lexer.current_pos() - _query; #ifdef PUGIXML_NO_EXCEPTIONS longjmp(_error_handler, 1); #else throw xpath_exception(*_result); #endif } void throw_error_oom() { #ifdef PUGIXML_NO_EXCEPTIONS throw_error("Out of memory"); #else throw std::bad_alloc(); #endif } void* alloc_node() { void* result = _alloc->allocate_nothrow(sizeof(xpath_ast_node)); if (!result) throw_error_oom(); return result; } const char_t* alloc_string(const xpath_lexer_string& value) { if (value.begin) { size_t length = static_cast(value.end - value.begin); char_t* c = static_cast(_alloc->allocate_nothrow((length + 1) * sizeof(char_t))); if (!c) throw_error_oom(); assert(c); // workaround for clang static analysis memcpy(c, value.begin, length * sizeof(char_t)); c[length] = 0; return c; } else return 0; } xpath_ast_node* parse_function_helper(ast_type_t type0, ast_type_t type1, size_t argc, xpath_ast_node* args[2]) { assert(argc <= 1); if (argc == 1 && args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]); } xpath_ast_node* parse_function(const xpath_lexer_string& name, size_t argc, xpath_ast_node* args[2]) { switch (name.begin[0]) { case 'b': if (name == PUGIXML_TEXT("boolean") && argc == 1) return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]); break; case 'c': if (name == PUGIXML_TEXT("count") && argc == 1) { if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]); } else if (name == PUGIXML_TEXT("contains") && argc == 2) return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_boolean, args[0], args[1]); else if (name == PUGIXML_TEXT("concat") && argc >= 2) return new (alloc_node()) xpath_ast_node(ast_func_concat, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("ceiling") && argc == 1) return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]); break; case 'f': if (name == PUGIXML_TEXT("false") && argc == 0) return new (alloc_node()) xpath_ast_node(ast_func_false, xpath_type_boolean); else if (name == PUGIXML_TEXT("floor") && argc == 1) return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]); break; case 'i': if (name == PUGIXML_TEXT("id") && argc == 1) return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]); break; case 'l': if (name == PUGIXML_TEXT("last") && argc == 0) return new (alloc_node()) xpath_ast_node(ast_func_last, xpath_type_number); else if (name == PUGIXML_TEXT("lang") && argc == 1) return new (alloc_node()) xpath_ast_node(ast_func_lang, xpath_type_boolean, args[0]); else if (name == PUGIXML_TEXT("local-name") && argc <= 1) return parse_function_helper(ast_func_local_name_0, ast_func_local_name_1, argc, args); break; case 'n': if (name == PUGIXML_TEXT("name") && argc <= 1) return parse_function_helper(ast_func_name_0, ast_func_name_1, argc, args); else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1) return parse_function_helper(ast_func_namespace_uri_0, ast_func_namespace_uri_1, argc, args); else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1) return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("not") && argc == 1) return new (alloc_node()) xpath_ast_node(ast_func_not, xpath_type_boolean, args[0]); else if (name == PUGIXML_TEXT("number") && argc <= 1) return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]); break; case 'p': if (name == PUGIXML_TEXT("position") && argc == 0) return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number); break; case 'r': if (name == PUGIXML_TEXT("round") && argc == 1) return new (alloc_node()) xpath_ast_node(ast_func_round, xpath_type_number, args[0]); break; case 's': if (name == PUGIXML_TEXT("string") && argc <= 1) return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]); else if (name == PUGIXML_TEXT("string-length") && argc <= 1) return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_number, args[0]); else if (name == PUGIXML_TEXT("starts-with") && argc == 2) return new (alloc_node()) xpath_ast_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]); else if (name == PUGIXML_TEXT("substring-before") && argc == 2) return new (alloc_node()) xpath_ast_node(ast_func_substring_before, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("substring-after") && argc == 2) return new (alloc_node()) xpath_ast_node(ast_func_substring_after, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3)) return new (alloc_node()) xpath_ast_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("sum") && argc == 1) { if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); return new (alloc_node()) xpath_ast_node(ast_func_sum, xpath_type_number, args[0]); } break; case 't': if (name == PUGIXML_TEXT("translate") && argc == 3) return new (alloc_node()) xpath_ast_node(ast_func_translate, xpath_type_string, args[0], args[1]); else if (name == PUGIXML_TEXT("true") && argc == 0) return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean); break; default: break; } throw_error("Unrecognized function or wrong parameter count"); return 0; } axis_t parse_axis_name(const xpath_lexer_string& name, bool& specified) { specified = true; switch (name.begin[0]) { case 'a': if (name == PUGIXML_TEXT("ancestor")) return axis_ancestor; else if (name == PUGIXML_TEXT("ancestor-or-self")) return axis_ancestor_or_self; else if (name == PUGIXML_TEXT("attribute")) return axis_attribute; break; case 'c': if (name == PUGIXML_TEXT("child")) return axis_child; break; case 'd': if (name == PUGIXML_TEXT("descendant")) return axis_descendant; else if (name == PUGIXML_TEXT("descendant-or-self")) return axis_descendant_or_self; break; case 'f': if (name == PUGIXML_TEXT("following")) return axis_following; else if (name == PUGIXML_TEXT("following-sibling")) return axis_following_sibling; break; case 'n': if (name == PUGIXML_TEXT("namespace")) return axis_namespace; break; case 'p': if (name == PUGIXML_TEXT("parent")) return axis_parent; else if (name == PUGIXML_TEXT("preceding")) return axis_preceding; else if (name == PUGIXML_TEXT("preceding-sibling")) return axis_preceding_sibling; break; case 's': if (name == PUGIXML_TEXT("self")) return axis_self; break; default: break; } specified = false; return axis_child; } nodetest_t parse_node_test_type(const xpath_lexer_string& name) { switch (name.begin[0]) { case 'c': if (name == PUGIXML_TEXT("comment")) return nodetest_type_comment; break; case 'n': if (name == PUGIXML_TEXT("node")) return nodetest_type_node; break; case 'p': if (name == PUGIXML_TEXT("processing-instruction")) return nodetest_type_pi; break; case 't': if (name == PUGIXML_TEXT("text")) return nodetest_type_text; break; default: break; } return nodetest_none; } // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall xpath_ast_node* parse_primary_expression() { switch (_lexer.current()) { case lex_var_ref: { xpath_lexer_string name = _lexer.contents(); if (!_variables) throw_error("Unknown variable: variable set is not provided"); xpath_variable* var = get_variable_scratch(_scratch, _variables, name.begin, name.end); if (!var) throw_error("Unknown variable: variable set does not contain the given name"); _lexer.next(); return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), var); } case lex_open_brace: { _lexer.next(); xpath_ast_node* n = parse_expression(); if (_lexer.current() != lex_close_brace) throw_error("Unmatched braces"); _lexer.next(); return n; } case lex_quoted_string: { const char_t* value = alloc_string(_lexer.contents()); xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_string_constant, xpath_type_string, value); _lexer.next(); return n; } case lex_number: { double value = 0; if (!convert_string_to_number_scratch(_scratch, _lexer.contents().begin, _lexer.contents().end, &value)) throw_error_oom(); xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_number_constant, xpath_type_number, value); _lexer.next(); return n; } case lex_string: { xpath_ast_node* args[2] = {0}; size_t argc = 0; xpath_lexer_string function = _lexer.contents(); _lexer.next(); xpath_ast_node* last_arg = 0; if (_lexer.current() != lex_open_brace) throw_error("Unrecognized function call"); _lexer.next(); if (_lexer.current() != lex_close_brace) args[argc++] = parse_expression(); while (_lexer.current() != lex_close_brace) { if (_lexer.current() != lex_comma) throw_error("No comma between function arguments"); _lexer.next(); xpath_ast_node* n = parse_expression(); if (argc < 2) args[argc] = n; else last_arg->set_next(n); argc++; last_arg = n; } _lexer.next(); return parse_function(function, argc, args); } default: throw_error("Unrecognizable primary expression"); return 0; } } // FilterExpr ::= PrimaryExpr | FilterExpr Predicate // Predicate ::= '[' PredicateExpr ']' // PredicateExpr ::= Expr xpath_ast_node* parse_filter_expression() { xpath_ast_node* n = parse_primary_expression(); while (_lexer.current() == lex_open_square_brace) { _lexer.next(); xpath_ast_node* expr = parse_expression(); if (n->rettype() != xpath_type_node_set) throw_error("Predicate has to be applied to node set"); n = new (alloc_node()) xpath_ast_node(ast_filter, n, expr, predicate_default); if (_lexer.current() != lex_close_square_brace) throw_error("Unmatched square brace"); _lexer.next(); } return n; } // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep // AxisSpecifier ::= AxisName '::' | '@'? // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')' // NameTest ::= '*' | NCName ':' '*' | QName // AbbreviatedStep ::= '.' | '..' xpath_ast_node* parse_step(xpath_ast_node* set) { if (set && set->rettype() != xpath_type_node_set) throw_error("Step has to be applied to node set"); bool axis_specified = false; axis_t axis = axis_child; // implied child axis if (_lexer.current() == lex_axis_attribute) { axis = axis_attribute; axis_specified = true; _lexer.next(); } else if (_lexer.current() == lex_dot) { _lexer.next(); return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0); } else if (_lexer.current() == lex_double_dot) { _lexer.next(); return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0); } nodetest_t nt_type = nodetest_none; xpath_lexer_string nt_name; if (_lexer.current() == lex_string) { // node name test nt_name = _lexer.contents(); _lexer.next(); // was it an axis name? if (_lexer.current() == lex_double_colon) { // parse axis name if (axis_specified) throw_error("Two axis specifiers in one step"); axis = parse_axis_name(nt_name, axis_specified); if (!axis_specified) throw_error("Unknown axis"); // read actual node test _lexer.next(); if (_lexer.current() == lex_multiply) { nt_type = nodetest_all; nt_name = xpath_lexer_string(); _lexer.next(); } else if (_lexer.current() == lex_string) { nt_name = _lexer.contents(); _lexer.next(); } else throw_error("Unrecognized node test"); } if (nt_type == nodetest_none) { // node type test or processing-instruction if (_lexer.current() == lex_open_brace) { _lexer.next(); if (_lexer.current() == lex_close_brace) { _lexer.next(); nt_type = parse_node_test_type(nt_name); if (nt_type == nodetest_none) throw_error("Unrecognized node type"); nt_name = xpath_lexer_string(); } else if (nt_name == PUGIXML_TEXT("processing-instruction")) { if (_lexer.current() != lex_quoted_string) throw_error("Only literals are allowed as arguments to processing-instruction()"); nt_type = nodetest_pi; nt_name = _lexer.contents(); _lexer.next(); if (_lexer.current() != lex_close_brace) throw_error("Unmatched brace near processing-instruction()"); _lexer.next(); } else throw_error("Unmatched brace near node type test"); } // QName or NCName:* else { if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:* { nt_name.end--; // erase * nt_type = nodetest_all_in_namespace; } else nt_type = nodetest_name; } } } else if (_lexer.current() == lex_multiply) { nt_type = nodetest_all; _lexer.next(); } else throw_error("Unrecognized node test"); xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, alloc_string(nt_name)); xpath_ast_node* last = 0; while (_lexer.current() == lex_open_square_brace) { _lexer.next(); xpath_ast_node* expr = parse_expression(); xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, 0, expr, predicate_default); if (_lexer.current() != lex_close_square_brace) throw_error("Unmatched square brace"); _lexer.next(); if (last) last->set_next(pred); else n->set_right(pred); last = pred; } return n; } // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step xpath_ast_node* parse_relative_location_path(xpath_ast_node* set) { xpath_ast_node* n = parse_step(set); while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) { lexeme_t l = _lexer.current(); _lexer.next(); if (l == lex_double_slash) n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); n = parse_step(n); } return n; } // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath xpath_ast_node* parse_location_path() { if (_lexer.current() == lex_slash) { _lexer.next(); xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path lexeme_t l = _lexer.current(); if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply) return parse_relative_location_path(n); else return n; } else if (_lexer.current() == lex_double_slash) { _lexer.next(); xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); return parse_relative_location_path(n); } // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1 return parse_relative_location_path(0); } // PathExpr ::= LocationPath // | FilterExpr // | FilterExpr '/' RelativeLocationPath // | FilterExpr '//' RelativeLocationPath // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr // UnaryExpr ::= UnionExpr | '-' UnaryExpr xpath_ast_node* parse_path_or_unary_expression() { // Clarification. // PathExpr begins with either LocationPath or FilterExpr. // FilterExpr begins with PrimaryExpr // PrimaryExpr begins with '$' in case of it being a variable reference, // '(' in case of it being an expression, string literal, number constant or // function call. if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || _lexer.current() == lex_quoted_string || _lexer.current() == lex_number || _lexer.current() == lex_string) { if (_lexer.current() == lex_string) { // This is either a function call, or not - if not, we shall proceed with location path const char_t* state = _lexer.state(); while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state; if (*state != '(') return parse_location_path(); // This looks like a function call; however this still can be a node-test. Check it. if (parse_node_test_type(_lexer.contents()) != nodetest_none) return parse_location_path(); } xpath_ast_node* n = parse_filter_expression(); if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) { lexeme_t l = _lexer.current(); _lexer.next(); if (l == lex_double_slash) { if (n->rettype() != xpath_type_node_set) throw_error("Step has to be applied to node set"); n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); } // select from location path return parse_relative_location_path(n); } return n; } else if (_lexer.current() == lex_minus) { _lexer.next(); // precedence 7+ - only parses union expressions xpath_ast_node* expr = parse_expression_rec(parse_path_or_unary_expression(), 7); return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr); } else return parse_location_path(); } struct binary_op_t { ast_type_t asttype; xpath_value_type rettype; int precedence; binary_op_t(): asttype(ast_unknown), rettype(xpath_type_none), precedence(0) { } binary_op_t(ast_type_t asttype_, xpath_value_type rettype_, int precedence_): asttype(asttype_), rettype(rettype_), precedence(precedence_) { } static binary_op_t parse(xpath_lexer& lexer) { switch (lexer.current()) { case lex_string: if (lexer.contents() == PUGIXML_TEXT("or")) return binary_op_t(ast_op_or, xpath_type_boolean, 1); else if (lexer.contents() == PUGIXML_TEXT("and")) return binary_op_t(ast_op_and, xpath_type_boolean, 2); else if (lexer.contents() == PUGIXML_TEXT("div")) return binary_op_t(ast_op_divide, xpath_type_number, 6); else if (lexer.contents() == PUGIXML_TEXT("mod")) return binary_op_t(ast_op_mod, xpath_type_number, 6); else return binary_op_t(); case lex_equal: return binary_op_t(ast_op_equal, xpath_type_boolean, 3); case lex_not_equal: return binary_op_t(ast_op_not_equal, xpath_type_boolean, 3); case lex_less: return binary_op_t(ast_op_less, xpath_type_boolean, 4); case lex_greater: return binary_op_t(ast_op_greater, xpath_type_boolean, 4); case lex_less_or_equal: return binary_op_t(ast_op_less_or_equal, xpath_type_boolean, 4); case lex_greater_or_equal: return binary_op_t(ast_op_greater_or_equal, xpath_type_boolean, 4); case lex_plus: return binary_op_t(ast_op_add, xpath_type_number, 5); case lex_minus: return binary_op_t(ast_op_subtract, xpath_type_number, 5); case lex_multiply: return binary_op_t(ast_op_multiply, xpath_type_number, 6); case lex_union: return binary_op_t(ast_op_union, xpath_type_node_set, 7); default: return binary_op_t(); } } }; xpath_ast_node* parse_expression_rec(xpath_ast_node* lhs, int limit) { binary_op_t op = binary_op_t::parse(_lexer); while (op.asttype != ast_unknown && op.precedence >= limit) { _lexer.next(); xpath_ast_node* rhs = parse_path_or_unary_expression(); binary_op_t nextop = binary_op_t::parse(_lexer); while (nextop.asttype != ast_unknown && nextop.precedence > op.precedence) { rhs = parse_expression_rec(rhs, nextop.precedence); nextop = binary_op_t::parse(_lexer); } if (op.asttype == ast_op_union && (lhs->rettype() != xpath_type_node_set || rhs->rettype() != xpath_type_node_set)) throw_error("Union operator has to be applied to node sets"); lhs = new (alloc_node()) xpath_ast_node(op.asttype, op.rettype, lhs, rhs); op = binary_op_t::parse(_lexer); } return lhs; } // Expr ::= OrExpr // OrExpr ::= AndExpr | OrExpr 'or' AndExpr // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr // EqualityExpr ::= RelationalExpr // | EqualityExpr '=' RelationalExpr // | EqualityExpr '!=' RelationalExpr // RelationalExpr ::= AdditiveExpr // | RelationalExpr '<' AdditiveExpr // | RelationalExpr '>' AdditiveExpr // | RelationalExpr '<=' AdditiveExpr // | RelationalExpr '>=' AdditiveExpr // AdditiveExpr ::= MultiplicativeExpr // | AdditiveExpr '+' MultiplicativeExpr // | AdditiveExpr '-' MultiplicativeExpr // MultiplicativeExpr ::= UnaryExpr // | MultiplicativeExpr '*' UnaryExpr // | MultiplicativeExpr 'div' UnaryExpr // | MultiplicativeExpr 'mod' UnaryExpr xpath_ast_node* parse_expression() { return parse_expression_rec(parse_path_or_unary_expression(), 0); } xpath_parser(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result) { } xpath_ast_node* parse() { xpath_ast_node* result = parse_expression(); if (_lexer.current() != lex_eof) { // there are still unparsed tokens left, error throw_error("Incorrect query"); } return result; } static xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result) { xpath_parser parser(query, variables, alloc, result); #ifdef PUGIXML_NO_EXCEPTIONS int error = setjmp(parser._error_handler); return (error == 0) ? parser.parse() : 0; #else return parser.parse(); #endif } }; struct xpath_query_impl { static xpath_query_impl* create() { void* memory = xml_memory::allocate(sizeof(xpath_query_impl)); return new (memory) xpath_query_impl(); } static void destroy(void* ptr) { if (!ptr) return; // free all allocated pages static_cast(ptr)->alloc.release(); // free allocator memory (with the first page) xml_memory::deallocate(ptr); } xpath_query_impl(): root(0), alloc(&block) { block.next = 0; block.capacity = sizeof(block.data); } xpath_ast_node* root; xpath_allocator alloc; xpath_memory_block block; }; PUGI__FN xpath_string evaluate_string_impl(xpath_query_impl* impl, const xpath_node& n, xpath_stack_data& sd) { if (!impl) return xpath_string(); #ifdef PUGIXML_NO_EXCEPTIONS if (setjmp(sd.error_handler)) return xpath_string(); #endif xpath_context c(n, 1, 1); return impl->root->eval_string(c, sd.stack); } PUGI__FN impl::xpath_ast_node* evaluate_node_set_prepare(xpath_query_impl* impl) { if (!impl) return 0; if (impl->root->rettype() != xpath_type_node_set) { #ifdef PUGIXML_NO_EXCEPTIONS return 0; #else xpath_parse_result res; res.error = "Expression does not evaluate to node set"; throw xpath_exception(res); #endif } return impl->root; } PUGI__NS_END namespace pugi { #ifndef PUGIXML_NO_EXCEPTIONS PUGI__FN xpath_exception::xpath_exception(const xpath_parse_result& result_): _result(result_) { assert(_result.error); } PUGI__FN const char* xpath_exception::what() const throw() { return _result.error; } PUGI__FN const xpath_parse_result& xpath_exception::result() const { return _result; } #endif PUGI__FN xpath_node::xpath_node() { } PUGI__FN xpath_node::xpath_node(const xml_node& node_): _node(node_) { } PUGI__FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_) { } PUGI__FN xml_node xpath_node::node() const { return _attribute ? xml_node() : _node; } PUGI__FN xml_attribute xpath_node::attribute() const { return _attribute; } PUGI__FN xml_node xpath_node::parent() const { return _attribute ? _node : _node.parent(); } PUGI__FN static void unspecified_bool_xpath_node(xpath_node***) { } PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type() const { return (_node || _attribute) ? unspecified_bool_xpath_node : 0; } PUGI__FN bool xpath_node::operator!() const { return !(_node || _attribute); } PUGI__FN bool xpath_node::operator==(const xpath_node& n) const { return _node == n._node && _attribute == n._attribute; } PUGI__FN bool xpath_node::operator!=(const xpath_node& n) const { return _node != n._node || _attribute != n._attribute; } #ifdef __BORLANDC__ PUGI__FN bool operator&&(const xpath_node& lhs, bool rhs) { return (bool)lhs && rhs; } PUGI__FN bool operator||(const xpath_node& lhs, bool rhs) { return (bool)lhs || rhs; } #endif PUGI__FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_) { assert(begin_ <= end_); size_t size_ = static_cast(end_ - begin_); if (size_ <= 1) { // deallocate old buffer if (_begin != &_storage) impl::xml_memory::deallocate(_begin); // use internal buffer if (begin_ != end_) _storage = *begin_; _begin = &_storage; _end = &_storage + size_; } else { // make heap copy xpath_node* storage = static_cast(impl::xml_memory::allocate(size_ * sizeof(xpath_node))); if (!storage) { #ifdef PUGIXML_NO_EXCEPTIONS return; #else throw std::bad_alloc(); #endif } memcpy(storage, begin_, size_ * sizeof(xpath_node)); // deallocate old buffer if (_begin != &_storage) impl::xml_memory::deallocate(_begin); // finalize _begin = storage; _end = storage + size_; } } PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(&_storage), _end(&_storage) { } PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_), _begin(&_storage), _end(&_storage) { _assign(begin_, end_); } PUGI__FN xpath_node_set::~xpath_node_set() { if (_begin != &_storage) impl::xml_memory::deallocate(_begin); } PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(ns._type), _begin(&_storage), _end(&_storage) { _assign(ns._begin, ns._end); } PUGI__FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns) { if (this == &ns) return *this; _type = ns._type; _assign(ns._begin, ns._end); return *this; } PUGI__FN xpath_node_set::type_t xpath_node_set::type() const { return _type; } PUGI__FN size_t xpath_node_set::size() const { return _end - _begin; } PUGI__FN bool xpath_node_set::empty() const { return _begin == _end; } PUGI__FN const xpath_node& xpath_node_set::operator[](size_t index) const { assert(index < size()); return _begin[index]; } PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin() const { return _begin; } PUGI__FN xpath_node_set::const_iterator xpath_node_set::end() const { return _end; } PUGI__FN void xpath_node_set::sort(bool reverse) { _type = impl::xpath_sort(_begin, _end, _type, reverse); } PUGI__FN xpath_node xpath_node_set::first() const { return impl::xpath_first(_begin, _end, _type); } PUGI__FN xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0) { } PUGI__FN xpath_parse_result::operator bool() const { return error == 0; } PUGI__FN const char* xpath_parse_result::description() const { return error ? error : "No error"; } PUGI__FN xpath_variable::xpath_variable(): _type(xpath_type_none), _next(0) { } PUGI__FN const char_t* xpath_variable::name() const { switch (_type) { case xpath_type_node_set: return static_cast(this)->name; case xpath_type_number: return static_cast(this)->name; case xpath_type_string: return static_cast(this)->name; case xpath_type_boolean: return static_cast(this)->name; default: assert(!"Invalid variable type"); return 0; } } PUGI__FN xpath_value_type xpath_variable::type() const { return _type; } PUGI__FN bool xpath_variable::get_boolean() const { return (_type == xpath_type_boolean) ? static_cast(this)->value : false; } PUGI__FN double xpath_variable::get_number() const { return (_type == xpath_type_number) ? static_cast(this)->value : impl::gen_nan(); } PUGI__FN const char_t* xpath_variable::get_string() const { const char_t* value = (_type == xpath_type_string) ? static_cast(this)->value : 0; return value ? value : PUGIXML_TEXT(""); } PUGI__FN const xpath_node_set& xpath_variable::get_node_set() const { return (_type == xpath_type_node_set) ? static_cast(this)->value : impl::dummy_node_set; } PUGI__FN bool xpath_variable::set(bool value) { if (_type != xpath_type_boolean) return false; static_cast(this)->value = value; return true; } PUGI__FN bool xpath_variable::set(double value) { if (_type != xpath_type_number) return false; static_cast(this)->value = value; return true; } PUGI__FN bool xpath_variable::set(const char_t* value) { if (_type != xpath_type_string) return false; impl::xpath_variable_string* var = static_cast(this); // duplicate string size_t size = (impl::strlength(value) + 1) * sizeof(char_t); char_t* copy = static_cast(impl::xml_memory::allocate(size)); if (!copy) return false; memcpy(copy, value, size); // replace old string if (var->value) impl::xml_memory::deallocate(var->value); var->value = copy; return true; } PUGI__FN bool xpath_variable::set(const xpath_node_set& value) { if (_type != xpath_type_node_set) return false; static_cast(this)->value = value; return true; } PUGI__FN xpath_variable_set::xpath_variable_set() { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _data[i] = 0; } PUGI__FN xpath_variable_set::~xpath_variable_set() { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) { xpath_variable* var = _data[i]; while (var) { xpath_variable* next = var->_next; impl::delete_xpath_variable(var->_type, var); var = next; } } } PUGI__FN xpath_variable* xpath_variable_set::find(const char_t* name) const { const size_t hash_size = sizeof(_data) / sizeof(_data[0]); size_t hash = impl::hash_string(name) % hash_size; // look for existing variable for (xpath_variable* var = _data[hash]; var; var = var->_next) if (impl::strequal(var->name(), name)) return var; return 0; } PUGI__FN xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type) { const size_t hash_size = sizeof(_data) / sizeof(_data[0]); size_t hash = impl::hash_string(name) % hash_size; // look for existing variable for (xpath_variable* var = _data[hash]; var; var = var->_next) if (impl::strequal(var->name(), name)) return var->type() == type ? var : 0; // add new variable xpath_variable* result = impl::new_xpath_variable(type, name); if (result) { result->_type = type; result->_next = _data[hash]; _data[hash] = result; } return result; } PUGI__FN bool xpath_variable_set::set(const char_t* name, bool value) { xpath_variable* var = add(name, xpath_type_boolean); return var ? var->set(value) : false; } PUGI__FN bool xpath_variable_set::set(const char_t* name, double value) { xpath_variable* var = add(name, xpath_type_number); return var ? var->set(value) : false; } PUGI__FN bool xpath_variable_set::set(const char_t* name, const char_t* value) { xpath_variable* var = add(name, xpath_type_string); return var ? var->set(value) : false; } PUGI__FN bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value) { xpath_variable* var = add(name, xpath_type_node_set); return var ? var->set(value) : false; } PUGI__FN xpath_variable* xpath_variable_set::get(const char_t* name) { return find(name); } PUGI__FN const xpath_variable* xpath_variable_set::get(const char_t* name) const { return find(name); } PUGI__FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0) { impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create(); if (!qimpl) { #ifdef PUGIXML_NO_EXCEPTIONS _result.error = "Out of memory"; #else throw std::bad_alloc(); #endif } else { impl::buffer_holder impl_holder(qimpl, impl::xpath_query_impl::destroy); qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result); if (qimpl->root) { qimpl->root->optimize(&qimpl->alloc); _impl = static_cast(impl_holder.release()); _result.error = 0; } } } PUGI__FN xpath_query::~xpath_query() { impl::xpath_query_impl::destroy(_impl); } PUGI__FN xpath_value_type xpath_query::return_type() const { if (!_impl) return xpath_type_none; return static_cast(_impl)->root->rettype(); } PUGI__FN bool xpath_query::evaluate_boolean(const xpath_node& n) const { if (!_impl) return false; impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; #ifdef PUGIXML_NO_EXCEPTIONS if (setjmp(sd.error_handler)) return false; #endif return static_cast(_impl)->root->eval_boolean(c, sd.stack); } PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const { if (!_impl) return impl::gen_nan(); impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; #ifdef PUGIXML_NO_EXCEPTIONS if (setjmp(sd.error_handler)) return impl::gen_nan(); #endif return static_cast(_impl)->root->eval_number(c, sd.stack); } #ifndef PUGIXML_NO_STL PUGI__FN string_t xpath_query::evaluate_string(const xpath_node& n) const { impl::xpath_stack_data sd; impl::xpath_string r = impl::evaluate_string_impl(static_cast(_impl), n, sd); return string_t(r.c_str(), r.length()); } #endif PUGI__FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const { impl::xpath_stack_data sd; impl::xpath_string r = impl::evaluate_string_impl(static_cast(_impl), n, sd); size_t full_size = r.length() + 1; if (capacity > 0) { size_t size = (full_size < capacity) ? full_size : capacity; assert(size > 0); memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t)); buffer[size - 1] = 0; } return full_size; } PUGI__FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const { impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast(_impl)); if (!root) return xpath_node_set(); impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; #ifdef PUGIXML_NO_EXCEPTIONS if (setjmp(sd.error_handler)) return xpath_node_set(); #endif impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_all); return xpath_node_set(r.begin(), r.end(), r.type()); } PUGI__FN xpath_node xpath_query::evaluate_node(const xpath_node& n) const { impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast(_impl)); if (!root) return xpath_node(); impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; #ifdef PUGIXML_NO_EXCEPTIONS if (setjmp(sd.error_handler)) return xpath_node(); #endif impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_first); return r.first(); } PUGI__FN const xpath_parse_result& xpath_query::result() const { return _result; } PUGI__FN static void unspecified_bool_xpath_query(xpath_query***) { } PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type() const { return _impl ? unspecified_bool_xpath_query : 0; } PUGI__FN bool xpath_query::operator!() const { return !_impl; } PUGI__FN xpath_node xml_node::select_node(const char_t* query, xpath_variable_set* variables) const { xpath_query q(query, variables); return select_node(q); } PUGI__FN xpath_node xml_node::select_node(const xpath_query& query) const { return query.evaluate_node(*this); } PUGI__FN xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const { xpath_query q(query, variables); return select_nodes(q); } PUGI__FN xpath_node_set xml_node::select_nodes(const xpath_query& query) const { return query.evaluate_node_set(*this); } PUGI__FN xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const { xpath_query q(query, variables); return select_single_node(q); } PUGI__FN xpath_node xml_node::select_single_node(const xpath_query& query) const { return query.evaluate_node(*this); } } #endif #ifdef __BORLANDC__ # pragma option pop #endif // Intel C++ does not properly keep warning state for function templates, // so popping warning state at the end of translation unit leads to warnings in the middle. #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) # pragma warning(pop) #endif // Undefine all local macros (makes sure we're not leaking macros in header-only mode) #undef PUGI__NO_INLINE #undef PUGI__UNLIKELY #undef PUGI__STATIC_ASSERT #undef PUGI__DMC_VOLATILE #undef PUGI__MSVC_CRT_VERSION #undef PUGI__NS_BEGIN #undef PUGI__NS_END #undef PUGI__FN #undef PUGI__FN_NO_INLINE #undef PUGI__NODETYPE #undef PUGI__IS_CHARTYPE_IMPL #undef PUGI__IS_CHARTYPE #undef PUGI__IS_CHARTYPEX #undef PUGI__ENDSWITH #undef PUGI__SKIPWS #undef PUGI__OPTSET #undef PUGI__PUSHNODE #undef PUGI__POPNODE #undef PUGI__SCANFOR #undef PUGI__SCANWHILE #undef PUGI__SCANWHILE_UNROLL #undef PUGI__ENDSEG #undef PUGI__THROW_ERROR #undef PUGI__CHECK_ERROR #endif /* * Copyright (c) 2006-2015 Arseny Kapoulkine * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ ================================================ FILE: CodeTool/Src/pugixml/pugixml.hpp ================================================ /* * pugixml parser - version 1.6 * -------------------------------------------------------- * Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at http://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end * of this file. * * This work is based on the pugxml parser, which is: * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) */ #ifndef PUGIXML_VERSION // Define version macro; evaluates to major * 100 + minor so that it's safe to use in less-than comparisons # define PUGIXML_VERSION 160 #endif // Include user configuration file (this can define various configuration macros) #include "pugiconfig.hpp" #ifndef HEADER_PUGIXML_HPP #define HEADER_PUGIXML_HPP // Include stddef.h for size_t and ptrdiff_t #include // Include exception header for XPath #if !defined(PUGIXML_NO_XPATH) && !defined(PUGIXML_NO_EXCEPTIONS) # include #endif // Include STL headers #ifndef PUGIXML_NO_STL # include # include # include #endif // Macro for deprecated features #ifndef PUGIXML_DEPRECATED # if defined(__GNUC__) # define PUGIXML_DEPRECATED __attribute__((deprecated)) # elif defined(_MSC_VER) && _MSC_VER >= 1300 # define PUGIXML_DEPRECATED __declspec(deprecated) # else # define PUGIXML_DEPRECATED # endif #endif // If no API is defined, assume default #ifndef PUGIXML_API # define PUGIXML_API #endif // If no API for classes is defined, assume default #ifndef PUGIXML_CLASS # define PUGIXML_CLASS PUGIXML_API #endif // If no API for functions is defined, assume default #ifndef PUGIXML_FUNCTION # define PUGIXML_FUNCTION PUGIXML_API #endif // If the platform is known to have long long support, enable long long functions #ifndef PUGIXML_HAS_LONG_LONG # if defined(__cplusplus) && __cplusplus >= 201103 # define PUGIXML_HAS_LONG_LONG # elif defined(_MSC_VER) && _MSC_VER >= 1400 # define PUGIXML_HAS_LONG_LONG # endif #endif // Character interface macros #ifdef PUGIXML_WCHAR_MODE # define PUGIXML_TEXT(t) L ## t # define PUGIXML_CHAR wchar_t #else # define PUGIXML_TEXT(t) t # define PUGIXML_CHAR char #endif namespace pugi { // Character type used for all internal storage and operations; depends on PUGIXML_WCHAR_MODE typedef PUGIXML_CHAR char_t; #ifndef PUGIXML_NO_STL // String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE typedef std::basic_string, std::allocator > string_t; #endif } // The PugiXML namespace namespace pugi { // Tree node types enum xml_node_type { node_null, // Empty (null) node handle node_document, // A document tree's absolute root node_element, // Element tag, i.e. '' node_pcdata, // Plain character data, i.e. 'text' node_cdata, // Character data, i.e. '' node_comment, // Comment tag, i.e. '' node_pi, // Processing instruction, i.e. '' node_declaration, // Document declaration, i.e. '' node_doctype // Document type declaration, i.e. '' }; // Parsing options // Minimal parsing mode (equivalent to turning all other flags off). // Only elements and PCDATA sections are added to the DOM tree, no text conversions are performed. const unsigned int parse_minimal = 0x0000; // This flag determines if processing instructions (node_pi) are added to the DOM tree. This flag is off by default. const unsigned int parse_pi = 0x0001; // This flag determines if comments (node_comment) are added to the DOM tree. This flag is off by default. const unsigned int parse_comments = 0x0002; // This flag determines if CDATA sections (node_cdata) are added to the DOM tree. This flag is on by default. const unsigned int parse_cdata = 0x0004; // This flag determines if plain character data (node_pcdata) that consist only of whitespace are added to the DOM tree. // This flag is off by default; turning it on usually results in slower parsing and more memory consumption. const unsigned int parse_ws_pcdata = 0x0008; // This flag determines if character and entity references are expanded during parsing. This flag is on by default. const unsigned int parse_escapes = 0x0010; // This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default. const unsigned int parse_eol = 0x0020; // This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default. const unsigned int parse_wconv_attribute = 0x0040; // This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default. const unsigned int parse_wnorm_attribute = 0x0080; // This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default. const unsigned int parse_declaration = 0x0100; // This flag determines if document type declaration (node_doctype) is added to the DOM tree. This flag is off by default. const unsigned int parse_doctype = 0x0200; // This flag determines if plain character data (node_pcdata) that is the only child of the parent node and that consists only // of whitespace is added to the DOM tree. // This flag is off by default; turning it on may result in slower parsing and more memory consumption. const unsigned int parse_ws_pcdata_single = 0x0400; // This flag determines if leading and trailing whitespace is to be removed from plain character data. This flag is off by default. const unsigned int parse_trim_pcdata = 0x0800; // This flag determines if plain character data that does not have a parent node is added to the DOM tree, and if an empty document // is a valid document. This flag is off by default. const unsigned int parse_fragment = 0x1000; // The default parsing mode. // Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded, // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. const unsigned int parse_default = parse_cdata | parse_escapes | parse_wconv_attribute | parse_eol; // The full parsing mode. // Nodes of all types are added to the DOM tree, character/reference entities are expanded, // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. const unsigned int parse_full = parse_default | parse_pi | parse_comments | parse_declaration | parse_doctype; // These flags determine the encoding of input data for XML document enum xml_encoding { encoding_auto, // Auto-detect input encoding using BOM or < / class xml_object_range { public: typedef It const_iterator; typedef It iterator; xml_object_range(It b, It e): _begin(b), _end(e) { } It begin() const { return _begin; } It end() const { return _end; } private: It _begin, _end; }; // Writer interface for node printing (see xml_node::print) class PUGIXML_CLASS xml_writer { public: virtual ~xml_writer() {} // Write memory chunk into stream/file/whatever virtual void write(const void* data, size_t size) = 0; }; // xml_writer implementation for FILE* class PUGIXML_CLASS xml_writer_file: public xml_writer { public: // Construct writer from a FILE* object; void* is used to avoid header dependencies on stdio xml_writer_file(void* file); virtual void write(const void* data, size_t size); private: void* file; }; #ifndef PUGIXML_NO_STL // xml_writer implementation for streams class PUGIXML_CLASS xml_writer_stream: public xml_writer { public: // Construct writer from an output stream object xml_writer_stream(std::basic_ostream >& stream); xml_writer_stream(std::basic_ostream >& stream); virtual void write(const void* data, size_t size); private: std::basic_ostream >* narrow_stream; std::basic_ostream >* wide_stream; }; #endif // A light-weight handle for manipulating attributes in DOM tree class PUGIXML_CLASS xml_attribute { friend class xml_attribute_iterator; friend class xml_node; private: xml_attribute_struct* _attr; typedef void (*unspecified_bool_type)(xml_attribute***); public: // Default constructor. Constructs an empty attribute. xml_attribute(); // Constructs attribute from internal pointer explicit xml_attribute(xml_attribute_struct* attr); // Safe bool conversion operator operator unspecified_bool_type() const; // Borland C++ workaround bool operator!() const; // Comparison operators (compares wrapped attribute pointers) bool operator==(const xml_attribute& r) const; bool operator!=(const xml_attribute& r) const; bool operator<(const xml_attribute& r) const; bool operator>(const xml_attribute& r) const; bool operator<=(const xml_attribute& r) const; bool operator>=(const xml_attribute& r) const; // Check if attribute is empty bool empty() const; // Get attribute name/value, or "" if attribute is empty const char_t* name() const; const char_t* value() const; // Get attribute value, or the default value if attribute is empty const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; // Get attribute value as a number, or the default value if conversion did not succeed or attribute is empty int as_int(int def = 0) const; unsigned int as_uint(unsigned int def = 0) const; double as_double(double def = 0) const; float as_float(float def = 0) const; #ifdef PUGIXML_HAS_LONG_LONG long long as_llong(long long def = 0) const; unsigned long long as_ullong(unsigned long long def = 0) const; #endif // Get attribute value as bool (returns true if first character is in '1tTyY' set), or the default value if attribute is empty bool as_bool(bool def = false) const; // Set attribute name/value (returns false if attribute is empty or there is not enough memory) bool set_name(const char_t* rhs); bool set_value(const char_t* rhs); // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set_value(int rhs); bool set_value(unsigned int rhs); bool set_value(double rhs); bool set_value(float rhs); bool set_value(bool rhs); #ifdef PUGIXML_HAS_LONG_LONG bool set_value(long long rhs); bool set_value(unsigned long long rhs); #endif // Set attribute value (equivalent to set_value without error checking) xml_attribute& operator=(const char_t* rhs); xml_attribute& operator=(int rhs); xml_attribute& operator=(unsigned int rhs); xml_attribute& operator=(double rhs); xml_attribute& operator=(float rhs); xml_attribute& operator=(bool rhs); #ifdef PUGIXML_HAS_LONG_LONG xml_attribute& operator=(long long rhs); xml_attribute& operator=(unsigned long long rhs); #endif // Get next/previous attribute in the attribute list of the parent node xml_attribute next_attribute() const; xml_attribute previous_attribute() const; // Get hash value (unique for handles to the same object) size_t hash_value() const; // Get internal pointer xml_attribute_struct* internal_object() const; }; #ifdef __BORLANDC__ // Borland C++ workaround bool PUGIXML_FUNCTION operator&&(const xml_attribute& lhs, bool rhs); bool PUGIXML_FUNCTION operator||(const xml_attribute& lhs, bool rhs); #endif // A light-weight handle for manipulating nodes in DOM tree class PUGIXML_CLASS xml_node { friend class xml_attribute_iterator; friend class xml_node_iterator; friend class xml_named_node_iterator; protected: xml_node_struct* _root; typedef void (*unspecified_bool_type)(xml_node***); public: // Default constructor. Constructs an empty node. xml_node(); // Constructs node from internal pointer explicit xml_node(xml_node_struct* p); // Safe bool conversion operator operator unspecified_bool_type() const; // Borland C++ workaround bool operator!() const; // Comparison operators (compares wrapped node pointers) bool operator==(const xml_node& r) const; bool operator!=(const xml_node& r) const; bool operator<(const xml_node& r) const; bool operator>(const xml_node& r) const; bool operator<=(const xml_node& r) const; bool operator>=(const xml_node& r) const; // Check if node is empty. bool empty() const; // Get node type xml_node_type type() const; // Get node name, or "" if node is empty or it has no name const char_t* name() const; // Get node value, or "" if node is empty or it has no value // Note: For text node.value() does not return "text"! Use child_value() or text() methods to access text inside nodes. const char_t* value() const; // Get attribute list xml_attribute first_attribute() const; xml_attribute last_attribute() const; // Get children list xml_node first_child() const; xml_node last_child() const; // Get next/previous sibling in the children list of the parent node xml_node next_sibling() const; xml_node previous_sibling() const; // Get parent node xml_node parent() const; // Get root of DOM tree this node belongs to xml_node root() const; // Get text object for the current node xml_text text() const; // Get child, attribute or next/previous sibling with the specified name xml_node child(const char_t* name) const; xml_attribute attribute(const char_t* name) const; xml_node next_sibling(const char_t* name) const; xml_node previous_sibling(const char_t* name) const; // Get child value of current node; that is, value of the first child node of type PCDATA/CDATA const char_t* child_value() const; // Get child value of child with specified name. Equivalent to child(name).child_value(). const char_t* child_value(const char_t* name) const; // Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value) bool set_name(const char_t* rhs); bool set_value(const char_t* rhs); // Add attribute with specified name. Returns added attribute, or empty attribute on errors. xml_attribute append_attribute(const char_t* name); xml_attribute prepend_attribute(const char_t* name); xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr); xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr); // Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors. xml_attribute append_copy(const xml_attribute& proto); xml_attribute prepend_copy(const xml_attribute& proto); xml_attribute insert_copy_after(const xml_attribute& proto, const xml_attribute& attr); xml_attribute insert_copy_before(const xml_attribute& proto, const xml_attribute& attr); // Add child node with specified type. Returns added node, or empty node on errors. xml_node append_child(xml_node_type type = node_element); xml_node prepend_child(xml_node_type type = node_element); xml_node insert_child_after(xml_node_type type, const xml_node& node); xml_node insert_child_before(xml_node_type type, const xml_node& node); // Add child element with specified name. Returns added node, or empty node on errors. xml_node append_child(const char_t* name); xml_node prepend_child(const char_t* name); xml_node insert_child_after(const char_t* name, const xml_node& node); xml_node insert_child_before(const char_t* name, const xml_node& node); // Add a copy of the specified node as a child. Returns added node, or empty node on errors. xml_node append_copy(const xml_node& proto); xml_node prepend_copy(const xml_node& proto); xml_node insert_copy_after(const xml_node& proto, const xml_node& node); xml_node insert_copy_before(const xml_node& proto, const xml_node& node); // Move the specified node to become a child of this node. Returns moved node, or empty node on errors. xml_node append_move(const xml_node& moved); xml_node prepend_move(const xml_node& moved); xml_node insert_move_after(const xml_node& moved, const xml_node& node); xml_node insert_move_before(const xml_node& moved, const xml_node& node); // Remove specified attribute bool remove_attribute(const xml_attribute& a); bool remove_attribute(const char_t* name); // Remove specified child bool remove_child(const xml_node& n); bool remove_child(const char_t* name); // Parses buffer as an XML document fragment and appends all nodes as children of the current node. // Copies/converts the buffer, so it may be deleted or changed after the function returns. // Note: append_buffer allocates memory that has the lifetime of the owning document; removing the appended nodes does not immediately reclaim that memory. xml_parse_result append_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); // Find attribute using predicate. Returns first attribute for which predicate returned true. template xml_attribute find_attribute(Predicate pred) const { if (!_root) return xml_attribute(); for (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute()) if (pred(attrib)) return attrib; return xml_attribute(); } // Find child node using predicate. Returns first child for which predicate returned true. template xml_node find_child(Predicate pred) const { if (!_root) return xml_node(); for (xml_node node = first_child(); node; node = node.next_sibling()) if (pred(node)) return node; return xml_node(); } // Find node from subtree using predicate. Returns first node from subtree (depth-first), for which predicate returned true. template xml_node find_node(Predicate pred) const { if (!_root) return xml_node(); xml_node cur = first_child(); while (cur._root && cur._root != _root) { if (pred(cur)) return cur; if (cur.first_child()) cur = cur.first_child(); else if (cur.next_sibling()) cur = cur.next_sibling(); else { while (!cur.next_sibling() && cur._root != _root) cur = cur.parent(); if (cur._root != _root) cur = cur.next_sibling(); } } return xml_node(); } // Find child node by attribute name/value xml_node find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const; xml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const; #ifndef PUGIXML_NO_STL // Get the absolute node path from root as a text string. string_t path(char_t delimiter = '/') const; #endif // Search for a node by path consisting of node names and . or .. elements. xml_node first_element_by_path(const char_t* path, char_t delimiter = '/') const; // Recursively traverse subtree with xml_tree_walker bool traverse(xml_tree_walker& walker); #ifndef PUGIXML_NO_XPATH // Select single node by evaluating XPath query. Returns first node from the resulting node set. xpath_node select_node(const char_t* query, xpath_variable_set* variables = 0) const; xpath_node select_node(const xpath_query& query) const; // Select node set by evaluating XPath query xpath_node_set select_nodes(const char_t* query, xpath_variable_set* variables = 0) const; xpath_node_set select_nodes(const xpath_query& query) const; // (deprecated: use select_node instead) Select single node by evaluating XPath query. xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const; xpath_node select_single_node(const xpath_query& query) const; #endif // Print subtree using a writer object void print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; #ifndef PUGIXML_NO_STL // Print subtree to stream void print(std::basic_ostream >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; void print(std::basic_ostream >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, unsigned int depth = 0) const; #endif // Child nodes iterators typedef xml_node_iterator iterator; iterator begin() const; iterator end() const; // Attribute iterators typedef xml_attribute_iterator attribute_iterator; attribute_iterator attributes_begin() const; attribute_iterator attributes_end() const; // Range-based for support xml_object_range children() const; xml_object_range children(const char_t* name) const; xml_object_range attributes() const; // Get node offset in parsed file/string (in char_t units) for debugging purposes ptrdiff_t offset_debug() const; // Get hash value (unique for handles to the same object) size_t hash_value() const; // Get internal pointer xml_node_struct* internal_object() const; }; #ifdef __BORLANDC__ // Borland C++ workaround bool PUGIXML_FUNCTION operator&&(const xml_node& lhs, bool rhs); bool PUGIXML_FUNCTION operator||(const xml_node& lhs, bool rhs); #endif // A helper for working with text inside PCDATA nodes class PUGIXML_CLASS xml_text { friend class xml_node; xml_node_struct* _root; typedef void (*unspecified_bool_type)(xml_text***); explicit xml_text(xml_node_struct* root); xml_node_struct* _data_new(); xml_node_struct* _data() const; public: // Default constructor. Constructs an empty object. xml_text(); // Safe bool conversion operator operator unspecified_bool_type() const; // Borland C++ workaround bool operator!() const; // Check if text object is empty bool empty() const; // Get text, or "" if object is empty const char_t* get() const; // Get text, or the default value if object is empty const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; // Get text as a number, or the default value if conversion did not succeed or object is empty int as_int(int def = 0) const; unsigned int as_uint(unsigned int def = 0) const; double as_double(double def = 0) const; float as_float(float def = 0) const; #ifdef PUGIXML_HAS_LONG_LONG long long as_llong(long long def = 0) const; unsigned long long as_ullong(unsigned long long def = 0) const; #endif // Get text as bool (returns true if first character is in '1tTyY' set), or the default value if object is empty bool as_bool(bool def = false) const; // Set text (returns false if object is empty or there is not enough memory) bool set(const char_t* rhs); // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set(int rhs); bool set(unsigned int rhs); bool set(double rhs); bool set(float rhs); bool set(bool rhs); #ifdef PUGIXML_HAS_LONG_LONG bool set(long long rhs); bool set(unsigned long long rhs); #endif // Set text (equivalent to set without error checking) xml_text& operator=(const char_t* rhs); xml_text& operator=(int rhs); xml_text& operator=(unsigned int rhs); xml_text& operator=(double rhs); xml_text& operator=(float rhs); xml_text& operator=(bool rhs); #ifdef PUGIXML_HAS_LONG_LONG xml_text& operator=(long long rhs); xml_text& operator=(unsigned long long rhs); #endif // Get the data node (node_pcdata or node_cdata) for this object xml_node data() const; }; #ifdef __BORLANDC__ // Borland C++ workaround bool PUGIXML_FUNCTION operator&&(const xml_text& lhs, bool rhs); bool PUGIXML_FUNCTION operator||(const xml_text& lhs, bool rhs); #endif // Child node iterator (a bidirectional iterator over a collection of xml_node) class PUGIXML_CLASS xml_node_iterator { friend class xml_node; private: mutable xml_node _wrap; xml_node _parent; xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent); public: // Iterator traits typedef ptrdiff_t difference_type; typedef xml_node value_type; typedef xml_node* pointer; typedef xml_node& reference; #ifndef PUGIXML_NO_STL typedef std::bidirectional_iterator_tag iterator_category; #endif // Default constructor xml_node_iterator(); // Construct an iterator which points to the specified node xml_node_iterator(const xml_node& node); // Iterator operators bool operator==(const xml_node_iterator& rhs) const; bool operator!=(const xml_node_iterator& rhs) const; xml_node& operator*() const; xml_node* operator->() const; const xml_node_iterator& operator++(); xml_node_iterator operator++(int); const xml_node_iterator& operator--(); xml_node_iterator operator--(int); }; // Attribute iterator (a bidirectional iterator over a collection of xml_attribute) class PUGIXML_CLASS xml_attribute_iterator { friend class xml_node; private: mutable xml_attribute _wrap; xml_node _parent; xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent); public: // Iterator traits typedef ptrdiff_t difference_type; typedef xml_attribute value_type; typedef xml_attribute* pointer; typedef xml_attribute& reference; #ifndef PUGIXML_NO_STL typedef std::bidirectional_iterator_tag iterator_category; #endif // Default constructor xml_attribute_iterator(); // Construct an iterator which points to the specified attribute xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent); // Iterator operators bool operator==(const xml_attribute_iterator& rhs) const; bool operator!=(const xml_attribute_iterator& rhs) const; xml_attribute& operator*() const; xml_attribute* operator->() const; const xml_attribute_iterator& operator++(); xml_attribute_iterator operator++(int); const xml_attribute_iterator& operator--(); xml_attribute_iterator operator--(int); }; // Named node range helper class PUGIXML_CLASS xml_named_node_iterator { friend class xml_node; public: // Iterator traits typedef ptrdiff_t difference_type; typedef xml_node value_type; typedef xml_node* pointer; typedef xml_node& reference; #ifndef PUGIXML_NO_STL typedef std::bidirectional_iterator_tag iterator_category; #endif // Default constructor xml_named_node_iterator(); // Construct an iterator which points to the specified node xml_named_node_iterator(const xml_node& node, const char_t* name); // Iterator operators bool operator==(const xml_named_node_iterator& rhs) const; bool operator!=(const xml_named_node_iterator& rhs) const; xml_node& operator*() const; xml_node* operator->() const; const xml_named_node_iterator& operator++(); xml_named_node_iterator operator++(int); const xml_named_node_iterator& operator--(); xml_named_node_iterator operator--(int); private: mutable xml_node _wrap; xml_node _parent; const char_t* _name; xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name); }; // Abstract tree walker class (see xml_node::traverse) class PUGIXML_CLASS xml_tree_walker { friend class xml_node; private: int _depth; protected: // Get current traversal depth int depth() const; public: xml_tree_walker(); virtual ~xml_tree_walker(); // Callback that is called when traversal begins virtual bool begin(xml_node& node); // Callback that is called for each node traversed virtual bool for_each(xml_node& node) = 0; // Callback that is called when traversal ends virtual bool end(xml_node& node); }; // Parsing status, returned as part of xml_parse_result object enum xml_parse_status { status_ok = 0, // No error status_file_not_found, // File was not found during load_file() status_io_error, // Error reading from file/stream status_out_of_memory, // Could not allocate memory status_internal_error, // Internal error occurred status_unrecognized_tag, // Parser could not determine tag type status_bad_pi, // Parsing error occurred while parsing document declaration/processing instruction status_bad_comment, // Parsing error occurred while parsing comment status_bad_cdata, // Parsing error occurred while parsing CDATA section status_bad_doctype, // Parsing error occurred while parsing document type declaration status_bad_pcdata, // Parsing error occurred while parsing PCDATA section status_bad_start_element, // Parsing error occurred while parsing start element tag status_bad_attribute, // Parsing error occurred while parsing element attribute status_bad_end_element, // Parsing error occurred while parsing end element tag status_end_element_mismatch,// There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag) status_append_invalid_root, // Unable to append nodes since root type is not node_element or node_document (exclusive to xml_node::append_buffer) status_no_document_element // Parsing resulted in a document without element nodes }; // Parsing result struct PUGIXML_CLASS xml_parse_result { // Parsing status (see xml_parse_status) xml_parse_status status; // Last parsed offset (in char_t units from start of input data) ptrdiff_t offset; // Source document encoding xml_encoding encoding; // Default constructor, initializes object to failed state xml_parse_result(); // Cast to bool operator operator bool() const; // Get error description const char* description() const; }; // Document class (DOM tree root) class PUGIXML_CLASS xml_document: public xml_node { private: char_t* _buffer; char _memory[192]; // Non-copyable semantics xml_document(const xml_document&); const xml_document& operator=(const xml_document&); void create(); void destroy(); public: // Default constructor, makes empty document xml_document(); // Destructor, invalidates all node/attribute handles to this document ~xml_document(); // Removes all nodes, leaving the empty document void reset(); // Removes all nodes, then copies the entire contents of the specified document void reset(const xml_document& proto); #ifndef PUGIXML_NO_STL // Load document from stream. xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default); #endif // (deprecated: use load_string instead) Load document from zero-terminated string. No encoding conversions are applied. xml_parse_result load(const char_t* contents, unsigned int options = parse_default); // Load document from zero-terminated string. No encoding conversions are applied. xml_parse_result load_string(const char_t* contents, unsigned int options = parse_default); // Load document from file xml_parse_result load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); xml_parse_result load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); // Load document from buffer. Copies/converts the buffer, so it may be deleted or changed after the function returns. xml_parse_result load_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). // You should ensure that buffer data will persist throughout the document's lifetime, and free the buffer memory manually once document is destroyed. xml_parse_result load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). // You should allocate the buffer with pugixml allocation function; document will free the buffer when it is no longer needed (you can't use it anymore). xml_parse_result load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); // Save XML document to writer (semantics is slightly different from xml_node::print, see documentation for details). void save(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; #ifndef PUGIXML_NO_STL // Save XML document to stream (semantics is slightly different from xml_node::print, see documentation for details). void save(std::basic_ostream >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; void save(std::basic_ostream >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default) const; #endif // Save XML to file bool save_file(const char* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; bool save_file(const wchar_t* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; // Get document element xml_node document_element() const; }; #ifndef PUGIXML_NO_XPATH // XPath query return type enum xpath_value_type { xpath_type_none, // Unknown type (query failed to compile) xpath_type_node_set, // Node set (xpath_node_set) xpath_type_number, // Number xpath_type_string, // String xpath_type_boolean // Boolean }; // XPath parsing result struct PUGIXML_CLASS xpath_parse_result { // Error message (0 if no error) const char* error; // Last parsed offset (in char_t units from string start) ptrdiff_t offset; // Default constructor, initializes object to failed state xpath_parse_result(); // Cast to bool operator operator bool() const; // Get error description const char* description() const; }; // A single XPath variable class PUGIXML_CLASS xpath_variable { friend class xpath_variable_set; protected: xpath_value_type _type; xpath_variable* _next; xpath_variable(); // Non-copyable semantics xpath_variable(const xpath_variable&); xpath_variable& operator=(const xpath_variable&); public: // Get variable name const char_t* name() const; // Get variable type xpath_value_type type() const; // Get variable value; no type conversion is performed, default value (false, NaN, empty string, empty node set) is returned on type mismatch error bool get_boolean() const; double get_number() const; const char_t* get_string() const; const xpath_node_set& get_node_set() const; // Set variable value; no type conversion is performed, false is returned on type mismatch error bool set(bool value); bool set(double value); bool set(const char_t* value); bool set(const xpath_node_set& value); }; // A set of XPath variables class PUGIXML_CLASS xpath_variable_set { private: xpath_variable* _data[64]; // Non-copyable semantics xpath_variable_set(const xpath_variable_set&); xpath_variable_set& operator=(const xpath_variable_set&); xpath_variable* find(const char_t* name) const; public: // Default constructor/destructor xpath_variable_set(); ~xpath_variable_set(); // Add a new variable or get the existing one, if the types match xpath_variable* add(const char_t* name, xpath_value_type type); // Set value of an existing variable; no type conversion is performed, false is returned if there is no such variable or if types mismatch bool set(const char_t* name, bool value); bool set(const char_t* name, double value); bool set(const char_t* name, const char_t* value); bool set(const char_t* name, const xpath_node_set& value); // Get existing variable by name xpath_variable* get(const char_t* name); const xpath_variable* get(const char_t* name) const; }; // A compiled XPath query object class PUGIXML_CLASS xpath_query { private: void* _impl; xpath_parse_result _result; typedef void (*unspecified_bool_type)(xpath_query***); // Non-copyable semantics xpath_query(const xpath_query&); xpath_query& operator=(const xpath_query&); public: // Construct a compiled object from XPath expression. // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on compilation errors. explicit xpath_query(const char_t* query, xpath_variable_set* variables = 0); // Destructor ~xpath_query(); // Get query expression return type xpath_value_type return_type() const; // Evaluate expression as boolean value in the specified context; performs type conversion if necessary. // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. bool evaluate_boolean(const xpath_node& n) const; // Evaluate expression as double value in the specified context; performs type conversion if necessary. // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. double evaluate_number(const xpath_node& n) const; #ifndef PUGIXML_NO_STL // Evaluate expression as string value in the specified context; performs type conversion if necessary. // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. string_t evaluate_string(const xpath_node& n) const; #endif // Evaluate expression as string value in the specified context; performs type conversion if necessary. // At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero). // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. // If PUGIXML_NO_EXCEPTIONS is defined, returns empty set instead. size_t evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const; // Evaluate expression as node set in the specified context. // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors. // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node set instead. xpath_node_set evaluate_node_set(const xpath_node& n) const; // Evaluate expression as node set in the specified context. // Return first node in document order, or empty node if node set is empty. // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors. // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node instead. xpath_node evaluate_node(const xpath_node& n) const; // Get parsing result (used to get compilation errors in PUGIXML_NO_EXCEPTIONS mode) const xpath_parse_result& result() const; // Safe bool conversion operator operator unspecified_bool_type() const; // Borland C++ workaround bool operator!() const; }; #ifndef PUGIXML_NO_EXCEPTIONS // XPath exception class class PUGIXML_CLASS xpath_exception: public std::exception { private: xpath_parse_result _result; public: // Construct exception from parse result explicit xpath_exception(const xpath_parse_result& result); // Get error message virtual const char* what() const throw(); // Get parse result const xpath_parse_result& result() const; }; #endif // XPath node class (either xml_node or xml_attribute) class PUGIXML_CLASS xpath_node { private: xml_node _node; xml_attribute _attribute; typedef void (*unspecified_bool_type)(xpath_node***); public: // Default constructor; constructs empty XPath node xpath_node(); // Construct XPath node from XML node/attribute xpath_node(const xml_node& node); xpath_node(const xml_attribute& attribute, const xml_node& parent); // Get node/attribute, if any xml_node node() const; xml_attribute attribute() const; // Get parent of contained node/attribute xml_node parent() const; // Safe bool conversion operator operator unspecified_bool_type() const; // Borland C++ workaround bool operator!() const; // Comparison operators bool operator==(const xpath_node& n) const; bool operator!=(const xpath_node& n) const; }; #ifdef __BORLANDC__ // Borland C++ workaround bool PUGIXML_FUNCTION operator&&(const xpath_node& lhs, bool rhs); bool PUGIXML_FUNCTION operator||(const xpath_node& lhs, bool rhs); #endif // A fixed-size collection of XPath nodes class PUGIXML_CLASS xpath_node_set { public: // Collection type enum type_t { type_unsorted, // Not ordered type_sorted, // Sorted by document order (ascending) type_sorted_reverse // Sorted by document order (descending) }; // Constant iterator type typedef const xpath_node* const_iterator; // We define non-constant iterator to be the same as constant iterator so that various generic algorithms (i.e. boost foreach) work typedef const xpath_node* iterator; // Default constructor. Constructs empty set. xpath_node_set(); // Constructs a set from iterator range; data is not checked for duplicates and is not sorted according to provided type, so be careful xpath_node_set(const_iterator begin, const_iterator end, type_t type = type_unsorted); // Destructor ~xpath_node_set(); // Copy constructor/assignment operator xpath_node_set(const xpath_node_set& ns); xpath_node_set& operator=(const xpath_node_set& ns); // Get collection type type_t type() const; // Get collection size size_t size() const; // Indexing operator const xpath_node& operator[](size_t index) const; // Collection iterators const_iterator begin() const; const_iterator end() const; // Sort the collection in ascending/descending order by document order void sort(bool reverse = false); // Get first node in the collection by document order xpath_node first() const; // Check if collection is empty bool empty() const; private: type_t _type; xpath_node _storage; xpath_node* _begin; xpath_node* _end; void _assign(const_iterator begin, const_iterator end); }; #endif #ifndef PUGIXML_NO_STL // Convert wide string to UTF8 std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const wchar_t* str); std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const std::basic_string, std::allocator >& str); // Convert UTF8 to wide string std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const char* str); std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const std::basic_string, std::allocator >& str); #endif // Memory allocation function interface; returns pointer to allocated memory or NULL on failure typedef void* (*allocation_function)(size_t size); // Memory deallocation function interface typedef void (*deallocation_function)(void* ptr); // Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions. void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate); // Get current memory management functions allocation_function PUGIXML_FUNCTION get_memory_allocation_function(); deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function(); } #if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) namespace std { // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_node_iterator&); std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_attribute_iterator&); std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_named_node_iterator&); } #endif #if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) namespace std { // Workarounds for (non-standard) iterator category detection std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_node_iterator&); std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_attribute_iterator&); std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_named_node_iterator&); } #endif #endif // Make sure implementation is included in header-only mode // Use macro expansion in #include to work around QMake (QTBUG-11923) #if defined(PUGIXML_HEADER_ONLY) && !defined(PUGIXML_SOURCE) # define PUGIXML_SOURCE "pugixml.cpp" # include PUGIXML_SOURCE #endif /* * Copyright (c) 2006-2015 Arseny Kapoulkine * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ ================================================ FILE: CompressToolsConfig.json ================================================ { "formatCommands": [ { "Key": "Windows", "Value": [ { "Key": "DXT5", "Value": "\"../../o2/AssetsBuildTool/Bin/nvcompress.exe\" -nomips -bc3 -alpha \"{input}\" \"{output}.dds\"" } ] }, { "Key": "Linux", "Value": [ { "Key": "DXT5", "Value": "/home/vboxuser/Desktop/NVIDIA_Texture_Tools_Linux_x86_64_3.2.1/nvcompress -nomips -bc3 -alpha \"{input}\" \"{output}.dds\"" } ] } ] } ================================================ FILE: Docs/en/Architecture/architecture.md ================================================ # Engine Architecture The architecture is divided into three layers: - **High-level**: scene, actors, components, UI, editor - **Low-level**: application wrapper, assets, rendering, animations, input, physics, scripting, sound - **Utility**: reflection and serialization, memory management, file system, debugging and logging, math, delegates, properties, data containers, timers The entry point is the application wrapper (`o2::Application`), which provides a cross-platform API for managing the application. It has platform-specific implementations for Windows, macOS, Linux, iOS, Android, and Emscripten (WIP). Some low-level and utility subsystems (rendering, file system, timers) also have platform-specific implementations. All subsystems are implemented as singletons for convenient access. Before the application starts, certain utility systems (such as memory management and reflection) are statically initialized. Then, at startup, an instance of the application is created, which initializes the remaining subsystems, and after that the main game loop begins. The game loop has two phases: update and rendering. Everything takes place inside `o2::Application::ProcessFrame`, where the input system, scene, physics, rendering, etc. are updated. A developer can override the logic of `o2::Application` by inheriting a custom class and implementing the necessary functionality such as initialization, startup, rendering, updates, minimizing, and restoring the application. ## Memory Management [(detailed documentation)](/Docs/en/Architecture/Utils/memory.md) The engine uses its own smart pointers with an external reference counter, but each object internally holds a reference to that counter. This allows converting a “raw” pointer into a smart pointer if the object inherits from `RefCounterable`, which stores a pointer to the counter. A strong reference `Ref<>` is used to manage object lifetime, while `WeakRef<>` does not affect it. Objects for these smart pointers are created only through the `mmake(...)` function, which allocates a single memory block for both the counter and the object, ensuring the counter is always placed before the object (cache-friendly). In debug mode, the engine has a GC that points out potential memory leaks and cyclic references but does not destroy objects itself. It is only used for analysis. The editor includes a tool that displays the memory tree and highlights issues. In addition, there are specialized reference types for serializing unique identifiers: `AssetRef` (for assets) and `LinkRef` (for actors and components).
Example ```C++ class MyObject: public o2::RefCounterable {}; Ref myObjectSample = mmake(...); myObjectSample->DoSmth(); WeakRef myWeakObject = WeakRef(myObjectSample); MyObject* rawObject = myObjectSample.Get(); Ref myObjectSample2 = Ref(rawObject); ```
## Reflection [(detailed documentation)](/Docs/en/Architecture/Utils/reflection.md) Reflection is used to access type structures at runtime (for finding animatable values by a string path, calling callbacks by name, serialization/deserialization, automatic script bindings). It relies on type metadata generated by the **o2CodeTool** utility. This tool parses header files (`.h`), finds C++ classes, analyzes their structure (including inheritance), locates `IObject` descendants, and generates type metadata at the end of the `.h` file. This metadata is stored in a shared repository and built incrementally: the code generator caches parsed files and updates only those that have changed.
Example ```C++ struct MyObject: public o2::IObject { float value = 0.0f; float DoSmth(float arg); IOBJECT(MyObject); }; MyObject myObjectSample; auto& type = TypeOf(MyObject); assert(myObjectSample.GetType() == type); float floatValue = type.GetField("value").GetValue(&myObjectSample); float funcResult = type.Invoke("DoSmth", &myObjectSample, floatValue); ```
## Serialization [(detailed documentation)](/Docs/en/Architecture/Utils/serialization.md) JSON and a binary format (in development) are used for internal data storage. The `o2::DataValue` structure (similar to RapidJSON or PugiXML) stores arrays, tables, or simple values (numbers, strings, booleans, etc.). A `DataValue` can be loaded from a file and then converted into a C++ object, or vice versa — an object can be serialized into `o2::DataValue` and saved. Serialization is performed via reflection, specifically the generated type metadata. A special object writes data to `o2::DataValue`. To be serialized, a class must implement the `o2::ISerializable` interface, and the fields to be serialized must be marked with the `@SERIALIZABLE` attribute. Only these types and fields are serialized, including primitives, containers, and smart pointers.
Example ```C++ class Reel : public ISerializable { public: LinkRef imagesContainer; // @SERIALIZABLE Vector> images; // @SERIALIZABLE Vector> blurredImages; // @SERIALIZABLE float imagesDistance = 100.0f; // @SERIALIZABLE bool disableExtendedSymbols = false; // @SERIALIZABLE SERIALIZABLE(Reel); }; ```
## Properties [(detailed documentation)](/Docs/en/Architecture/Utils/properties.md) Properties allow declaring variables that use getter and setter “under the hood,” making the code more concise. Instead of `object.SetValue(object.GetValue() + 200.0f);`, you can write `object.value += 200.0f;`, similar to properties in C#. To declare properties in a class, first use the `PROPERTIES(class_name)` macro. Then for each property, use the `PROPERTY(type, name, setter, getter)` macro, where `setter` and `getter` are class functions handling read and write operations.
Example ```C++ class MyObject { public: PROPERTIES(MyObject); PROPERTY(float, value, SetValue, GetValue); public: void SetValue(float value); float GetValue() const; }; MyObject object; object.value = object.value + 100.0f; // object.SetValue(object.GetValue() + 100.0f); ```
## Delegates [(detailed documentation)](/Docs/en/Architecture/Utils/function.md) `o2::Function<>` is an analog of `std::function<>` with extended functionality that allows storing multiple delegates simultaneously. This approach simplifies subscription and event systems. For example, in a button class, you can declare `o2::Function onClick;` and add several listeners to it.
Example ```C++ class MyButton { public: Function onClicked; ... }; MyButton button; button.onClicked += []() { ... }; button.onClicked += []() { ... }; button.onClicked += []() { ... }; ```
## Application Wrapper [(detailed documentation)](/Docs/en/Architecture/LowLevel/application.md) As mentioned above, this is the entry point and the main system of the engine. During initialization, it sets up the other subsystems. Then the game loop begins, processed in the `ProcessFrame()` function, where the scene, input, and all other subsystems are updated, and a frame is rendered. The application wrapper also handles system messages (activation, deactivation, etc.). A user can hook into any of these points by overriding special functions in their custom application class.
Example ```C++ class MyApplication: public o2::Application { private: void OnUpdate(float dt) override; void OnDraw() override; void OnActivated() override; void OnDeactivated() override; void OnStarted() override; void OnClosing() override; void OnResizing() override; }; ```
## Assets [(detailed documentation)](/Docs/en/Architecture/LowLevel/assets.md) The engine treats various resources (textures, sounds, text configs, etc.) as assets provided in raw form. For faster loading at runtime, they are pre-built: textures are packed into atlases and compressed, sounds are converted, and configs are turned into binary form. Each asset has a unique `id` stored in a `.meta` file alongside the asset itself. That file may also contain compression info and other data not suitable for the original file. In addition, a tree of assets is built for efficient metadata loading. Assets are processed by the **AssetsBuilder** tool, which detects changed resources and updates their built versions. It runs before the editor starts, during its operation, and when building the final release. The engine provides the `o2::Assets` subsystem (a singleton) accessed from anywhere via the `o2Assets` macro. It loads the asset tree on startup and offers an easy interface to retrieve assets. Smart pointers `o2::AssetRef<>` are used; they serialize, cache the loading process, and automatically unload the asset when no references remain. Assets can be individual files or “embedded” (instance). In the latter case, the asset is stored directly within a scene or a prefab.
Example ```C++ AssetRef image = o2Assets.GetAssetRef(id); sprite.Load(image); ```
## Rendering [(detailed documentation)](/Docs/en/Architecture/LowLevel/render.md) The rendering subsystem is available via the `o2Render` singleton. It can draw triangle meshes with materials (shaders, textures, parameters (WIP)) and uses batching: meshes with identical materials are combined and submitted to the render in a single call. It supports scissor test, stencil masks, and render targets. Above the mesh rendering, there are abstractions: sprites, text, skinned meshes, particle effects, and Spine animations. They all implement `o2::IDrawable`; objects with rectangular dimensions also implement `o2::IRectDrawable`. The parameters of `o2::IRectDrawable` include position, size, rotation, scale, skew, or setting the transform via `o2::Basis`. - **Sprites** support display modes: normal, 9-slice, tiled, progress filled. They have color, transparency, and are loaded from textures. - **Text** works with both bitmap and vector fonts (via FreeType). CPU-based effects (shadow, outline, gradient, etc.) are available, along with formatting and alignment settings. - **Particle systems** are single emitters with a set of effects. Rendering can be a regular sprite or a frame-by-frame animation. Emission parameters are adjustable, and in the editor, the effect can be rewound backward. Rendering also includes camera support (`o2::Camera`), which sets the viewport in the engine’s logical rendering coordinates.
Example ```C++ AssetRef imageAsset = o2Assets.GetAssetRef(id); auto sprite = mmake(imageAsset); ... sprite->position = Vec2F(10, 10); sprite->mode = SpriteMode::FixedAspect; sprite->transparency = 0.5f; ... sprite->Draw(); ```
## Animations [(detailed documentation)](/Docs/en/Architecture/LowLevel/animations.md) The engine has a built-in animation system and Spine integration. Spine animations are loaded from an asset, can be played, mixed, and have skins switched. The built-in format is deeply integrated into the engine and can animate any field, including custom ones. The basic unit is **`o2::AnimationClip`**, which can be saved as an asset (`o2::AnimationAsset`). Clips consist of tracks, each animating one field identified by a string path (e.g., `"myStructure/myFolder/myParameter"`). Tracks contain key frames with a specific value and time. To play a clip, use **`o2::AnimationPlayer`**: it takes an animation clip and a target object. By string paths, reflection finds the required fields. When the time updates, the player interpolates between key frames in the tracks, ensuring smooth animation at any framerate. On the scene, there is an **`o2::AnimationComponent`** that can play multiple animations on an actor simultaneously and blend them by weights. It stores a list of states (clips) and switches among them. Above it, there is **`o2::AnimationStateGraphComponent`** — a state machine for animations. It includes nodes (states) with several clips and transitions defining start time, duration, and easing functions. A developer specifies a target node, and the graph automatically finds a route, applying transitions and blending. This system works with both the built-in and Spine animations. The editor has a special built-in animation editor. [More details](/Docs/en/Editor/Animation/animation.md). Animations can also be constructed from code via the **`o2::Animate`** interface.
Example ```C++ sample->SetHighlightAnimation(Animate(*sample->GetHighlightDrawable()). Hide().Scale(1.5f).Then(). Wait(0.3f).Then(). Show().Scale(1.0f).For(0.2f).Then(). Wait(1.0f).Then(). Hide().For(0.2f)); ```
## Input Handling [(detailed documentation)](/Docs/en/Architecture/LowLevel/input.md) The input system is accessed through the singleton `o2Events`. It provides basic handlers for system events (key presses, cursor position, etc.) and a higher-level logic (clicks, multi-touch). The high-level layer takes rendering scissor and element overlap into account. For handling touch/click (hover, pressed, etc.), inherit from `o2::CursorAreaEventsListener` and implement the required methods (pressed, released, enter, exit, etc.). Two methods are mandatory: 1. Checking if a click is valid (for example, whether the cursor is inside the object bounds). 2. `OnDraw` — called during rendering to record the object’s order and current scissor state. Afterwards, the input system automatically determines which object was clicked and calls the appropriate callbacks.
Example ```C++ class MyInteractiveObject: public o2::CursorAreaEventsListener { public: bool IsUnderPoint(const Vec2F& point) override { return _rectangle.IsInside(point); } void Draw() { sprite.Draw(); o2::CursorAreaEventsListener::OnDrawn(); } private: void OnCursorPressed(const Input::Cursor& cursor) override { o2Debug.Log("Pressed!"); } void OnCursorReleased(const Input::Cursor& cursor) override { o2Debug.Log("Released!"); } }; ... auto object = mmake(); ... object.Draw(); ```
## Scripting [(detailed documentation)](/Docs/en/Architecture/LowLevel/scripting.md) The engine uses **JerryScript** — a compact and performant JavaScript runtime, which also allows using TypeScript if you want static typing. On top of JerryScript, the engine has a wrapper accessible via the `o2Scripts` singleton and a JavaScript-value wrapper `o2::ScriptValue`. - `o2Scripts` can load and run scripts from files or strings and work with the global namespace via `o2::ScriptValue`. - `o2::ScriptValue` represents any JS variable (number, string, boolean, function, array, or object) and provides a convenient interface for handling these types, classes, and prototypes. C++ type binding is done through reflection: at application startup, the engine registers the required classes in the global JavaScript runtime, using the generated type metadata.
Example ```C++ o2Scripts.GetGlobal().SetProperty("myValue", 256); o2Scripts.Eval("print('myValue is ' + myValue)"); ... o2Scripts.Eval("let myObject = new MyObject"); auto myJSObject = o2Scripts.GetGlobal().GetProperty("myObject"); auto myProperty = myJSObject["propName"]; if (myProperty.GetValueType() == o2::ScriptValue::ValueType::Number) { float myPropertyValue = myProperty.ToNumber(); ... } ```
## Physics [(detailed documentation)](/Docs/en/Architecture/LowLevel/physics.md) The engine has Box2D integrated. When the application starts, it initializes the physics world, into which objects can be added via scene primitives. You can configure how the engine’s coordinate units scale to the physics world, solver precision, and collision between layers. The base scene primitive is `o2::RigidBody`. It contains the physical parameters of the body and integrates it into the physics world. Colliders (`o2::ICollider`) such as `BoxCollider` or `CircleCollider` can be attached to it. All physics configuration and management happens through the scene and editor. ## Sound (TBD) Not yet implemented in the engine. ## Scene and Actors [(detailed documentation)](/Docs/en/Architecture/HighLevel/scene.md) Above all subsystems is the scene system, accessed via the `o2Scene` singleton. It stores a list of actors (`o2::Actor`), which have components defining logic and rendering. Actors can belong to different types, such as `o2::Widget` (UI), `o2::RigidBody` (physics), or any user-defined class. A scene can be saved and loaded from an asset, including incremental loading. Logically, there is only one scene instance (at least for now). The scene updates and renders itself automatically. ### Actors Each actor (`o2::Actor`) has a transform, visibility and activity flags, plus child actors and components. Child actors inherit their parent’s transform and flags. If a parent actor moves, all its children move accordingly. The same applies to enabling or disabling them. The engine provides basic actor types like sprites, animations, cameras, particles, UI, etc. A developer can inherit custom classes from `o2::Actor` and override the needed methods (`OnStart`, `OnEnabled/Disabled`, `OnDraw`, `OnUpdate`, etc.). This allows actors to represent specific entities (for instance, `o2::Button` inherits from `o2::Widget`, which inherits from `o2::Actor`). ### Components Actors can contain a list of components that define their logic and rendering. To create a custom component, inherit from `o2::Component` and implement the required interface (`OnStart`, `OnEnabled/Disabled`, `OnDraw`, `OnUpdate`, etc.). This lets you compose logic: a single base actor can have multiple components. ### Prototypes For faster and simpler development, the engine supports prototypes (similar to Unity’s prefabs). An actor can be saved as an asset and become a prototype, which can be inherited by other prototypes that modify the base. From one prototype, you can create many copies on the scene and then edit them. This is especially useful for UI. You might have a base button prototype with specific graphics and logic, then derive several variations (green, blue, red). If you need to change the blue button’s color to purple, you only edit the prototype. Likewise, changes to the base button prototype propagate to all its inheritors. ### Scene Rendering Scene rendering uses cameras and layers: - The scene is divided into named layers, each with a specified rendering order. - Cameras (at least one) are placed in the scene, each with its own transform and a list of layers to render. Actors are assigned to layers and have a numerical priority defined in the actor itself. It can also inherit the layer and priority from its parent, so children render immediately after the parent and share its layer/priority. If inheritance is disabled, they render on their own layer based on the sorting order. By default, the scene is drawn according to the hierarchy, but you can manually adjust this using priorities and layers. ### Editor There’s a built-in editor for editing scenes, prototypes, components, and assets. It includes various specialized tools (asset settings, log, parameters window, game window, scene hierarchy, scene editor, animation editor). [More on the editor](/Docs/en/Editor/editor.md). ## UI [(detailed documentation)](/Docs/en/Architecture/HighLevel/ui.md) UI in the engine is part of the scene and follows its paradigm. The base UI element is `o2::Widget` (inheriting from `o2::Actor`), which overrides the actor logic: - **Adaptive Layout** The transform includes anchors for flexible positioning relative to the parent, enabling adaptive UI layout. - **Internal Widgets** A widget can contain child controls that aren’t “full-fledged children” in the scene hierarchy, which is convenient for complex UI elements (e.g., a window with a header and a close button). - **Layer System** A widget holds layers (`o2::WidgetLayer`) that can have their own graphics (sprite, text, etc.), transform with anchors, nested layers, and names. Layers are a simplified analog of actors, easing rendering and preventing the scene hierarchy from becoming overloaded. - **Animation States** A widget can have multiple named states that can be turned on or off independently. Switching a state triggers an animation defined in code or in the editor (see the animation section). ### Layout Containers For adaptive interfaces, there are special container widgets (`o2::HorizontalLayout`, `o2::VerticalLayout`, `o2::GridLayout`). They arrange their child elements according to the given rules, stretching/shrinking them or adjusting to their sizes. ### Built-in UI Widgets The engine provides many basic UI controls: images, text, buttons, checkboxes, text fields, progress bars, scrollers, lists (regular or drop-down), trees, popups, windows, and so on. Since the UI subsystem extends the scene system, UI elements can coexist with any game objects. The entire o2 editor is built on this UI system ([details in the Habr article](https://habr.com/ru/articles/521306/)). ================================================ FILE: Docs/en/main.md ================================================ ## Motivation The engine is designed as a professional tool for developing 2D mobile games. Its design is guided by two key objectives: development speed and performance. Development speed is ensured by an intuitive API, an editor, and a scripting language. - A user-friendly API means it covers all the developer's use cases, is easy to understand, and has minimal hidden pitfalls. Unity3D's internal API served as a reference in many aspects. - The editor provides all the essential tools for game development: scene, assets, parameters, animations, particles. It is convenient and follows the modern standards of engines with editors, such as Unity3D, Unreal Engine, Unigine, etc. - The scripting language simplifies writing game logic and makes the engine's API even more accessible. o2 uses JavaScript and TypeScript for scripting, as these are popular languages, especially among web developers, who have very few available game engines. Performance is achieved by implementing the engine in C++ and allowing game logic to be written in C++. The engine also has different abstraction layers, so for maximum performance, the developer can work directly with the low-level subsystems like rendering, resource loading, etc. Combining all these approaches results in efficient game development, rapid prototyping, and high technical quality. ## General Engine Concept The engine’s core concept is a scene with a component-based approach. The scene is a tree structure of actors with specific types. Each actor has a transform that depends on its parent, as well as a set of components defining behavior and rendering. Rendering is divided into layers; actors can be assigned to specific layers or inherit the rendering order from their parent. You configure the scene and its assets in the editor. Actor, component, and game code can be written in C++ or in a scripting language (JS/TS). The scene subsystem is high-level and is built atop the low-level subsystems: assets, application, rendering, animation, physics, scripting, input. When working at the high level, you can still use the low-level layer directly for more optimizations. For instance, if you need to display a large number of sprites, instead of creating multiple heavy actors, you can implement a single actor that draws many sprites directly via the low-level renderer. The low-level layer relies on utilities that provide support for all subsystems: memory management, reflection, serialization, properties, math, file system, debugging, and logging. ## The Concept of Integrating o2 Into Other Engines o2 can be used not only as a standalone engine but also as an embedded one. Essentially, it integrates into the game loop of another engine, hooks into its rendering and input processing, and interacts with it according to clearly defined boundaries. There are two approaches: **dominant** and **subordinate**. In the first approach, o2 wraps the other engine inside itself, controlling its input handling, frame updates, and rendering. This is the preferred way. In the second approach, everything is reversed: o2 is embedded into the other engine’s game loop. Typically, other engines also have a scene hierarchy. o2 can work with it if you inherit the base object of the other engine's hierarchy from a certain o2 interface. This allows o2’s editor to display the other engine’s hierarchy and lets you edit object parameters, which become available through reflection. It is important that the other engine uses the same render API as o2. In extreme cases, it’s possible to implement a custom rendering subsystem for the specific implementation in the other engine, since essentially all that’s needed is the ability to draw textured, shaded triangle meshes. Usually, other engines have this functionality in a separate API. ## Documentation - [Architecture](/Docs/en/Architecture/architecture.md) - [Editor](/Docs/en/Editor/editor.md) - [Video tutorial series on setting up a test slot-game scene](https://drive.google.com/drive/folders/1m-lgSaM2hYQxbKnIwymDfMCe3SzjKrP1?usp=sharing) ================================================ FILE: Docs/ru/Architecture/HighLevel/components.md ================================================ ## Базовые компоненты В движке есть базовый набор компонент: - `o2::ImageComponent` Обертка над `o2::Sprite` из рендера, умеет все то же самое - `o2::MeshComponent` Обертка над движковым `o2::Mesh`, но с добавлением функционала в редакторе по построению этого меша - `o2::SkinnedMeshComponent` Меш, который может скинниться. Spine-подобные анимации могут бысть сделаны с помощью него - `o2::AnimationComponent` Компонент анимаций. В нем задается список анимаций, которые могут изменять актор, компоненты и все что есть ниже по иерархии - `o2::ParticlesEmitterComponent` Обертка над партикл-эмиттером из рендера. Умеет все то же самое - `o2::ScissorClippingComponent` Задает отсечение дочерних объектов по своей трансформации. Отсечение работает только на те сущности, которые унаследовали от него приоритет отрисовки - `o2::ScriptableComponent` Компонент в котором можно задать поведение через JS-скрипт ================================================ FILE: Docs/ru/Architecture/HighLevel/scene.md ================================================ ## Сцена Сцена является еще одной подсистемой движка, в которой используются низкоуровенвые системы. Сцена состоит из иерархии акторов и слоев. Она может быть загружена и выгружена, может быть изменена в рантайме. ### Иерархия У каждого актора могут быть акторы-дети. У них в свою очередь тоже могут быть дети. В сцене хранится список "рутовых" акторов. Таким образом получается иерархия акторов на сцене. Акторы могут быть разных типов, наследуясь от базового `o2::Actor`. На акторах могут быть компоненты. Компоненты определяют логику актора, могут быть отрисовываемыми. Если компонент отрисовывается, он принажделит какому-то слою и имеет приоритет отрисовки. ### Слои Сцена разделена на слои. Эти слои задают порядок отрисовки сцены. Порядок слоев задается разработчиком, список слоев и их имена тоже. Рисуемые сущности распределяются по слоям, одна сущность может быть только на одном слое. Внутри слоя сущности сортируются по приоритетам. ### Актор, o2::Actor Это базовый элемент сцены. У него есть имя, трансформация, список детей и список компонент. Акторы могут быть разных типов, унаследованных от `o2::Actor`. У акторов есть цикл жизни: - `constructor` - конструктор актора - `deserialization` - десериализация данных актора. ПРоисходит автоматически - `OnDeserialized` - коллбек на завершение десериализации - `OnAddToScene`/`RemovedFromScene` - добавление/удаление из сцены - `OnStart` - старт актора, перед первым апдейтом - `OnEnabled`/`Disabled` - включение/выключение актора - `Update` - обновление актора и компонент - `OnTransformUpdated`/`Changed` - обновление и изменение трансформации ### Компонент, o2::Component Все компоненты наследуются от этого общего интерфейса. Внутри компоненты задается какая-то логика, которая может взаимодействовать с другими частями сцены и ассетами через ссылки. У компонентов, как и у акторов, тоже есть такие же ивенты и цикл жизни: конструктор, десериализация, старт, обновление и тп. ### Рисуемый компонент, o2::DrawableComponent Этот интерфейс определяет что компонент может что-то рисовать на сцене. В нем определяется слой и индекс сортировки. Чем он больше, тем позднее он отрисуется в выбранном слое. Индекс сортировки не обязателен, он может быть унаследован от родителя. В таком случае родитель при отрисовки себя нарисует и эту сущность. Если таких сущностей несколько у родителя, он нарисует их в порядке расположения в иерархии. Если родителя нет, то объект помещается в специальный контейнер слоя с приоритетом 0, в котором подобные сущности рисуются так же в порядке расположения в иерархии. Таким образом, если задать отрицательный индекс, то компонент будет отрисован ранее других компонентов, у которых индекс не задан, тк он будет нулевым. По умолчанию индекс сортировки не задан и используется родительский. То есть сцена рисуется в порядке обхода иерархии. ### Прототипы Для ускорения создания сцены и удобства работы в сцене можно использовать прототипы. Это такие предзаготовленные куски иерархии сцены, фактически актор с его детьми, который затем можно "инстанцировать" на сцену, т.е. создать его копию. При этом, если в редакторе на сцене что-то поменять в одном из инстансов прототипа, то можно это изменение применить к базовому прототипу, и все остальные инстансы получат такое же изменение. Но это работает только в редакторе. Прототипы можно создавать от прототипов, изменяя какие-либо его параметры. Тогда на конечном инстансе унаследованного прототипа будут отображаться изменения как базового прототипа, так и унаследованного ### Ссылки Для связа компонет, акторов и ассетов между собой используются ссылки. Они ссылаются на сущности по уникальным идентификаторам, происходит это автоматически. Это нужно чтобы не искать акторы и их компоненты по пути в коде. Путь может быть нарушен при изменении иерархии, и тогда придется переписывать код. В случае ссылок изменение иерархии не приведет к нарушению ссылок, все будет работать. Ссылаться можно на другие акторы через `o2::ActorRef` или `o2::Ref`. Точно так же на другие компоненты через `o2::ComponentRef` и `o2::Ref`. На ассеты можно ссылаться через подобные же `o2::AssetRef` `o2::Ref`. ### Камеры, o2::CameraActor Это специальные акторы, которые задают отрисовку сцены. Без камеры ничего нарисовано не будет, должна быть хотя бы одна на сцене. В камере определяется список слоев, которые она рисует. Трансформация камеры задает область видимости в сцене. Работает аналогично камере рендера, своего рода "окно" в пространство сцены. ================================================ FILE: Docs/ru/Architecture/HighLevel/ui.md ================================================ ## Система интерфейсов Для работы с пользовательским интерфейсом есть набор специальных акторов, которые могут рисовать интерфейс и обрабатывать клики по нему. Все работает в рамках сцены, через наследника от `o2::Actor` - `o2::Widget`. Все остальные типы интерфейсных акторов наследуются от него. ### o2::Widget Наследует все свойства актора: имя, трансформацию, компоненты, прототипирование. При этом добавляет и новые свойства: #### layout Это расширение transform. которое добавляет адаптивность верстки. В нем задаются относительные координаты от родительского transform, к которым потом плюсуются числовые смещения. С помощью относительных координат можно задать выравнивание по какому-то краю или углу, а так же задать процентное отношение занимаемой площади по горизонтали и вертикали. Числовые смещения позволяют задать область более точно, или для явного указания размера #### Слои Для отрисовки графики UI используются слои, которые являются простой версией актора. Слои так же выстроены в структуру, для каждого слоя задается его layout, а так же графический элемент. Графический элемент - это любой наследник от `o2::IRectDrawable`: Sprite, Text, etc Слои могут отключаться и у них есть настраиваемая прозрачность, которая влияет и на дочерние слои #### Состояния Это элементарная анимационная стейт-машина, где задается список состояний, и каждое состояние может быть включено либо выключено. Переход состояния из вкл в выкл и наоборот происходит через анимацию, которая задается через анимационный клип. #### Прозрачность и видимость Прозрачность задается на виджете и распространяется на его слои, а так же на все дочерние виджеты и так далее. Видимость управляется через интерфейс `SetEnabled()` из актора и может быть анимировано. Если задано специальное состояние с именем 'visible', то оно будет использоваться для переключения видимости #### Фокусировка Некоторые виджеты могут принимать на себя фокус, например кнопки, поля ввода и тд. Тогда они становятся первыми в очереди на обработку хоткеев. #### Внутренние дети Иногда, элементы интерфейса бывают довольно сложными и одними слоями не обойтись. Например, рассмотрим окно. Гораздо удобнее когда окно представлено единым объектом, а все его дети - это его контент. Однако, на самом окне есть заголовок, кнопка закрытия. В виджетах есть возможность сделать такие элементы внутренними, то есть они как бы являются детьми, но при этом при попытке перечислить детей - о них ничего не будет известно. ## Типы встроенных виджетов - `Grid/Horizontal/VerticalLayout` - динамическое расположение дочерних элементов по сетке/по горизонтали/по вертикали - `Button` - кнопка - `EditBox` - поле ввода текста - `Image` - спрайт - `Label` - текст - `Toggle` - флаг, чекбокс - `Vertical/HorizontalScrillBar` - вертикальный/горизонтальный скролл-бар - `Vertical/HorizontalProgressBar` - прогресс-бары - `List/LongList` - списки - `DropDown` - выпадающий список - `Tree` - дерево - `ContextMenu` - контекстное меню ================================================ FILE: Docs/ru/Architecture/LowLevel/animations.md ================================================ ## Анимации Все анимации в движке наследуются от общего интерфейса `o2::IAnimation`. Он задает интерфейс сущности, которая может обновиться, у нее есть старт, длительность, окончание и текущее время. От него наследуется основной класс анимации `o2::AnimationPlayer`. В нем задается target анимации - объект, к которому применяется анимация, и анимационный клип. ### Анимационный клип, o2::AnimationClip Анимационный клип содержит в себе список треков с ключами. Каждый трек привязывается к определенному параметру таргета, через рефлексию. Параметр биндится через путь, наподобие пути директории "myClass/someObject/myProperty", в котором описано как через рефлексию искать нужное свойство объекта. Так же на треке есть набор ключей, отобращающих ключевые состояния параметра в определенный момент времени и способ интерполяции между ними. Типы треков: - float - числовой, представлен в виде кривой безье - bool - булевый, показывающие true/false на определенных частях таймлайна - color - изменение цвета по времени - vector2 - задается сплайном движения в 2D пространстве и графиком интерполяции по этому сплайну - любые кастомные Анимационный клип можно создать из кода или из редактора. Его можно сохранить и загрузить из ассета - `o2::AnimationClipAsset`. Для создания из кода есть 2 способа: - вручную добавляя треки и ключи в них - через вспомогательный класс `o2::Animate` ### o2::Animate Позволяет похожим на натуральный язык задать секвенции для некоторых параметров: позиция, альфа, скейл, поворот Для этого нужно создать обхект `o2::Animate`, передав туда target анимации. Далее используя функции Move/Alpha/Scale/Rotate задается начальное состояние анимации. Следующее состояние разделяется фукнцией `Then()`, после которой можно описать следующее состояние параметров и задать время интерполяции через `.For(sec)`, в секундах. так же можно задать паузу через `.Wait(sec)`. ### Target анимации и инициализация В качестве таргета должен быть задан объект, отображенный в рефлексии, то есть наследованный от `o2::IObject`. Для хоть какой-либо анимации должен быть задан анимационный клип `o2::AnimationClip`. Как только эти два параметра появляются, происходит биндинг треков из клипа к конкретным параметрам таргета: для каждого трека, по его пути ищется нужное поле, и через интерфейс `o2::IValueProxy` передается под управление анимацоннным трекам. При запуске анимации все треки стартуют синхронно, в процессе интерполяции передают новые значения через прокси в нужные поля классов или функции-сеттеры через property. ### Анимация на сцене, o2::AnimationComponent Этот компонент работает наподобие `o2::AnimationPlayer`, точнее использует его внутри. При этом позволяет проигрывать несколько клипов на одном объекте одновременно, смешивая треки между собой. Например, в компоненте задано два клипа, анимирующих какое-то числовое значение. Они задаются именованными стейтами, с весом. Чем больше вес стейта, тем большее влияние он оказывает на конечное значение параметра. Таким образом можно делать плавыне переходы между анимациями и запускать несколько анимаций одновременно или по очереди. ================================================ FILE: Docs/ru/Architecture/LowLevel/application.md ================================================ ## Application, обертка приложения Этот класс - точка входа в движок, он отвечает за инициализацию всех подсистем, за игровой цикл и за фрейм прилоежния (окно на РС или фулскрин приложение на других платформах). Разработчик может сделать своего наследника от этого класса и перегрузить в нем функции, отвечающие за работу приложения: OnStart, OnUpdate, OnActivated/Deactivated и тд Так же можно менять параметры фрейма: подпись, размер и тд, если это поддерживается на текущей ОС. ## Инициализация Для старта приложения создается экземпляр класса и вызывается один или несколько методов, в зависимости от платформы: `Initialize`, `Launch`. Внутри так или иначе вызывается `BasicInitialize`, который инициализирует подсистемы. Для интеграции в mte инициализация платформо-зависимой части окна приложения и рендера отключены. ## Цикл апдейта он происходит в методе ProcessFrame, который циклически вызывается из платформо-зависимой части. В нем замеряется время кадра для обсчета внутренних подсистем. После этого происходит лимитирование FPS если необходимо. Далее обновляются подсистемы движка и запускается рендеринг. После запускается обработка ввода. Для внедрения кода в цикл апдейта или отрисовки можно перегрузить функции `OnUpdate()` и `OnDraw()` ================================================ FILE: Docs/ru/Architecture/LowLevel/assets.md ================================================ ## Assets, система ассетов Каждый ресурс игры - это ассет. Они попадают в сыром виде в папку с ассетами, и перед запуском собираются определенным образом в конечный формат. Так, например, на этапе сборки происходит упаковка текстур в атласы и их сжатие. Каждый ассет содержит мета-данные, в которых определен уникальный идентификатор и другие параметры. Эти мета-данные леэат рядом с ассетом, имеют такое же имя файла, но с расширением .meta. Сущности в движке могут ссылаться на ассет как по пути, так и по идентификатору. Второй способ является основным. Идентификатор остается неизменным если ассет переместить или переименовать. Таким образом ассеты можно перемещать как угодно и ссылки останутся неизменными. ### Система ассетов Для базовой работы с ассетами в движке есть отдельная подсистема `o2::Assets`, с быстрым доступом по макросу `o2Assets`. Она содержит в себе кеш ресурсов, дерево жоступных ассетов и имеет функционал по работе с ассетами: создание экземпляра, перемещение, удаление и тд. ### Базовый класс ассета Asset Он содержит в себе базовую информацию об ассете: идентификатор, путь к ассету. А так же базовый функционал - загрузка, сохранение. ### Типы ассетов Подтипы ассетов наследуются от базового `o2::Asset`: - FolderAsset: папка с ассетами, которые можно получить - ActorAsset: прототип актора - AnimationAsset: анимация - AtlasAsset: атлас - ImageAsset: картинка, ссылается на атлас - BinaryAsset: Бинарный файл - DataAsset: Сериализованные данные, конфиги - SceneAsset: Сцена - Vector/BitmapFont: Векторный/Растровый шрифт - JavaScriptAsset: JS скрипт ### Ссылки на ассеты Базовая ссылка на ассет - это `o2::AssetRef`. От него наследуется шаблонный класс-ссылка `o2::Ref<>`. Он функционирует как типичный умный указатель. Работу с ассетами корректнее вести через ссылки, во избежании дублирования загрузки ассетов ================================================ FILE: Docs/ru/Architecture/LowLevel/input.md ================================================ ## Система ввода, o2::EventSystem и o2::Input `o2::EventSystem` занимается обработкой нажатия клавишь и мышки (или тачей). Она перенаправляет сообщения в нужные сущности, разрешая внутри себя проблемы отсечения и порядка отрисовки. `o2::Input` предоставляет информацию о текущем состоянии систем ввода: - нажатие клавиш: только что нажата, нажата когда-либо, только что отпущена - нажание курсоров (тачей): нажатие, отпускание - положение курсора, дельта курсора за кадр ### Обработка клавиш, o2::KeyboardEventsListener Этот класс используется как интерфейс обработчика нажатий. От него можно наследоваться и перегрузить нужные функции. Сообщения о нажатии/отпускании клавишь приходят всем наследникам интерфейса автоматически ### Обработка курсора и тачей, o2::CursorAreaEventsListener Этот интерфейс обрабатывает не все нажатия и события, а только при попадании курсора в него с условием перекрытия другими обработчиками тачей. Наследовавшись от интерфейса, нужно перегрузить функцию `IsUnderPoint`, которая проверяет попадание точки в область, без учета отсечения. Например, попадание по какой-то геометрической форме или в графику. А так же необходимо вызывать функцию `OnDraw` в тот момент, когда сущность появляется графически на экране Система ввода сама занимается вопросом отсечения и перекрытия слушателей друг другом. Так же нужно перегрузить нужные функции-сообщения курсоров и тачей: -`OnCursorPressed` - курсор нажат на сущности -`OnCursorReleased` - курсор отпущен, не обязательно над ней -`OnCursorPressBreak` - прерывание нажатого курсора (системное, выход за область экрана и тп) -`OnCursorPressedOutside` - курсор нажат снаружи -`OnCursorReleasedOutside` - курсор отпущен снаружи -`OnCursorStillDown` - курсор все еще нажат, не факт что внутри -`OnCursorMoved` - курсор переместился внутри области -`OnCursorEnter` - курсор вошел в область -`OnCursorExit` - курсор вышел из области -`OnCursorDblClicked` - двойной клик по области ================================================ FILE: Docs/ru/Architecture/LowLevel/physics.md ================================================ ## Физика В движок интегрирован физический движок Box2D. Он интегрирован в сцену, и оперируется физическими телами (RigidBody), формами (Colliders) и джоинтами (пока нет) ### Физическое тело, o2::RigidBody Это наследник от `o2::Actor`, который привязывается к динамике физического тела из Box2D. В нем задается масса, инерция, скорость и поведение. Поведение может быть 3х типов: - Dynamic - Динамическое, влияет на другие тела и другие тела влияют на него - Static - статичное тело, не вдигается, отталкивает другие тела - Kinematic - движущееся статичное тело, отталкивает другие, но другие тела не могут на него повлиять ### Формы, коллайдеры Используются для задания формы твердых тел: - box - circle ================================================ FILE: Docs/ru/Architecture/LowLevel/render.md ================================================ ## Рендер За рендеринг отвечает отдельная подсистема Render, с макросом быстрого доступа o2Render. В нем инициализируется рендер и нужные API, если требуется. Через него происходит отрисовка мешей, с использованием батчинга. Можно задавать камеру, отсечение, ренеринг в текстуру. Так же в подсистему рендера входят базовые примитивы: спрайт, текст и эффекты частиц. ### Текстуры Для работы с текстурами используется класс `o2::Texture` и ссылки на них `o2::TextureRef`. Текстуры - это как правило атласы, загруженные с диска, или рендер-таргеты. Важно знать, что текстуры и ImageAsset'ы - это отдельные сущности. Текстуры - это текстуры в видеопамяти, а ImageAsset'ы могут быть отображены как частью текстуры (в атласе), так и быть самостоятельной текстурой. Текстура может быть создана сама по себе, в нее может быть загружен растр, она может быть загружена с диска в определенном формате. Текстура может быть рендер-таргетом, для этого она создается с соответствующим флагом. ### Камера, o2::Camera Задает транформацию, через которую сцена рендерится в текущий момент. Положение задается через интерфейс `o2::Transform`. Фактически трансформацию камеры можно воспринимать как окно, через которое мы смотрим на сцену ### Меши, o2::Mesh Для отрисовки графики используются меши, из них строятся спрайты, текст и тд. Меш состоит из буффера вершин и индексов полигонов. В нем задается текстура. При передаче меша в отрисовку, его вершины и индексы копируются в буффер текущего батча, если текстура не изменилась. Иначе, создается новый батч, а предыдущий отправляется на отрисовку. ### IDrawable Это базовый интерфейс рисуемой сущности, запоминает во время отрисовки текущий прямоугольник отсечения ### IRectDrawable Базовый примитив прямоугольной отрисовываемой сущности. Наследуется от `o2::Transform`, имеет цвет, прохрачность и может отключаться ### Спрайты, o2::Sprite Наследуется от `o2::IRectDrawable`. Спрайт задается текстурой и областью из нее. По умолчанию это задается через `o2::ImageAsset`. Так же спрайт можно создать без текстуры, тогда будет использована дефолтная белая текстура. У спрайта задается режим отрисовки Mode: - Default - по умолчанию, арстягивается во все стороны - Sliced - растягивается с сохранением пропорций границ, 9-slice - Tiled - при растягивании текстура дублируется - FixedAspect - сохраняется соотношение сторон спрайта, вписывается в размер спрайта - FillLeftToRight, FillRightToLeft, FillUpToDown, FillDownToUp - заполнение спрайта по горизонтали/вертикали - Fill360CW, Fill360CCW - заполнение спрайта по/против часовой стрелки Трансформации, цвет, прозрачность - задаются через базовый класс `IRectDrawable`. ### Текст, o2::Text Наследуется от `o2::IRectDrawable`. В нем задается шрифт (векторный или растровый), размер текста, форматирование текста и сам текст. Шрифт задается через ассет `o2::FontAsset`, у которого может быть 2 реализации: `o2::VectorFontAsset` и `o2::BitmapFontAsset`. Текст форматируется относительно прямоугольной области, задаваемой `o2::IRectDrawable`. В форматировании доступны следующие параметры: - hor/verAlign выравнивание по горизонтали/вертикали - перенос слов на следующую строку при горизонтальном переполнении - окончание строки троеточием (...) при горизонтальном переполнении - коэф. межбуквенного и межстрочного расстояния ### Растровый и векторный шрифты Растровый шрифт задается заранее заготовленными и отрендеренными символами в атласе и их описанием. Векторный шрифт генерируется в рантайме, подрендеривая и упаковывая в специальный атлас нужные глифы. На векторный шрифт могут накладываться графические эффекты - обводка, градиент, тень и кастомные. Эти эффекты накладываются посимвольно, во время рендеринга глифифов в атлас, на CPU. ### Эффекты частиц, o2::ParticleEmitter Эмитирует определенные частицы, занимается их динамикой и эффектами. В нем задается форма, которая по размеру привязывается к интерфейсу `o2::IRectDrawable`. Задается лимит частиц, коло-во испускаемых в секунду частиц. Так же старотовые параметры частиц (скорость, угол) Во время апдейта к частицам применяются эффекты, например гравитация и другие кастомные ================================================ FILE: Docs/ru/Architecture/LowLevel/scripting.md ================================================ ## Скриптинг В о2 встроен скриптовый движок, с имплементацией JS на jerryscript. Скриптовым движком управляет подсистема `o2::ScriptEngine`. Она хранит глобальное состояние его можно получить через `GetGlobal`. Может парсить и запускать скрипты (`Parse`/`Run`/`Eval`) Так же он управляет подключением дебаггера. ### Обертка скрипт-значения, o2::ScriptValue Этот класс является универсальной оберткой любого скриптового значения. В нем может храниться как простой тип (number, string, bool ...), так и массивы, объекты и функции. Для определения типа объекта используются функции-геттеры `IsArray`/`IsObject`, или `GetValueType`. Так же класс имеет операторы конвертации в/из нужного типа #### Объекты Для обхектных типов есть функционал по получению property объекта: `GetProperty`, а так же перебор всех пропертей `ForEachProperties`. Так же можно добавлять и удалять проперти в объекте. Есть функционал для прототипов объектов, можно получить или установить прототип: `Set/getPrototype` Так же есть функция `Contruct` для конструирования обхекта из функции-конструктора #### Массивы Для работы с массивами есть функции получения элемента: `operator[int]` и `Set/GetElement`. А так же получение длины массива `GetLength()`. И добавление/удаление элемента в массиве: `Add/RemoveElement`. #### Функции В переменной так же может быть функция, которую можно вызвать. Вызвать можно с передачей С++ параметров через шаблоны, тогда внутри они сконвертируются в скриптовые значения: `Invoke`. Либо сразу с уже заготовленными скриптовыми занчениями: `InvokeRaw`. Так же при вызове функции можно задать параметр this первым аргументом #### Биндинг классов и функций в скриптинг Каждый объект, при включенном скриптинге может хранить в себе закешированное скриптовое значение на этот объект. Это скриптовое значение представляет из себя объект с нативным поинтером на себа внутри. Так же в нем есть поля, которые биндятся к скриптингу Для каждого типа в рефлексии генерируется прототип, на который потом ссылкаются инстансы этого типа. То есть функции фактически хранятся в прототипе. Базовые классы становятся прототипами наследников. ================================================ FILE: Docs/ru/Architecture/Utils/containers.md ================================================ # Контейнеры данных Для удобства работы в движке добавлены специальные контейнеры данных, которые являются обертками над контейнерами стандартной библиотеки, но привносящие удобный функционал. ## `o2::Vector` `Vector<_type>` — шаблонный класс, наследник `std::vector<_type>`. Предоставляет расширенный набор методов для удобной работы со списком: добавление, удаление, поиск, фильтрация, сортировка и пр. ### Основные операции - **Конструкторы** (пустой, список инициализации, копирования, перемещения). - **Операторы** `=`, `+`, `-`, `+=`, `-=`, `==`, `!=`: - Сложение/вычитание с другим вектором или элементом. - Сравнение на равенство/неравенство. - **Размер и память**: `Count()`, `IsEmpty()`, `Capacity()`, `Resize()`, `Reserve()`, `ShrinkToFit()`. - **Доступ к элементам**: `Get(idx)`, `Set(idx, value)`, `Data()`. - **Модификация**: `Add(...)`, `Insert(...)`, `Remove(...)`, `RemoveAt(idx)`, `PopBack()`, `Clear()`. - **Поиск**: `IndexOf(value)`, `Contains(value)`, `Find(...)`, `FindAll(...)`, `First()`, `Last()`. - **Отбор**: `Where(...)`, `All(...)`, `Any(...)`. - **Сортировка**: `Sort(...)`, `SortBy(...)`, `Sorted(...)`. - **Преобразование**: `Convert(...)`, `Cast()`, `DynamicCast()`. - **Итерация**: `ForEach(...)`, а также методы `Begin()`, `End()` для итераторов. ### Дополнительно - **Take(...)** — возвращает подмножество элементов по индексу или количеству. - **Clone()** — создает копию текущего вектора. - **Min(...) / Max(...)** — находит минимальный/максимальный элемент по селектору. - **Sum(...)** — суммирует значения, вычисленные по селектору. - **Reverse()** — изменяет порядок на обратный. При включенном `ENABLE_MEMORY_ANALYZE` доступны методы для анализа памяти. ## `o2::Map` `Map<_key_type, _value_type>` — шаблонная обёртка над `std::map`. Хранит пары (ключ-значение) и предоставляет дополнительные методы для удобного управления данными. ### Основные операции - **Добавление**: `Add(key, value)`, `Add(Map)`. - **Удаление**: `Remove(key)`, `RemoveAll(match)`, `Clear()`. - **Проверка наличия**: `ContainsKey(key)`, `ContainsValue(value)`, `Contains(pair)`. - **Поиск**: `FindKey(key)`, `FindValue(value)`, `Find(match)`, `FindAll(match)`, `First(match)`, `Last(match)`. - **Доступ**: `Get(key)`, `Set(key, value)`, `TryGetValue(key, outValue)`. - **Размер**: `Count()`, `IsEmpty()`. - **Итерации**: `ForEach(func)`, а также `Begin()`, `End()` для итераторов. - **Условия**: `All(match)`, `Any(match)`. - **Мин/макс/сумма**: `Min(selector)`, `Max(selector)`, `Sum(selector)`. ### Дополнительно - **Where(...)** — фильтрация пар по условию. - **Сравнение**: `==`, `!=`. - **Операторы присваивания**: копирование и инициализация списком. - При `ENABLE_MEMORY_ANALYZE` доступен функционал анализа памяти. ================================================ FILE: Docs/ru/Architecture/Utils/debug.md ================================================ # Документация `Debug` ## Описание Синглтон для вывода логов и отрисовки отладочных примитивов: линий, стрелок, окружностей, прямоугольников и текста. ## Макрос - **o2Debug** — глобальная точка доступа к экземпляру `Debug`. ## Конструктор и деструктор - **Debug(RefCounter\* refCounter)** — инициализирует систему логирования и шрифтов. - **~Debug()** — освобождает ресурсы. ## Методы логирования - **Log(format, ...)** / **LogStr(out)** — вывод информационных сообщений. - **LogWarning(format, ...)** / **LogWarningStr(out)** — вывод предупреждений. - **LogError(format, ...)** / **LogErrorStr(out)** — вывод ошибок. - **GetLog()** — возвращает основной лог. ## Методы рисования Отрисовывают отладочные примитивы сразу или с заданным временем исчезновения (`delay`): - **DrawLine(...)** - **DrawArrow(...)** - **DrawRay(...)** - **DrawCircle(...)** - **DrawRect(...)** - **DrawLine(Vector points, ...)** - **DrawText(...)** ## Методы обновления и отображения - **Update(isEditor, dt)** — обновляет таймеры отладочных объектов. - **Draw(isEditor)** — рисует все активные отладочные объекты. ## Внутренние структуры - **IDbgDrawable** — базовый интерфейс отладочного объекта (цвет, время). - **DbgLine**, **DbgArrow**, **DbgCircle**, **DbgRect**, **DbgPolyLine**, **DbgText** — структуры для хранения данных и отрисовки конкретных примитивов. ================================================ FILE: Docs/ru/Architecture/Utils/filesystem.md ================================================ # Документация `FileSystem` ## Описание `FileSystem` — синглтон для работы с файловой системой. Позволяет получать информацию о файлах и папках, копировать, удалять, создавать и перемещать их. Также содержит вспомогательные методы для работы с путями. ## Макрос - **o2FileSystem** — глобальная точка доступа к единственному экземпляру `FileSystem`. ## Конструктор и деструктор - **FileSystem(RefCounter\* refCounter)** — инициализация. - **~FileSystem()** — освобождает ресурсы. ## Платформозависимые методы - **GetAssetManager()** *(Android)* — возвращает `AAssetManager`. - **GetBundlePath()** *(iOS/Mac)* — возвращает путь к бандлу. ## Основные методы - **GetFolderInfo(path)** — возвращает информацию о папке и файлах в ней. - **GetFileInfo(path)** — возвращает информацию о файле. - **SetFileEditDate(path, time)** — задаёт время изменения файла. - **FileCopy(source, dest)** — копирует файл. - **FileDelete(file)** — удаляет файл. - **FileMove(source, dest)** — перемещает файл. - **FolderCreate(path, recursive)** — создаёт папку (рекурсивно при необходимости). - **FolderCopy(from, to)** — копирует папку. - **FolderRemove(path, recursive)** — удаляет папку (рекурсивно при необходимости). - **Rename(old, newPath)** — переименовывает файл или папку. - **IsFolderExist(path)** — проверяет наличие папки. - **IsFileExist(path)** — проверяет наличие файла. - **ExtractPathStr(path)** — возвращает путь без имени файла. - **GetFileExtension(filePath)** — возвращает расширение файла. - **GetFileNameWithoutExtension(filePath)** — имя файла без расширения. - **GetPathWithoutDirectories(path)** — возвращает имя папки/файла без родительских директорий. - **GetParentPath(path)** — возвращает путь к родительской директории. - **ReadFile(path)** — читает содержимое файла. - **GetPathRelativeToPath(from, to)** — формирует относительный путь. - **CanonicalizePath(path)** — упрощает путь, убирает `.` и `..`. - **WriteFile(path, data)** — записывает строку в файл. ## Внутренние поля - **mLog** — поток логирования работы с файловой системой. ================================================ FILE: Docs/ru/Architecture/Utils/function.md ================================================ ## o2::Function<> Для удобной работы с подписками в движке есть свой тип делегатов, наподобие `std::function<>`. Но в отличие от std варианта, `o2::Function<>` ведет себя как делегаты из C#, и фактически является массивом из функций. то есть можно описать делегат, например, на клик по кнопке: - `o2::Function onClicked;` и на него можно подписываться/отписываться множество раз: ```C++ button->onClicked += myFunction; ... button->onClicked += []() { o2Debug.Log("Clicked!"); }; ``` При вызове делегата (нажатии на кнопку), будут вызваны все подписчики. Этот делегат оптимизирован и его можно относительно бесплатно использовать, внутри есть оптимизация по типу small string optimization: если хранится всего лишь одна функция, то она хранится без аллокаций ================================================ FILE: Docs/ru/Architecture/Utils/logging.md ================================================ ## Logging Для вывода лога используется иерархия каналов вывода в лог `o2::LogStream`. Каждый канал имеет свой строковый идентификатор и список дочерних каналов. Вывод в дочерний канал так же выводит и в родительский. Верхнеуровневыми каналами являются вывод в консоль и в файл. Можно создавать свои каналы, биндить к другим. Сообщения лога делятся на 3 типа важности: - обычное сообщение - предупреждение - ошибка ================================================ FILE: Docs/ru/Architecture/Utils/math.md ================================================ ## Математика В движке представлены базовые типы для 2D математики: - `Vec2F/I` - двумерный вектор - `RectF/I` - прямоугольник с автосортировкой краев - left всегда меньше right, top всегда выше bottom - `BorderF/I` - рамка вокруг прямоугольника - `Basis` - базис трансформации, фактически матрица 3x2 - `Transform` - трансормация - `Spline` - двумерный сплайн - `Curve` - кривая как функция А так же математические функции в пространстве `o2::Math`: Min, Max, Floor, Ceil, Round, Clamp, Sin, Cos и тд ## Система координат По умолчанию в движке используется декартова система координат: ноль в центре экрана, ось X направлена вправо, ось Y направлена вверх ## Basis Является матрицей 3x2, но в несколько непривычном, но более удобном виде. Он задается в виде пары осеч `xv` и `yv`, определяющих нормализованные направления осей X и Y. Они не обязательно могут быть единичными и перпендикулярными, повно как и в матрице. Эти оси отсчитываются от центра `origin`. Таким образом интуитивно понятно задается базис трансформации, который работает как матрица. Есть методы композиции из position/angle/scaleи обратной декомпозиции. ## Transform Более подробное описание трансформации, в котором содержится: - position - позиция относительно pivot - pivot - точка смещения. От нее отсчитывается позиция, то есть пивот всегда в нуле - size - размер - scale - скейл. По умолчанию (1; 1), умножает size относительно pivot - angle - угол поворота - shear - "сдвиг/скос", смещающий прямоугольник в параллелограмм И много вспомогательных и полезных методов. ## Spline Кривая безье в двумерном пространстве. Задаются опорные точки, на которых могут быть заданы вспомогательные точки для предыдущего и следующего сегмента. Используется обычная интерполяция безье по 4м точкам. ## Curve То же кривая, но представляющая функцию с интерполяцией по оси X, возвращающей единственное значение результата функции по Y. Внутри так же используются кривые безье по 4м точкам ================================================ FILE: Docs/ru/Architecture/Utils/memory.md ================================================ ## Менеджмент памяти Сейчас используется ручной подход к памяти, с возможностью анализа количества аллокаций по месту их выделения. Для этого переопределены функции new() с параметрами исходника и номера строки. Для удоства они спрятаны в макрос mnew (managed new), который регистрирует аллокацию. Далее можно вывести список мест аллокации, осортированный по сумме аллокаций: `o2::MemoryManager::DumpInfo`. Таким образом можно вычислить утечки и расход памяти ## Ссылки и GC Я планирую перейти на использование умных указателей, с сохранением ссылки на счетчик внутри обёекта. Это будет представлено в типе Ref<>, который уже реализован в некотором виде для текстур, ассетов и акторов. К нему будет поставляться отладочный GC, который сможет строить дерево аллокаций и позволит более подробно изучать расход памяти. И устранит ошибки с утечками из-за ручного управления памятью ================================================ FILE: Docs/ru/Architecture/Utils/properties.md ================================================ ## Properties Для удобной работы с сущностями движка и пользовательским кодом, в движке есть специальные обертки над setter/getter функциями. Например, есть функции для значения прозрачности: ```C++ void SetTransparency(float value); float GetTransparency() const; ``` использовать их в математических вычислениях не удобно, особенно если вычисления сложные. `object.SetTransparency(object.GetTransparency()*0.5f);` Гораздо проще оперировать значениями переменных: `object.transparency *= 0.5f;` запись получается короче и более читаемой. Для этого в движке есть макросы, определяющие property а-ля C#. ```C++ PROPERTIES(MyClass); PROPERTY(float, transparency, SetTransparency, GetTransparency); GETTER(int, index, GetIndex); ACCESSOR(Actor*, child, String, GetChild, GetAllChilds); ``` Они определяют новый класс, который хранит ссылку на искомый класс, и перегружает необходимые математические методы, в которых использует указанные setter/getter. Это привносит накладные ресурсы в виде одного указателя на каждую property. В примере выше указаны 3 типа: - `PROPERTY` - стандартный getter/setter - `GETTER`/`SETTER` - определение значения только на чтение или запись - `ACCESSOR` - определяет переменную с перегруженным `operator[]` указанного типа. Удобен для доступа к элементам по имени, как в данном примере доступ к детям актора: `actor->child["name of child"]`; Так же property носят утилитарный характер в анимациях. Они доступны для анимирования, в тч `ACCESSOR`, что позволяет коду реагировать на изменение значения через setter. ================================================ FILE: Docs/ru/Architecture/Utils/reflection.md ================================================ ## Рефлексия В движке используется собственная система типов. С помощью нее можно узнать параметры типа объекта в рантайме: размер, название, список полей и фукнций. Так это можно менять поля объекта по имени в рантайме, вызывать функции так же по имени. Так же поддерживаются аттрибуты для полей и функцийю. Они обозначаются в коде начиная с `@`, как правило в верхнем регистре. Например `@SERIALIZABLE`. Есть внутренние движковые аттрибуты, можно добавлять свои. Изменять тип, добавлять новые поля или функции нельзя. Рефлексия используется для сериализации и десериализации, поиска анимированных полей, генерации интерфейса редактора. Концептуально все делится на 2 подсистемы: система типов и кодогенерация. Отдельная утилита, поставляемая вместе с движком, парсит заголовочные .h/.hpp файлы, ищет там классы которые должны быть отражены в рефлексии, и генерирует мета-код описания типа, который добавляет в конец заголовочного файла. Выглядит это примерно так:
Пример мета-кода ``` // --- META --- CLASS_BASES_META(Reel) { BASE_CLASS(Component); } END_META; CLASS_FIELDS_META(Reel) { FIELD().PUBLIC().SERIALIZABLE_ATTRIBUTE().NAME(blurredImages); FIELD().PUBLIC().SERIALIZABLE_ATTRIBUTE().DEFAULT_VALUE(100.0f).NAME(imagesDistance); FIELD().PRIVATE().NAME(mImages); FIELD().PRIVATE().DEFAULT_VALUE(0.0f).NAME(mRotatingOffset); } END_META; CLASS_METHODS_META(Reel) { FUNCTION().PUBLIC().CONSTRUCTOR(); FUNCTION().PRIVATE().SIGNATURE(void, OnDisabled); FUNCTION().PRIVATE().SIGNATURE(void, UpdateImagesLayout); } END_META; // --- END META --- ```
Добавление в конец не особо мешает разработке, но является оптимальным вариантом для компиляции, в сравнении с выделением всего мета-кода в один большой файл. В такой файл подключается весь проект, и при любом изменении происходит долгая компиляция. На основе сгенеренной мета-информации происходит инициализация типов на старте приложения, регистрация скриптованных типов, а так же сериализация в нужный момент. ### Система типов Как бы странно ни звучало, у типа тоже есть подтипы. Базовым типом является `o2::Type`. Он хранит в себе базовую информацию о типе: название, размер, уникальный id, список базовых типов, список полей, список функций-членов и список статичных функций. Для функций и полей хранится список аттрибутов, которые могут содержать мета-данные. Кроме получения данных о типе, класс `o2::Type` дает дополнительный функционал: - создание экземпляра объекта этого типа `CreateSample()` - поиск указателя на поле по определенному. Поле может быть вложенным в подобъекты, тогда путь задается как путь к директории, с разделением слешами: `path/to/some/field`. - получение прокси-структуры для поля этого типа. Эти проксти-структуры (`IAbstractValueProxy`) объединяют в себе разные подходы владения и изменения значением. Это может быть указатель на значение, либо пара функций setter/getter, либо значение из скрипта и тд - сериализация/десериализация - проверка на равенство. `IsValueEquals` получает на вход два `void*` на значения, внутри происходит автоматическая проверка - копирование значения `CopyValue` От базового `o2::Type` наследуются специализированные типы: - `FunctionType` - функция-делегат `Function<>` - `ObjectType` - объект. Имеет методы каста вверх и вниз относительно `IObject` - `FundamentalType` - фундаментальный тип языка (int, float, string ...) - `PointerType` - указатель на тип, может вернуть тип не-указатель - `PropertyType` - тип для проперти - `VectorType` - тип для `Vector<>`, может вернуть кол-во элементов и поинтер на определенный элемент по индексу - `MapType` - тип для `Map<>`, может возвращать значения по ключам, список ключей - `StringPointerAccessorType` - тип для string pointer accessor, специальной обертки для перегрузки оператора `operator[](String& key)` - `EnumType` - тип для enum'ов, позволяет получить список всех возможных значеный enum'а ### Аттрибуты Для обозначения каких-то свойств полей или функций использутся аттрибуты. Они могут показывать сериализуется поле или нет, исключается или наоборот добавляется в редактор и тп. Можно создавать пользовательские аттрибуты. Аттрибут задается специальным классом, унаследованным от `IAttribute` с внутренними макросами, обозначающими именование в коде и мета-информации. ``` ATTRIBUTE_COMMENT_DEFINITION("SERIALIZABLE"); // В коде тег будет читаться как @SERIALIZABLE ATTRIBUTE_SHORT_DEFINITION("SERIALIZABLE_ATTRIBUTE"); // В мета-информацию будет добавлен как .SERIALIZABLE_ATTRIBUTE() ``` ### Мета-код описания типов и его использование Этот мета-код фактически является шаблонными функциями, инжектируемые в класс для которого строится тип. Он делится на 3 блока: список базовых классов, список полей и список функций. Каждый из этих блоков является шаблонной функцией. В качестве шаблона задается специальный процессор типа наподобие `o2::BaseTypeProcessor`, в котором есть функции-обработчики записей о базовых классах, полях и методах. Таким образом можно задать какой-то процессор типа объекта, который выполняет нужную функцию при переборе данных о типе. Так происходит инициализация типов на старте. Кроме добавления в заголовочный файл мета-информации о типе, в исполняемые .cpp файлы автоматически добавляется регистрация типа, например `DECLARE_CLASS(Reel);`. Она инициирует регистрацию типа с определенным процессором. Этот процессор создает объект типа нужного типа (наследники от `o2::Type`) и заполняет его данными. Так же с помощью этого процессора происходит сериализация и десериализация, о ней в отдельном разделе ### Подсистема рефлексии o2::Reflection В движке есть класс-синглтон, отвечающий за систему рефлексии - `o2::Reflection`. Для более короткого доступа есть макрос `o2Reflection.`. Через него можно получить список всех типов, создать экземпляр типа, получить тип по имени, сконвертировать enum в строку и обратно. ### Рефлексия объектов Для того, чтобы класс был отражен в рефлексии, его нужно унаследовать от `o2::IObject` и разместить в теле класса макрос `IOBJECT(NAME_OF_CLASS)`. Этот макрос добавит нужные поля и функции в класс. Система кодогенерирования сама поймет эти признаки и сгенерирует мета-код ### Получение типа объекта В классах, которые отражены в рефлексии, добавляется статичное полу `o2::Type* type`, в котором хранится тип класса. Так же добавляется **не статичный** метод `const o2::Type& GetType() const`, который в рантайме возвращает реальный тип объекта. Так же доступен метод `TypeOf(value)`, который возвращает тип для любого значения value, которое туда передается. Это может быть как обхект, так и элементарный тип int, float, bool и др. ================================================ FILE: Docs/ru/Architecture/Utils/serialization.md ================================================ ## Сериализация С помощью сгенерированной мета-информации о классах происходит автоматическая сериализация и десериализация обхектов. Не нужно вручную писать код записи и чтения, все происходит автоматически и оптимизированно. Базово сериализаци происходит в формате Json, но может быть добавлен любой друго тип данных, например бинарный. Чтобы сделать тип сериализуемым, его нужно унаследовать от базового класса `o2::ISerializable`, который уже унаследован от `o2::IObject`. И добавить макрос `SERIALIZABLE(NAME_OF_CLASS)` внутрь класса, который уже включает в себя макрос `IOBJECT()`. Сериализуемые поля должны быть отмечены тегом `@SERIALIZABLE`. Сериализуются простые типы, вложенные объекты, пользовательские типы.
Пример сериализуемого класса ```C++ class Reel : public ISerializable { public: ActorRef imagesContainer; // @SERIALIZABLE Vector images; // @SERIALIZABLE Vector blurredImages; // @SERIALIZABLE float imagesDistance = 100.0f; // @SERIALIZABLE bool disableExtendedSymbols = false; // @SERIALIZABLE SERIALIZABLE(Reel); }; ```
## DataValue Для работы со структурой данных (в частности json), используется древовидная структура из DataValue. Эта реализация крайне похожа на rapidjson. В этой структуре хранится тип значения и собственно значение. Значение может быть простым (число, строка, bool, null), объектом или массивом. Для чтения и записи в файл используется обертка DataDocument. ================================================ FILE: Docs/ru/Architecture/Utils/string.md ================================================ ## String Для удобства добавлена обертка над `std::string`, привносящая удобный функционал: - конвертация базовых типов в/из строки - `Append` - добавление строки в конец - `Insert` - вставка строки - `Erase` - удаление промежутка - `Replace` - замена подстроки на другую - `Find` - поиск подстроки - `Contains` - содержит ли подстроку - `CountOf` - кол-во подстрок - `Starts/EndsWith` - начинается/заканчивается на опдстроку - `Split` - разделение на массив подстрок - `TrimStart/End` - обрезка в начале/конце ================================================ FILE: Docs/ru/Architecture/architecture.md ================================================ # Архитектура движка Архитектура делится на три слоя: - **верхний**: сцена, акторы, компоненты, UI, редактор - **низкий**: обёртка приложения, ассеты, рендер, анимации, ввод, физика, скрипты, звуки - **утилитарный**: рефлексия и сериализация, менеджмент памяти, файловая система, отладка и логгирование, математика, делегаты, проперти, контейнеры данных, таймеры Входная точка — это обёртка приложения (`o2::Application`), которая предоставляет кроссплатформенное API для управления приложением. Она имеет платформенные реализации для Windows, macOS, Linux, iOS, Android, Emscripten (WIP). Часть низкоуровневых и утилитарных систем (рендер, файловая система, таймеры) также имеют платформенные реализации. Все подсистемы оформлены как синглтоны для удобного доступа к ним. Перед запуском приложения статически инициализируются некоторые утилитарные системы (например, менеджмент памяти, рефлексия). Затем при старте создаётся экземпляр приложения, который инициализирует остальные подсистемы, и после этого запускается игровой цикл. Игровой цикл состоит из двух фаз: обновление и отрисовка. Всё выполняется внутри o2::Application::ProcessFrame, где обновляются система ввода, сцена, физика, вызывается рендер и т. д. Разработчик может переопределить логику o2::Application, унаследовав собственный класс и реализовав там необходимые функции: инициализацию, запуск, отрисовку, обновление, сворачивание и разворачивание приложения. ## Менеджмент памяти [(подробная документация)](/Docs/ru/Architecture/Utils/memory.md) В движке используются собственные смарт-указатели, которые имеют внешний счётчик ссылок с внутренней ссылкой на него в самом объекте. Это даёт возможность преобразовывать обычный «сырой» указатель в умный, если объект унаследован от `RefCounterable`, хранящего в себе ссылку на счётчик. Для управления временем жизни используется сильная ссылка `Ref<>`, а для не влияющих на время жизни — слабая ссылка `WeakRef<>`. Объекты для умных указателей создаются только через функцию `mmake(...)`, которая выделяет память под счётчик и объект одним блоком, чтобы счётчик всегда шёл перед объектом (cache-friendly). В режиме отладки в движке работает отладочный GC, указывающий на возможные утечки памяти и циклические ссылки, однако сам он объекты не уничтожает и служит лишь для анализа. В редакторе есть утилита для просмотра дерева памяти, где подсвечиваются проблемы. Кроме того, в движке предусмотрены специализированные ссылки для сериализации уникальных идентификаторов: `AssetRef` (для ассетов) и `LinkRef` (для акторов и компонентов).
Пример ```C++ class MyObject: public o2::RefCounterable {}; Ref myObjectSample = mmake(...); myObjectSample->DoSmth(); WeakRef myWeakObject = WeakRef(myObjectSample); MyObject* rawObject = myObjectSample.Get(); Ref myObjectSample2 = Ref(rawObject); ```
## Рефлексия [(подробная документация)](/Docs/ru/Architecture/Utils/reflection.md) Используется для доступа к структуре типов в рантайме (поиск анимируемых значений по строковому пути, вызов коллбеков по имени, сериализация/десериализация, автоматические биндинги скриптов). В основе лежит метаинформация о типах, генерируемая утилитой **o2CodeTool**. Она парсит заголовочные файлы (`.h`), находит в них классы C++ и анализирует их структуру (включая наследование). Затем определяет наследников `IObject` и в конце `.h` генерирует метаинформацию о типе. Эта метаинформация сохраняется в общий репозиторий и формируется инкрементально: кодогенератор хранит кэш проанализированных файлов и обновляет только те, что были изменены.
Пример ```C++ struct MyObject: public o2::IObject { float value = 0.0f; float DoSmth(float arg); IOBJECT(MyObject); }; MyObject myObjectSample; auto& type = TypeOf(MyObject); assert(myObjectSample.GetType() == type); float floatValue = type.GetField("value").GetValue(&myObjectSample); float funcResult = type.Invoke("DoSmth", &myObjectSample, floatValue); ```
## Сериализация [(подробная документация)](/Docs/ru/Architecture/Utils/serialization.md) Для внутреннего хранения данных используются форматы JSON и бинарный (в разработке). Данные представляются в виде `o2::DataValue` — структуры наподобие RapidJSON или PugiXML, позволяющей хранить массивы, таблицы или простые значения (числа, строки, логические и т. д.). Объект `o2::DataValue` может быть загружен из файла и преобразован в C++-объект, либо наоборот — объект сериализуется в `o2::DataValue` и сохраняется. Сериализация осуществляется через рефлексию, а именно с помощью генерируемой метаинформации типов. В процессе сериализации специальный объект записывает данные в `o2::DataValue`. Для этого объект обязан унаследовать интерфейс `o2::ISerializable`, а поля, подлежащие сериализации, должны быть помечены атрибутом `@SERIALIZABLE`. Таким образом, сериализуются только необходимые типы и поля, включая примитивы, контейнеры и смарт-указатели.
Пример ```C++ class Reel : public ISerializable { public: LinkRef imagesContainer; // @SERIALIZABLE Vector> images; // @SERIALIZABLE Vector> blurredImages; // @SERIALIZABLE float imagesDistance = 100.0f; // @SERIALIZABLE bool disableExtendedSymbols = false; // @SERIALIZABLE SERIALIZABLE(Reel); }; ```
## Проперти [(подробная документация)](/Docs/ru/Architecture/Utils/properties.md) Проперти позволяют объявлять переменные, которые используют сеттер и геттер «под капотом», упрощая код. Вместо `object.SetValue(object.GetValue() + 200.0f);` можно писать `object.value += 200.0f;`, аналогично механизму свойств из C#. Чтобы объявить проперти в классе, сначала ставится макрос `PROPERTIES(class_name)`. Затем для каждой проперти используется макрос `PROPERTY(type, name, setter, getter)`, где `setter` и `getter` — функции класса, обрабатывающие чтение и запись значения.
Пример ```C++ class MyObject { public: PROPERTIES(MyObject); PROPERTY(float, value, SetValue, GetValue); public: void SetValue(float value); float GetValue() const; }; MyObject object; object.value = object.value + 100.0f; // object.SetValue(object.GetValue() + 100.0f); ```
## Делегаты [(подробная документация)](/Docs/ru/Architecture/Utils/function.md) `o2::Function<>` — это аналог `std::function<>` с расширенным функционалом, позволяющий хранить несколько делегатов одновременно. Такой подход упрощает систему подписок и событий в логике. Например, можно объявить в классе кнопки `o2::Function onClick;` и подписать на неё несколько обработчиков.
Пример ```C++ class MyButton { public: Function onClicked; ... }; MyButton button; button.onClicked += []() { ... }; button.onClicked += []() { ... }; button.onClicked += []() { ... }; ```
## Обертка приложения [(подробная документация)](/Docs/ru/Architecture/LowLevel/application.md) Как было описано выше это входная точка и основная система движка. На этапе инициализации она инициализирует другие подсистемы. Далее начинается игровой цикл, который обрабатывается в функции ProcessFrame(). Там вызывается апдейт сцены, инпута и всех остальных подсистем, а так же происходит рендер кадра. Так же в обертке приложения обрабатываются системные сообщения: активация и деактивация, и т.д. Пользователь может вклиниться в любой их этих точек, перегрузив специальные функции в своем кастомном классе приложения
Пример ```C++ class MyApplication: public o2::Application { private: void OnUpdate(float dt) override; void OnDraw() override; void OnActivated() override; void OnDeactivated() override; void OnStarted() override; void OnClosing() override; void OnResizing() override; }; ```
## Ассеты [(подробная документация)](/Docs/ru/Architecture/LowLevel/assets.md) Движок рассматривает ресурсы (текстуры, звуки, текстовые конфиги и т. д.) как ассеты, поступающие в сыром виде. Для быстроты загрузки в рантайме они предварительно собираются: текстуры упаковываются в атласы и сжимаются, звуки конвертируются, конфиги бинаризируются. Каждый ассет имеет уникальный `id`, хранящийся в `.meta`-файле рядом с самим ассетом. В этом файле также может быть информация о сжатии и другие данные, которые нельзя разместить в исходном файле. Кроме того, создаётся дерево ассетов, позволяющее эффективно загружать их метаданные. Процесс сборки ассетов осуществляет утилита **AssetsBuilder**, отслеживающая изменения ресурсов и обновляющая их собранные версии. Она запускается перед стартом редактора, во время его работы и при сборке финального билда. Для работы с ассетами предусмотрена подсистема `o2::Assets` (синглтон), доступная из любого места в коде через макрос `o2Assets`. Она загружает дерево ассетов при старте и предоставляет к ним удобный интерфейс. Используются умные ссылки `o2::AssetRef<>`, которые сериализуются, кешируют загрузку и автоматически выгружают ассет, если на него нет активных ссылок. Ассеты могут существовать как отдельные файлы или быть «встроенными» (instance). В последнем случае ассет сохраняется непосредственно внутри сцены или префаба.
Пример ```C++ AssetRef image = o2Assets.GetAssetRef(id); sprite.Load(image); ```
## Рендер [(подробная документация)](/Docs/ru/Architecture/LowLevel/render.md) Подсистема рендеринга доступна через синглтон `o2Render`. Она может рисовать треугольные меши с материалами (шейдеры, текстуры, параметры (WIP)) и использует батчинг: меши с одинаковыми материалами объединяются и отправляются на рендер одним вызовом. Поддерживается настройка отсечения, стенсил-маски и рендер-таргетов. Сверху над рендером мешей есть абстракции: спрайт, текст, скиннинг-меши, эффекты частиц, Spine-анимации. Все они реализуют `o2::IDrawable`, а объекты с прямоугольными размерами — ещё и `o2::IRectDrawable`. Параметры `o2::IRectDrawable` включают позицию, размер, поворот, скейл, скос или задание трансформа через `o2::Basis`. - **Спрайты** поддерживают режимы отображения: обычный, 9-slice, tiled, progress filled. Задают цвет и прозрачность, загружаются из текстур. - **Текст** работает с растровыми и векторными шрифтами (через FreeType). Есть эффекты CPU (тень, обводка, градиент и т. д.), а также параметры форматирования и выравнивания. - **Система частиц** представлена одиночными эмиттерами с набором эффектов. Рендер осуществляется как обычный спрайт или покадровая анимация. Поддерживаются стартовые параметры, а в редакторе можно отмотать эффект назад. Так же в рендере есть поддержка камер (`o2::Camera`), задающие вьюпорт в логических координатах рендера.
Пример ```C++ AssetRef imageAsset = o2Assets.GetAssetRef(id); auto sprite = mmake(imageAsset); ... sprite->position = Vec2F(10, 10); sprite->mode = SpriteMode::FixedAspect; sprite->transparency = 0.5f; ... sprite->Draw(); ```
## Анимации [(подробная документация)](/Docs/ru/Architecture/LowLevel/animations.md) В движке существует встроенная система анимаций и интеграция со Spine. Spine-анимации загружаются из ассета, умеют проигрываться, микшироваться и менять скины. Встроенный формат тесно интегрирован в движок и позволяет анимировать любые поля (включая пользовательские). Основная единица — **`o2::AnimationClip`**, который может быть сохранён как ассет (`o2::AnimationAsset`). Клипы состоят из треков, где каждый трек анимирует одно поле, определяемое строковым путём (например, `"myStructure/myFolder/myParameter"`). Треки включают ключевые кадры с конкретным значением и временем. Для проигрывания используется **`o2::AnimationPlayer`**: ему передаётся анимационный клип и целевой объект. По строковым путям рефлексия находит требуемые поля. При обновлении времени плеер интерполирует ключевые кадры в треках, обеспечивая плавность при любом фреймрейте. На сцене доступен компонент **`o2::AnimationComponent`**, позволяющий одновременно проигрывать несколько анимаций на актёре и смешивать их по весам. Он хранит список состояний (клипов) и переключается между ними. Сверху над ним существует **`o2::AnimationStateGraphComponent`** — анимационный граф состояний. Он содержит узлы (состояния) с несколькими анимационными клипами и переходы, задающие момент старта, длительность и easing-функцию. Разработчик указывает целевую ноду, а граф автоматически выстраивает путь, обрабатывая все переходы и блендинги. Эта система работает и со встроенными, и со Spine-анимациями. В редакторе есть специальный редактор встроенных анимаций. [Подробнее](/Docs/ru/Editor/Animation/animation.md). Так же анимации возможно конструировать из кода через интерфейс **`o2::Animate`**
Пример ```C++ sample->SetHighlightAnimation(Animate(*sample->GetHighlightDrawable()). Hide().Scale(1.5f).Then(). Wait(0.3f).Then(). Show().Scale(1.0f).For(0.2f).Then(). Wait(1.0f).Then(). Hide().For(0.2f)); ```
## Обработка ввода [(подробная документация)](/Docs/ru/Architecture/LowLevel/input.md) Система ввода доступна через синглтон `o2Events`. Она предоставляет базовые обработчики системных событий (нажатие кнопок, положение курсора и т. д.) и высокоуровневую логику (клики, мультитач). Высокоуровневая часть учитывает рендер-отсечение и перекрытие элементов. Для реализации работы с тачем (кликами, наведением) следует наследоваться от `o2::CursorAreaEventsListener` и реализовать нужные методы (нажатие, отжатие, вход, выход и т. д.). Обязательны два метода: 1. Проверка условия клика (например, попадает ли курсор в границы объекта). 2. `OnDraw` — вызывается при отрисовке, чтобы зафиксировать порядок объектов и текущее рендер-отсечение. Далее система ввода автоматически определяет, на какой объект пришёлся клик, и вызывает соответствующие колбэки.
Пример ```C++ class MyInteractiveObject: public o2::CursorAreaEventsListener { public: bool IsUnderPoint(const Vec2F& point) override { return _rectangle.IsInside(point); } void Draw() { sprite.Draw(); o2::CursorAreaEventsListener::OnDrawn(); } private: void OnCursorPressed(const Input::Cursor& cursor) override { o2Debug.Log("Pressed!"); } void OnCursorReleased(const Input::Cursor& cursor) override { o2Debug.Log("Released!"); } }; ... auto object = mmake(); ... object.Draw(); ```
## Скрипты [(подробная документация)](/Docs/ru/Architecture/LowLevel/scripting.md) В движке используется **JerryScript** — компактный и производительный JavaScript-рантайм, который также позволяет писать код на TypeScript при желании иметь статическую типизацию. Сверху JerryScript реализована движковая обёртка, доступная через синглтон `o2Scripts`, и враппер JavaScript-переменных `o2::ScriptValue`. - `o2Scripts` позволяет загружать и выполнять скрипты из файлов и строк, а также работать с глобальным пространством имён через `o2::ScriptValue`. - `o2::ScriptValue` отражает любую JS-переменную (число, строку, булевое, функцию, массив или объект) и предоставляет удобный интерфейс для взаимодействия с этими типами, а также с классами и прототипами. Биндинг типов C++ выполняется за счёт механизма рефлексии: при запуске приложения движок регистрирует необходимые классы в глобальном пространстве рантайма JavaScript, используя сгенерированную метаинформацию.
Пример ```C++ o2Scripts.GetGlobal().SetProperty("myValue", 256); o2Scripts.Eval("print('myValue is ' + myValue)"); ... o2Scripts.Eval("let myObject = new MyObject"); auto myJSObject = o2Scripts.GetGlobal().GetProperty("myObject"); auto myProperty = myJSObject["propName"]; if (myProperty.GetValueType() == o2::ScriptValue::ValueType::Number) { float myPropertyValue = myProperty.ToNumber(); ... } ```
## Физика [(подробная документация)](/Docs/ru/Architecture/LowLevel/physics.md) В o2 встроен физический движок Box2D. При старте приложения инициализируется физический мир, в который можно добавлять объекты через примитивы сцены. Для игрового мира можно настраивать масштабирование движковой единицы пространства в мир физики, параметры точности солвера и коллизии между слоями. Базовый примитив на сцене — это `o2::RigidBody`. В нём задаются физические параметры тела, и оно интегрируется в физический мир. К нему могут быть прикреплены коллайдеры — `o2::ICollider`, такие как `BoxCollider`, `CircleCollider` и т. п. Работа и настройка физики происходит через сцену и редактор. ## Звукци (TBD) На текущий момент не реализованы в движке ## Сцена и акторы [(подробная документация)](/Docs/ru/Architecture/HighLevel/scene.md) Над всеми подсистемами работает система сцены, доступная через синглтон `o2Scene`. В ней хранится список акторов (`o2::Actor`), имеющих свои компоненты, определяющие логику и отрисовку. Акторы могут относиться к разным типам, например `o2::Widget` (UI), `o2::RigidBody` (физическое тело) и другие пользовательские классы. Сцену можно сохранять и загружать из ассета, включая инкрементальную загрузку. Логически она существует в единственном экземпляре (по крайней мере, на данный момент). Сама сцена обновляется и рендерится автоматически. ### Акторы Каждый актор (`o2::Actor`) имеет трансформацию, флаги видимости и активности, а также содержит дочерних акторов и компоненты. Дочерние акторы наследуют трансформацию родителя и его флаги. Если родительский актор сдвигается, то все потомки тоже смещаются по иерархии. То же самое происходит при отключении или включении акторов. В движке уже есть набор базовых типов: спрайты, анимации, камеры, частицы, UI и т. д. Разработчик может унаследовать собственные классы от `o2::Actor` и переопределить необходимые методы (`OnStart`, `OnEnabled/Disabled`, `OnDraw`, `OnUpdate` и т. п.). Это позволяет трактовать акторы как конкретные сущности с определёнными целями (например, `o2::Button` наследуется от `o2::Widget`, что в свою очередь является потомком `o2::Actor`). ### Компоненты Акторы могут содержать список компонентов, определяющих их логику и отрисовку. Для создания пользовательской компоненты нужно унаследовать её от `o2::Component` и реализовать нужный функционал (`OnStart`, `OnEnabled/Disabled`, `OnDraw`, `OnUpdate` и т. д.). Такой подход позволяет реализовывать логику по принципу композиции: один базовый актор может включать несколько компонентов. ### Прототипы Для ускорения и упрощения разработки используется механизм прототипов — аналогичный префабам в Unity3D. Актор может быть сохранён в ассет, становясь прототипом, от которого можно наследовать другие прототипы, внося изменения относительно базового. Из прототипа легко создать множество копий на сцене, а затем при необходимости модифицировать их. Такой механизм особенно полезен в UI. Можно создать базовый прототип кнопки, настроить её графику и логику, а затем сделать несколько наследованных прототипов (зелёная, синяя, красная). Если нужно изменить, к примеру, цвет синей кнопки на фиолетовый, это делается в одном месте — в самом прототипе. А изменения в базовом прототипе распространятся на все места, где он используется. ### Отрисовка сцены Рендер сцены осуществляется с помощью камер и слоёв: - Сцена делится на именованные слои, которым задаётся порядок отрисовки. - На сцену помещаются камеры (как минимум одна), каждая из которых имеет свою трансформацию и список слоёв для рендеринга. Акторы привязываются к слоям и имеют числовой приоритет. Он задаётся в самом акторе. При желании приоритет и слой можно наследовать от родителя, тогда дочерние акторы рисуются сразу после родителя, поддерживая его слой и приоритет. Если наследование не включено, они выводятся отдельно на своём слое согласно сортировке. Таким образом, по умолчанию иерархия определяет порядок отрисовки, но при необходимости можно вручную влиять на это при помощи приоритетов и слоёв. ### Редактор Для редактирования сцены, прототипов, компонентов и ассетов существует встроенный редактор, включающий ряд специализированных утилит (настройка ассетов, лог, окно параметров, окно игры, иерархия сцены, редактор самой сцены и анимаций). [Подробнее о редакторе](/Docs/ru/Editor/editor.md). ## UI [(подробная документация)](/Docs/ru/Architecture/HighLevel/ui.md) Интерфейсы в движке являются частью сцены и основаны на её парадигме. Базовым элементом UI служит `o2::Widget` (наследник `o2::Actor`), который переопределяет логику актора: - **Адаптивная верстка:** В трансформацию добавляются якоря, позволяющие гибко привязывать виджет к родителю для построения адаптивного интерфейса. - **Внутренние виджеты:** Внутри виджета могут находиться дочерние контролы, не являющиеся полноправными «детьми» в общей иерархии, что удобно для комплексных UI-элементов (например, окно с хедером и кнопкой закрытия). - **Система слоёв:** Виджет содержит слои (`o2::WidgetLayer`), которые имеют собственную графику (спрайт, текст и т. д.), трансформацию с якорями, иерархию вложенных слоёв и имена. Слои представляют упрощённый аналог акторов, облегчающий отрисовку и не загромождающий иерархию сцены. - **Анимационные состояния:** У виджета есть набор независимых состояний (по имени), каждое из которых может включаться/выключаться. При переключении состояния проигрывается анимация, заданная в коде или в редакторе (см. раздел анимаций). ### Layout-контейнеры Для создания адаптивного интерфейса используются специальные виджеты-контейнеры (`o2::HorizontalLayout`, `o2::VerticalLayout`, `o2::GridLayout`). Они упорядочивают дочерние элементы согласно заданным правилам, растягивая/сжимая их или подстраиваясь под размеры. ### Набор готовых виджетов В движке есть множество базовых UI-контролов: картинка, текст, кнопка, чекбокс, текстовое поле, прогресс-бары, скроллеры, списки (обычные и выпадающие), дерево, попап, окно и т. д. Поскольку UI-подсистема — это расширение системы сцены, её элементы могут сочетаться с любыми игровыми объектами. Собственно, весь редактор o2 построен на этой системе UI ([подробнее в статье на Habr](https://habr.com/ru/articles/521306/)). ================================================ FILE: Docs/ru/Editor/Animation/animation.md ================================================ ## Animation. Окно анимации ![animation](animation.png) В этом окне редактируется ассет анимаций. Функционал аналогичен другим редакторам анимаций, например Spine. В окне есть тулбар с типичным для таких редакторов функционалом: просмотр, запись, прокрутка, плей/стоп, режим кривых, список параметров и добавление ключа. Слева в окне отображен список параметров, повторяющих иерархию на сцене (4). Справа включи на таймлайне (3). Сверху от таймлайна управление временем анимации (2). ### Компонента анимации Чтобы добавить анимацию на актор, нужно добавить компоненту Animation через меню добавления компонент. В этом компоненте задается список анимаций (1), которые могут проигрываться одновременно. Если в нескольких анимациях анимируются одни и те же параметры, то вычисляется среднее, в зависимости от веса (Weight). Таким образом можно смешивать несколько анимаций и делать плавные переходы между ними. В каждой анимации задается ссылка ассет на анимацию (4). Ее можно выбрать из готового ассета, или создать ассет inplace. Чтобя отредактировать анимацию, можно нажать иконку карандаша (3) на заголовке анимации ### Параметры анимации Чтобы заанимировать какой-то параметр, нужно добавить его в анимацию. Для этого нужно кликнуть кнопку с полосками, откроется окно доступных параметров. В этом списке с помощью кнопок (+) и (-) можно добавлять или удалять анимируемые параметры. Анимировать можно все, что отображается в окне настроек Properties. ### Ключ и параметры \ Для каждого параметра выводится поле редактирования слева. На таймлайне столбиками отмечены ключи, в которых параметр явно задан. Между ключами происходит интерполяция, в зависимости от настройки кривой ### Настройка кривых ![Alt text](image-3.png) По клику на указанную на скриншоте кнопку в тулбаре, таймлайн перезодит в режим кривых. В нем отображаются кривые для числовых параметров. Они представляют из себя кривые безье, и редактируются как в аналогичных редакторах с помощью мышки. Зум и скролл делается как в сцене, левой кнопкой мыши и колесиком. ================================================ FILE: Docs/ru/Editor/Assets/assets.md ================================================ ## Assets. Окно ассетов ![assets](assets.png) В этом окне можно увидеть ассеты, которые есть в игре, отредактировать их или "вытащить" на сцену. Слева в окне отображена иерархия папок (2). Выбрав папку, в окне файлов (3) покажутся ассеты в выбранной папке. По кнопке (4) можно включать и выключать отображение папок. Сверху есть фильтр для поиска по имени (1). Ассеты и папки можно перемещать с помощью drag'n'drop в папки. Можно копировать, вставлять и удалять. Функционал практически аналогичен типичному обозревателю файлов в ОС. Создавать новые ассеты можно через контекстное меню, пункт Create. По клику на ассет его можно выделить, и тогда в окне Properties покажутся его настройки. Там, например, можно изменять параметры атласов и текстур, стили шрифтов. Для некоторых типов ассетов работает drag'n'drop в иерархию или сцену: текстуры и прототипы. Для этого их просто нужно перетащить в нужное место. ### Настройка текстур и атласов Выбрав нужный атлас или текстуру можно настроить их параметры. настройки отобразятся в окне Properties. Как только выделение с файла будет снято - он будет автоматически созранен (будет изменено на ручное сохранение) При выборе текстуры отображается ее превью, поверх которого можно отредактировать отступы для 9-slice спрайта. В поле Atlas задается ссылка на атлас, в который попадет текстура. Чтобы задать атлас, нужно его перетащить drg'n'drop-ом в это поле из окна ассетов. При выборе атласа показываются его параметры, так же в окне Properties. В нем есть общие настройки атласа (Common) и платформо-зависимые (вам это не нужно по идее). Внутри общих настроек можно задать максимальный размер страницы атласа (может быть упакован в несколько страниц), формат сжатия и отступы для текстур при упаковке. ================================================ FILE: Docs/ru/Editor/Game/game.md ================================================ ## Game. Окно игры В этом окне отображается игра, как будто она запущена отдельным приложением. Отрисовка происходит честно через камеры. Обрабатываются клики мышкой. Сверху в панели можно выбрать эмулируемое разрешение экрана ================================================ FILE: Docs/ru/Editor/Log/log.md ================================================ ## Log. Окно логов ![log](log.png) В этом окне отображаются логи, выведенные через систему отладки движка. Логи разделены по важности: - обычные - предупреждения (желтый) - ошибки (красный) И выведены списком в порядке их появления (1). Логи можно очистить (2), отключить отображение по важности (3) (4) (5). В строке снизу показано последнее сообщение лога (6). ================================================ FILE: Docs/ru/Editor/Properties/properties.md ================================================ ## Properties. Окно настроек В этом окне происходит настройка выбранной сущности. Это может быть ассет, какие-либо настройки или актор. на скриншоте показан пример актора с типом Widget. Особенностбю является возможность редактирования нескольких выбранных сущностей сразу. В таком случае редактор пытается отобращить общие поля и общие значения. Если он не находит общего, или эти значения различаются, то ничего не отображается или показывается прочерк вместо значения Редактор умеет показывать много типов полей, включая пользовательские: - числа, строки, bool, enum - массивы - вложенные объекты по значению - вложенные обхекты по указателю. Доступно удаление и создание с выбором типа - ссылки на другие акторы. Назначаются через drag'n'drop из иерархии - ссылки на ассеты. Назначаются через drag'n'drop из окна ассетов, либо создаются inplace. Это значит ассет сохраняется вместе с актором. ### (1) Заголовок Здесь отображена основная информация по актору - активность (кружок слева сверху), имя, теги, слой, залочка. Все эти контролы доступны для редактирования. ### (2) Трансформация Здесь отображаются параметры локальной трансформации выбранного актора: - Позиция - Pivot - Размеры - Скейл - Поворот и слой - Layout: настройка динамической верстки для виджетов ### (3) Настройки актора Если редактируется не сам o2::Actor, а его наследник, тогда показываются его параметры. На примере в скриншоте показан коэффициент прозрачности и список состояний виджета. Настройки берутся их актора через рефлексию. По умолчанию показываются все публичные поля. Так же отмеченные специальным тегом в коде ### (4) Компоненты Далее списокм поблочно показаны параметры компонентов. Точно так же показываются публичные поля, заданные в компоненте. Через крестик можно удалить компонент ### (5) Меню добавления компоненты По клику в это меню оно раскрывается, внутри показано дерево компонент. Через строку ввода можно отфильтровать по имени. По дабл-клику или клавише Enter выбранный тип компонента добавляется на выбранный актор ================================================ FILE: Docs/ru/Editor/Scene/scene.md ================================================ ## Scene. Окно сцены В этом окне отображаются акторы на сцене в порядке расположения на слоях, вне зависимости от камеры. Сцену можно скроллить и зумить. Скролл через зажатую левую кнопку мыши, зум колесиком. на фоне нарисована сетка, которая показывает кратные 10ти юниты сцены. Левой кнопкой мыши можно выбирать акторы. Если кликать в одну точку, выбор происходит циклически от верхнего к нижнему. Таким образом можно выбрать нужную ноду в иерархии кликнув несколько раз. Так же отображается активный тул (2), выбранный в тулбаре. Он интерактивный, работает так же как и в других редакторах. У активного тула может включаться специальный режим через зажатике клавиш Shift/Ctrl/Alt. Среди них - снеппинг, выравнивание по осям и др. ### Слои В окне сцены можно настроить слои и их порядок. Для этого нужно кликнуть Layers сверху (1). В выпадающем меню можно их пересортировать через drag'n'drop, создать новый, удалить старый, переименовать слой через дабл-клик, включить/выключить галкой. ================================================ FILE: Docs/ru/Editor/Tree/tree.md ================================================ ## Tree. Окно иерахии Окно иерархии может работать в двух режимах: иерархия сцены и порядок отрисовки. режимы переключаются по кнопке (2). ### Режим сцены: Основная часть окна - это иерархия сцены. Каждая строка - отдельный актор. Сверху есть фильтр по имени (1). В строке каждого актора (3) отображается его имя, которое можно редактировать по дабл-клику. Так же отображается его активность (5). Яркий заполненный кружок - нода активна. Пустой тусклый кружок (6) - нода не активна. Полный, но тусклый кружок (7) - сама нода активна, но тк кто-то из ее родителей не активен, она считается не кативной. Залочка выбора в сцене (4). Иногда полезно отключать выбор в сцене для некоторых частей иерархии, чтобы они не мешались. Так же может быть отображен значок звена цепи (8) - это значит что актор создан из прототипа. По клику на эту иконку, в окне Assets подсветится прототип Акторы можно перетаскивать через drag'n'drop. Для этого нужно зажать мышкой нужный актор (или несколько) и начать перемещать. Наведя на нужно место нужно отпустить мышку. При нажатии правой кнопки мыши откроется контекстное меню. В нем обозначены хоткеи на доступные действия. Для их работы окно Tree или Scene должны быть в фокусе. Если они в фокусе - то выбранные акторы подсечиваются зеленым цветом, иначе серым. Через контекстное меню можно создавать новые акторы. Для этого можно выбрать Create empty actor, для создания пустого актора, либо выбрать нужный тип через меню Create. ### Режим порядка отрисовки В этом режиме отображается иерархия отрисовки и ее порядок. На первом уровне показан список камер. В данном примере она одна - Camera. Внутри каждой камеры есть слои, в порядке их отрисовки - Background, Reels, Frame, GUI. Внутри слоев отсортированный список рисуемых сущностей, с приоритетом в конце строки. С 0-м приоритетом всегда отображается Layer roots - это контейнер обхектов, у которых не установлен числовой приоритет. Эти сущности тоже могут содержат в себе сущности, если они наследуют приоритет отрисовки от родителя. Цветом отмечены раздельные батчи, в конце которых добавляется строка End of batch #N, где N - это номер батча Для изменения очередности отрисовки можно перемещать объекты через drag'n'drop. ================================================ FILE: Docs/ru/Editor/editor.md ================================================ ## Редактор Редактор - это место, где верстается сцена и создается контент для игры. В нем есть внутренние окна, которые могут быть прикреплены друг другу, а так же вложены в несколько вкладок. Эти окна можно перемещать, прицеплять к другим окнам (таскать за заголовок окна) и складывать во вкладки (дабл-клик в заголовок). Редактор может работать в двух режимах: редактирование и игра. В первом режиме сцена загружена, но не получает апдейт и как бы находится в статичном состоянии. В таком режиме ее можно редактировать и сохранять. Во втором режиме - режиме игры - можно проверить работу сцены, все отображаются в редакторе, но происходит обновление и обрабатывает инпут в окне игры. В это время сцену сохранять нельзя. Рассмотрим окна и элементы, которые есть в редакторе в раскладке по умолчанию: ![editor](editor.png) - (1) панель запуска сцены. При нажатии на Play оно разворачивается и позволяет поставить игру на паузу и проиграть один кадр. Выпадающий список не функционален, подразумевает запуск на других устройствах. - (2) панель утилит. Выбирается активный тул, который переключает режим редактирования в сцене - (3) [Tree](/Docs/ru/Editor/Tree/tree.md). Окно иерархии сцены. Показыввает акторы и их детей в сцене - (4) [Scene](/Docs/ru/Editor/Scene/scene.md). Окно редактирования сцены - (5) [Properties](/Docs/ru/Editor/Properties/properties.md). Окно настроек выбранного объекта - (5) [Game](/Docs/ru/Editor/Game/game.md). Окно игры, эмулирует вывод графики и обработку ввода как будто приложение запущено отдельно - (6) [Assets](/Docs/ru/Editor/Assets/assets.md). Окно ассетов, в нем можно перемещать, редактировать и просматривать ассеты - (6) [Log](/Docs/ru/Editor/Log/log.md). Окно лога, в него выводятся отладочные сообщения - (6) [Animation](/Docs/ru/Editor/Animation/animation.md). Редактор анимации, в нем редактируются ключи, параметры и кривые ================================================ FILE: Docs/ru/main.md ================================================ ## Мотивация Движок создается как профессиональный инструмент для разработки мобильных 2D игр. Его дизайн строится из двух ключевых направлений: скорость разработки и производительность. Скорость разработки обеспечивается удобством API, редактором и скриптовым языком. - Удобное API означает что оно покрывает все необходимые кейсы разработчика, его легко понять и использовать. В нем минимум подводных камней, оно интуитивно понятно. Во многом ориентиром было внутреннее API движка Unity3D. - Редактор предоставляем весь необходимый функционал для разработки игр: сцена, ассеты, параметры, анимации, частицы. Он удобный и следует современным стандартам движокв с редакторами: Unity3D, Unreal Engine, Unigine, etc - Скриптовый язык упрощает написание игровой логики, делает API движка еще доступнее. В о2 для скриптов выбран JavaScript и TypeScript, т.к. это довольно распространенные языки, особенно среди Web разработчиков, у которых очень мало доступных игровых движков Произодвительность обеспечивается тем что сам движок написан на С++ и позволяет писать игровую логику на С++. Так же в движке есть разделение на уровни абстракций, и для достижения максимальной производительности разработчик может использовать низкоуровневые подсистемы движка напрямую: рендер, загрузка ресурсов и тд. Комбинация всех этих подходов обеспечивает эффективную разработку игр, быстрое прототипирование, при этом сохраняя высокую планку технического качества ## Общая концепция движка Базовой концепцией движка является сцена с компонентным подходом. В сцене выстраивается древовидная структура из акторов, имеющих определенный тип. Акторы имеют трансформацию, зависящую от родителя, а так же набор компонент, определяющих поведение и отрисовку. Отрисовка сцены делится на слои, акторы могут занимать определнные слои или наследовать приоритет отрисовки от родителя. Сцена и ее ассеты настраиваются в редакторе. Код акторов, компонент и игры пишется на С++ или скриптовом языке (JS/TS). Подсистема сцены является врехнеуровневой и одна основывается на низкоуровневых подсистемах: ассеты, приложение, рендер, анимации, физика, скрипты, инпут. При работе с верхним уровнем можно использовать низкий уровень напрямую для достижения наибольших оптимизаций. Например, если требуется отобразить большое количество спрайтов, вместо использования множества тяжеловесных акторов использовать один актор, отрисовывающий множество спрайтов напрямую через низкоуровневый рендер Низкий уровень основывается на утилитах, обеспечивающих поддержку всех подсистем: менеджмент памяти, рефлексия, сериализация, проперти, математика, файловая система, отладка и логгирование. ## Концепция интеграции о2 в другие движки Движок о2 можно использовать не только как самостоятельный движок, но и как встраиваемый. По сути он встраивается в игровой цикл другого движка, в его рендер и обработку инпута, и взаимодействет с ним с определенными разграничениями. Есть два подхода: главенстрвующий и ведомый. В первом случае движок о2 оборачивает внутри себя другой движок, подчиняя себе его обработку инпута, обновление кадра и рендеринг. Это предпочтительный способ. Во втором случае все наоборот, о2 встраивается в игровой цикл другого движка. Как правило другие движки так же имеют иерархию сцены. Движок о2 так же может работать и с ней, если отнаследовать базовый объект иерархии движка от определенного интерфейса о2. Это позволит отобразить иерархию другого движка прямо в редакторе о2, а так же даст возможность редактировать параметры объектов. Они станут доступны через рефлексию Важно чтобы в другом движке использовалось то же render api, что и в o2. В крайнем случае возможна реализация подистсемы рендера под конкретную имплементацию в другом движке. Ведь по сути от нее нужен вывод мешей треугольников с текстурой и шейдером. Как правило в других движках этот функционал вынесен в отдельное API. ## Документация - [Архитектура](/Docs/ru/Architecture/architecture.md) - [Редактор](/Docs/ru/Editor/editor.md) - [Цикл видео-туториалов по настройке тестовой сцены слот-игры](https://drive.google.com/drive/folders/1m-lgSaM2hYQxbKnIwymDfMCe3SzjKrP1?usp=sharing) ================================================ FILE: Editor/Assets/BasicAtlas.atlas ================================================ { "mPages": [ { "mSize": { "x": 2048, "y": 2048 }, "mImagesRects": [ { "Key": "32ad3f000a6b5fda39ad54624dcd1faa", "Value": { "left": 350, "bottom": 1776, "right": 370, "top": 1796 } }, { "Key": "4ca64f006ea3650561c405895d7c75bf", "Value": { "left": 56, "bottom": 1884, "right": 106, "top": 1934 } }, { "Key": "57ac6501709c48d3787b437546946c28", "Value": { "left": 15, "bottom": 1560, "right": 65, "top": 1610 } }, { "Key": "030001020f840bd92b4509cd2d577559", "Value": { "left": 1645, "bottom": 1800, "right": 1665, "top": 1820 } }, { "Key": "478514024c9c0cb854b9126c2f2d2607", "Value": { "left": 1961, "bottom": 1830, "right": 1981, "top": 1850 } }, { "Key": "72381902329400821187457f66005e84", "Value": { "left": 997, "bottom": 1800, "right": 1017, "top": 1820 } }, { "Key": "36942f0200314c5e55a2550f113325d4", "Value": { "left": 422, "bottom": 1800, "right": 442, "top": 1820 } }, { "Key": "307655027af95f14370c2ffc61632f01", "Value": { "left": 575, "bottom": 1884, "right": 600, "top": 1909 } }, { "Key": "1b293703451e37d706fb7748469e08bb", "Value": { "left": 1046, "bottom": 1776, "right": 1066, "top": 1796 } }, { "Key": "6c7d7204331f14d86774363220a767b0", "Value": { "left": 661, "bottom": 1858, "right": 681, "top": 1878 } }, { "Key": "52e145054c0f496f3aa67d424e485af4", "Value": { "left": 1265, "bottom": 1830, "right": 1286, "top": 1850 } }, { "Key": "31a9020630255cc11b236fe16025516a", "Value": { "left": 1525, "bottom": 1800, "right": 1545, "top": 1820 } }, { "Key": "19f1480664de4c0b1d4f58ef04ba19e4", "Value": { "left": 518, "bottom": 1800, "right": 538, "top": 1820 } }, { "Key": "4e5b4e066f10548e335210236af46e01", "Value": { "left": 1722, "bottom": 1830, "right": 1742, "top": 1850 } }, { "Key": "49be56066b956738561b3410432148f6", "Value": { "left": 592, "bottom": 1938, "right": 622, "top": 1968 } }, { "Key": "699b04077c1b0a016a8f17de78fb4bf8", "Value": { "left": 1772, "bottom": 1992, "right": 1812, "top": 2032 } }, { "Key": "733601084caf34553ee648723c4f35be", "Value": { "left": 2, "bottom": 1128, "right": 12, "top": 1178 } }, { "Key": "681b1d0846ca2cf9407570075db31a2d", "Value": { "left": 2, "bottom": 1290, "right": 52, "top": 1340 } }, { "Key": "32794f087da131ca780428ad6fd463fa", "Value": { "left": 473, "bottom": 1918, "right": 485, "top": 1930 } }, { "Key": "2b19000955c963fd6c0b0af07fae2676", "Value": { "left": 56, "bottom": 1992, "right": 65, "top": 2042 } }, { "Key": "3ecc3c09309b6acd07400dab40ba53a5", "Value": { "left": 1429, "bottom": 1800, "right": 1449, "top": 1820 } }, { "Key": "142469090bcb20c24bd227f674f20695", "Value": { "left": 2029, "bottom": 1800, "right": 2039, "top": 1820 } }, { "Key": "41df300a33bc6fe365c7553102276156", "Value": { "left": 1169, "bottom": 1830, "right": 1189, "top": 1850 } }, { "Key": "6371320a681e22eb5e37519315ad40b5", "Value": { "left": 562, "bottom": 1830, "right": 582, "top": 1850 } }, { "Key": "2640510a17026a0e32b31efd3c402c0d", "Value": { "left": 329, "bottom": 1918, "right": 341, "top": 1930 } }, { "Key": "788e1b0b00887b2d07756cbf62855cb3", "Value": { "left": 297, "bottom": 1918, "right": 309, "top": 1930 } }, { "Key": "1f344e0b73185347370b0778377d49a9", "Value": { "left": 958, "bottom": 1938, "right": 988, "top": 1968 } }, { "Key": "1f21370c782109b823d11e4a317c06ac", "Value": { "left": 1022, "bottom": 1776, "right": 1042, "top": 1796 } }, { "Key": "32a2400c7dcb7aaf29e3729e0015524c", "Value": { "left": 1643, "bottom": 1858, "right": 1663, "top": 1878 } }, { "Key": "36e2240d67b63628380f00e10ff525e4", "Value": { "left": 948, "bottom": 1830, "right": 968, "top": 1850 } }, { "Key": "07df580d646f523814fb1dfa1a032880", "Value": { "left": 662, "bottom": 1776, "right": 682, "top": 1796 } }, { "Key": "2b72590d15f550c512e446de2cd73200", "Value": { "left": 374, "bottom": 1858, "right": 394, "top": 1878 } }, { "Key": "2cfd7d0d00a7628202907e0d10d33253", "Value": { "left": 1434, "bottom": 1830, "right": 1454, "top": 1850 } }, { "Key": "42f7050e392b57a01bda55e42a101505", "Value": { "left": 106, "bottom": 322, "right": 206, "top": 422 } }, { "Key": "2bea1b0e0dc334ef4d7d73907776492b", "Value": { "left": 686, "bottom": 1776, "right": 706, "top": 1796 } }, { "Key": "702f3b0e291b134e7fe656243bd33b7d", "Value": { "left": 974, "bottom": 1776, "right": 994, "top": 1796 } }, { "Key": "51ce450e4dde5a940e313b1f579833ec", "Value": { "left": 558, "bottom": 1938, "right": 588, "top": 1968 } }, { "Key": "121e600f2a8b13aa511c2b4a11693ee9", "Value": { "left": 138, "bottom": 1830, "right": 162, "top": 1854 } }, { "Key": "5ffb001041e4477b5e952bda0c994001", "Value": { "left": 1571, "bottom": 1858, "right": 1591, "top": 1878 } }, { "Key": "591f03127b42058b52b7551d506b43d4", "Value": { "left": 302, "bottom": 1938, "right": 342, "top": 1978 } }, { "Key": "68ca46120340458a6165262e65215b32", "Value": { "left": 134, "bottom": 1858, "right": 154, "top": 1878 } }, { "Key": "4b426c1230e851bb43645f874af90c0f", "Value": { "left": 350, "bottom": 1858, "right": 370, "top": 1878 } }, { "Key": "5a320d131c7e7d0e31c272165b195cd1", "Value": { "left": 755, "bottom": 1830, "right": 776, "top": 1850 } }, { "Key": "27c90e13537260835a33574067e879b0", "Value": { "left": 1549, "bottom": 1800, "right": 1569, "top": 1820 } }, { "Key": "7b5d00142e125b0b2fcb6ab768015af3", "Value": { "left": 643, "bottom": 2036, "right": 649, "top": 2042 } }, { "Key": "2b7c7314787e224a2d4e36000b1f2754", "Value": { "left": 518, "bottom": 1776, "right": 538, "top": 1796 } }, { "Key": "2e1f151556f90d6c00794feb232c0812", "Value": { "left": 398, "bottom": 1858, "right": 418, "top": 1878 } }, { "Key": "6bd46d174c5778235f036c466a14569c", "Value": { "left": 566, "bottom": 1776, "right": 586, "top": 1796 } }, { "Key": "4bba69197e1d50a716f838f4297a08c6", "Value": { "left": 1835, "bottom": 1858, "right": 1855, "top": 1878 } }, { "Key": "2b793b1a747167266984178a32e32d37", "Value": { "left": 1938, "bottom": 1830, "right": 1957, "top": 1850 } }, { "Key": "5ed83b1a2d9554e654d616f1125770aa", "Value": { "left": 1023, "bottom": 1918, "right": 1034, "top": 1929 } }, { "Key": "31d11d1b4ae008106f8569b959e72e8c", "Value": { "left": 854, "bottom": 1776, "right": 874, "top": 1796 } }, { "Key": "37cf2b1b28ac5e1b0272688960da3faa", "Value": { "left": 350, "bottom": 1800, "right": 370, "top": 1820 } }, { "Key": "0804451b664226dd06421c3039062bea", "Value": { "left": 398, "bottom": 1800, "right": 418, "top": 1820 } }, { "Key": "53b81d1c1d7b359b7833213467275026", "Value": { "left": 129, "bottom": 1918, "right": 144, "top": 1933 } }, { "Key": "1813201c420a5b7b05ae23f244553190", "Value": { "left": 1985, "bottom": 1830, "right": 2005, "top": 1850 } }, { "Key": "1b582c1d0d7c08d64ec65c182cf83ea7", "Value": { "left": 394, "bottom": 1830, "right": 414, "top": 1850 } }, { "Key": "7fae2e1d1d9245d2651a47c07c2868cb", "Value": { "left": 890, "bottom": 1938, "right": 920, "top": 1968 } }, { "Key": "69204e1d69a568237d6a5d6a1b7a3ef1", "Value": { "left": 2, "bottom": 110, "right": 13, "top": 214 } }, { "Key": "30c44f1d3a020549091368ee10242557", "Value": { "left": 230, "bottom": 1800, "right": 250, "top": 1820 } }, { "Key": "72082a1f02b2369a6ebe44f326513324", "Value": { "left": 1884, "bottom": 1800, "right": 1904, "top": 1820 } }, { "Key": "200f651f024d34763b852794303a23d2", "Value": { "left": 2, "bottom": 1938, "right": 52, "top": 1988 } }, { "Key": "6eab1f21570e74c279d81a6629376682", "Value": { "left": 1097, "bottom": 1830, "right": 1117, "top": 1850 } }, { "Key": "1a36752146b9557f7cd761ba79d47e94", "Value": { "left": 158, "bottom": 1800, "right": 178, "top": 1820 } }, { "Key": "3ed409235a342972306c7b0933647511", "Value": { "left": 1331, "bottom": 1858, "right": 1351, "top": 1878 } }, { "Key": "6e971e235a7c5b2101a4317503c85537", "Value": { "left": 16, "bottom": 1128, "right": 66, "top": 1178 } }, { "Key": "1db20a2430920e752fbe48f84c6c26f4", "Value": { "left": 924, "bottom": 1884, "right": 949, "top": 1909 } }, { "Key": "6fd46d247f183bac5c7f17e55d937922", "Value": { "left": 434, "bottom": 1884, "right": 484, "top": 1909 } }, { "Key": "44b9252613bf763933ae3d0e36504f91", "Value": { "left": 623, "bottom": 2036, "right": 629, "top": 2042 } }, { "Key": "0540372660dd761419143ca574cb27e4", "Value": { "left": 182, "bottom": 1800, "right": 202, "top": 1820 } }, { "Key": "5f5841267c8d387d7de441cf5c97258b", "Value": { "left": 804, "bottom": 1858, "right": 824, "top": 1878 } }, { "Key": "31e057267cbf1b5444701f1722b74eb2", "Value": { "left": 566, "bottom": 1858, "right": 586, "top": 1878 } }, { "Key": "124c7226031f44cd20fe5a9b6c5d1ac2", "Value": { "left": 1162, "bottom": 1938, "right": 1192, "top": 1968 } }, { "Key": "07f6672722551dc57802769e0a7a4c8d", "Value": { "left": 1482, "bottom": 1830, "right": 1502, "top": 1850 } }, { "Key": "2b5175271de526a5147d745d6ea900f7", "Value": { "left": 780, "bottom": 1858, "right": 800, "top": 1878 } }, { "Key": "3f02032807bd607762ab0ee748924b0c", "Value": { "left": 1355, "bottom": 1858, "right": 1375, "top": 1878 } }, { "Key": "44b8262876e4683548b83b554e544bd7", "Value": { "left": 1794, "bottom": 1830, "right": 1814, "top": 1850 } }, { "Key": "0a1b49284a84494d362b7baf1181176b", "Value": { "left": 295, "bottom": 1884, "right": 314, "top": 1910 } }, { "Key": "311766284f1a03f22a5646697a2b6471", "Value": { "left": 1594, "bottom": 1918, "right": 1624, "top": 1926 } }, { "Key": "2e3a772860da3b1d3db2226504fe236f", "Value": { "left": 734, "bottom": 1800, "right": 754, "top": 1820 } }, { "Key": "7ba135291ad820ae241238582e671ba2", "Value": { "left": 2, "bottom": 1614, "right": 11, "top": 1664 } }, { "Key": "7308512942a4704708ca55320bc953a9", "Value": { "left": 346, "bottom": 1830, "right": 366, "top": 1850 } }, { "Key": "7b175e291a460aec259d179c58511101", "Value": { "left": 278, "bottom": 1800, "right": 298, "top": 1820 } }, { "Key": "017a2a2a1df6218e168766c171e65c33", "Value": { "left": 230, "bottom": 1776, "right": 250, "top": 1796 } }, { "Key": "3d92112b49ba16f46aa3249767164401", "Value": { "left": 1115, "bottom": 1858, "right": 1135, "top": 1878 } }, { "Key": "41d93c2b3a39274a7d35039540fe3aab", "Value": { "left": 1168, "bottom": 1992, "right": 1208, "top": 2032 } }, { "Key": "79ab3e2b2d254269187d39fd7f766955", "Value": { "left": 667, "bottom": 1992, "right": 707, "top": 2032 } }, { "Key": "4126572b2947687f44c94e68660d1bca", "Value": { "left": 769, "bottom": 1884, "right": 794, "top": 1909 } }, { "Key": "3c407b2b46f807e6602877a4259c2a79", "Value": { "left": 2, "bottom": 1560, "right": 11, "top": 1610 } }, { "Key": "005b202c650949397c95564d0de102f5", "Value": { "left": 245, "bottom": 1992, "right": 295, "top": 2042 } }, { "Key": "16aa3d2c44704f5d76fb7ba26d833596", "Value": { "left": 1309, "bottom": 1800, "right": 1329, "top": 1820 } }, { "Key": "10d90c2d06855e3e6f8d34405b4b079a", "Value": { "left": 1588, "bottom": 1938, "right": 1618, "top": 1968 } }, { "Key": "7260312d19e92c0d40c307a13e7355ed", "Value": { "left": 110, "bottom": 1830, "right": 134, "top": 1854 } }, { "Key": "0824232e6191377627b702fc0f552603", "Value": { "left": 855, "bottom": 1918, "right": 866, "top": 1929 } }, { "Key": "2e3d582e085c21d943eb68c334e954c8", "Value": { "left": 1787, "bottom": 1858, "right": 1807, "top": 1878 } }, { "Key": "52c8772f641a30933b5c46be47a80b53", "Value": { "left": 1798, "bottom": 1884, "right": 1824, "top": 1909 } }, { "Key": "1b6724306a1b40cf2115319d1c381026", "Value": { "left": 1050, "bottom": 1884, "right": 1100, "top": 1909 } }, { "Key": "33cb3c3034c56e73099d2edc35ec4dbc", "Value": { "left": 1404, "bottom": 1992, "right": 1444, "top": 2032 } }, { "Key": "35d73d3060ef522f728d654c31bb3732", "Value": { "left": 1410, "bottom": 1918, "right": 1419, "top": 1927 } }, { "Key": "4d7c59300b78244b250b3f14794f7c30", "Value": { "left": 830, "bottom": 1776, "right": 850, "top": 1796 } }, { "Key": "304562300aa144977c64737149537ad6", "Value": { "left": 56, "bottom": 1074, "right": 106, "top": 1124 } }, { "Key": "221859314013209c72795c99260719ed", "Value": { "left": 1635, "bottom": 1884, "right": 1685, "top": 1909 } }, { "Key": "12a80f3344a31e2d3354161c2f944638", "Value": { "left": 488, "bottom": 1884, "right": 513, "top": 1909 } }, { "Key": "74f605357436654a0cdb0ba9699d3617", "Value": { "left": 1788, "bottom": 1800, "right": 1808, "top": 1820 } }, { "Key": "435138351b066b1e08794d583f1a5840", "Value": { "left": 710, "bottom": 1800, "right": 730, "top": 1820 } }, { "Key": "00533d362a0c38c31f4d66921cac0be6", "Value": { "left": 1141, "bottom": 1800, "right": 1161, "top": 1820 } }, { "Key": "1efa5a3609e93b26740d4bbf59860925", "Value": { "left": 69, "bottom": 1992, "right": 119, "top": 2042 } }, { "Key": "684c733646a47f364a4c3fc716dd5c63", "Value": { "left": 318, "bottom": 1884, "right": 343, "top": 1910 } }, { "Key": "59ea323733796f7b522f19622984279d", "Value": { "left": 326, "bottom": 1800, "right": 346, "top": 1820 } }, { "Key": "1aad7e376c1866741eec7af66d88718e", "Value": { "left": 1211, "bottom": 1858, "right": 1231, "top": 1878 } }, { "Key": "3e3b1639646b2d8435c4415d5d424648", "Value": { "left": 1165, "bottom": 1800, "right": 1185, "top": 1820 } }, { "Key": "6338023a6c50328d3bab0bb453f864cf", "Value": { "left": 830, "bottom": 1800, "right": 850, "top": 1820 } }, { "Key": "2726133a77804ef50abf7de97d40637b", "Value": { "left": 1290, "bottom": 1830, "right": 1310, "top": 1850 } }, { "Key": "3ccc453a1b03741164900bd765750438", "Value": { "left": 494, "bottom": 1800, "right": 514, "top": 1820 } }, { "Key": "0ca3463a618a4f0e52eb0cd473541835", "Value": { "left": 1020, "bottom": 1830, "right": 1040, "top": 1850 } }, { "Key": "0096333b50663c5276a9663e2ae53701", "Value": { "left": 1746, "bottom": 1830, "right": 1766, "top": 1850 } }, { "Key": "54aa383b507022dd4d0b371f2a8b24d2", "Value": { "left": 225, "bottom": 1918, "right": 239, "top": 1932 } }, { "Key": "749b253c0a4659251eb1169857b81aa6", "Value": { "left": 825, "bottom": 1918, "right": 836, "top": 1929 } }, { "Key": "3c40393d03af1c4760f92eee1a6666f3", "Value": { "left": 971, "bottom": 1858, "right": 991, "top": 1878 } }, { "Key": "69de633d136b4c903d2d39f74bc7566a", "Value": { "left": 446, "bottom": 1858, "right": 466, "top": 1878 } }, { "Key": "25803a3e06cc40b82fcf214a2d4e3db6", "Value": { "left": 1770, "bottom": 1830, "right": 1790, "top": 1850 } }, { "Key": "6d66543e4b014c561fc16c7c7b792e44", "Value": { "left": 393, "bottom": 1918, "right": 405, "top": 1930 } }, { "Key": "7fed733e18332f2d647354bf375820be", "Value": { "left": 768, "bottom": 1938, "right": 798, "top": 1968 } }, { "Key": "52375c3f583904686b61698f023f6fdd", "Value": { "left": 566, "bottom": 1800, "right": 586, "top": 1820 } }, { "Key": "0b78004054635ed540d678bc332c3c87", "Value": { "left": 1307, "bottom": 1858, "right": 1327, "top": 1878 } }, { "Key": "3a5d434026851c7718a1233d0ab2013f", "Value": { "left": 110, "bottom": 1938, "right": 210, "top": 1978 } }, { "Key": "602a754042293ca8784648ab0974477d", "Value": { "left": 1453, "bottom": 1800, "right": 1473, "top": 1820 } }, { "Key": "11871a410d053f797d83262c17f5568c", "Value": { "left": 56, "bottom": 1020, "right": 106, "top": 1070 } }, { "Key": "5f42584132dd50f7040b468c35b633da", "Value": { "left": 926, "bottom": 1776, "right": 946, "top": 1796 } }, { "Key": "233c0d4269646e2f31e71b8d5d1e5fc4", "Value": { "left": 806, "bottom": 1800, "right": 826, "top": 1820 } }, { "Key": "0064294220b1273b6b9152523b963cdc", "Value": { "left": 1118, "bottom": 1918, "right": 1168, "top": 1927 } }, { "Key": "62dd34421c60266949cd2c982d905c03", "Value": { "left": 1410, "bottom": 1830, "right": 1430, "top": 1850 } }, { "Key": "10b54243335e704f02303c8959e84535", "Value": { "left": 106, "bottom": 738, "right": 176, "top": 809 } }, { "Key": "041862435ce94df953a73a501775426b", "Value": { "left": 1397, "bottom": 1918, "right": 1406, "top": 1927 } }, { "Key": "22fc284427297a99761a2732351e3bcd", "Value": { "left": 1241, "bottom": 1830, "right": 1261, "top": 1850 } }, { "Key": "6c0b3f44539347465fbc4ca23cfd630b", "Value": { "left": 1139, "bottom": 1858, "right": 1159, "top": 1878 } }, { "Key": "391d434423a375d232167252668112c2", "Value": { "left": 1692, "bottom": 1800, "right": 1712, "top": 1820 } }, { "Key": "328477442d7b256a29de46ec652366a7", "Value": { "left": 720, "bottom": 1918, "right": 731, "top": 1929 } }, { "Key": "06be084535be030858333acf49d92db4", "Value": { "left": 166, "bottom": 1830, "right": 190, "top": 1854 } }, { "Key": "6e5320454c85738663ce23b55dbd4dfa", "Value": { "left": 828, "bottom": 1858, "right": 848, "top": 1878 } }, { "Key": "698b294551681f373f3a5d233f7c048d", "Value": { "left": 996, "bottom": 1830, "right": 1016, "top": 1850 } }, { "Key": "7112354647cc3b075496797f0e634a33", "Value": { "left": 1226, "bottom": 1918, "right": 1274, "top": 1927 } }, { "Key": "1a1a5d462ec011d23a095fa761211711", "Value": { "left": 2, "bottom": 1992, "right": 52, "top": 2042 } }, { "Key": "50600547271f4d2f38d4282109604b00", "Value": { "left": 1461, "bottom": 1884, "right": 1481, "top": 1909 } }, { "Key": "55612948208b611c6518424a33152bfc", "Value": { "left": 1193, "bottom": 1830, "right": 1213, "top": 1850 } }, { "Key": "03a5164927dd0e7d254555f3454f1205", "Value": { "left": 1859, "bottom": 1858, "right": 1879, "top": 1878 } }, { "Key": "423a2e4971d01ef40b016611069c7e89", "Value": { "left": 1818, "bottom": 1830, "right": 1838, "top": 1850 } }, { "Key": "60bf6b496ccd45d944ec41184aeb62c6", "Value": { "left": 470, "bottom": 1776, "right": 490, "top": 1796 } }, { "Key": "04d6224a54773744177e575760953423", "Value": { "left": 924, "bottom": 1830, "right": 944, "top": 1850 } }, { "Key": "3413234a0ae275d734b158ae52574be2", "Value": { "left": 613, "bottom": 1858, "right": 633, "top": 1878 } }, { "Key": "6e031d4c1377202c3a5a783240f55e49", "Value": { "left": 637, "bottom": 1858, "right": 657, "top": 1878 } }, { "Key": "7167574c690f33d1144a07d126c80813", "Value": { "left": 923, "bottom": 1858, "right": 943, "top": 1878 } }, { "Key": "25896a4c65bb6d021da41e1540b5348f", "Value": { "left": 1724, "bottom": 1938, "right": 1774, "top": 1968 } }, { "Key": "4392114d25d616c562b14a96373a52bb", "Value": { "left": 2, "bottom": 1344, "right": 7, "top": 1394 } }, { "Key": "4694254d5c164bb85bae7b8c0ac82f28", "Value": { "left": 1674, "bottom": 1830, "right": 1694, "top": 1850 } }, { "Key": "2c77314d33f1336a1840362b2c9d1b2a", "Value": { "left": 1021, "bottom": 1800, "right": 1041, "top": 1820 } }, { "Key": "18664b4d2b3430cd005469184dcb7f59", "Value": { "left": 1333, "bottom": 1800, "right": 1353, "top": 1820 } }, { "Key": "7575594d29b11a772b430135450f1abe", "Value": { "left": 1908, "bottom": 1800, "right": 1928, "top": 1820 } }, { "Key": "765f0d4e10b21aec273c3d092d27126e", "Value": { "left": 110, "bottom": 1918, "right": 125, "top": 1933 } }, { "Key": "7c09624e7daa45ef4dd24628717942d5", "Value": { "left": 569, "bottom": 1992, "right": 619, "top": 2042 } }, { "Key": "2aed7e4e04982b9d10b05c736fb253fe", "Value": { "left": 626, "bottom": 1938, "right": 676, "top": 1968 } }, { "Key": "66ac154f1c1f06111075313339e66aa4", "Value": { "left": 1554, "bottom": 1830, "right": 1574, "top": 1850 } }, { "Key": "13cc3f4f45710a54352307ef5f001eef", "Value": { "left": 731, "bottom": 1830, "right": 751, "top": 1850 } }, { "Key": "0022335023a07b4b394c61236933222a", "Value": { "left": 1715, "bottom": 1858, "right": 1735, "top": 1878 } }, { "Key": "3aa5715005765c392f0e0bc013f82e10", "Value": { "left": 542, "bottom": 1858, "right": 562, "top": 1878 } }, { "Key": "15df295163e609cf295f4be120572807", "Value": { "left": 254, "bottom": 1776, "right": 274, "top": 1796 } }, { "Key": "731832515faa10846a4967e973b25d43", "Value": { "left": 691, "bottom": 1884, "right": 741, "top": 1909 } }, { "Key": "06a16251065b6c4308414f0b052c5a3b", "Value": { "left": 870, "bottom": 1918, "right": 881, "top": 1929 } }, { "Key": "6c06665158ed26e82d8306d04f9f73c4", "Value": { "left": 1448, "bottom": 1992, "right": 1488, "top": 2032 } }, { "Key": "17eb725123f5219028c552b8149f330c", "Value": { "left": 828, "bottom": 1830, "right": 848, "top": 1850 } }, { "Key": "078a5c5269ee695a722144d642937467", "Value": { "left": 1451, "bottom": 1858, "right": 1471, "top": 1878 } }, { "Key": "0f555e523e671f08741010d779e5363a", "Value": { "left": 1379, "bottom": 1858, "right": 1399, "top": 1878 } }, { "Key": "6f632454112e23a87ded0987767167d8", "Value": { "left": 56, "bottom": 1398, "right": 106, "top": 1448 } }, { "Key": "660054543ee938f231472c8a3e9115a2", "Value": { "left": 680, "bottom": 1938, "right": 730, "top": 1968 } }, { "Key": "782607554b0f21084ded5ae06a3d68b6", "Value": { "left": 409, "bottom": 1918, "right": 421, "top": 1930 } }, { "Key": "0824555552e83f137bea39715a717db2", "Value": { "left": 1523, "bottom": 1858, "right": 1543, "top": 1878 } }, { "Key": "6935315628ef0c881f764b0a5ba74fe7", "Value": { "left": 685, "bottom": 1858, "right": 704, "top": 1878 } }, { "Key": "59c96a567a71232e4a442a3f16462b5d", "Value": { "left": 2, "bottom": 218, "right": 102, "top": 318 } }, { "Key": "51ff7c566d413ee67fd406f012de66c1", "Value": { "left": 1689, "bottom": 1884, "right": 1740, "top": 1909 } }, { "Key": "13591d571afc12bf6d712ee753750268", "Value": { "left": 1314, "bottom": 1830, "right": 1334, "top": 1850 } }, { "Key": "657107580d8d6e2e2a095a9f3e5b2f5c", "Value": { "left": 1474, "bottom": 1938, "right": 1504, "top": 1968 } }, { "Key": "3bf440583f843a155ddd77b4244706a2", "Value": { "left": 542, "bottom": 1800, "right": 562, "top": 1820 } }, { "Key": "4b587658011b29bb03cd435336194c6c", "Value": { "left": 515, "bottom": 1992, "right": 565, "top": 2042 } }, { "Key": "2db22e592f981ca01e47235a71625654", "Value": { "left": 56, "bottom": 1236, "right": 66, "top": 1286 } }, { "Key": "74086a597ee67e91405c1a0b0efe419b", "Value": { "left": 222, "bottom": 1830, "right": 246, "top": 1854 } }, { "Key": "17a1715932ee790051a81af35bf310aa", "Value": { "left": 123, "bottom": 1992, "right": 173, "top": 2042 } }, { "Key": "5219235a0fc2622920a3158b12741171", "Value": { "left": 2033, "bottom": 1830, "right": 2043, "top": 1850 } }, { "Key": "60ed725a3d34272d059324b94e692036", "Value": { "left": 398, "bottom": 1776, "right": 418, "top": 1796 } }, { "Key": "0a77395b4cd81aed6a55012160e32ffe", "Value": { "left": 405, "bottom": 1884, "right": 430, "top": 1909 } }, { "Key": "13de255c0a0f177552c23a120e360df8", "Value": { "left": 1259, "bottom": 1858, "right": 1279, "top": 1878 } }, { "Key": "780a1a5d6ce91d64442a0f8f708e2023", "Value": { "left": 1690, "bottom": 1938, "right": 1720, "top": 1968 } }, { "Key": "3baa405d339f58ab636530c92f1310b4", "Value": { "left": 1764, "bottom": 1800, "right": 1784, "top": 1820 } }, { "Key": "7d843e5e0cde648337a05bb6623a2a00", "Value": { "left": 538, "bottom": 1830, "right": 558, "top": 1850 } }, { "Key": "67e9505e448369275b7a311b508f0755", "Value": { "left": 198, "bottom": 1884, "right": 228, "top": 1914 } }, { "Key": "3b9f525e4be211da376e4f8e667b4e95", "Value": { "left": 1529, "bottom": 1918, "right": 1538, "top": 1927 } }, { "Key": "5c8f735e0626703c68375587092b511f", "Value": { "left": 1309, "bottom": 1884, "right": 1319, "top": 1909 } }, { "Key": "780f085f12c9163638327be949611fc8", "Value": { "left": 254, "bottom": 1858, "right": 274, "top": 1878 } }, { "Key": "07ac3a5f2251088947083bce123839b9", "Value": { "left": 546, "bottom": 1884, "right": 571, "top": 1909 } }, { "Key": "18770e601cfa5abd72cb7b061296152f", "Value": { "left": 230, "bottom": 1858, "right": 250, "top": 1878 } }, { "Key": "00ed1560468115f6550541dc7ac54751", "Value": { "left": 299, "bottom": 1992, "right": 349, "top": 2042 } }, { "Key": "79bc326019263d237f137a627d8c1f45", "Value": { "left": 852, "bottom": 1830, "right": 872, "top": 1850 } }, { "Key": "78813a607702658230400ce6143a0a8f", "Value": { "left": 2009, "bottom": 1830, "right": 2029, "top": 1850 } }, { "Key": "6ca8496030160e99272a75a135454b85", "Value": { "left": 1019, "bottom": 1858, "right": 1039, "top": 1878 } }, { "Key": "77d5176139101e81137d499c70052ebc", "Value": { "left": 745, "bottom": 1884, "right": 765, "top": 1909 } }, { "Key": "2adb56610cab4d602fb6062b582b7c61", "Value": { "left": 1128, "bottom": 1938, "right": 1158, "top": 1968 } }, { "Key": "14466d616af14fdd3d94541c058c55ae", "Value": { "left": 798, "bottom": 1884, "right": 808, "top": 1909 } }, { "Key": "20d96f61176b2d6d7fb91235159d44f5", "Value": { "left": 973, "bottom": 1800, "right": 993, "top": 1820 } }, { "Key": "112077614d0305be65f907c538ca1f62", "Value": { "left": 1291, "bottom": 1918, "right": 1341, "top": 1927 } }, { "Key": "30f6096246af62b6395e17092ead3fa5", "Value": { "left": 1133, "bottom": 1884, "right": 1153, "top": 1909 } }, { "Key": "5b492262019075be60c50c7a7a8f4439", "Value": { "left": 1475, "bottom": 1858, "right": 1495, "top": 1878 } }, { "Key": "2a13006326f35cff2c0408dc48be0f54", "Value": { "left": 1145, "bottom": 1830, "right": 1165, "top": 1850 } }, { "Key": "4e9c0a6367712dc71d7864e112ee1073", "Value": { "left": 1066, "bottom": 1918, "right": 1086, "top": 1928 } }, { "Key": "4bfd046473e85477661226ea70543b7a", "Value": { "left": 490, "bottom": 1830, "right": 510, "top": 1850 } }, { "Key": "6031706418516c4355323b481f555675", "Value": { "left": 2027, "bottom": 1858, "right": 2046, "top": 1878 } }, { "Key": "32d449667c0b255a7aa57d1d3b6f0f44", "Value": { "left": 2, "bottom": 1830, "right": 52, "top": 1880 } }, { "Key": "318a6c664a451b14170075374d942536", "Value": { "left": 1669, "bottom": 1800, "right": 1688, "top": 1820 } }, { "Key": "650c7b66370f2b0460fe0509059666e4", "Value": { "left": 1104, "bottom": 1884, "right": 1129, "top": 1909 } }, { "Key": "67924967653217e15b5c266e4eed361d", "Value": { "left": 659, "bottom": 1830, "right": 679, "top": 1850 } }, { "Key": "4d345a677c6e5c0e41196c7568304c76", "Value": { "left": 887, "bottom": 1992, "right": 928, "top": 2032 } }, { "Key": "748d796725b867fd6135105725ee07d7", "Value": { "left": 206, "bottom": 1858, "right": 226, "top": 1878 } }, { "Key": "23a50e686362786770a2329c58d95ee2", "Value": { "left": 1508, "bottom": 1938, "right": 1516, "top": 1968 } }, { "Key": "562938681f5f234d3cb33c9d46e75071", "Value": { "left": 1212, "bottom": 1992, "right": 1252, "top": 2032 } }, { "Key": "453a7b68174246e27a370e083f806b91", "Value": { "left": 590, "bottom": 1800, "right": 610, "top": 1820 } }, { "Key": "06470f6928c4378e7c1e31f413a137dc", "Value": { "left": 780, "bottom": 1918, "right": 791, "top": 1929 } }, { "Key": "4c3715695b1a3fed0d5a2a93447314df", "Value": { "left": 106, "bottom": 426, "right": 206, "top": 526 } }, { "Key": "2a7b1669373d57e42f9035225a4a4c22", "Value": { "left": 322, "bottom": 1830, "right": 342, "top": 1850 } }, { "Key": "7da75a6938e7194d2d4a3a62615565fc", "Value": { "left": 470, "bottom": 1800, "right": 490, "top": 1820 } }, { "Key": "5d65226a1e2816d050af554625192398", "Value": { "left": 2, "bottom": 1398, "right": 52, "top": 1448 } }, { "Key": "09b44d6a4e8927f40a6826c07d5b69f9", "Value": { "left": 1650, "bottom": 1830, "right": 1670, "top": 1850 } }, { "Key": "38515d6a082a49430c38322b35f51152", "Value": { "left": 279, "bottom": 1918, "right": 293, "top": 1932 } }, { "Key": "445f076b10cc17e92b30538f1c3c0bfc", "Value": { "left": 924, "bottom": 1938, "right": 954, "top": 1968 } }, { "Key": "153a346b58f76ba94e416db20f587244", "Value": { "left": 1980, "bottom": 1800, "right": 2000, "top": 1820 } }, { "Key": "029a646b21e3528d523f7a3f36cb4a7a", "Value": { "left": 683, "bottom": 1830, "right": 703, "top": 1850 } }, { "Key": "75fd696b197523351ff218f2007b35fa", "Value": { "left": 1073, "bottom": 1830, "right": 1093, "top": 1850 } }, { "Key": "425d6b6b34666dfe66c0353b60a56594", "Value": { "left": 1447, "bottom": 1884, "right": 1457, "top": 1909 } }, { "Key": "6b31296c3d3c54f062913bac516e6eb8", "Value": { "left": 1890, "bottom": 1830, "right": 1910, "top": 1850 } }, { "Key": "6178636c3089374f799f548b1d0d5689", "Value": { "left": 2, "bottom": 1506, "right": 52, "top": 1556 } }, { "Key": "09df6a6c4d7b25e139f063be7a356bde", "Value": { "left": 878, "bottom": 1800, "right": 898, "top": 1820 } }, { "Key": "68a8066d52ea4321063e1de047a508d6", "Value": { "left": 1418, "bottom": 1884, "right": 1443, "top": 1909 } }, { "Key": "54540c6d09e92f2072c56ff6229c42e2", "Value": { "left": 442, "bottom": 1830, "right": 462, "top": 1850 } }, { "Key": "6fe3096f11792bb14ea020781f2a1e2d", "Value": { "left": 750, "bottom": 1918, "right": 761, "top": 1929 } }, { "Key": "65eb2f6f0461757f5a745acf68e36e25", "Value": { "left": 374, "bottom": 1800, "right": 394, "top": 1820 } }, { "Key": "6f646670444357a320e9423f2eaa4e80", "Value": { "left": 1924, "bottom": 1884, "right": 1974, "top": 1909 } }, { "Key": "23801071629939ea6a0054b87cdd16a9", "Value": { "left": 900, "bottom": 1918, "right": 1004, "top": 1929 } }, { "Key": "44402071050555a124c77e7344733da4", "Value": { "left": 1883, "bottom": 1858, "right": 1903, "top": 1878 } }, { "Key": "4af3567144e93bfb574d7eff08276b1f", "Value": { "left": 686, "bottom": 1800, "right": 706, "top": 1820 } }, { "Key": "03d8647120c94ede2993460304155899", "Value": { "left": 1196, "bottom": 1938, "right": 1226, "top": 1968 } }, { "Key": "0076397239c3101d45355ef116411c75", "Value": { "left": 1968, "bottom": 1938, "right": 1998, "top": 1968 } }, { "Key": "02d76c7230fb29d76262371646dc3718", "Value": { "left": 446, "bottom": 1776, "right": 466, "top": 1796 } }, { "Key": "4a446b731cad7540075e713659336d0e", "Value": { "left": 1217, "bottom": 1830, "right": 1237, "top": 1850 } }, { "Key": "7172077513da491f1f1046554a7d0bcc", "Value": { "left": 1880, "bottom": 1938, "right": 1930, "top": 1968 } }, { "Key": "3821097566522d056655626b4d6f6167", "Value": { "left": 717, "bottom": 2036, "right": 767, "top": 2041 } }, { "Key": "6a7e3675537b2d771c25300f48634962", "Value": { "left": 302, "bottom": 1776, "right": 322, "top": 1796 } }, { "Key": "56585e75082216ba67755c2d5ecb6ed3", "Value": { "left": 542, "bottom": 1776, "right": 562, "top": 1796 } }, { "Key": "1a0c0677587a3c73719c6aa379d113c1", "Value": { "left": 56, "bottom": 1506, "right": 106, "top": 1556 } }, { "Key": "0a7e1d772d8163c74c276b82046055af", "Value": { "left": 258, "bottom": 1938, "right": 298, "top": 1978 } }, { "Key": "6b9e3a777ef30b0346e62cb63ca10d5a", "Value": { "left": 106, "bottom": 842, "right": 156, "top": 893 } }, { "Key": "43ad697756894fa942a9115f69e858d5", "Value": { "left": 370, "bottom": 1830, "right": 390, "top": 1850 } }, { "Key": "69826e777c0875aa2538405f72e1787f", "Value": { "left": 1578, "bottom": 1830, "right": 1598, "top": 1850 } }, { "Key": "33dc27782cbd3b856f98546a48551add", "Value": { "left": 1846, "bottom": 1938, "right": 1876, "top": 1968 } }, { "Key": "127a2878256c72d05bbc46b313760577", "Value": { "left": 586, "bottom": 1830, "right": 606, "top": 1850 } }, { "Key": "54533c7853254fc26d4f6bd9082129a8", "Value": { "left": 899, "bottom": 1858, "right": 919, "top": 1878 } }, { "Key": "0ffc467840e900ce18ad18ce4da851da", "Value": { "left": 1547, "bottom": 1858, "right": 1567, "top": 1878 } }, { "Key": "525e72785d54327e07125b1e030e72b1", "Value": { "left": 1573, "bottom": 1800, "right": 1593, "top": 1820 } }, { "Key": "4e001b7940a900a748a414b035541820", "Value": { "left": 1069, "bottom": 1800, "right": 1089, "top": 1820 } }, { "Key": "29821f7977603f9b4d555dd659f271a7", "Value": { "left": 17, "bottom": 110, "right": 117, "top": 210 } }, { "Key": "3b0a3d7952be0a6a56036a5675792f0b", "Value": { "left": 836, "bottom": 1938, "right": 886, "top": 1968 } }, { "Key": "27ed427925bf0f15242e054d7d15565c", "Value": { "left": 1656, "bottom": 1938, "right": 1686, "top": 1968 } }, { "Key": "0c9c7079001e4d00039e31d77b0340e1", "Value": { "left": 170, "bottom": 1918, "right": 185, "top": 1933 } }, { "Key": "4c237879436f27d225870c8c10c8650d", "Value": { "left": 1870, "bottom": 1884, "right": 1920, "top": 1909 } }, { "Key": "35b70b7a022239575e6c5caf32445477", "Value": { "left": 182, "bottom": 1776, "right": 202, "top": 1796 } }, { "Key": "6684387a17f21d804e0c625c3caf019f", "Value": { "left": 189, "bottom": 1918, "right": 203, "top": 1932 } }, { "Key": "781a427a28b90ffe23a75d426a9443e6", "Value": { "left": 524, "bottom": 1938, "right": 554, "top": 1968 } }, { "Key": "68176d7a25466a163a972c1d02f90197", "Value": { "left": 232, "bottom": 1884, "right": 262, "top": 1914 } }, { "Key": "468a0f7c35cb0353298d77d67de26056", "Value": { "left": 992, "bottom": 1938, "right": 1022, "top": 1968 } }, { "Key": "4b3d777c3edd7518080a277b3bfa1296", "Value": { "left": 782, "bottom": 1800, "right": 802, "top": 1820 } }, { "Key": "06b2507f1dc27444485922973f1651c6", "Value": { "left": 1932, "bottom": 1800, "right": 1952, "top": 1820 } }, { "Key": "3803547f5e515b5c33764a6736060bc7", "Value": { "left": 1698, "bottom": 1830, "right": 1718, "top": 1850 } }, { "Key": "3f775a7f10983ba21cd81541526524cf", "Value": { "left": 998, "bottom": 1776, "right": 1018, "top": 1796 } }, { "Key": "41516f7f0265318f5f6d731f16f66682", "Value": { "left": 2, "bottom": 1074, "right": 52, "top": 1124 } }, { "Key": "0d090480192b622f13f708e024385b7e", "Value": { "left": 1812, "bottom": 1938, "right": 1842, "top": 1968 } }, { "Key": "6daf1e8158c73247507728605cb232fe", "Value": { "left": 1230, "bottom": 1938, "right": 1260, "top": 1968 } }, { "Key": "4458068263d003483fca161a66a50c84", "Value": { "left": 976, "bottom": 1992, "right": 1016, "top": 2032 } }, { "Key": "5cc7078218605bcf392a532264644d1a", "Value": { "left": 374, "bottom": 1776, "right": 394, "top": 1796 } }, { "Key": "01c62a82737d79b045f411651bdd2ce6", "Value": { "left": 662, "bottom": 1884, "right": 687, "top": 1909 } }, { "Key": "4f482b827d0e70ac4031022c21737971", "Value": { "left": 758, "bottom": 1776, "right": 778, "top": 1796 } }, { "Key": "365d6782616b35260cdd62af000c03d6", "Value": { "left": 266, "bottom": 1884, "right": 291, "top": 1910 } }, { "Key": "5130158340bc173258075d59545861e1", "Value": { "left": 194, "bottom": 1830, "right": 218, "top": 1854 } }, { "Key": "1b4e1f836afb6b7a38b32c5d7e8c31aa", "Value": { "left": 972, "bottom": 1830, "right": 992, "top": 1850 } }, { "Key": "006c29830a4061c219336f376edd7408", "Value": { "left": 1420, "bottom": 1938, "right": 1470, "top": 1968 } }, { "Key": "792525843ae60c666e3b7e9100bd36ac", "Value": { "left": 1955, "bottom": 1858, "right": 1975, "top": 1878 } }, { "Key": "66a662840f893c5e33eb68ff57751cb1", "Value": { "left": 517, "bottom": 1884, "right": 542, "top": 1909 } }, { "Key": "4f0c3185756751f601600a741a761dd6", "Value": { "left": 494, "bottom": 1858, "right": 514, "top": 1878 } }, { "Key": "65472887152f187c50a824111b2646a2", "Value": { "left": 110, "bottom": 1776, "right": 130, "top": 1796 } }, { "Key": "15d62b872c3534251a074af843192a3f", "Value": { "left": 17, "bottom": 2, "right": 28, "top": 106 } }, { "Key": "27250e883db655432ad15beb37827100", "Value": { "left": 1121, "bottom": 1830, "right": 1141, "top": 1850 } }, { "Key": "3da4158824d77f8a722366e166d166ac", "Value": { "left": 806, "bottom": 1776, "right": 826, "top": 1796 } }, { "Key": "08102b891cb142b90e4240df07f947c2", "Value": { "left": 144, "bottom": 1884, "right": 194, "top": 1914 } }, { "Key": "77c5378922e432762d8578080cbb35bd", "Value": { "left": 1090, "bottom": 1918, "right": 1100, "top": 1928 } }, { "Key": "18867189163f78f1110406954fc902d2", "Value": { "left": 1052, "bottom": 1918, "right": 1062, "top": 1928 } }, { "Key": "7d390b8a244a17b8151e2a552bff1d77", "Value": { "left": 1979, "bottom": 1858, "right": 1999, "top": 1878 } }, { "Key": "7497418a192e3b84404d30cc3125162b", "Value": { "left": 1492, "bottom": 1992, "right": 1532, "top": 2032 } }, { "Key": "0c6a5d8a4a661a94747c6bf051ae52cc", "Value": { "left": 758, "bottom": 1800, "right": 778, "top": 1820 } }, { "Key": "0733208b08c93dd669e00f4c219c633a", "Value": { "left": 590, "bottom": 1776, "right": 610, "top": 1796 } }, { "Key": "1e0d548b73bc26bc2c0e538329f5163b", "Value": { "left": 1920, "bottom": 1992, "right": 1960, "top": 2032 } }, { "Key": "431f6a8b1fa51b507bcf13da74b15da5", "Value": { "left": 2, "bottom": 946, "right": 72, "top": 1016 } }, { "Key": "45a96f8d00a84100285c6c934c9a35d6", "Value": { "left": 1186, "bottom": 1884, "right": 1196, "top": 1909 } }, { "Key": "1d66598e2402227f299625033b627c88", "Value": { "left": 1298, "bottom": 1938, "right": 1348, "top": 1968 } }, { "Key": "36ab678e3d2829e7337c50795c776702", "Value": { "left": 950, "bottom": 1776, "right": 970, "top": 1796 } }, { "Key": "34c1728e5959446a322b3abd0166447c", "Value": { "left": 708, "bottom": 1858, "right": 728, "top": 1878 } }, { "Key": "717f148f5dd235e30a7732a50c550b8e", "Value": { "left": 1187, "bottom": 1858, "right": 1207, "top": 1878 } }, { "Key": "4fc26f8f22f13b4d2b45412a54061211", "Value": { "left": 56, "bottom": 1938, "right": 106, "top": 1988 } }, { "Key": "56130790077f636835d452e879313909", "Value": { "left": 1237, "bottom": 1800, "right": 1257, "top": 1820 } }, { "Key": "06834b90737824c019bf06f575bc5511", "Value": { "left": 1044, "bottom": 1830, "right": 1069, "top": 1850 } }, { "Key": "4469659002a71b5f254f744108064c02", "Value": { "left": 755, "bottom": 1992, "right": 795, "top": 2032 } }, { "Key": "737a6f90605173ff5aee59a84e7456ac", "Value": { "left": 1283, "bottom": 1858, "right": 1303, "top": 1878 } }, { "Key": "48bb0e912c9b39666e735b4e3a886eb5", "Value": { "left": 2034, "bottom": 1884, "right": 2044, "top": 1904 } }, { "Key": "729f389179896e145e2c2d9f4601358c", "Value": { "left": 302, "bottom": 1858, "right": 322, "top": 1878 } }, { "Key": "0a256d914aae1bef013f020f70dc0320", "Value": { "left": 949, "bottom": 1800, "right": 969, "top": 1820 } }, { "Key": "72c5439208a9592b0e70560e6dcb2704", "Value": { "left": 1124, "bottom": 1992, "right": 1164, "top": 2032 } }, { "Key": "69d8209312f214ac766623ce37fc368c", "Value": { "left": 590, "bottom": 1858, "right": 609, "top": 1878 } }, { "Key": "6bfe26935ff23aca66982fc5129f62a5", "Value": { "left": 953, "bottom": 1884, "right": 963, "top": 1909 } }, { "Key": "106d599344ab622f788725dc1a9b2d40", "Value": { "left": 346, "bottom": 1938, "right": 446, "top": 1978 } }, { "Key": "38e15d9337ec6c765a613ed6385a7259", "Value": { "left": 1093, "bottom": 1800, "right": 1113, "top": 1820 } }, { "Key": "15d21a945b6a61cd10eb51d973764806", "Value": { "left": 1070, "bottom": 1776, "right": 1095, "top": 1795 } }, { "Key": "4b7125941858520c06572f0c31a365b1", "Value": { "left": 638, "bottom": 1800, "right": 658, "top": 1820 } }, { "Key": "5dc21695180c481f79594f2943d77fa5", "Value": { "left": 1866, "bottom": 1830, "right": 1886, "top": 1850 } }, { "Key": "42de0d960e43186b233a053066245c1d", "Value": { "left": 2, "bottom": 842, "right": 102, "top": 942 } }, { "Key": "4be6659607ff04405eed6a4f5c7641d8", "Value": { "left": 635, "bottom": 1830, "right": 655, "top": 1850 } }, { "Key": "3a16329731654e127b140d834daf3014", "Value": { "left": 110, "bottom": 1884, "right": 140, "top": 1914 } }, { "Key": "35d45597574d6da4125d56f026622089", "Value": { "left": 885, "bottom": 1918, "right": 896, "top": 1929 } }, { "Key": "3c5000983faf14af2ff15e4628054e0f", "Value": { "left": 2004, "bottom": 1800, "right": 2025, "top": 1820 } }, { "Key": "0c560598714a2c8b3eb82ae603ee78bd", "Value": { "left": 967, "bottom": 1884, "right": 1017, "top": 1909 } }, { "Key": "645c0d9811e46c6a0ff0007649142762", "Value": { "left": 1530, "bottom": 1830, "right": 1550, "top": 1850 } }, { "Key": "35de0b9966e72d501fd4124c61413f86", "Value": { "left": 1091, "bottom": 1858, "right": 1111, "top": 1878 } }, { "Key": "66222199071f48b65a517562683657cb", "Value": { "left": 852, "bottom": 1858, "right": 872, "top": 1878 } }, { "Key": "678f3b994792282b57067997708137b0", "Value": { "left": 1828, "bottom": 1884, "right": 1838, "top": 1909 } }, { "Key": "6be0629a7f532e3b50cd6b8028780add", "Value": { "left": 707, "bottom": 1830, "right": 727, "top": 1850 } }, { "Key": "3ffc4e9b156a328e75c2510a185e3447", "Value": { "left": 1956, "bottom": 1800, "right": 1976, "top": 1820 } }, { "Key": "5a052c9c3bb10d494da427ce2dcc6d0b", "Value": { "left": 1427, "bottom": 1858, "right": 1447, "top": 1878 } }, { "Key": "72b3429c340349362c50008c3bf70c58", "Value": { "left": 1477, "bottom": 1800, "right": 1497, "top": 1820 } }, { "Key": "54ed149d6c4009d64c685983728a1b1b", "Value": { "left": 840, "bottom": 1918, "right": 851, "top": 1929 } }, { "Key": "0e1b4c9d732143c0649c77fd4cc95098", "Value": { "left": 1536, "bottom": 1992, "right": 1576, "top": 2032 } }, { "Key": "3f603a9e07a6001867272fca648e2d28", "Value": { "left": 1200, "bottom": 1884, "right": 1251, "top": 1909 } }, { "Key": "2476549e78e44b98719b14da5c4134db", "Value": { "left": 1542, "bottom": 1918, "right": 1590, "top": 1927 } }, { "Key": "0d1a159f71725db57bc8657c7a34211a", "Value": { "left": 231, "bottom": 1992, "right": 241, "top": 2042 } }, { "Key": "6559699f7855266e0f686d614f992182", "Value": { "left": 148, "bottom": 1918, "right": 166, "top": 1933 } }, { "Key": "39fb6a9f2c400a6b36e0614432c44b89", "Value": { "left": 1978, "bottom": 1884, "right": 2002, "top": 1908 } }, { "Key": "470500a075811926793a60284b925a5f", "Value": { "left": 1934, "bottom": 1938, "right": 1964, "top": 1968 } }, { "Key": "35ab75a033eb67461637458a31c20f06", "Value": { "left": 2, "bottom": 1236, "right": 52, "top": 1286 } }, { "Key": "324112a175042fb832b233fb2d950b2b", "Value": { "left": 1008, "bottom": 1918, "right": 1019, "top": 1929 } }, { "Key": "456610a279177bd27132039f6c9c046a", "Value": { "left": 418, "bottom": 1830, "right": 438, "top": 1850 } }, { "Key": "69a564a235c80c55159e50d8601030df", "Value": { "left": 422, "bottom": 1858, "right": 442, "top": 1878 } }, { "Key": "4f1e6fa245900e7f0e8954af1a505ec9", "Value": { "left": 1038, "bottom": 1918, "right": 1048, "top": 1928 } }, { "Key": "438b78a21bfe61f33790360a703b0b6d", "Value": { "left": 206, "bottom": 1776, "right": 226, "top": 1796 } }, { "Key": "202924a37cfe76312bba65d85a083037", "Value": { "left": 1931, "bottom": 1858, "right": 1951, "top": 1878 } }, { "Key": "3a5d29a31f5522ff1742339438281665", "Value": { "left": 782, "bottom": 1776, "right": 802, "top": 1796 } }, { "Key": "5b4c2ea318924e6409f4639b047433f8", "Value": { "left": 326, "bottom": 1776, "right": 346, "top": 1796 } }, { "Key": "06d553a32bf63e3148df5308361e31a6", "Value": { "left": 254, "bottom": 1800, "right": 274, "top": 1820 } }, { "Key": "1f567fa431f2371a538646f27128767f", "Value": { "left": 2, "bottom": 634, "right": 102, "top": 734 } }, { "Key": "480277a63e4f29092bd8095a558f0cf3", "Value": { "left": 1513, "bottom": 1884, "right": 1563, "top": 1909 } }, { "Key": "594e45a71e9b723423ff1c0b5c2732c9", "Value": { "left": 1836, "bottom": 1800, "right": 1856, "top": 1820 } }, { "Key": "2b594da76cd63ef042d21d0f7a5541b0", "Value": { "left": 1172, "bottom": 1918, "right": 1222, "top": 1927 } }, { "Key": "785d75a7453d47d907d2717527b01b21", "Value": { "left": 2, "bottom": 2, "right": 13, "top": 106 } }, { "Key": "3b1d60a914de1949664603c71e29748a", "Value": { "left": 110, "bottom": 1800, "right": 130, "top": 1820 } }, { "Key": "55ed66a92fe1176674d36fa95be23741", "Value": { "left": 1739, "bottom": 1858, "right": 1759, "top": 1878 } }, { "Key": "3c374faa59f4169e448640451e8c7999", "Value": { "left": 1964, "bottom": 1992, "right": 2004, "top": 2032 } }, { "Key": "047125ac645757370538749441e716aa", "Value": { "left": 1357, "bottom": 1800, "right": 1377, "top": 1820 } }, { "Key": "5a506fac4bd724fd7cb30e9324e33ac6", "Value": { "left": 278, "bottom": 1776, "right": 298, "top": 1796 } }, { "Key": "1d7a7eac346469fc025a054e41e97b4b", "Value": { "left": 1506, "bottom": 1830, "right": 1526, "top": 1850 } }, { "Key": "76b963ad2f355a7a0bfd6cfa57434173", "Value": { "left": 1914, "bottom": 1830, "right": 1934, "top": 1850 } }, { "Key": "3a1771ad7b2c33446e9e4918798b0fa0", "Value": { "left": 1264, "bottom": 1938, "right": 1294, "top": 1968 } }, { "Key": "661810ae7278533651ab14ce7d5b02ea", "Value": { "left": 2, "bottom": 426, "right": 102, "top": 526 } }, { "Key": "789c46ae7749792468c0759112c07c8f", "Value": { "left": 425, "bottom": 1918, "right": 437, "top": 1930 } }, { "Key": "10da4daf062652a1109870f7341a00e6", "Value": { "left": 2, "bottom": 1668, "right": 7, "top": 1718 } }, { "Key": "25fe24b15a643db6408474c87f060807", "Value": { "left": 756, "bottom": 1858, "right": 776, "top": 1878 } }, { "Key": "2afb49b10d0a64ca2423073421b03e7c", "Value": { "left": 1501, "bottom": 1800, "right": 1521, "top": 1820 } }, { "Key": "75626bb107dc2e62446319ef51b22e72", "Value": { "left": 134, "bottom": 1776, "right": 154, "top": 1796 } }, { "Key": "3db124b21b76367c60276e680ddd3a9a", "Value": { "left": 1189, "bottom": 1800, "right": 1209, "top": 1820 } }, { "Key": "112e27b2699838915c2728de34f6766a", "Value": { "left": 407, "bottom": 1992, "right": 457, "top": 2042 } }, { "Key": "0f5f2fb233a8486f279b12b338235635", "Value": { "left": 106, "bottom": 634, "right": 206, "top": 734 } }, { "Key": "774865b273573cf4092515ec758a5a00", "Value": { "left": 446, "bottom": 1800, "right": 466, "top": 1820 } }, { "Key": "47b36fb265a33d7264b108b71f49788d", "Value": { "left": 732, "bottom": 1858, "right": 752, "top": 1878 } }, { "Key": "3ec067b34c1273214d7136f173c51c04", "Value": { "left": 11, "bottom": 1668, "right": 61, "top": 1718 } }, { "Key": "44f367b43ad37edf74d46dbf21954378", "Value": { "left": 461, "bottom": 1992, "right": 511, "top": 2042 } }, { "Key": "05fb7cb46f9b68b21b710da4496979be", "Value": { "left": 2, "bottom": 738, "right": 102, "top": 838 } }, { "Key": "71f906b500ad3db16f2e193f720901dd", "Value": { "left": 663, "bottom": 2036, "right": 713, "top": 2041 } }, { "Key": "538858b561c55f5768b558d868a1494f", "Value": { "left": 799, "bottom": 1992, "right": 839, "top": 2032 } }, { "Key": "425b7bb56bf153692f200f30446701b8", "Value": { "left": 494, "bottom": 1776, "right": 514, "top": 1796 } }, { "Key": "5f3057b6579c79624dab3a6e6509044d", "Value": { "left": 1405, "bottom": 1800, "right": 1425, "top": 1820 } }, { "Key": "4ac760b64c831cd8030c07d77097254f", "Value": { "left": 361, "bottom": 1918, "right": 373, "top": 1930 } }, { "Key": "779a6db61bdb3be37c723d6d13055ba2", "Value": { "left": 206, "bottom": 1800, "right": 226, "top": 1820 } }, { "Key": "466209b744113e2e2f00468514096178", "Value": { "left": 623, "bottom": 1992, "right": 663, "top": 2032 } }, { "Key": "54772db77d4168b17bd54bc47eb81845", "Value": { "left": 1667, "bottom": 1858, "right": 1687, "top": 1878 } }, { "Key": "54be57b767d45e0437b4256e70044b16", "Value": { "left": 1622, "bottom": 1938, "right": 1652, "top": 1968 } }, { "Key": "44f97eb708244d9d3a82672828ff5ab6", "Value": { "left": 662, "bottom": 1800, "right": 682, "top": 1820 } }, { "Key": "28ed12b864fb77e1596d23be6d7115ee", "Value": { "left": 878, "bottom": 1776, "right": 898, "top": 1796 } }, { "Key": "190819b830c0514328f239ab1fa67c72", "Value": { "left": 614, "bottom": 1800, "right": 634, "top": 1820 } }, { "Key": "36381ab856e21d206b244e1b06737b5b", "Value": { "left": 947, "bottom": 1858, "right": 967, "top": 1878 } }, { "Key": "525f69b859154d322a44304944642d03", "Value": { "left": 841, "bottom": 1884, "right": 866, "top": 1909 } }, { "Key": "038d77b825c407256b1a319e5c182af9", "Value": { "left": 2, "bottom": 1722, "right": 12, "top": 1772 } }, { "Key": "546234b9099b361750c635157f2232cb", "Value": { "left": 854, "bottom": 1800, "right": 874, "top": 1820 } }, { "Key": "559c35ba2dc500b9146c6f654b925b14", "Value": { "left": 765, "bottom": 1918, "right": 776, "top": 1929 } }, { "Key": "1b107fba691359fe56301c2537d311b8", "Value": { "left": 261, "bottom": 1918, "right": 275, "top": 1932 } }, { "Key": "0a1801bb711a77c60d1679f411b36610", "Value": { "left": 2, "bottom": 1182, "right": 11, "top": 1232 } }, { "Key": "749d29bb6c3779a535123773412905ad", "Value": { "left": 1744, "bottom": 1884, "right": 1794, "top": 1909 } }, { "Key": "080c03bc303d37fc1b33333b4db333e4", "Value": { "left": 1381, "bottom": 1800, "right": 1401, "top": 1820 } }, { "Key": "4c2040bc3f284f8d415e02a908746904", "Value": { "left": 1458, "bottom": 1830, "right": 1478, "top": 1850 } }, { "Key": "1f5749bc6ff127440b4144807aad3926", "Value": { "left": 76, "bottom": 946, "right": 126, "top": 996 } }, { "Key": "455655bc15fd1b43025130401fee2903", "Value": { "left": 1345, "bottom": 1918, "right": 1393, "top": 1927 } }, { "Key": "27587cbc421e343b6a172ac445976fbe", "Value": { "left": 243, "bottom": 1918, "right": 257, "top": 1932 } }, { "Key": "650f05bd13c30fe20cb51f072b7158ac", "Value": { "left": 1716, "bottom": 1800, "right": 1736, "top": 1820 } }, { "Key": "6d8e26bf1c642edf1421275871e44c4d", "Value": { "left": 604, "bottom": 1884, "right": 629, "top": 1909 } }, { "Key": "6d502dbf63ec3d501f4f242f091d31a8", "Value": { "left": 2, "bottom": 530, "right": 102, "top": 630 } }, { "Key": "00a120c04e8d576676041a9f78ed6876", "Value": { "left": 182, "bottom": 1858, "right": 202, "top": 1878 } }, { "Key": "32a52dc06a01174c24c91fd0470b521f", "Value": { "left": 345, "bottom": 1918, "right": 357, "top": 1930 } }, { "Key": "310c57c01d81514264a35e92147c0695", "Value": { "left": 876, "bottom": 1858, "right": 895, "top": 1878 } }, { "Key": "2cd15cc006a9434340881834695b201e", "Value": { "left": 1026, "bottom": 1938, "right": 1056, "top": 1968 } }, { "Key": "038b6ac03b5d39e44855155b2cfd17fb", "Value": { "left": 1352, "bottom": 1938, "right": 1382, "top": 1968 } }, { "Key": "3bc720c118ed0f71156b56ff220517ad", "Value": { "left": 812, "bottom": 1884, "right": 837, "top": 1909 } }, { "Key": "31d16bc164d5193d66cf30674a824bad", "Value": { "left": 1213, "bottom": 1800, "right": 1233, "top": 1820 } }, { "Key": "3bb56ec16bfd38e07e6d0ebc282642fa", "Value": { "left": 2, "bottom": 1884, "right": 52, "top": 1934 } }, { "Key": "0e971cc24ed76b3a01e2479e36e876fd", "Value": { "left": 450, "bottom": 1938, "right": 490, "top": 1978 } }, { "Key": "422043c2736f09560c6d21e658ee7683", "Value": { "left": 15, "bottom": 1182, "right": 65, "top": 1232 } }, { "Key": "6f1c03c31634776772b40eb339ba39a1", "Value": { "left": 1043, "bottom": 1858, "right": 1063, "top": 1878 } }, { "Key": "591a19c30f2c066a3e9d0ac23d5636aa", "Value": { "left": 1403, "bottom": 1858, "right": 1423, "top": 1878 } }, { "Key": "20324bc467e374d318f447cc01c33e40", "Value": { "left": 902, "bottom": 1776, "right": 922, "top": 1796 } }, { "Key": "40c87ec45ab06d5067f2199828893b23", "Value": { "left": 925, "bottom": 1800, "right": 945, "top": 1820 } }, { "Key": "351040c57b69389a361e3ea6791f1f9d", "Value": { "left": 802, "bottom": 1938, "right": 832, "top": 1968 } }, { "Key": "489b66c526fb155d37935e626a35213e", "Value": { "left": 2, "bottom": 1020, "right": 52, "top": 1070 } }, { "Key": "627879c55d55252c12e70ff81ba77503", "Value": { "left": 1856, "bottom": 1884, "right": 1866, "top": 1909 } }, { "Key": "41fe49c7590a4fef6c2220df1d7b7d87", "Value": { "left": 1067, "bottom": 1858, "right": 1087, "top": 1878 } }, { "Key": "78d153c7721c600652de44a443fc762d", "Value": { "left": 326, "bottom": 1858, "right": 346, "top": 1878 } }, { "Key": "46566cc7182e52e65ccb23636f311aec", "Value": { "left": 1020, "bottom": 1992, "right": 1120, "top": 2032 } }, { "Key": "444571c9370c6315115f10624ab0015d", "Value": { "left": 1812, "bottom": 1800, "right": 1832, "top": 1820 } }, { "Key": "6c030fca2a162fbc3b713e6b347409bc", "Value": { "left": 514, "bottom": 1830, "right": 534, "top": 1850 } }, { "Key": "4be121ca5a8346872dc606b94bcc4903", "Value": { "left": 1366, "bottom": 1884, "right": 1376, "top": 1909 } }, { "Key": "704d3eca14ef09fe7f6403fc28b30af0", "Value": { "left": 15, "bottom": 1614, "right": 65, "top": 1664 } }, { "Key": "3a474acb2c6e301c56005dfa28900761", "Value": { "left": 470, "bottom": 1858, "right": 490, "top": 1878 } }, { "Key": "5f116ccb51b84961716a02cf69bb3f66", "Value": { "left": 1386, "bottom": 1938, "right": 1416, "top": 1968 } }, { "Key": "6cd41ccc028c51c461a5755c16c4120b", "Value": { "left": 353, "bottom": 1992, "right": 403, "top": 2042 } }, { "Key": "269832cd5b6d3c22365a05c128127d44", "Value": { "left": 1816, "bottom": 1992, "right": 1916, "top": 2032 } }, { "Key": "02093ccd514e707f0d97363b5a586089", "Value": { "left": 1499, "bottom": 1884, "right": 1509, "top": 1909 } }, { "Key": "4b1576cd389d313448200d037bee454d", "Value": { "left": 610, "bottom": 1830, "right": 631, "top": 1850 } }, { "Key": "45d262ce5cd66abb769443f0020c0644", "Value": { "left": 810, "bottom": 1918, "right": 821, "top": 1929 } }, { "Key": "45cc01cf1d6114d7161a0eb3016c3940", "Value": { "left": 614, "bottom": 1776, "right": 634, "top": 1796 } }, { "Key": "0bb21fcf2a9d59731e6f7bcb5f790769", "Value": { "left": 1404, "bottom": 1884, "right": 1414, "top": 1909 } }, { "Key": "75de6acf151e03724be01ccc668037bf", "Value": { "left": 313, "bottom": 1918, "right": 325, "top": 1930 } }, { "Key": "48a803d01eba69a826b9433d1f5c74aa", "Value": { "left": 638, "bottom": 1776, "right": 658, "top": 1796 } }, { "Key": "637e18d0543970a8502250431f967c02", "Value": { "left": 1621, "bottom": 1800, "right": 1641, "top": 1820 } }, { "Key": "649a34d011312f0053bb7a6049d87c68", "Value": { "left": 1499, "bottom": 1858, "right": 1519, "top": 1878 } }, { "Key": "432e3cd02deb14824fb749746eb841c9", "Value": { "left": 1691, "bottom": 1858, "right": 1711, "top": 1878 } }, { "Key": "49914fd04c69532e2f686e70438246c7", "Value": { "left": 1624, "bottom": 1992, "right": 1664, "top": 2032 } }, { "Key": "3bf44fd06dc15be1225c471977c55e24", "Value": { "left": 795, "bottom": 1918, "right": 806, "top": 1929 } }, { "Key": "36560cd15c64708710a74d6c17562771", "Value": { "left": 518, "bottom": 1858, "right": 538, "top": 1878 } }, { "Key": "3d9f26d140170fd2694b3a9a0b4b01fc", "Value": { "left": 1485, "bottom": 1884, "right": 1495, "top": 1909 } }, { "Key": "36552ed1342572934c84007c190968b2", "Value": { "left": 56, "bottom": 1452, "right": 106, "top": 1502 } }, { "Key": "52793ad12a1d17b438a07882274801d3", "Value": { "left": 734, "bottom": 1776, "right": 754, "top": 1796 } }, { "Key": "24cb3cd12ba628cd1c366e721f9767e5", "Value": { "left": 1104, "bottom": 1918, "right": 1114, "top": 1928 } }, { "Key": "027c5bd1366578a42cb4406a763b0c36", "Value": { "left": 494, "bottom": 1938, "right": 520, "top": 1971 } }, { "Key": "31bc71d11e040f296289400255cd44e0", "Value": { "left": 1278, "bottom": 1918, "right": 1287, "top": 1927 } }, { "Key": "4d0a16d335cf763c4b1b298e08c07386", "Value": { "left": 1740, "bottom": 1800, "right": 1760, "top": 1820 } }, { "Key": "78fd4fd32460578e71a660494ac229b5", "Value": { "left": 1619, "bottom": 1858, "right": 1639, "top": 1878 } }, { "Key": "41f672d310b84eb418f54de266564b7c", "Value": { "left": 11, "bottom": 1344, "right": 21, "top": 1394 } }, { "Key": "74843ad46bb7716008181dde34275ad0", "Value": { "left": 1386, "bottom": 1830, "right": 1406, "top": 1850 } }, { "Key": "0a0768d465c119435a1259a546b74bea", "Value": { "left": 2, "bottom": 1452, "right": 52, "top": 1502 } }, { "Key": "5fff73d414ad467e03685d0a6614095a", "Value": { "left": 177, "bottom": 1992, "right": 227, "top": 2042 } }, { "Key": "79930dd67ade03ed2f0317fc55680239", "Value": { "left": 106, "bottom": 218, "right": 206, "top": 318 } }, { "Key": "043677d61cdb5b240952141e61df282e", "Value": { "left": 1581, "bottom": 1884, "right": 1631, "top": 1909 } }, { "Key": "07217ad66edd15986cda39045abb1de8", "Value": { "left": 1842, "bottom": 1830, "right": 1862, "top": 1850 } }, { "Key": "3f541bd74565005f1e577dcd78607ee7", "Value": { "left": 1256, "bottom": 1992, "right": 1356, "top": 2032 } }, { "Key": "54c045d717b271dc10bd5e9f69611522", "Value": { "left": 16, "bottom": 1722, "right": 66, "top": 1772 } }, { "Key": "560f6bd82c4c4ef635813018768d064b", "Value": { "left": 1477, "bottom": 1918, "right": 1525, "top": 1927 } }, { "Key": "01f342d9768621963e463c1f6bd61e6c", "Value": { "left": 250, "bottom": 1830, "right": 270, "top": 1850 } }, { "Key": "58614ed9192c5a003133737e45ec1585", "Value": { "left": 441, "bottom": 1918, "right": 453, "top": 1930 } }, { "Key": "065572d91dd10e4d6ac06cf049d44336", "Value": { "left": 653, "bottom": 2036, "right": 659, "top": 2042 } }, { "Key": "6a387bd918eb39f3079a75796db55d4a", "Value": { "left": 1094, "bottom": 1938, "right": 1124, "top": 1968 } }, { "Key": "160104da0967563125ad686703e8527a", "Value": { "left": 457, "bottom": 1918, "right": 469, "top": 1930 } }, { "Key": "1e086ada4002060e2a9a18020d915e7b", "Value": { "left": 1811, "bottom": 1858, "right": 1831, "top": 1878 } }, { "Key": "29991fdb6c684da368e2435d6a7a6c92", "Value": { "left": 56, "bottom": 1776, "right": 106, "top": 1826 } }, { "Key": "677c5cdb367c384b455a6201167a2109", "Value": { "left": 711, "bottom": 1992, "right": 751, "top": 2032 } }, { "Key": "127e42dc65cf0e39157e1ea817ad6c4b", "Value": { "left": 376, "bottom": 1884, "right": 401, "top": 1909 } }, { "Key": "665a4ddc0a1b0a0e525770675ada557c", "Value": { "left": 1261, "bottom": 1800, "right": 1281, "top": 1820 } }, { "Key": "523d73dc430978bd205b62ac43d108f8", "Value": { "left": 1597, "bottom": 1800, "right": 1617, "top": 1820 } }, { "Key": "082c7adc114072223f8624d3657d369c", "Value": { "left": 106, "bottom": 530, "right": 206, "top": 630 } }, { "Key": "048005dd1a3b5b24427623dc3ae543a2", "Value": { "left": 1763, "bottom": 1858, "right": 1783, "top": 1878 } }, { "Key": "774511dd0c17278327a37a61259312ec", "Value": { "left": 274, "bottom": 1830, "right": 294, "top": 1850 } }, { "Key": "091e37dd7c032c6c589424ac64c816a4", "Value": { "left": 710, "bottom": 1776, "right": 730, "top": 1796 } }, { "Key": "6e6747dd38b07eb6388b25ff595e2cee", "Value": { "left": 804, "bottom": 1830, "right": 824, "top": 1850 } }, { "Key": "262b5fdd68660a1c564463250003263d", "Value": { "left": 422, "bottom": 1776, "right": 442, "top": 1796 } }, { "Key": "2e9d76dd344d6a7628982a922dac3778", "Value": { "left": 278, "bottom": 1858, "right": 298, "top": 1878 } }, { "Key": "3e6d21de649d6d8671587a2505f42bcc", "Value": { "left": 466, "bottom": 1830, "right": 486, "top": 1850 } }, { "Key": "100946df482b0cda570110de23e93351", "Value": { "left": 1360, "bottom": 1992, "right": 1400, "top": 2032 } }, { "Key": "590b46df4f7122cb30614bba0f591559", "Value": { "left": 902, "bottom": 1800, "right": 921, "top": 1820 } }, { "Key": "5fb07cdf72db68ec2383741603480b53", "Value": { "left": 1595, "bottom": 1858, "right": 1615, "top": 1878 } }, { "Key": "299b48e027d0686405925a2412df3f79", "Value": { "left": 56, "bottom": 1830, "right": 106, "top": 1880 } }, { "Key": "55864ae04d8d76e3674a5d3f210d0132", "Value": { "left": 110, "bottom": 1858, "right": 130, "top": 1878 } }, { "Key": "66de7fe06fcf11d5534f7d306268399c", "Value": { "left": 1907, "bottom": 1858, "right": 1927, "top": 1878 } }, { "Key": "6c1222e14ca4398d5c8d7cbc115f2840", "Value": { "left": 1323, "bottom": 1884, "right": 1348, "top": 1909 } }, { "Key": "67e86ce16b231d8d36f64ec14a9a1c99", "Value": { "left": 1380, "bottom": 1884, "right": 1400, "top": 1909 } }, { "Key": "72e37ae1388974ad7a993d373ab56ba1", "Value": { "left": 1117, "bottom": 1800, "right": 1137, "top": 1820 } }, { "Key": "6b283ee32c6032f821dd699566a924bc", "Value": { "left": 1626, "bottom": 1830, "right": 1646, "top": 1850 } }, { "Key": "1fd643e3718b28ec40157bf56fcb590d", "Value": { "left": 1060, "bottom": 1938, "right": 1090, "top": 1968 } }, { "Key": "63bb6ee349d31989559f57c840d81866", "Value": { "left": 1668, "bottom": 1992, "right": 1768, "top": 2032 } }, { "Key": "6ea314e470626614681843882a1803d1", "Value": { "left": 843, "bottom": 1992, "right": 883, "top": 2032 } }, { "Key": "72ed0fe553872449613d43ca0be545a3", "Value": { "left": 1021, "bottom": 1884, "right": 1046, "top": 1909 } }, { "Key": "5bf81ee545af13071b9d7e2877f00610", "Value": { "left": 1045, "bottom": 1800, "right": 1065, "top": 1820 } }, { "Key": "6b470de62923542911ed03432213563c", "Value": { "left": 633, "bottom": 1884, "right": 658, "top": 1909 } }, { "Key": "693019e64db207b44941030950950f55", "Value": { "left": 1338, "bottom": 1830, "right": 1358, "top": 1850 } }, { "Key": "531d00e7050764177538268b12226ef5", "Value": { "left": 633, "bottom": 2036, "right": 639, "top": 2042 } }, { "Key": "607b57e75dfe1ee103b369af38ab75d0", "Value": { "left": 2, "bottom": 322, "right": 102, "top": 422 } }, { "Key": "71ab5ce818200ebe79e5421f737858b9", "Value": { "left": 56, "bottom": 1290, "right": 106, "top": 1340 } }, { "Key": "28ea75e86ebe4d45722a4aa63c471559", "Value": { "left": 1602, "bottom": 1830, "right": 1622, "top": 1850 } }, { "Key": "631d77e84a46720c07800e75562e0706", "Value": { "left": 1423, "bottom": 1918, "right": 1473, "top": 1927 } }, { "Key": "5c4657e95eb356133d6102ad258b38d1", "Value": { "left": 207, "bottom": 1918, "right": 221, "top": 1932 } }, { "Key": "6ee211ea0b413267340a3e665c800d55", "Value": { "left": 1362, "bottom": 1830, "right": 1382, "top": 1850 } }, { "Key": "19f41dea4e4a13f50a020e2f72220b70", "Value": { "left": 2003, "bottom": 1858, "right": 2023, "top": 1878 } }, { "Key": "37fb3fea30e501d008a455d6364c22cc", "Value": { "left": 995, "bottom": 1858, "right": 1015, "top": 1878 } }, { "Key": "0f8341ea3e692c9911eb1daf1e9b4e7e", "Value": { "left": 1567, "bottom": 1884, "right": 1577, "top": 1909 } }, { "Key": "641a79ea094a621145ea6c3369474ce4", "Value": { "left": 735, "bottom": 1918, "right": 746, "top": 1929 } }, { "Key": "2bc876eb20e874f138c80aa13c010fcd", "Value": { "left": 377, "bottom": 1918, "right": 389, "top": 1930 } }, { "Key": "3cb634ec0c2a4357104d377d5b6b70f3", "Value": { "left": 870, "bottom": 1884, "right": 920, "top": 1909 } }, { "Key": "2c6a44ed41965abc1a6d17074f375ffd", "Value": { "left": 1285, "bottom": 1800, "right": 1305, "top": 1820 } }, { "Key": "69056cee22f677695d9540140be069f5", "Value": { "left": 1778, "bottom": 1938, "right": 1808, "top": 1968 } }, { "Key": "28e813ef74100f1012ba2a92173f42ae", "Value": { "left": 1163, "bottom": 1858, "right": 1183, "top": 1878 } }, { "Key": "763732ef5458313915c3067a2b3c4e4b", "Value": { "left": 1842, "bottom": 1884, "right": 1852, "top": 1909 } }, { "Key": "209332ef3b3b7c081e620ce00c9e79f6", "Value": { "left": 298, "bottom": 1830, "right": 318, "top": 1850 } }, { "Key": "1f9e44ef743150ce413f35206e607f8a", "Value": { "left": 1235, "bottom": 1858, "right": 1255, "top": 1878 } }, { "Key": "318353ef18463f74356c61cf62e2655d", "Value": { "left": 2, "bottom": 1776, "right": 52, "top": 1826 } }, { "Key": "14cf63ef797313a57f5c1d0e36954c80", "Value": { "left": 597, "bottom": 1918, "right": 608, "top": 1929 } }, { "Key": "478b75ef613a0f3f560513f2505f448d", "Value": { "left": 158, "bottom": 1776, "right": 178, "top": 1796 } }, { "Key": "0edd5cf06d14584b2a7a6f6c109b667d", "Value": { "left": 302, "bottom": 1800, "right": 322, "top": 1820 } }, { "Key": "1d7a57f110e27e926320191b2c1f3c6e", "Value": { "left": 2006, "bottom": 1884, "right": 2030, "top": 1908 } }, { "Key": "5dd75cf130c54760239a02887dc27cc7", "Value": { "left": 2036, "bottom": 1938, "right": 2046, "top": 1963 } }, { "Key": "00e30bf2552d06127c1d6bd6121b6df3", "Value": { "left": 1520, "bottom": 1938, "right": 1550, "top": 1968 } }, { "Key": "500247f24466585a79427cfa01af7dce", "Value": { "left": 1352, "bottom": 1884, "right": 1362, "top": 1909 } }, { "Key": "296609f45d5c66f1662224e457af5253", "Value": { "left": 158, "bottom": 1858, "right": 178, "top": 1878 } }, { "Key": "529e59f47958149e773d7ee574b446aa", "Value": { "left": 2002, "bottom": 1938, "right": 2032, "top": 1968 } }, { "Key": "080924f564be321631537a4942fa64a9", "Value": { "left": 1255, "bottom": 1884, "right": 1305, "top": 1909 } }, { "Key": "77d528f50f68274831a55392291b7727", "Value": { "left": 1580, "bottom": 1992, "right": 1620, "top": 2032 } }, { "Key": "657d27f6662b025769741b7571df4551", "Value": { "left": 932, "bottom": 1992, "right": 972, "top": 2032 } }, { "Key": "3b8b47f65dba59ff46fa153361030882", "Value": { "left": 1860, "bottom": 1800, "right": 1880, "top": 1820 } }, { "Key": "032d7cf61fd679320acb69bb42de42ce", "Value": { "left": 214, "bottom": 1938, "right": 254, "top": 1978 } }, { "Key": "548a54f733c041ff66a7740d3f6357c3", "Value": { "left": 1554, "bottom": 1938, "right": 1584, "top": 1968 } }, { "Key": "7b1f59f85dc573751dfb30cd0f910f13", "Value": { "left": 134, "bottom": 1800, "right": 154, "top": 1820 } }, { "Key": "488377f87257761c278906856d810341", "Value": { "left": 734, "bottom": 1938, "right": 764, "top": 1968 } }, { "Key": "699270fa415802b04fdb6f4c53fc365c", "Value": { "left": 876, "bottom": 1830, "right": 896, "top": 1850 } }, { "Key": "1fb37cfa09b15ef049c673f426384df2", "Value": { "left": 612, "bottom": 1918, "right": 716, "top": 1929 } }, { "Key": "35ad0efb53496d0912370f7d051a1778", "Value": { "left": 347, "bottom": 1884, "right": 372, "top": 1909 } }, { "Key": "429c14fb5b927a6c63d37e4a16e82996", "Value": { "left": 771, "bottom": 2036, "right": 821, "top": 2041 } }, { "Key": "5e4c46fb29056c521b45568c43bc3c9d", "Value": { "left": 489, "bottom": 1918, "right": 593, "top": 1929 } }, { "Key": "089c41fc1ab81a672292049d196e2136", "Value": { "left": 780, "bottom": 1830, "right": 800, "top": 1850 } }, { "Key": "683a62fd1b9a26a86d3a1c046dd871aa", "Value": { "left": 2008, "bottom": 1992, "right": 2043, "top": 2027 } }, { "Key": "267964fe2f9d001f378667c8063a3afc", "Value": { "left": 900, "bottom": 1830, "right": 920, "top": 1850 } }, { "Key": "234425ff2d201c58768a5aad661228d2", "Value": { "left": 1157, "bottom": 1884, "right": 1182, "top": 1909 } } ] } ], "builtImages": [ { "id": "5c8f735e0626703c68375587092b511f", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "25fe24b15a643db6408474c87f060807", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5f5841267c8d387d7de441cf5c97258b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5c4657e95eb356133d6102ad258b38d1", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "7167574c690f33d1144a07d126c80813", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "048005dd1a3b5b24427623dc3ae543a2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "37fb3fea30e501d008a455d6364c22cc", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6684387a17f21d804e0c625c3caf019f", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "7d390b8a244a17b8151e2a552bff1d77", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "10b54243335e704f02303c8959e84535", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "209332ef3b3b7c081e620ce00c9e79f6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "762f0b3d5dec7cac3cab3bf517b24985", "time": { "mYear": 2020, "mMonth": 3, "mDay": 24, "mHour": 12, "mMinute": 51, "mSecond": 46 } }, { "id": "704d3eca14ef09fe7f6403fc28b30af0", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "31bc71d11e040f296289400255cd44e0", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0bb21fcf2a9d59731e6f7bcb5f790769", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "127a2878256c72d05bbc46b313760577", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "67924967653217e15b5c266e4eed361d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "7d843e5e0cde648337a05bb6623a2a00", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "32d449667c0b255a7aa57d1d3b6f0f44", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6ea314e470626614681843882a1803d1", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "33cb3c3034c56e73099d2edc35ec4dbc", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "267964fe2f9d001f378667c8063a3afc", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6371320a681e22eb5e37519315ad40b5", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "79bc326019263d237f137a627d8c1f45", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "089c41fc1ab81a672292049d196e2136", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "431f6a8b1fa51b507bcf13da74b15da5", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6eab1f21570e74c279d81a6629376682", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "7b1f59f85dc573751dfb30cd0f910f13", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "318353ef18463f74356c61cf62e2655d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "30c44f1d3a020549091368ee10242557", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2b793b1a747167266984178a32e32d37", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "75626bb107dc2e62446319ef51b22e72", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "65eb2f6f0461757f5a745acf68e36e25", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4c2040bc3f284f8d415e02a908746904", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3821097566522d056655626b4d6f6167", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "76b963ad2f355a7a0bfd6cfa57434173", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "28ea75e86ebe4d45722a4aa63c471559", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0540372660dd761419143ca574cb27e4", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "20324bc467e374d318f447cc01c33e40", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6178636c3089374f799f548b1d0d5689", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3f775a7f10983ba21cd81541526524cf", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "590b46df4f7122cb30614bba0f591559", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "52793ad12a1d17b438a07882274801d3", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "18664b4d2b3430cd005469184dcb7f59", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3ecc3c09309b6acd07400dab40ba53a5", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "68ca46120340458a6165262e65215b32", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "38e15d9337ec6c765a613ed6385a7259", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "142469090bcb20c24bd227f674f20695", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "304562300aa144977c64737149537ad6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "56585e75082216ba67755c2d5ecb6ed3", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "36ab678e3d2829e7337c50795c776702", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "71f906b500ad3db16f2e193f720901dd", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0c9c7079001e4d00039e31d77b0340e1", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6bd46d174c5778235f036c466a14569c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "52375c3f583904686b61698f023f6fdd", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "391d434423a375d232167252668112c2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5219235a0fc2622920a3158b12741171", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1f21370c782109b823d11e4a317c06ac", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "7575594d29b11a772b430135450f1abe", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "59c96a567a71232e4a442a3f16462b5d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "435138351b066b1e08794d583f1a5840", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "31a9020630255cc11b236fe16025516a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4b7125941858520c06572f0c31a365b1", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0f8341ea3e692c9911eb1daf1e9b4e7e", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "017a2a2a1df6218e168766c171e65c33", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "702f3b0e291b134e7fe656243bd33b7d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2bea1b0e0dc334ef4d7d73907776492b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "678f3b994792282b57067997708137b0", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "02d76c7230fb29d76262371646dc3718", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3bf44fd06dc15be1225c471977c55e24", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "15df295163e609cf295f4be120572807", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3a5d29a31f5522ff1742339438281665", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4d7c59300b78244b250b3f14794f7c30", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "438b78a21bfe61f33790360a703b0b6d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "28ed12b864fb77e1596d23be6d7115ee", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "31d11d1b4ae008106f8569b959e72e8c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "07df580d646f523814fb1dfa1a032880", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "35b70b7a022239575e6c5caf32445477", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4e9c0a6367712dc71d7864e112ee1073", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "425b7bb56bf153692f200f30446701b8", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "262b5fdd68660a1c564463250003263d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5d65226a1e2816d050af554625192398", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "77d528f50f68274831a55392291b7727", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "36552ed1342572934c84007c190968b2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "591f03127b42058b52b7551d506b43d4", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0f5f2fb233a8486f279b12b338235635", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "32ad3f000a6b5fda39ad54624dcd1faa", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5a506fac4bd724fd7cb30e9324e33ac6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "48a803d01eba69a826b9433d1f5c74aa", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2b7c7314787e224a2d4e36000b1f2754", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5b4c2ea318924e6409f4639b047433f8", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "48bb0e912c9b39666e735b4e3a886eb5", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "45cc01cf1d6114d7161a0eb3016c3940", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "60ed725a3d34272d059324b94e692036", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "71ab5ce818200ebe79e5421f737858b9", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "60bf6b496ccd45d944ec41184aeb62c6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4f482b827d0e70ac4031022c21737971", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "478b75ef613a0f3f560513f2505f448d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "311766284f1a03f22a5646697a2b6471", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "27c90e13537260835a33574067e879b0", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3b8b47f65dba59ff46fa153361030882", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1f567fa431f2371a538646f27128767f", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "72082a1f02b2369a6ebe44f326513324", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3baa405d339f58ab636530c92f1310b4", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "72b3429c340349362c50008c3bf70c58", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "594e45a71e9b723423ff1c0b5c2732c9", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "00ed1560468115f6550541dc7ac54751", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "45a96f8d00a84100285c6c934c9a35d6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "23a50e686362786770a2329c58d95ee2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5f3057b6579c79624dab3a6e6509044d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "030001020f840bd92b4509cd2d577559", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "650f05bd13c30fe20cb51f072b7158ac", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "05fb7cb46f9b68b21b710da4496979be", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "525e72785d54327e07125b1e030e72b1", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4d0a16d335cf763c4b1b298e08c07386", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1f5749bc6ff127440b4144807aad3926", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "16aa3d2c44704f5d76fb7ba26d833596", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "731832515faa10846a4967e973b25d43", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "038b6ac03b5d39e44855155b2cfd17fb", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "047125ac645757370538749441e716aa", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "080c03bc303d37fc1b33333b4db333e4", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1b6724306a1b40cf2115319d1c381026", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2afb49b10d0a64ca2423073421b03e7c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3ffc4e9b156a328e75c2510a185e3447", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5f116ccb51b84961716a02cf69bb3f66", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "56130790077f636835d452e879313909", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "318a6c664a451b14170075374d942536", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "17a1715932ee790051a81af35bf310aa", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "657d27f6662b025769741b7571df4551", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "602a754042293ca8784648ab0974477d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5bf81ee545af13071b9d7e2877f00610", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "40c87ec45ab06d5067f2199828893b23", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "453a7b68174246e27a370e083f806b91", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "12a80f3344a31e2d3354161c2f944638", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "445f076b10cc17e92b30538f1c3c0bfc", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "041862435ce94df953a73a501775426b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "160104da0967563125ad686703e8527a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0804451b664226dd06421c3039062bea", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "788e1b0b00887b2d07756cbf62855cb3", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "37cf2b1b28ac5e1b0272688960da3faa", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2aed7e4e04982b9d10b05c736fb253fe", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "44f97eb708244d9d3a82672828ff5ab6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1d4f08fb7872523b28f226cc40766a4f", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "529e59f47958149e773d7ee574b446aa", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4b3d777c3edd7518080a277b3bfa1296", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "351040c57b69389a361e3ea6791f1f9d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "09df6a6c4d7b25e139f063be7a356bde", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "20d96f61176b2d6d7fb91235159d44f5", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6bfe26935ff23aca66982fc5129f62a5", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "11871a410d053f797d83262c17f5568c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "58614ed9192c5a003133737e45ec1585", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6cd41ccc028c51c461a5755c16c4120b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0a77395b4cd81aed6a55012160e32ffe", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "488377f87257761c278906856d810341", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4392114d25d616c562b14a96373a52bb", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1b107fba691359fe56301c2537d311b8", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "68176d7a25466a163a972c1d02f90197", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "546234b9099b361750c635157f2232cb", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6d8e26bf1c642edf1421275871e44c4d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "190819b830c0514328f239ab1fa67c72", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "59ea323733796f7b522f19622984279d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "29991fdb6c684da368e2435d6a7a6c92", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "42f7050e392b57a01bda55e42a101505", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "38515d6a082a49430c38322b35f51152", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "68a8066d52ea4321063e1de047a508d6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "79930dd67ade03ed2f0317fc55680239", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "32794f087da131ca780428ad6fd463fa", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "233c0d4269646e2f31e71b8d5d1e5fc4", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "78813a607702658230400ce6143a0a8f", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "027c5bd1366578a42cb4406a763b0c36", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "559c35ba2dc500b9146c6f654b925b14", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "53b81d1c1d7b359b7833213467275026", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1fd643e3718b28ec40157bf56fcb590d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "54be57b767d45e0437b4256e70044b16", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "7b175e291a460aec259d179c58511101", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "54aa383b507022dd4d0b371f2a8b24d2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "09b44d6a4e8927f40a6826c07d5b69f9", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "684c733646a47f364a4c3fc716dd5c63", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "27587cbc421e343b6a172ac445976fbe", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "66a662840f893c5e33eb68ff57751cb1", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "54c045d717b271dc10bd5e9f69611522", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6f632454112e23a87ded0987767167d8", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6b31296c3d3c54f062913bac516e6eb8", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "785d75a7453d47d907d2717527b01b21", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3d9f26d140170fd2694b3a9a0b4b01fc", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "645c0d9811e46c6a0ff0007649142762", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "562938681f5f234d3cb33c9d46e75071", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "39fb6a9f2c400a6b36e0614432c44b89", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "423a2e4971d01ef40b016611069c7e89", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "25803a3e06cc40b82fcf214a2d4e3db6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "66ac154f1c1f06111075313339e66aa4", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6b470de62923542911ed03432213563c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "49914fd04c69532e2f686e70438246c7", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "74843ad46bb7716008181dde34275ad0", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5130158340bc173258075d59545861e1", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "25896a4c65bb6d021da41e1540b5348f", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6ee211ea0b413267340a3e665c800d55", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4694254d5c164bb85bae7b8c0ac82f28", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "538858b561c55f5768b558d868a1494f", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2cfd7d0d00a7628202907e0d10d33253", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3803547f5e515b5c33764a6736060bc7", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4ca64f006ea3650561c405895d7c75bf", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0d090480192b622f13f708e024385b7e", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6b283ee32c6032f821dd699566a924bc", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "693019e64db207b44941030950950f55", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "7c09624e7daa45ef4dd24628717942d5", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "07ac3a5f2251088947083bce123839b9", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0a0768d465c119435a1259a546b74bea", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "57ac6501709c48d3787b437546946c28", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "13591d571afc12bf6d712ee753750268", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "10da4daf062652a1109870f7341a00e6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "100946df482b0cda570110de23e93351", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "62dd34421c60266949cd2c982d905c03", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4e5b4e066f10548e335210236af46e01", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0ca3463a618a4f0e52eb0cd473541835", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "324112a175042fb832b233fb2d950b2b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "32a52dc06a01174c24c91fd0470b521f", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4ac760b64c831cd8030c07d77097254f", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "749b253c0a4659251eb1169857b81aa6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6c030fca2a162fbc3b713e6b347409bc", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "01c62a82737d79b045f411651bdd2ce6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4469659002a71b5f254f744108064c02", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "789c46ae7749792468c0759112c07c8f", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1db20a2430920e752fbe48f84c6c26f4", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4bfd046473e85477661226ea70543b7a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2bc876eb20e874f138c80aa13c010fcd", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "77c5378922e432762d8578080cbb35bd", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "792525843ae60c666e3b7e9100bd36ac", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "27250e883db655432ad15beb37827100", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "15d21a945b6a61cd10eb51d973764806", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "699270fa415802b04fdb6f4c53fc365c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6e6747dd38b07eb6388b25ff595e2cee", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "13cc3f4f45710a54352307ef5f001eef", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5a320d131c7e7d0e31c272165b195cd1", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "03a5164927dd0e7d254555f3454f1205", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "24cb3cd12ba628cd1c366e721f9767e5", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "677c5cdb367c384b455a6201167a2109", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4b587658011b29bb03cd435336194c6c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1a1a5d462ec011d23a095fa761211711", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6c06665158ed26e82d8306d04f9f73c4", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4fc26f8f22f13b4d2b45412a54061211", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "065572d91dd10e4d6ac06cf049d44336", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "112e27b2699838915c2728de34f6766a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "489b66c526fb155d37935e626a35213e", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "005b202c650949397c95564d0de102f5", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "04d6224a54773744177e575760953423", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6031706418516c4355323b481f555675", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "75fd696b197523351ff218f2007b35fa", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6d66543e4b014c561fc16c7c7b792e44", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "35d73d3060ef522f728d654c31bb3732", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "765f0d4e10b21aec273c3d092d27126e", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "029a646b21e3528d523f7a3f36cb4a7a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "782607554b0f21084ded5ae06a3d68b6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "06834b90737824c019bf06f575bc5511", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3e6d21de649d6d8671587a2505f42bcc", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1b582c1d0d7c08d64ec65c182cf83ea7", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "30f6096246af62b6395e17092ead3fa5", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "19f41dea4e4a13f50a020e2f72220b70", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4d345a677c6e5c0e41196c7568304c76", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6fe3096f11792bb14ea020781f2a1e2d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2640510a17026a0e32b31efd3c402c0d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2a13006326f35cff2c0408dc48be0f54", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "75de6acf151e03724be01ccc668037bf", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "44f367b43ad37edf74d46dbf21954378", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6b9e3a777ef30b0346e62cb63ca10d5a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3b9f525e4be211da376e4f8e667b4e95", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "41516f7f0265318f5f6d731f16f66682", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6ca8496030160e99272a75a135454b85", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "69a564a235c80c55159e50d8601030df", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "591a19c30f2c066a3e9d0ac23d5636aa", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "54533c7853254fc26d4f6bd9082129a8", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0824555552e83f137bea39715a717db2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "79ab3e2b2d254269187d39fd7f766955", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "737a6f90605173ff5aee59a84e7456ac", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5a052c9c3bb10d494da427ce2dcc6d0b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3d92112b49ba16f46aa3249767164401", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "42de0d960e43186b233a053066245c1d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "124c7226031f44cd20fe5a9b6c5d1ac2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "36381ab856e21d206b244e1b06737b5b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6f1c03c31634776772b40eb339ba39a1", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "35de0b9966e72d501fd4124c61413f86", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "627879c55d55252c12e70ff81ba77503", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1f9e44ef743150ce413f35206e607f8a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "66222199071f48b65a517562683657cb", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "50600547271f4d2f38d4282109604b00", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "35ab75a033eb67461637458a31c20f06", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "500247f24466585a79427cfa01af7dce", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2b5175271de526a5147d745d6ea900f7", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3c40393d03af1c4760f92eee1a6666f3", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "631d77e84a46720c07800e75562e0706", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "03d8647120c94ede2993460304155899", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "34c1728e5959446a322b3abd0166447c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "55864ae04d8d76e3674a5d3f210d0132", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6c7d7204331f14d86774363220a767b0", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0b78004054635ed540d678bc332c3c87", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "28e813ef74100f1012ba2a92173f42ae", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "47b36fb265a33d7264b108b71f49788d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "78fd4fd32460578e71a660494ac229b5", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0ffc467840e900ce18ad18ce4da851da", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6e031d4c1377202c3a5a783240f55e49", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0a1801bb711a77c60d1679f411b36610", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "7497418a192e3b84404d30cc3125162b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1d7a57f110e27e926320191b2c1f3c6e", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "466209b744113e2e2f00468514096178", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "13de255c0a0f177552c23a120e360df8", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "121e600f2a8b13aa511c2b4a11693ee9", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0022335023a07b4b394c61236933222a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1e0d548b73bc26bc2c0e538329f5163b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5fb07cdf72db68ec2383741603480b53", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3bb56ec16bfd38e07e6d0ebc282642fa", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "429c14fb5b927a6c63d37e4a16e82996", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "31e057267cbf1b5444701f1722b74eb2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "717f148f5dd235e30a7732a50c550b8e", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "749d29bb6c3779a535123773412905ad", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "748d796725b867fd6135105725ee07d7", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0d1a159f71725db57bc8657c7a34211a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "18770e601cfa5abd72cb7b061296152f", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "296609f45d5c66f1662224e457af5253", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6c0b3f44539347465fbc4ca23cfd630b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "69d8209312f214ac766623ce37fc368c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "780f085f12c9163638327be949611fc8", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2b72590d15f550c512e446de2cd73200", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6e5320454c85738663ce23b55dbd4dfa", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2e9d76dd344d6a7628982a922dac3778", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4f0c3185756751f601600a741a761dd6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "69de633d136b4c903d2d39f74bc7566a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "00a120c04e8d576676041a9f78ed6876", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "49be56066b956738561b3410432148f6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "699b04077c1b0a016a8f17de78fb4bf8", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3413234a0ae275d734b158ae52574be2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "72c5439208a9592b0e70560e6dcb2704", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "36560cd15c64708710a74d6c17562771", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "7da75a6938e7194d2d4a3a62615565fc", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3a474acb2c6e301c56005dfa28900761", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "51ff7c566d413ee67fd406f012de66c1", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "74086a597ee67e91405c1a0b0efe419b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "781a427a28b90ffe23a75d426a9443e6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "763732ef5458313915c3067a2b3c4e4b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2e1f151556f90d6c00794feb232c0812", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5e4c46fb29056c521b45568c43bc3c9d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3aa5715005765c392f0e0bc013f82e10", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4b426c1230e851bb43645f874af90c0f", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "660054543ee938f231472c8a3e9115a2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "41fe49c7590a4fef6c2220df1d7b7d87", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "560f6bd82c4c4ef635813018768d064b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "78d153c7721c600652de44a443fc762d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "729f389179896e145e2c2d9f4601358c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3a16329731654e127b140d834daf3014", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "649a34d011312f0053bb7a6049d87c68", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "01f342d9768621963e463c1f6bd61e6c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4b1576cd389d313448200d037bee454d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "22fc284427297a99761a2732351e3bcd", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "36e2240d67b63628380f00e10ff525e4", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "456610a279177bd27132039f6c9c046a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0a7e1d772d8163c74c276b82046055af", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "54772db77d4168b17bd54bc47eb81845", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3f02032807bd607762ab0ee748924b0c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "7308512942a4704708ca55320bc953a9", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "14cf63ef797313a57f5c1d0e36954c80", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "432e3cd02deb14824fb749746eb841c9", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4be6659607ff04405eed6a4f5c7641d8", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4bba69197e1d50a716f838f4297a08c6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5b492262019075be60c50c7a7a8f4439", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2e3d582e085c21d943eb68c334e954c8", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "55612948208b611c6518424a33152bfc", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "17eb725123f5219028c552b8149f330c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1b4e1f836afb6b7a38b32c5d7e8c31aa", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "55ed66a92fe1176674d36fa95be23741", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1d66598e2402227f299625033b627c88", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "200f651f024d34763b852794303a23d2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "41f672d310b84eb418f54de266564b7c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4be121ca5a8346872dc606b94bcc4903", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "202924a37cfe76312bba65d85a083037", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "10d90c2d06855e3e6f8d34405b4b079a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "32a2400c7dcb7aaf29e3729e0015524c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1a0c0677587a3c73719c6aa379d113c1", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0f555e523e671f08741010d779e5363a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5ffb001041e4477b5e952bda0c994001", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "683a62fd1b9a26a86d3a1c046dd871aa", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "641a79ea094a621145ea6c3369474ce4", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4a446b731cad7540075e713659336d0e", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "780a1a5d6ce91d64442a0f8f708e2023", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4458068263d003483fca161a66a50c84", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "69826e777c0875aa2538405f72e1787f", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "35d45597574d6da4125d56f026622089", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5fff73d414ad467e03685d0a6614095a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6d502dbf63ec3d501f4f242f091d31a8", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5dd75cf130c54760239a02887dc27cc7", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "51ce450e4dde5a940e313b1f579833ec", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "52e145054c0f496f3aa67d424e485af4", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "06a16251065b6c4308414f0b052c5a3b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1d7a7eac346469fc025a054e41e97b4b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2726133a77804ef50abf7de97d40637b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "33dc27782cbd3b856f98546a48551add", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "69056cee22f677695d9540140be069f5", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0096333b50663c5276a9663e2ae53701", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6f646670444357a320e9423f2eaa4e80", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "299b48e027d0686405925a2412df3f79", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "41d93c2b3a39274a7d35039540fe3aab", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "07f6672722551dc57802769e0a7a4c8d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "44b8262876e4683548b83b554e544bd7", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6fd46d247f183bac5c7f17e55d937922", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5dc21695180c481f79594f2943d77fa5", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "779a6db61bdb3be37c723d6d13055ba2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6a387bd918eb39f3079a75796db55d4a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "774865b273573cf4092515ec758a5a00", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "36942f0200314c5e55a2550f113325d4", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "468a0f7c35cb0353298d77d67de26056", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "525f69b859154d322a44304944642d03", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4c237879436f27d225870c8c10c8650d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "65472887152f187c50a824111b2646a2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0c560598714a2c8b3eb82ae603ee78bd", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3cb634ec0c2a4357104d377d5b6b70f3", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "661810ae7278533651ab14ce7d5b02ea", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3b1d60a914de1949664603c71e29748a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "45d262ce5cd66abb769443f0020c0644", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "06470f6928c4378e7c1e31f413a137dc", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "221859314013209c72795c99260719ed", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "07217ad66edd15986cda39045abb1de8", "time": { "mYear": 2020, "mMonth": 3, "mDay": 24, "mHour": 12, "mMinute": 51, "mSecond": 46 } }, { "id": "1b293703451e37d706fb7748469e08bb", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2adb56610cab4d602fb6062b582b7c61", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "29821f7977603f9b4d555dd659f271a7", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3c374faa59f4169e448640451e8c7999", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "531d00e7050764177538268b12226ef5", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "422043c2736f09560c6d21e658ee7683", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0edd5cf06d14584b2a7a6f6c109b667d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1a36752146b9557f7cd761ba79d47e94", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1813201c420a5b7b05ae23f244553190", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "478514024c9c0cb854b9126c2f2d2607", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "650c7b66370f2b0460fe0509059666e4", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "52c8772f641a30933b5c46be47a80b53", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "19f1480664de4c0b1d4f58ef04ba19e4", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "032d7cf61fd679320acb69bb42de42ce", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "234425ff2d201c58768a5aad661228d2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0e1b4c9d732143c0649c77fd4cc95098", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2e3a772860da3b1d3db2226504fe236f", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "00e30bf2552d06127c1d6bd6121b6df3", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3bc720c118ed0f71156b56ff220517ad", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3ccc453a1b03741164900bd765750438", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1f344e0b73185347370b0778377d49a9", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "127e42dc65cf0e39157e1ea817ad6c4b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "15d62b872c3534251a074af843192a3f", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "72381902329400821187457f66005e84", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "7fae2e1d1d9245d2651a47c07c2868cb", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3b0a3d7952be0a6a56036a5675792f0b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3bf440583f843a155ddd77b4244706a2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "307655027af95f14370c2ffc61632f01", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "27ed427925bf0f15242e054d7d15565c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "02093ccd514e707f0d97363b5a586089", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0c6a5d8a4a661a94747c6bf051ae52cc", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6338023a6c50328d3bab0bb453f864cf", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "607b57e75dfe1ee103b369af38ab75d0", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4126572b2947687f44c94e68660d1bca", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "72ed0fe553872449613d43ca0be545a3", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "7172077513da491f1f1046554a7d0bcc", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "365d6782616b35260cdd62af000c03d6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "7b5d00142e125b0b2fcb6ab768015af3", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "31d16bc164d5193d66cf30674a824bad", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2c77314d33f1336a1840362b2c9d1b2a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 24, "mHour": 12, "mMinute": 51, "mSecond": 46 } }, { "id": "4e001b7940a900a748a414b035541820", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0076397239c3101d45355ef116411c75", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6c1222e14ca4398d5c8d7cbc115f2840", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "470500a075811926793a60284b925a5f", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "08102b891cb142b90e4240df07f947c2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "67e9505e448369275b7a311b508f0755", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3db124b21b76367c60276e680ddd3a9a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "35ad0efb53496d0912370f7d051a1778", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3e3b1639646b2d8435c4415d5d424648", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "665a4ddc0a1b0a0e525770675ada557c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "5ed83b1a2d9554e654d616f1125770aa", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "69204e1d69a568237d6a5d6a1b7a3ef1", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "72e37ae1388974ad7a993d373ab56ba1", "time": { "mYear": 2020, "mMonth": 3, "mDay": 24, "mHour": 12, "mMinute": 51, "mSecond": 46 } }, { "id": "77d5176139101e81137d499c70052ebc", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "44b9252613bf763933ae3d0e36504f91", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4f1e6fa245900e7f0e8954af1a505ec9", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "657107580d8d6e2e2a095a9f3e5b2f5c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "4c3715695b1a3fed0d5a2a93447314df", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "18867189163f78f1110406954fc902d2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "06b2507f1dc27444485922973f1651c6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "112077614d0305be65f907c538ca1f62", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "74f605357436654a0cdb0ba9699d3617", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "548a54f733c041ff66a7740d3f6357c3", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "637e18d0543970a8502250431f967c02", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1efa5a3609e93b26740d4bbf59860925", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "54ed149d6c4009d64c685983728a1b1b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "006c29830a4061c219336f376edd7408", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "14466d616af14fdd3d94541c058c55ae", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2b19000955c963fd6c0b0af07fae2676", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "7112354647cc3b075496797f0e634a33", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "080924f564be321631537a4942fa64a9", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "23801071629939ea6a0054b87cdd16a9", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3c5000983faf14af2ff15e4628054e0f", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3c407b2b46f807e6602877a4259c2a79", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "7ba135291ad820ae241238582e671ba2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0064294220b1273b6b9152523b963cdc", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "082c7adc114072223f8624d3657d369c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "038d77b825c407256b1a319e5c182af9", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3f603a9e07a6001867272fca648e2d28", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2b594da76cd63ef042d21d0f7a5541b0", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3ec067b34c1273214d7136f173c51c04", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "67e86ce16b231d8d36f64ec14a9a1c99", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "06be084535be030858333acf49d92db4", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1fb37cfa09b15ef049c673f426384df2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "7260312d19e92c0d40c307a13e7355ed", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2476549e78e44b98719b14da5c4134db", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "681b1d0846ca2cf9407570075db31a2d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6e971e235a7c5b2101a4317503c85537", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2db22e592f981ca01e47235a71625654", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0733208b08c93dd669e00f4c219c633a", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "425d6b6b34666dfe66c0353b60a56594", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6daf1e8158c73247507728605cb232fe", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "733601084caf34553ee648723c4f35be", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "480277a63e4f29092bd8095a558f0cf3", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "091e37dd7c032c6c589424ac64c816a4", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "043677d61cdb5b240952141e61df282e", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "328477442d7b256a29de46ec652366a7", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3a1771ad7b2c33446e9e4918798b0fa0", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "455655bc15fd1b43025130401fee2903", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "523d73dc430978bd205b62ac43d108f8", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "698b294551681f373f3a5d233f7c048d", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0824232e6191377627b702fc0f552603", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "6be0629a7f532e3b50cd6b8028780add", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "06d553a32bf63e3148df5308361e31a6", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "0a256d914aae1bef013f020f70dc0320", "time": { "mYear": 2020, "mMonth": 3, "mDay": 24, "mHour": 12, "mMinute": 51, "mSecond": 46 } }, { "id": "7fed733e18332f2d647354bf375820be", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "2cd15cc006a9434340881834695b201e", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "43ad697756894fa942a9115f69e858d5", "time": { "mYear": 2020, "mMonth": 3, "mDay": 24, "mHour": 12, "mMinute": 51, "mSecond": 46 } }, { "id": "774511dd0c17278327a37a61259312ec", "time": { "mYear": 2020, "mMonth": 3, "mDay": 24, "mHour": 12, "mMinute": 51, "mSecond": 46 } }, { "id": "46566cc7182e52e65ccb23636f311aec", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "54540c6d09e92f2072c56ff6229c42e2", "time": { "mYear": 2020, "mMonth": 3, "mDay": 24, "mHour": 12, "mMinute": 51, "mSecond": 46 } }, { "id": "3f541bd74565005f1e577dcd78607ee7", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "1e086ada4002060e2a9a18020d915e7b", "time": { "mYear": 2020, "mMonth": 3, "mDay": 24, "mHour": 12, "mMinute": 51, "mSecond": 46 } }, { "id": "66de7fe06fcf11d5534f7d306268399c", "time": { "mYear": 2020, "mMonth": 3, "mDay": 24, "mHour": 12, "mMinute": 51, "mSecond": 46 } }, { "id": "269832cd5b6d3c22365a05c128127d44", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "3a5d434026851c7718a1233d0ab2013f", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "106d599344ab622f788725dc1a9b2d40", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } }, { "id": "63bb6ee349d31989559f57c840d81866", "time": { "mYear": 2020, "mMonth": 3, "mDay": 10, "mHour": 14, "mMinute": 42, "mSecond": 31 } } ], "mImages": [ { "id": "63bb6ee349d31989559f57c840d81866", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "106d599344ab622f788725dc1a9b2d40", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3a5d434026851c7718a1233d0ab2013f", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "269832cd5b6d3c22365a05c128127d44", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1e086ada4002060e2a9a18020d915e7b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "66de7fe06fcf11d5534f7d306268399c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3f541bd74565005f1e577dcd78607ee7", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "46566cc7182e52e65ccb23636f311aec", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "774511dd0c17278327a37a61259312ec", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "43ad697756894fa942a9115f69e858d5", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "54540c6d09e92f2072c56ff6229c42e2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "7fed733e18332f2d647354bf375820be", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2cd15cc006a9434340881834695b201e", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0824232e6191377627b702fc0f552603", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6be0629a7f532e3b50cd6b8028780add", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "698b294551681f373f3a5d233f7c048d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "06d553a32bf63e3148df5308361e31a6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0a256d914aae1bef013f020f70dc0320", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "523d73dc430978bd205b62ac43d108f8", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "043677d61cdb5b240952141e61df282e", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0733208b08c93dd669e00f4c219c633a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "480277a63e4f29092bd8095a558f0cf3", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2476549e78e44b98719b14da5c4134db", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "733601084caf34553ee648723c4f35be", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1fb37cfa09b15ef049c673f426384df2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6daf1e8158c73247507728605cb232fe", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6e971e235a7c5b2101a4317503c85537", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3a1771ad7b2c33446e9e4918798b0fa0", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "328477442d7b256a29de46ec652366a7", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "681b1d0846ca2cf9407570075db31a2d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2db22e592f981ca01e47235a71625654", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "425d6b6b34666dfe66c0353b60a56594", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "091e37dd7c032c6c589424ac64c816a4", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "455655bc15fd1b43025130401fee2903", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "7260312d19e92c0d40c307a13e7355ed", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "67e86ce16b231d8d36f64ec14a9a1c99", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "080924f564be321631537a4942fa64a9", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0064294220b1273b6b9152523b963cdc", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "7112354647cc3b075496797f0e634a33", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3c407b2b46f807e6602877a4259c2a79", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3f603a9e07a6001867272fca648e2d28", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "7ba135291ad820ae241238582e671ba2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2b594da76cd63ef042d21d0f7a5541b0", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3c5000983faf14af2ff15e4628054e0f", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "06be084535be030858333acf49d92db4", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "038d77b825c407256b1a319e5c182af9", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3ec067b34c1273214d7136f173c51c04", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "23801071629939ea6a0054b87cdd16a9", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "082c7adc114072223f8624d3657d369c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "06b2507f1dc27444485922973f1651c6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4f1e6fa245900e7f0e8954af1a505ec9", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "74f605357436654a0cdb0ba9699d3617", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "637e18d0543970a8502250431f967c02", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "112077614d0305be65f907c538ca1f62", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "006c29830a4061c219336f376edd7408", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "657107580d8d6e2e2a095a9f3e5b2f5c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "54ed149d6c4009d64c685983728a1b1b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2b19000955c963fd6c0b0af07fae2676", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1efa5a3609e93b26740d4bbf59860925", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "44b9252613bf763933ae3d0e36504f91", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4c3715695b1a3fed0d5a2a93447314df", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "548a54f733c041ff66a7740d3f6357c3", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "14466d616af14fdd3d94541c058c55ae", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "18867189163f78f1110406954fc902d2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "77d5176139101e81137d499c70052ebc", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "7b5d00142e125b0b2fcb6ab768015af3", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "470500a075811926793a60284b925a5f", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0076397239c3101d45355ef116411c75", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "665a4ddc0a1b0a0e525770675ada557c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "31d16bc164d5193d66cf30674a824bad", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3db124b21b76367c60276e680ddd3a9a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3e3b1639646b2d8435c4415d5d424648", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "69204e1d69a568237d6a5d6a1b7a3ef1", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "08102b891cb142b90e4240df07f947c2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "72e37ae1388974ad7a993d373ab56ba1", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "365d6782616b35260cdd62af000c03d6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "67e9505e448369275b7a311b508f0755", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "35ad0efb53496d0912370f7d051a1778", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6c1222e14ca4398d5c8d7cbc115f2840", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5ed83b1a2d9554e654d616f1125770aa", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "72ed0fe553872449613d43ca0be545a3", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4e001b7940a900a748a414b035541820", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2c77314d33f1336a1840362b2c9d1b2a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "7172077513da491f1f1046554a7d0bcc", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4126572b2947687f44c94e68660d1bca", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "27ed427925bf0f15242e054d7d15565c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3bc720c118ed0f71156b56ff220517ad", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0e1b4c9d732143c0649c77fd4cc95098", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "00e30bf2552d06127c1d6bd6121b6df3", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "72381902329400821187457f66005e84", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6338023a6c50328d3bab0bb453f864cf", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "02093ccd514e707f0d97363b5a586089", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0c6a5d8a4a661a94747c6bf051ae52cc", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "52c8772f641a30933b5c46be47a80b53", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1f344e0b73185347370b0778377d49a9", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "607b57e75dfe1ee103b369af38ab75d0", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "032d7cf61fd679320acb69bb42de42ce", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2e3a772860da3b1d3db2226504fe236f", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3bf440583f843a155ddd77b4244706a2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "7fae2e1d1d9245d2651a47c07c2868cb", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3b0a3d7952be0a6a56036a5675792f0b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "127e42dc65cf0e39157e1ea817ad6c4b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "15d62b872c3534251a074af843192a3f", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "19f1480664de4c0b1d4f58ef04ba19e4", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "307655027af95f14370c2ffc61632f01", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "234425ff2d201c58768a5aad661228d2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3ccc453a1b03741164900bd765750438", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "29821f7977603f9b4d555dd659f271a7", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1b293703451e37d706fb7748469e08bb", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4c237879436f27d225870c8c10c8650d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "774865b273573cf4092515ec758a5a00", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "36942f0200314c5e55a2550f113325d4", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0edd5cf06d14584b2a7a6f6c109b667d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "422043c2736f09560c6d21e658ee7683", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3c374faa59f4169e448640451e8c7999", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "468a0f7c35cb0353298d77d67de26056", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "06470f6928c4378e7c1e31f413a137dc", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "779a6db61bdb3be37c723d6d13055ba2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6a387bd918eb39f3079a75796db55d4a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2adb56610cab4d602fb6062b582b7c61", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "531d00e7050764177538268b12226ef5", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "221859314013209c72795c99260719ed", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "661810ae7278533651ab14ce7d5b02ea", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1a36752146b9557f7cd761ba79d47e94", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "45d262ce5cd66abb769443f0020c0644", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "650c7b66370f2b0460fe0509059666e4", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3b1d60a914de1949664603c71e29748a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0c560598714a2c8b3eb82ae603ee78bd", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "65472887152f187c50a824111b2646a2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3cb634ec0c2a4357104d377d5b6b70f3", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1813201c420a5b7b05ae23f244553190", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "525f69b859154d322a44304944642d03", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "478514024c9c0cb854b9126c2f2d2607", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5dc21695180c481f79594f2943d77fa5", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "07217ad66edd15986cda39045abb1de8", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "44b8262876e4683548b83b554e544bd7", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0096333b50663c5276a9663e2ae53701", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "69056cee22f677695d9540140be069f5", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "06a16251065b6c4308414f0b052c5a3b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "33dc27782cbd3b856f98546a48551add", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "69826e777c0875aa2538405f72e1787f", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1d7a7eac346469fc025a054e41e97b4b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "07f6672722551dc57802769e0a7a4c8d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "35d45597574d6da4125d56f026622089", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2726133a77804ef50abf7de97d40637b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6fd46d247f183bac5c7f17e55d937922", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "41d93c2b3a39274a7d35039540fe3aab", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6d502dbf63ec3d501f4f242f091d31a8", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4458068263d003483fca161a66a50c84", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "51ce450e4dde5a940e313b1f579833ec", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "299b48e027d0686405925a2412df3f79", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "52e145054c0f496f3aa67d424e485af4", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6f646670444357a320e9423f2eaa4e80", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5fff73d414ad467e03685d0a6614095a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5dd75cf130c54760239a02887dc27cc7", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "22fc284427297a99761a2732351e3bcd", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "683a62fd1b9a26a86d3a1c046dd871aa", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3a16329731654e127b140d834daf3014", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4a446b731cad7540075e713659336d0e", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "55612948208b611c6518424a33152bfc", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "41df300a33bc6fe365c7553102276156", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1b4e1f836afb6b7a38b32c5d7e8c31aa", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "36e2240d67b63628380f00e10ff525e4", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "14cf63ef797313a57f5c1d0e36954c80", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "17eb725123f5219028c552b8149f330c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "780a1a5d6ce91d64442a0f8f708e2023", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4be6659607ff04405eed6a4f5c7641d8", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "10d90c2d06855e3e6f8d34405b4b079a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4b1576cd389d313448200d037bee454d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "456610a279177bd27132039f6c9c046a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "7308512942a4704708ca55320bc953a9", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2a7b1669373d57e42f9035225a4a4c22", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "01f342d9768621963e463c1f6bd61e6c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "200f651f024d34763b852794303a23d2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "202924a37cfe76312bba65d85a083037", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "641a79ea094a621145ea6c3369474ce4", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4bba69197e1d50a716f838f4297a08c6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2e3d582e085c21d943eb68c334e954c8", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "55ed66a92fe1176674d36fa95be23741", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1a0c0677587a3c73719c6aa379d113c1", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "432e3cd02deb14824fb749746eb841c9", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "54772db77d4168b17bd54bc47eb81845", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "32a2400c7dcb7aaf29e3729e0015524c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5ffb001041e4477b5e952bda0c994001", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4be121ca5a8346872dc606b94bcc4903", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "649a34d011312f0053bb7a6049d87c68", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "41f672d310b84eb418f54de266564b7c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1d66598e2402227f299625033b627c88", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0a7e1d772d8163c74c276b82046055af", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5b492262019075be60c50c7a7a8f4439", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "078a5c5269ee695a722144d642937467", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0f555e523e671f08741010d779e5363a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3f02032807bd607762ab0ee748924b0c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3ed409235a342972306c7b0933647511", "time": { "mYear": 2025, "mMonth": 4, "mDay": 1, "mHour": 23, "mMinute": 15, "mSecond": 32 } }, { "id": "717f148f5dd235e30a7732a50c550b8e", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6c0b3f44539347465fbc4ca23cfd630b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "41fe49c7590a4fef6c2220df1d7b7d87", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "749d29bb6c3779a535123773412905ad", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "429c14fb5b927a6c63d37e4a16e82996", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6e5320454c85738663ce23b55dbd4dfa", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "72c5439208a9592b0e70560e6dcb2704", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "560f6bd82c4c4ef635813018768d064b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6935315628ef0c881f764b0a5ba74fe7", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "36560cd15c64708710a74d6c17562771", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2b72590d15f550c512e446de2cd73200", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "51ff7c566d413ee67fd406f012de66c1", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0d1a159f71725db57bc8657c7a34211a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "699b04077c1b0a016a8f17de78fb4bf8", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0e971cc24ed76b3a01e2479e36e876fd", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2e9d76dd344d6a7628982a922dac3778", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "74086a597ee67e91405c1a0b0efe419b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "00a120c04e8d576676041a9f78ed6876", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "7da75a6938e7194d2d4a3a62615565fc", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "296609f45d5c66f1662224e457af5253", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "49be56066b956738561b3410432148f6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "748d796725b867fd6135105725ee07d7", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "18770e601cfa5abd72cb7b061296152f", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "780f085f12c9163638327be949611fc8", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "781a427a28b90ffe23a75d426a9443e6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "729f389179896e145e2c2d9f4601358c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "78d153c7721c600652de44a443fc762d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4b426c1230e851bb43645f874af90c0f", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "763732ef5458313915c3067a2b3c4e4b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2e1f151556f90d6c00794feb232c0812", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5e4c46fb29056c521b45568c43bc3c9d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "69de633d136b4c903d2d39f74bc7566a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3a474acb2c6e301c56005dfa28900761", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4f0c3185756751f601600a741a761dd6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "660054543ee938f231472c8a3e9115a2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3aa5715005765c392f0e0bc013f82e10", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "31e057267cbf1b5444701f1722b74eb2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "69d8209312f214ac766623ce37fc368c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3413234a0ae275d734b158ae52574be2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6e031d4c1377202c3a5a783240f55e49", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6c7d7204331f14d86774363220a767b0", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3bb56ec16bfd38e07e6d0ebc282642fa", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "34c1728e5959446a322b3abd0166447c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "47b36fb265a33d7264b108b71f49788d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3b9f525e4be211da376e4f8e667b4e95", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2b5175271de526a5147d745d6ea900f7", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "627879c55d55252c12e70ff81ba77503", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "42de0d960e43186b233a053066245c1d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "66222199071f48b65a517562683657cb", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "310c57c01d81514264a35e92147c0695", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "54533c7853254fc26d4f6bd9082129a8", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "631d77e84a46720c07800e75562e0706", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "36381ab856e21d206b244e1b06737b5b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3c40393d03af1c4760f92eee1a6666f3", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "124c7226031f44cd20fe5a9b6c5d1ac2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6ca8496030160e99272a75a135454b85", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6f1c03c31634776772b40eb339ba39a1", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1d7a57f110e27e926320191b2c1f3c6e", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "35de0b9966e72d501fd4124c61413f86", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3d92112b49ba16f46aa3249767164401", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "03d8647120c94ede2993460304155899", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "28e813ef74100f1012ba2a92173f42ae", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "79ab3e2b2d254269187d39fd7f766955", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1aad7e376c1866741eec7af66d88718e", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1f9e44ef743150ce413f35206e607f8a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "13de255c0a0f177552c23a120e360df8", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "737a6f90605173ff5aee59a84e7456ac", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0b78004054635ed540d678bc332c3c87", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "466209b744113e2e2f00468514096178", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "41516f7f0265318f5f6d731f16f66682", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0a1801bb711a77c60d1679f411b36610", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "591a19c30f2c066a3e9d0ac23d5636aa", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5a052c9c3bb10d494da427ce2dcc6d0b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "35ab75a033eb67461637458a31c20f06", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "50600547271f4d2f38d4282109604b00", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1e0d548b73bc26bc2c0e538329f5163b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0824555552e83f137bea39715a717db2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0ffc467840e900ce18ad18ce4da851da", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "500247f24466585a79427cfa01af7dce", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5fb07cdf72db68ec2383741603480b53", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "78fd4fd32460578e71a660494ac229b5", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "121e600f2a8b13aa511c2b4a11693ee9", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "55864ae04d8d76e3674a5d3f210d0132", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "69a564a235c80c55159e50d8601030df", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0022335023a07b4b394c61236933222a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "7497418a192e3b84404d30cc3125162b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "35d73d3060ef522f728d654c31bb3732", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6c06665158ed26e82d8306d04f9f73c4", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "065572d91dd10e4d6ac06cf049d44336", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "30f6096246af62b6395e17092ead3fa5", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "03a5164927dd0e7d254555f3454f1205", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "75de6acf151e03724be01ccc668037bf", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6b9e3a777ef30b0346e62cb63ca10d5a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "489b66c526fb155d37935e626a35213e", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "792525843ae60c666e3b7e9100bd36ac", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "15d21a945b6a61cd10eb51d973764806", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "19f41dea4e4a13f50a020e2f72220b70", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4d345a677c6e5c0e41196c7568304c76", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6fe3096f11792bb14ea020781f2a1e2d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "77c5378922e432762d8578080cbb35bd", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1a1a5d462ec011d23a095fa761211711", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1db20a2430920e752fbe48f84c6c26f4", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2640510a17026a0e32b31efd3c402c0d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1b582c1d0d7c08d64ec65c182cf83ea7", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4fc26f8f22f13b4d2b45412a54061211", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "32a52dc06a01174c24c91fd0470b521f", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3e6d21de649d6d8671587a2505f42bcc", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4bfd046473e85477661226ea70543b7a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6c030fca2a162fbc3b713e6b347409bc", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4ac760b64c831cd8030c07d77097254f", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "765f0d4e10b21aec273c3d092d27126e", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "749b253c0a4659251eb1169857b81aa6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4469659002a71b5f254f744108064c02", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "005b202c650949397c95564d0de102f5", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2bc876eb20e874f138c80aa13c010fcd", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "029a646b21e3528d523f7a3f36cb4a7a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6d66543e4b014c561fc16c7c7b792e44", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "13cc3f4f45710a54352307ef5f001eef", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5a320d131c7e7d0e31c272165b195cd1", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "24cb3cd12ba628cd1c366e721f9767e5", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6e6747dd38b07eb6388b25ff595e2cee", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "677c5cdb367c384b455a6201167a2109", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6031706418516c4355323b481f555675", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "324112a175042fb832b233fb2d950b2b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "699270fa415802b04fdb6f4c53fc365c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "112e27b2699838915c2728de34f6766a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "04d6224a54773744177e575760953423", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "01c62a82737d79b045f411651bdd2ce6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "44f367b43ad37edf74d46dbf21954378", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "782607554b0f21084ded5ae06a3d68b6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0ca3463a618a4f0e52eb0cd473541835", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "06834b90737824c019bf06f575bc5511", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "75fd696b197523351ff218f2007b35fa", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "789c46ae7749792468c0759112c07c8f", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "27250e883db655432ad15beb37827100", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2a13006326f35cff2c0408dc48be0f54", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4b587658011b29bb03cd435336194c6c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5130158340bc173258075d59545861e1", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "7c09624e7daa45ef4dd24628717942d5", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "538858b561c55f5768b558d868a1494f", "time": { "mYear": 2026, "mMonth": 4, "mDay": 10, "mHour": 22, "mMinute": 39, "mSecond": 23 } }, { "id": "4ca64f006ea3650561c405895d7c75bf", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "66a662840f893c5e33eb68ff57751cb1", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "13591d571afc12bf6d712ee753750268", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "693019e64db207b44941030950950f55", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6ee211ea0b413267340a3e665c800d55", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "74843ad46bb7716008181dde34275ad0", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "62dd34421c60266949cd2c982d905c03", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2cfd7d0d00a7628202907e0d10d33253", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "07ac3a5f2251088947083bce123839b9", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "562938681f5f234d3cb33c9d46e75071", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6b470de62923542911ed03432213563c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "645c0d9811e46c6a0ff0007649142762", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "66ac154f1c1f06111075313339e66aa4", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "100946df482b0cda570110de23e93351", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0d090480192b622f13f708e024385b7e", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6b283ee32c6032f821dd699566a924bc", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "09b44d6a4e8927f40a6826c07d5b69f9", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4694254d5c164bb85bae7b8c0ac82f28", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3803547f5e515b5c33764a6736060bc7", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4e5b4e066f10548e335210236af46e01", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "25896a4c65bb6d021da41e1540b5348f", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "25803a3e06cc40b82fcf214a2d4e3db6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "54c045d717b271dc10bd5e9f69611522", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "423a2e4971d01ef40b016611069c7e89", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "785d75a7453d47d907d2717527b01b21", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "54be57b767d45e0437b4256e70044b16", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6b31296c3d3c54f062913bac516e6eb8", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "53b81d1c1d7b359b7833213467275026", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "54aa383b507022dd4d0b371f2a8b24d2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "10da4daf062652a1109870f7341a00e6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "57ac6501709c48d3787b437546946c28", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "78813a607702658230400ce6143a0a8f", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "49914fd04c69532e2f686e70438246c7", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "684c733646a47f364a4c3fc716dd5c63", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "27587cbc421e343b6a172ac445976fbe", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6f632454112e23a87ded0987767167d8", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3d9f26d140170fd2694b3a9a0b4b01fc", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0a0768d465c119435a1259a546b74bea", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1fd643e3718b28ec40157bf56fcb590d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "39fb6a9f2c400a6b36e0614432c44b89", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "559c35ba2dc500b9146c6f654b925b14", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "7b175e291a460aec259d179c58511101", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "027c5bd1366578a42cb4406a763b0c36", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "59ea323733796f7b522f19622984279d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "37cf2b1b28ac5e1b0272688960da3faa", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "58614ed9192c5a003133737e45ec1585", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0804451b664226dd06421c3039062bea", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "11871a410d053f797d83262c17f5568c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "351040c57b69389a361e3ea6791f1f9d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "488377f87257761c278906856d810341", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2aed7e4e04982b9d10b05c736fb253fe", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "68176d7a25466a163a972c1d02f90197", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "445f076b10cc17e92b30538f1c3c0bfc", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1b107fba691359fe56301c2537d311b8", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "453a7b68174246e27a370e083f806b91", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "190819b830c0514328f239ab1fa67c72", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "160104da0967563125ad686703e8527a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "44f97eb708244d9d3a82672828ff5ab6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4af3567144e93bfb574d7eff08276b1f", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "788e1b0b00887b2d07756cbf62855cb3", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4392114d25d616c562b14a96373a52bb", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "79930dd67ade03ed2f0317fc55680239", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4b3d777c3edd7518080a277b3bfa1296", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "233c0d4269646e2f31e71b8d5d1e5fc4", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "68a8066d52ea4321063e1de047a508d6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "546234b9099b361750c635157f2232cb", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "09df6a6c4d7b25e139f063be7a356bde", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "38515d6a082a49430c38322b35f51152", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "40c87ec45ab06d5067f2199828893b23", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "32794f087da131ca780428ad6fd463fa", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "20d96f61176b2d6d7fb91235159d44f5", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6bfe26935ff23aca66982fc5129f62a5", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "42f7050e392b57a01bda55e42a101505", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5bf81ee545af13071b9d7e2877f00610", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6d8e26bf1c642edf1421275871e44c4d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "29991fdb6c684da368e2435d6a7a6c92", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0a77395b4cd81aed6a55012160e32ffe", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "041862435ce94df953a73a501775426b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6cd41ccc028c51c461a5755c16c4120b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "12a80f3344a31e2d3354161c2f944638", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "529e59f47958149e773d7ee574b446aa", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "56130790077f636835d452e879313909", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1f5749bc6ff127440b4144807aad3926", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "731832515faa10846a4967e973b25d43", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "16aa3d2c44704f5d76fb7ba26d833596", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "00ed1560468115f6550541dc7ac54751", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "047125ac645757370538749441e716aa", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "080c03bc303d37fc1b33333b4db333e4", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5f3057b6579c79624dab3a6e6509044d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "17a1715932ee790051a81af35bf310aa", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "602a754042293ca8784648ab0974477d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "72b3429c340349362c50008c3bf70c58", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2afb49b10d0a64ca2423073421b03e7c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "23a50e686362786770a2329c58d95ee2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "27c90e13537260835a33574067e879b0", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "525e72785d54327e07125b1e030e72b1", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5f116ccb51b84961716a02cf69bb3f66", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "657d27f6662b025769741b7571df4551", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "030001020f840bd92b4509cd2d577559", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "318a6c664a451b14170075374d942536", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "311766284f1a03f22a5646697a2b6471", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "650f05bd13c30fe20cb51f072b7158ac", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4d0a16d335cf763c4b1b298e08c07386", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3baa405d339f58ab636530c92f1310b4", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1b6724306a1b40cf2115319d1c381026", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "444571c9370c6315115f10624ab0015d", "time": { "mYear": 2025, "mMonth": 4, "mDay": 1, "mHour": 23, "mMinute": 15, "mSecond": 32 } }, { "id": "594e45a71e9b723423ff1c0b5c2732c9", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3b8b47f65dba59ff46fa153361030882", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "72082a1f02b2369a6ebe44f326513324", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1f567fa431f2371a538646f27128767f", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "038b6ac03b5d39e44855155b2cfd17fb", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3ffc4e9b156a328e75c2510a185e3447", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "05fb7cb46f9b68b21b710da4496979be", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "45a96f8d00a84100285c6c934c9a35d6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "478b75ef613a0f3f560513f2505f448d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "35b70b7a022239575e6c5caf32445477", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "438b78a21bfe61f33790360a703b0b6d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4e9c0a6367712dc71d7864e112ee1073", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "15df295163e609cf295f4be120572807", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5a506fac4bd724fd7cb30e9324e33ac6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6a7e3675537b2d771c25300f48634962", "time": { "mYear": 2025, "mMonth": 4, "mDay": 1, "mHour": 23, "mMinute": 15, "mSecond": 32 } }, { "id": "5b4c2ea318924e6409f4639b047433f8", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "32ad3f000a6b5fda39ad54624dcd1faa", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5cc7078218605bcf392a532264644d1a", "time": { "mYear": 2025, "mMonth": 4, "mDay": 1, "mHour": 23, "mMinute": 15, "mSecond": 32 } }, { "id": "60ed725a3d34272d059324b94e692036", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "262b5fdd68660a1c564463250003263d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3bf44fd06dc15be1225c471977c55e24", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "60bf6b496ccd45d944ec41184aeb62c6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "425b7bb56bf153692f200f30446701b8", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2b7c7314787e224a2d4e36000b1f2754", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "77d528f50f68274831a55392291b7727", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "36552ed1342572934c84007c190968b2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0f5f2fb233a8486f279b12b338235635", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "45cc01cf1d6114d7161a0eb3016c3940", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "48a803d01eba69a826b9433d1f5c74aa", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "07df580d646f523814fb1dfa1a032880", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5d65226a1e2816d050af554625192398", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "71ab5ce818200ebe79e5421f737858b9", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "591f03127b42058b52b7551d506b43d4", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4f482b827d0e70ac4031022c21737971", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3a5d29a31f5522ff1742339438281665", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3da4158824d77f8a722366e166d166ac", "time": { "mYear": 2025, "mMonth": 4, "mDay": 1, "mHour": 23, "mMinute": 15, "mSecond": 32 } }, { "id": "4d7c59300b78244b250b3f14794f7c30", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "48bb0e912c9b39666e735b4e3a886eb5", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "31d11d1b4ae008106f8569b959e72e8c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "28ed12b864fb77e1596d23be6d7115ee", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "20324bc467e374d318f447cc01c33e40", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "304562300aa144977c64737149537ad6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5f42584132dd50f7040b468c35b633da", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "36ab678e3d2829e7337c50795c776702", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "59c96a567a71232e4a442a3f16462b5d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3f775a7f10983ba21cd81541526524cf", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "1f21370c782109b823d11e4a317c06ac", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "142469090bcb20c24bd227f674f20695", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "68ca46120340458a6165262e65215b32", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "702f3b0e291b134e7fe656243bd33b7d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5219235a0fc2622920a3158b12741171", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "52793ad12a1d17b438a07882274801d3", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2bea1b0e0dc334ef4d7d73907776492b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0f8341ea3e692c9911eb1daf1e9b4e7e", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6bd46d174c5778235f036c466a14569c", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "56585e75082216ba67755c2d5ecb6ed3", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "02d76c7230fb29d76262371646dc3718", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "017a2a2a1df6218e168766c171e65c33", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "153a346b58f76ba94e416db20f587244", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "71f906b500ad3db16f2e193f720901dd", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "7575594d29b11a772b430135450f1abe", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "391d434423a375d232167252668112c2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "678f3b994792282b57067997708137b0", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "31a9020630255cc11b236fe16025516a", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3ecc3c09309b6acd07400dab40ba53a5", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "18664b4d2b3430cd005469184dcb7f59", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2c6a44ed41965abc1a6d17074f375ffd", "time": { "mYear": 2025, "mMonth": 4, "mDay": 1, "mHour": 23, "mMinute": 15, "mSecond": 32 } }, { "id": "00533d362a0c38c31f4d66921cac0be6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "38e15d9337ec6c765a613ed6385a7259", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0c9c7079001e4d00039e31d77b0340e1", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6178636c3089374f799f548b1d0d5689", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "590b46df4f7122cb30614bba0f591559", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "435138351b066b1e08794d583f1a5840", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4b7125941858520c06572f0c31a365b1", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "52375c3f583904686b61698f023f6fdd", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "3821097566522d056655626b4d6f6167", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6559699f7855266e0f686d614f992182", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "65eb2f6f0461757f5a745acf68e36e25", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "318353ef18463f74356c61cf62e2655d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "30c44f1d3a020549091368ee10242557", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0540372660dd761419143ca574cb27e4", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "7b1f59f85dc573751dfb30cd0f910f13", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "75626bb107dc2e62446319ef51b22e72", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "2b793b1a747167266984178a32e32d37", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "76b963ad2f355a7a0bfd6cfa57434173", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "28ea75e86ebe4d45722a4aa63c471559", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "4c2040bc3f284f8d415e02a908746904", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6eab1f21570e74c279d81a6629376682", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "33cb3c3034c56e73099d2edc35ec4dbc", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "267964fe2f9d001f378667c8063a3afc", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "79bc326019263d237f137a627d8c1f45", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "089c41fc1ab81a672292049d196e2136", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "32d449667c0b255a7aa57d1d3b6f0f44", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "67924967653217e15b5c266e4eed361d", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "431f6a8b1fa51b507bcf13da74b15da5", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "127a2878256c72d05bbc46b313760577", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6371320a681e22eb5e37519315ad40b5", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "31bc71d11e040f296289400255cd44e0", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "7d843e5e0cde648337a05bb6623a2a00", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6ea314e470626614681843882a1803d1", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0bb21fcf2a9d59731e6f7bcb5f790769", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "209332ef3b3b7c081e620ce00c9e79f6", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "10b54243335e704f02303c8959e84535", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "7d390b8a244a17b8151e2a552bff1d77", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "704d3eca14ef09fe7f6403fc28b30af0", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "44402071050555a124c77e7344733da4", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "0a1b49284a84494d362b7baf1181176b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5c4657e95eb356133d6102ad258b38d1", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "6684387a17f21d804e0c625c3caf019f", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "048005dd1a3b5b24427623dc3ae543a2", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "37fb3fea30e501d008a455d6364c22cc", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "7167574c690f33d1144a07d126c80813", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5f5841267c8d387d7de441cf5c97258b", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "25fe24b15a643db6408474c87f060807", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } }, { "id": "5c8f735e0626703c68375587092b511f", "time": { "mYear": 2025, "mMonth": 3, "mDay": 27, "mHour": 13, "mMinute": 14, "mSecond": 27 } } ] } ================================================ FILE: Editor/Assets/BasicAtlas.atlas.meta ================================================ { "Type": "o2::AtlasAsset::Meta", "Value": { "mId": "6bd459187f2675966f8c67e46e525c59", "common": { "border": 2 } } } ================================================ FILE: Editor/Assets/Editor UI styles.meta ================================================ { "Type": "o2::DefaultAssetMeta", "Value": { "mId": "02481bc9676a33e752b64cab5a7d3f9e" } } ================================================ FILE: Editor/Assets/SimulationDevicesList.json ================================================ { "list": [ { "deviceName": "iPhoneX Landscape", "resolution": { "x": 2436, "y": 1125 } }, { "deviceName": "iPhone6 Portrait", "resolution": { "x": 750, "y": 1334 } }, { "deviceName": "iPhone6 Landscape", "resolution": { "x": 1334, "y": 750 } }, { "deviceName": "iPhone4 Portrait", "resolution": { "x": 640, "y": 960 } }, { "deviceName": "iPhone4 Landscape", "resolution": { "x": 960, "y": 640 } }, { "deviceName": "iPad Portrait", "resolution": { "x": 768, "y": 1024 } }, { "deviceName": "iPad Landscape", "resolution": { "x": 1024, "y": 768 } }, { "deviceName": "iPadPro Portrait", "resolution": { "x": 1668, "y": 2388 } }, { "deviceName": "iPadPro Landscape", "resolution": { "x": 2388, "y": 1668 } }, { "deviceName": "Nexus7 Portrait", "resolution": { "x": 1200, "y": 1920 } }, { "deviceName": "Nexus7 Landscape", "resolution": { "x": 1920, "y": 1200 } }, { "deviceName": "Samsung S10 Plus Landscape", "resolution": { "x": 3040, "y": 1440 } }, { "deviceName": "Samsung S10 Plus Portrait", "resolution": { "x": 1440, "y": 3040 } }, { "deviceName": "Samsung S10 E Landscape", "resolution": { "x": 2280, "y": 1080 } }, { "deviceName": "Samsung S10 E Portrait", "resolution": { "x": 1080, "y": 2280 } }, { "deviceName": "Samsung S10 5G Landscape", "resolution": { "x": 3040, "y": 1440 } }, { "deviceName": "Samsung S 105G Portrait", "resolution": { "x": 1440, "y": 3040 } }, { "deviceName": "Samsung S 8 Landscape", "resolution": { "x": 2960, "y": 1440 } }, { "deviceName": "Samsung S 8 Portrait", "resolution": { "x": 1440, "y": 2960 } }, { "deviceName": "Kindle Fire Landscape", "resolution": { "x": 1920, "y": 1200 } }, { "deviceName": "Kindle Fire Portrait", "resolution": { "x": 1200, "y": 1920 } }, { "deviceName": "Sony Xperia 10 Landscape", "resolution": { "x": 2520, "y": 1080 } }, { "deviceName": "Sony Xperia 10 Portrait", "resolution": { "x": 1080, "y": 2520 } }, { "deviceName": "MateX Fold Portrait", "resolution": { "x": 1148, "y": 2480 } }, { "deviceName": "MateX Fold Landscape", "resolution": { "x": 2480, "y": 1148 } }, { "deviceName": "MateX Portrait", "resolution": { "x": 2200, "y": 2480 } }, { "deviceName": "MateX Landscape", "resolution": { "x": 2480, "y": 2200 } } ] } ================================================ FILE: Editor/Assets/SimulationDevicesList.json.meta ================================================ { "Type": "o2::DefaultAssetMeta", "Value": { "mId": "3c6f682b546e7ed940df2de21774600f" } } ================================================ FILE: Editor/Assets/debugFont.ttf.meta ================================================ { "Type": "o2::VectorFontAsset::Meta", "Value": { "mId": "204d443723d72f2c138401f153a97a97", "mEffects": null } } ================================================ FILE: Editor/Assets/stdFont.ttf.meta ================================================ { "Type": "o2::VectorFontAsset::Meta", "Value": { "mId": "28ea3885486a6d3e5658445b2de14465", "mEffects": null } } ================================================ FILE: Editor/Assets/ui/.meta ================================================ { "Type": "o2::DefaultAssetMeta", "Value": { "mId": "dbfaa7613bd42d6c31f1f52c53a2f873" } } ================================================ FILE: Editor/Assets/ui/CurveHandle.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "31bc71d11e040f296289400255cd44e0", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/CurveHandleHover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "041862435ce94df953a73a501775426b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/CurveHandlePressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "35d73d3060ef522f728d654c31bb3732", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/CurveHandleSelected.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3b9f525e4be211da376e4f8e667b4e95", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/CurveSupportHandle.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "065572d91dd10e4d6ac06cf049d44336", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/CurveSupportHandleHover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "531d00e7050764177538268b12226ef5", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/CurveSupportHandlePressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "7b5d00142e125b0b2fcb6ab768015af3", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/CurveSupportHandleSelected.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "44b9252613bf763933ae3d0e36504f91", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/JSFileIcon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0a1b49284a84494d362b7baf1181176b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/TopologyTool.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6559699f7855266e0f686d614f992182", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_accept_prefab.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "07ac3a5f2251088947083bce123839b9", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_accept_prefab_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "72ed0fe553872449613d43ca0be545a3", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_accept_prefab_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "234425ff2d201c58768a5aad661228d2", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_actor_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "77d528f50f68274831a55392291b7727", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_add_asset_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6c06665158ed26e82d8306d04f9f73c4", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_anim_file_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "677c5cdb367c384b455a6201167a2109", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_asset_icon_selection.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0e1b4c9d732143c0649c77fd4cc95098", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_big_file_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "100946df482b0cda570110de23e93351", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_big_folder_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "79ab3e2b2d254269187d39fd7f766955", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_big_lock_close.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "03a5164927dd0e7d254555f3454f1205", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_big_lock_open.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "62dd34421c60266949cd2c982d905c03", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_big_lock_unknown.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "18770e601cfa5abd72cb7b061296152f", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_big_text_file_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "41d93c2b3a39274a7d35039540fe3aab", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_break_prefab.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "68a8066d52ea4321063e1de047a508d6", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_break_prefab_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "52c8772f641a30933b5c46be47a80b53", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_break_prefab_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "525f69b859154d322a44304944642d03", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_component_head.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "15d21a945b6a61cd10eb51d973764806", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_enable_dot_big.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "77c5378922e432762d8578080cbb35bd", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_enable_dot_big_unknown.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4f1e6fa245900e7f0e8954af1a505ec9", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_enable_toggle_big.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3f02032807bd607762ab0ee748924b0c", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_enable_toggle_big_focused.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "06d553a32bf63e3148df5308361e31a6", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_enable_toggle_big_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "523d73dc430978bd205b62ac43d108f8", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_enable_toggle_big_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "091e37dd7c032c6c589424ac64c816a4", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_eye_closed_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1f9e44ef743150ce413f35206e607f8a", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_eye_opened_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "66222199071f48b65a517562683657cb", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_filter_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "594e45a71e9b723423ff1c0b5c2732c9", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_folder_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "72082a1f02b2369a6ebe44f326513324", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_gear_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "7575594d29b11a772b430135450f1abe", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_gray_options.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "44f97eb708244d9d3a82672828ff5ab6", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_gray_options_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2e3a772860da3b1d3db2226504fe236f", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_gray_options_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3b1d60a914de1949664603c71e29748a", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_green_edit_box.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "01c62a82737d79b045f411651bdd2ce6", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_handle_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "749b253c0a4659251eb1169857b81aa6", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_handle_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "324112a175042fb832b233fb2d950b2b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_handle_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "559c35ba2dc500b9146c6f654b925b14", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_handle_side_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "45d262ce5cd66abb769443f0020c0644", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_handle_side_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "06470f6928c4378e7c1e31f413a137dc", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_handle_side_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "06a16251065b6c4308414f0b052c5a3b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_image_asset_back.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "72c5439208a9592b0e70560e6dcb2704", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_layer_big.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "02d76c7230fb29d76262371646dc3718", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_layer_icon_t.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4b3d777c3edd7518080a277b3bfa1296", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_link_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0c9c7079001e4d00039e31d77b0340e1", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_log_errors_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "03d8647120c94ede2993460304155899", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_log_errors_inactive_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3a1771ad7b2c33446e9e4918798b0fa0", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_log_info_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "54be57b767d45e0437b4256e70044b16", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_log_info_inactive_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "657107580d8d6e2e2a095a9f3e5b2f5c", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_log_warnings_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3a16329731654e127b140d834daf3014", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_log_warnings_inactive_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2cd15cc006a9434340881834695b201e", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_move_tool_center.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "74086a597ee67e91405c1a0b0efe419b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_move_tool_center_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "7260312d19e92c0d40c307a13e7355ed", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_move_tool_center_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "06be084535be030858333acf49d92db4", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_pivot.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5c4657e95eb356133d6102ad258b38d1", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_pivot_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3a5d29a31f5522ff1742339438281665", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_pivot_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "54aa383b507022dd4d0b371f2a8b24d2", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_pivot_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1b107fba691359fe56301c2537d311b8", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_position_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "09b44d6a4e8927f40a6826c07d5b69f9", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_prefab_link_big.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "78fd4fd32460578e71a660494ac229b5", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_red_edit_box.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6d8e26bf1c642edf1421275871e44c4d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_revert_prefab.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "684c733646a47f364a4c3fc716dd5c63", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_revert_prefab_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "365d6782616b35260cdd62af000c03d6", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_revert_prefab_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4126572b2947687f44c94e68660d1bca", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_right_move_arrow.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5e4c46fb29056c521b45568c43bc3c9d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_right_move_arrow_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1fb37cfa09b15ef049c673f426384df2", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_right_move_arrow_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "23801071629939ea6a0054b87cdd16a9", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_right_scale_arrow.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "641a79ea094a621145ea6c3369474ce4", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_right_scale_arrow_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0824232e6191377627b702fc0f552603", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_right_scale_arrow_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "328477442d7b256a29de46ec652366a7", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_rotate_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "525e72785d54327e07125b1e030e72b1", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_round_field.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "731832515faa10846a4967e973b25d43", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_round_field_focused.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0c560598714a2c8b3eb82ae603ee78bd", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_round_field_gray.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "51ff7c566d413ee67fd406f012de66c1", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_round_field_gray_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "043677d61cdb5b240952141e61df282e", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_round_field_gray_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3f603a9e07a6001867272fca648e2d28", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_round_field_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4c237879436f27d225870c8c10c8650d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_round_field_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6f646670444357a320e9423f2eaa4e80", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_save_gray copy 2.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3a474acb2c6e301c56005dfa28900761", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_save_gray copy.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5a320d131c7e7d0e31c272165b195cd1", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_save_gray.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "68ca46120340458a6165262e65215b32", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_scale_both.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3bf44fd06dc15be1225c471977c55e24", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_scale_both_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "35d45597574d6da4125d56f026622089", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_scale_both_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "14cf63ef797313a57f5c1d0e36954c80", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_scale_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "438b78a21bfe61f33790360a703b0b6d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_scene_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "28ed12b864fb77e1596d23be6d7115ee", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_small_panel_back.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "781a427a28b90ffe23a75d426a9443e6", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_small_panel_down_back.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0076397239c3101d45355ef116411c75", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_small_trash_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "7da75a6938e7194d2d4a3a62615565fc", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_tag_big.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "67924967653217e15b5c266e4eed361d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_trach_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "425b7bb56bf153692f200f30446701b8", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_transform_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6e6747dd38b07eb6388b25ff595e2cee", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_up_move_arrow.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "785d75a7453d47d907d2717527b01b21", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_up_move_arrow_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "69204e1d69a568237d6a5d6a1b7a3ef1", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_up_move_arrow_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "15d62b872c3534251a074af843192a3f", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_up_scale_arrow.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6fe3096f11792bb14ea020781f2a1e2d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_up_scale_arrow_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "54ed149d6c4009d64c685983728a1b1b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI2_up_scale_arrow_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5ed83b1a2d9554e654d616f1125770aa", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI3_add_btn.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "33cb3c3034c56e73099d2edc35ec4dbc", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI3_add_btn_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "562938681f5f234d3cb33c9d46e75071", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI3_add_btn_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "7497418a192e3b84404d30cc3125162b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI3_anchor_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "32794f087da131ca780428ad6fd463fa", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI3_anchor_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "789c46ae7749792468c0759112c07c8f", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI3_anchor_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2bc876eb20e874f138c80aa13c010fcd", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI3_anchors_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "39fb6a9f2c400a6b36e0614432c44b89", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI3_anchors_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1d7a57f110e27e926320191b2c1f3c6e", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI3_ch_arrows.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "142469090bcb20c24bd227f674f20695", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI3_icon_anchor.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "56130790077f636835d452e879313909", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI3_icon_max_size.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "423a2e4971d01ef40b016611069c7e89", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI3_icon_min_size.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "25803a3e06cc40b82fcf214a2d4e3db6", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI3_icon_offsets.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "190819b830c0514328f239ab1fa67c72", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI3_icon_size.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "52375c3f583904686b61698f023f6fdd", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI3_icon_weight.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "72b3429c340349362c50008c3bf70c58", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI3_rotate_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "58614ed9192c5a003133737e45ec1585", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI3_rotate_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6d66543e4b014c561fc16c7c7b792e44", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI3_rotate_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "782607554b0f21084ded5ae06a3d68b6", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Background.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0f5f2fb233a8486f279b12b338235635", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Box_focus.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "304562300aa144977c64737149537ad6", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 12, "bottom": 13, "right": 12, "top": 12 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Box_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1f5749bc6ff127440b4144807aad3926", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 12, "bottom": 13, "right": 12, "top": 12 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Box_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "00ed1560468115f6550541dc7ac54751", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 12, "bottom": 13, "right": 12, "top": 12 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Box_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "71ab5ce818200ebe79e5421f737858b9", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 12, "bottom": 13, "right": 12, "top": 12 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Check_bk.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "28ea75e86ebe4d45722a4aa63c471559", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Check_bk_focus.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "04d6224a54773744177e575760953423", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Check_bk_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4f0c3185756751f601600a741a761dd6", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Check_bk_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5fb07cdf72db68ec2383741603480b53", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Check_unknown.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6b283ee32c6032f821dd699566a924bc", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Ckeck.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "7167574c690f33d1144a07d126c80813", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Close_button_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "72381902329400821187457f66005e84", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Close_button_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "19f1480664de4c0b1d4f58ef04ba19e4", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Close_button_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1a36752146b9557f7cd761ba79d47e94", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Context_menu.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "42f7050e392b57a01bda55e42a101505", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 25, "bottom": 25, "right": 25, "top": 25 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Context_menu_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "422043c2736f09560c6d21e658ee7683", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 14, "bottom": 20, "right": 15, "top": 20 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Context_menu_white.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5fff73d414ad467e03685d0a6614095a", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 14, "bottom": 20, "right": 15, "top": 20 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Down_icn.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2b793b1a747167266984178a32e32d37", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Down_icn_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6935315628ef0c881f764b0a5ba74fe7", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Down_icn_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "310c57c01d81514264a35e92147c0695", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Down_icn_white.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6031706418516c4355323b481f555675", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Editbox_focus.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "7c09624e7daa45ef4dd24628717942d5", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 13, "bottom": 14, "right": 14, "top": 14 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Editbox_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3bb56ec16bfd38e07e6d0ebc282642fa", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 13, "bottom": 14, "right": 14, "top": 14 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Editbox_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "41516f7f0265318f5f6d731f16f66682", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 13, "bottom": 14, "right": 14, "top": 14 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Editbox_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4fc26f8f22f13b4d2b45412a54061211", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 13, "bottom": 14, "right": 14, "top": 14 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Hor_scrollbar_bk.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "560f6bd82c4c4ef635813018768d064b", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 4, "bottom": 0, "right": 4, "top": 0 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Hor_scrollhandle_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "455655bc15fd1b43025130401fee2903", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 4, "bottom": 0, "right": 4, "top": 0 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Hor_scrollhandle_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2476549e78e44b98719b14da5c4134db", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 4, "bottom": 0, "right": 4, "top": 0 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Hor_scrollhandle_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "7112354647cc3b075496797f0e634a33", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 4, "bottom": 0, "right": 4, "top": 0 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Options_button_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "06b2507f1dc27444485922973f1651c6", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Options_button_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "74f605357436654a0cdb0ba9699d3617", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Options_button_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3db124b21b76367c60276e680ddd3a9a", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Radio.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "37fb3fea30e501d008a455d6364c22cc", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Radio_bk.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "30c44f1d3a020549091368ee10242557", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Radio_bk_focus.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0ca3463a618a4f0e52eb0cd473541835", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Radio_bk_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "41fe49c7590a4fef6c2220df1d7b7d87", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Radio_bk_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "737a6f90605173ff5aee59a84e7456ac", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Record_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3ffc4e9b156a328e75c2510a185e3447", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Right_icn.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3ecc3c09309b6acd07400dab40ba53a5", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Right_icn_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4b1576cd389d313448200d037bee454d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Right_icn_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "00a120c04e8d576676041a9f78ed6876", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Right_icn_white.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3d92112b49ba16f46aa3249767164401", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Right_icn_white_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3c5000983faf14af2ff15e4628054e0f", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Right_icn_white_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "637e18d0543970a8502250431f967c02", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_Separator.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "71f906b500ad3db16f2e193f720901dd", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 5, "bottom": 0, "right": 5, "top": 0 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_ToolsPanel_bk.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "027c5bd1366578a42cb4406a763b0c36", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 2, "bottom": 0, "right": 3, "top": 0 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Up_Menu.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "32d449667c0b255a7aa57d1d3b6f0f44", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 15, "bottom": 20, "right": 16, "top": 19 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Up_Menu_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "35ab75a033eb67461637458a31c20f06", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 15, "bottom": 20, "right": 16, "top": 19 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Up_Menu_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "005b202c650949397c95564d0de102f5", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 14, "bottom": 18, "right": 17, "top": 21 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Ver_scrollbar_bk.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0d1a159f71725db57bc8657c7a34211a", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 0, "bottom": 6, "right": 0, "top": 5 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Ver_scrollhandle_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2db22e592f981ca01e47235a71625654", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 0, "bottom": 6, "right": 0, "top": 5 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Ver_scrollhandle_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "733601084caf34553ee648723c4f35be", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 0, "bottom": 6, "right": 0, "top": 5 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Ver_scrollhandle_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "038d77b825c407256b1a319e5c182af9", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 0, "bottom": 6, "right": 0, "top": 5 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Ver_separator.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "10da4daf062652a1109870f7341a00e6", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 0, "bottom": 4, "right": 0, "top": 4 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_Window_place.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "79930dd67ade03ed2f0317fc55680239", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 6, "bottom": 6, "right": 5, "top": 6 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_accept_prefab.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6b470de62923542911ed03432213563c", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_accept_prefab_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "35ad0efb53496d0912370f7d051a1778", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_accept_prefab_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "127e42dc65cf0e39157e1ea817ad6c4b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_actor_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "591f03127b42058b52b7551d506b43d4", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_add_asset_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4d345a677c6e5c0e41196c7568304c76", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_add_btn.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6ea314e470626614681843882a1803d1", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_add_btn_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "49914fd04c69532e2f686e70438246c7", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_add_btn_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "466209b744113e2e2f00468514096178", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_add_key.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "79bc326019263d237f137a627d8c1f45", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_add_key_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "74843ad46bb7716008181dde34275ad0", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_add_key_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "13de255c0a0f177552c23a120e360df8", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_anchor_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "788e1b0b00887b2d07756cbf62855cb3", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_anchor_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "32a52dc06a01174c24c91fd0470b521f", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_anchor_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4ac760b64c831cd8030c07d77097254f", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_anchors_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5130158340bc173258075d59545861e1", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_anchors_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "121e600f2a8b13aa511c2b4a11693ee9", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_anim_file_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4469659002a71b5f254f744108064c02", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_anim_loop.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4b7125941858520c06572f0c31a365b1", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_anim_loop_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0022335023a07b4b394c61236933222a", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_anim_loop_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "32a2400c7dcb7aaf29e3729e0015524c", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_anim_loop_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0f555e523e671f08741010d779e5363a", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_anim_not_loop.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6ee211ea0b413267340a3e665c800d55", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_anim_pause.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "262b5fdd68660a1c564463250003263d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_anim_play.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "56585e75082216ba67755c2d5ecb6ed3", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_anim_properties_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3ccc453a1b03741164900bd765750438", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_anim_type.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0e965d945dc6039230dc70217aa93738" } } ================================================ FILE: Editor/Assets/ui/UI4_animation_bar.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4eb376172ea1460d322b526c7010467b", "sliceBorder": { "left": 4, "bottom": 4, "right": 4, "top": 4 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_animation_component.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "779a6db61bdb3be37c723d6d13055ba2", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_animation_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6c030fca2a162fbc3b713e6b347409bc", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_animation_state_default.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1b3e58037ba3321740c925a95a085c40", "sliceBorder": { "left": 18, "bottom": 20, "right": 19, "top": 17 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_animation_state_frame.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "053d07b13b9965125f8a17a539fb42ee", "sliceBorder": { "left": 18, "bottom": 19, "right": 19, "top": 18 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_animation_state_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1ce60ae16b1c39e970487a8144c63c45", "sliceBorder": { "left": 18, "bottom": 20, "right": 19, "top": 17 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_animation_state_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "223424113ef646e41ddb1a0b171d766e", "sliceBorder": { "left": 18, "bottom": 20, "right": 19, "top": 17 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_animation_state_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3b2e4bbe24616b710e490c194e2748dd", "sliceBorder": { "left": 18, "bottom": 20, "right": 19, "top": 17 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_animation_state_shadow.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "46bd2edc70e13a7857cc0dca5b5f3402", "sliceBorder": { "left": 17, "bottom": 19, "right": 19, "top": 18 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_animation_wnd_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2726133a77804ef50abf7de97d40637b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_asset_icon_selection.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "032d7cf61fd679320acb69bb42de42ce", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_big_file_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "538858b561c55f5768b558d868a1494f", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_big_folder_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1e0d548b73bc26bc2c0e538329f5163b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_big_fragment_shader_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5751123f0006723b5344243d371025d8" } } ================================================ FILE: Editor/Assets/ui/UI4_big_js_file_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0e971cc24ed76b3a01e2479e36e876fd", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_big_lock_close.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "699270fa415802b04fdb6f4c53fc365c", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_big_lock_open.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2cfd7d0d00a7628202907e0d10d33253", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_big_lock_unknown.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2b72590d15f550c512e446de2cd73200", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_big_material_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "48836bfb5de56a911adc361a7e7f58a7" } } ================================================ FILE: Editor/Assets/ui/UI4_big_text_file_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4458068263d003483fca161a66a50c84", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_big_vertex_shader_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "703d1aea0d761a32089d53700cc36075" } } ================================================ FILE: Editor/Assets/ui/UI4_bones_tool.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3da4158824d77f8a722366e166d166ac", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_bool_type.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "435138351b066b1e08794d583f1a5840", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_break_prefab.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0a77395b4cd81aed6a55012160e32ffe", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_break_prefab_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "307655027af95f14370c2ffc61632f01", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_break_prefab_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "650c7b66370f2b0460fe0509059666e4", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_brush_tool.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "15df295163e609cf295f4be120572807", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_button_focus.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6cd41ccc028c51c461a5755c16c4120b", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 14, "bottom": 15, "right": 15, "top": 14 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_button_pressed-87.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "200f651f024d34763b852794303a23d2", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 14, "bottom": 15, "right": 15, "top": 14 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_button_pressed-90.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "41f672d310b84eb418f54de266564b7c", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 0, "bottom": 7, "right": 0, "top": 6 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_button_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "112e27b2699838915c2728de34f6766a", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 14, "bottom": 15, "right": 15, "top": 14 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_button_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "489b66c526fb155d37935e626a35213e", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 14, "bottom": 15, "right": 15, "top": 14 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_button_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6f632454112e23a87ded0987767167d8", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 14, "bottom": 15, "right": 15, "top": 14 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_camera_icn.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6a7e3675537b2d771c25300f48634962", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_ch_arrows.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5219235a0fc2622920a3158b12741171", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_color_type.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "60ed725a3d34272d059324b94e692036", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_common_anim_track.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "683a62fd1b9a26a86d3a1c046dd871aa", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 7, "bottom": 9, "right": 8, "top": 12 } } } ================================================ FILE: Editor/Assets/ui/UI4_component_head.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "06834b90737824c019bf06f575bc5511", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 4, "bottom": 5, "right": 5, "top": 4 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_component_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3e6d21de649d6d8671587a2505f42bcc", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_component_icon_dark.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0edd5cf06d14584b2a7a6f6c109b667d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_create_asset_instance.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2c77314d33f1336a1840362b2c9d1b2a", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_create_asset_instance_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "43ad697756894fa942a9115f69e858d5", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_create_asset_instance_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1e086ada4002060e2a9a18020d915e7b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_curve_color.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2afb49b10d0a64ca2423073421b03e7c", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_curves_mode.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "602a754042293ca8784648ab0974477d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_dopesheet_back.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6b9e3a777ef30b0346e62cb63ca10d5a", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 9, "bottom": 10, "right": 10, "top": 11 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_drag_handle.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3baa405d339f58ab636530c92f1310b4", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_edit_anim_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1aad7e376c1866741eec7af66d88718e", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_edit_anim_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "41df300a33bc6fe365c7553102276156", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_edit_anim_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2a7b1669373d57e42f9035225a4a4c22", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_emitter_component.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5ffb001041e4477b5e952bda0c994001", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_enable_dot_big.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "24cb3cd12ba628cd1c366e721f9767e5", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_enable_dot_big_unknown.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "18867189163f78f1110406954fc902d2", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_enable_toggle_big.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1b4e1f836afb6b7a38b32c5d7e8c31aa", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_enable_toggle_big_focused.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "698b294551681f373f3a5d233f7c048d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_enable_toggle_big_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6be0629a7f532e3b50cd6b8028780add", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_enable_toggle_big_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0733208b08c93dd669e00f4c219c633a", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_eye_closed_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6ca8496030160e99272a75a135454b85", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_eye_opened_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "69a564a235c80c55159e50d8601030df", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_filter_icon .png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "37cf2b1b28ac5e1b0272688960da3faa", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_filter_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4d0a16d335cf763c4b1b298e08c07386", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_float_type.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2b7c7314787e224a2d4e36000b1f2754", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_folder_icn.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5cc7078218605bcf392a532264644d1a", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_folder_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "318a6c664a451b14170075374d942536", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_folder_icon_dark.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "69d8209312f214ac766623ce37fc368c", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_frame_tool.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5b4c2ea318924e6409f4639b047433f8", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_game_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "590b46df4f7122cb30614bba0f591559", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_gear_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "52793ad12a1d17b438a07882274801d3", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_graph_component.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "306f0da0079e493b6c1b4ccf656c31cc" } } ================================================ FILE: Editor/Assets/ui/UI4_graph_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5e7112ec1c332d0a260a32887b1d4233" } } ================================================ FILE: Editor/Assets/ui/UI4_gray_options.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "233c0d4269646e2f31e71b8d5d1e5fc4", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_gray_options_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6338023a6c50328d3bab0bb453f864cf", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_gray_options_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "36942f0200314c5e55a2550f113325d4", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_green_edit_box.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1db20a2430920e752fbe48f84c6c26f4", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 8, "bottom": 9, "right": 8, "top": 8 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_handles_mode.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "453a7b68174246e27a370e083f806b91", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_icon_anchor.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "650f05bd13c30fe20cb51f072b7158ac", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_icon_max_size.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4694254d5c164bb85bae7b8c0ac82f28", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_icon_min_size.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3803547f5e515b5c33764a6736060bc7", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_icon_offsets.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0804451b664226dd06421c3039062bea", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_icon_size.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "017a2a2a1df6218e168766c171e65c33", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_icon_weight.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3b8b47f65dba59ff46fa153361030882", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_image_asset_back.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "699b04077c1b0a016a8f17de78fb4bf8", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_image_component.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2b5175271de526a5147d745d6ea900f7", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_image_frame_tool.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3ed409235a342972306c7b0933647511", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_image_icn.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2c6a44ed41965abc1a6d17074f375ffd", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_key.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5c8f735e0626703c68375587092b511f", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_key_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "678f3b994792282b57067997708137b0", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_key_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "45a96f8d00a84100285c6c934c9a35d6", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_keys_select border.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6230017d7be059ae0da43af543232301", "sliceBorder": { "left": 1, "bottom": 7, "right": 3, "top": 7 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_keys_select border_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "12f84b277f524d8552593f4226f6678e", "sliceBorder": { "left": 1, "bottom": 7, "right": 3, "top": 7 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_keys_select border_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0f97699553dd0f690bbf2e7556123dda", "sliceBorder": { "left": 1, "bottom": 8, "right": 3, "top": 7 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_keys_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "657d27f6662b025769741b7571df4551", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 6, "bottom": 6, "right": 7, "top": 7 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_keys_select_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0a7e1d772d8163c74c276b82046055af", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 6, "bottom": 6, "right": 7, "top": 7 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_keys_select_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3c374faa59f4169e448640451e8c7999", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 6, "bottom": 6, "right": 7, "top": 7 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_layer_big.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2bea1b0e0dc334ef4d7d73907776492b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_layer_icon_t.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5bf81ee545af13071b9d7e2877f00610", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_link_icon-143.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "53b81d1c1d7b359b7833213467275026", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_link_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "00533d362a0c38c31f4d66921cac0be6", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_list_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1f21370c782109b823d11e4a317c06ac", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_lock_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6bd46d174c5778235f036c466a14569c", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_log_errors_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "124c7226031f44cd20fe5a9b6c5d1ac2", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_log_errors_inactive_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6daf1e8158c73247507728605cb232fe", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_log_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "75626bb107dc2e62446319ef51b22e72", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_log_info_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0d090480192b622f13f708e024385b7e", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_log_info_inactive_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "548a54f733c041ff66a7740d3f6357c3", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_log_warnings_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "780a1a5d6ce91d64442a0f8f708e2023", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_log_warnings_inactive_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "7fed733e18332f2d647354bf375820be", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_log_wnd_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "20d96f61176b2d6d7fb91235159d44f5", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_map_key.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0bb21fcf2a9d59731e6f7bcb5f790769", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_map_key_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3d9f26d140170fd2694b3a9a0b4b01fc", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_map_key_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "500247f24466585a79427cfa01af7dce", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_menu_new_asset.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "205825070fac326515311f4245b6347f" } } ================================================ FILE: Editor/Assets/ui/UI4_menu_open_asset.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "74696cd5175133463b9f64f874333205" } } ================================================ FILE: Editor/Assets/ui/UI4_menu_revert_asset.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4804420054634e9a08a90c1b32336b0b" } } ================================================ FILE: Editor/Assets/ui/UI4_menu_save_as_asset.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "518b628b6be73f9058764d5e69ca3fea" } } ================================================ FILE: Editor/Assets/ui/UI4_menu_save_asset.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "7a725f47375b380d3f9320c0241c5f45" } } ================================================ FILE: Editor/Assets/ui/UI4_menu_toggled.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "488377f87257761c278906856d810341", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 8, "bottom": 8, "right": 8, "top": 9 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_menu_toggled_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "69056cee22f677695d9540140be069f5", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 8, "bottom": 8, "right": 8, "top": 9 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_menu_toggled_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "7fae2e1d1d9245d2651a47c07c2868cb", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 8, "bottom": 8, "right": 8, "top": 9 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_minus_small_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "36e2240d67b63628380f00e10ff525e4", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_minus_small_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "65472887152f187c50a824111b2646a2", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_minus_small_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5dc21695180c481f79594f2943d77fa5", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_move_left.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3f775a7f10983ba21cd81541526524cf", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_move_right.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "45cc01cf1d6114d7161a0eb3016c3940", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_move_tool.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "18664b4d2b3430cd005469184dcb7f59", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_non_loop_anim_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1b293703451e37d706fb7748469e08bb", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_non_loop_anim_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3e3b1639646b2d8435c4415d5d424648", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_non_loop_anim_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4e001b7940a900a748a414b035541820", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_o2_sign.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "431f6a8b1fa51b507bcf13da74b15da5", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_off_dot.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "127a2878256c72d05bbc46b313760577", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_on_dot.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "7d390b8a244a17b8151e2a552bff1d77", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_on_off_dot.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "60bf6b496ccd45d944ec41184aeb62c6", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_other_type.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4f482b827d0e70ac4031022c21737971", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_panel_button.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "445f076b10cc17e92b30538f1c3c0bfc", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 7, "bottom": 9, "right": 8, "top": 7 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_panel_button_focus.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "33dc27782cbd3b856f98546a48551add", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 7, "bottom": 9, "right": 8, "top": 7 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_panel_button_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "00e30bf2552d06127c1d6bd6121b6df3", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 7, "bottom": 9, "right": 8, "top": 7 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_panel_button_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2adb56610cab4d602fb6062b582b7c61", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 7, "bottom": 9, "right": 8, "top": 7 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_panel_subpanel_bk.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1d66598e2402227f299625033b627c88", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 17, "bottom": 15, "right": 18, "top": 13 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_panel_subpanel_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "006c29830a4061c219336f376edd7408", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 17, "bottom": 15, "right": 18, "top": 13 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_panel_subpanel_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "08102b891cb142b90e4240df07f947c2", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 17, "bottom": 15, "right": 18, "top": 13 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_path_tool.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5f42584132dd50f7040b468c35b633da", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_pause_btn_inactive.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "44b8262876e4683548b83b554e544bd7", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_pause_btn_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "7308512942a4704708ca55320bc953a9", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_pause_btn_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4be6659607ff04405eed6a4f5c7641d8", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_pause_btn_select .png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "54772db77d4168b17bd54bc47eb81845", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_pause_btn_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2e1f151556f90d6c00794feb232c0812", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_pause_green.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "345f713368971d42030d5d0979ec32e4" } } ================================================ FILE: Editor/Assets/ui/UI4_pause_green_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "63be07d703c22bc170e862102cd77109" } } ================================================ FILE: Editor/Assets/ui/UI4_pause_green_selected.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "22921cc073ac241b3c1920e94b385dc5" } } ================================================ FILE: Editor/Assets/ui/UI4_pencil_icon_green.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "078a5c5269ee695a722144d642937467", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_pivot.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6684387a17f21d804e0c625c3caf019f", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_pivot_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "478b75ef613a0f3f560513f2505f448d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_pivot_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "27587cbc421e343b6a172ac445976fbe", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_pivot_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "38515d6a082a49430c38322b35f51152", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_play_anim_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "591a19c30f2c066a3e9d0ac23d5636aa", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_play_anim_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "649a34d011312f0053bb7a6049d87c68", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_play_anim_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "01f342d9768621963e463c1f6bd61e6c", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_play_btn_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "748d796725b867fd6135105725ee07d7", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_play_btn_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6c0b3f44539347465fbc4ca23cfd630b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_play_btn_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "54533c7853254fc26d4f6bd9082129a8", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_play_green.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6360353c0a00406e5aef0586639650b4" } } ================================================ FILE: Editor/Assets/ui/UI4_play_green_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "268325ac1cfa0726407e50b84494501f" } } ================================================ FILE: Editor/Assets/ui/UI4_play_green_selected.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "09bb28a82b5836836c7a59c14e954c65" } } ================================================ FILE: Editor/Assets/ui/UI4_play_panel_bk.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "25896a4c65bb6d021da41e1540b5348f", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 18, "bottom": 14, "right": 18, "top": 14 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_plus_small_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3413234a0ae275d734b158ae52574be2", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_plus_small_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0096333b50663c5276a9663e2ae53701", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_plus_small_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "07f6672722551dc57802769e0a7a4c8d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_position_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "13591d571afc12bf6d712ee753750268", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_prefab_link_big.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0824555552e83f137bea39715a717db2", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_preview_anim.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4af3567144e93bfb574d7eff08276b1f", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_red_edit_box.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "12a80f3344a31e2d3354161c2f944638", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 8, "bottom": 8, "right": 9, "top": 8 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_remove_asset_instance.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "72e37ae1388974ad7a993d373ab56ba1", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_remove_asset_instance_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "54540c6d09e92f2072c56ff6229c42e2", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_remove_asset_instance_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "66de7fe06fcf11d5534f7d306268399c", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_revert.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "44402071050555a124c77e7344733da4", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_revert_prefab.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "66a662840f893c5e33eb68ff57751cb1", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_revert_prefab_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6c1222e14ca4398d5c8d7cbc115f2840", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_revert_prefab_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3bc720c118ed0f71156b56ff220517ad", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_rewind_left.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "16aa3d2c44704f5d76fb7ba26d833596", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_rewind_right.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "09df6a6c4d7b25e139f063be7a356bde", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_rotate_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "160104da0967563125ad686703e8527a", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_rotate_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "030001020f840bd92b4509cd2d577559", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_rotate_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "75de6acf151e03724be01ccc668037bf", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_rotate_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2640510a17026a0e32b31efd3c402c0d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_rotate_tool.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "080c03bc303d37fc1b33333b4db333e4", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_round_field.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1b6724306a1b40cf2115319d1c381026", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 14, "bottom": 12, "right": 15, "top": 12 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_round_field_focused.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3cb634ec0c2a4357104d377d5b6b70f3", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 14, "bottom": 12, "right": 15, "top": 12 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_round_field_gray.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "749d29bb6c3779a535123773412905ad", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 14, "bottom": 12, "right": 15, "top": 12 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_round_field_gray_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "480277a63e4f29092bd8095a558f0cf3", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 14, "bottom": 12, "right": 15, "top": 12 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_round_field_gray_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "080924f564be321631537a4942fa64a9", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 14, "bottom": 12, "right": 15, "top": 12 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_round_field_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "221859314013209c72795c99260719ed", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 14, "bottom": 12, "right": 15, "top": 12 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_round_field_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6fd46d247f183bac5c7f17e55d937922", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 14, "bottom": 12, "right": 15, "top": 12 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_save_asset_instance.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "07217ad66edd15986cda39045abb1de8", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_save_asset_instance_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0a256d914aae1bef013f020f70dc0320", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_save_asset_instance_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "774511dd0c17278327a37a61259312ec", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_save_gray copy.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "792525843ae60c666e3b7e9100bd36ac", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_save_gray.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "36ab678e3d2829e7337c50795c776702", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_save_gray_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "22fc284427297a99761a2732351e3bcd", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_scale_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4d7c59300b78244b250b3f14794f7c30", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_scale_tool.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "31d11d1b4ae008106f8569b959e72e8c", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_scene_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "07df580d646f523814fb1dfa1a032880", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_search_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "13cc3f4f45710a54352307ef5f001eef", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_search_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "75fd696b197523351ff218f2007b35fa", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_search_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "7b175e291a460aec259d179c58511101", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_select_tool.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "047125ac645757370538749441e716aa", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_selected_key.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6bfe26935ff23aca66982fc5129f62a5", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_selected_key_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5dd75cf130c54760239a02887dc27cc7", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_selected_key_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "02093ccd514e707f0d97363b5a586089", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_selected_map_key.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "763732ef5458313915c3067a2b3c4e4b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_selected_map_key_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "14466d616af14fdd3d94541c058c55ae", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_selected_map_key_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "425d6b6b34666dfe66c0353b60a56594", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_selection_frame.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "42de0d960e43186b233a053066245c1d", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 4, "bottom": 5, "right": 7, "top": 5 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_shadow_separator.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "429c14fb5b927a6c63d37e4a16e82996", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 4, "bottom": 0, "right": 3, "top": 0 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_shear_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6454514469135ee7070c5d4f02887a76" } } ================================================ FILE: Editor/Assets/ui/UI4_small_panel_back.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "49be56066b956738561b3410432148f6", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 7, "bottom": 8, "right": 7, "top": 8 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_small_panel_down_back.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "470500a075811926793a60284b925a5f", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 7, "bottom": 8, "right": 7, "top": 8 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_small_trash_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "36560cd15c64708710a74d6c17562771", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_square_button.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1fd643e3718b28ec40157bf56fcb590d", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 7, "bottom": 7, "right": 8, "top": 8 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_square_button_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "67e9505e448369275b7a311b508f0755", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 7, "bottom": 7, "right": 8, "top": 8 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_square_button_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1f344e0b73185347370b0778377d49a9", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 7, "bottom": 7, "right": 8, "top": 8 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_square_field.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "529e59f47958149e773d7ee574b446aa", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 6, "bottom": 8, "right": 8, "top": 7 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_step_btn_pressed .png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5b492262019075be60c50c7a7a8f4439", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_step_btn_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2e9d76dd344d6a7628982a922dac3778", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_step_btn_regular .png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2e3d582e085c21d943eb68c334e954c8", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_step_btn_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "780f085f12c9163638327be949611fc8", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_step_btn_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "36381ab856e21d206b244e1b06737b5b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_stop_anim_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6f1c03c31634776772b40eb339ba39a1", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_stop_anim_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "55612948208b611c6518424a33152bfc", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_stop_anim_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "17eb725123f5219028c552b8149f330c", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_stop_btn_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "31e057267cbf1b5444701f1722b74eb2", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_stop_btn_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3aa5715005765c392f0e0bc013f82e10", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_stop_btn_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "35de0b9966e72d501fd4124c61413f86", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_sub_track.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6cf040522c78223433793d2e3e1a7283", "sliceBorder": { "left": 6, "bottom": 6, "right": 6, "top": 7 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_tag_big.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6371320a681e22eb5e37519315ad40b5", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_time_line.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0f8341ea3e692c9911eb1daf1e9b4e7e", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 0, "bottom": 3, "right": 0, "top": 21 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_time_line_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "627879c55d55252c12e70ff81ba77503", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 0, "bottom": 3, "right": 0, "top": 21 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_time_line_left.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "30f6096246af62b6395e17092ead3fa5", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 7, "bottom": 0, "right": 8, "top": 0 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_time_line_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4be121ca5a8346872dc606b94bcc4903", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 0, "bottom": 3, "right": 0, "top": 21 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_time_line_right.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "50600547271f4d2f38d4282109604b00", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 7, "bottom": 0, "right": 9, "top": 0 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_time_line_right_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "77d5176139101e81137d499c70052ebc", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 6, "bottom": 0, "right": 8, "top": 0 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_time_line_right_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "67e86ce16b231d8d36f64ec14a9a1c99", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 6, "bottom": 0, "right": 8, "top": 0 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_trach_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "35b70b7a022239575e6c5caf32445477", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_transform_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4bfd046473e85477661226ea70543b7a", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_transform_icon_white.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3bf440583f843a155ddd77b4244706a2", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_tree_icon-223.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "78813a607702658230400ce6143a0a8f", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_tree_icon-61.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "40c87ec45ab06d5067f2199828893b23", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_tree_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "702f3b0e291b134e7fe656243bd33b7d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_tree_wnd_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4e5b4e066f10548e335210236af46e01", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_unlock_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5f3057b6579c79624dab3a6e6509044d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_vector_type.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "27c90e13537260835a33574067e879b0", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_weight_tool.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "444571c9370c6315115f10624ab0015d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI4_window_frame_docked.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "29821f7977603f9b4d555dd659f271a7", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 17, "bottom": 17, "right": 17, "top": 33 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_window_frame_docked_tab.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "082c7adc114072223f8624d3657d369c", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 17, "bottom": 17, "right": 17, "top": 33 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_window_frame_docked_tab_active_back copy.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "63bb6ee349d31989559f57c840d81866", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 17, "bottom": 15, "right": 18, "top": 13 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_window_frame_docked_tab_back.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3f541bd74565005f1e577dcd78607ee7", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 17, "bottom": 15, "right": 18, "top": 13 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_window_frame_docked_tab_inactive.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3a5d434026851c7718a1233d0ab2013f", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 17, "bottom": 15, "right": 18, "top": 13 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI4_window_frame_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "607b57e75dfe1ee103b369af38ab75d0", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 17, "bottom": 17, "right": 17, "top": 33 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI_Background.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "59c96a567a71232e4a442a3f16462b5d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Box_focus.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "318353ef18463f74356c61cf62e2655d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Box_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5d65226a1e2816d050af554625192398", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Box_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "36552ed1342572934c84007c190968b2", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Box_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6178636c3089374f799f548b1d0d5689", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Check_bk.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "7d843e5e0cde648337a05bb6623a2a00", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Check_bk_focus.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "693019e64db207b44941030950950f55", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Check_bk_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3c40393d03af1c4760f92eee1a6666f3", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Check_bk_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "029a646b21e3528d523f7a3f36cb4a7a", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Check_unknown.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "546234b9099b361750c635157f2232cb", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Ckeck.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "25fe24b15a643db6408474c87f060807", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Close_button_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1813201c420a5b7b05ae23f244553190", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Close_button_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "478514024c9c0cb854b9126c2f2d2607", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Close_button_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1d7a7eac346469fc025a054e41e97b4b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Context_menu.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1f567fa431f2371a538646f27128767f", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 25, "bottom": 25, "right": 25, "top": 25 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI_Context_menu_select copy.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3ec067b34c1273214d7136f173c51c04", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Context_menu_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "299b48e027d0686405925a2412df3f79", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Context_menu_white.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1a0c0677587a3c73719c6aa379d113c1", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Down_icn.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "267964fe2f9d001f378667c8063a3afc", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Editbox_focus.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "11871a410d053f797d83262c17f5568c", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Editbox_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1a1a5d462ec011d23a095fa761211711", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Editbox_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4b587658011b29bb03cd435336194c6c", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Editbox_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4ca64f006ea3650561c405895d7c75bf", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Hor_scrollbar_bk.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "631d77e84a46720c07800e75562e0706", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Hor_scrollhandle_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0064294220b1273b6b9152523b963cdc", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Hor_scrollhandle_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2b594da76cd63ef042d21d0f7a5541b0", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Hor_scrollhandle_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "112077614d0305be65f907c538ca1f62", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_ListBox_selection_hover.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1efa5a3609e93b26740d4bbf59860925", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_ListBox_selection_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6e971e235a7c5b2101a4317503c85537", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_ListBox_selection_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "681b1d0846ca2cf9407570075db31a2d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Options_button_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "665a4ddc0a1b0a0e525770675ada557c", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Options_button_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "31d16bc164d5193d66cf30674a824bad", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Options_button_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0c6a5d8a4a661a94747c6bf051ae52cc", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Radio.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5f5841267c8d387d7de441cf5c97258b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Radio_bk.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "089c41fc1ab81a672292049d196e2136", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Radio_bk_focus.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "645c0d9811e46c6a0ff0007649142762", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Radio_bk_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6c7d7204331f14d86774363220a767b0", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Radio_bk_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "27250e883db655432ad15beb37827100", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Right_icn.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "76b963ad2f355a7a0bfd6cfa57434173", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Right_icn_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "69de633d136b4c903d2d39f74bc7566a", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Right_icn_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0b78004054635ed540d678bc332c3c87", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Separator.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3821097566522d056655626b4d6f6167", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_ToolsPanel_bk.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "351040c57b69389a361e3ea6791f1f9d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Up_Menu.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "704d3eca14ef09fe7f6403fc28b30af0", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Up_Menu_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "44f367b43ad37edf74d46dbf21954378", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Up_Menu_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "54c045d717b271dc10bd5e9f69611522", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Ver_scrollbar_bk.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0a1801bb711a77c60d1679f411b36610", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Ver_scrollhandle_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "7ba135291ad820ae241238582e671ba2", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Ver_scrollhandle_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3c407b2b46f807e6602877a4259c2a79", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Ver_scrollhandle_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2b19000955c963fd6c0b0af07fae2676", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Ver_separator.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4392114d25d616c562b14a96373a52bb", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_Window_place.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "05fb7cb46f9b68b21b710da4496979be", "atlasId": "6bd459187f2675966f8c67e46e525c59", "sliceBorder": { "left": 3, "bottom": 4, "right": 4, "top": 4 }, "defaultMode": "Sliced" } } ================================================ FILE: Editor/Assets/ui/UI_brush_tool.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "20324bc467e374d318f447cc01c33e40", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_brush_tool_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "202924a37cfe76312bba65d85a083037", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_brush_tool_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4b426c1230e851bb43645f874af90c0f", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_button_focus.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "17a1715932ee790051a81af35bf310aa", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_button_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "57ac6501709c48d3787b437546946c28", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_button_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0a0768d465c119435a1259a546b74bea", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_button_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "29991fdb6c684da368e2435d6a7a6c92", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_frame_tool.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "31a9020630255cc11b236fe16025516a", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_frame_tool_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4a446b731cad7540075e713659336d0e", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_frame_tool_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "729f389179896e145e2c2d9f4601358c", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_link_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "7b1f59f85dc573751dfb30cd0f910f13", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_list_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "65eb2f6f0461757f5a745acf68e36e25", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_lock_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6eab1f21570e74c279d81a6629376682", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_move_tool.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0540372660dd761419143ca574cb27e4", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_move_tool_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "78d153c7721c600652de44a443fc762d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_move_tool_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "34c1728e5959446a322b3abd0166447c", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_o2_sign.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "10b54243335e704f02303c8959e84535", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_off_dot.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "209332ef3b3b7c081e620ce00c9e79f6", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_on_dot.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "048005dd1a3b5b24427623dc3ae543a2", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_on_off_dot.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "38e15d9337ec6c765a613ed6385a7259", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_panel_button.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "038b6ac03b5d39e44855155b2cfd17fb", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_panel_button_focus.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "10d90c2d06855e3e6f8d34405b4b079a", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_panel_button_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6a387bd918eb39f3079a75796db55d4a", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_panel_button_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "51ce450e4dde5a940e313b1f579833ec", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_panel_subpanel_bk.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "660054543ee938f231472c8a3e9115a2", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_panel_subpanel_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "7172077513da491f1f1046554a7d0bcc", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_panel_subpanel_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "3b0a3d7952be0a6a56036a5675792f0b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_pause_btn_inactive.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "55ed66a92fe1176674d36fa95be23741", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_pause_btn_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "717f148f5dd235e30a7732a50c550b8e", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_pause_btn_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "296609f45d5c66f1662224e457af5253", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_pause_btn_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "55864ae04d8d76e3674a5d3f210d0132", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_play_btn_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5a052c9c3bb10d494da427ce2dcc6d0b", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_play_btn_select copy.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "774865b273573cf4092515ec758a5a00", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_play_btn_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "19f41dea4e4a13f50a020e2f72220b70", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_play_panel_bk.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2aed7e4e04982b9d10b05c736fb253fe", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_rotate_tool.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "32ad3f000a6b5fda39ad54624dcd1faa", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_rotate_tool_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "52e145054c0f496f3aa67d424e485af4", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_rotate_tool_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4bba69197e1d50a716f838f4297a08c6", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_scale_tool.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "391d434423a375d232167252668112c2", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_scale_tool_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "432e3cd02deb14824fb749746eb841c9", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_scale_tool_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6e5320454c85738663ce23b55dbd4dfa", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_search_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6b31296c3d3c54f062913bac516e6eb8", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_search_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "66ac154f1c1f06111075313339e66aa4", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_search_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "59ea323733796f7b522f19622984279d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_select_tool.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5a506fac4bd724fd7cb30e9324e33ac6", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_select_tool_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "69826e777c0875aa2538405f72e1787f", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_select_tool_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "456610a279177bd27132039f6c9c046a", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_square_button.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "68176d7a25466a163a972c1d02f90197", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_square_button_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "27ed427925bf0f15242e054d7d15565c", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_square_button_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "468a0f7c35cb0353298d77d67de26056", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_square_field.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "5f116ccb51b84961716a02cf69bb3f66", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_step_btn_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "28e813ef74100f1012ba2a92173f42ae", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_step_btn_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "47b36fb265a33d7264b108b71f49788d", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_step_btn_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "1b582c1d0d7c08d64ec65c182cf83ea7", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_stop_btn_pressed.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "0ffc467840e900ce18ad18ce4da851da", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_stop_btn_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6e031d4c1377202c3a5a783240f55e49", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_stop_btn_select.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "2a13006326f35cff2c0408dc48be0f54", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_tree_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4c2040bc3f284f8d415e02a908746904", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_unlock_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "48a803d01eba69a826b9433d1f5c74aa", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_window_frame_docked.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "6d502dbf63ec3d501f4f242f091d31a8", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_window_frame_docked_tab.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4c3715695b1a3fed0d5a2a93447314df", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_window_frame_docked_tab_active_back copy.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "106d599344ab622f788725dc1a9b2d40", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_window_frame_docked_tab_back.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "46566cc7182e52e65ccb23636f311aec", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_window_frame_docked_tab_inactive.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "269832cd5b6d3c22365a05c128127d44", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/UI_window_frame_regular.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "661810ae7278533651ab14ce7d5b02ea", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/circle_hole_handle.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "765f0d4e10b21aec273c3d092d27126e", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/function_icon.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "153a346b58f76ba94e416db20f587244", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/hor_hole_handle.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "311766284f1a03f22a5646697a2b6471", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/hor_slice_line.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "4e9c0a6367712dc71d7864e112ee1073", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/ver_hole_handle.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "23a50e686362786770a2329c58d95ee2", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui/ver_slice_line.png.meta ================================================ { "Type": "o2::ImageAsset::Meta", "Value": { "mId": "48bb0e912c9b39666e735b4e3a886eb5", "atlasId": "6bd459187f2675966f8c67e46e525c59" } } ================================================ FILE: Editor/Assets/ui.meta ================================================ { "Type": "o2::DefaultAssetMeta", "Value": { "mId": "65dc37735fa861b35a0c3d4c10246e36" } } ================================================ FILE: Editor/Platforms/Mac/Editor.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 50; objects = { /* Begin PBXBuildFile section */ A667A4552962318600B565EE /* stdafx.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3392962318600B565EE /* stdafx.h */; }; A667A4562962318600B565EE /* EditorApplication.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A33B2962318600B565EE /* EditorApplication.cpp */; }; A667A4572962318600B565EE /* CurvePreview.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A33D2962318600B565EE /* CurvePreview.h */; }; A667A4582962318600B565EE /* ImageSlicesEditorWidget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A33E2962318600B565EE /* ImageSlicesEditorWidget.cpp */; }; A667A4592962318600B565EE /* ScrollView.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A33F2962318600B565EE /* ScrollView.h */; }; A667A45A2962318600B565EE /* FrameScrollView.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3402962318600B565EE /* FrameScrollView.cpp */; }; A667A45B2962318600B565EE /* ImageSlicesEditorWidget.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3412962318600B565EE /* ImageSlicesEditorWidget.h */; }; A667A45C2962318600B565EE /* FrameScrollView.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3422962318600B565EE /* FrameScrollView.h */; }; A667A45D2962318600B565EE /* CurvesEditor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3442962318600B565EE /* CurvesEditor.cpp */; }; A667A45E2962318600B565EE /* CurvesEditor.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3452962318600B565EE /* CurvesEditor.h */; }; A667A45F2962318600B565EE /* CurveActions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3462962318600B565EE /* CurveActions.cpp */; }; A667A4602962318600B565EE /* CurveActions.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3472962318600B565EE /* CurveActions.h */; }; A667A4612962318600B565EE /* SplineEditor.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3492962318600B565EE /* SplineEditor.h */; }; A667A4622962318600B565EE /* SplineEditor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A34A2962318600B565EE /* SplineEditor.cpp */; }; A667A4632962318600B565EE /* SpoilerWithHead.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A34B2962318600B565EE /* SpoilerWithHead.cpp */; }; A667A4642962318600B565EE /* SpoilerWithHead.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A34C2962318600B565EE /* SpoilerWithHead.h */; }; A667A4652962318600B565EE /* CurvePreview.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A34D2962318600B565EE /* CurvePreview.cpp */; }; A667A4662962318600B565EE /* ScrollView.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A34E2962318600B565EE /* ScrollView.cpp */; }; A667A4672962318600B565EE /* UIRoot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A34F2962318600B565EE /* UIRoot.cpp */; }; A667A4682962318600B565EE /* DockableWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3512962318600B565EE /* DockableWindow.cpp */; }; A667A4692962318600B565EE /* WindowsLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3522962318600B565EE /* WindowsLayout.cpp */; }; A667A46A2962318600B565EE /* WindowsManager.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3532962318600B565EE /* WindowsManager.h */; }; A667A46B2962318600B565EE /* WindowsManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3542962318600B565EE /* WindowsManager.cpp */; }; A667A46C2962318600B565EE /* IEditorWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3552962318600B565EE /* IEditorWindow.h */; }; A667A46D2962318600B565EE /* DockWindowPlace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3562962318600B565EE /* DockWindowPlace.cpp */; }; A667A46E2962318600B565EE /* WindowsLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3572962318600B565EE /* WindowsLayout.h */; }; A667A46F2962318600B565EE /* DockableWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3582962318600B565EE /* DockableWindow.h */; }; A667A4702962318600B565EE /* IEditorWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3592962318600B565EE /* IEditorWindow.cpp */; }; A667A4712962318600B565EE /* DockWindowPlace.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A35A2962318600B565EE /* DockWindowPlace.h */; }; A667A4722962318600B565EE /* EditorUIStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A35C2962318600B565EE /* EditorUIStyle.h */; }; A667A4732962318600B565EE /* BasicUIStyle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A35D2962318600B565EE /* BasicUIStyle.cpp */; }; A667A4742962318600B565EE /* EditorUIStyle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A35E2962318600B565EE /* EditorUIStyle.cpp */; }; A667A4752962318600B565EE /* BasicUIStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A35F2962318600B565EE /* BasicUIStyle.h */; }; A667A4762962318600B565EE /* EditorConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3602962318600B565EE /* EditorConfig.cpp */; }; A667A4772962318600B565EE /* ScaleTool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3622962318600B565EE /* ScaleTool.cpp */; }; A667A4782962318600B565EE /* SelectionTool.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3632962318600B565EE /* SelectionTool.h */; }; A667A4792962318700B565EE /* MoveTool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3642962318600B565EE /* MoveTool.cpp */; }; A667A47A2962318700B565EE /* CustomFrameTool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3652962318600B565EE /* CustomFrameTool.cpp */; }; A667A47B2962318700B565EE /* RotateTool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3662962318600B565EE /* RotateTool.cpp */; }; A667A47C2962318700B565EE /* ScaleTool.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3672962318600B565EE /* ScaleTool.h */; }; A667A47D2962318700B565EE /* FrameTool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3682962318600B565EE /* FrameTool.cpp */; }; A667A47E2962318700B565EE /* FrameTool.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3692962318600B565EE /* FrameTool.h */; }; A667A47F2962318700B565EE /* RotateTool.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A36A2962318600B565EE /* RotateTool.h */; }; A667A4802962318700B565EE /* CustomFrameTool.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A36B2962318600B565EE /* CustomFrameTool.h */; }; A667A4812962318700B565EE /* MoveTool.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A36C2962318600B565EE /* MoveTool.h */; }; A667A4822962318700B565EE /* SplineTool.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A36D2962318600B565EE /* SplineTool.h */; }; A667A4832962318700B565EE /* IEditorTool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A36E2962318600B565EE /* IEditorTool.cpp */; }; A667A4842962318700B565EE /* SplineTool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A36F2962318600B565EE /* SplineTool.cpp */; }; A667A4852962318700B565EE /* IEditorTool.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3702962318600B565EE /* IEditorTool.h */; }; A667A4862962318700B565EE /* SelectionTool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3712962318600B565EE /* SelectionTool.cpp */; }; A667A4872962318700B565EE /* MenuPanel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3722962318600B565EE /* MenuPanel.cpp */; }; A667A4882962318700B565EE /* EditorApplication.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3732962318600B565EE /* EditorApplication.h */; }; A667A4892962318700B565EE /* UIRoot.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3742962318600B565EE /* UIRoot.h */; }; A667A48A2962318700B565EE /* IPropertyField.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3762962318600B565EE /* IPropertyField.cpp */; }; A667A48B2962318700B565EE /* ComponentProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3782962318600B565EE /* ComponentProperty.cpp */; }; A667A48C2962318700B565EE /* ActorProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3792962318600B565EE /* ActorProperty.cpp */; }; A667A48D2962318700B565EE /* Vector2IntProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A37A2962318600B565EE /* Vector2IntProperty.cpp */; }; A667A48E2962318700B565EE /* CurveProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A37B2962318600B565EE /* CurveProperty.cpp */; }; A667A48F2962318700B565EE /* VectorProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A37C2962318600B565EE /* VectorProperty.h */; }; A667A4902962318700B565EE /* ScriptValueProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A37D2962318600B565EE /* ScriptValueProperty.cpp */; }; A667A4912962318700B565EE /* WStringProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A37E2962318600B565EE /* WStringProperty.h */; }; A667A4922962318700B565EE /* CurveProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A37F2962318600B565EE /* CurveProperty.h */; }; A667A4932962318700B565EE /* FloatProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3802962318600B565EE /* FloatProperty.h */; }; A667A4942962318700B565EE /* IntegerProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3812962318600B565EE /* IntegerProperty.cpp */; }; A667A4952962318700B565EE /* BorderIntProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3822962318600B565EE /* BorderIntProperty.h */; }; A667A4962962318700B565EE /* ScriptValueProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3832962318600B565EE /* ScriptValueProperty.h */; }; A667A4972962318700B565EE /* EnumProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3842962318600B565EE /* EnumProperty.h */; }; A667A4982962318700B565EE /* TagProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3852962318600B565EE /* TagProperty.h */; }; A667A4992962318700B565EE /* WStringProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3862962318600B565EE /* WStringProperty.cpp */; }; A667A49A2962318700B565EE /* RectangleFloatProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3872962318600B565EE /* RectangleFloatProperty.h */; }; A667A49B2962318700B565EE /* ObjectProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3882962318600B565EE /* ObjectProperty.cpp */; }; A667A49C2962318700B565EE /* EnumProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3892962318600B565EE /* EnumProperty.cpp */; }; A667A49D2962318700B565EE /* StringProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A38A2962318600B565EE /* StringProperty.cpp */; }; A667A49E2962318700B565EE /* ObjectProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A38B2962318600B565EE /* ObjectProperty.h */; }; A667A49F2962318700B565EE /* BorderFloatProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A38C2962318600B565EE /* BorderFloatProperty.h */; }; A667A4A02962318700B565EE /* BooleanProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A38D2962318600B565EE /* BooleanProperty.h */; }; A667A4A12962318700B565EE /* LayerProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A38E2962318600B565EE /* LayerProperty.h */; }; A667A4A22962318700B565EE /* RectangleIntProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A38F2962318600B565EE /* RectangleIntProperty.h */; }; A667A4A32962318700B565EE /* LayerProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3902962318600B565EE /* LayerProperty.cpp */; }; A667A4A42962318700B565EE /* ComponentProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3912962318600B565EE /* ComponentProperty.h */; }; A667A4A52962318700B565EE /* BorderIntProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3922962318600B565EE /* BorderIntProperty.cpp */; }; A667A4A62962318700B565EE /* Vector2FloatProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3932962318600B565EE /* Vector2FloatProperty.cpp */; }; A667A4A72962318700B565EE /* EnumMaskProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3942962318600B565EE /* EnumMaskProperty.h */; }; A667A4A82962318700B565EE /* ObjectPtrProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3952962318600B565EE /* ObjectPtrProperty.cpp */; }; A667A4A92962318700B565EE /* ColorProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3962962318600B565EE /* ColorProperty.h */; }; A667A4AA2962318700B565EE /* SceneLayersListProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3972962318600B565EE /* SceneLayersListProperty.cpp */; }; A667A4AB2962318700B565EE /* AssetProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3982962318600B565EE /* AssetProperty.cpp */; }; A667A4AC2962318700B565EE /* RectangleIntProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3992962318600B565EE /* RectangleIntProperty.cpp */; }; A667A4AD2962318700B565EE /* ObjectPtrProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A39A2962318600B565EE /* ObjectPtrProperty.h */; }; A667A4AE2962318700B565EE /* StringProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A39B2962318600B565EE /* StringProperty.h */; }; A667A4AF2962318700B565EE /* FloatProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A39C2962318600B565EE /* FloatProperty.cpp */; }; A667A4B02962318700B565EE /* SceneLayersListProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A39D2962318600B565EE /* SceneLayersListProperty.h */; }; A667A4B12962318700B565EE /* RectangleFloatProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A39E2962318600B565EE /* RectangleFloatProperty.cpp */; }; A667A4B22962318700B565EE /* Vector2IntProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A39F2962318600B565EE /* Vector2IntProperty.h */; }; A667A4B32962318700B565EE /* ColorProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3A02962318600B565EE /* ColorProperty.cpp */; }; A667A4B42962318700B565EE /* TagProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3A12962318600B565EE /* TagProperty.cpp */; }; A667A4B52962318700B565EE /* ActorProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3A22962318600B565EE /* ActorProperty.h */; }; A667A4B62962318700B565EE /* Vector2FloatProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3A32962318600B565EE /* Vector2FloatProperty.h */; }; A667A4B72962318700B565EE /* AssetProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3A42962318600B565EE /* AssetProperty.h */; }; A667A4B82962318700B565EE /* BorderFloatProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3A52962318600B565EE /* BorderFloatProperty.cpp */; }; A667A4B92962318700B565EE /* VectorProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3A62962318600B565EE /* VectorProperty.cpp */; }; A667A4BA2962318700B565EE /* IntegerProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3A72962318600B565EE /* IntegerProperty.h */; }; A667A4BB2962318700B565EE /* BooleanProperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3A82962318600B565EE /* BooleanProperty.cpp */; }; A667A4BC2962318700B565EE /* CameraActorViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3AA2962318600B565EE /* CameraActorViewer.cpp */; }; A667A4BD2962318700B565EE /* SpriteViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3AB2962318600B565EE /* SpriteViewer.cpp */; }; A667A4BE2962318700B565EE /* CameraActorViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3AC2962318600B565EE /* CameraActorViewer.h */; }; A667A4BF2962318700B565EE /* TextViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3AD2962318600B565EE /* TextViewer.cpp */; }; A667A4C02962318700B565EE /* DefaultObjectPropertiesViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3AE2962318600B565EE /* DefaultObjectPropertiesViewer.cpp */; }; A667A4C12962318700B565EE /* AnimationStateViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3B02962318600B565EE /* AnimationStateViewer.h */; }; A667A4C22962318700B565EE /* MeshComponentViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3B12962318600B565EE /* MeshComponentViewer.h */; }; A667A4C32962318700B565EE /* MeshComponentViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3B22962318600B565EE /* MeshComponentViewer.cpp */; }; A667A4C42962318700B565EE /* AnimationStateViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3B32962318600B565EE /* AnimationStateViewer.cpp */; }; A667A4C52962318700B565EE /* AnimationViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3B42962318600B565EE /* AnimationViewer.cpp */; }; A667A4C62962318700B565EE /* DefaultObjectPropertiesViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3B52962318600B565EE /* DefaultObjectPropertiesViewer.h */; }; A667A4C72962318700B565EE /* AnimationViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3B62962318600B565EE /* AnimationViewer.h */; }; A667A4C82962318700B565EE /* ImageAssetViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3B82962318600B565EE /* ImageAssetViewer.h */; }; A667A4C92962318700B565EE /* ImageAssetViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3B92962318600B565EE /* ImageAssetViewer.cpp */; }; A667A4CA2962318700B565EE /* TextViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3BA2962318600B565EE /* TextViewer.h */; }; A667A4CB2962318700B565EE /* SpriteViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3BB2962318600B565EE /* SpriteViewer.h */; }; A667A4CC2962318700B565EE /* ObjectViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3BC2962318600B565EE /* ObjectViewer.h */; }; A667A4CD2962318700B565EE /* IObjectPropertiesViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3BD2962318600B565EE /* IObjectPropertiesViewer.h */; }; A667A4CE2962318700B565EE /* ObjectViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3BE2962318600B565EE /* ObjectViewer.cpp */; }; A667A4CF2962318700B565EE /* Properties.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3BF2962318600B565EE /* Properties.cpp */; }; A667A4D02962318700B565EE /* IPropertyField.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3C02962318600B565EE /* IPropertyField.h */; }; A667A4D12962318700B565EE /* PropertiesContext.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3C12962318600B565EE /* PropertiesContext.h */; }; A667A4D22962318700B565EE /* IObjectPropertiesViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3C22962318600B565EE /* IObjectPropertiesViewer.cpp */; }; A667A4D32962318700B565EE /* PropertiesContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3C32962318600B565EE /* PropertiesContext.cpp */; }; A667A4D42962318700B565EE /* Properties.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3C42962318600B565EE /* Properties.h */; }; A667A4D52962318700B565EE /* ActionsList.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3C62962318600B565EE /* ActionsList.h */; }; A667A4D62962318700B565EE /* Select.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3C72962318600B565EE /* Select.cpp */; }; A667A4D72962318700B565EE /* Reparent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3C82962318600B565EE /* Reparent.cpp */; }; A667A4D82962318700B565EE /* PropertyChange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3C92962318600B565EE /* PropertyChange.cpp */; }; A667A4D92962318700B565EE /* Reparent.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3CA2962318600B565EE /* Reparent.h */; }; A667A4DA2962318700B565EE /* Enable.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3CB2962318600B565EE /* Enable.h */; }; A667A4DB2962318700B565EE /* Lock.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3CC2962318600B565EE /* Lock.h */; }; A667A4DC2962318700B565EE /* Delete.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3CD2962318600B565EE /* Delete.h */; }; A667A4DD2962318700B565EE /* Delete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3CE2962318600B565EE /* Delete.cpp */; }; A667A4DE2962318700B565EE /* Transform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3CF2962318600B565EE /* Transform.cpp */; }; A667A4DF2962318700B565EE /* ActionsList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3D02962318600B565EE /* ActionsList.cpp */; }; A667A4E02962318700B565EE /* Create.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3D12962318600B565EE /* Create.cpp */; }; A667A4E12962318700B565EE /* Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3D22962318600B565EE /* Transform.h */; }; A667A4E22962318700B565EE /* PropertyChange.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3D32962318600B565EE /* PropertyChange.h */; }; A667A4E32962318700B565EE /* IAction.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3D42962318600B565EE /* IAction.h */; }; A667A4E42962318700B565EE /* Enable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3D52962318600B565EE /* Enable.cpp */; }; A667A4E52962318700B565EE /* Lock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3D62962318600B565EE /* Lock.cpp */; }; A667A4E62962318700B565EE /* Create.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3D72962318600B565EE /* Create.h */; }; A667A4E72962318700B565EE /* IAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3D82962318600B565EE /* IAction.cpp */; }; A667A4E82962318700B565EE /* Select.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3D92962318600B565EE /* Select.h */; }; A667A4E92962318700B565EE /* CurveEditorDlg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3DB2962318600B565EE /* CurveEditorDlg.cpp */; }; A667A4EA2962318700B565EE /* EditNameDlg.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3DC2962318600B565EE /* EditNameDlg.h */; }; A667A4EB2962318700B565EE /* KeyEditDlg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3DD2962318600B565EE /* KeyEditDlg.cpp */; }; A667A4EC2962318700B565EE /* EditNameDlg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3DE2962318600B565EE /* EditNameDlg.cpp */; }; A667A4ED2962318700B565EE /* OpenSaveDialog.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3E02962318600B565EE /* OpenSaveDialog.h */; }; A667A4EE2962318700B565EE /* OpenSaveDialog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3E22962318600B565EE /* OpenSaveDialog.cpp */; }; A667A4EF2962318700B565EE /* OpenSaveDialog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3E52962318600B565EE /* OpenSaveDialog.cpp */; }; A667A4F02962318700B565EE /* KeyEditDlg.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3E62962318600B565EE /* KeyEditDlg.h */; }; A667A4F12962318700B565EE /* ColorPickerDlg.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3E72962318600B565EE /* ColorPickerDlg.h */; }; A667A4F22962318700B565EE /* ColorPickerDlg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3E82962318600B565EE /* ColorPickerDlg.cpp */; }; A667A4F32962318700B565EE /* CurveEditorDlg.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3E92962318600B565EE /* CurveEditorDlg.h */; }; A667A4F42962318700B565EE /* EditorConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3EA2962318600B565EE /* EditorConfig.h */; }; A667A4F52962318700B565EE /* MenuPanel.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3EB2962318600B565EE /* MenuPanel.h */; }; A667A4F62962318700B565EE /* ToolsPanel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3EC2962318600B565EE /* ToolsPanel.cpp */; }; A667A4F72962318700B565EE /* ToolsPanel.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3ED2962318600B565EE /* ToolsPanel.h */; }; A667A4F82962318700B565EE /* SceneTree.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3EF2962318600B565EE /* SceneTree.h */; }; A667A4F92962318700B565EE /* TreeWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3F02962318600B565EE /* TreeWindow.cpp */; }; A667A4FA2962318700B565EE /* TreeWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3F12962318600B565EE /* TreeWindow.h */; }; A667A4FB2962318700B565EE /* SceneTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3F22962318600B565EE /* SceneTree.cpp */; }; A667A4FC2962318700B565EE /* FoldersTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3F42962318600B565EE /* FoldersTree.cpp */; }; A667A4FD2962318700B565EE /* AssetsWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3F52962318600B565EE /* AssetsWindow.cpp */; }; A667A4FE2962318700B565EE /* AssetsIconsScroll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3F62962318600B565EE /* AssetsIconsScroll.cpp */; }; A667A4FF2962318700B565EE /* AssetsWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3F72962318600B565EE /* AssetsWindow.h */; }; A667A5002962318700B565EE /* AssetIcon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3F82962318600B565EE /* AssetIcon.cpp */; }; A667A5012962318700B565EE /* AssetsIconsScroll.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3F92962318600B565EE /* AssetsIconsScroll.h */; }; A667A5022962318700B565EE /* FoldersTree.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3FA2962318600B565EE /* FoldersTree.h */; }; A667A5032962318700B565EE /* AssetIcon.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3FB2962318600B565EE /* AssetIcon.h */; }; A667A5042962318700B565EE /* SceneEditScreen.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3FD2962318600B565EE /* SceneEditScreen.h */; }; A667A5052962318700B565EE /* SceneDragHandle.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A3FE2962318600B565EE /* SceneDragHandle.h */; }; A667A5062962318700B565EE /* SceneEditScreen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A3FF2962318600B565EE /* SceneEditScreen.cpp */; }; A667A5072962318700B565EE /* SceneEditorLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4002962318600B565EE /* SceneEditorLayer.h */; }; A667A5082962318700B565EE /* SceneWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4012962318600B565EE /* SceneWindow.h */; }; A667A5092962318700B565EE /* SceneWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4022962318600B565EE /* SceneWindow.cpp */; }; A667A50A2962318700B565EE /* LayersPopup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4032962318600B565EE /* LayersPopup.cpp */; }; A667A50B2962318700B565EE /* SceneDragHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4042962318600B565EE /* SceneDragHandle.cpp */; }; A667A50C2962318700B565EE /* LayersPopup.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4052962318600B565EE /* LayersPopup.h */; }; A667A50D2962318700B565EE /* stdafx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4062962318600B565EE /* stdafx.cpp */; }; A667A50E2962318700B565EE /* PropertiesWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4082962318600B565EE /* PropertiesWindow.h */; }; A667A50F2962318700B565EE /* AssetPropertiesViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4092962318600B565EE /* AssetPropertiesViewer.h */; }; A667A5102962318700B565EE /* AssetPropertiesViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A40A2962318600B565EE /* AssetPropertiesViewer.cpp */; }; A667A5112962318700B565EE /* DefaultActorComponentViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A40C2962318600B565EE /* DefaultActorComponentViewer.cpp */; }; A667A5122962318700B565EE /* DefaultActorTransformViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A40D2962318600B565EE /* DefaultActorTransformViewer.h */; }; A667A5132962318700B565EE /* IActorPropertiesViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A40E2962318600B565EE /* IActorPropertiesViewer.h */; }; A667A5142962318700B565EE /* ActorViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A40F2962318600B565EE /* ActorViewer.cpp */; }; A667A5152962318700B565EE /* IActorTransformViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4102962318600B565EE /* IActorTransformViewer.h */; }; A667A5162962318700B565EE /* AddComponentPanel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4112962318600B565EE /* AddComponentPanel.cpp */; }; A667A5172962318700B565EE /* IActorComponentViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4122962318600B565EE /* IActorComponentViewer.cpp */; }; A667A5182962318700B565EE /* DefaultActorHeaderViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4132962318600B565EE /* DefaultActorHeaderViewer.h */; }; A667A5192962318700B565EE /* IActorPropertiesViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4142962318600B565EE /* IActorPropertiesViewer.cpp */; }; A667A51A2962318700B565EE /* IActorHeaderViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4152962318600B565EE /* IActorHeaderViewer.cpp */; }; A667A51B2962318700B565EE /* ActorViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4162962318600B565EE /* ActorViewer.h */; }; A667A51C2962318700B565EE /* DefaultActorHeaderViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4172962318600B565EE /* DefaultActorHeaderViewer.cpp */; }; A667A51D2962318700B565EE /* IActorTransformViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4182962318600B565EE /* IActorTransformViewer.cpp */; }; A667A51E2962318700B565EE /* DefaultActorComponentViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4192962318600B565EE /* DefaultActorComponentViewer.h */; }; A667A51F2962318700B565EE /* DefaultActorPropertiesViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A41A2962318600B565EE /* DefaultActorPropertiesViewer.h */; }; A667A5202962318700B565EE /* IActorHeaderViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A41B2962318600B565EE /* IActorHeaderViewer.h */; }; A667A5212962318700B565EE /* IActorComponentViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A41C2962318600B565EE /* IActorComponentViewer.h */; }; A667A5222962318700B565EE /* DefaultActorPropertiesViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A41D2962318600B565EE /* DefaultActorPropertiesViewer.cpp */; }; A667A5232962318700B565EE /* AddComponentPanel.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A41E2962318600B565EE /* AddComponentPanel.h */; }; A667A5242962318700B565EE /* DefaultActorTransformViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A41F2962318600B565EE /* DefaultActorTransformViewer.cpp */; }; A667A5252962318700B565EE /* IPropertiesViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4202962318600B565EE /* IPropertiesViewer.h */; }; A667A5262962318700B565EE /* IPropertiesViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4212962318600B565EE /* IPropertiesViewer.cpp */; }; A667A5272962318700B565EE /* DefaultPropertiesViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4222962318600B565EE /* DefaultPropertiesViewer.h */; }; A667A5282962318700B565EE /* DefaultPropertiesViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4232962318600B565EE /* DefaultPropertiesViewer.cpp */; }; A667A5292962318700B565EE /* PropertiesWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4242962318600B565EE /* PropertiesWindow.cpp */; }; A667A52A2962318700B565EE /* DefaultWidgetLayerPropertiesViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4262962318600B565EE /* DefaultWidgetLayerPropertiesViewer.h */; }; A667A52B2962318700B565EE /* IWidgetLayerLayoutViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4272962318600B565EE /* IWidgetLayerLayoutViewer.cpp */; }; A667A52C2962318700B565EE /* IWidgetLayerHeadViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4282962318600B565EE /* IWidgetLayerHeadViewer.h */; }; A667A52D2962318700B565EE /* DefaultWidgetLayerLayoutViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4292962318600B565EE /* DefaultWidgetLayerLayoutViewer.h */; }; A667A52E2962318700B565EE /* WidgetLayerViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A42A2962318600B565EE /* WidgetLayerViewer.cpp */; }; A667A52F2962318700B565EE /* IWidgetLayerLayoutViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A42B2962318600B565EE /* IWidgetLayerLayoutViewer.h */; }; A667A5302962318700B565EE /* IWidgetLayerPropertiesViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A42C2962318600B565EE /* IWidgetLayerPropertiesViewer.cpp */; }; A667A5312962318700B565EE /* WidgetLayerViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A42D2962318600B565EE /* WidgetLayerViewer.h */; }; A667A5322962318700B565EE /* IWidgetLayerHeadViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A42E2962318600B565EE /* IWidgetLayerHeadViewer.cpp */; }; A667A5332962318700B565EE /* IWidgetLayerPropertiesViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A42F2962318600B565EE /* IWidgetLayerPropertiesViewer.h */; }; A667A5342962318700B565EE /* DefaultWidgetLayerLayoutViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4302962318600B565EE /* DefaultWidgetLayerLayoutViewer.cpp */; }; A667A5352962318700B565EE /* DefaultWidgetLayerHeadViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4312962318600B565EE /* DefaultWidgetLayerHeadViewer.cpp */; }; A667A5362962318700B565EE /* DefaultWidgetLayerHeadViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4322962318600B565EE /* DefaultWidgetLayerHeadViewer.h */; }; A667A5372962318700B565EE /* DefaultWidgetLayerPropertiesViewer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4332962318600B565EE /* DefaultWidgetLayerPropertiesViewer.cpp */; }; A667A5382962318700B565EE /* GameWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4352962318600B565EE /* GameWindow.cpp */; }; A667A5392962318700B565EE /* GameWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4362962318600B565EE /* GameWindow.h */; }; A667A53A2962318700B565EE /* LogWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4382962318600B565EE /* LogWindow.h */; }; A667A53B2962318700B565EE /* LogWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4392962318600B565EE /* LogWindow.cpp */; }; A667A53C2962318700B565EE /* KeyHandlesSheet.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A43B2962318600B565EE /* KeyHandlesSheet.h */; }; A667A53D2962318700B565EE /* AnimationKeysActions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A43C2962318600B565EE /* AnimationKeysActions.cpp */; }; A667A53E2962318700B565EE /* KeyHandlesSheet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A43D2962318600B565EE /* KeyHandlesSheet.cpp */; }; A667A53F2962318700B565EE /* Tree.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A43E2962318600B565EE /* Tree.h */; }; A667A5402962318700B565EE /* CurvesSheet.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A43F2962318600B565EE /* CurvesSheet.h */; }; A667A5412962318700B565EE /* PropertiesListDlg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4402962318600B565EE /* PropertiesListDlg.cpp */; }; A667A5422962318700B565EE /* PropertiesListDlg.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4412962318600B565EE /* PropertiesListDlg.h */; }; A667A5432962318700B565EE /* Timeline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4422962318600B565EE /* Timeline.cpp */; }; A667A5442962318700B565EE /* Tree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4432962318600B565EE /* Tree.cpp */; }; A667A5452962318700B565EE /* AnimationWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4442962318600B565EE /* AnimationWindow.h */; }; A667A5462962318700B565EE /* CurvesSheet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4452962318600B565EE /* CurvesSheet.cpp */; }; A667A5472962318700B565EE /* MapKeyFramesTrackControl.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4472962318600B565EE /* MapKeyFramesTrackControl.h */; }; A667A5482962318700B565EE /* KeyFramesTrackControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4482962318600B565EE /* KeyFramesTrackControl.cpp */; }; A667A5492962318700B565EE /* AnimationTrackWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4492962318600B565EE /* AnimationTrackWrapper.h */; }; A667A54A2962318700B565EE /* MapKeyFramesTrackControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A44A2962318600B565EE /* MapKeyFramesTrackControl.cpp */; }; A667A54B2962318700B565EE /* AnimationKeyDragHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A44B2962318600B565EE /* AnimationKeyDragHandle.cpp */; }; A667A54C2962318700B565EE /* Vec2KeyFramesTrackControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A44C2962318600B565EE /* Vec2KeyFramesTrackControl.cpp */; }; A667A54D2962318700B565EE /* ITrackControl.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A44D2962318600B565EE /* ITrackControl.h */; }; A667A54E2962318700B565EE /* ITrackControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A44E2962318600B565EE /* ITrackControl.cpp */; }; A667A54F2962318700B565EE /* KeyFramesTrackControl.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A44F2962318600B565EE /* KeyFramesTrackControl.h */; }; A667A5502962318700B565EE /* Vec2KeyFramesTrackControl.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4502962318600B565EE /* Vec2KeyFramesTrackControl.h */; }; A667A5512962318700B565EE /* AnimationKeyDragHandle.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4512962318600B565EE /* AnimationKeyDragHandle.h */; }; A667A5522962318700B565EE /* AnimationWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A667A4522962318600B565EE /* AnimationWindow.cpp */; }; A667A5532962318700B565EE /* Timeline.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4532962318600B565EE /* Timeline.h */; }; A667A5542962318700B565EE /* AnimationKeysActions.h in Headers */ = {isa = PBXBuildFile; fileRef = A667A4542962318600B565EE /* AnimationKeysActions.h */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ A667A3392962318600B565EE /* stdafx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stdafx.h; sourceTree = ""; }; A667A33B2962318600B565EE /* EditorApplication.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EditorApplication.cpp; sourceTree = ""; }; A667A33D2962318600B565EE /* CurvePreview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CurvePreview.h; sourceTree = ""; }; A667A33E2962318600B565EE /* ImageSlicesEditorWidget.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageSlicesEditorWidget.cpp; sourceTree = ""; }; A667A33F2962318600B565EE /* ScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollView.h; sourceTree = ""; }; A667A3402962318600B565EE /* FrameScrollView.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FrameScrollView.cpp; sourceTree = ""; }; A667A3412962318600B565EE /* ImageSlicesEditorWidget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageSlicesEditorWidget.h; sourceTree = ""; }; A667A3422962318600B565EE /* FrameScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FrameScrollView.h; sourceTree = ""; }; A667A3442962318600B565EE /* CurvesEditor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CurvesEditor.cpp; sourceTree = ""; }; A667A3452962318600B565EE /* CurvesEditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CurvesEditor.h; sourceTree = ""; }; A667A3462962318600B565EE /* CurveActions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CurveActions.cpp; sourceTree = ""; }; A667A3472962318600B565EE /* CurveActions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CurveActions.h; sourceTree = ""; }; A667A3492962318600B565EE /* SplineEditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SplineEditor.h; sourceTree = ""; }; A667A34A2962318600B565EE /* SplineEditor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SplineEditor.cpp; sourceTree = ""; }; A667A34B2962318600B565EE /* SpoilerWithHead.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpoilerWithHead.cpp; sourceTree = ""; }; A667A34C2962318600B565EE /* SpoilerWithHead.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpoilerWithHead.h; sourceTree = ""; }; A667A34D2962318600B565EE /* CurvePreview.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CurvePreview.cpp; sourceTree = ""; }; A667A34E2962318600B565EE /* ScrollView.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScrollView.cpp; sourceTree = ""; }; A667A34F2962318600B565EE /* UIRoot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UIRoot.cpp; sourceTree = ""; }; A667A3512962318600B565EE /* DockableWindow.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DockableWindow.cpp; sourceTree = ""; }; A667A3522962318600B565EE /* WindowsLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WindowsLayout.cpp; sourceTree = ""; }; A667A3532962318600B565EE /* WindowsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WindowsManager.h; sourceTree = ""; }; A667A3542962318600B565EE /* WindowsManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WindowsManager.cpp; sourceTree = ""; }; A667A3552962318600B565EE /* IEditorWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IEditorWindow.h; sourceTree = ""; }; A667A3562962318600B565EE /* DockWindowPlace.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DockWindowPlace.cpp; sourceTree = ""; }; A667A3572962318600B565EE /* WindowsLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WindowsLayout.h; sourceTree = ""; }; A667A3582962318600B565EE /* DockableWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DockableWindow.h; sourceTree = ""; }; A667A3592962318600B565EE /* IEditorWindow.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IEditorWindow.cpp; sourceTree = ""; }; A667A35A2962318600B565EE /* DockWindowPlace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DockWindowPlace.h; sourceTree = ""; }; A667A35C2962318600B565EE /* EditorUIStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditorUIStyle.h; sourceTree = ""; }; A667A35D2962318600B565EE /* BasicUIStyle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BasicUIStyle.cpp; sourceTree = ""; }; A667A35E2962318600B565EE /* EditorUIStyle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EditorUIStyle.cpp; sourceTree = ""; }; A667A35F2962318600B565EE /* BasicUIStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BasicUIStyle.h; sourceTree = ""; }; A667A3602962318600B565EE /* EditorConfig.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EditorConfig.cpp; sourceTree = ""; }; A667A3622962318600B565EE /* ScaleTool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScaleTool.cpp; sourceTree = ""; }; A667A3632962318600B565EE /* SelectionTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectionTool.h; sourceTree = ""; }; A667A3642962318600B565EE /* MoveTool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MoveTool.cpp; sourceTree = ""; }; A667A3652962318600B565EE /* CustomFrameTool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CustomFrameTool.cpp; sourceTree = ""; }; A667A3662962318600B565EE /* RotateTool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RotateTool.cpp; sourceTree = ""; }; A667A3672962318600B565EE /* ScaleTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScaleTool.h; sourceTree = ""; }; A667A3682962318600B565EE /* FrameTool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FrameTool.cpp; sourceTree = ""; }; A667A3692962318600B565EE /* FrameTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FrameTool.h; sourceTree = ""; }; A667A36A2962318600B565EE /* RotateTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RotateTool.h; sourceTree = ""; }; A667A36B2962318600B565EE /* CustomFrameTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomFrameTool.h; sourceTree = ""; }; A667A36C2962318600B565EE /* MoveTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MoveTool.h; sourceTree = ""; }; A667A36D2962318600B565EE /* SplineTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SplineTool.h; sourceTree = ""; }; A667A36E2962318600B565EE /* IEditorTool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IEditorTool.cpp; sourceTree = ""; }; A667A36F2962318600B565EE /* SplineTool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SplineTool.cpp; sourceTree = ""; }; A667A3702962318600B565EE /* IEditorTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IEditorTool.h; sourceTree = ""; }; A667A3712962318600B565EE /* SelectionTool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SelectionTool.cpp; sourceTree = ""; }; A667A3722962318600B565EE /* MenuPanel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MenuPanel.cpp; sourceTree = ""; }; A667A3732962318600B565EE /* EditorApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditorApplication.h; sourceTree = ""; }; A667A3742962318600B565EE /* UIRoot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIRoot.h; sourceTree = ""; }; A667A3762962318600B565EE /* IPropertyField.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IPropertyField.cpp; sourceTree = ""; }; A667A3782962318600B565EE /* ComponentProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ComponentProperty.cpp; sourceTree = ""; }; A667A3792962318600B565EE /* ActorProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ActorProperty.cpp; sourceTree = ""; }; A667A37A2962318600B565EE /* Vector2IntProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Vector2IntProperty.cpp; sourceTree = ""; }; A667A37B2962318600B565EE /* CurveProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CurveProperty.cpp; sourceTree = ""; }; A667A37C2962318600B565EE /* VectorProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VectorProperty.h; sourceTree = ""; }; A667A37D2962318600B565EE /* ScriptValueProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptValueProperty.cpp; sourceTree = ""; }; A667A37E2962318600B565EE /* WStringProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WStringProperty.h; sourceTree = ""; }; A667A37F2962318600B565EE /* CurveProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CurveProperty.h; sourceTree = ""; }; A667A3802962318600B565EE /* FloatProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FloatProperty.h; sourceTree = ""; }; A667A3812962318600B565EE /* IntegerProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntegerProperty.cpp; sourceTree = ""; }; A667A3822962318600B565EE /* BorderIntProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BorderIntProperty.h; sourceTree = ""; }; A667A3832962318600B565EE /* ScriptValueProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptValueProperty.h; sourceTree = ""; }; A667A3842962318600B565EE /* EnumProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EnumProperty.h; sourceTree = ""; }; A667A3852962318600B565EE /* TagProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TagProperty.h; sourceTree = ""; }; A667A3862962318600B565EE /* WStringProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WStringProperty.cpp; sourceTree = ""; }; A667A3872962318600B565EE /* RectangleFloatProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RectangleFloatProperty.h; sourceTree = ""; }; A667A3882962318600B565EE /* ObjectProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectProperty.cpp; sourceTree = ""; }; A667A3892962318600B565EE /* EnumProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EnumProperty.cpp; sourceTree = ""; }; A667A38A2962318600B565EE /* StringProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StringProperty.cpp; sourceTree = ""; }; A667A38B2962318600B565EE /* ObjectProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectProperty.h; sourceTree = ""; }; A667A38C2962318600B565EE /* BorderFloatProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BorderFloatProperty.h; sourceTree = ""; }; A667A38D2962318600B565EE /* BooleanProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BooleanProperty.h; sourceTree = ""; }; A667A38E2962318600B565EE /* LayerProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LayerProperty.h; sourceTree = ""; }; A667A38F2962318600B565EE /* RectangleIntProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RectangleIntProperty.h; sourceTree = ""; }; A667A3902962318600B565EE /* LayerProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LayerProperty.cpp; sourceTree = ""; }; A667A3912962318600B565EE /* ComponentProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ComponentProperty.h; sourceTree = ""; }; A667A3922962318600B565EE /* BorderIntProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BorderIntProperty.cpp; sourceTree = ""; }; A667A3932962318600B565EE /* Vector2FloatProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Vector2FloatProperty.cpp; sourceTree = ""; }; A667A3942962318600B565EE /* EnumMaskProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EnumMaskProperty.h; sourceTree = ""; }; A667A3952962318600B565EE /* ObjectPtrProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectPtrProperty.cpp; sourceTree = ""; }; A667A3962962318600B565EE /* ColorProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ColorProperty.h; sourceTree = ""; }; A667A3972962318600B565EE /* SceneLayersListProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SceneLayersListProperty.cpp; sourceTree = ""; }; A667A3982962318600B565EE /* AssetProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AssetProperty.cpp; sourceTree = ""; }; A667A3992962318600B565EE /* RectangleIntProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RectangleIntProperty.cpp; sourceTree = ""; }; A667A39A2962318600B565EE /* ObjectPtrProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectPtrProperty.h; sourceTree = ""; }; A667A39B2962318600B565EE /* StringProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringProperty.h; sourceTree = ""; }; A667A39C2962318600B565EE /* FloatProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FloatProperty.cpp; sourceTree = ""; }; A667A39D2962318600B565EE /* SceneLayersListProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SceneLayersListProperty.h; sourceTree = ""; }; A667A39E2962318600B565EE /* RectangleFloatProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RectangleFloatProperty.cpp; sourceTree = ""; }; A667A39F2962318600B565EE /* Vector2IntProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Vector2IntProperty.h; sourceTree = ""; }; A667A3A02962318600B565EE /* ColorProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ColorProperty.cpp; sourceTree = ""; }; A667A3A12962318600B565EE /* TagProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TagProperty.cpp; sourceTree = ""; }; A667A3A22962318600B565EE /* ActorProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ActorProperty.h; sourceTree = ""; }; A667A3A32962318600B565EE /* Vector2FloatProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Vector2FloatProperty.h; sourceTree = ""; }; A667A3A42962318600B565EE /* AssetProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AssetProperty.h; sourceTree = ""; }; A667A3A52962318600B565EE /* BorderFloatProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BorderFloatProperty.cpp; sourceTree = ""; }; A667A3A62962318600B565EE /* VectorProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VectorProperty.cpp; sourceTree = ""; }; A667A3A72962318600B565EE /* IntegerProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntegerProperty.h; sourceTree = ""; }; A667A3A82962318600B565EE /* BooleanProperty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BooleanProperty.cpp; sourceTree = ""; }; A667A3AA2962318600B565EE /* CameraActorViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CameraActorViewer.cpp; sourceTree = ""; }; A667A3AB2962318600B565EE /* SpriteViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpriteViewer.cpp; sourceTree = ""; }; A667A3AC2962318600B565EE /* CameraActorViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CameraActorViewer.h; sourceTree = ""; }; A667A3AD2962318600B565EE /* TextViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextViewer.cpp; sourceTree = ""; }; A667A3AE2962318600B565EE /* DefaultObjectPropertiesViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DefaultObjectPropertiesViewer.cpp; sourceTree = ""; }; A667A3B02962318600B565EE /* AnimationStateViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimationStateViewer.h; sourceTree = ""; }; A667A3B12962318600B565EE /* MeshComponentViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MeshComponentViewer.h; sourceTree = ""; }; A667A3B22962318600B565EE /* MeshComponentViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MeshComponentViewer.cpp; sourceTree = ""; }; A667A3B32962318600B565EE /* AnimationStateViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AnimationStateViewer.cpp; sourceTree = ""; }; A667A3B42962318600B565EE /* AnimationViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AnimationViewer.cpp; sourceTree = ""; }; A667A3B52962318600B565EE /* DefaultObjectPropertiesViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DefaultObjectPropertiesViewer.h; sourceTree = ""; }; A667A3B62962318600B565EE /* AnimationViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimationViewer.h; sourceTree = ""; }; A667A3B82962318600B565EE /* ImageAssetViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageAssetViewer.h; sourceTree = ""; }; A667A3B92962318600B565EE /* ImageAssetViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageAssetViewer.cpp; sourceTree = ""; }; A667A3BA2962318600B565EE /* TextViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextViewer.h; sourceTree = ""; }; A667A3BB2962318600B565EE /* SpriteViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpriteViewer.h; sourceTree = ""; }; A667A3BC2962318600B565EE /* ObjectViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectViewer.h; sourceTree = ""; }; A667A3BD2962318600B565EE /* IObjectPropertiesViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IObjectPropertiesViewer.h; sourceTree = ""; }; A667A3BE2962318600B565EE /* ObjectViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectViewer.cpp; sourceTree = ""; }; A667A3BF2962318600B565EE /* Properties.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Properties.cpp; sourceTree = ""; }; A667A3C02962318600B565EE /* IPropertyField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IPropertyField.h; sourceTree = ""; }; A667A3C12962318600B565EE /* PropertiesContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertiesContext.h; sourceTree = ""; }; A667A3C22962318600B565EE /* IObjectPropertiesViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IObjectPropertiesViewer.cpp; sourceTree = ""; }; A667A3C32962318600B565EE /* PropertiesContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PropertiesContext.cpp; sourceTree = ""; }; A667A3C42962318600B565EE /* Properties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Properties.h; sourceTree = ""; }; A667A3C62962318600B565EE /* ActionsList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ActionsList.h; sourceTree = ""; }; A667A3C72962318600B565EE /* Select.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Select.cpp; sourceTree = ""; }; A667A3C82962318600B565EE /* Reparent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Reparent.cpp; sourceTree = ""; }; A667A3C92962318600B565EE /* PropertyChange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PropertyChange.cpp; sourceTree = ""; }; A667A3CA2962318600B565EE /* Reparent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reparent.h; sourceTree = ""; }; A667A3CB2962318600B565EE /* Enable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Enable.h; sourceTree = ""; }; A667A3CC2962318600B565EE /* Lock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Lock.h; sourceTree = ""; }; A667A3CD2962318600B565EE /* Delete.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Delete.h; sourceTree = ""; }; A667A3CE2962318600B565EE /* Delete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Delete.cpp; sourceTree = ""; }; A667A3CF2962318600B565EE /* Transform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Transform.cpp; sourceTree = ""; }; A667A3D02962318600B565EE /* ActionsList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ActionsList.cpp; sourceTree = ""; }; A667A3D12962318600B565EE /* Create.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Create.cpp; sourceTree = ""; }; A667A3D22962318600B565EE /* Transform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Transform.h; sourceTree = ""; }; A667A3D32962318600B565EE /* PropertyChange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertyChange.h; sourceTree = ""; }; A667A3D42962318600B565EE /* IAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IAction.h; sourceTree = ""; }; A667A3D52962318600B565EE /* Enable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Enable.cpp; sourceTree = ""; }; A667A3D62962318600B565EE /* Lock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Lock.cpp; sourceTree = ""; }; A667A3D72962318600B565EE /* Create.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Create.h; sourceTree = ""; }; A667A3D82962318600B565EE /* IAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IAction.cpp; sourceTree = ""; }; A667A3D92962318600B565EE /* Select.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Select.h; sourceTree = ""; }; A667A3DB2962318600B565EE /* CurveEditorDlg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CurveEditorDlg.cpp; sourceTree = ""; }; A667A3DC2962318600B565EE /* EditNameDlg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditNameDlg.h; sourceTree = ""; }; A667A3DD2962318600B565EE /* KeyEditDlg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KeyEditDlg.cpp; sourceTree = ""; }; A667A3DE2962318600B565EE /* EditNameDlg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EditNameDlg.cpp; sourceTree = ""; }; A667A3E02962318600B565EE /* OpenSaveDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenSaveDialog.h; sourceTree = ""; }; A667A3E22962318600B565EE /* OpenSaveDialog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OpenSaveDialog.cpp; sourceTree = ""; }; A667A3E52962318600B565EE /* OpenSaveDialog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OpenSaveDialog.cpp; sourceTree = ""; }; A667A3E62962318600B565EE /* KeyEditDlg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyEditDlg.h; sourceTree = ""; }; A667A3E72962318600B565EE /* ColorPickerDlg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ColorPickerDlg.h; sourceTree = ""; }; A667A3E82962318600B565EE /* ColorPickerDlg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ColorPickerDlg.cpp; sourceTree = ""; }; A667A3E92962318600B565EE /* CurveEditorDlg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CurveEditorDlg.h; sourceTree = ""; }; A667A3EA2962318600B565EE /* EditorConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditorConfig.h; sourceTree = ""; }; A667A3EB2962318600B565EE /* MenuPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MenuPanel.h; sourceTree = ""; }; A667A3EC2962318600B565EE /* ToolsPanel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ToolsPanel.cpp; sourceTree = ""; }; A667A3ED2962318600B565EE /* ToolsPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ToolsPanel.h; sourceTree = ""; }; A667A3EF2962318600B565EE /* SceneTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SceneTree.h; sourceTree = ""; }; A667A3F02962318600B565EE /* TreeWindow.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TreeWindow.cpp; sourceTree = ""; }; A667A3F12962318600B565EE /* TreeWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TreeWindow.h; sourceTree = ""; }; A667A3F22962318600B565EE /* SceneTree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SceneTree.cpp; sourceTree = ""; }; A667A3F42962318600B565EE /* FoldersTree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FoldersTree.cpp; sourceTree = ""; }; A667A3F52962318600B565EE /* AssetsWindow.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AssetsWindow.cpp; sourceTree = ""; }; A667A3F62962318600B565EE /* AssetsIconsScroll.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AssetsIconsScroll.cpp; sourceTree = ""; }; A667A3F72962318600B565EE /* AssetsWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AssetsWindow.h; sourceTree = ""; }; A667A3F82962318600B565EE /* AssetIcon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AssetIcon.cpp; sourceTree = ""; }; A667A3F92962318600B565EE /* AssetsIconsScroll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AssetsIconsScroll.h; sourceTree = ""; }; A667A3FA2962318600B565EE /* FoldersTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FoldersTree.h; sourceTree = ""; }; A667A3FB2962318600B565EE /* AssetIcon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AssetIcon.h; sourceTree = ""; }; A667A3FD2962318600B565EE /* SceneEditScreen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SceneEditScreen.h; sourceTree = ""; }; A667A3FE2962318600B565EE /* SceneDragHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SceneDragHandle.h; sourceTree = ""; }; A667A3FF2962318600B565EE /* SceneEditScreen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SceneEditScreen.cpp; sourceTree = ""; }; A667A4002962318600B565EE /* SceneEditorLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SceneEditorLayer.h; sourceTree = ""; }; A667A4012962318600B565EE /* SceneWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SceneWindow.h; sourceTree = ""; }; A667A4022962318600B565EE /* SceneWindow.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SceneWindow.cpp; sourceTree = ""; }; A667A4032962318600B565EE /* LayersPopup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LayersPopup.cpp; sourceTree = ""; }; A667A4042962318600B565EE /* SceneDragHandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SceneDragHandle.cpp; sourceTree = ""; }; A667A4052962318600B565EE /* LayersPopup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LayersPopup.h; sourceTree = ""; }; A667A4062962318600B565EE /* stdafx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = stdafx.cpp; sourceTree = ""; }; A667A4082962318600B565EE /* PropertiesWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertiesWindow.h; sourceTree = ""; }; A667A4092962318600B565EE /* AssetPropertiesViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AssetPropertiesViewer.h; sourceTree = ""; }; A667A40A2962318600B565EE /* AssetPropertiesViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AssetPropertiesViewer.cpp; sourceTree = ""; }; A667A40C2962318600B565EE /* DefaultActorComponentViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DefaultActorComponentViewer.cpp; sourceTree = ""; }; A667A40D2962318600B565EE /* DefaultActorTransformViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DefaultActorTransformViewer.h; sourceTree = ""; }; A667A40E2962318600B565EE /* IActorPropertiesViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IActorPropertiesViewer.h; sourceTree = ""; }; A667A40F2962318600B565EE /* ActorViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ActorViewer.cpp; sourceTree = ""; }; A667A4102962318600B565EE /* IActorTransformViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IActorTransformViewer.h; sourceTree = ""; }; A667A4112962318600B565EE /* AddComponentPanel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AddComponentPanel.cpp; sourceTree = ""; }; A667A4122962318600B565EE /* IActorComponentViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IActorComponentViewer.cpp; sourceTree = ""; }; A667A4132962318600B565EE /* DefaultActorHeaderViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DefaultActorHeaderViewer.h; sourceTree = ""; }; A667A4142962318600B565EE /* IActorPropertiesViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IActorPropertiesViewer.cpp; sourceTree = ""; }; A667A4152962318600B565EE /* IActorHeaderViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IActorHeaderViewer.cpp; sourceTree = ""; }; A667A4162962318600B565EE /* ActorViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ActorViewer.h; sourceTree = ""; }; A667A4172962318600B565EE /* DefaultActorHeaderViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DefaultActorHeaderViewer.cpp; sourceTree = ""; }; A667A4182962318600B565EE /* IActorTransformViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IActorTransformViewer.cpp; sourceTree = ""; }; A667A4192962318600B565EE /* DefaultActorComponentViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DefaultActorComponentViewer.h; sourceTree = ""; }; A667A41A2962318600B565EE /* DefaultActorPropertiesViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DefaultActorPropertiesViewer.h; sourceTree = ""; }; A667A41B2962318600B565EE /* IActorHeaderViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IActorHeaderViewer.h; sourceTree = ""; }; A667A41C2962318600B565EE /* IActorComponentViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IActorComponentViewer.h; sourceTree = ""; }; A667A41D2962318600B565EE /* DefaultActorPropertiesViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DefaultActorPropertiesViewer.cpp; sourceTree = ""; }; A667A41E2962318600B565EE /* AddComponentPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddComponentPanel.h; sourceTree = ""; }; A667A41F2962318600B565EE /* DefaultActorTransformViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DefaultActorTransformViewer.cpp; sourceTree = ""; }; A667A4202962318600B565EE /* IPropertiesViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IPropertiesViewer.h; sourceTree = ""; }; A667A4212962318600B565EE /* IPropertiesViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IPropertiesViewer.cpp; sourceTree = ""; }; A667A4222962318600B565EE /* DefaultPropertiesViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DefaultPropertiesViewer.h; sourceTree = ""; }; A667A4232962318600B565EE /* DefaultPropertiesViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DefaultPropertiesViewer.cpp; sourceTree = ""; }; A667A4242962318600B565EE /* PropertiesWindow.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PropertiesWindow.cpp; sourceTree = ""; }; A667A4262962318600B565EE /* DefaultWidgetLayerPropertiesViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DefaultWidgetLayerPropertiesViewer.h; sourceTree = ""; }; A667A4272962318600B565EE /* IWidgetLayerLayoutViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IWidgetLayerLayoutViewer.cpp; sourceTree = ""; }; A667A4282962318600B565EE /* IWidgetLayerHeadViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IWidgetLayerHeadViewer.h; sourceTree = ""; }; A667A4292962318600B565EE /* DefaultWidgetLayerLayoutViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DefaultWidgetLayerLayoutViewer.h; sourceTree = ""; }; A667A42A2962318600B565EE /* WidgetLayerViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WidgetLayerViewer.cpp; sourceTree = ""; }; A667A42B2962318600B565EE /* IWidgetLayerLayoutViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IWidgetLayerLayoutViewer.h; sourceTree = ""; }; A667A42C2962318600B565EE /* IWidgetLayerPropertiesViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IWidgetLayerPropertiesViewer.cpp; sourceTree = ""; }; A667A42D2962318600B565EE /* WidgetLayerViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WidgetLayerViewer.h; sourceTree = ""; }; A667A42E2962318600B565EE /* IWidgetLayerHeadViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IWidgetLayerHeadViewer.cpp; sourceTree = ""; }; A667A42F2962318600B565EE /* IWidgetLayerPropertiesViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IWidgetLayerPropertiesViewer.h; sourceTree = ""; }; A667A4302962318600B565EE /* DefaultWidgetLayerLayoutViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DefaultWidgetLayerLayoutViewer.cpp; sourceTree = ""; }; A667A4312962318600B565EE /* DefaultWidgetLayerHeadViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DefaultWidgetLayerHeadViewer.cpp; sourceTree = ""; }; A667A4322962318600B565EE /* DefaultWidgetLayerHeadViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DefaultWidgetLayerHeadViewer.h; sourceTree = ""; }; A667A4332962318600B565EE /* DefaultWidgetLayerPropertiesViewer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DefaultWidgetLayerPropertiesViewer.cpp; sourceTree = ""; }; A667A4352962318600B565EE /* GameWindow.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GameWindow.cpp; sourceTree = ""; }; A667A4362962318600B565EE /* GameWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GameWindow.h; sourceTree = ""; }; A667A4382962318600B565EE /* LogWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogWindow.h; sourceTree = ""; }; A667A4392962318600B565EE /* LogWindow.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogWindow.cpp; sourceTree = ""; }; A667A43B2962318600B565EE /* KeyHandlesSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyHandlesSheet.h; sourceTree = ""; }; A667A43C2962318600B565EE /* AnimationKeysActions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AnimationKeysActions.cpp; sourceTree = ""; }; A667A43D2962318600B565EE /* KeyHandlesSheet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KeyHandlesSheet.cpp; sourceTree = ""; }; A667A43E2962318600B565EE /* Tree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Tree.h; sourceTree = ""; }; A667A43F2962318600B565EE /* CurvesSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CurvesSheet.h; sourceTree = ""; }; A667A4402962318600B565EE /* PropertiesListDlg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PropertiesListDlg.cpp; sourceTree = ""; }; A667A4412962318600B565EE /* PropertiesListDlg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertiesListDlg.h; sourceTree = ""; }; A667A4422962318600B565EE /* Timeline.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Timeline.cpp; sourceTree = ""; }; A667A4432962318600B565EE /* Tree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Tree.cpp; sourceTree = ""; }; A667A4442962318600B565EE /* AnimationWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimationWindow.h; sourceTree = ""; }; A667A4452962318600B565EE /* CurvesSheet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CurvesSheet.cpp; sourceTree = ""; }; A667A4472962318600B565EE /* MapKeyFramesTrackControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MapKeyFramesTrackControl.h; sourceTree = ""; }; A667A4482962318600B565EE /* KeyFramesTrackControl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KeyFramesTrackControl.cpp; sourceTree = ""; }; A667A4492962318600B565EE /* AnimationTrackWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimationTrackWrapper.h; sourceTree = ""; }; A667A44A2962318600B565EE /* MapKeyFramesTrackControl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MapKeyFramesTrackControl.cpp; sourceTree = ""; }; A667A44B2962318600B565EE /* AnimationKeyDragHandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AnimationKeyDragHandle.cpp; sourceTree = ""; }; A667A44C2962318600B565EE /* Vec2KeyFramesTrackControl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Vec2KeyFramesTrackControl.cpp; sourceTree = ""; }; A667A44D2962318600B565EE /* ITrackControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ITrackControl.h; sourceTree = ""; }; A667A44E2962318600B565EE /* ITrackControl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ITrackControl.cpp; sourceTree = ""; }; A667A44F2962318600B565EE /* KeyFramesTrackControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyFramesTrackControl.h; sourceTree = ""; }; A667A4502962318600B565EE /* Vec2KeyFramesTrackControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Vec2KeyFramesTrackControl.h; sourceTree = ""; }; A667A4512962318600B565EE /* AnimationKeyDragHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimationKeyDragHandle.h; sourceTree = ""; }; A667A4522962318600B565EE /* AnimationWindow.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AnimationWindow.cpp; sourceTree = ""; }; A667A4532962318600B565EE /* Timeline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Timeline.h; sourceTree = ""; }; A667A4542962318600B565EE /* AnimationKeysActions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimationKeysActions.h; sourceTree = ""; }; A6CA52A626DD1D9400EAD895 /* libEditor.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libEditor.a; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ A6CA52A426DD1D9400EAD895 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ A667A3382962318600B565EE /* o2Editor */ = { isa = PBXGroup; children = ( A667A3392962318600B565EE /* stdafx.h */, A667A33A2962318600B565EE /* Core */, A667A3EE2962318600B565EE /* TreeWindow */, A667A3F32962318600B565EE /* AssetsWindow */, A667A3FC2962318600B565EE /* SceneWindow */, A667A4062962318600B565EE /* stdafx.cpp */, A667A4072962318600B565EE /* PropertiesWindow */, A667A4342962318600B565EE /* GameWindow */, A667A4372962318600B565EE /* LogWindow */, A667A43A2962318600B565EE /* AnimationWindow */, ); name = o2Editor; path = ../../Sources/o2Editor; sourceTree = ""; }; A667A33A2962318600B565EE /* Core */ = { isa = PBXGroup; children = ( A667A33B2962318600B565EE /* EditorApplication.cpp */, A667A33C2962318600B565EE /* UI */, A667A34F2962318600B565EE /* UIRoot.cpp */, A667A3502962318600B565EE /* WindowsSystem */, A667A35B2962318600B565EE /* UIStyle */, A667A3602962318600B565EE /* EditorConfig.cpp */, A667A3612962318600B565EE /* Tools */, A667A3722962318600B565EE /* MenuPanel.cpp */, A667A3732962318600B565EE /* EditorApplication.h */, A667A3742962318600B565EE /* UIRoot.h */, A667A3752962318600B565EE /* Properties */, A667A3C52962318600B565EE /* Actions */, A667A3DA2962318600B565EE /* Dialogs */, A667A3EA2962318600B565EE /* EditorConfig.h */, A667A3EB2962318600B565EE /* MenuPanel.h */, A667A3EC2962318600B565EE /* ToolsPanel.cpp */, A667A3ED2962318600B565EE /* ToolsPanel.h */, ); path = Core; sourceTree = ""; }; A667A33C2962318600B565EE /* UI */ = { isa = PBXGroup; children = ( A667A33D2962318600B565EE /* CurvePreview.h */, A667A33E2962318600B565EE /* ImageSlicesEditorWidget.cpp */, A667A33F2962318600B565EE /* ScrollView.h */, A667A3402962318600B565EE /* FrameScrollView.cpp */, A667A3412962318600B565EE /* ImageSlicesEditorWidget.h */, A667A3422962318600B565EE /* FrameScrollView.h */, A667A3432962318600B565EE /* CurveEditor */, A667A3482962318600B565EE /* SplineEditor */, A667A34B2962318600B565EE /* SpoilerWithHead.cpp */, A667A34C2962318600B565EE /* SpoilerWithHead.h */, A667A34D2962318600B565EE /* CurvePreview.cpp */, A667A34E2962318600B565EE /* ScrollView.cpp */, ); path = UI; sourceTree = ""; }; A667A3432962318600B565EE /* CurveEditor */ = { isa = PBXGroup; children = ( A667A3442962318600B565EE /* CurvesEditor.cpp */, A667A3452962318600B565EE /* CurvesEditor.h */, A667A3462962318600B565EE /* CurveActions.cpp */, A667A3472962318600B565EE /* CurveActions.h */, ); path = CurveEditor; sourceTree = ""; }; A667A3482962318600B565EE /* SplineEditor */ = { isa = PBXGroup; children = ( A667A3492962318600B565EE /* SplineEditor.h */, A667A34A2962318600B565EE /* SplineEditor.cpp */, ); path = SplineEditor; sourceTree = ""; }; A667A3502962318600B565EE /* WindowsSystem */ = { isa = PBXGroup; children = ( A667A3512962318600B565EE /* DockableWindow.cpp */, A667A3522962318600B565EE /* WindowsLayout.cpp */, A667A3532962318600B565EE /* WindowsManager.h */, A667A3542962318600B565EE /* WindowsManager.cpp */, A667A3552962318600B565EE /* IEditorWindow.h */, A667A3562962318600B565EE /* DockWindowPlace.cpp */, A667A3572962318600B565EE /* WindowsLayout.h */, A667A3582962318600B565EE /* DockableWindow.h */, A667A3592962318600B565EE /* IEditorWindow.cpp */, A667A35A2962318600B565EE /* DockWindowPlace.h */, ); path = WindowsSystem; sourceTree = ""; }; A667A35B2962318600B565EE /* UIStyle */ = { isa = PBXGroup; children = ( A667A35C2962318600B565EE /* EditorUIStyle.h */, A667A35D2962318600B565EE /* BasicUIStyle.cpp */, A667A35E2962318600B565EE /* EditorUIStyle.cpp */, A667A35F2962318600B565EE /* BasicUIStyle.h */, ); path = UIStyle; sourceTree = ""; }; A667A3612962318600B565EE /* Tools */ = { isa = PBXGroup; children = ( A667A3622962318600B565EE /* ScaleTool.cpp */, A667A3632962318600B565EE /* SelectionTool.h */, A667A3642962318600B565EE /* MoveTool.cpp */, A667A3652962318600B565EE /* CustomFrameTool.cpp */, A667A3662962318600B565EE /* RotateTool.cpp */, A667A3672962318600B565EE /* ScaleTool.h */, A667A3682962318600B565EE /* FrameTool.cpp */, A667A3692962318600B565EE /* FrameTool.h */, A667A36A2962318600B565EE /* RotateTool.h */, A667A36B2962318600B565EE /* CustomFrameTool.h */, A667A36C2962318600B565EE /* MoveTool.h */, A667A36D2962318600B565EE /* SplineTool.h */, A667A36E2962318600B565EE /* IEditorTool.cpp */, A667A36F2962318600B565EE /* SplineTool.cpp */, A667A3702962318600B565EE /* IEditorTool.h */, A667A3712962318600B565EE /* SelectionTool.cpp */, ); path = Tools; sourceTree = ""; }; A667A3752962318600B565EE /* Properties */ = { isa = PBXGroup; children = ( A667A3762962318600B565EE /* IPropertyField.cpp */, A667A3772962318600B565EE /* Basic */, A667A3A92962318600B565EE /* Objects */, A667A3BC2962318600B565EE /* ObjectViewer.h */, A667A3BD2962318600B565EE /* IObjectPropertiesViewer.h */, A667A3BE2962318600B565EE /* ObjectViewer.cpp */, A667A3BF2962318600B565EE /* Properties.cpp */, A667A3C02962318600B565EE /* IPropertyField.h */, A667A3C12962318600B565EE /* PropertiesContext.h */, A667A3C22962318600B565EE /* IObjectPropertiesViewer.cpp */, A667A3C32962318600B565EE /* PropertiesContext.cpp */, A667A3C42962318600B565EE /* Properties.h */, ); path = Properties; sourceTree = ""; }; A667A3772962318600B565EE /* Basic */ = { isa = PBXGroup; children = ( A667A3782962318600B565EE /* ComponentProperty.cpp */, A667A3792962318600B565EE /* ActorProperty.cpp */, A667A37A2962318600B565EE /* Vector2IntProperty.cpp */, A667A37B2962318600B565EE /* CurveProperty.cpp */, A667A37C2962318600B565EE /* VectorProperty.h */, A667A37D2962318600B565EE /* ScriptValueProperty.cpp */, A667A37E2962318600B565EE /* WStringProperty.h */, A667A37F2962318600B565EE /* CurveProperty.h */, A667A3802962318600B565EE /* FloatProperty.h */, A667A3812962318600B565EE /* IntegerProperty.cpp */, A667A3822962318600B565EE /* BorderIntProperty.h */, A667A3832962318600B565EE /* ScriptValueProperty.h */, A667A3842962318600B565EE /* EnumProperty.h */, A667A3852962318600B565EE /* TagProperty.h */, A667A3862962318600B565EE /* WStringProperty.cpp */, A667A3872962318600B565EE /* RectangleFloatProperty.h */, A667A3882962318600B565EE /* ObjectProperty.cpp */, A667A3892962318600B565EE /* EnumProperty.cpp */, A667A38A2962318600B565EE /* StringProperty.cpp */, A667A38B2962318600B565EE /* ObjectProperty.h */, A667A38C2962318600B565EE /* BorderFloatProperty.h */, A667A38D2962318600B565EE /* BooleanProperty.h */, A667A38E2962318600B565EE /* LayerProperty.h */, A667A38F2962318600B565EE /* RectangleIntProperty.h */, A667A3902962318600B565EE /* LayerProperty.cpp */, A667A3912962318600B565EE /* ComponentProperty.h */, A667A3922962318600B565EE /* BorderIntProperty.cpp */, A667A3932962318600B565EE /* Vector2FloatProperty.cpp */, A667A3942962318600B565EE /* EnumMaskProperty.h */, A667A3952962318600B565EE /* ObjectPtrProperty.cpp */, A667A3962962318600B565EE /* ColorProperty.h */, A667A3972962318600B565EE /* SceneLayersListProperty.cpp */, A667A3982962318600B565EE /* AssetProperty.cpp */, A667A3992962318600B565EE /* RectangleIntProperty.cpp */, A667A39A2962318600B565EE /* ObjectPtrProperty.h */, A667A39B2962318600B565EE /* StringProperty.h */, A667A39C2962318600B565EE /* FloatProperty.cpp */, A667A39D2962318600B565EE /* SceneLayersListProperty.h */, A667A39E2962318600B565EE /* RectangleFloatProperty.cpp */, A667A39F2962318600B565EE /* Vector2IntProperty.h */, A667A3A02962318600B565EE /* ColorProperty.cpp */, A667A3A12962318600B565EE /* TagProperty.cpp */, A667A3A22962318600B565EE /* ActorProperty.h */, A667A3A32962318600B565EE /* Vector2FloatProperty.h */, A667A3A42962318600B565EE /* AssetProperty.h */, A667A3A52962318600B565EE /* BorderFloatProperty.cpp */, A667A3A62962318600B565EE /* VectorProperty.cpp */, A667A3A72962318600B565EE /* IntegerProperty.h */, A667A3A82962318600B565EE /* BooleanProperty.cpp */, ); path = Basic; sourceTree = ""; }; A667A3A92962318600B565EE /* Objects */ = { isa = PBXGroup; children = ( A667A3AA2962318600B565EE /* CameraActorViewer.cpp */, A667A3AB2962318600B565EE /* SpriteViewer.cpp */, A667A3AC2962318600B565EE /* CameraActorViewer.h */, A667A3AD2962318600B565EE /* TextViewer.cpp */, A667A3AE2962318600B565EE /* DefaultObjectPropertiesViewer.cpp */, A667A3AF2962318600B565EE /* Components */, A667A3B42962318600B565EE /* AnimationViewer.cpp */, A667A3B52962318600B565EE /* DefaultObjectPropertiesViewer.h */, A667A3B62962318600B565EE /* AnimationViewer.h */, A667A3B72962318600B565EE /* Assets */, A667A3BA2962318600B565EE /* TextViewer.h */, A667A3BB2962318600B565EE /* SpriteViewer.h */, ); path = Objects; sourceTree = ""; }; A667A3AF2962318600B565EE /* Components */ = { isa = PBXGroup; children = ( A667A3B02962318600B565EE /* AnimationStateViewer.h */, A667A3B12962318600B565EE /* MeshComponentViewer.h */, A667A3B22962318600B565EE /* MeshComponentViewer.cpp */, A667A3B32962318600B565EE /* AnimationStateViewer.cpp */, ); path = Components; sourceTree = ""; }; A667A3B72962318600B565EE /* Assets */ = { isa = PBXGroup; children = ( A667A3B82962318600B565EE /* ImageAssetViewer.h */, A667A3B92962318600B565EE /* ImageAssetViewer.cpp */, ); path = Assets; sourceTree = ""; }; A667A3C52962318600B565EE /* Actions */ = { isa = PBXGroup; children = ( A667A3C62962318600B565EE /* ActionsList.h */, A667A3C72962318600B565EE /* Select.cpp */, A667A3C82962318600B565EE /* Reparent.cpp */, A667A3C92962318600B565EE /* PropertyChange.cpp */, A667A3CA2962318600B565EE /* Reparent.h */, A667A3CB2962318600B565EE /* Enable.h */, A667A3CC2962318600B565EE /* Lock.h */, A667A3CD2962318600B565EE /* Delete.h */, A667A3CE2962318600B565EE /* Delete.cpp */, A667A3CF2962318600B565EE /* Transform.cpp */, A667A3D02962318600B565EE /* ActionsList.cpp */, A667A3D12962318600B565EE /* Create.cpp */, A667A3D22962318600B565EE /* Transform.h */, A667A3D32962318600B565EE /* PropertyChange.h */, A667A3D42962318600B565EE /* IAction.h */, A667A3D52962318600B565EE /* Enable.cpp */, A667A3D62962318600B565EE /* Lock.cpp */, A667A3D72962318600B565EE /* Create.h */, A667A3D82962318600B565EE /* IAction.cpp */, A667A3D92962318600B565EE /* Select.h */, ); path = Actions; sourceTree = ""; }; A667A3DA2962318600B565EE /* Dialogs */ = { isa = PBXGroup; children = ( A667A3DB2962318600B565EE /* CurveEditorDlg.cpp */, A667A3DC2962318600B565EE /* EditNameDlg.h */, A667A3DD2962318600B565EE /* KeyEditDlg.cpp */, A667A3DE2962318600B565EE /* EditNameDlg.cpp */, A667A3DF2962318600B565EE /* System */, A667A3E62962318600B565EE /* KeyEditDlg.h */, A667A3E72962318600B565EE /* ColorPickerDlg.h */, A667A3E82962318600B565EE /* ColorPickerDlg.cpp */, A667A3E92962318600B565EE /* CurveEditorDlg.h */, ); path = Dialogs; sourceTree = ""; }; A667A3DF2962318600B565EE /* System */ = { isa = PBXGroup; children = ( A667A3E02962318600B565EE /* OpenSaveDialog.h */, A667A3E12962318600B565EE /* Mac */, A667A3E32962318600B565EE /* New Group */, A667A3E42962318600B565EE /* Windows */, ); path = System; sourceTree = ""; }; A667A3E12962318600B565EE /* Mac */ = { isa = PBXGroup; children = ( A667A3E22962318600B565EE /* OpenSaveDialog.cpp */, ); path = Mac; sourceTree = ""; }; A667A3E32962318600B565EE /* New Group */ = { isa = PBXGroup; children = ( ); path = "New Group"; sourceTree = ""; }; A667A3E42962318600B565EE /* Windows */ = { isa = PBXGroup; children = ( A667A3E52962318600B565EE /* OpenSaveDialog.cpp */, ); path = Windows; sourceTree = ""; }; A667A3EE2962318600B565EE /* TreeWindow */ = { isa = PBXGroup; children = ( A667A3EF2962318600B565EE /* SceneTree.h */, A667A3F02962318600B565EE /* TreeWindow.cpp */, A667A3F12962318600B565EE /* TreeWindow.h */, A667A3F22962318600B565EE /* SceneTree.cpp */, ); path = TreeWindow; sourceTree = ""; }; A667A3F32962318600B565EE /* AssetsWindow */ = { isa = PBXGroup; children = ( A667A3F42962318600B565EE /* FoldersTree.cpp */, A667A3F52962318600B565EE /* AssetsWindow.cpp */, A667A3F62962318600B565EE /* AssetsIconsScroll.cpp */, A667A3F72962318600B565EE /* AssetsWindow.h */, A667A3F82962318600B565EE /* AssetIcon.cpp */, A667A3F92962318600B565EE /* AssetsIconsScroll.h */, A667A3FA2962318600B565EE /* FoldersTree.h */, A667A3FB2962318600B565EE /* AssetIcon.h */, ); path = AssetsWindow; sourceTree = ""; }; A667A3FC2962318600B565EE /* SceneWindow */ = { isa = PBXGroup; children = ( A667A3FD2962318600B565EE /* SceneEditScreen.h */, A667A3FE2962318600B565EE /* SceneDragHandle.h */, A667A3FF2962318600B565EE /* SceneEditScreen.cpp */, A667A4002962318600B565EE /* SceneEditorLayer.h */, A667A4012962318600B565EE /* SceneWindow.h */, A667A4022962318600B565EE /* SceneWindow.cpp */, A667A4032962318600B565EE /* LayersPopup.cpp */, A667A4042962318600B565EE /* SceneDragHandle.cpp */, A667A4052962318600B565EE /* LayersPopup.h */, ); path = SceneWindow; sourceTree = ""; }; A667A4072962318600B565EE /* PropertiesWindow */ = { isa = PBXGroup; children = ( A667A4082962318600B565EE /* PropertiesWindow.h */, A667A4092962318600B565EE /* AssetPropertiesViewer.h */, A667A40A2962318600B565EE /* AssetPropertiesViewer.cpp */, A667A40B2962318600B565EE /* ActorsViewer */, A667A4202962318600B565EE /* IPropertiesViewer.h */, A667A4212962318600B565EE /* IPropertiesViewer.cpp */, A667A4222962318600B565EE /* DefaultPropertiesViewer.h */, A667A4232962318600B565EE /* DefaultPropertiesViewer.cpp */, A667A4242962318600B565EE /* PropertiesWindow.cpp */, A667A4252962318600B565EE /* WidgetLayerViewer */, ); path = PropertiesWindow; sourceTree = ""; }; A667A40B2962318600B565EE /* ActorsViewer */ = { isa = PBXGroup; children = ( A667A40C2962318600B565EE /* DefaultActorComponentViewer.cpp */, A667A40D2962318600B565EE /* DefaultActorTransformViewer.h */, A667A40E2962318600B565EE /* IActorPropertiesViewer.h */, A667A40F2962318600B565EE /* ActorViewer.cpp */, A667A4102962318600B565EE /* IActorTransformViewer.h */, A667A4112962318600B565EE /* AddComponentPanel.cpp */, A667A4122962318600B565EE /* IActorComponentViewer.cpp */, A667A4132962318600B565EE /* DefaultActorHeaderViewer.h */, A667A4142962318600B565EE /* IActorPropertiesViewer.cpp */, A667A4152962318600B565EE /* IActorHeaderViewer.cpp */, A667A4162962318600B565EE /* ActorViewer.h */, A667A4172962318600B565EE /* DefaultActorHeaderViewer.cpp */, A667A4182962318600B565EE /* IActorTransformViewer.cpp */, A667A4192962318600B565EE /* DefaultActorComponentViewer.h */, A667A41A2962318600B565EE /* DefaultActorPropertiesViewer.h */, A667A41B2962318600B565EE /* IActorHeaderViewer.h */, A667A41C2962318600B565EE /* IActorComponentViewer.h */, A667A41D2962318600B565EE /* DefaultActorPropertiesViewer.cpp */, A667A41E2962318600B565EE /* AddComponentPanel.h */, A667A41F2962318600B565EE /* DefaultActorTransformViewer.cpp */, ); path = ActorsViewer; sourceTree = ""; }; A667A4252962318600B565EE /* WidgetLayerViewer */ = { isa = PBXGroup; children = ( A667A4262962318600B565EE /* DefaultWidgetLayerPropertiesViewer.h */, A667A4272962318600B565EE /* IWidgetLayerLayoutViewer.cpp */, A667A4282962318600B565EE /* IWidgetLayerHeadViewer.h */, A667A4292962318600B565EE /* DefaultWidgetLayerLayoutViewer.h */, A667A42A2962318600B565EE /* WidgetLayerViewer.cpp */, A667A42B2962318600B565EE /* IWidgetLayerLayoutViewer.h */, A667A42C2962318600B565EE /* IWidgetLayerPropertiesViewer.cpp */, A667A42D2962318600B565EE /* WidgetLayerViewer.h */, A667A42E2962318600B565EE /* IWidgetLayerHeadViewer.cpp */, A667A42F2962318600B565EE /* IWidgetLayerPropertiesViewer.h */, A667A4302962318600B565EE /* DefaultWidgetLayerLayoutViewer.cpp */, A667A4312962318600B565EE /* DefaultWidgetLayerHeadViewer.cpp */, A667A4322962318600B565EE /* DefaultWidgetLayerHeadViewer.h */, A667A4332962318600B565EE /* DefaultWidgetLayerPropertiesViewer.cpp */, ); path = WidgetLayerViewer; sourceTree = ""; }; A667A4342962318600B565EE /* GameWindow */ = { isa = PBXGroup; children = ( A667A4352962318600B565EE /* GameWindow.cpp */, A667A4362962318600B565EE /* GameWindow.h */, ); path = GameWindow; sourceTree = ""; }; A667A4372962318600B565EE /* LogWindow */ = { isa = PBXGroup; children = ( A667A4382962318600B565EE /* LogWindow.h */, A667A4392962318600B565EE /* LogWindow.cpp */, ); path = LogWindow; sourceTree = ""; }; A667A43A2962318600B565EE /* AnimationWindow */ = { isa = PBXGroup; children = ( A667A43B2962318600B565EE /* KeyHandlesSheet.h */, A667A43C2962318600B565EE /* AnimationKeysActions.cpp */, A667A43D2962318600B565EE /* KeyHandlesSheet.cpp */, A667A43E2962318600B565EE /* Tree.h */, A667A43F2962318600B565EE /* CurvesSheet.h */, A667A4402962318600B565EE /* PropertiesListDlg.cpp */, A667A4412962318600B565EE /* PropertiesListDlg.h */, A667A4422962318600B565EE /* Timeline.cpp */, A667A4432962318600B565EE /* Tree.cpp */, A667A4442962318600B565EE /* AnimationWindow.h */, A667A4452962318600B565EE /* CurvesSheet.cpp */, A667A4462962318600B565EE /* TrackControls */, A667A4522962318600B565EE /* AnimationWindow.cpp */, A667A4532962318600B565EE /* Timeline.h */, A667A4542962318600B565EE /* AnimationKeysActions.h */, ); path = AnimationWindow; sourceTree = ""; }; A667A4462962318600B565EE /* TrackControls */ = { isa = PBXGroup; children = ( A667A4472962318600B565EE /* MapKeyFramesTrackControl.h */, A667A4482962318600B565EE /* KeyFramesTrackControl.cpp */, A667A4492962318600B565EE /* AnimationTrackWrapper.h */, A667A44A2962318600B565EE /* MapKeyFramesTrackControl.cpp */, A667A44B2962318600B565EE /* AnimationKeyDragHandle.cpp */, A667A44C2962318600B565EE /* Vec2KeyFramesTrackControl.cpp */, A667A44D2962318600B565EE /* ITrackControl.h */, A667A44E2962318600B565EE /* ITrackControl.cpp */, A667A44F2962318600B565EE /* KeyFramesTrackControl.h */, A667A4502962318600B565EE /* Vec2KeyFramesTrackControl.h */, A667A4512962318600B565EE /* AnimationKeyDragHandle.h */, ); path = TrackControls; sourceTree = ""; }; A6CA529D26DD1D9400EAD895 = { isa = PBXGroup; children = ( A667A3382962318600B565EE /* o2Editor */, A6CA52A726DD1D9400EAD895 /* Products */, ); sourceTree = ""; }; A6CA52A726DD1D9400EAD895 /* Products */ = { isa = PBXGroup; children = ( A6CA52A626DD1D9400EAD895 /* libEditor.a */, ); name = Products; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ A6CA52A226DD1D9400EAD895 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( A667A4F82962318700B565EE /* SceneTree.h in Headers */, A667A4F12962318700B565EE /* ColorPickerDlg.h in Headers */, A667A4642962318600B565EE /* SpoilerWithHead.h in Headers */, A667A4F32962318700B565EE /* CurveEditorDlg.h in Headers */, A667A53C2962318700B565EE /* KeyHandlesSheet.h in Headers */, A667A4E22962318700B565EE /* PropertyChange.h in Headers */, A667A5502962318700B565EE /* Vec2KeyFramesTrackControl.h in Headers */, A667A4B22962318700B565EE /* Vector2IntProperty.h in Headers */, A667A45B2962318600B565EE /* ImageSlicesEditorWidget.h in Headers */, A667A4BA2962318700B565EE /* IntegerProperty.h in Headers */, A667A4C62962318700B565EE /* DefaultObjectPropertiesViewer.h in Headers */, A667A4E82962318700B565EE /* Select.h in Headers */, A667A4EA2962318700B565EE /* EditNameDlg.h in Headers */, A667A49A2962318700B565EE /* RectangleFloatProperty.h in Headers */, A667A4F72962318700B565EE /* ToolsPanel.h in Headers */, A667A4A42962318700B565EE /* ComponentProperty.h in Headers */, A667A4962962318700B565EE /* ScriptValueProperty.h in Headers */, A667A52C2962318700B565EE /* IWidgetLayerHeadViewer.h in Headers */, A667A4552962318600B565EE /* stdafx.h in Headers */, A667A4D92962318700B565EE /* Reparent.h in Headers */, A667A50E2962318700B565EE /* PropertiesWindow.h in Headers */, A667A50C2962318700B565EE /* LayersPopup.h in Headers */, A667A4A92962318700B565EE /* ColorProperty.h in Headers */, A667A4592962318600B565EE /* ScrollView.h in Headers */, A667A45E2962318600B565EE /* CurvesEditor.h in Headers */, A667A4C22962318700B565EE /* MeshComponentViewer.h in Headers */, A667A4752962318600B565EE /* BasicUIStyle.h in Headers */, A667A4782962318600B565EE /* SelectionTool.h in Headers */, A667A4D42962318700B565EE /* Properties.h in Headers */, A667A4E12962318700B565EE /* Transform.h in Headers */, A667A4DB2962318700B565EE /* Lock.h in Headers */, A667A5212962318700B565EE /* IActorComponentViewer.h in Headers */, A667A5032962318700B565EE /* AssetIcon.h in Headers */, A667A4BE2962318700B565EE /* CameraActorViewer.h in Headers */, A667A4ED2962318700B565EE /* OpenSaveDialog.h in Headers */, A667A46C2962318600B565EE /* IEditorWindow.h in Headers */, A667A52D2962318700B565EE /* DefaultWidgetLayerLayoutViewer.h in Headers */, A667A4E32962318700B565EE /* IAction.h in Headers */, A667A4B62962318700B565EE /* Vector2FloatProperty.h in Headers */, A667A4DA2962318700B565EE /* Enable.h in Headers */, A667A4572962318600B565EE /* CurvePreview.h in Headers */, A667A54D2962318700B565EE /* ITrackControl.h in Headers */, A667A48F2962318700B565EE /* VectorProperty.h in Headers */, A667A49F2962318700B565EE /* BorderFloatProperty.h in Headers */, A667A51E2962318700B565EE /* DefaultActorComponentViewer.h in Headers */, A667A46F2962318600B565EE /* DockableWindow.h in Headers */, A667A4982962318700B565EE /* TagProperty.h in Headers */, A667A51F2962318700B565EE /* DefaultActorPropertiesViewer.h in Headers */, A667A4A72962318700B565EE /* EnumMaskProperty.h in Headers */, A667A50F2962318700B565EE /* AssetPropertiesViewer.h in Headers */, A667A5052962318700B565EE /* SceneDragHandle.h in Headers */, A667A4DC2962318700B565EE /* Delete.h in Headers */, A667A4B72962318700B565EE /* AssetProperty.h in Headers */, A667A46A2962318600B565EE /* WindowsManager.h in Headers */, A667A5492962318700B565EE /* AnimationTrackWrapper.h in Headers */, A667A4AE2962318700B565EE /* StringProperty.h in Headers */, A667A47F2962318700B565EE /* RotateTool.h in Headers */, A667A4D02962318700B565EE /* IPropertyField.h in Headers */, A667A4C82962318700B565EE /* ImageAssetViewer.h in Headers */, A667A51B2962318700B565EE /* ActorViewer.h in Headers */, A667A4892962318700B565EE /* UIRoot.h in Headers */, A667A5022962318700B565EE /* FoldersTree.h in Headers */, A667A4912962318700B565EE /* WStringProperty.h in Headers */, A667A4722962318600B565EE /* EditorUIStyle.h in Headers */, A667A4B02962318700B565EE /* SceneLayersListProperty.h in Headers */, A667A4CC2962318700B565EE /* ObjectViewer.h in Headers */, A667A5082962318700B565EE /* SceneWindow.h in Headers */, A667A4802962318700B565EE /* CustomFrameTool.h in Headers */, A667A5422962318700B565EE /* PropertiesListDlg.h in Headers */, A667A5402962318700B565EE /* CurvesSheet.h in Headers */, A667A5332962318700B565EE /* IWidgetLayerPropertiesViewer.h in Headers */, A667A4F42962318700B565EE /* EditorConfig.h in Headers */, A667A4602962318600B565EE /* CurveActions.h in Headers */, A667A4D12962318700B565EE /* PropertiesContext.h in Headers */, A667A4932962318700B565EE /* FloatProperty.h in Headers */, A667A4A12962318700B565EE /* LayerProperty.h in Headers */, A667A5122962318700B565EE /* DefaultActorTransformViewer.h in Headers */, A667A4AD2962318700B565EE /* ObjectPtrProperty.h in Headers */, A667A49E2962318700B565EE /* ObjectProperty.h in Headers */, A667A52F2962318700B565EE /* IWidgetLayerLayoutViewer.h in Headers */, A667A5392962318700B565EE /* GameWindow.h in Headers */, A667A53A2962318700B565EE /* LogWindow.h in Headers */, A667A4812962318700B565EE /* MoveTool.h in Headers */, A667A5012962318700B565EE /* AssetsIconsScroll.h in Headers */, A667A5452962318700B565EE /* AnimationWindow.h in Headers */, A667A4922962318700B565EE /* CurveProperty.h in Headers */, A667A5512962318700B565EE /* AnimationKeyDragHandle.h in Headers */, A667A5532962318700B565EE /* Timeline.h in Headers */, A667A5312962318700B565EE /* WidgetLayerViewer.h in Headers */, A667A47C2962318700B565EE /* ScaleTool.h in Headers */, A667A54F2962318700B565EE /* KeyFramesTrackControl.h in Headers */, A667A4B52962318700B565EE /* ActorProperty.h in Headers */, A667A4952962318700B565EE /* BorderIntProperty.h in Headers */, A667A5542962318700B565EE /* AnimationKeysActions.h in Headers */, A667A4CD2962318700B565EE /* IObjectPropertiesViewer.h in Headers */, A667A5152962318700B565EE /* IActorTransformViewer.h in Headers */, A667A4852962318700B565EE /* IEditorTool.h in Headers */, A667A4612962318600B565EE /* SplineEditor.h in Headers */, A667A46E2962318600B565EE /* WindowsLayout.h in Headers */, A667A4FF2962318700B565EE /* AssetsWindow.h in Headers */, A667A4CA2962318700B565EE /* TextViewer.h in Headers */, A667A4F52962318700B565EE /* MenuPanel.h in Headers */, A667A4822962318700B565EE /* SplineTool.h in Headers */, A667A5202962318700B565EE /* IActorHeaderViewer.h in Headers */, A667A4A22962318700B565EE /* RectangleIntProperty.h in Headers */, A667A4972962318700B565EE /* EnumProperty.h in Headers */, A667A4C72962318700B565EE /* AnimationViewer.h in Headers */, A667A45C2962318600B565EE /* FrameScrollView.h in Headers */, A667A4A02962318700B565EE /* BooleanProperty.h in Headers */, A667A4E62962318700B565EE /* Create.h in Headers */, A667A5472962318700B565EE /* MapKeyFramesTrackControl.h in Headers */, A667A53F2962318700B565EE /* Tree.h in Headers */, A667A4D52962318700B565EE /* ActionsList.h in Headers */, A667A4882962318700B565EE /* EditorApplication.h in Headers */, A667A5182962318700B565EE /* DefaultActorHeaderViewer.h in Headers */, A667A4F02962318700B565EE /* KeyEditDlg.h in Headers */, A667A47E2962318700B565EE /* FrameTool.h in Headers */, A667A4712962318600B565EE /* DockWindowPlace.h in Headers */, A667A4C12962318700B565EE /* AnimationStateViewer.h in Headers */, A667A5362962318700B565EE /* DefaultWidgetLayerHeadViewer.h in Headers */, A667A52A2962318700B565EE /* DefaultWidgetLayerPropertiesViewer.h in Headers */, A667A5272962318700B565EE /* DefaultPropertiesViewer.h in Headers */, A667A5252962318700B565EE /* IPropertiesViewer.h in Headers */, A667A5232962318700B565EE /* AddComponentPanel.h in Headers */, A667A5132962318700B565EE /* IActorPropertiesViewer.h in Headers */, A667A4FA2962318700B565EE /* TreeWindow.h in Headers */, A667A4CB2962318700B565EE /* SpriteViewer.h in Headers */, A667A5072962318700B565EE /* SceneEditorLayer.h in Headers */, A667A5042962318700B565EE /* SceneEditScreen.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ A6CA52A526DD1D9400EAD895 /* Editor */ = { isa = PBXNativeTarget; buildConfigurationList = A6CA52B126DD1D9400EAD895 /* Build configuration list for PBXNativeTarget "Editor" */; buildPhases = ( A6CA52A226DD1D9400EAD895 /* Headers */, A6CA52A326DD1D9400EAD895 /* Sources */, A6CA52A426DD1D9400EAD895 /* Frameworks */, ); buildRules = ( ); dependencies = ( ); name = Editor; productName = Editor; productReference = A6CA52A626DD1D9400EAD895 /* libEditor.a */; productType = "com.apple.product-type.library.static"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ A6CA529E26DD1D9400EAD895 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1250; TargetAttributes = { A6CA52A526DD1D9400EAD895 = { CreatedOnToolsVersion = 12.5.1; }; }; }; buildConfigurationList = A6CA52A126DD1D9400EAD895 /* Build configuration list for PBXProject "Editor" */; compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = A6CA529D26DD1D9400EAD895; productRefGroup = A6CA52A726DD1D9400EAD895 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( A6CA52A526DD1D9400EAD895 /* Editor */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ A6CA52A326DD1D9400EAD895 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( A667A50A2962318700B565EE /* LayersPopup.cpp in Sources */, A667A5172962318700B565EE /* IActorComponentViewer.cpp in Sources */, A667A4BD2962318700B565EE /* SpriteViewer.cpp in Sources */, A667A48C2962318700B565EE /* ActorProperty.cpp in Sources */, A667A53B2962318700B565EE /* LogWindow.cpp in Sources */, A667A4B12962318700B565EE /* RectangleFloatProperty.cpp in Sources */, A667A52B2962318700B565EE /* IWidgetLayerLayoutViewer.cpp in Sources */, A667A4E92962318700B565EE /* CurveEditorDlg.cpp in Sources */, A667A5262962318700B565EE /* IPropertiesViewer.cpp in Sources */, A667A5442962318700B565EE /* Tree.cpp in Sources */, A667A4652962318600B565EE /* CurvePreview.cpp in Sources */, A667A5102962318700B565EE /* AssetPropertiesViewer.cpp in Sources */, A667A4FD2962318700B565EE /* AssetsWindow.cpp in Sources */, A667A4D22962318700B565EE /* IObjectPropertiesViewer.cpp in Sources */, A667A4BF2962318700B565EE /* TextViewer.cpp in Sources */, A667A4DD2962318700B565EE /* Delete.cpp in Sources */, A667A4662962318600B565EE /* ScrollView.cpp in Sources */, A667A4992962318700B565EE /* WStringProperty.cpp in Sources */, A667A5432962318700B565EE /* Timeline.cpp in Sources */, A667A51D2962318700B565EE /* IActorTransformViewer.cpp in Sources */, A667A54C2962318700B565EE /* Vec2KeyFramesTrackControl.cpp in Sources */, A667A4FB2962318700B565EE /* SceneTree.cpp in Sources */, A667A4BB2962318700B565EE /* BooleanProperty.cpp in Sources */, A667A5382962318700B565EE /* GameWindow.cpp in Sources */, A667A4A52962318700B565EE /* BorderIntProperty.cpp in Sources */, A667A4F62962318700B565EE /* ToolsPanel.cpp in Sources */, A667A4842962318700B565EE /* SplineTool.cpp in Sources */, A667A4732962318600B565EE /* BasicUIStyle.cpp in Sources */, A667A4AB2962318700B565EE /* AssetProperty.cpp in Sources */, A667A48D2962318700B565EE /* Vector2IntProperty.cpp in Sources */, A667A4A62962318700B565EE /* Vector2FloatProperty.cpp in Sources */, A667A45D2962318600B565EE /* CurvesEditor.cpp in Sources */, A667A51A2962318700B565EE /* IActorHeaderViewer.cpp in Sources */, A667A5412962318700B565EE /* PropertiesListDlg.cpp in Sources */, A667A5222962318700B565EE /* DefaultActorPropertiesViewer.cpp in Sources */, A667A5092962318700B565EE /* SceneWindow.cpp in Sources */, A667A4C02962318700B565EE /* DefaultObjectPropertiesViewer.cpp in Sources */, A667A4E42962318700B565EE /* Enable.cpp in Sources */, A667A53D2962318700B565EE /* AnimationKeysActions.cpp in Sources */, A667A47D2962318700B565EE /* FrameTool.cpp in Sources */, A667A49D2962318700B565EE /* StringProperty.cpp in Sources */, A667A4772962318600B565EE /* ScaleTool.cpp in Sources */, A667A5002962318700B565EE /* AssetIcon.cpp in Sources */, A667A5372962318700B565EE /* DefaultWidgetLayerPropertiesViewer.cpp in Sources */, A667A4702962318600B565EE /* IEditorWindow.cpp in Sources */, A667A5192962318700B565EE /* IActorPropertiesViewer.cpp in Sources */, A667A49B2962318700B565EE /* ObjectProperty.cpp in Sources */, A667A4EB2962318700B565EE /* KeyEditDlg.cpp in Sources */, A667A4692962318600B565EE /* WindowsLayout.cpp in Sources */, A667A5322962318700B565EE /* IWidgetLayerHeadViewer.cpp in Sources */, A667A46D2962318600B565EE /* DockWindowPlace.cpp in Sources */, A667A4DF2962318700B565EE /* ActionsList.cpp in Sources */, A667A5482962318700B565EE /* KeyFramesTrackControl.cpp in Sources */, A667A5302962318700B565EE /* IWidgetLayerPropertiesViewer.cpp in Sources */, A667A4D32962318700B565EE /* PropertiesContext.cpp in Sources */, A667A48E2962318700B565EE /* CurveProperty.cpp in Sources */, A667A4D72962318700B565EE /* Reparent.cpp in Sources */, A667A4902962318700B565EE /* ScriptValueProperty.cpp in Sources */, A667A4862962318700B565EE /* SelectionTool.cpp in Sources */, A667A54B2962318700B565EE /* AnimationKeyDragHandle.cpp in Sources */, A667A4632962318600B565EE /* SpoilerWithHead.cpp in Sources */, A667A4EC2962318700B565EE /* EditNameDlg.cpp in Sources */, A667A4EE2962318700B565EE /* OpenSaveDialog.cpp in Sources */, A667A4682962318600B565EE /* DockableWindow.cpp in Sources */, A667A54A2962318700B565EE /* MapKeyFramesTrackControl.cpp in Sources */, A667A4942962318700B565EE /* IntegerProperty.cpp in Sources */, A667A4C32962318700B565EE /* MeshComponentViewer.cpp in Sources */, A667A51C2962318700B565EE /* DefaultActorHeaderViewer.cpp in Sources */, A667A5292962318700B565EE /* PropertiesWindow.cpp in Sources */, A667A5142962318700B565EE /* ActorViewer.cpp in Sources */, A667A52E2962318700B565EE /* WidgetLayerViewer.cpp in Sources */, A667A5242962318700B565EE /* DefaultActorTransformViewer.cpp in Sources */, A667A4792962318700B565EE /* MoveTool.cpp in Sources */, A667A46B2962318600B565EE /* WindowsManager.cpp in Sources */, A667A5162962318700B565EE /* AddComponentPanel.cpp in Sources */, A667A4A32962318700B565EE /* LayerProperty.cpp in Sources */, A667A4562962318600B565EE /* EditorApplication.cpp in Sources */, A667A4582962318600B565EE /* ImageSlicesEditorWidget.cpp in Sources */, A667A45F2962318600B565EE /* CurveActions.cpp in Sources */, A667A54E2962318700B565EE /* ITrackControl.cpp in Sources */, A667A4B92962318700B565EE /* VectorProperty.cpp in Sources */, A667A4E72962318700B565EE /* IAction.cpp in Sources */, A667A5352962318700B565EE /* DefaultWidgetLayerHeadViewer.cpp in Sources */, A667A4AC2962318700B565EE /* RectangleIntProperty.cpp in Sources */, A667A4CF2962318700B565EE /* Properties.cpp in Sources */, A667A5112962318700B565EE /* DefaultActorComponentViewer.cpp in Sources */, A667A5282962318700B565EE /* DefaultPropertiesViewer.cpp in Sources */, A667A4C42962318700B565EE /* AnimationStateViewer.cpp in Sources */, A667A4D62962318700B565EE /* Select.cpp in Sources */, A667A4EF2962318700B565EE /* OpenSaveDialog.cpp in Sources */, A667A4672962318600B565EE /* UIRoot.cpp in Sources */, A667A4762962318600B565EE /* EditorConfig.cpp in Sources */, A667A4CE2962318700B565EE /* ObjectViewer.cpp in Sources */, A667A50B2962318700B565EE /* SceneDragHandle.cpp in Sources */, A667A45A2962318600B565EE /* FrameScrollView.cpp in Sources */, A667A4FC2962318700B565EE /* FoldersTree.cpp in Sources */, A667A5462962318700B565EE /* CurvesSheet.cpp in Sources */, A667A4A82962318700B565EE /* ObjectPtrProperty.cpp in Sources */, A667A4AA2962318700B565EE /* SceneLayersListProperty.cpp in Sources */, A667A48A2962318700B565EE /* IPropertyField.cpp in Sources */, A667A4E52962318700B565EE /* Lock.cpp in Sources */, A667A5342962318700B565EE /* DefaultWidgetLayerLayoutViewer.cpp in Sources */, A667A4B32962318700B565EE /* ColorProperty.cpp in Sources */, A667A4F92962318700B565EE /* TreeWindow.cpp in Sources */, A667A4C92962318700B565EE /* ImageAssetViewer.cpp in Sources */, A667A49C2962318700B565EE /* EnumProperty.cpp in Sources */, A667A4742962318600B565EE /* EditorUIStyle.cpp in Sources */, A667A4B82962318700B565EE /* BorderFloatProperty.cpp in Sources */, A667A5522962318700B565EE /* AnimationWindow.cpp in Sources */, A667A4B42962318700B565EE /* TagProperty.cpp in Sources */, A667A4E02962318700B565EE /* Create.cpp in Sources */, A667A50D2962318700B565EE /* stdafx.cpp in Sources */, A667A4AF2962318700B565EE /* FloatProperty.cpp in Sources */, A667A4BC2962318700B565EE /* CameraActorViewer.cpp in Sources */, A667A48B2962318700B565EE /* ComponentProperty.cpp in Sources */, A667A4F22962318700B565EE /* ColorPickerDlg.cpp in Sources */, A667A47A2962318700B565EE /* CustomFrameTool.cpp in Sources */, A667A47B2962318700B565EE /* RotateTool.cpp in Sources */, A667A5062962318700B565EE /* SceneEditScreen.cpp in Sources */, A667A53E2962318700B565EE /* KeyHandlesSheet.cpp in Sources */, A667A4DE2962318700B565EE /* Transform.cpp in Sources */, A667A4D82962318700B565EE /* PropertyChange.cpp in Sources */, A667A4832962318700B565EE /* IEditorTool.cpp in Sources */, A667A4FE2962318700B565EE /* AssetsIconsScroll.cpp in Sources */, A667A4872962318700B565EE /* MenuPanel.cpp in Sources */, A667A4622962318600B565EE /* SplineEditor.cpp in Sources */, A667A4C52962318700B565EE /* AnimationViewer.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ A6CA52AF26DD1D9400EAD895 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( PLATFORM_MAC, "$(inherited)", SCRIPTING_BACKEND_JERRYSCRIPT, ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 11.3; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-fdeclspec", ); SDKROOT = macosx; SYSTEM_HEADER_SEARCH_PATHS = ( ../../Sources, ../.., ../../3rdPartyLibs/FreeType/include, ../../3rdPartyLibs, ../../3rdPartyLibs/rapidjson/include, ); USER_HEADER_SEARCH_PATHS = ( ../../Sources, ../.., ../../3rdPartyLibs/FreeType/include, ../../3rdPartyLibs, ../../3rdPartyLibs/rapidjson/include, ../../Sources, ); USE_HEADERMAP = YES; WARNING_CFLAGS = "-Wno-undefined-var-template"; }; name = Debug; }; A6CA52B026DD1D9400EAD895 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( PLATFORM_MAC, "$(inherited)", SCRIPTING_BACKEND_JERRYSCRIPT, ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 11.3; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-fdeclspec", ); SDKROOT = macosx; SYSTEM_HEADER_SEARCH_PATHS = ( ../../Sources, ../.., ../../3rdPartyLibs/FreeType/include, ../../3rdPartyLibs, ../../3rdPartyLibs/rapidjson/include, ); USER_HEADER_SEARCH_PATHS = ( ../../Sources, ../.., ../../3rdPartyLibs/FreeType/include, ../../3rdPartyLibs, ../../3rdPartyLibs/rapidjson/include, ../../Sources, ); USE_HEADERMAP = YES; WARNING_CFLAGS = "-Wno-undefined-var-template"; }; name = Release; }; A6CA52B226DD1D9400EAD895 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = K48QWFFT79; EXECUTABLE_PREFIX = lib; GCC_ENABLE_CPP_EXCEPTIONS = YES; GCC_ENABLE_CPP_RTTI = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SYSTEM_HEADER_SEARCH_PATHS = ( /Users/playrix/PetStory/o2/Framework/Sources, /Users/playrix/PetStory/o2/Framework, /Users/playrix/PetStory/o2/Framework/3rdPartyLibs/FreeType/include, /Users/playrix/PetStory/o2/Framework/3rdPartyLibs, /Users/playrix/PetStory/o2/Framework/3rdPartyLibs/rapidjson/include, ); }; name = Debug; }; A6CA52B326DD1D9400EAD895 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = K48QWFFT79; EXECUTABLE_PREFIX = lib; GCC_ENABLE_CPP_EXCEPTIONS = YES; GCC_ENABLE_CPP_RTTI = YES; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SYSTEM_HEADER_SEARCH_PATHS = ( /Users/playrix/PetStory/o2/Framework/Sources, /Users/playrix/PetStory/o2/Framework, /Users/playrix/PetStory/o2/Framework/3rdPartyLibs/FreeType/include, /Users/playrix/PetStory/o2/Framework/3rdPartyLibs, /Users/playrix/PetStory/o2/Framework/3rdPartyLibs/rapidjson/include, ); }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ A6CA52A126DD1D9400EAD895 /* Build configuration list for PBXProject "Editor" */ = { isa = XCConfigurationList; buildConfigurations = ( A6CA52AF26DD1D9400EAD895 /* Debug */, A6CA52B026DD1D9400EAD895 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; A6CA52B126DD1D9400EAD895 /* Build configuration list for PBXNativeTarget "Editor" */ = { isa = XCConfigurationList; buildConfigurations = ( A6CA52B226DD1D9400EAD895 /* Debug */, A6CA52B326DD1D9400EAD895 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = A6CA529E26DD1D9400EAD895 /* Project object */; } ================================================ FILE: Editor/Platforms/Mac/Editor.xcodeproj/xcuserdata/playrix.xcuserdatad/xcschemes/xcschememanagement.plist ================================================ SchemeUserState Editor.xcscheme_^#shared#^_ orderHint 4 ================================================ FILE: Editor/Platforms/Windows/Editor.vcxproj ================================================ Debug Win32 FastDebug Win32 FastDebug x64 Release Win32 Debug x64 Release x64 {B8629B91-422C-4541-9E06-6013F5C99E66} Win32Proj o2Test 10.0 EditorLib StaticLibrary true v143 NotSet StaticLibrary true v143 NotSet StaticLibrary false v143 true NotSet StaticLibrary true v143 NotSet false StaticLibrary true v143 NotSet false StaticLibrary false v143 true NotSet false false $(SolutionDir)Temp\$(Configuration)\Libs\ $(SolutionDir)Temp\$(Configuration)\EditorLib\ Editor true .lib false $(SolutionDir)Temp\$(Configuration)\Libs\ $(SolutionDir)Temp\$(Configuration)\EditorLib\ Editor true .lib true $(SolutionDir)Temp\$(Configuration)\Libs\ $(SolutionDir)Temp\$(Configuration)\EditorLib\ true Editor .lib true $(SolutionDir)Temp\$(Configuration)\Libs\ $(SolutionDir)Temp\$(Configuration)\EditorLib\ true Editor .lib false $(SolutionDir)Temp\$(Configuration)\Libs\ $(SolutionDir)Temp\$(Configuration)\EditorLib\ true Editor .lib false $(SolutionDir)Temp\$(Configuration)\Libs\ $(SolutionDir)Temp\$(Configuration)\EditorLib\ true Editor .lib Use Level3 Disabled WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;DEBUG;PLATFORM_WINDOWS;%(PreprocessorDefinitions) ..\..\..\o2Engine\;..\..\..\o2Engine\Sources\;..\..\Sources\;..\..\..\o2Engine\Dependencies\;..\..\..\o2Engine\Dependencies\freetype\include\;%(AdditionalIncludeDirectories) false ProgramDatabase Disabled Default true true false Console Debug $(SolutionDir)Tmp\o2Engine_$(Configuration).lib;opengl32.lib;%(AdditionalDependencies) false false false /WHOLEARCHIVE:$(SolutionDir)Tmp\o2Engine_$(Configuration).lib %(AdditionalOptions) true $(IntDir)$(MSBuildProjectName).log ..\..\..\CodeTool\Bin\CodeTool.exe -sources "$(ProjectDir)..\..\Sources" -msvs_project "$(ProjectPath)" -parent_projects "$(ProjectDir)..\..\..\Framework\Sources\o2\CodeToolCache.xml" Generating reflection Use Level3 Disabled WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;DEBUG;PLATFORM_WINDOWS;%(PreprocessorDefinitions) ..\..\..\o2Engine\;..\..\..\o2Engine\Sources\;..\..\Sources\;..\..\..\o2Engine\Dependencies\;..\..\..\o2Engine\Dependencies\freetype\include\;%(AdditionalIncludeDirectories) false ProgramDatabase Disabled Default true true false Console Debug $(SolutionDir)Tmp\o2Engine_$(Configuration).lib;opengl32.lib;%(AdditionalDependencies) false false false /WHOLEARCHIVE:$(SolutionDir)Tmp\o2Engine_$(Configuration).lib %(AdditionalOptions) true $(IntDir)$(MSBuildProjectName).log ..\..\..\CodeTool\Bin\CodeTool.exe -sources "$(ProjectDir)..\..\Sources" -msvs_project "$(ProjectPath)" -parent_projects "$(ProjectDir)..\..\..\Framework\Sources\o2\CodeToolCache.xml" Generating reflection Use Level2 Disabled _CRT_SECURE_NO_WARNINGS;PLATFORM_WINDOWS;SCRIPTING_BACKEND_JERRYSCRIPT;DEBUG;%(PreprocessorDefinitions) $(SolutionDir)..\..\o2\Framework\3rdPartyLibs\FreeType\include;$(SolutionDir)..\..\o2\Framework;$(SolutionDir)..\..\o2\Framework\Sources;$(SolutionDir)..\..\o2\Editor\Sources;$(SolutionDir)..\..\o2\Framework\3rdPartyLibs;$(SolutionDir)..\..\o2\Framework\3rdPartyLibs\rapidjson\include;$(SolutionDir)..\..\o2\Framework\3rdPartyLibs\jerryscript\jerry-core\include;%(AdditionalIncludeDirectories) true o2Editor/stdafx.h false stdcpp20 ProgramDatabase true MultiThreadedDebugDLL /bigobj Console true $(SolutionDir)Lib\o2engine.lib;%(AdditionalDependencies) $(IntDir)$(MSBuildProjectName).log $(ProjectDir)..\..\..\CodeTool\Bin\CodeTool.exe -sources "$(ProjectDir)..\..\Sources" -msvs_project "$(ProjectPath)" -parent_projects "$(ProjectDir)..\..\..\Framework\Sources\o2\CodeToolCache.xml" Reflection generation Use Level2 Disabled _CRT_SECURE_NO_WARNINGS;PLATFORM_WINDOWS;SCRIPTING_BACKEND_JERRYSCRIPT;%(PreprocessorDefinitions) $(SolutionDir)..\..\o2\Framework\3rdPartyLibs\FreeType\include;$(SolutionDir)..\..\o2\Framework;$(SolutionDir)..\..\o2\Framework\Sources;$(SolutionDir)..\..\o2\Editor\Sources;$(SolutionDir)..\..\o2\Framework\3rdPartyLibs;$(SolutionDir)..\..\o2\Framework\3rdPartyLibs\rapidjson\include;$(SolutionDir)..\..\o2\Framework\3rdPartyLibs\jerryscript\jerry-core\include;%(AdditionalIncludeDirectories) true o2Editor/stdafx.h stdcpp20 MultiThreadedDLL ProgramDatabase true Default /bigobj Console true $(SolutionDir)Lib\o2engine.lib;%(AdditionalDependencies) $(IntDir)$(MSBuildProjectName).log $(ProjectDir)..\..\..\CodeTool\Bin\CodeTool.exe -sources "$(ProjectDir)..\..\Sources" -msvs_project "$(ProjectPath)" -parent_projects "$(ProjectDir)..\..\..\Framework\Sources\o2\CodeToolCache.xml" Reflection generation Level3 Use MaxSpeed true true WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;PLATFORM_WINDOWS;%(PreprocessorDefinitions) ..\..\..\o2Engine\;..\..\..\o2Engine\Sources\;..\..\Sources\;..\..\..\o2Engine\Dependencies\;..\..\..\o2Engine\Dependencies\freetype\include\;%(AdditionalIncludeDirectories) true true true true /bigobj %(AdditionalOptions) Speed false true AdvancedVectorExtensions2 Console Debug true true $(SolutionDir)Tmp\o2Engine_$(Configuration).lib;opengl32.lib;%(AdditionalDependencies) UseLinkTimeCodeGeneration /WHOLEARCHIVE:$(SolutionDir)Tmp\o2Engine_$(Configuration).lib %(AdditionalOptions) $(IntDir)$(MSBuildProjectName).log ..\..\..\CodeTool\Bin\CodeTool.exe -sources "$(ProjectDir)..\..\Sources" -msvs_project "$(ProjectPath)" -parent_projects "$(ProjectDir)..\..\..\Framework\Sources\o2\CodeToolCache.xml" Generating reflection Level2 Use MaxSpeed true true _CRT_SECURE_NO_WARNINGS;PLATFORM_WINDOWS;SCRIPTING_BACKEND_JERRYSCRIPT;%(PreprocessorDefinitions) $(SolutionDir)..\..\o2\Framework\3rdPartyLibs\FreeType\include;$(SolutionDir)..\..\o2\Framework;$(SolutionDir)..\..\o2\Framework\Sources;$(SolutionDir)..\..\o2\Editor\Sources;$(SolutionDir)..\..\o2\Framework\3rdPartyLibs;$(SolutionDir)..\..\o2\Framework\3rdPartyLibs\rapidjson\include;$(SolutionDir)..\..\o2\Framework\3rdPartyLibs\jerryscript\jerry-core\include;%(AdditionalIncludeDirectories) true o2Editor/stdafx.h stdcpp20 true StreamingSIMDExtensions2 false AnySuitable Speed /bigobj Console true true true $(SolutionDir)Lib\o2engine.lib;%(AdditionalDependencies) $(IntDir)$(MSBuildProjectName).log $(ProjectDir)..\..\..\CodeTool\Bin\CodeTool.exe -sources "$(ProjectDir)..\..\Sources" -msvs_project "$(ProjectPath)" -parent_projects "$(ProjectDir)..\..\..\Framework\Sources\o2\CodeToolCache.xml" Reflection generation Create Create ================================================ FILE: Editor/Platforms/Windows/Editor.vcxproj.filters ================================================ {aa3f22a5-4b80-4789-a8d7-b2712c76e790} {41532706-fbc0-4598-ba11-545e96cab0e0} {1863c2cd-421f-497c-84ca-9ceeb95f1c4a} Sources\o2Editor\AnimationWindow Sources\o2Editor\AnimationWindow Sources\o2Editor\AnimationWindow Sources\o2Editor\AnimationWindow Sources\o2Editor\AnimationWindow Sources\o2Editor\AnimationWindow Sources\o2Editor\AnimationWindow\TrackControls Sources\o2Editor\AnimationWindow\TrackControls Sources\o2Editor\AnimationWindow\TrackControls Sources\o2Editor\AnimationWindow\TrackControls Sources\o2Editor\AnimationWindow\TrackControls Sources\o2Editor\AnimationWindow\TrackControls Sources\o2Editor\AnimationWindow Sources\o2Editor\AssetsWindow Sources\o2Editor\AssetsWindow Sources\o2Editor\AssetsWindow Sources\o2Editor\AssetsWindow Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Dialogs Sources\o2Editor\Core\Dialogs Sources\o2Editor\Core\Dialogs Sources\o2Editor\Core\Dialogs Sources\o2Editor\Core\Dialogs\System Sources\o2Editor\Core Sources\o2Editor\Core Sources\o2Editor\Core Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties Sources\o2Editor\Core\Properties Sources\o2Editor\Core\Properties Sources\o2Editor\Core\Properties\Objects Sources\o2Editor\Core\Properties\Objects\Assets Sources\o2Editor\Core\Properties\Objects\Assets Sources\o2Editor\Core\Properties\Objects Sources\o2Editor\Core\Properties\Objects\Components Sources\o2Editor\Core\Properties\Objects\Components Sources\o2Editor\Core\Properties\Objects\Components\SkinnedMesh Sources\o2Editor\Core\Properties\Objects\Components\SkinnedMesh Sources\o2Editor\Core\Properties\Objects\Components\SkinnedMesh Sources\o2Editor\Core\Properties\Objects Sources\o2Editor\Core\Properties\Objects Sources\o2Editor\Core\Properties\Objects Sources\o2Editor\Core\Properties Sources\o2Editor\Core\Properties Sources\o2Editor\Core Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core Sources\o2Editor\Core\UIStyle Sources\o2Editor\Core\UIStyle Sources\o2Editor\Core\UI\CurveEditor Sources\o2Editor\Core\UI\CurveEditor Sources\o2Editor\Core\UI Sources\o2Editor\Core\UI Sources\o2Editor\Core\UI Sources\o2Editor\Core\UI Sources\o2Editor\Core\UI\SplineEditor Sources\o2Editor\Core\UI Sources\o2Editor\Core\UI Sources\o2Editor\Core\WindowsSystem Sources\o2Editor\Core\WindowsSystem Sources\o2Editor\Core\WindowsSystem Sources\o2Editor\Core\WindowsSystem Sources\o2Editor\Core\WindowsSystem Sources\o2Editor\GameWindow Sources\o2Editor\LogWindow Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow Sources\o2Editor\PropertiesWindow Sources\o2Editor\PropertiesWindow Sources\o2Editor\PropertiesWindow Sources\o2Editor\PropertiesWindow\WidgetLayerViewer Sources\o2Editor\PropertiesWindow\WidgetLayerViewer Sources\o2Editor\PropertiesWindow\WidgetLayerViewer Sources\o2Editor\PropertiesWindow\WidgetLayerViewer Sources\o2Editor\PropertiesWindow\WidgetLayerViewer Sources\o2Editor\PropertiesWindow\WidgetLayerViewer Sources\o2Editor\PropertiesWindow\WidgetLayerViewer Sources\o2Editor\SceneWindow Sources\o2Editor\SceneWindow Sources\o2Editor\SceneWindow Sources\o2Editor\SceneWindow Sources\o2Editor\SceneWindow Sources\o2Editor\TreeWindow Sources\o2Editor\TreeWindow Sources\o2Editor\TreeWindow Sources\o2Editor\TreeWindow Sources\o2Editor\Utils Sources\o2Editor Sources\o2Editor\AnimationWindow Sources\o2Editor\AnimationWindow Sources\o2Editor\AnimationWindow Sources\o2Editor\AnimationWindow Sources\o2Editor\AnimationWindow Sources\o2Editor\AnimationWindow Sources\o2Editor\AnimationWindow\TrackControls Sources\o2Editor\AnimationWindow\TrackControls Sources\o2Editor\AnimationWindow\TrackControls Sources\o2Editor\AnimationWindow\TrackControls Sources\o2Editor\AnimationWindow\TrackControls Sources\o2Editor\AnimationWindow Sources\o2Editor\AssetsWindow Sources\o2Editor\AssetsWindow Sources\o2Editor\AssetsWindow Sources\o2Editor\AssetsWindow Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Actions Sources\o2Editor\Core\Dialogs Sources\o2Editor\Core\Dialogs Sources\o2Editor\Core\Dialogs Sources\o2Editor\Core\Dialogs Sources\o2Editor\Core\Dialogs\System\Linux Sources\o2Editor\Core\Dialogs\System\Mac Sources\o2Editor\Core\Dialogs\System\Windows Sources\o2Editor\Core Sources\o2Editor\Core Sources\o2Editor\Core Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties\Basic Sources\o2Editor\Core\Properties Sources\o2Editor\Core\Properties Sources\o2Editor\Core\Properties Sources\o2Editor\Core\Properties\Objects Sources\o2Editor\Core\Properties\Objects\Assets Sources\o2Editor\Core\Properties\Objects\Assets Sources\o2Editor\Core\Properties\Objects Sources\o2Editor\Core\Properties\Objects\Components Sources\o2Editor\Core\Properties\Objects\Components Sources\o2Editor\Core\Properties\Objects\Components\SkinnedMesh Sources\o2Editor\Core\Properties\Objects\Components\SkinnedMesh Sources\o2Editor\Core\Properties\Objects\Components\SkinnedMesh Sources\o2Editor\Core\Properties\Objects Sources\o2Editor\Core\Properties\Objects Sources\o2Editor\Core\Properties\Objects Sources\o2Editor\Core\Properties Sources\o2Editor\Core\Properties Sources\o2Editor\Core Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core\Tools Sources\o2Editor\Core Sources\o2Editor\Core\UIStyle Sources\o2Editor\Core\UIStyle Sources\o2Editor\Core\UI\CurveEditor Sources\o2Editor\Core\UI\CurveEditor Sources\o2Editor\Core\UI Sources\o2Editor\Core\UI Sources\o2Editor\Core\UI Sources\o2Editor\Core\UI Sources\o2Editor\Core\UI\SplineEditor Sources\o2Editor\Core\UI Sources\o2Editor\Core\UI Sources\o2Editor\Core\WindowsSystem Sources\o2Editor\Core\WindowsSystem Sources\o2Editor\Core\WindowsSystem Sources\o2Editor\Core\WindowsSystem Sources\o2Editor\Core\WindowsSystem Sources\o2Editor\GameWindow Sources\o2Editor\LogWindow Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow\ActorsViewer Sources\o2Editor\PropertiesWindow Sources\o2Editor\PropertiesWindow Sources\o2Editor\PropertiesWindow Sources\o2Editor\PropertiesWindow Sources\o2Editor\PropertiesWindow\WidgetLayerViewer Sources\o2Editor\PropertiesWindow\WidgetLayerViewer Sources\o2Editor\PropertiesWindow\WidgetLayerViewer Sources\o2Editor\PropertiesWindow\WidgetLayerViewer Sources\o2Editor\PropertiesWindow\WidgetLayerViewer Sources\o2Editor\PropertiesWindow\WidgetLayerViewer Sources\o2Editor\PropertiesWindow\WidgetLayerViewer Sources\o2Editor\SceneWindow Sources\o2Editor\SceneWindow Sources\o2Editor\SceneWindow Sources\o2Editor\SceneWindow Sources\o2Editor\TreeWindow Sources\o2Editor\TreeWindow Sources\o2Editor\TreeWindow Sources\o2Editor\TreeWindow Sources\o2Editor\Utils Sources\o2Editor ================================================ FILE: Editor/Sources/o2Editor/Actions/ActionsList.cpp ================================================ #include "o2Editor/stdafx.h" #include "ActionsList.h" #include "o2Editor/Actions/PropertyChange.h" #include "o2Editor/Windows/SceneWindow/SceneEditScreen.h" namespace Editor { ActionsList::ActionsList(): ActionsList(nullptr) {} ActionsList::ActionsList(RefCounter* refCounter) : RefCounterable(refCounter) {} ActionsList::~ActionsList() {} int ActionsList::GetUndoActionsCount() const { return mActions.Count(); } int ActionsList::GetRedoActionsCount() const { return mForwardActions.Count(); } String ActionsList::GetLastActionName() const { if (mActions.Count() > 0) return mActions.Last()->GetName(); return ""; } String ActionsList::GetNextForwardActionName() const { if (mForwardActions.Count() > 0) return mForwardActions.Last()->GetName(); return ""; } void ActionsList::UndoAction() { if (mActions.Count() > 0) { auto last = mActions.Last(); last->Undo(); mForwardActions.Add(mActions.PopBack()); OnActionUndo(last); } } void ActionsList::RedoAction() { if (mForwardActions.Count() > 0) { auto last = mForwardActions.Last(); last->Redo(); mActions.Add(mForwardActions.PopBack()); OnActionDone(last); } } void ActionsList::DoneAction(const Ref& action) { mActions.Add(action); mForwardActions.Clear(); OnActionDone(action); } void ActionsList::DoneActorPropertyChangeAction(const String& path, const Vector& prevValue, const Vector& newValue) { auto action = mmake(o2EditorSceneScreen.GetSelectedObjects(), path, prevValue, newValue); DoneAction(action); } void ActionsList::ResetUndoActions() { mActions.Clear(); mForwardActions.Clear(); } const Vector> ActionsList::GetUndoActions() const { return mActions; } const Vector> ActionsList::GetRedoActions() const { return mForwardActions; } } ================================================ FILE: Editor/Sources/o2Editor/Actions/ActionsList.h ================================================ #pragma once #include "o2Editor/Actions/IAction.h" namespace Editor { // --------------------------------------------------- // Done editor actions list. Can undo and redo actions // --------------------------------------------------- class ActionsList: public RefCounterable { public: // Default constructor ActionsList(); // Constructor with ref counter explicit ActionsList(RefCounter* refCounter); // Destructor. Destroys stored actions ~ActionsList(); // Returns count of undo actions int GetUndoActionsCount() const; // Returns count of redo actions int GetRedoActionsCount() const; // Returns last action name String GetLastActionName() const; // Returns next forward action name String GetNextForwardActionName() const; // Undo last action void UndoAction(); // Redo next action void RedoAction(); // Called when action was done void DoneAction(const Ref& action); // Called when some property changed, stores action for undo void DoneActorPropertyChangeAction(const String& path, const Vector& prevValue, const Vector& newValue); // Resets undo and redo actions void ResetUndoActions(); // Returns done actions const Vector> GetUndoActions() const; // Returns redo actions const Vector> GetRedoActions() const; protected: // Called when an action has been done (including redo) virtual void OnActionDone(const Ref& action) {} // Called when an action has been undone virtual void OnActionUndo(const Ref& action) {} protected: Vector> mActions; // Done actions Vector> mForwardActions; // Forward actions, what you can redo }; } ================================================ FILE: Editor/Sources/o2Editor/Actions/Create.cpp ================================================ #include "o2Editor/stdafx.h" #include "Create.h" #include "o2/Scene/Actor.h" #include "o2/Scene/Scene.h" #include "o2Editor/Windows/SceneWindow/SceneEditScreen.h" #include "o2Editor/Windows/TreeWindow/TreeWindow.h" namespace Editor { CreateAction::CreateAction() {} CreateAction::CreateAction(const Vector>& objects, const Ref& parent, const Ref& prevObject) { objectsIds = objects.Convert([](auto& x) { return x->GetID(); }); objectsData.Set(objects); insertParentId = parent ? parent->GetID() : 0; insertPrevObjectId = prevObject ? prevObject->GetID() : 0; } String CreateAction::GetName() const { return "Create objects"; } void CreateAction::Redo() { auto parent = o2Scene.GetEditableObjectByID(insertParentId); auto prevObject = o2Scene.GetEditableObjectByID(insertPrevObjectId); Vector> objects; if (parent) { int insertIdx = parent->GetEditableChildren().IndexOf(prevObject) + 1; objectsData.Get(objects); for (auto& object : objects) parent->AddEditableChild(object, insertIdx++); } else { int insertIdx = o2Scene.GetRootEditableObjects().IndexOf(prevObject) + 1; objectsData.Get(objects); for (auto& object : objects) object->SetIndexInSiblings(insertIdx++); } o2EditorTree.HighlightObjectTreeNode(objects.Last()); o2EditorSceneScreen.SelectObjectsWithoutAction(objects, false); } void CreateAction::Undo() { for (auto& objectId : objectsIds) { auto object = o2Scene.GetEditableObjectByID(objectId); // if (object) // delete object; } o2EditorSceneScreen.ClearSelectionWithoutAction(); } } // --- META --- DECLARE_CLASS(Editor::CreateAction, Editor__CreateAction); // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Actions/Create.h ================================================ #pragma once #include "o2/Utils/Types/Containers/Vector.h" #include "o2Editor/Actions/IAction.h" using namespace o2; namespace o2 { class SceneEditableObject; } namespace Editor { // ----------------------------- // Scene objects creation action // ----------------------------- class CreateAction: public IAction { public: DataDocument objectsData; // Serialized created objects Vector objectsIds; // Created objects ids SceneUID insertParentId; // Parent id SceneUID insertPrevObjectId; // Previous object id public: // Default constructor CreateAction(); // Constructor wit created actors and their places in their parents CreateAction(const Vector>& objects, const Ref& parent, const Ref& prevObject); // Returns name of action String GetName() const override; // Creates all objects again void Redo() override; // Removes created objects void Undo() override; SERIALIZABLE(CreateAction); }; } // --- META --- CLASS_BASES_META(Editor::CreateAction) { BASE_CLASS(Editor::IAction); } END_META; CLASS_FIELDS_META(Editor::CreateAction) { FIELD().PUBLIC().NAME(objectsData); FIELD().PUBLIC().NAME(objectsIds); FIELD().PUBLIC().NAME(insertParentId); FIELD().PUBLIC().NAME(insertPrevObjectId); } END_META; CLASS_METHODS_META(Editor::CreateAction) { FUNCTION().PUBLIC().CONSTRUCTOR(); FUNCTION().PUBLIC().CONSTRUCTOR(const Vector>&, const Ref&, const Ref&); FUNCTION().PUBLIC().SIGNATURE(String, GetName); FUNCTION().PUBLIC().SIGNATURE(void, Redo); FUNCTION().PUBLIC().SIGNATURE(void, Undo); } END_META; // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Actions/Delete.cpp ================================================ #include "o2Editor/stdafx.h" #include "Delete.h" #include "o2/Scene/Actor.h" #include "o2/Scene/Scene.h" #include "o2Editor/Windows/SceneWindow/SceneEditScreen.h" #include "o2Editor/Windows/TreeWindow/SceneHierarchyTree.h" #include "o2Editor/Windows/TreeWindow/TreeWindow.h" namespace Editor { DeleteAction::DeleteAction() {} DeleteAction::DeleteAction(const Vector>& objects) { for (auto& object : objects) { ObjectInfo info; info.objectData.Set(object); info.idx = o2Scene.GetObjectHierarchyIdx(object); if (auto parent = object->GetEditableParent()) { info.parentId = parent->GetID(); auto parentChilds = parent->GetEditableChildren(); info.prevObjectId = 0; for (auto& child : parentChilds) { if (child == object) break; info.prevObjectId = child->GetID(); } } else { info.parentId = 0; auto rootObjects = o2Scene.GetRootEditableObjects(); info.prevObjectId = 0; for (auto& child : rootObjects) { if (child == object) break; info.prevObjectId = child->GetID(); } } objectsInfos.Add(info); } objectsInfos.Sort([](auto& a, auto& b) { return a.idx < b.idx; }); } String DeleteAction::GetName() const { return "Actors deletion"; } void DeleteAction::Redo() { for (auto& info : objectsInfos) { auto object = o2Scene.GetEditableObjectByID((SceneUID)info.objectData["Value"]["Id"]); // if (object) // delete object; } o2EditorSceneScreen.ClearSelectionWithoutAction(); o2EditorTree.UpdateTreeView(); } void DeleteAction::Undo() { Ref lastRestored; for (auto& info : objectsInfos) { auto parent = o2Scene.GetEditableObjectByID(info.parentId); if (parent) { SceneUID prevId = info.prevObjectId; int idx = parent->GetEditableChildren().IndexOf([=](auto& x) { return x->GetID() == prevId; }) + 1; Ref newObject; info.objectData.Get(newObject); parent->AddEditableChild(newObject, idx); o2EditorSceneScreen.SelectObjectWithoutAction(newObject); lastRestored = newObject; } else { int idx = o2Scene.GetRootActors().IndexOf([&](auto& x) { return x->GetID() == info.prevObjectId; }) + 1; Ref newObject; info.objectData.Get(newObject); newObject->SetIndexInSiblings(idx); o2EditorSceneScreen.SelectObjectWithoutAction(newObject); lastRestored = newObject; } } o2EditorTree.HighlightObjectTreeNode(lastRestored); o2EditorTree.UpdateTreeView(); } bool DeleteAction::ObjectInfo::operator==(const ObjectInfo& other) const { return objectData == other.objectData && parentId == other.parentId && prevObjectId == other.prevObjectId; } } // --- META --- DECLARE_CLASS(Editor::DeleteAction, Editor__DeleteAction); DECLARE_CLASS(Editor::DeleteAction::ObjectInfo, Editor__DeleteAction__ObjectInfo); // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Actions/Delete.h ================================================ #pragma once #include "o2/Utils/Serialization/DataValue.h" #include "o2/Utils/Types/Containers/Vector.h" #include "o2Editor/Actions/IAction.h" using namespace o2; namespace o2 { class SceneEditableObject; } namespace Editor { // --------------------- // Delete objects action // --------------------- class DeleteAction: public IAction { public: class ObjectInfo: public ISerializable { public: DataDocument objectData; // Serialized object @SERIALIZABLE SceneUID parentId; // Previous object parent @SERIALIZABLE SceneUID prevObjectId; // Previous object sibling @SERIALIZABLE int idx; // Index in children @SERIALIZABLE bool operator==(const ObjectInfo& other) const; SERIALIZABLE(ObjectInfo); }; public: Vector objectsInfos; // Deleted objects infos public: // Default constructor DeleteAction(); // Constructor with objects, that will be deleted DeleteAction(const Vector>& objects); // Returns name of action String GetName() const override; // Deletes objects again void Redo() override; // Reverting deleted objects void Undo() override; SERIALIZABLE(DeleteAction); }; } // --- META --- CLASS_BASES_META(Editor::DeleteAction) { BASE_CLASS(Editor::IAction); } END_META; CLASS_FIELDS_META(Editor::DeleteAction) { FIELD().PUBLIC().NAME(objectsInfos); } END_META; CLASS_METHODS_META(Editor::DeleteAction) { FUNCTION().PUBLIC().CONSTRUCTOR(); FUNCTION().PUBLIC().CONSTRUCTOR(const Vector>&); FUNCTION().PUBLIC().SIGNATURE(String, GetName); FUNCTION().PUBLIC().SIGNATURE(void, Redo); FUNCTION().PUBLIC().SIGNATURE(void, Undo); } END_META; CLASS_BASES_META(Editor::DeleteAction::ObjectInfo) { BASE_CLASS(o2::ISerializable); } END_META; CLASS_FIELDS_META(Editor::DeleteAction::ObjectInfo) { FIELD().PUBLIC().SERIALIZABLE_ATTRIBUTE().NAME(objectData); FIELD().PUBLIC().SERIALIZABLE_ATTRIBUTE().NAME(parentId); FIELD().PUBLIC().SERIALIZABLE_ATTRIBUTE().NAME(prevObjectId); FIELD().PUBLIC().SERIALIZABLE_ATTRIBUTE().NAME(idx); } END_META; CLASS_METHODS_META(Editor::DeleteAction::ObjectInfo) { } END_META; // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Actions/Enable.cpp ================================================ #include "o2Editor/stdafx.h" #include "Enable.h" #include "o2/Scene/Actor.h" #include "o2Editor/Windows/SceneWindow/SceneEditScreen.h" namespace Editor { EnableAction::EnableAction() {} EnableAction::EnableAction(const Vector>& objects, bool enable): enable(enable) { objectsIds = objects.Convert([](auto& x) { return x->GetID(); }); } String EnableAction::GetName() const { return enable ? "Enable actors" : "Disable actors"; } void EnableAction::Redo() { for (auto& id : objectsIds) { auto object = o2Scene.GetEditableObjectByID(id); if (object) object->SetEnabled(enable); } } void EnableAction::Undo() { for (auto& id : objectsIds) { auto object = o2Scene.GetEditableObjectByID(id); if (object) object->SetEnabled(!enable); } } } // --- META --- DECLARE_CLASS(Editor::EnableAction, Editor__EnableAction); // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Actions/Enable.h ================================================ #pragma once #include "o2/Utils/Types/Containers/Vector.h" #include "o2Editor/Actions/IAction.h" using namespace o2; namespace o2 { class SceneEditableObject; } namespace Editor { // ------------------------------- // Enable or disable scene objects // ------------------------------- class EnableAction: public IAction { public: Vector objectsIds; // Changed objects bool enable; // Enabled or disabled public: // Default constructor EnableAction(); // COnstructor with enabled or disabled objects EnableAction(const Vector>& objects, bool enable); // Returns name of action String GetName() const override; // Enable or disable again void Redo() override; // Reverts objects to previous state void Undo() override; SERIALIZABLE(EnableAction); }; } // --- META --- CLASS_BASES_META(Editor::EnableAction) { BASE_CLASS(Editor::IAction); } END_META; CLASS_FIELDS_META(Editor::EnableAction) { FIELD().PUBLIC().NAME(objectsIds); FIELD().PUBLIC().NAME(enable); } END_META; CLASS_METHODS_META(Editor::EnableAction) { FUNCTION().PUBLIC().CONSTRUCTOR(); FUNCTION().PUBLIC().CONSTRUCTOR(const Vector>&, bool); FUNCTION().PUBLIC().SIGNATURE(String, GetName); FUNCTION().PUBLIC().SIGNATURE(void, Redo); FUNCTION().PUBLIC().SIGNATURE(void, Undo); } END_META; // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Actions/IAction.cpp ================================================ #include "o2Editor/stdafx.h" #include "IAction.h" // --- META --- DECLARE_CLASS(Editor::IAction, Editor__IAction); // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Actions/IAction.h ================================================ #pragma once #include "o2/Utils/Serialization/Serializable.h" using namespace o2; namespace Editor { // ----------------------------- // Basic editor action interface // ----------------------------- class IAction: public ISerializable, public RefCounterable { public: // VIrtual destructor virtual ~IAction() {} // Returns name of action virtual String GetName() const { return "Unknown"; } // Does action again virtual void Redo() {} // Undoing action virtual void Undo() {} SERIALIZABLE(IAction); }; } // --- META --- CLASS_BASES_META(Editor::IAction) { BASE_CLASS(o2::ISerializable); BASE_CLASS(o2::RefCounterable); } END_META; CLASS_FIELDS_META(Editor::IAction) { } END_META; CLASS_METHODS_META(Editor::IAction) { FUNCTION().PUBLIC().SIGNATURE(String, GetName); FUNCTION().PUBLIC().SIGNATURE(void, Redo); FUNCTION().PUBLIC().SIGNATURE(void, Undo); } END_META; // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Actions/Lock.cpp ================================================ #include "o2Editor/stdafx.h" #include "Lock.h" #include "o2/Scene/Actor.h" #include "o2Editor/Windows/SceneWindow/SceneEditScreen.h" namespace Editor { LockAction::LockAction() {} LockAction::LockAction(const Vector>& objects, bool lock): lock(lock) { objectsIds = objects.Convert([](auto& x) { return x->GetID(); }); } String LockAction::GetName() const { return lock ? "Lock actors" : "Unlock actors"; } void LockAction::Redo() { for (auto& id : objectsIds) { auto object = o2Scene.GetEditableObjectByID(id); if (object) object->SetLocked(lock); } } void LockAction::Undo() { for (auto& id : objectsIds) { auto object = o2Scene.GetEditableObjectByID(id); if (object) object->SetLocked(!lock); } } } // --- META --- DECLARE_CLASS(Editor::LockAction, Editor__LockAction); // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Actions/Lock.h ================================================ #pragma once #include "o2/Utils/Types/Containers/Vector.h" #include "o2Editor/Actions/IAction.h" using namespace o2; namespace o2 { class SceneEditableObject; } namespace Editor { // ---------------------------------- // Locking or unlocking object action // ---------------------------------- class LockAction: public IAction { public: Vector objectsIds; // Changed objects bool lock; // Lock state public: // Default constructor LockAction(); // Constructor with list of objects LockAction(const Vector>& object, bool lock); // Return name of action String GetName() const override; // Sets stored lock void Redo() override; // Sets previous lock void Undo() override; SERIALIZABLE(LockAction); }; } // --- META --- CLASS_BASES_META(Editor::LockAction) { BASE_CLASS(Editor::IAction); } END_META; CLASS_FIELDS_META(Editor::LockAction) { FIELD().PUBLIC().NAME(objectsIds); FIELD().PUBLIC().NAME(lock); } END_META; CLASS_METHODS_META(Editor::LockAction) { FUNCTION().PUBLIC().CONSTRUCTOR(); FUNCTION().PUBLIC().CONSTRUCTOR(const Vector>&, bool); FUNCTION().PUBLIC().SIGNATURE(String, GetName); FUNCTION().PUBLIC().SIGNATURE(void, Redo); FUNCTION().PUBLIC().SIGNATURE(void, Undo); } END_META; // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Actions/PropertyChange.cpp ================================================ #include "o2Editor/stdafx.h" #include "PropertyChange.h" #include "o2/Scene/Actor.h" #include "o2/Scene/Component.h" #include "o2/Scene/Scene.h" #include "o2/Utils/Editor/SceneEditableObject.h" namespace Editor { PropertyChangeAction::PropertyChangeAction() { } PropertyChangeAction::PropertyChangeAction(const Vector>& objects, const String& propertyPath, const Vector& beforeValues, const Vector& afterValues) : objectsIds(objects.Convert([](const auto& x) { return x->GetID(); })), propertyPath(propertyPath), beforeValues(beforeValues), afterValues(afterValues) { } String PropertyChangeAction::GetName() const { return "Property changed"; } void PropertyChangeAction::Redo() { SetProperties(afterValues); } void PropertyChangeAction::Undo() { SetProperties(beforeValues); } void PropertyChangeAction::SetProperties(Vector& values) { Vector> objects = objectsIds.Convert>([](SceneUID id) { return o2Scene.GetEditableObjectByID(id); }); int idx = 0; for (auto& object : objects) { if (!object) continue; const FieldInfo* fi = nullptr; void* ptr = nullptr; if (auto objectType = dynamic_cast(&object->GetType())) { void* realTypeObject = objectType->DynamicCastFromIObject(dynamic_cast(object.Get())); ptr = objectType->GetFieldPtr(realTypeObject, propertyPath, fi); } if (fi && ptr) fi->Deserialize(ptr, values[idx]); object->OnChanged(); idx++; } } } // --- META --- DECLARE_CLASS(Editor::PropertyChangeAction, Editor__PropertyChangeAction); // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Actions/PropertyChange.h ================================================ #pragma once #include "o2Editor/Actions/IAction.h" using namespace o2; namespace o2 { class SceneEditableObject; } namespace Editor { // ----------------------------------------------------- // Scene object property change action. // Storing path to value, values before and after change // ----------------------------------------------------- class PropertyChangeAction: public IAction { public: Vector objectsIds; // Changed objects String propertyPath; // Path to property Vector beforeValues; // Serialized values before change Vector afterValues; // Serialized values after change public: // Default constructor PropertyChangeAction(); // Constructor with all data PropertyChangeAction(const Vector>& objects, const String& propertyPath, const Vector& beforeValues, const Vector& afterValues); // Returns name of action String GetName() const override; // Sets object's properties value as after change void Redo() override; // Sets object's properties value as before change void Undo() override; SERIALIZABLE(PropertyChangeAction); protected: // Sets object's properties values void SetProperties(Vector& value); }; } // --- META --- CLASS_BASES_META(Editor::PropertyChangeAction) { BASE_CLASS(Editor::IAction); } END_META; CLASS_FIELDS_META(Editor::PropertyChangeAction) { FIELD().PUBLIC().NAME(objectsIds); FIELD().PUBLIC().NAME(propertyPath); FIELD().PUBLIC().NAME(beforeValues); FIELD().PUBLIC().NAME(afterValues); } END_META; CLASS_METHODS_META(Editor::PropertyChangeAction) { FUNCTION().PUBLIC().CONSTRUCTOR(); FUNCTION().PUBLIC().CONSTRUCTOR(const Vector>&, const String&, const Vector&, const Vector&); FUNCTION().PUBLIC().SIGNATURE(String, GetName); FUNCTION().PUBLIC().SIGNATURE(void, Redo); FUNCTION().PUBLIC().SIGNATURE(void, Undo); FUNCTION().PROTECTED().SIGNATURE(void, SetProperties, Vector&); } END_META; // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Actions/Reparent.cpp ================================================ #include "o2Editor/stdafx.h" #include "Reparent.h" #include "o2/Scene/Actor.h" #include "o2Editor/Windows/SceneWindow/SceneEditScreen.h" #include "o2Editor/Windows/TreeWindow/SceneHierarchyTree.h" #include "o2Editor/Windows/TreeWindow/TreeWindow.h" namespace Editor { ReparentAction::ReparentAction() {} ReparentAction::ReparentAction(const Vector>& beginObjects) { for (auto& object : beginObjects) { ObjectInfo info; auto parent = object->GetEditableParent(); Vector> parentChildren = parent ? parent->GetEditableChildren() : DynamicCastVector(o2Scene.GetRootActors()); int actorIdx = parentChildren.IndexOf(object); info.objectId = object->GetID(); info.objectHierarchyIdx = o2Scene.GetObjectHierarchyIdx(object); info.lastParentId = parent ? parent->GetID() : 0; info.lastPrevObjectId = actorIdx > 0 ? parentChildren[actorIdx - 1]->GetID() : 0; info.transform = object->GetTransform(); objectsInfos.Add(info); } objectsInfos.Sort([](auto& a, auto& b) { return a.objectHierarchyIdx < b.objectHierarchyIdx; }); } ReparentAction::~ReparentAction() {} void ReparentAction::ObjectsReparented(const Ref& newParent, const Ref& prevActor) { newParentId = newParent ? newParent->GetID() : 0; newPrevObjectId = prevActor ? prevActor->GetID() : 0; } String ReparentAction::GetName() const { return "Actors rearrange"; } void ReparentAction::Redo() { auto parent = o2Scene.GetEditableObjectByID(newParentId); auto prevObject = o2Scene.GetEditableObjectByID(newPrevObjectId); if (parent) { int insertIdx = parent->GetEditableChildren().IndexOf(prevObject) + 1; for (auto& info : objectsInfos) { auto object = o2Scene.GetEditableObjectByID(info.objectId); object->SetEditableParent(nullptr); parent->AddEditableChild(object, insertIdx++); object->SetTransform(info.transform); } } else { int insertIdx = 0; if (auto prevActor = DynamicCast(prevObject)) insertIdx = o2Scene.GetRootActors().IndexOf(prevActor) + 1; for (auto& info : objectsInfos) { auto object = o2Scene.GetEditableObjectByID(info.objectId); object->SetEditableParent(nullptr); object->SetIndexInSiblings(insertIdx++); object->SetTransform(info.transform); } } o2EditorTree.UpdateTreeView(); } void ReparentAction::Undo() { for (auto& info : objectsInfos) { auto object = o2Scene.GetEditableObjectByID(info.objectId); auto parent = o2Scene.GetEditableObjectByID(info.lastParentId); auto prevObject = o2Scene.GetEditableObjectByID(info.lastPrevObjectId); object->SetEditableParent(nullptr); if (parent) { int idx = parent->GetEditableChildren().IndexOf(prevObject) + 1; parent->AddEditableChild(object, idx); object->SetTransform(info.transform); } else { int idx = o2Scene.GetRootEditableObjects().IndexOf(prevObject) + 1; object->SetIndexInSiblings(idx); object->SetTransform(info.transform); } } o2EditorTree.UpdateTreeView(); } } // --- META --- DECLARE_CLASS(Editor::ReparentAction, Editor__ReparentAction); // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Actions/Reparent.h ================================================ #pragma once #include "o2/Utils/Math/Basis.h" #include "o2/Utils/Types/Containers/Vector.h" #include "o2Editor/Actions/IAction.h" using namespace o2; namespace o2 { class Actor; class SceneEditableObject; } namespace Editor { // ------------------------------ // Change object's parents action // Storing old and new parent and // index in parents // ------------------------------ class ReparentAction: public IAction { public: struct ObjectInfo { SceneUID objectId; // Object id SceneUID lastParentId; // Previous parent id SceneUID lastPrevObjectId; // Previous object id in children int objectHierarchyIdx; // Object index in hierarchy Basis transform; // Object transform bool operator==(const ObjectInfo& other) const { return objectId == other.objectId; } }; Vector objectsInfos; // Changed objects info SceneUID newParentId; // New parent id SceneUID newPrevObjectId; // New object id in children public: // Default constructor ReparentAction(); // Constructor ReparentAction(const Vector>& beginObjects); // Destructor ~ReparentAction(); // Called when object are reparented, stores all required data to restore old objects' parents void ObjectsReparented(const Ref& newParent, const Ref& prevObject); // Returns name of action String GetName() const override; // Sets new parents again void Redo() override; // Sets previous stored parents and index in children void Undo() override; SERIALIZABLE(ReparentAction); }; } // --- META --- CLASS_BASES_META(Editor::ReparentAction) { BASE_CLASS(Editor::IAction); } END_META; CLASS_FIELDS_META(Editor::ReparentAction) { FIELD().PUBLIC().NAME(objectsInfos); FIELD().PUBLIC().NAME(newParentId); FIELD().PUBLIC().NAME(newPrevObjectId); } END_META; CLASS_METHODS_META(Editor::ReparentAction) { FUNCTION().PUBLIC().CONSTRUCTOR(); FUNCTION().PUBLIC().CONSTRUCTOR(const Vector>&); FUNCTION().PUBLIC().SIGNATURE(void, ObjectsReparented, const Ref&, const Ref&); FUNCTION().PUBLIC().SIGNATURE(String, GetName); FUNCTION().PUBLIC().SIGNATURE(void, Redo); FUNCTION().PUBLIC().SIGNATURE(void, Undo); } END_META; // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Actions/Select.cpp ================================================ #include "o2Editor/stdafx.h" #include "Select.h" #include "o2/Scene/Actor.h" #include "o2Editor/Windows/SceneWindow/SceneEditScreen.h" namespace Editor { SelectAction::SelectAction() {} SelectAction::SelectAction(const Vector>& selectedObjects, const Vector>& prevSelectedObjects) { selectedObjectsIds = selectedObjects.Convert([](auto& x) { return x->GetID(); }); prevSelectedObjectsIds = prevSelectedObjects.Convert([](auto& x) { return x->GetID(); }); } String SelectAction::GetName() const { return "Actors selection"; } void SelectAction::Redo() { auto& selScreen = o2EditorSceneScreen; selScreen.mSelectedObjects = selectedObjectsIds.Convert>( [&](SceneUID id) { return o2Scene.GetEditableObjectByID(id); }); selScreen.UpdateTopSelectedObjects(); selScreen.OnObjectsSelectedFromThis(); selScreen.mNeedRedraw = true; } void SelectAction::Undo() { auto& selScreen = o2EditorSceneScreen; selScreen.mSelectedObjects.Clear(); prevSelectedObjectsIds.ForEach([&](SceneUID id) { if (auto obj = o2Scene.GetEditableObjectByID(id)) selScreen.mSelectedObjects.Add(obj); }); selScreen.UpdateTopSelectedObjects(); selScreen.OnObjectsSelectedFromThis(); selScreen.mNeedRedraw = true; } } // --- META --- DECLARE_CLASS(Editor::SelectAction, Editor__SelectAction); // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Actions/Select.h ================================================ #pragma once #include "o2/Utils/Types/Containers/Vector.h" #include "o2Editor/Actions/IAction.h" using namespace o2; namespace o2 { class SceneEditableObject; } namespace Editor { // ----------------------------- // Scene object selection action // ----------------------------- class SelectAction: public IAction { public: Vector selectedObjectsIds; // Selected objects ids Vector prevSelectedObjectsIds; // Selected objects ids before public: // Default constructor SelectAction(); // CUnstructor with new and previous selected objects SelectAction(const Vector>& selectedObjects, const Vector>& prevSelectedObjects); // Returns name of action String GetName() const override; // Selects objects again void Redo() override; // Selects previous selected objects void Undo() override; SERIALIZABLE(SelectAction); }; } // --- META --- CLASS_BASES_META(Editor::SelectAction) { BASE_CLASS(Editor::IAction); } END_META; CLASS_FIELDS_META(Editor::SelectAction) { FIELD().PUBLIC().NAME(selectedObjectsIds); FIELD().PUBLIC().NAME(prevSelectedObjectsIds); } END_META; CLASS_METHODS_META(Editor::SelectAction) { FUNCTION().PUBLIC().CONSTRUCTOR(); FUNCTION().PUBLIC().CONSTRUCTOR(const Vector>&, const Vector>&); FUNCTION().PUBLIC().SIGNATURE(String, GetName); FUNCTION().PUBLIC().SIGNATURE(void, Redo); FUNCTION().PUBLIC().SIGNATURE(void, Undo); } END_META; // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Actions/Transform.cpp ================================================ #include "o2Editor/stdafx.h" #include "Transform.h" #include "o2/Scene/Actor.h" #include "o2Editor/Windows/SceneWindow/SceneEditScreen.h" namespace Editor { TransformAction::TransformAction() {} TransformAction::TransformAction(const Vector>& actors) { objectsIds = actors.Convert([](auto& x) { return x->GetID(); }); GetTransforms(objectsIds, beforeTransforms); } void TransformAction::Completed() { GetTransforms(objectsIds, doneTransforms); } String TransformAction::GetName() const { return "Actors transformation"; } void TransformAction::Redo() { SetTransforms(objectsIds, doneTransforms); } void TransformAction::Undo() { SetTransforms(objectsIds, beforeTransforms); } void TransformAction::GetTransforms(const Vector& objectIds, Vector& transforms) { transforms = objectIds.Convert([=](SceneUID id) { auto object = o2Scene.GetEditableObjectByID(id); if (object) { Transform res; res.transform = object->GetTransform(); res.layout = object->GetLayout(); return res; } return Transform(); }); } void TransformAction::SetTransforms(const Vector& objectIds, Vector& transforms) { for (int i = 0; i < objectsIds.Count(); i++) { auto object = o2Scene.GetEditableObjectByID(objectsIds[i]); if (object) { object->SetTransform(transforms[i].transform); object->SetLayout(transforms[i].layout); } } } bool TransformAction::Transform::operator==(const Transform& other) const { return transform == other.transform && layout == other.layout; } } // --- META --- DECLARE_CLASS(Editor::TransformAction, Editor__TransformAction); // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Actions/Transform.h ================================================ #pragma once #include "o2/Scene/ActorTransform.h" #include "o2/Utils/Math/Basis.h" #include "o2Editor/Actions/IAction.h" using namespace o2; namespace o2 { class SceneEditableObject; } namespace Editor { // --------------------------- // Objects transforming action // --------------------------- class TransformAction: public IAction { public: struct Transform { Basis transform; Layout layout; bool operator==(const Transform& other) const; }; Vector objectsIds; // Changed objects ids Vector beforeTransforms; // Transforms before changing Vector doneTransforms; // Transforms after changing public: // Default constructor TransformAction(); // Constructor with objects, stores theirs before changing transforms TransformAction(const Vector>& objects); // Called when transform completed, stores changed transforms void Completed(); // Returns name of action String GetName() const override; // Sets new transforms again void Redo() override; // Sets transformations before transform void Undo() override; SERIALIZABLE(TransformAction); private: // Gets objects transforms and puts into transforms vector void GetTransforms(const Vector& objectIds, Vector& transforms); // Sets transformations and layouts to objects void SetTransforms(const Vector& objectIds, Vector& transforms); }; } // --- META --- CLASS_BASES_META(Editor::TransformAction) { BASE_CLASS(Editor::IAction); } END_META; CLASS_FIELDS_META(Editor::TransformAction) { FIELD().PUBLIC().NAME(objectsIds); FIELD().PUBLIC().NAME(beforeTransforms); FIELD().PUBLIC().NAME(doneTransforms); } END_META; CLASS_METHODS_META(Editor::TransformAction) { FUNCTION().PUBLIC().CONSTRUCTOR(); FUNCTION().PUBLIC().CONSTRUCTOR(const Vector>&); FUNCTION().PUBLIC().SIGNATURE(void, Completed); FUNCTION().PUBLIC().SIGNATURE(String, GetName); FUNCTION().PUBLIC().SIGNATURE(void, Redo); FUNCTION().PUBLIC().SIGNATURE(void, Undo); FUNCTION().PRIVATE().SIGNATURE(void, GetTransforms, const Vector&, Vector&); FUNCTION().PRIVATE().SIGNATURE(void, SetTransforms, const Vector&, Vector&); } END_META; // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Dialogs/ColorPickerDlg.cpp ================================================ #include "o2Editor/stdafx.h" #include "ColorPickerDlg.h" #include "o2/Scene/UI/UIManager.h" #include "o2/Scene/UI/WidgetLayer.h" #include "o2/Scene/UI/WidgetLayout.h" #include "o2/Scene/UI/Widgets/DropDown.h" #include "o2/Scene/UI/Widgets/EditBox.h" #include "o2/Scene/UI/Widgets/HorizontalLayout.h" #include "o2/Scene/UI/Widgets/HorizontalProgress.h" #include "o2/Scene/UI/Widgets/Image.h" #include "o2/Scene/UI/Widgets/Label.h" #include "o2/Scene/UI/Widgets/VerticalLayout.h" #include "o2/Scene/UI/Widgets/VerticalProgress.h" #include "o2/Scene/UI/Widgets/Window.h" #include "o2Editor/UIRoot.h" #include "o2Editor/Utils/CommonTextures.h" DECLARE_SINGLETON(Editor::ColorPickerDlg); namespace Editor { ColorPickerDlg::ColorPickerDlg(RefCounter* refCounter) : CursorEventsListener(refCounter), Singleton(refCounter) { mWindow = DynamicCast(EditorUIRoot.AddWidget(o2UI.CreateWindow("Color picker"))); InitializeControls(); mWindow->Hide(true); mWindow->layout->size = Vec2F(400, 600); mWindow->layout->worldPosition = Vec2F(); mWindow->GetBackCursorListener().onCursorReleased = [&](const Input::Cursor& c) { OnCursorPressedOutside(); }; mWindow->onHide = MakeFunction(this, &ColorPickerDlg::OnHide); } ColorPickerDlg::~ColorPickerDlg() {} void ColorPickerDlg::Show(const Color4& color, const Function& onChanged, const Function& onCompleted/* = Function()*/) { mInstance->mColorValue = color; mInstance->mWindow->ShowModal(); mInstance->mOnChangedCallback = onChanged; mInstance->mOnCompletedCallback = onCompleted; mInstance->UpdateValues(ParameterType::General); } void ColorPickerDlg::OnHide() { mOnCompletedCallback(); } void ColorPickerDlg::InitializeControls() { InitializeChessBackTexture(); InitializeColorPreview(); InitializePickArea(); InitializeColorParams(); } void ColorPickerDlg::InitializeChessBackTexture() { Color4 color1(1.0f, 1.0f, 1.0f, 1.0f), color2(0.7f, 0.7f, 0.7f, 1.0f); Bitmap backLayerBitmap(PixelFormat::R8G8B8A8, Vec2I(20, 20)); backLayerBitmap.Fill(color1); backLayerBitmap.FillRect(0, 10, 10, 0, color2); backLayerBitmap.FillRect(10, 20, 20, 10, color2); mChessBackTexture = TextureRef(backLayerBitmap); } void ColorPickerDlg::InitializeColorPreview() { auto colorPreviewContainer = mmake(); *colorPreviewContainer->layout = WidgetLayout::HorStretch(VerAlign::Top, 0, 0, 30, 0); auto colorPreview = o2UI.CreateWidget("colorProperty"); *colorPreview->layout = WidgetLayout::BothStretch(5, 5, 5, 5); auto backImage = mmake(); backImage->image = mmake(CommonTextures::checkedBackground, RectI(0, 0, 20, 20)); backImage->GetImage()->mode = SpriteMode::Tiled; *backImage->layout = WidgetLayout::BothStretch(1, 1, 1, 1); colorPreview->AddChild(backImage); Bitmap colorLayerBitmap(PixelFormat::R8G8B8A8, Vec2I(20, 20)); colorLayerBitmap.Fill(Color4::White()); mColorSampleImage = mmake(); mColorSampleImage->image = mmake(colorLayerBitmap); *mColorSampleImage->layout = WidgetLayout::BothStretch(1, 1, 1, 1); colorPreview->AddChild(mColorSampleImage); colorPreviewContainer->AddChild(colorPreview); mWindow->AddChild(colorPreviewContainer); } void ColorPickerDlg::InitializePickArea() { auto pickAreaContainer = mmake(); *pickAreaContainer->layout = WidgetLayout(Vec2F(0.0f, 0.5f), Vec2F(1.0f, 1.0f), Vec2F(0, 0), Vec2F(0, -30)); auto pickArea = mmake(); *pickArea->layout = WidgetLayout::BothStretch(5, 5, 5, 5); pickArea->AddLayer("back", mmake("ui/UI4_Editbox_regular.png"), Layout::BothStretch(-9, -9, -9, -9)); mColorPickAreaBitmap = mmake(PixelFormat::R8G8B8A8, Vec2I(80, 80)); mColorPickAreaBitmap->Clear(Color4::White()); mColorPickAreaTexture = TextureRef(*mColorPickAreaBitmap); mColorPickAreaColor = pickArea->AddLayer("color", mmake(mColorPickAreaTexture, RectI(0, 0, 80, 80)), Layout::BothStretch(1, 1, 1, 1)); mColorPickAreaHandle = o2UI.CreateImage("ui/circle_hole_handle.png"); *mColorPickAreaHandle->layout = WidgetLayout::Based(BaseCorner::Center, Vec2F(15, 15)); pickArea->AddChild(mColorPickAreaHandle); pickAreaContainer->AddChild(pickArea); mWindow->AddChild(pickAreaContainer); mColorPickHandle = mmake(); mColorPickAreaHandle->onDraw += [&]() { mColorPickHandle->OnDrawn(); }; mColorPickHandle->isUnderPoint = [&](const Vec2F& point) { return mColorPickAreaColor->IsUnderPoint(point); }; mColorPickHandle->onMoved = MakeFunction(this, &ColorPickerDlg::OnColorPickHandleMoved); } void ColorPickerDlg::InitializeColorParams() { auto colorParamsArea = mmake(); *colorParamsArea->layout = WidgetLayout(Vec2F(0.0f, 0.0f), Vec2F(1.0f, 0.5f), Vec2F(0, 0), Vec2F(0, 0)); colorParamsArea->border = BorderF(5, 5, 5, 5); // HSL/RGB sliders auto hParamWidget = mColorHProperty.Initialize("Hue", ParameterType::H, Ref(this), [](float value, Color4& color) { float h, s, l; color.ToHSL(h, s, l); h = value; color.SetHSL(h, s, l); }, [](const Color4& color) { float h, s, l; color.ToHSL(h, s, l); return h; }, [](int x) { Color4 color; float h = x/255.0f, s = 1.0f, l = 0.5f; color.SetHSL(h, s, l); return color; }); auto sParamWidget = mColorSProperty.Initialize("Saturation", ParameterType::S, Ref(this), [](float value, Color4& color) { float h, s, l; color.ToHSL(h, s, l); s = value; color.SetHSL(h, s, l); }, [](const Color4& color) { float h, s, l; color.ToHSL(h, s, l); return s; }, [this](int x) { Color4 color = mColorValue; float h, s, l; color.ToHSL(h, s, l); s = x/255.0f; color.SetHSL(h, s, l); return color; }); auto lParamWidget = mColorLProperty.Initialize("Lightness", ParameterType::L, Ref(this), [](float value, Color4& color) { float h, s, l; color.ToHSL(h, s, l); l = value; color.SetHSL(h, s, l); }, [](const Color4& color) { float h, s, l; color.ToHSL(h, s, l); return l; }, [this](int x) { Color4 color = mColorValue; float h, s, l; color.ToHSL(h, s, l); l = x/255.0f; color.SetHSL(h, s, l); return color; }); auto rParamWidget = mColorRProperty.Initialize("Red", ParameterType::R, Ref(this), [](float value, Color4& color) { color.r = (int)(value*255.0f); }, [](const Color4& color) { return color.r/255.0f; }, [this](int x) { return Color4(x, mColorValue.g, mColorValue.b, mColorValue.a); }); auto gParamWidget = mColorGProperty.Initialize("Green", ParameterType::G, Ref(this), [](float value, Color4& color) { color.g = (int)(value*255.0f); }, [](const Color4& color) { return color.g/255.0f; }, [this](int x) { return Color4(mColorValue.r, x, mColorValue.b, mColorValue.a); }); auto bParamWidget = mColorBProperty.Initialize("Blue", ParameterType::B, Ref(this), [](float value, Color4& color) { color.b = (int)(value*255.0f); }, [](const Color4& color) { return color.b/255.0f; }, [this](int x) { return Color4(mColorValue.r, mColorValue.g, x, mColorValue.a); }); auto aParamWidget = mColorAProperty.Initialize("Alpha", ParameterType::A, Ref(this), [](float value, Color4& color) { color.a = (int)(value*255.0f); }, [](const Color4& color) { return color.a/255.0f; }, [this](int x) { return Color4(mColorValue.r, mColorValue.g, mColorValue.b, x); }); // RGBA auto rgbaContainer = mmake(); auto rgbaLabel = o2UI.CreateLabel("RGBA"); *rgbaLabel->layout = WidgetLayout::Based(BaseCorner::Left, Vec2F(100, 20)); rgbaLabel->horAlign = HorAlign::Left; rgbaContainer->AddChild(rgbaLabel); mRGBAEditBox = o2UI.CreateEditBox("singleline"); *mRGBAEditBox->layout = WidgetLayout::HorStretch(VerAlign::Middle, 100, 0, 20); mRGBAEditBox->onChangeCompleted = [&](const WString& text) { OnColorEditBoxRGBAChanged((String)text); }; rgbaContainer->AddChild(mRGBAEditBox); // HEX auto hexContainer = mmake(); auto hexLabel = o2UI.CreateLabel("HEX"); *hexLabel->layout = WidgetLayout::Based(BaseCorner::Left, Vec2F(100, 20)); hexLabel->horAlign = HorAlign::Left; hexContainer->AddChild(hexLabel); mHEXEditBox = o2UI.CreateEditBox("singleline"); *mHEXEditBox->layout = WidgetLayout::HorStretch(VerAlign::Middle, 100, 0, 20); mHEXEditBox->onChangeCompleted = [&](const WString& text) { OnColorEditBoxHEXChanged((String)text); }; hexContainer->AddChild(mHEXEditBox); colorParamsArea->AddChild(hParamWidget); colorParamsArea->AddChild(sParamWidget); colorParamsArea->AddChild(lParamWidget); colorParamsArea->AddChild(rParamWidget); colorParamsArea->AddChild(gParamWidget); colorParamsArea->AddChild(bParamWidget); colorParamsArea->AddChild(aParamWidget); colorParamsArea->AddChild(rgbaContainer); colorParamsArea->AddChild(hexContainer); mWindow->AddChild(colorParamsArea); } void ColorPickerDlg::OnColorPickHandleMoved(const Input::Cursor& cursor) { auto rt = mColorPickAreaColor->GetRect(); Vec2F anchorPos = (cursor.position - rt.LeftBottom())/rt.Size(); anchorPos.x = Math::Clamp01(anchorPos.x); anchorPos.y = Math::Clamp01(anchorPos.y); mColorPickAreaHandle->layout->anchorMin = anchorPos; mColorPickAreaHandle->layout->anchorMax = anchorPos; mColorValue.SetHSL(mColorHProperty.progressBar->value, anchorPos.y, anchorPos.x); UpdateValues(ParameterType::Picker); OnColorChanged(ParameterType::Picker); } void ColorPickerDlg::UpdateColorPickHandle() { auto rt = mColorPickAreaColor->GetRect(); float h, s, l; mColorValue.ToHSL(h, s, l); Vec2F anchorPos = Vec2F(l, s); anchorPos.x = Math::Clamp01(anchorPos.x); anchorPos.y = Math::Clamp01(anchorPos.y); mColorPickAreaHandle->layout->anchorMin = anchorPos; mColorPickAreaHandle->layout->anchorMax = anchorPos; } void ColorPickerDlg::UpdateColorEditBoxeRGBA() { String rgbaText = String::Format("%d, %d, %d, %d", mColorValue.r, mColorValue.g, mColorValue.b, mColorValue.a); mRGBAEditBox->text = (WString)rgbaText; } void ColorPickerDlg::UpdateColorEditBoxHEX() { String hexText = String::Format("#%02X%02X%02X%02X", mColorValue.r, mColorValue.g, mColorValue.b, mColorValue.a); mHEXEditBox->text = (WString)hexText; } void ColorPickerDlg::OnColorEditBoxRGBAChanged(const String& text) { Vector splitText; // Split string by any non-digit character String buffer; for (int i = 0; i < text.Length(); i++) { if (text[i] >= '0' && text[i] <= '9') buffer += text[i]; else { if (buffer.Length() > 0) splitText.Add(buffer); buffer.Clear(); } } // Get available values float r = splitText.Count() > 0 ? (float)splitText[0]/255.0f : 1.0f; float g = splitText.Count() > 1 ? (float)splitText[1]/255.0f : 1.0f; float b = splitText.Count() > 2 ? (float)splitText[2]/255.0f : 1.0f; float a = splitText.Count() > 3 ? (float)splitText[3]/255.0f : 1.0f; // Update color value mColorValue = Color4(r, g, b, a); UpdateValues(ParameterType::RGBABox); } void ColorPickerDlg::OnColorEditBoxHEXChanged(const String& text) { // Extract hex string String hexText = text.Length() > 0 && text[0] == '#' ? text.SubStr(1) : text; UInt32 hexValue = 0; // Convert hex string to integer for (int i = 0; i < hexText.Length(); i++) { hexValue <<= 4; if (hexText[i] >= '0' && hexText[i] <= '9') hexValue += hexText[i] - '0'; else if (hexText[i] >= 'A' && hexText[i] <= 'F') hexValue += hexText[i] - 'A' + 10; else if (hexText[i] >= 'a' && hexText[i] <= 'f') hexValue += hexText[i] - 'a' + 10; } // Update color value mColorValue.r = (hexValue >> 24) & 0xFF; mColorValue.g = (hexValue >> 16) & 0xFF; mColorValue.b = (hexValue >> 8) & 0xFF; mColorValue.a = hexValue & 0xFF; UpdateValues(ParameterType::HEXBox); } void ColorPickerDlg::OnColorChanged(ParameterType changedParameter) { mOnChangedCallback(mColorValue, true); UpdateValues(changedParameter); } void ColorPickerDlg::UpdateValues(ParameterType changedParameter) { mColorSampleImage->GetImage()->SetColor(mColorValue); if (changedParameter != ParameterType::S && changedParameter != ParameterType::L && changedParameter != ParameterType::Picker) mColorHProperty.UpdateValue(mColorValue); if (changedParameter != ParameterType::H && changedParameter != ParameterType::L) mColorSProperty.UpdateValue(mColorValue); if (changedParameter != ParameterType::H && changedParameter != ParameterType::S) mColorLProperty.UpdateValue(mColorValue); mColorRProperty.UpdateValue(mColorValue); mColorGProperty.UpdateValue(mColorValue); mColorBProperty.UpdateValue(mColorValue); mColorAProperty.UpdateValue(mColorValue); if (changedParameter == ParameterType::H || changedParameter == ParameterType::S || changedParameter == ParameterType::L) mColorValue.SetHSL(mColorHProperty.progressBar->value, mColorSProperty.progressBar->value, mColorLProperty.progressBar->value); UpdateColorPickBitmap(); if (changedParameter != ParameterType::Picker) UpdateColorPickHandle(); if (changedParameter != ParameterType::RGBABox) UpdateColorEditBoxeRGBA(); if (changedParameter != ParameterType::HEXBox) UpdateColorEditBoxHEX(); } void ColorPickerDlg::UpdateColorPickBitmap() { float h = mColorHProperty.progressBar->value; Vec2I sz = mColorPickAreaBitmap->GetSize(); for (int i = 0; i < sz.x; i++) { for (int j = 0; j < sz.y; j++) { Color4 c; c.SetHSL(h, (float)i/(float)sz.x, (float)j/(float)sz.y); UInt cc = c.ABGR(); memcpy(mColorPickAreaBitmap->GetData() + 4*i*sz.x + 4*j, &cc, 4); } } mColorPickAreaTexture->SetData(*mColorPickAreaBitmap); } void ColorPickerDlg::OnCursorPressedOutside() { mOnChangedCallback(mColorValue, true); mWindow->Hide(); } Ref ColorPickerDlg::ColorProperty::Initialize(const String& name, ParameterType type, const Ref& dialog, const Function& setValue, const Function& getValue, const Function& updateBitmap) { this->dialog = dialog; this->type = type; this->setValue = setValue; this->getValue = getValue; this->updateBitmap = updateBitmap; auto resLayout = mmake(); nameLabel = o2UI.CreateLabel(name); *nameLabel->layout = WidgetLayout::Based(BaseCorner::Left, Vec2F(100, 20)); nameLabel->horAlign = HorAlign::Left; resLayout->AddChild(nameLabel); progressBar = o2UI.CreateWidget("wide"); *progressBar->layout = WidgetLayout::HorStretch(VerAlign::Middle, 100, 50, 20); progressBar->onChangeByUser = [&](float v) { OnProgressBarChanged(v); }; bitmap = mmake(PixelFormat::R8G8B8A8, Vec2F(256, 256)); progressBarTexture = TextureRef(*bitmap); progressBar->AddLayer("color", mmake(progressBarTexture, RectI(0, 0, 256, 256)), Layout::BothStretch(1, 1, 1, 1), 0.5f); auto backSprite = mmake(dialog->mChessBackTexture, RectI(0, 0, 20, 20)); backSprite->mode = SpriteMode::Tiled; progressBar->AddLayer("colorBack", backSprite, Layout::BothStretch(1, 1, 1, 1), 0.4f); resLayout->AddChild(progressBar); editBox = o2UI.CreateEditBox("singleline"); *editBox->layout = WidgetLayout::Based(BaseCorner::Right, Vec2F(45, 20)); editBox->SetFilterInteger(); editBox->onChangeCompleted = [&](const WString& text) { progressBar->SetValue(((float)text/255.0f)); }; resLayout->AddChild(editBox); return resLayout; } void ColorPickerDlg::ColorProperty::UpdateValue(const Color4& value) { if (mChanging) return; progressBar->SetValue(getValue(value)); editBox->text = (WString)(int)(getValue(value)*255.0f); UpdateBitmap(); } void ColorPickerDlg::ColorProperty::OnProgressBarChanged(float value) { mChanging = true; if (auto dialog = this->dialog.Lock()) { setValue(value, dialog->mColorValue); editBox->text = (WString)(int)(value*255.0f); dialog->OnColorChanged(type); } mChanging = false; } void ColorPickerDlg::ColorProperty::UpdateBitmap() { int bpp = 4; UInt8* c1 = bitmap->GetData(); int h = bitmap->GetSize().y; int w = bitmap->GetSize().x; for (int i = 0; i < 256; i++) *(ULong*)(c1 + bpp*i) = updateBitmap(i).ABGR(); for (int i = 1; i < h; i++) memcpy(c1 + bpp*w*i, c1, bpp*w); progressBarTexture->SetData(*bitmap); } } // --- META --- ENUM_META(Editor::ColorPickerDlg::ParameterType, Editor__ColorPickerDlg__ParameterType) { ENUM_ENTRY(A); ENUM_ENTRY(B); ENUM_ENTRY(G); ENUM_ENTRY(General); ENUM_ENTRY(H); ENUM_ENTRY(HEXBox); ENUM_ENTRY(L); ENUM_ENTRY(Picker); ENUM_ENTRY(R); ENUM_ENTRY(RGBABox); ENUM_ENTRY(S); } END_ENUM_META; // --- END META --- ================================================ FILE: Editor/Sources/o2Editor/Dialogs/ColorPickerDlg.h ================================================ #pragma once #include "o2/Events/CursorEventsArea.h" #include "o2/Events/CursorAreaEventsListener.h" #include "o2/Render/TextureRef.h" #include "o2/Utils/Function/Function.h" #include "o2/Utils/Math/Color.h" #include "o2/Utils/Singleton.h" using namespace o2; namespace o2 { class Bitmap; class DropDown; class EditBox; class HorizontalProgress; class Image; class Label; class VerticalProgress; class Widget; class WidgetLayer; class Window; } namespace Editor { // -------------------- // Color picking dialog // -------------------- class ColorPickerDlg : public Singleton, public CursorEventsListener { public: enum class ParameterType { H, S, L, R, G, B, A, General, Picker, RGBABox, HEXBox }; public: // Default constructor ColorPickerDlg(RefCounter* refCounter); // Destructor ~ColorPickerDlg(); // Shows color picking window. Delegate onChanged is called when color changed and onCompleted when ok pressed static void Show(const Color4& color, const Function& onChanged, const Function& onCompleted = {}); REF_COUNTERABLE_IMPL(Singleton, CursorEventsListener); protected: struct ColorProperty { WeakRef dialog; ParameterType type; Ref