hap-cli 0.8.18__tar.gz → 0.8.19__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hap_cli-0.8.18 → hap_cli-0.8.19}/PKG-INFO +1 -1
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/__init__.py +1 -1
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/record.py +82 -19
- hap_cli-0.8.19/hap_cli/tests/test_member_relation_array_wrap.py +103 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli.egg-info/PKG-INFO +1 -1
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli.egg-info/SOURCES.txt +1 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/MANIFEST.in +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/README.md +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/app_live_tests/__init__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/app_live_tests/__main__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/app_live_tests/config.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/app_live_tests/harness.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/app_live_tests/smoke.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/app_live_tests/state.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/README.md +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/README_CN.md +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/__main__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/__init__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/app_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/app_creator_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/app_editor_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/auth_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/calendar_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/chart_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/chat_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/chatbot_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/config_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/contact_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/department_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/group_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/icon_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/instance_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/node_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/optionset_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/page_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/post_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/record_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/region_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/role_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/update_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/upload_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/v3_registry.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/workflow_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/commands/worksheet_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/context.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/__init__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/action_spec_adapter.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/__init__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/_hapmeta/__init__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/_hapmeta/control_type_codes.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/_hapmeta/worksheet_templates.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/charts.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/cleanup.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/compiler.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/config.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/design/design.schema.json +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/errors.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/examples/minimal.design.json +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/executor.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/fields.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/hap.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/merge.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/recording/__init__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/recording/console.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/recording/jsonl.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/recording/mirror.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/recording/report.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/schema.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/seed/INSTRUCTIONS.md +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/seed/__init__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/seed/cli.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/seed/executor.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/seed/resources/attachments.json +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/seed/resources/sample.docx +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/seed/resources/sample.pdf +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/seed/resources/sample_images.json +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/seed/template.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/selftest.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/smoke.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/steps.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/store.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/validate.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/workflow_dsl.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/auth.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/calendar_mod.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/chart.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/chat.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/chatbot.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/cli_access.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/contact.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/control_type_codes.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/department.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/editor/__init__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/editor/_hapmeta/__init__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/editor/_hapmeta/control_type_codes.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/editor/apply.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/editor/componentlower.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/editor/editspec.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/editor/errors.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/editor/fieldlower.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/editor/jsonschema_mini.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/editor/models.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/editor/ops.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/editor/planner.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/editor/reader.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/field_normalizer.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/field_spec_adapter.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/filter_translator.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/flow_node.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/global_meta.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/group.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/icon_index.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/instance.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/logger.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/optionset.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/page.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/post.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/response_crypto.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/role.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/role_perm_builder.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/session.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/token_crypto.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/update.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/upload.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/v3/__init__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/v3/dispatcher.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/v3/render.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/v3/schema.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/view_spec_adapter.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/workflow.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/workflow_node_dsl.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/worksheet.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/worksheet_templates.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/hap_cli.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/i18n.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/locale/__init__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/locale/messages.json +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/locale/messages.schema.json +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/__init__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/conftest.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_app_creator.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_app_editor.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_app_export_usage.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_auth_prerelease.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_bug_036430.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_bug_036750.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_chart.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_cli_access.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_config_cmd.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_core.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_destructive_confirm_cli.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_full_e2e.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_global_meta.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_i18n.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_instance_history_cli.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_integration.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_integration_approval.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_integration_approval_actions.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_integration_calendar.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_integration_destructive.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_integration_misc.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_integration_post.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_integration_social.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_integration_v3.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_integration_workflow.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_integration_worksheet_extra.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_multi_profile.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_org_approval_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_org_id_cli.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_org_id_docs.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_parameter_conventions.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_parameter_mapping_registry.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_record_batch_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_record_field_alias.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_record_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_select_rejects_relation_value.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_semantic_types_registry.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_update.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_v3_api_schema_loader.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_v3_dispatcher.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_v3_registry_coverage.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_v3_session.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_v3_yaml_translation.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_workflow_list_cli.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_workflow_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_worksheet_crud_cli.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/tests/test_worksheet_v3_semantic_cli.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/utils/__init__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/utils/formatting.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/utils/options.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/utils/parameter_mapping.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli.egg-info/dependency_links.txt +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli.egg-info/entry_points.txt +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli.egg-info/requires.txt +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli.egg-info/top_level.txt +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/__init__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/__main__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/_wftest.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/charts.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/cleanup.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/compiler.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/config.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/errors.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/executor.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/fields.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/hap.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/recording/__init__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/recording/console.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/recording/jsonl.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/recording/mirror.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/recording/report.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/schema.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/seed/__init__.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/seed/cli.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/seed/executor.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/seed/template.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/selftest.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/smoke.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/step.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/steps.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/store.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/live_tests/workflow_dsl.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/setup.cfg +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/setup.py +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/skills/cli/hap-cli-app-editor/scripts/editspec/component.schema.json +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/skills/cli/hap-cli-app-editor/scripts/editspec/custom-action.schema.json +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/skills/cli/hap-cli-app-editor/scripts/editspec/envelope.schema.json +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/skills/cli/hap-cli-app-editor/scripts/editspec/field.schema.json +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/INDEX.json +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/add_member_to_role.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/batch_delete_records.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/create_optionset.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/create_role.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/delete_optionset.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/delete_record.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/delete_role.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/delete_worksheet.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/get_app_info.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/get_app_knowledge_list.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/get_app_worksheets_list.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/get_optionset_list.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/get_record_details.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/get_record_discussions.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/get_record_list.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/get_record_logs.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/get_record_pivot_data.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/get_record_relations.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/get_record_share_link.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/get_regions.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/get_role_details.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/get_role_list.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/knowledge_search.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/leave_all_roles.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/remove_member_from_role.yaml +0 -0
- {hap_cli-0.8.18 → hap_cli-0.8.19}/sources/v3-api-schema/update_optionset.yaml +0 -0
|
@@ -259,6 +259,67 @@ def _legacy_cell_entry(
|
|
|
259
259
|
return {"value": _legacy_cell_value(ctrl, value)}
|
|
260
260
|
|
|
261
261
|
|
|
262
|
+
def _coerce_entity_ids(
|
|
263
|
+
value: Any, id_keys: tuple[str, ...], *, field_label: str,
|
|
264
|
+
) -> list[str]:
|
|
265
|
+
"""Flatten a member / department / org-role / relation cell value to a
|
|
266
|
+
list of id strings, ready to be wrapped as ``[{idKey: id}, ...]``.
|
|
267
|
+
|
|
268
|
+
Accepts every realistic input shape so callers never have to pre-shape:
|
|
269
|
+
* a scalar id, or comma-separated ids (``"a,b"``);
|
|
270
|
+
* a list/tuple mixing ids and ``{idKey: ...}`` objects;
|
|
271
|
+
* a single ``{idKey: ...}`` object — the ``get_records`` read-back
|
|
272
|
+
shape carries display fields (``fullname`` / ``avatar`` / ``name``)
|
|
273
|
+
too, so only the id is kept;
|
|
274
|
+
* a JSON-array/object *string* of the above (e.g. a value copied
|
|
275
|
+
straight out of a record dump).
|
|
276
|
+
|
|
277
|
+
``id_keys`` lists the accepted id field names in priority order, e.g.
|
|
278
|
+
``("accountId", "aid")`` for USER_PICKER. An object that carries none of
|
|
279
|
+
them fails loudly instead of being ``str()``-mangled into a junk id —
|
|
280
|
+
that silent mangling sent garbage members to the server before.
|
|
281
|
+
"""
|
|
282
|
+
if value is None or value == "":
|
|
283
|
+
return []
|
|
284
|
+
# A JSON-array/object string is parsed structurally rather than
|
|
285
|
+
# comma-split (a member object's JSON has commas inside it).
|
|
286
|
+
if isinstance(value, str):
|
|
287
|
+
s = value.strip()
|
|
288
|
+
if s[:1] in ("[", "{"):
|
|
289
|
+
try:
|
|
290
|
+
value = json.loads(s)
|
|
291
|
+
except (ValueError, TypeError):
|
|
292
|
+
pass
|
|
293
|
+
if isinstance(value, dict):
|
|
294
|
+
items: list[Any] = [value]
|
|
295
|
+
elif isinstance(value, (list, tuple)):
|
|
296
|
+
items = list(value)
|
|
297
|
+
else:
|
|
298
|
+
items = [p for p in str(value).split(",") if p.strip() != ""]
|
|
299
|
+
out: list[str] = []
|
|
300
|
+
for it in items:
|
|
301
|
+
if isinstance(it, dict):
|
|
302
|
+
rid = next(
|
|
303
|
+
(str(it[k]) for k in id_keys if it.get(k) not in (None, "")),
|
|
304
|
+
None,
|
|
305
|
+
)
|
|
306
|
+
if rid is None:
|
|
307
|
+
raise ValueError(
|
|
308
|
+
f"Field '{field_label}': object value is missing an id "
|
|
309
|
+
f"field ({'/'.join(id_keys)}): {it!r}"
|
|
310
|
+
)
|
|
311
|
+
out.append(rid)
|
|
312
|
+
elif isinstance(it, (list, tuple)):
|
|
313
|
+
raise ValueError(
|
|
314
|
+
f"Field '{field_label}': nested array is not a valid id: {it!r}"
|
|
315
|
+
)
|
|
316
|
+
else:
|
|
317
|
+
s2 = str(it).strip()
|
|
318
|
+
if s2:
|
|
319
|
+
out.append(s2)
|
|
320
|
+
return out
|
|
321
|
+
|
|
322
|
+
|
|
262
323
|
def _legacy_cell_value(ctrl: dict[str, Any], value: Any) -> str:
|
|
263
324
|
"""Serialize one cell to the legacy receiveControls `value`
|
|
264
325
|
string, per the shapes proven in
|
|
@@ -271,14 +332,15 @@ def _legacy_cell_value(ctrl: dict[str, Any], value: Any) -> str:
|
|
|
271
332
|
if t == 10: # MULTI_SELECT
|
|
272
333
|
return json.dumps(_resolve_option_keys(ctrl, value), ensure_ascii=False)
|
|
273
334
|
|
|
335
|
+
label = _option_field_label(ctrl)
|
|
336
|
+
|
|
274
337
|
if t in (29, 35): # RELATE_SHEET / CASCADING_SELECT -> [{"sid": rowId}, ...]
|
|
275
338
|
# Cascade (35) is a relation to a row in another worksheet, persisted
|
|
276
339
|
# the same way as a plain relate (29): an array of {"sid": rowId}. A
|
|
277
|
-
# bare rowId makes the server answer "服务异常" (bug #642cc8).
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
ids = [s for s in str(value).split(",") if s != ""]
|
|
340
|
+
# bare rowId makes the server answer "服务异常" (bug #642cc8). Object
|
|
341
|
+
# inputs ({"sid": rowId, ...} read-back shape) keep only the sid.
|
|
342
|
+
ids = _coerce_entity_ids(value, ("sid", "rowid", "rowId"),
|
|
343
|
+
field_label=label)
|
|
282
344
|
return json.dumps([{"sid": rid} for rid in ids], ensure_ascii=False)
|
|
283
345
|
|
|
284
346
|
if t == 48: # ORG_ROLE -> [{"organizeId": id}, ...]
|
|
@@ -286,20 +348,21 @@ def _legacy_cell_value(ctrl: dict[str, Any], value: Any) -> str:
|
|
|
286
348
|
# of {"organizeId": id} objects; organizeName is display-only and the
|
|
287
349
|
# server resolves it from the id. A bare organizeId is rejected with
|
|
288
350
|
# "服务异常" (bug #642cc8). See pd-openweb CellControls/OrgRole.jsx.
|
|
289
|
-
ids =
|
|
290
|
-
|
|
291
|
-
return json.dumps([{"organizeId":
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
351
|
+
ids = _coerce_entity_ids(value, ("organizeId", "id"),
|
|
352
|
+
field_label=label)
|
|
353
|
+
return json.dumps([{"organizeId": i} for i in ids], ensure_ascii=False)
|
|
354
|
+
|
|
355
|
+
if t == 26: # USER_PICKER -> always an array of {"accountId": id}, even
|
|
356
|
+
# for a single member. Object inputs (the full member object the UI
|
|
357
|
+
# holds / get_records returns: {accountId, fullname, avatar, ...})
|
|
358
|
+
# are reduced to their accountId — a bare object would fail the save.
|
|
359
|
+
ids = _coerce_entity_ids(value, ("accountId", "aid"),
|
|
360
|
+
field_label=label)
|
|
361
|
+
return json.dumps([{"accountId": i} for i in ids], ensure_ascii=False)
|
|
362
|
+
if t == 27: # DEPARTMENT -> [{"departmentId": id}, ...]
|
|
363
|
+
ids = _coerce_entity_ids(value, ("departmentId", "id"),
|
|
364
|
+
field_label=label)
|
|
365
|
+
return json.dumps([{"departmentId": i} for i in ids],
|
|
303
366
|
ensure_ascii=False)
|
|
304
367
|
|
|
305
368
|
if t == 36: # SWITCH / checkbox
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""Member / department / org-role / relation cells must always serialize
|
|
2
|
+
to a JSON *array* of id objects, and must accept object-shaped inputs.
|
|
3
|
+
|
|
4
|
+
A USER_PICKER (26) cell is always an array, even for a single member
|
|
5
|
+
(evidence: a bare ``{"accountId":...}`` object on AddWorksheetRow fails
|
|
6
|
+
server-side). hap-cli's encoder already wraps scalars in an array, but it
|
|
7
|
+
mangled object-shaped inputs: ``[{"accountId": str(i)} for i in value]``
|
|
8
|
+
ran ``str()`` over a whole member dict when the value was a member object
|
|
9
|
+
or — the natural ``get_records`` read-back shape — a list of member
|
|
10
|
+
objects ``[{"accountId","fullname","avatar",...}]``. The id is now
|
|
11
|
+
extracted from such objects and the cell is always emitted as an array.
|
|
12
|
+
|
|
13
|
+
The same fix covers DEPARTMENT (27, ``departmentId``), ORG_ROLE
|
|
14
|
+
(48, ``organizeId``) and RELATE_SHEET/CASCADING (29/35, ``sid``).
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
|
|
19
|
+
import pytest
|
|
20
|
+
|
|
21
|
+
from hap_cli.core import record as rec_mod
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _val(type_code, value):
|
|
25
|
+
return rec_mod._legacy_cell_value({"type": type_code, "controlName": "f"}, value)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TestUserPickerAlwaysArray:
|
|
29
|
+
def test_single_account_id_string(self):
|
|
30
|
+
assert _val(26, "a1") == '[{"accountId": "a1"}]'
|
|
31
|
+
|
|
32
|
+
def test_comma_separated_ids(self):
|
|
33
|
+
assert _val(26, "a1,a2") == '[{"accountId": "a1"}, {"accountId": "a2"}]'
|
|
34
|
+
|
|
35
|
+
def test_list_of_ids(self):
|
|
36
|
+
assert _val(26, ["a1", "a2"]) == \
|
|
37
|
+
'[{"accountId": "a1"}, {"accountId": "a2"}]'
|
|
38
|
+
|
|
39
|
+
def test_single_member_object_keeps_only_account_id(self):
|
|
40
|
+
v = {"accountId": "a1", "fullname": "林梦阳", "name": "林梦阳",
|
|
41
|
+
"avatar": "https://x", "avatarMiddle": "https://y"}
|
|
42
|
+
assert _val(26, v) == '[{"accountId": "a1"}]'
|
|
43
|
+
|
|
44
|
+
def test_list_of_member_objects_readback_shape(self):
|
|
45
|
+
v = [{"accountId": "a1", "fullname": "甲", "avatar": "u1"},
|
|
46
|
+
{"accountId": "a2", "fullname": "乙", "avatar": "u2"}]
|
|
47
|
+
assert _val(26, v) == \
|
|
48
|
+
'[{"accountId": "a1"}, {"accountId": "a2"}]'
|
|
49
|
+
|
|
50
|
+
def test_json_array_of_objects_string(self):
|
|
51
|
+
v = json.dumps([{"accountId": "a1", "fullname": "甲"}])
|
|
52
|
+
assert _val(26, v) == '[{"accountId": "a1"}]'
|
|
53
|
+
|
|
54
|
+
def test_json_object_string(self):
|
|
55
|
+
v = json.dumps({"accountId": "a1", "fullname": "甲"})
|
|
56
|
+
assert _val(26, v) == '[{"accountId": "a1"}]'
|
|
57
|
+
|
|
58
|
+
def test_member_object_without_account_id_rejected(self):
|
|
59
|
+
with pytest.raises(ValueError):
|
|
60
|
+
_val(26, {"fullname": "甲", "avatar": "u"})
|
|
61
|
+
|
|
62
|
+
def test_empty_is_empty_array(self):
|
|
63
|
+
assert _val(26, "") == "[]"
|
|
64
|
+
assert _val(26, None) == "[]"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class TestDepartmentObjectShape:
|
|
68
|
+
def test_object_keeps_department_id(self):
|
|
69
|
+
v = {"departmentId": "d1", "departmentName": "研发"}
|
|
70
|
+
assert _val(27, v) == '[{"departmentId": "d1"}]'
|
|
71
|
+
|
|
72
|
+
def test_list_of_objects(self):
|
|
73
|
+
v = [{"departmentId": "d1"}, {"departmentId": "d2"}]
|
|
74
|
+
assert _val(27, v) == \
|
|
75
|
+
'[{"departmentId": "d1"}, {"departmentId": "d2"}]'
|
|
76
|
+
|
|
77
|
+
def test_plain_id_still_works(self):
|
|
78
|
+
assert _val(27, "d1") == '[{"departmentId": "d1"}]'
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class TestOrgRoleObjectShape:
|
|
82
|
+
def test_object_keeps_organize_id(self):
|
|
83
|
+
v = {"organizeId": "o1", "organizeName": "主管"}
|
|
84
|
+
assert _val(48, v) == '[{"organizeId": "o1"}]'
|
|
85
|
+
|
|
86
|
+
def test_plain_id_still_works(self):
|
|
87
|
+
assert _val(48, "o1") == '[{"organizeId": "o1"}]'
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class TestRelateObjectShape:
|
|
91
|
+
def test_relate_object_keeps_sid(self):
|
|
92
|
+
v = {"sid": "row1", "name": "记录甲"}
|
|
93
|
+
assert _val(29, v) == '[{"sid": "row1"}]'
|
|
94
|
+
|
|
95
|
+
def test_relate_list_of_objects_readback(self):
|
|
96
|
+
v = [{"sid": "row1", "name": "甲"}, {"sid": "row2", "name": "乙"}]
|
|
97
|
+
assert _val(29, v) == '[{"sid": "row1"}, {"sid": "row2"}]'
|
|
98
|
+
|
|
99
|
+
def test_relate_plain_rowid_still_works(self):
|
|
100
|
+
assert _val(29, "row1") == '[{"sid": "row1"}]'
|
|
101
|
+
|
|
102
|
+
def test_cascading_object_keeps_sid(self):
|
|
103
|
+
assert _val(35, {"sid": "row1"}) == '[{"sid": "row1"}]'
|
|
@@ -168,6 +168,7 @@ hap_cli/tests/test_integration_social.py
|
|
|
168
168
|
hap_cli/tests/test_integration_v3.py
|
|
169
169
|
hap_cli/tests/test_integration_workflow.py
|
|
170
170
|
hap_cli/tests/test_integration_worksheet_extra.py
|
|
171
|
+
hap_cli/tests/test_member_relation_array_wrap.py
|
|
171
172
|
hap_cli/tests/test_multi_profile.py
|
|
172
173
|
hap_cli/tests/test_org_approval_v3_semantic_cli.py
|
|
173
174
|
hap_cli/tests/test_org_id_cli.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hap_cli-0.8.18 → hap_cli-0.8.19}/hap_cli/core/app_creator/seed/resources/sample_images.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|