From d9ac7d14f08ad5e7eb3acda2c1c285be9656f721 Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Tue, 29 Sep 2020 20:21:15 +0200 Subject: [PATCH 01/30] fixes #156 --- .../y_check_prefer_case_to_elseif.clas.abap | 30 ++-- ...refer_case_to_elseif.clas.testclasses.abap | 132 ++++++++++++++++++ src/y_code_pal_version.intf.abap | 2 +- 3 files changed, 152 insertions(+), 12 deletions(-) diff --git a/src/checks/y_check_prefer_case_to_elseif.clas.abap b/src/checks/y_check_prefer_case_to_elseif.clas.abap index 90a60d28..cd9ef033 100644 --- a/src/checks/y_check_prefer_case_to_elseif.clas.abap +++ b/src/checks/y_check_prefer_case_to_elseif.clas.abap @@ -7,7 +7,8 @@ CLASS y_check_prefer_case_to_elseif DEFINITION PUBLIC INHERITING FROM y_check_ba PRIVATE SECTION. TYPES: BEGIN OF counter, if_structure TYPE sstruc, - if_statement TYPE sstmnt, + if_statement type sstmnt, + condition TYPE string, count TYPE i, END OF counter. TYPES counters TYPE TABLE OF counter. @@ -19,7 +20,7 @@ ENDCLASS. -CLASS y_check_prefer_case_to_elseif IMPLEMENTATION. +CLASS Y_CHECK_PREFER_CASE_TO_ELSEIF IMPLEMENTATION. METHOD constructor. @@ -42,26 +43,34 @@ CLASS y_check_prefer_case_to_elseif IMPLEMENTATION. DATA(tokens) = ref_scan_manager->get_tokens( ). LOOP AT structures ASSIGNING FIELD-SYMBOL() - WHERE type EQ scan_struc_type-condition. + WHERE type = scan_struc_type-condition + OR type = scan_struc_type-alternation. IF skip( ) = abap_true. CONTINUE. ENDIF. - DATA(structure) = structures[ -back ]. - DATA(statement) = statements[ structure-stmnt_from ]. + DATA(statement) = statements[ -stmnt_from ]. DATA(token) = tokens[ statement-from ]. - IF token-str <> 'IF'. + DATA(if_structure) = COND #( WHEN token-str = 'IF' THEN + WHEN token-str = 'ELSEIF' THEN structures[ -back ] ). + + IF if_structure IS INITIAL. CONTINUE. ENDIF. + DATA(condition) = tokens[ statement-from + 1 ]. + TRY. - counters[ if_statement = statement ]-count = counters[ if_statement = statement ]-count + 1. + counters[ if_structure = if_structure + condition = condition-str ]-count = counters[ if_structure = if_structure + condition = condition-str ]-count + 1. CATCH cx_sy_itab_line_not_found. counters = VALUE #( BASE counters - ( if_structure = structure - if_statement = statement + ( if_structure = if_structure + if_statement = statements[ if_structure-stmnt_from ] + condition = condition-str count = 1 ) ). ENDTRY. @@ -86,6 +95,7 @@ CLASS y_check_prefer_case_to_elseif IMPLEMENTATION. METHOD handle_result. LOOP AT counters ASSIGNING FIELD-SYMBOL(). + DATA(configuration) = detect_check_configuration( error_count = -count statement = -if_statement ). @@ -99,6 +109,4 @@ CLASS y_check_prefer_case_to_elseif IMPLEMENTATION. error_priority = configuration-prio ). ENDLOOP. ENDMETHOD. - - ENDCLASS. diff --git a/src/checks/y_check_prefer_case_to_elseif.clas.testclasses.abap b/src/checks/y_check_prefer_case_to_elseif.clas.testclasses.abap index 3a5f6d15..5491d1b0 100644 --- a/src/checks/y_check_prefer_case_to_elseif.clas.testclasses.abap +++ b/src/checks/y_check_prefer_case_to_elseif.clas.testclasses.abap @@ -196,3 +196,135 @@ CLASS ltc_multiples_if IMPLEMENTATION. ENDMETHOD. ENDCLASS. + + +CLASS ltc_multiple_conditions DEFINITION INHERITING FROM y_unit_test_base FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. + PROTECTED SECTION. + METHODS get_cut REDEFINITION. + METHODS get_code_with_issue REDEFINITION. + METHODS get_code_without_issue REDEFINITION. + METHODS get_code_with_exemption REDEFINITION. +ENDCLASS. + +CLASS ltc_multiple_conditions IMPLEMENTATION. + + METHOD get_cut. + result ?= NEW y_check_prefer_case_to_elseif( ). + ENDMETHOD. + + METHOD get_code_with_issue. + result = VALUE #( + ( 'REPORT y_example. ' ) + + ( ' START-OF-SELECTION. ' ) + ( ' DATA(value) = 0. ' ) + ( ' ' ) + ( | IF sy-langu = 'EN'. | ) + ( ' IF sy-mandt = 000. ' ) + ( ' value = 0. ' ) + ( ' ELSEIF sy-mandt = 100. ' ) + ( ' value = 1. ' ) + ( ' ELSEIF sy-mandt = 200. ' ) + ( ' value = 2. ' ) + ( ' ENDIF. ' ) + ( | ELSEIF sy-langu = 'DE'. | ) + ( ' IF sy-mandt = 300. ' ) + ( ' value = 3. ' ) + ( ' ELSEIF sy-mandt = 400. ' ) + ( ' value = 4. ' ) + ( ' ELSEIF sy-mandt = 500. ' ) + ( ' value = 5. ' ) + ( ' ELSEIF sy-mandt = 600. ' ) + ( ' value = 6. ' ) + ( ' ELSEIF sy-mandt = 700. ' ) + ( ' value = 7. ' ) + ( ' ENDIF. ' ) + ( | ELSEIF sy-langu = 'PT'. | ) + ( ' value = 8. ' ) + ( | ELSEIF sy-mandt = 100. | ) + ( ' value = 8. ' ) + ( | ELSEIF sy-mandt = 200. | ) + ( ' value = 8. ' ) + ( ' ENDIF. ' ) + ). + ENDMETHOD. + + METHOD get_code_without_issue. + result = VALUE #( + ( 'REPORT y_example. ' ) + + ( ' START-OF-SELECTION. ' ) + ( ' DATA(value) = 0. ' ) + ( ' ' ) + ( | IF sy-langu = 'EN'. | ) + ( ' CASE sy-mandt. ' ) + ( ' WHEN 000. ' ) + ( ' value = 0. ' ) + ( ' WHEN 100. ' ) + ( ' value = 1. ' ) + ( ' WHEN 200. ' ) + ( ' value = 2. ' ) + ( ' ENDCASE. ' ) + ( | ELSEIF sy-langu = 'DE'. | ) + ( ' CASE sy-mandt. ' ) + ( ' WHEN 300. ' ) + ( ' value = 3. ' ) + ( ' WHEN 400. ' ) + ( ' value = 4. ' ) + ( ' WHEN 500. ' ) + ( ' value = 5. ' ) + ( ' WHEN 600. ' ) + ( ' value = 6. ' ) + ( ' WHEN 700. ' ) + ( ' value = 7. ' ) + ( ' ENDCASE. ' ) + ( | ELSEIF sy-langu = 'PT'. | ) + ( ' value = 8. ' ) + ( | ELSEIF sy-mandt = 100. | ) + ( ' value = 8. ' ) + ( | ELSEIF sy-mandt = 200. | ) + ( ' value = 8. ' ) + ( ' ENDIF. ' ) + ). + + ENDMETHOD. + + METHOD get_code_with_exemption. + result = VALUE #( + ( 'REPORT y_example. ' ) + + ( ' START-OF-SELECTION. ' ) + ( ' DATA(value) = 0. ' ) + ( ' ' ) + ( | IF sy-langu = 'EN'. | ) + ( ' IF sy-mandt = 000. ' ) + ( ' value = 0. ' ) + ( ' ELSEIF sy-mandt = 100. ' ) + ( ' value = 1. ' ) + ( ' ELSEIF sy-mandt = 200. ' ) + ( ' value = 2. ' ) + ( ' ENDIF. ' ) + ( | ELSEIF sy-langu = 'DE'. | ) + ( ' IF sy-mandt = 300. "#EC PREFER_CASE ' ) + ( ' value = 3. ' ) + ( ' ELSEIF sy-mandt = 400. ' ) + ( ' value = 4. ' ) + ( ' ELSEIF sy-mandt = 500. ' ) + ( ' value = 5. ' ) + ( ' ELSEIF sy-mandt = 600. ' ) + ( ' value = 6. ' ) + ( ' ELSEIF sy-mandt = 700. ' ) + ( ' value = 7. ' ) + ( ' ENDIF. ' ) + ( | ELSEIF sy-langu = 'PT'. | ) + ( ' value = 8. ' ) + ( | ELSEIF sy-mandt = 100. | ) + ( ' value = 8. ' ) + ( | ELSEIF sy-mandt = 200. | ) + ( ' value = 8. ' ) + ( ' ENDIF. ' ) + ). + ENDMETHOD. + + +ENDCLASS. diff --git a/src/y_code_pal_version.intf.abap b/src/y_code_pal_version.intf.abap index be36c773..2d486691 100644 --- a/src/y_code_pal_version.intf.abap +++ b/src/y_code_pal_version.intf.abap @@ -1,3 +1,3 @@ INTERFACE y_code_pal_version PUBLIC. - CONSTANTS abap TYPE string VALUE '1.04.0' ##NO_TEXT. + CONSTANTS abap TYPE string VALUE '1.04.1' ##NO_TEXT. ENDINTERFACE. From edcea8403c6f45b414efad899c0e1586f56cb201 Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Tue, 29 Sep 2020 15:26:26 -0300 Subject: [PATCH 02/30] Update changelog.txt --- changelog.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog.txt b/changelog.txt index ec20ea9f..d3ab72f7 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,10 @@ Legend + : added - : removed +2020-09-30 v1.04.1 +------------------ +* Fixes #156 (Prefer CASE to ELSE IF) + 2020-09-22 v1.04.0 ------------------ + API to read version From c6f866f38812fd3a5104a31d4b8e2a248a06e33c Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Tue, 29 Sep 2020 15:27:25 -0300 Subject: [PATCH 03/30] Update changelog.txt --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index d3ab72f7..e97392b5 100644 --- a/changelog.txt +++ b/changelog.txt @@ -10,7 +10,7 @@ Legend 2020-09-30 v1.04.1 ------------------ -* Fixes #156 (Prefer CASE to ELSE IF) +* #156 2020-09-22 v1.04.0 ------------------ From 6917ebcdb5d0ff369e68f5e3e51f574211992ae9 Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Tue, 29 Sep 2020 21:16:58 +0200 Subject: [PATCH 04/30] enabling log in exemption table --- src/foundation/ytab_exemptions.tabl.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/foundation/ytab_exemptions.tabl.xml b/src/foundation/ytab_exemptions.tabl.xml index 4d94a28c..de0fa2dd 100644 --- a/src/foundation/ytab_exemptions.tabl.xml +++ b/src/foundation/ytab_exemptions.tabl.xml @@ -17,6 +17,7 @@ 5 APPL1 X + X X From 28d9685c39e14dabdd398a875338add49174de09 Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Tue, 29 Sep 2020 16:18:54 -0300 Subject: [PATCH 05/30] Update changelog.txt --- changelog.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index e97392b5..39baa9a5 100644 --- a/changelog.txt +++ b/changelog.txt @@ -10,7 +10,8 @@ Legend 2020-09-30 v1.04.1 ------------------ -* #156 ++ enabling table log for exemptions +* prefer case to else if (#156) 2020-09-22 v1.04.0 ------------------ From 6d0b75f92b5f8944ec3c99874a3c93aef0d8977d Mon Sep 17 00:00:00 2001 From: Steffen Date: Thu, 1 Oct 2020 15:01:44 +0200 Subject: [PATCH 06/30] Extend magic number check to find numbers in single quotes (#160) --- src/checks/y_check_magic_number.clas.abap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/checks/y_check_magic_number.clas.abap b/src/checks/y_check_magic_number.clas.abap index a226f9c2..a8a9f35a 100644 --- a/src/checks/y_check_magic_number.clas.abap +++ b/src/checks/y_check_magic_number.clas.abap @@ -103,7 +103,7 @@ CLASS Y_CHECK_MAGIC_NUMBER IMPLEMENTATION. RETURN. ENDIF. - FIND REGEX '^(?![01]$)\d*$' IN token_string. + FIND REGEX `^(?!'?[01]'?$)'?\d+'?$` IN token_string. IF sy-subrc EQ 0. magic_number = token_string. result = abap_true. From 3e42646c8a367b943358f76be93abf5499fe4e06 Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Thu, 1 Oct 2020 10:23:18 -0300 Subject: [PATCH 07/30] Update changelog.txt --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index 39baa9a5..544f0aed 100644 --- a/changelog.txt +++ b/changelog.txt @@ -10,6 +10,7 @@ Legend 2020-09-30 v1.04.1 ------------------ +* magic number to support numeric strings (#142) + enabling table log for exemptions * prefer case to else if (#156) From 686a21d39bb5dc68a773461b81a17c1ed749ecf7 Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Thu, 1 Oct 2020 18:16:48 +0200 Subject: [PATCH 08/30] fixes #154 --- .../y_check_non_class_exception.clas.abap | 62 +++++++++++-------- ..._non_class_exception.clas.testclasses.abap | 9 +++ 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/checks/y_check_non_class_exception.clas.abap b/src/checks/y_check_non_class_exception.clas.abap index fc549e1c..4b05871b 100644 --- a/src/checks/y_check_non_class_exception.clas.abap +++ b/src/checks/y_check_non_class_exception.clas.abap @@ -1,22 +1,18 @@ -CLASS y_check_non_class_exception DEFINITION - PUBLIC - INHERITING FROM y_check_base - CREATE PUBLIC . - +CLASS y_check_non_class_exception DEFINITION PUBLIC INHERITING FROM y_check_base CREATE PUBLIC . PUBLIC SECTION. - METHODS constructor . PROTECTED SECTION. METHODS inspect_tokens REDEFINITION. - + METHODS inspect_message IMPORTING statement TYPE sstmnt + index TYPE i. + METHODS inspect_raise IMPORTING statement TYPE sstmnt + index TYPE i. PRIVATE SECTION. - METHODS checkif_error - IMPORTING index TYPE i - statement TYPE sstmnt. + METHODS checkif_error IMPORTING index TYPE i + statement TYPE sstmnt. ENDCLASS. - CLASS Y_CHECK_NON_CLASS_EXCEPTION IMPLEMENTATION. @@ -47,19 +43,35 @@ CLASS Y_CHECK_NON_CLASS_EXCEPTION IMPLEMENTATION. METHOD inspect_tokens. - CASE get_token_abs( statement-from ). - WHEN 'RAISE'. - IF 'RESUMABLE SHORTDUMP EVENT' NS get_token_abs( statement-from + 1 ) AND NOT - ( get_token_abs( statement-from + 1 ) EQ 'EXCEPTION' AND get_token_abs( statement-from + 2 ) EQ 'TYPE' ). - checkif_error( index = index - statement = statement ). - ENDIF. - WHEN 'MESSAGE'. - LOOP AT ref_scan_manager->get_tokens( ) TRANSPORTING NO FIELDS - FROM statement-from TO statement-to WHERE str = 'RAISING' AND type EQ 'I'. - checkif_error( index = index - statement = statement ). - ENDLOOP. - ENDCASE. + inspect_raise( statement = statement + index = index ). + + inspect_message( statement = statement + index = index ). ENDMETHOD. + + + METHOD inspect_message. + CHECK get_token_abs( statement-from ) = 'MESSAGE'. + + LOOP AT ref_scan_manager->get_tokens( ) TRANSPORTING NO FIELDS + FROM statement-from TO statement-to + WHERE str = 'RAISING' AND type EQ 'I'. + + checkif_error( index = index + statement = statement ). + + ENDLOOP. + ENDMETHOD. + + + METHOD inspect_raise. + CHECK get_token_abs( statement-from ) = 'RAISE'. + CHECK statement-from + 1 = statement-to. + + checkif_error( index = index + statement = statement ). + ENDMETHOD. + + ENDCLASS. diff --git a/src/checks/y_check_non_class_exception.clas.testclasses.abap b/src/checks/y_check_non_class_exception.clas.testclasses.abap index 7055796d..d66f6172 100644 --- a/src/checks/y_check_non_class_exception.clas.testclasses.abap +++ b/src/checks/y_check_non_class_exception.clas.testclasses.abap @@ -34,6 +34,14 @@ CLASS ltc_raise IMPLEMENTATION. ( 'REPORT y_example. ' ) ( ' CLASS cx_demo DEFINITION INHERITING FROM cx_static_check. ' ) + ( ' PUBLIC SECTION. ' ) + ( ' CLASS-METHODS create RETURNING VALUE(result) TYPE REF TO cx_demo. ' ) + ( ' ENDCLASS. ' ) + + ( ' CLASS cx_demo IMPLEMENTATION. ' ) + ( ' METHOD create. ' ) + ( ' result = NEW cx_demo( ). ' ) + ( ' ENDMETHOD. ' ) ( ' ENDCLASS. ' ) ( ' CLASS y_example DEFINITION. ' ) @@ -47,6 +55,7 @@ CLASS ltc_raise IMPLEMENTATION. ( ' RAISE EXCEPTION TYPE cx_demo. ' ) ( ' RAISE RESUMABLE EXCEPTION TYPE cx_demo. ' ) ( ' RAISE EVENT event. ' ) + ( ' RAISE EXCEPTION cx_demo=>create( ). ' ) ( ' ENDMETHOD. ' ) ( ' ENDCLASS. ' ) ). From 2a0aac8086f851a382729f804256dbf1a183166e Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Thu, 1 Oct 2020 18:34:46 +0200 Subject: [PATCH 09/30] Adding unit test to new magic number --- ...y_check_magic_number.clas.testclasses.abap | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/checks/y_check_magic_number.clas.testclasses.abap b/src/checks/y_check_magic_number.clas.testclasses.abap index 247e72db..7553e7bf 100644 --- a/src/checks/y_check_magic_number.clas.testclasses.abap +++ b/src/checks/y_check_magic_number.clas.testclasses.abap @@ -139,3 +139,47 @@ CLASS ltc_check IMPLEMENTATION. ENDMETHOD. ENDCLASS. + + +CLASS ltc_numeric_string DEFINITION INHERITING FROM y_unit_test_base FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. + PROTECTED SECTION. + METHODS get_cut REDEFINITION. + METHODS get_code_with_issue REDEFINITION. + METHODS get_code_without_issue REDEFINITION. + METHODS get_code_with_exemption REDEFINITION. +ENDCLASS. + +CLASS ltc_numeric_string IMPLEMENTATION. + + METHOD get_cut. + result ?= NEW y_check_magic_number( ). + ENDMETHOD. + + METHOD get_code_with_issue. + result = VALUE #( + ( ' REPORT ut_test.' ) + ( ' START-OF-SELECTION.' ) + ( | DATA(skip) = '20'. | ) + ( | CHECK skip = '30'. | ) + ). + ENDMETHOD. + + METHOD get_code_without_issue. + result = VALUE #( + ( ' REPORT ut_test.' ) + ( ' START-OF-SELECTION.' ) + ( ' DATA(skip) = abap_false.' ) + ( ' CHECK skip = abap_true.' ) + ). + ENDMETHOD. + + METHOD get_code_with_exemption. + result = VALUE #( + ( ' REPORT ut_test.' ) + ( ' START-OF-SELECTION.' ) + ( | DATA(skip) = '20'. | ) + ( | CHECK skip = '30'. "#EC CI_MAGIC' | ) + ). + ENDMETHOD. + +ENDCLASS. From 8f3026ed2db7edc0c5b2b804f610de6ecc6412f4 Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Fri, 2 Oct 2020 21:34:13 +0200 Subject: [PATCH 10/30] adding / removing all checks --- .../y_profile_admin_classes.prog.abap | 173 ++++++++++++++---- src/profiles/y_profile_administrator.prog.xml | 12 ++ 2 files changed, 151 insertions(+), 34 deletions(-) diff --git a/src/profiles/y_profile_admin_classes.prog.abap b/src/profiles/y_profile_admin_classes.prog.abap index 14ef1a3d..6deb48c3 100644 --- a/src/profiles/y_profile_admin_classes.prog.abap +++ b/src/profiles/y_profile_admin_classes.prog.abap @@ -258,11 +258,18 @@ CLASS lcl_util DEFINITION. "#EC NUMBER_METHODS CLASS-METHODS: get_cursor_field RETURNING VALUE(result) TYPE char20, - call_check_info. + call_check_info, + add_all_checks. + CLASS-METHODS add_check + IMPORTING + edit_mode TYPE abap_bool DEFAULT abap_false + RAISING + cx_failed. + CLASS-METHODS remove_all_checks. PRIVATE SECTION. - CLASS-METHODS request_to_replace + CLASS-METHODS request_confirmation IMPORTING - profile TYPE ytab_profiles-profile. + text_question TYPE string. ENDCLASS. @@ -387,6 +394,12 @@ CLASS lcl_check_events IMPLEMENTATION. WHEN 'BTN_REMOVE'. lcl_util=>remove_selected_check( ). + WHEN 'BTN_ADD_ALL'. + lcl_util=>add_all_checks( ). + + WHEN 'BTN_REMOVE_ALL'. + lcl_util=>remove_all_checks( ). + ENDCASE. lcl_util=>refresh_checks( ). ENDMETHOD. @@ -463,6 +476,7 @@ CLASS lcl_util IMPLEMENTATION. sy_repid = sy_repid events = NEW lcl_check_events( ) ). + checks_tree->toolbar_control( )->add_button( fcode = 'BTN_ADD' icon = '@04@' butn_type = cntb_btype_button @@ -483,6 +497,16 @@ CLASS lcl_util IMPLEMENTATION. butn_type = cntb_btype_button quickinfo = 'Check Documentation'(052) ). + checks_tree->toolbar_control( )->add_button( fcode = 'BTN_ADD_ALL' + icon = '@VY@' + butn_type = cntb_btype_button + quickinfo = 'Add All'(058) ). + + checks_tree->toolbar_control( )->add_button( fcode = 'BTN_REMOVE_ALL' + icon = '@VZ@' + butn_type = cntb_btype_button + quickinfo = 'Remove All'(059) ). + checks_tree->set_field_visibility( fieldname = 'START_DATE' is_visible = abap_true ). checks_tree->set_field_visibility( fieldname = 'END_DATE' @@ -997,7 +1021,7 @@ CLASS lcl_util IMPLEMENTATION. ENDTRY. IF profile_manager->profile_exists( structure-profile-profile ) = abap_true. - request_to_replace( structure-profile-profile ). + request_confirmation( | Would you like to replace the { structure-profile-profile } profile? | ). check_check_rights( structure-profile-profile ). ENDIF. @@ -1146,7 +1170,7 @@ CLASS lcl_util IMPLEMENTATION. METHOD init_add_check. DATA obj TYPE REF TO y_check_base. - io_check_id = ''. + "io_check_id = ''. io_check_description = ''. io_start_date = '20190101'. io_end_date = '99991231'. @@ -1193,46 +1217,59 @@ CLASS lcl_util IMPLEMENTATION. ENDMETHOD. METHOD check_customization. - CHECK user_command EQ 'ENTR_400' AND - io_check_id NE space. + CHECK user_command EQ 'ENTR_400' + AND io_check_id NE space. + + add_check( edit_mode ). + ENDMETHOD. + METHOD add_check. TRY. - DATA(check) = VALUE ytab_checks( profile = lcl_util=>get_selected_profile( )-profile - checkid = io_check_id - start_date = io_start_date - end_date = io_end_date - objects_created_on = io_creation_date - threshold = io_threshold - prio = io_prio - apply_on_productive_code = chbx_on_prodcode - apply_on_testcode = chbx_on_testcode - last_changed_by = sy-uname - last_changed_on = sy-datum - last_changed_at = sy-timlo ). + DATA(profile) = lcl_util=>get_selected_profile( )-profile. + CATCH ycx_entry_not_found. + MESSAGE 'Please select a profile!'(005) TYPE 'I'. + ENDTRY. - TRY. - profile_manager->get_check_description( check-checkid ). + DATA(check) = VALUE ytab_checks( profile = profile + checkid = io_check_id + start_date = io_start_date + end_date = io_end_date + objects_created_on = io_creation_date + threshold = io_threshold + prio = io_prio + apply_on_productive_code = chbx_on_prodcode + apply_on_testcode = chbx_on_testcode + last_changed_by = sy-uname + last_changed_on = sy-datum + last_changed_at = sy-timlo ). - CATCH ycx_entry_not_found. - MESSAGE 'Check is not registered!'(044) TYPE 'I'. - RAISE EXCEPTION TYPE cx_failed. - ENDTRY. - IF chbx_on_prodcode EQ abap_false AND chbx_on_testcode EQ abap_false. - MESSAGE 'Please choose Productive Code and/or Testcode for check execution!'(051) TYPE 'I'. - RAISE EXCEPTION TYPE cx_failed. - ENDIF. - IF edit_mode EQ abap_true. + TRY. + profile_manager->get_check_description( check-checkid ). + CATCH ycx_entry_not_found. + MESSAGE 'Check is not registered!'(044) TYPE 'I'. + RAISE EXCEPTION TYPE cx_failed. + ENDTRY. + + IF chbx_on_prodcode = abap_false + AND chbx_on_testcode = abap_false. + MESSAGE 'Please choose Productive Code and/or Testcode for check execution!'(051) TYPE 'I'. + RAISE EXCEPTION TYPE cx_failed. + ENDIF. + + TRY. + IF edit_mode = abap_true. profile_manager->check_time_overlap( check = check selected_check = lcl_util=>get_selected_check( ) ). + profile_manager->delete_check( lcl_util=>get_selected_check( ) ). ELSE. profile_manager->check_time_overlap( check = check ). ENDIF. profile_manager->insert_check( check ). - CATCH ycx_entry_not_found. - MESSAGE 'Please select a check!'(015) TYPE 'I'. + MESSAGE 'Check is not registered!'(044) TYPE 'I'. + RAISE EXCEPTION TYPE cx_failed. CATCH ycx_failed_to_add_a_line ycx_failed_to_remove_a_line. @@ -1281,13 +1318,13 @@ CLASS lcl_util IMPLEMENTATION. ENDTRY. ENDMETHOD. - METHOD request_to_replace. + METHOD request_confirmation. DATA answer TYPE c. CALL FUNCTION 'POPUP_TO_CONFIRM' EXPORTING titlebar = | Confirmation | - text_question = | Would you like to replace the { profile } profile? | + text_question = text_question display_cancel_button = abap_false IMPORTING answer = answer. @@ -1297,4 +1334,72 @@ CLASS lcl_util IMPLEMENTATION. ENDIF. ENDMETHOD. + METHOD add_all_checks. + TRY. + DATA(profile) = lcl_util=>get_selected_profile( )-profile. + CATCH ycx_entry_not_found. + MESSAGE 'Please select a profile!'(005) TYPE 'I'. + ENDTRY. + + TRY. + profile_manager->check_delegation_rights( profile ). + CATCH ycx_no_delegation_rights. + MESSAGE 'You are not a delegate of the profile!'(006) TYPE 'W'. + ENDTRY. + + TRY. + profile_manager->select_checks( profile ). + request_confirmation( | Would you like to replace the current checks? | ). + CATCH ycx_entry_not_found. + request_confirmation( | Would you like to add all the checks? | ). + ENDTRY. + + profile_manager->remove_all_checks( profile ). + + TRY. + DATA(available_checks) = profile_manager->select_existing_checks( ). + CATCH ycx_entry_not_found. + MESSAGE 'Checks not registered!'(021) TYPE 'S'. + ENDTRY. + + LOOP AT available_checks ASSIGNING FIELD-SYMBOL(). + io_check_id = -checkid. + init_add_check( ). + TRY. + add_check( ). + CATCH cx_failed. + CONTINUE. + ENDTRY. + ENDLOOP. + + MESSAGE 'Action Executed Successfully!'(056) TYPE 'S'. + ENDMETHOD. + + + METHOD remove_all_checks. + TRY. + DATA(profile) = lcl_util=>get_selected_profile( )-profile. + CATCH ycx_entry_not_found. + MESSAGE 'Please select a profile!'(005) TYPE 'I'. + ENDTRY. + + TRY. + profile_manager->check_delegation_rights( profile ). + CATCH ycx_no_delegation_rights. + MESSAGE 'You are not a delegate of the profile!'(006) TYPE 'W'. + ENDTRY. + + TRY. + DATA(checks) = profile_manager->select_checks( profile ). + CATCH ycx_entry_not_found. + RETURN. + ENDTRY. + + request_confirmation( | Would you like to remove all the checks? | ). + + profile_manager->remove_all_checks( profile ). + + MESSAGE 'Action Executed Successfully!'(056) TYPE 'S'. + ENDMETHOD. + ENDCLASS. diff --git a/src/profiles/y_profile_administrator.prog.xml b/src/profiles/y_profile_administrator.prog.xml index c7b72b08..b093d337 100644 --- a/src/profiles/y_profile_administrator.prog.xml +++ b/src/profiles/y_profile_administrator.prog.xml @@ -1542,6 +1542,18 @@ Action Canceled 25 + + I + 058 + Add All + 17 + + + I + 059 + Remove All + 27 + R Profile Administrator for code pal for ABAP From 9093d9cc3228232ac7032e2d3226988b84afd27e Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Fri, 2 Oct 2020 16:42:27 -0300 Subject: [PATCH 11/30] Update changelog.txt --- changelog.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 544f0aed..12e2fe0f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,7 +8,11 @@ Legend + : added - : removed -2020-09-30 v1.04.1 +2020-10-10 v1.05.1 +------------------ ++ add/remove all check in profiles + +2020-10-05 v1.04.1 ------------------ * magic number to support numeric strings (#142) + enabling table log for exemptions From 78c1ceaa645c0e4d1483c1de1e0ab8dc15c0ca0c Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Fri, 2 Oct 2020 22:04:34 +0200 Subject: [PATCH 12/30] 1.05.0 --- src/y_code_pal_version.intf.abap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/y_code_pal_version.intf.abap b/src/y_code_pal_version.intf.abap index 2d486691..32f2392a 100644 --- a/src/y_code_pal_version.intf.abap +++ b/src/y_code_pal_version.intf.abap @@ -1,3 +1,3 @@ INTERFACE y_code_pal_version PUBLIC. - CONSTANTS abap TYPE string VALUE '1.04.1' ##NO_TEXT. + CONSTANTS abap TYPE string VALUE '1.05.0' ##NO_TEXT. ENDINTERFACE. From 149709c2c0d7d62946c5a41472a21250fa38ad3e Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Mon, 5 Oct 2020 21:18:14 +0200 Subject: [PATCH 13/30] fixes #136 --- .../y_ci_check_registration.prog.abap | 206 ++++++++++++++++++ .../y_ci_check_registration.prog.xml | 51 +++++ 2 files changed, 257 insertions(+) create mode 100644 src/foundation/y_ci_check_registration.prog.abap create mode 100644 src/foundation/y_ci_check_registration.prog.xml diff --git a/src/foundation/y_ci_check_registration.prog.abap b/src/foundation/y_ci_check_registration.prog.abap new file mode 100644 index 00000000..8048a650 --- /dev/null +++ b/src/foundation/y_ci_check_registration.prog.abap @@ -0,0 +1,206 @@ +REPORT y_ci_check_registration. + +DATA: BEGIN OF comments, + title TYPE string VALUE 'code pal for ABAP - Check Activation Tool (Local Only)', + runmode TYPE string VALUE 'Please choose a runmode', + END OF comments. + +DATA: BEGIN OF messages, + checks_not_found TYPE string VALUE 'Code Pal Checks not found.', + successfully_activated TYPE string VALUE 'Entrys Successfully activated (category + checks)', + failed_activation TYPE string VALUE 'Entrys Failed to activate', + successfully_deactivated TYPE string VALUE 'Entrys Successfully deactivated (category + checks)', + failed_deactivation TYPE string VALUE 'Entrys Failed to deactivate', + done TYPE string VALUE 'Done!', + END OF messages. + +CONSTANTS: BEGIN OF reference, + check_base TYPE sci_chk VALUE 'Y_CHECK_BASE', + class TYPE tadir-object VALUE 'CLAS', + foundation TYPE string VALUE 'FOUNDATION', + checks TYPE string VALUE 'CHECKS', + modifiable TYPE e070-trstatus VALUE 'D', + modifiable_protected TYPE e070-trstatus VALUE 'L', + error TYPE c LENGTH 1 VALUE 'E', + END OF reference. + +CLASS lcl_check_registration DEFINITION. + PUBLIC SECTION. + CLASS-DATA name_tab TYPE STANDARD TABLE OF scitests-name. + + CLASS-METHODS select_object_list + RETURNING VALUE(result) LIKE name_tab + RAISING cx_failed. + + CLASS-METHODS activate_check + IMPORTING name TYPE sci_chk + RAISING cx_failed + cx_sy_create_object_error. + + CLASS-METHODS deactivate_check + IMPORTING name TYPE sci_chk + RAISING cx_failed + cx_sy_create_object_error. + + CLASS-METHODS is_check_compatible + IMPORTING name TYPE sci_chk + RAISING cx_sy_create_object_error. + + CLASS-METHODS get_category_name + RETURNING VALUE(result) TYPE sci_chk. + + PROTECTED SECTION. + PRIVATE SECTION. +ENDCLASS. + +CLASS lcl_check_registration IMPLEMENTATION. + METHOD get_category_name. + result = cl_abap_objectdescr=>describe_by_object_ref( NEW y_category_code_pal( ) )->get_relative_name( ). + ENDMETHOD. + + METHOD is_check_compatible. + IF name NE get_category_name( ). + DATA code_pal_check TYPE REF TO y_check_base. + CREATE OBJECT code_pal_check TYPE (name). + ENDIF. + ENDMETHOD. + + METHOD select_object_list. + SELECT SINGLE devclass FROM tadir + WHERE obj_name EQ @reference-check_base + AND object EQ @reference-class + AND delflag EQ @abap_false + INTO @DATA(packagename). + IF sy-subrc <> 0. + RAISE EXCEPTION TYPE cx_failed. + ENDIF. + + REPLACE reference-foundation IN packagename WITH reference-checks. + + SELECT obj_name FROM tadir + WHERE devclass EQ @packagename + AND object EQ @reference-class + AND delflag EQ @abap_false + INTO TABLE @result. + IF sy-subrc <> 0. + RAISE EXCEPTION TYPE cx_failed. + ENDIF. + + APPEND get_category_name( ) TO result. + SORT result ASCENDING AS TEXT. + ENDMETHOD. + + METHOD activate_check. + is_check_compatible( name ). + + INSERT scitests FROM name. + IF sy-subrc <> 0. + RAISE EXCEPTION TYPE cx_failed. + ENDIF. + ENDMETHOD. + + METHOD deactivate_check. + is_check_compatible( name ). + + DELETE FROM scitests WHERE name = name. + IF sy-subrc <> 0. + RAISE EXCEPTION TYPE cx_failed. + ENDIF. + ENDMETHOD. + +ENDCLASS. + +CLASS lcl_util DEFINITION. + PUBLIC SECTION. + CLASS-METHODS activate_all_checks. + + CLASS-METHODS deactivate_all_checks. + + PROTECTED SECTION. + PRIVATE SECTION. + CLASS-METHODS get_obj_list + RETURNING VALUE(result) LIKE lcl_check_registration=>name_tab. + +ENDCLASS. + +CLASS lcl_util IMPLEMENTATION. + + METHOD get_obj_list. + TRY. + result = lcl_check_registration=>select_object_list( ). + CATCH cx_failed. + MESSAGE messages-checks_not_found TYPE reference-error. + ENDTRY. + ENDMETHOD. + + METHOD activate_all_checks. + DATA(count_successes) = 0. + DATA(count_errors) = 0. + LOOP AT get_obj_list( ) ASSIGNING FIELD-SYMBOL(). + TRY. + lcl_check_registration=>activate_check( ). + count_successes = count_successes + 1. + CATCH cx_failed. + count_errors = count_errors + 1. + + + DATA dta TYPE REF TO cl_ci_tests. + + ENDTRY. + ENDLOOP. + WRITE: / |{ count_successes } { messages-successfully_activated }|. + WRITE: / |{ count_errors } { messages-failed_activation }|. + ENDMETHOD. + + METHOD deactivate_all_checks. + DATA(count_successes) = 0. + DATA(count_faults) = 0. + LOOP AT get_obj_list( ) ASSIGNING FIELD-SYMBOL(). + TRY. + lcl_check_registration=>deactivate_check( ). + count_successes = count_successes + 1. + CATCH cx_failed. + count_faults = count_faults + 1. + ENDTRY. + ENDLOOP. + WRITE: / |{ count_successes } { messages-successfully_deactivated }|. + WRITE: / |{ count_faults } { messages-failed_deactivation }|. + ENDMETHOD. + +ENDCLASS. + +START-OF-SELECTION. + + SELECTION-SCREEN BEGIN OF BLOCK part0. + SELECTION-SCREEN COMMENT /1(83) comm0 MODIF ID mg1. + + SELECTION-SCREEN BEGIN OF BLOCK part1 WITH FRAME. + SELECTION-SCREEN COMMENT /1(60) comm1 MODIF ID mg1. + PARAMETERS: p_activa RADIOBUTTON GROUP g1, + p_deacti RADIOBUTTON GROUP g1, + p_reacti RADIOBUTTON GROUP g1 DEFAULT 'X'. + SELECTION-SCREEN END OF BLOCK part1. + SELECTION-SCREEN END OF BLOCK part0. + +AT SELECTION-SCREEN OUTPUT. + comm0 = comments-title. + comm1 = comments-runmode. + +START-OF-SELECTION. + WRITE: / comments-title. + WRITE: / space. + + IF p_activa = abap_true. + lcl_util=>activate_all_checks( ). + + ELSEIF p_deacti = abap_true. + lcl_util=>deactivate_all_checks( ). + + ELSEIF p_reacti = abap_true. + lcl_util=>deactivate_all_checks( ). + lcl_util=>activate_all_checks( ). + + ENDIF. + COMMIT WORK. + + WRITE: / |{ messages-done }|. diff --git a/src/foundation/y_ci_check_registration.prog.xml b/src/foundation/y_ci_check_registration.prog.xml new file mode 100644 index 00000000..9573122d --- /dev/null +++ b/src/foundation/y_ci_check_registration.prog.xml @@ -0,0 +1,51 @@ + + + + + + Y_CI_CHECK_REGISTRATION + 1 + E + X + X + + + + R + Program Y_CHECK_REGISTRATION + 28 + + + S + P_ACTIVA + Activate + 16 + + + S + P_DEACTI + Deactivate + 18 + + + S + P_LOCAL + Keep the checks local? + 30 + + + S + P_REACTI + Reactivate + 18 + + + S + P_TRANSP + Transport ID + 20 + + + + + From 4eaf9726c3644779d3e79de200ae1952716d106f Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Mon, 5 Oct 2020 16:20:10 -0300 Subject: [PATCH 14/30] Update changelog.txt --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index 12e2fe0f..e9a51c33 100644 --- a/changelog.txt +++ b/changelog.txt @@ -10,6 +10,7 @@ Legend 2020-10-10 v1.05.1 ------------------ ++ report to activate or deactivate the SCI entries + add/remove all check in profiles 2020-10-05 v1.04.1 From 383d93da21f3b1c0ef7809d516b2a7499e82ae4d Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Mon, 5 Oct 2020 16:29:42 -0300 Subject: [PATCH 15/30] How to install via report --- pages/how-to-install.md | 22 +++++----------------- pages/imgs/sci-checks.png | Bin 52927 -> 0 bytes pages/imgs/sci-management-of-checks.png | Bin 36680 -> 0 bytes 3 files changed, 5 insertions(+), 17 deletions(-) delete mode 100644 pages/imgs/sci-checks.png delete mode 100644 pages/imgs/sci-management-of-checks.png diff --git a/pages/how-to-install.md b/pages/how-to-install.md index 65b568c5..8addf1fa 100644 --- a/pages/how-to-install.md +++ b/pages/how-to-install.md @@ -12,30 +12,18 @@ Follow the step-by-step available in the abapGit documentation: [Installing onli ![how to clone repository](imgs/clone-repository.png) -### 2. Activate code pal for ABAP category +### 2. Activate code pal for ABAP -Start the transaction `SCI`, and go to the `Code Inspector > Management of > Checks` menu. -Then, select the `Y_CATEGORY_CODE_PAL` check class and save it. +Execute the report `Y_CI_CHECK_REGISTRATION` using the run mode `Activate`. -![how to activate the category](imgs/sci-management-of-checks.png) - -(In some system releases, the path to the `Check Management` might differ from the screenshot.) - -### 3. Activate code pal for ABAP checks - -Start the transaction `SCI` again, and go to the `Code Inspector > Management of > Checks` menu. -Then, select all the `Y_CHECK_*` check classes and save it. - -![how to activate the checks](imgs/sci-checks.png) - -### 4. Create code inspector variant +### 3. Create code inspector variant Start the transaction `SCI` again, and create a new global check variant. Then, select the `code pal for ABAP` group and save it. ![how to create code inspector variant](imgs/sci-check-variant.png) -### 5. User Parameter +### 4. User Parameter It requires you to set the ABAP Test Cockpit (ATC) to run in Code Inspector mode. @@ -43,7 +31,7 @@ Start the transaction `SU3`, and add/set the user parameter `SATC_CI_MODE` to `X ![user parameter](imgs/user-parameter.png) -### 6. Service +### 5. Service > :warn: Optional Feature! diff --git a/pages/imgs/sci-checks.png b/pages/imgs/sci-checks.png deleted file mode 100644 index 773a9b3668b319d64700c890de049a5d04e644ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52927 zcmcF~2UJtd+Adf?LIiTTp;{1Un8_g_=nh4T|t)UTR+1l;pURH%u5*}qVi~RjOk^wXZd9mq3CVmAK*!UU%uPYgt%+oj)EoyH%@h<{&I(3;8qRW0Zr z)hyebUR?trVW2a7=jL(jQS*u@hb#Qr?|RbwUm(0f%=dmb^ltNAGVkTTZ)^jSdB^Vk z{p3S3@7KR?Y!loEk{@~RHx;%~d}{^viRYB8yoTLeus(S{dhUROZinA@(X_koBT%aHucdVFnoTw-$#P0z; z&tall+r^GIzVzAXoGsXETuT}Wl)!b4PFVHWYT!MrO%|%#Q(gLR{@n!elz_*l%Us6np09jXI0LcyTo*W9~@nvY! z!~-`xHgmVkoS5jId!Mwj&6O*72YrIq4u>5@zouv%RC`<7L9T$dW9vz?St`-m>phR` zR#$lHofhH+M)xGkxYo?gnR=^d`G1)j#@0`wGXJ_oWGe&glX)5%G@qw4ftvywLf2d$I7*lNa6**FRkJpXpxHzQbfoefLc_;Y)Zodb~6=*MUPPY2%XCAu(iZXGEPN zEfc8TS)P(&KU}D&-{)vzGB^C^wkNKzU-)pgZkR-9ynP4a@?p z6kPfGC$q9Rk>KJr%#!+oov^GrC+yH(q<`yjz8}uk|2B<11vnf#b{!?zrjZy%m0Vbo zxNUU2ZO-o0tA|^LNZ!I2tZ3Vt?drxOjGDIU)Jr}^bpsW8UPduqZ^9=jgtX-|R2mWX z4_+uXP~aw|UDN(Esq;1)?KYjY4Al4sKQ)^-V}30omN-QCZff8xW;yx5>1eMgUV{YX znr8?3QYx@;jr@wOruUAyob(wh;hR%@PE8GCUZtSbzZB^ArDHQRM91kYn&-{yIYXEf za$wA&Qk0FHhYFtMDv**=i zaszR&J@+=a%5NxFU$=PUclN%A;`#<{Gv z6AV0`HrX9Fc1nYCf#@oTh^>>bc_$SA&h60Oiz*hzubYYr>zqh^uKYZ4aUVc!AoH5H=aIicVN5q^&% z91OG}+0{U2E3NzP9VLhTAqh{3<#D_V3+yr0@8(V2XL?1{lYhWj)4@Y+4;Dp3`Di zs0kCAD(Ny^kZ+PT0jkV^&NH26G;Y%B#8MHqJs+=t>v|Tio~}yT;`&cZ2hZN0MjHt> z6`f`Vd8WV0RPgkHf)(+00rK)@$Ju^eo+~ZEc~Uw$4RP?|g!TFZ5>e=D8vE#Z1`Qem zN1b9ud*=DW%Dj~_9>a4-H12jvdkR8~uqnHYFjA`rm+ddQ1qVHN7F`B_=;FRCb+Ef^ zhcRgaBLqnX_JU3xewLHILbPe#FVF<1D5tQ#Ta-oy@_KOAlbsGm6Sjp?d{ff(%a*l7 zWeS;t(Yv9c2GoK%qGHNT$Jcx%))@BgBSXNx!7#!(2^#~2l zVI48B9tEBAd7jcTKO5oz!ggRP+1Tie?DX}!E#m=5=S*&!KIx-!Dv$K<18bwT>z$AI zO~S{t73!Knle`inD`q>o90!RIgELGpoZ`A?cn3mv=a+GBV3o)Lk*+S=@7@F1;Kii*Cx3(!7CVu0{JzQRMZ#O`R}*ugVRpdS zeSGZ5^AN)K{;LdkTsx(0|Rcx>DWzzoz;-r0K zm6Lh@ex;^jxi0&69irD)v46lK(G)q~pGKsSvdVv2h=Ed4|H0-KJgxu3Y8>n1w4QL* zKfPGc9sfT!^nW?5KmA!;AQ?F6dDM9;JX~q@*6+?OxF^h-D=PR!FK(8WmQwsNQd;=O ztW4B6uayjA(dXKJrwM!UKf)$>dQcrN#K2{Xz0vi@@q;Io{dS1eu0-rW z1iLF@s&8vW=vooUbL{@>-+IK-HU_lUNhV0iE@3QNr-PZnFTvFuW5EMFR2O z2nBLaA=B0=tT6Nz`ew}lCkEsCg;On2d+7-fNXDsJq2G!)f-y+>=}IKF^mur}6LO18 zkl&&bZQpd1toS9CS#?VL@Vg?BXW54S%uKh=x(L%vCF}R8uqT6K7||5u#%cTeaS<@c zsGrbvas#DTK{eQ+>!@O>3Xj@S2r;lereEC(7142+ZTYqao;Fcp7bXEQFT7`!1u`cq zqCw4obZpJ{GB@UZ^W|)NYdk2We*uGv?q9<$rZ^*cV4QB)ooI0NBKr9bdyf4z$45sU zMR7h;p`f^N9Q6ArE%o(?zHgBaHqNJ#^h59#GvwgH`c_34=t7SE4*pulMcInNN*^C_ zvY=#AGqIs&w|V7$8QQ!_xrNZ#;aGr^U#&=ZeKzsExj9T*XeB8QcNk)}TOOi)mVw75 z#Y;qm`fJP<&##3u=)|>BAb53n(y$Fb-tOf!&Sg0sj#0lKAE0$G;5SUI0yRVMHqj+~ zFB$ARDui>wv+jnlo*O889<7u1uSwFnN6ZEj{QY|8A#3aXyD7o%)T)sLKke@9VL#;q zJ?4b6i8Eh2--~;{w-n7JMDOPIKI4N(T;)1k#C|ojcic-RD2Z<{rQ9E#*QeoRbsKuXSq-N&`+IS(c$(*3atsL zqp>#@&#E_{TA8! zu|1)q++ONvNj*o04pvb%2H)eZd9d)f2-m?8YZbdq(bp5BtVRb;3V-dnpbJD~uOVrq zodH`9L{v?DV=(?O(5qAl?cwDH@5K}PXz*#!Y9R4e!{)>DlcDD|51jIY?&D1uypE1< zHbEzxaLZySI~Si9=B0yYr8_Mv;WG~ zWqMZdII1FDqU^`uee194wK;RtVPw}=-sW0UMt$NZ&g3mIWwx9}sDe69dm+Pf89T{? zwPB5K@{JtgowUJ8g4+|xrO}wiO1#tRJ}b6fyd)lrTJYKc;Box1)~$UIfS0OqX6<(g zK%qImOuShL6OlS2#T9@ha|gkbwm9pQ!ljbSvgUb99sXTc$hpj$@9eRK3E#x+QdLH( zw}$P$hy*p~C+bd~xIxESVTCo4s$$iAZ@TKZF7TNOCqF5}p3E=rHCf)Ixv@71`do}V zVpLjfj7dx0-%;9&cT{2$lT+MGswSZZkB$KkRpnwA!#dGqQ|$en(W)^{Kz@uTv8>;K zAG(La?y@2h8>kl<6a-1yzd?O|a5_JE{M1t4*MHOd0DC?dwx?ns*f}(COl14KfSye+ zHV%7Sqqrj*@$nkoOKUG~iM1oJ)DQjHc&aK)LFaMpXRafW=rFa&;Nm?YJXQ{)l;ppH zl+qqnZ+Ja#c%DL8tvmTF@+})Q=*ku1A1MTC^(TO`T-i;m z9ae5L9T0)JtXKekBiNzsK_m@zJB}-CwJp$ed#qW)!}eXY;1K(nX%-*zoQ}_@hxkq- zuU#AAWDV$114lo!2?r%hxtBs3_}qDEXP`@9Y;}#@1c`Zc{fg~FujQQqo>^8`Nw7XP zV8&YiRy}e%?>CV z=!>Plr(-rL`DTl1k5`SMhn9MloV|KCR=as%Y0{IOlnQo37N$XLkA2hI&8xexAffsf zD_;Rny`GEB>^Lv2b=MKTutSQbibb-Ligdbr3w+;>o2Ou?<1QMyLdi2NeXcI}2<@3c zRTtd6g>=$jDBOPTK2yXMmbbG+^CKM)PSK$yXMR1}Fc&w#P$uCG}qz|+iC36{Ca z<7hcRFx5AlUGgn1#d*@{Muo2A&Fq(@3ulTdFGKjw%bmQqeKt{y1rocrt(5p zgGfKyg`uj=!}Ng#|4r#HsH2M1griXK(!mhf!!GqA9)jT))~) zOQL&fH9>N~Ew|5SLG^UP4U{AwoP-aS52jzhl;^*HjvU+4(Pu)Gz6>ghIr*%z@MEZm z_5u&qM%9sno~9`PG=l)c^91ETCu+slk>gg&dv>VT&i8?Fm%mbR`0xDmb_w(0HNml6 zKT!is#wDf7S-*%No(wLdB;cafm7=i$e3$fu5+*#<=-KUp&+JVH*S3F}>r9=8@;m~p znD~EN&6a*=bU*qn)?s@g9>^y_+~yA6Pq+-Ytlabfe1O|uY05Ea?FB3QO&fsv@kb5E z4PTIZP7*l9IAqHQFs}}{i}mwaUK3$v*Lzf11@4Iim1pZc13VQoWu#<7&+ElEwxR(2T**cIyAv7d$Ig!uFKW(y{TNWi-p7iz>ZcUmUpb;Hc|Af; z*&RQ9Jl>bHpxW6nyw6;*;9Z3W0N^6F8!T2+(~+uQhC&uLF1mQRtePSB4YGkgZezj( zlt)Q%&WxM~O4YwM5W-e0*3yFd)d94y?jN5yMB>nVAm;s>z7c&#(~d&zzRmII+wJWr z3W-rOuicFS@hQcATd&pk^7d&Pk?JonR(G)Sipx&pl}_Ak0#;`tqarV)&e5r3hiFB7 z;V`W6EZ~ita3B7c=mLx*AqspmZu=`m%DVu?*vLYf@ghPKbtjc^2eJl36cg1v{OI3gd8dr``1RZRZv<5E;_%`K9gSVdEm3=3Mn2O?r&p99 z+7BRlW{TuCNyNF%ZFCgNLOu$q6L;vU@R982(>OC(&}I#Ob>XtLQTPq#q4Y<05HPj6yt9+>H*Axt=r+Thlx*&%i&j-}{(x$)<;Tn1_6zPtH; zHjjyZxGkm!;{D`~wIvTG0%VOV%#n0ib%d0=8obS>Ydjfei zIs#W|+50nan6+U$fGD#M`9&ThUn`%MoZ|Zd!y($N+qDV9Eo0;?Pr>86$KRz6$(Ns> zf3+lVS_?V=jU8WRnvmif<>ava2)bmIoda!?5)f`?K=MfIa8aiS(&dZqOS(V-nmM7y zjo`)sP}EI-TdX^@v@%4#(QSE6rw4)p35laNTiMw!0HyGYgcaS@b}m~fdM^j}`twCu zJMLd{xMIvY8mL=+|5)vt?a?9x_hn5SY^a{z8!{_>>6khoG)K~$@OChcfnlYKZFwMJb;;L0m|>uf8q@l@5TS3MnpL*5sbgWD+E*jb2Q?gRN_Ad zE&f?e6n1`=n|A4U+wVBzUAMyp5dn^hYpzCI*}$cWZmdIBXVB$ zZ`PM$>eYc$;t&COcEpJW_7=>e=J3kgsD;!Rr^kz@e}!d+nLv;~6qSfU?mtmT4y1t9 z&TQcyl1YS|Yw%Q6sbk%>?wt%HGveX?JqOa`FXUr_)}#Ki-uxc}ZE1av0E)kT**`d? zfrFGppQN7r^I0135gXomWWXcMS|ATo3f|kef5?mC0{ihFQtqIS6a4U+z~RJXQ3Zn$7t6cMCB$ z|KBP0|0Og2chy|p_&e*U-0kh}i`5A1{VcRS5A}7sFCyaU;-b!~j-P-9=Mq=+fzPmp ze0+WDZOSFIgpvQ?vKdg@#$g?(Eb2azym5JfKr+UsNBp75ME{;h|LvLzoix78RFQWe zjLr<8Vb7W!Zit!f4oN$kGC%bM3aj0M%cR`xI`Glh z#Sm7(JBM|U_+!bh{cPC~UVRh?~YM&f<4}vw~q|BB3&T z+!7$Xm{T{{SpWz6Vp&qIJQq&qV|L^KqdH*U3|)gy1O0rKfWrL_K*PcWQvMGc)=gzg z(H}iKE*n=HrzWZZN397BD7pghW60r>oY>kg{hD!%Ci78cZ}pW;l%IS*F~B3D36Z~D zu)c%|tAvzi-8e_H-)NBv`pXMwGtG2hY zArPfA)3-L}C?l{s;@7MZy|pXz zw||SB0XL;lB!9+3G8PWp-geB(Oh@S5K2f_k9iV@rGogjx=+8;d=2A7_&r1Jb{ou+7 z4Ryv@Qtii6`rCzHwqXctzx4pFZ^8e(tw_8RJR=<~>54spr+QM(?>R4_O?*~5czVj; zO89T2e8{3+3)eBR_tUKTaM>ey;Q-UuZ$!gq9C7&2Yof7T+_b+D3&!-&?{#j|u+Puz z%V#_{)!dAMDsQ1M_^SA^d?Vw-W0I-1)3yb~W9wJ5g**U^`vX`DZ!s?QdG!&2FBAQE zG@o(cwaUQks-x-CHMkA{;x>{x&q9iqB)=z+cr~^i4&BbG_G74a&Bxa)iQ}7-@Hn58 z3nM;2(|PLdhMdNQGkWLeuXm|~?gzDLii0-ihC0!bOeUC}@KuvnRNp#kUVTmg`?smDV@82AVL{Sh0Gt&-M%qzV{z3KRa5W%k|Dsck}S6TU1%aX4iby%S3>MDqSDvG`+9Mb54M~FJcrAOBC#wUJtqK!kFjJU^WR>Z?BjRxR}z+$!WF@2R)Cv= z;Ro|izGv@8+Zb#d1g-8xr#&DCSdtgyPm8{OBi0d>h!<^WbKPJ>EQNuwhsIEfiCd2T zATVjDF=*FQwW&V)tzYRlBj(VPPUby==8oU)~^bO9)^SM4~mAFD?=C9EwaO_smO&vkiknO?X<#vn^#I@O>hULCYYwi zTD1p%4LoEGpOLK$XM%ss zPE;}e>qI!;JBH8-R2%iT;%K@{p7e#&nl&CIH#<+FwujhnK_=U_r zpulnj*&G6XNl`pE?}uR8zqG-U^J`cCgB|`42_LuD_oy$tCgvG+NHly$Pd21 zLCgOaMLXx`&MbrIv(93@%H6pJ1$Gx#*Jr=dbO@!@(a!G0B|Yw}_o->>4gS{ZDs)f6 z$=KOnRuFYs3Ah_C`Vk<=JGZ1h1f683%d1&F=Jvnf&Hr3p|96M_{}f4-rWu&bCd89e zy1K63Vy?96i_-|LJ3DX`y&Qw1>4TZ5{D#O+Jon}$Md3Ha-_Ib#<6XLcXe&PqOHEA` z7qyKGdf5V*kJTXBboyyt+4i*6J9fuMN@M#MLVim=EijseI?Yp2{#gE3uwkmlS=r0l zrThFr(w`W|yH6qiKo4*iWt&FAA{7yr34UJi7$IwVE=)_~AjM@JSLkW|^J37U7U->V zZoBY!Q>8k(rF-+yV?sBqLAE0g$X9|!rz|=Kl1;Pa_U0RXmJY8UczhooRu{d^O&-l> zA>r)nHVPe*!zHd@T~r)*M^d-K6FcchmG`#+#aU(yh@d4g|iL zXv3;^+i+rTyykv%e`I7F=EA`*I+2sT;h|a6MjpPl06tim@fqpAJ%Wx%Sx}ixHc~UR zlI4DF)mSN!#S-vU@T8m0H9If0d%_-ib(>?R!%|Ghr|j^3v)Wb2SmHJ4#)Ya)y7Y(m zu!vJfW5AZ*pbwX<GkgE|-qt>ZOU3+0H{{hB;H&$IrLzq4R z@I!I*D#N7v%6OhD1ZR4rWTahct@Lf-Q_lxRa~2tOjDsY_l}D!+WslBFAv~E!Dq-b* zqo`kQ5!Us?i`lVE3*~dbIHA5^5ne7CHLAvvYIG{6F=VvgBS-AmX`-fM&5ed%)+3=1oP4`A@-{eatq;XA_l?O9S_whiY znf$(n3c?)t)DUhOV@p{zKVpNwy4dK+7^jRYNw?I+@5QXWN4l>^K?DUy8BBl9)V1|7 z&h%J7%WaKzWlIVZ)paSb96m;-D4kn!iKN24qweNn6Y$%atQC(8YtJRuuc1S z^hod)i`W=VLS8!(f;9*IeVIj;38|_*7bSek3M3xK4i9sP0ImUdGX0tpMOaE9wu~pi zxblN04>@+fMnIDUzPTb-#^sGpN@8l`CG#31eQyV{Ds8{$S$!OZxpNk*UBK@15 zW|$D%x|qC#p72J`>g$9YsPlYhq`uLE*XlO@T9R+X2wh1(X;3sUC}|@qn~x9aTwaH0 zxcQxU)WldP(QhoYv%kf}@Un_2I@YS~COVqjNN!pxRxxYKoobqJj_4iD($N6 z?$1Op{qd%!1w_a-q~*^NOKuffH;Ik!>2dTKK2w;q#idkV2bq*X@kSi;U3AVIQVx zpESN9_Z57W;#2}vscfm%r}%)(mkXCS81)(O&#AV0CPi4f1}%`trEU+sVv&G(ODd?5 zN5pBUlzItp1ckfQF!^H$GMt33P*%KqH@^(DcRdrdcR~C1)WZ(55`CJoFtNeWt{Z%4 zFQbN6xs@QU=c`BjdmUD$(doEv)$}GpoIDDeYYF91o@|AXzRTSRvtu0ot7C1A!Q5JJ z!8S}{;dDf?fyJ$*}lShSbZ4%!xN zpAZ9Ysprhf5)!HDF@sVab37QIx&2bydj3F|qVemAb$dDR=Qnm3t_AM8>ZV?vSC(w_ z<~4SS1jSUEyr}BPSMXW_@-y+iv;3`b52_KIop`&Cr*;@|+Oq}{i_i9&Gi?Rj4apVx z_+`vh2SeA!8XKs`Kv~;i?)ooU`NZrTORq|B+v}DL;ec|S<3IS&uNQcuL-$Zyt|{CY%1}Pziw8o>~(qCvR7vw zA9`aIW#ehyGi|mVN8iz~@C=HW)6>4~2MWJ4Q#ZDI2AV0Z>4}{@0hUIjAAaDUv-7U} zz4Jd$xWpadL7<;l=#)*{w`d(~$y>)uqVm5BTSyUIoG2p~bSdN_48C%IVbxY){W3D-5chVV6X5nWTn# zhC8M`cPIAPN4X82rgQYPRqjy8CHqttbLt z)1_K`|jH?8vA|?%PrlzSDlF_+f-PU_7w;% zh9r*rD16>%w$$pNt+~8PQ9gL5nys_rO9e*Uegk!Lg|OrpL%9UH<9)JkM24R-Ye*y%&x@d$g2( z%*jld{-!(!DX{rzzH^OoJxDP#80_wYraDyjAIkPa9)ZO$wCwC>td9zO3RI;0-9{G< zO`VS>l0J&Ex4w9^;xo3cb9k^oe&{jn_30N&e#chNC=`!KNh!0zVQGO)B_aqznLhws zC4Z^Vm7Q%=G@6WfI3Yb*?TbdY?2~jzAWS~{zJ_|%MHC$NNQQx^7(+S!=3A!A_F z=NFKj4M0Z3B>qEpGbN0|lP&MxkAk}+uyCQcqfaHqRK4&;gMMO}F8*kJqO(ce$x~~;mn~YE&?eDaB{%WM;wzUu0RraMfcn$_0x5%QcwJq# zd{-G-)SGW+MIMhP4FjoPJj;9bRK8f}1MKHWOQ4vj*}B~NixP6`46rRUlho3}1nS4b zIVB;Pg%K+{)W9IhZq>kp{WgkENbaD)m&zOOLp~mE7*M_f2`jBlwVhF~%6b%Gm%emet0CYkz5X4y#DN1pWql^9O^0!df@{3~r_?^ejFSe- zr<)DV7AEfIreCsu1I(^%`od|NwB-QO8m^eV{ISce&1pMJWwENN(Ax61samG2DPUf; z4X0w7>L~3SPApV)q(zF^IyKXpn~A;M1Cb2dyX-kIw5}IZFymc~XQVxX-)jRu?c7G+ zuliZ&S9N&l^rruZm)^qZR7xtBx2~m96~#YKftmSMV*y$WBXBg&<+i5-L(F`9Ed4M8 z%<{ku!+6){Ul9N~tTMg!iEHlUH~cT}-;GB`ST;--``=M*5J`QxE?^~*S~Erk<^Za5 z-e>i#)s+vF0!jv33u|@eH?I^7vZa4arzo*#%7n_WUssDhEx1YNe7y5!r!>2qYhbw2 zwr4&L*FIO3Q82tBC&yGFawk9hYFriLXWnhUv+@x+&eLaWrSr!9l@*0gRjyj~OpJ}8 zq7Nmd_$4%T739X~PU9={p|MZE&WuVir(wnu57vZ47K)MHYbu0_~1(b-6{5IFwvZN{oGmFO=Y zuTbcoFrP4-#K#pT&?rq(3jpSy-FfRVGO9SRyNkQYG<=AG9CnLXI5OO2diAwOFJvQB zdP82bc&$N|P2HWiTn_FqOIXV-k3|z0mQY1CI$3B~`GS{bUy=z_|5A|PYfeL`K3o60 z2SxqRgY_|`)mcH_QB~m%?&9lOq2%`OWnlweKl@mXLhWUTLAu3_N)jyUNAnQEjp-)yyXaQ@g%-}tft}0Gu-@m zW}&pr#jL|5#;b*HQaOh!MxS#Lkm&RT-`NoA@tZJ3eBG z$zdm3I|YM2^DJog=g-H8ou3a>eo@P5RY*{s6He*vF`q9;`~LCVwi@bdDQbHyk3vF? z+eH0=%MOnrV`1+Ww)k~*qpdf=diAtyq_E|@RMnz3TJ!_!O=^|KDVz@+38JIP0H69= zw|#mbbtPOFzQe#9{zeEP1?ePT%yg3zdG|~zXy(i)s@+sK@hR@7qt={Msgxb(W3V@~ zT*8~5RT$3ISefhghe4!4J5n!~35Fl}Rk;>74DLQ(i?GGf%=92Bwzp4ZC=H}zZJWfHESflWv$6gy$Dh_Vhv2E}>3bWlE zkB-jw+aygSA1y};PkGZ0NaO|$~x9KWDx~?g*vZWo#wp0W`(#%Yks&OZ1 zo>*^Z34N0wlRb|mwYJ`l%FxJpyJNAsnRbnzOvxhy0Tdaq%nKFswBt852n(CtrjunR zx1x)d>DD3d%w7@jvGs~oVl+*5#^xY>D;e@EP@rp}9T^NP>9q5vxphvkBaJHf{P~sb z&-{a=GKIrhXU-Inh89mhjcNdV0;$mw8B~pDL+d)dC1F3SKw`7TAw3+Yl>sAg!tpj7 z7>TS&v%EhOQahQHr)Su69TMxoEp`!tR~z%kf+qQI0BJF|D;jdwD}@ z0Xy&(6(#7UoisOIq=n~|gZ z7_X_0!_M;k{*Ih%h0h75IU)W+AALH34XCfJu^B!-(+BWN$VBmr%IR-PwRo*%?5jG*B$qvxknsN)qm2}S8-!ad9vEJN6r|+nVQb1O3 zU1SL=D=aXz4olNqj^ zPBb)Io8P>mvaJ{9H%a)``Yqi?=<{$ti@x<%uvg^cxtBGUwlhpq& zrT_;&(<_)N#Cly{N9&LUUgxrY_BBs*Kw_8FS!~Yu2+q}B^AIWE+fjwt`t8uT=f3R~ zMkRdmK?ha7)hAb7P!=`58jAfTJiFb`KTOq$x`g2wn$G;Ov$L~ZU0vew8mk^}_bbt1 z;YZft53bMwfw8p~H`3LxH(}=@C!56PE!eEl%T~F*>|@<4w~*_{d>OR&gFXv6zwsBh zozaWyu%nL6-Rxc6k-$l2h?H34N?T9Qg6{2(*Y?<30^fA}L6+ROs=nrH`SOGf zK<`mKV?rc?&i(inKpee~Ojm2sT31od*KpMGAV468A&8~sQ{{ZZ|F$#z9R?iMa}&SH zXS$p#!q(_}v=!7N(mJ#BLP-g(`J^>4#=F*~0zaiQ+T5jP!$i;##zrWL22tkCgn1h0 zsbl!_OOC|9Nki@#7qDu5s-n_Asu@ArOJtFnBF6Jpihy9H>w6B7%KB2~B-hp6+58iJ zh9H&0-eL@H-RHaUe^ftLY9IdT`t_P<6d8dJ=)qQ9{`?Yi_;*k_25J~ZrUlcBPEEhp zlB1c>{#&WDZLQjj3qqv)@086Oj@q3P%gBv<-|P?!R|guNHa(jsGDgc4D{v!uK0fj{ zHy!>3D`%z!{-a#kSoZqJR3+J)p3H1b}EOf(2M$ek5G%tIj$&7S6r z(E4+jLC-B;gbYF0}`ML@xR?_%D2N?my-zDsu} zu?~4Tz)Y698hV*Ns&fkI9$36B-1t?R!&8rX>d6n9Z38*|u<`A@lnk)RX{F9*Kj(~# z*`y`~VmQALPO=%NCO=dn3Y2|NSBlKixn+B-{dyn~b;vlfl6uIEmwVZ>WS+~o{YDo1 zG=h-a6hn5r=ed`e%XR>DDv}(OKZbXOAp|YmUfWaY&2oPJRLTu^QVX#kvid0aFCu3t zcH~JWLE|h2q}t@A7T%z(z8odUnLzwh#&|01iP^hJ)ZhzkUuS!h{H)}PerwFCc#iiM z|GByqcDdW54}|O|+|ySl*xMC&d?v>BpH8Ih+T1mqfI^Gk^{tAG3e!^5G}3rytd>re z!E9wRyFli&K?CQub+=+ zqL8<^s>4Srcir`onJL)}Bjd8F#`c^5HV1F-z9njC)r0e&zTt^UJx`PN5r@HIpAHjC z^_00m40CDlJiWJqQAZ)^10nXd+jSy#ZjdPuJtGsV(22G?%bW!235=y}SBiCQtOp%V!PWipk30;!NODd$pX3cV)8^vR*)h zG`jg)u#VYv>tBj|^+D4_6vZv45);!(N$I2oAvI-s2^V96h$--hE2}C|SJ}(4d2-_q zrsOJdGVsd}t4XWb4VBy<7_7Us`L@IZ+f<{(=A7x)(&iiP7l8HzunF~)ya~MaYHj4V z#u@&&$IpHRQCuclDS7LOBocQJ)bz1mc?41Yx_%+6W_wm4EVuf*=8D=cRRz%(9>Ap~ zCEVZOX~>gDFdP8wTo71y^R;H8e{!yIerS?N*7f0>P6xX>!HI-{eIhJBCz*T!bHfvC z8ApS+KP}taBIFMa+B&2Z1^1KZ)j^EwNnkuxDIL(9JIcGo!8^Dd<4tPm{Vvq$S>D5JfWD&8>JK0 z?t6<@&sWi1U773LbGhbwHze*cWQ4tbJTcstN{7=#!3z@FU{hnnE=yUC-h_Z$sY%p+uU+jEZ~k(yQZ(z&tav0rS7b;al$GE??n^qA>a;(jsu zkI$+|FVIgglyVJ2h;4_MUiX|%3Gq89*6-`_D7A6yMT7F-DGf!hUl2@N-KD&D73- zTYytirl%$08~$K1gxMhEz$u1Su!nV@dci-b8{@(dJ54-8+QJJ?e!TB?di1B|fmHPq z70=6p&r@`~Msvm(I0u8{4`}5e~z9 z58w$xRYJ5B6&~S{NNFj9$)7Fex*}RSavIY8g_AZ5R>7_9QBvxMu26+ca)$*kT#9 z5hC6%^122GKM_7hYb?XI}azZi`Kd+tsZ>3#6ZJ(_V3u~B#3enJetHid1;x|dVWJ?GH$9N*mS)U^Lm z(WQqlp|7sfig#PkDvWTHMz)1fALA%-H=Tnb{SIw)C*}3SltGECt%8u>I;gj-?id-5 z>c();YwOkFjQUqZEAWBa| zZysW5dw#e)b98+f6MfleLB@`tbm~yyL!SvxTOe+GxH>Fxyoc|AWWCel))wZK8T^e2 z{6Si<1gkds_NzQj@SUZvbW2mV_l9DgFKUmvq5)VXE}k_baNN+OtKyQ206ar8kF3s~ zFMmrDOioW_$-9CU#rU4?4u$@ABzj^p2lxd<1Lp)EBt{5hHW@{4hccBtt|WryN{Y_i zDDTzuR(AyE=O~HhwFGob(%tJPkCnZS-#SLJtbRSuQb6sj4nv5^Z)9fGPo*Mn*=T+-wG$yB41=a%eTscu-hwJdh)(r>io`$vD2H zxl|nQjW;SJf z@?hM7Q{#+_Re51gKD_q?*vZ%h?V61 z{?$+ab`(AEWHmzC<@YHve&rWhwnfbmI~;vo1$(is$O9P1oXCA^YZX=hs5d0t@%-pt zox3Ir8&&WcE2h8nAi#5BvE$voB3kYRN~aKx-x_np{vEk?fj@l2-mN3t2@vmUca(^= zuT1esYP@)bh?iBoLT)dw_Ltp4TOQSJ1Yx$`MNrN~ zb@zMyoa^YFoC?{MG+(Qw7O|qem6Q@gp1hPa(^Ai&`yv7t9-DEler_#W@Ld-WOSS!M z(P{sfH!~bvew69@wOm{y?UTZ?6FqhFx#XpT3C=mSOJeqVU-l7PB@^0I8U0VDD9WF4 z4p>#!#WK~?TJCb<&zXv_Kay{C7GgFR|BYN4&>Q8{D3RK){PF?il^{Te8dh1RIKMkR zVFUCwY)|Cq7gWEuqE`iwM~?NJUhC?HGuG6yG=bgqj-V3%T`&Dncoe|ITI!T%EWVwI97ZBT&>e&Sr3@BeMYWnqkXUPFt6ljj|O(uo;tB= zILwMZYnRgk5}Zn;d5o0Hgq7<*^)4QpRD8<8uKVmRw7sZq`p`GDsj&!waNs3?(gTNS zZ3RpTMzQ>3%+8z{9o0GJ_)f-@CiBG$(Rs3|ZudQ;s^U<=ND_1TK*ETFWi6a|)o7Wn z>BWk7(y3k!{~n6ZuMcRb295M$NQOu7ed-O{M#L5H#Liel9Nn0tfLd-o32~+97Uc8 zBjZ7LE3Zy_MwkJ4gUz;rH1{BCukv;2EoBm-m!GHyHki`8ML%&f0}{j^1a5!*QDB?E2svJvmw>HzuU3*@H*+@#Gv0>};4-J1kosB1^xj zisNVe03bLODr_@kTBT$+u^kntEfehZT0FVqpZ9`^t1K}>FW5@lu>higuC$a=l&z^ zAqx(J#?qOmw*0RTz)Me985;OF*>mDAd+@q9Lf6m44!+%ly;FVUA|!)6Y1PYZiTSGp3Xw>x@R-5`2~hZDdmyd!yp`~GCmzb0Bza0<_U8zh8}y}@?h zX3sFJ@>(KftUb1>iq%UCjcCASyNN1zmjw6Wi+485evMxi zkf6ylsBqXlTL;T5pr0MYKVeinInB}1yt@V2Du^$8K*o4*9QYk-2(K|_K4os46{}E9 zDe264N!|n-Fr1vN5Md?wF#GB3W5kr3!W`5k-RQAn9hLsv=dtgO7B(eogKw?l+`QKhK0(R^Xb^g_a9~6bCm`5j^mufuNqVVm$I6Egat8O8 zA_VH#L6fr%-P4SFavo!@p3tUXUg*XR{|f1ewbRDqOs5fs^EMCUffb9rgBtF9=7w({Q~@zbBZDY`T1(bi_8uw2Lr-qJ&$hFGg1Kk zC>gm&61M)Xmg)1zlIc=a2jXxK&`p1D14xtc9UE3U(f!lcY(#hnM_b>)74ufW%>NdA=&s;jxXm_=U; z1@8LhSB}>!htBRadKZX2uPWD7tX)&ofaB{~OI5~%+L|^LPE|5T?aGrGIhTBb{I zN={dOa~7+$Q=u{{zKtXC!$t(Z+IA_EymgAVIhQXx{ z?R7L@XNRZz1H+)s#t>SK6Dr^>E7N&!?IJa1#{G0%3*xo2^|<^QdwcGq)Pt%j!^iB! zM~1yTg4K;REQ~l7%S)Y1=gvoShx^XX&i~TQPh*RvHbb}bKM1-=?kk?I&3wEk%P4SM~L<6%MCvU0S|Os zlyr4wS-EKD`_wt0DLmbXZ&R~28HC}QS16f8$fdGpNlJJZpP8D$FN>UXmB#Nvc16Cg z(ZMp6>MpELuAhpm1=Nz?J$|59%CTljx7rNr+go7$P1hj8t5m0t&J)_C>7 zLyW$$C0Xp$zVyH=kD8a7fnZROp~CD`kB&$0|9Peyk;AH7vd zV%HfpXyU>P-SK8Kvz-aTL2_~vC=CvK1qwi zj;ZXi(Hx~B_`+1W@%x;ZQrX%b?Vfm=gV4O?a@5|~%GW1?-5671Q01$t zsBuJ&;LI5PdcEEj6$pUnFhPwiPt4DY^Ab%5-u?MJ&z zxyH<@s^_fVjO56W+KHjw$9yNcM8kT70Z%HCA%L=T?P!-m_ne2yNQ`OhrS!LH8zZ^S zI(yV+B%9$e@wJvR(Q)G2?=gC2;qQ(MyX8P{K2$-k=_!mBX;o-v6a<0pzgYdLO!Xj3 zicQlkHCRvu#H71TWInE+H9VB!syPrca#;@!N6mMJ~ndo8tc_LM@}wiO{NQ z7NX`P1g>M34Tn7fOM~D!;8&8A6(ggbe)ESQBeK-SWwgLx)b)eWG6@xQ#XzeC-_?L3 z;5m!&srK%jJr}v5A9b4u^M+&;PGwKqTejkz-F|CS%Clmvmu_Bm@=i+e4Es?xlko^* zd2v2C*LN?t3ZHTNG!*+lr^)r1#0m;ybJ~UZVfk-$86S}QsE$KQ6ejf<>*Az*YzJWF zJ;tLKvZ%BY|5cZ7`|bDgE|ODgjiDf~%4WapT@6^=c_`qK8CtwizMtp-Y$_$zx(-DQ zrEk8abK%mg4}49N-K{Pu zvz^_(wt-w6V(zr*6m#Y2-gwg@wL%dBVHMob*sYC?O2BW>(6F=}WC&L~{Q;GM!OUs3 zhNg8)oowh|1*Dw%HbSRW<(^L?d4s#!!gY4PJEBrbv^f^f4|F|{>jpixT4GGgALtC$ z7@Mp{N2}rq9AeHQs;4o1aNXAq->rL3+1_dmtQg{XGm-dv znM+43#gU@d^n!aS#Jj`}V_^7B?!ISoiv^0@{Yo$;mH<~l)1ftSnfbvC1Fezk+6?Xc z2jCH~hj3dAOz*WQ$1==-xyW{!Y>mgTvh-p2Dl*yzs`UK;;A~mRf8yY~`38&wi*7gs z;`Jg+hx>a~*M_7`IA<#{q-?{Jkxgtl-(yFr*~HY_QvFL9+aF4I_jlbv(_rg{pEOu% z8R)csJ*&ryN?g?Bmkh|#_Q2%3Pip00NC5hbEZrG`&d)Li1aZy4rCtx2Zc!Pn1aB-b zd3o4I+Quohp8(yGUbd0r*O^s^lX4)@Uf5QI2{bu>!qy+Cv6*~O95BBHg~Q_nttv_I zQ?eqgynXO{q4x8v7uL1uMnzW2Y#g&cB-3cX8XPKCB$G7kqDzFV_n3li=U?o(WX@P3 z=ZjwXT*2jWE!*^@IRcFDoT^s(L|FSNPtpE~P*OU$S4n0aAM(wWwqIM5v6&c`y zsIY1ei7l-l`1D-IqVQALR){AwT6ltdBFgAu7Afc?)HT=$3ESU{?#p6=^HL8*x68ia zS+ixDg9U5zBR!2tV2fBHj(X0@+Az`txuEBA zNbv5s!Q+{ZQ`3s4@y*)`R^Ww@h~j9MB6waXVvIy;fo7!ouEY2^t1EyXOuEd{nFy=? zmW>r==Xi}3XL}F={)Mj!8i1R&6Sal?L1wq5`1Tk_lO5m4di%kr5bRuF8w1OG)8}y4 zl%l%5f$G&QLAb$u*@%vTwNst9e#V;klra_&j43Se6OBvX{aV5meJNZG>%-RiR!=B! z37I&G3(^Z~-M3YLR6xNL254>!s=C&~k!MlzZ;9~;G}eWegsSTiA6ZAX3puJ_YSg&vXjtW7hk0u!_y;{D--zSJS$N2q-xADrHh&7?TGyZyy zt#%`nl7fw2{%a`trTI-^j;68+Yv<@t$vu73I*!?OJe)8 zUQRl{?q+TMIT{w#wwV!B9R=oIF&m}pS%+(<5BpzXNAVUaxSe=s*JHLmuPrMX$25a!Sl4p&?#G~s{s)B$;}y5Y_>bB) z?q1Xdf-m6q>OfKK%M4Etp^7511e{pBI?Q*S<_&1ME6uQv_eKF3!^*hJ3x}W?tr@yy zxdRP;qMJg@3k5-dEE$b~lSHb%UYj5SL=4Sg9~$NyenDV9K)>+bTl(USJdS3htb^65 z&PDde_!U8+2MpIW>O4@SEn)ZomF~=L&I1=b#kKqT!*I@_VCjZNY#JpEng%zD$W*&k z#$^NSSjY3J6~eY|p0yj;5iCNu$ERJu=TmdUGw!>I$%={Yy>aTMYG^D>4eLCRc%+)k ze~Wb@6pn0PdYf_9Wv(tfL=RNJqc0Dz`BbX zaq^&#ND3skOwf@(h1uY?dDddf1$AJr)z&+Ht5=Cp^L87IXQ76vpl|e5s%HyI-F<3a zd+Me_MwMB5hSKKFEbkYGO0_g378X^J$R^3T`Wtrpa% z(*=OAfZ+NcWMRk)w(h=Osixuzh!GdOLGy%-bV4`^;C+Yf!5plS&RxdO`mFEF+uhH* zM?CU}KO}AXVr0h0dY`l|r#{~;>e}PuRk%+`Q>OefX%LIcEUH9hWKA(&CyuLLayj!> zm{BsfVN&o^AcbsxT6Es2XuZ$5q*!7C)bT~ImIX%<)_Yvr6d7Rulk@$g$IJ`8*Dx_jKd#bRZo|c3Bb0%#ydK(Gf*|n1L z0g)8n{z0J@HIWKTay%`x@O8BpEqr}ITL58(^%d(>P~z_oN|oN2G%cN(oJN)ia4Nz?YXGs1B=#JZ+7Ozc7I*#$m_=>%DPA7 zlGj=dKB^ePu}1)5>{s3e=e!a9Se7>R(ma2P{dvN zF2Yrv2CtH%)LpJ$tI*VTBg#Y0ru0?(fm8=)X7Md4zu;#{5QWOd*ayXY-NGYhO?u>t z@;Vq$uPvn$wJ0^AHQC^2C!I+89KD|$TC+7u1<%I0V$O|gZEPuhPBhk$3l2A#R9~c8 z9naBF!D~_?sRs)&hufau0Eaxsoe>T%9kO>JBZS*pmL1^v;@)mCc~*azoSop8#+iu| zs;7NK|i$EhGGHCMY?4Z+m!P=*jtOMBmEGJS3hGriO~9FG%0SQJr%1fE+jh zfsD$)@x$WNfa+m;9$9}dJU9`4oWP6{=0$YLf!tVbm@QD^@ z{huQ_%`H7hiJ>j^wp@OwvNok)DRtvVIjgTmoeXN6D;;58?!q5N8EuR0>+clyQUAPR ztwuUJ$BBEQD|#4mQ__C&*kyA_90d6cTiXY9?I$^T@H3(7G!6f>q*B4cK42*#f|@51 z)|0T=u0|bHwILfqDGu)S7z}|czjZ_u1<6~M8}}@Qa00#grC~6LZOx{CzNqxzQ>+Za zj%A?$!!zPNSy92~t$JRbCq~!o$VHJ9m6a(b#^*wV5gmh|g`w*4(X!m>yhqWrRJwxQ ziJk3NW5=okDhLWk^H;x=fbb5{8dKHmq_{Leee!1)0Jn(@t}LcAGjQ8W^Lx(T^c`7a zwMaVlqz(+dC&Z?)cpX3PBK_0iHs?^7D}S4FV-|MKK3WFN6$`RFaP`9DD0v_nfo}cze`Bf7M<%dtzQ}(9+dqN8#|*qp)WFqBrCT3B_t*M zDI_gn0v@}C`7NsZ2Ik8(+vaql@(6hYk3_uQZvI9;hxW@1zxiX&HhL*2 zRT4K7BXIUvao&CNGG>niBpHVhc5hFYQ`tU5l|CpoNGbYdS~4%LDi*HJ&va`jhY(xa z<}Y>(>;J-!^plEr{y`t{$;}jXWn%DD4g-YDehEdtC8fh)wzz2@d&URwru8ZslAC%y z4-VVFg>9Ac8udW;iOCwfnO?4S6}#~k8=$h16>)<-pJsl#B!Wl7We5HSIG(;+Kzu?> z+Q-22--)6)72zrm37S0Ok*4C&1Rjq1s!wzBc(U{>;f@Zz@8;;;uViCr(=%^cEUYf* zbt82AO8X)g1x;aF94WACTd-fDq2YKRopJEEMUB0Qg4qBKA+ah}i z0egHqko_<*yvkG>zYX^*Ep_d_s7hAT)19e0QYEx2wVT5CQjf2e@KD7Y?d}b1hO=K9 zmr}@yP}dK)#FT7e^`>rpf~7ROb&p`@72R5*uRug$>gRxj`G* zvtrf%;D*YUThEB{yfX%asp4Y5ZAjNkWofM3!3bnf#Lxep_E&+5VV3hZHpwTix0&5d@inHpmk(u(1^j zdRskn5zk_t!o-@WBTM|l39M^XIunH0!9IO!omsSe<0siu+WGM{3mjKfKse+gDA5!@ zdI)E~xAuT%&NK<-!T%P0tXB>fe(6K?-_R&7>h<$v9N_im?jKwuNAEVA!C!e`1BPeVuinp8|UiECF{ z{@2v%yPWMGqMfL=SX#8VZf&K|t+&d9mM_;?PgWhKs26S1xYg`&7BBj(u1=5LYwY zBP)jDVFl5#$uNj3-plA@1c=>n^$AM5vaFLc_Gv=Qj1{2AEKN>+R@#j*q@vM>1%UXm zx@`(7MOK>{wITa?O~dDa`V*cM6tx?vIZEcK8?Z zj01#aCH`@)AsJZn2+0aCgKc$Z+Rc*TX$v|@v}6-S*N^ocjB^JO_F;v+wG-^>exk{) zGC`=tGj^VDH@UUY&F;@HY<9nRTe%egt`o+hm-6RDjQN4N-`|%MMPa{X;fhNe6 zRXTv%-9RKf`pvh(^D^qWP4$)^S&@*NiDb%d{2gk8@gNMsJNQCeo^|Dovryiv^D1L> z=xJf{mhUiz#DBSrK8b%d(A8zmX{KTDL$|#lLJJOp(;Um+m&Bl-8*g(OE9E3nS_w$Y zKT|%T+$qN=YxP4P0yd}dafe@Qh_9_*$sMjBYmhAc?_P3j8B@vOJFuEIivL;55x80N z6`%$h4HDq^V9;l2gJ$ek>>qo{%ENv|DP8G&1Q?$HKiJ=3i z0e15eWSn+&X2xC&u6*M=+!kXi{q_9ChBe+&4HQKc73xp@r2x4>_zwE&7W|7vE4J%0 zM(L+zX_X$hY$*uRzcsO2m>F3=ed-gQYEDpXT_5-GSAAut8mna@#tSAOQmKIz)|6nwM6AX8^xj^m0zUph zscOR|iQSLFw9!}><+&hbuwU7!&eGqhF$n-OcL}p`{T-rxd|>g)q}{#L9JIL^5O%?f z9^}FyR$B2@`I&HrNrnE^`axWc3$m4*#sv9{qKVI8m zEeP8H&gDmL7EyuOQeh$8aY)piqSdwIwy1xvLnb;#`p1?F|94PTnm z$sG&IkhB^G(>M!UHa!6HtGr89o>+U= z6hp;CboT>PkCjd`Ese5;JBius#q5r{Rn*hg-at*Rnf~b)-`@3$q@_-Up1JZ=Eq+c_ z);oyZWj)KtiwC6z%jsCQg1U^4>U%Zn!gGf3H269gqgUVTV5V#+Ed}?JA}DqM zvz@ckFH?F{Xstl2r?@#~zu=aLmIN@?_E+O0Y7>w-icXZ zV@0AXZ#j#Ln6AcAo8Ww9?NNQG7x?7V|7wEb_7@_Dhe?2p^N_FJ=I-%J%bbeI>1!&k zCnqv_<|s5^9S+&s*xclpHIUat*il@nE%ze6gI(+XPHhS2Di6DTLuy&$L6eF;qOWTQ zWqywspi;Qn3*6t~YmBb>h4r_2(UnbQX*y4A##bu5v*wYHPqd=bW`)@W<9Gl-eEpgi zRv?*=;eby@v0v&d+T+X{4C#%^=c$6`sB$8}6hwCncQpJ*G3UDe9)NFak(cnzbL|96 zD=;N=Y4!ANEaXu+0XTu0=X&Cq{|5g7>q7#j&Dl{_-S8mK)pTht7QYcd;1u?-k*^|{ z$Q$&=OalU3W_gMX(N#N&JWRhoZkl`P8Ks7vl)GUF1tHd4Vt@*0$Kqr?X5z$L+x>iM zD~0fRtTbJZq4;yNBZoV64xv*|iA`$K*wh(WkxY~ATTT_kO_!XJ!)*J9gPY3=U|8f3 z@7U~k&{dZ;`!CW;>~Md-GQWV2{jc!unC&@wtsyP*>GQ+X#aMHqzBNF~AO>%1-ts{> zsd?^28w6t%_Rp0mHXjw1-y*tSXc5QS9N-;5`ME{*^OJ()c9tMA7!r_ENvz#LbX}4- zttMgVsp%zH`GCR!$00+dK}zhsAdKaP{u0nEV~)1Ad!g^yxuTij{qPa3+0h*X0d>yZ zbhf7>z6EWMnSpz^4ltS4HY#BWpv9o)lugWe~TAWeYUSh)B5FA+lNbLfJoUy4-00J+zehd za^yJRIM2d8p?vh{`!$ti$4g@OWnoP9b;q8b;#{~#5F?-Mo8zcMu(z{ zLLpDxF7bE!q=mU@Epd{=Q7K07Y=T(SoxTPa{_%UcnKOShw3j;gp;eEdOVwj;T?lPT z9H4rT$@2+J#`YQ9Lzl;qK2Qr;S9cZG#K+4F|-!{`9@EmLiWl)z; zikGIN6ZPAk8N0tau7$8=m6ivhfFhg#1JFARe17OJ`%WXxG_KZV1(@E0nb0A^kjz^* z-&P&oC0O}O_-M=(viDuxe)7|0lbF$TyFW;Q+<4-3f zmqEG~f&T*^>c#XwQ&wy5$+xZ?mE zo>|oj5UyEi351Vc%ym@ne@bEbbV$nGlv2Z4|FPzqpZ*u@rerEGVe)U`n!zk9H}DFI zK~y=`rhqltGEMtcL}O1`+^ZZI3^Di5M)lnOm~&)GN+xY+^#S&xSvh>^(tYkF)n~c8 z3M7|#8ok~zAG=;9VHL~OGs8s{wg0|}w+%T;yu|Sg61c8G5x2d!ubiGjTI;RNp}Gh8 z7~L@%p|EE}-w~>p*6VW|*u&wf15IVCg*<29Vvsp=!J5dn-|MW6!Hc_8L`J?+)#w}6 zXT1RS{{-TCeb*#0uhIagUAujtm+K>+P*oiR6SnE-_QqaKeCNVPo}Utt`e_T&+yD;~YRlt}%8n)tye(Fz@NJYL z`mi_;V+8E%@5X;6c+SKmNsJ=Tcdkm_oJLVM(38b9$%uVguPiYUHUgo&=ijRB_lC2P zY;x=7-@>ryhECv}fJ?mvf~7Y-Hpf4Xr`e%ZIc@Fwn@&<>8B2Qs5QI(ZfihZ7t{&ymQ!4mcMYd1X1;lnPM z{b3zMTcHmp*_%A?r*1qrMeEas?Ht?7zntk7xt4$&k{K52%_Grp!!z(oUk8^!X1hwG zRN^i8Xo@g|i?({@RAWx3IPq*B9&s^QF5@()y9arhpZdT6@TtSj9(k51tW%8$2QIpD zoE16=^~_KMi3Cz{lM6_mAKo8J3alfNCo~vl2E~H`AN%M!wDp+6aS5fjj1M)$5@A7c zd6(r^!$_AG0U>3j@;i86PNfueF)woOT|sLN#_m~{Ka$wNy1vs4y>nY-pV@W4ONt%V z-=&SP>jiraE`mX_FMqm+qM=XpcI$;aJA~KWBCD!&gI}vb8Sx_9`o!a2&Wl-y0m7`r zh7`_@)XxCgnN|%{`XzTXFE986EoaE$A~^` zKTkl{0R(VC1lhw+q^-ol$FK3J0Z z8p}*YemE&ixmyP@`mtTd#%ja1TS#xf7;2iLjMQ>$G{nLkfyGl2Kgl}L76%64*lQcE zYo!yMeAN_n+`7qU`Byk7RT@+up>Q3$*ot37%14gkUb^Th zCL2!Q#4lSLj$@7sTGym9#xEAnxkHJP3r62Zd3y@$0ig19^`;WIVOqS07JVw$LuwxX-YE_6o|aNpymJrcv};PEB2T(4ZPf-ZIVo2(Y(x89L) z4p@}3vl@n!XsF!t#8&tt_4F7ot`8V)Y0*d}8+dDxAZ}}?o2i{OWT84>b0^t5``yjK z4fty%EpoKs-r&-3k3lr+NwB=G;aq0Of{Qd(38s0=R}hsprKxt__e_dXrYZto}g`q#eWboy5g3p#cv^2K@W$5KXwt%r)OT) z+ooneP4?cVM_-$N6a{>GmCV}-Gb;7LEBrcQCop1Abm+!=pLRi&x`1TuRAZx%pJ;iV zH*ThXL?1M7VKj91LsL}2ZSCw=;OOnUHf zxfjlPcUTP9^9 zqL1(ta(vuR=WKNjGO#ZKqG73HLc(tJ1u+RD?DP-{*Srwg2cr4m%BH0<US^OhfAb zCXkd4A00@#XbS|Aau!Zyn$-A)G`6yt@gci%jE%{ynYd6oAMVJAp>P}qnx^_X>|>zw zc9f4qyreqd&Q2eGQ(@K*)2YbeZI0ej!Zg-+Zu-rrZNQUhM_-Q5Q<*%0$Y-^!*ORn- z-lWxY8}*reIa7P%R{lJ>Ei^&8l4{H+>$iMT)5&gO4;_z&M7gXsHP&3^=93RLz(SE}F>?FVKeh_P*OrhY1<&z`=1R4aB!>-kG%>UM|G z?EK%;-i^freSuhap-6O&yP$`q)B8zWTnO06(XsJ7|73od5gA*O^r`j3z-6^bJ8(_Y zoap0dMc=n#zieHP4{Q@vqsmy6rk1Y+IHWOoPxFT+!Xx6=f+-iv(=LW)n*;>EqO;`` zU6HGqndh;1!AVVx(%%GWG@o1+`oN3tirTaP#Q^i~2`}*Em(T>pjQy7l`RFfzfv*2K zXFC1-3|aa(WgvV7zFUiV(Z|X1rq+(<`(wX^0?Lmgyg>#;r)D4eu3w>yTzu3)ISu2opO^cR|JVmh%e3M&ejdEG4uuxs>{D zb9G#wjWeC7%epx(4_+NzGe4t{UKGV$1KQwbvl3f=*(Ek%WIJB34z#fni9Zy~jPYdo z7y~%f9~BfC`l-CHnuC_`6#04lR#?;KQSm$xw1eXXU23E+jyD(?6X6Egf1rCePom zdRfpjXD0a8E6C{Nxo#IgaTh2HXhRLhA$%%_Afc9fxe_VH<%f$>^K-t#@SPVClPm5|H(a{x~Bx;Y+kr#EX# zl3arJGdir)E>m^4<4(jYbe_{+*7;9N#shDea zg!C@+?ttDDok&&4)ZB=Nre;iM*CoB(Q}KxX2fh8YuMxAE`Xd{nRwFS(?_FOZNOtc7 z^l_a>`af8$S!9UtAFOD_*(bi6ASg3QisXR%GR(zMAsW@@G0If61Q+mW?XC zEnm9_FG=2%#%zjj?{KWzY`B)+(AzjDSuqT|C=D%JY<@L;Qrkuj@BE#h?x_-9y#2{g znXzu~vxICkXR6dkpksrX-c?D}UFsMM4+7GsObXel|F|cJrGz%x1UU+}{WRJzTj_5d z4#Xz7N=cm6_~mOi2>{#nniH~|!iH}l9u{5|2~g592~ z0I+eY;mS~Q3$h$ac=5tvRyDJarA}oJKjadlKBn2BTFmL~+`i-6m%Mu3X9G0G!&huO zJQ5;ANOi?gyul-;8HSz@Bb9PkDpFNjT%~s^(+w(qnBqS;mwDWzJx0F46$ooXw_oEr z!Ser5D)K8$uxYwW08#3he{VgvJ~&Qbts|E_EG(Ufk(68w(2M&EkZLcqc!{k)kvz0( z`_kPdD-g)5n2C%dmR4Wg+))Ru2}mgt{4$@T2`QI8-*x|+pjT8m;S=0b7dm!bd2}&& zu+;~!{^KqOWs#B}R=o9Qch67h&LV}T+f^NYY)4pMJ!%U%mrcazD5BTdcmy1MJZFX| z>7?c`Vt36gP`d(s0rs8~_2yYL4LnD>JA7;b75;;yx^%2d!s^^ZO< zlm4CIv~(bi^Ogt}=3?}Rj^_i9VGmS^8E)2{jqOU57Yl*4&ato-xoi>P>uw6XvM(vJMTnu)`Fz>>=1Qy z7?QZ<--RKScp2qTY!E$!U*Xxq3i(%|;;u29y@y;zjRQ-OW;KZhi?gLp_to!tF3V%9 zS%>?j&I;f^4mL7tVfVuKR+dTD>9O~Zcg9q%`)Bl%kR|E@79?b!K7`jKD<{>0E^2jB ztkBc*Xi;LGUxH@VjX3OneHKTtLB$JSNoSkkj#yjc^3LE!rb9en?Xy1JJs`m9ed^U> zt=^d^1MwYGwqj66ECWODxh*Qv9kE!NP|b9-U2KFD8_(`Y6~e8G*Vd-KYKIE6oPna> z>46sJ(~V~h?`4+vi%<>BjZjU}=uVY-Qn&`dVfO0)8r_`Ul=P9PV4f0ejQlAiL|D^R zq)&CXFYXXlfQfI8k)sXfuQMfAqJQvH6M?nL)4j8^3#I7O8@84w-ii3}!}5@jc)5>A@eUURLhI0VUnu>U9yO zNb3bn4-1=mH9KDmuK$h){Ii*|s4@8yRWznnQ+5&V28s&&+>D$fAl2rt9=J_@*)EBc zMesRmCasC2KWR7y_jso~9?dB~pPc7`#t9kL-Fv{BCM$UbOkmR7s_dZTez-J@73c7- zx+Nwyw)^u-tMbcmcguf{DF>pDus0ymX{S2PAL_nbMO~`~7BE8c4nF4UeSBT6^TNA{ zg%Ju$rrgZ`1Rt-vU6btY#pMb8AFZbXXH~X3nO^Nx|0o?dp`B}x|EC0cn}O4l9X$fz z_<_%(-Tz;q?*OF4Bk0xwh-iY49bgN$G=o;vHu$PR&B-)w;|zMI_Nzl)Wl>I$(8^*CujTPZd~&3D^WI0!4*(!dIoKCk z8a!7>LI8rymm26AdCvbY`_lVWpMNUJS~vn7#MqWeVh6voSbhslwP!XeHi$90w1`_h zFZl5~#mD5TTs$DMbB6j_*iCZ*Ia5T=Th#a ze5pbEIow!EZzi+;XY$%WBAnANyn{~KeoK7 z;~oP3@q$gw6CueF*I?^L7ERD{+n6re4PF`2SQmX3G;~&=EmnlI?XZ2pvI^gSvQbsv zwZrCB=`$sG=72_aY#Y>9& zIg$;*ozg^a6q)w@0A{U|mJ*$2aNGNZW!gw-!J(-hW(>Ewe51iJ&B{ap!W+1`5NRYG zcY%%0wM8#V4%)Y0?+SgkwfIF}P@NduC z6df+mlpUd#S>NCTzMG-?@`A1jQs;t1b1{aA#fnpJ4~JYSItNr@+rnH&gHA2lRE`0^ zfB)>#RF0ZZbFjqn0DF8LM3P0}x5UdzO#MigU2KAhJ#`9m!$WXpjrF6k!axy=?H{LkdO#fL zO{kIEkCgCkl@cuc;s)6RY!KUEvFfE69n51zOx1XrVPG_2qSl~sFhAv~xM}Gqx;3I| zxu9{4aj_z|&oMgf{`3Xhy9xt@ia#4`NcKBaA=|Z#iMpTnVLri{aEh*-1Gp1yF0?7+ zfZ8R5XZjGn^LnmuAGDn!Bm7+MXY6P@I(9Url6>A)(6Zpt$kQ%6$aFE`^u*5EXJSrD zV9B>o9%d+i*4+lT zXL=!Q^YQa@_1X+x5h<>ke#?fc4``?Q2x-x-;BrZF-r0|a)9>)mVx;nmI0J0D3gsZD zMi4-7581tV`}Ms6ZVtqGMcB(9F>k0*qSs7`4(`=>1`N2u_HkgINH|6oIDDC=!)R{O zc>M%$(72bM?RO*2xL8FlHV=E>Gby5Q_BX`XDZ5(l-PfSZ>-RCAg<=Mr^hmlk(^758 zLWmQfG}=U{c>B0vq(w$72Si`<{4WPOA2V_@07 z$H4{hlt%9lH-`H)8~NUe7(QLgVN-#e1;Um)S06mTPdw6=Wq?h7_CvJL*&6g97c)%> znD5oi#6B}0^V|l=(`0GW?#VE?#?`}_v#5>;6zJZ%&9VGK@$QVFVZu$7+_`?IO>yeeTF1EynUG;KXw8nJ=F@%1Oa1dl-XP~(v7{f1-#1O-Ds`L6zSQl@ z_rR~VNQKP3@VpPa)w$FSb)@v1cc^V=+N~_PP$1)5c;UuVSN6OFsVz11o8Beo-6I!1 zmhaLdPoo7CpF*zwA`PYK(x2*IiwgJwp7m5lPBA{49Da^BzhTzX46CQGd3O&n8%Ikj zj%!#>%^hm7fSgtTUdzoeoA4epj;cC=fbhCXgD^mveIP>OA!l{OEnohA(J|UUN%+u> zR47h!`=oq*ktTBm37<)PacH-G0*;$FF0M;w6D zhMiw#(dvvl{!q-$FR3PaZV)WU;)~625*RGj7(kWwVr-So%SQvSWU+?RHO=q6bYE8c z1wsYP_V%Bg-9l142RfJ7AcLc@@U7th7G4CWeQj2$zH-DCYM&yjsyqM^ZQIvn<}fg% zT*N584ckp%y$!!azQ+7d><;`PF{85@}SzlrI5dgP^)ozw{qwuGY$I|tsk2JNa zJTKxeADP&hm4{=8mEPVT3&9NJce|zJgzR!CI*Wv13cVF)3QaTBelq+MlX$H_SI!@8A z?0f4%cb8@UdDMXQ_^)B`S4i9c<9VjJ$332t8`nu0vh(&_2>uknUduT;zf4JuF+o_? zqiXCf^&6yJ=)C_O$u*FZ{-toGZyzray70%9aa;F}U~%R!6nxtE2|AGq*vLf9y~pqs zb~FV)c1*yieU-2Rn_;DwZEE?&WYzVv!a8$v3=N@6tHzSVm8QSVhKj9a7QK0H85uX# z)BX7go)JeThd3afm1QVfT=!}v&vS7G^#$Myzsn{E6Q)#7IyNMy(~kjSTXs?6TB*VQ zN^-j0SPGB%TgwH8GrFiQoZ1Gx=EK}V&(8A)1_uH&4K78Lsmhk0KJ|i-ojMFfXFw;8 z&Rb44CA^eg6Y~GHcGhuG^!@s`Q4tZ4ZYgPzZlon8mqxl9mIei+L%KmwLXa+D3F&TF z8YGr(SYXNDEZp}~_w$@{UcYnrXK-hib-weRna^Bveco3+)O3${;3u--@LRyHO=$5^ zPe;8QB8?oVyqdub{q0MHEC3WL382*j#s}g4?7QyL=K`Lb;hXu^3{M=DJJhib$y_}} zRHl5Cw03`0-Uk}1YCfnXM5EymA`VB~2~n%mvBjehC^u-+)PZ5ti?C6!20cZ44G;>q zBY>l!sv?)apKQfEQ&zv7clUK9W5c9HY@y;{Bkt5S9@QxT{CQreEuiXEHK6daVw!Gb z7ycc9s`!1~WRjIzmn_V17y *JT38h+n1B`Ipbb;CdP1^B0LbBWVNz?Kh^`b>IU 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 Date: Mon, 5 Oct 2020 21:32:22 +0200 Subject: [PATCH 16/30] typo --- src/foundation/y_ci_check_registration.prog.abap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/foundation/y_ci_check_registration.prog.abap b/src/foundation/y_ci_check_registration.prog.abap index 8048a650..393a5c33 100644 --- a/src/foundation/y_ci_check_registration.prog.abap +++ b/src/foundation/y_ci_check_registration.prog.abap @@ -2,7 +2,7 @@ REPORT y_ci_check_registration. DATA: BEGIN OF comments, title TYPE string VALUE 'code pal for ABAP - Check Activation Tool (Local Only)', - runmode TYPE string VALUE 'Please choose a runmode', + runmode TYPE string VALUE 'Please choose a run mode', END OF comments. DATA: BEGIN OF messages, From 2424ea03ac20e18d92dbf45abad75fd9ab2ec18a Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Wed, 7 Oct 2020 21:08:38 +0200 Subject: [PATCH 17/30] allows run only once --- src/foundation/y_check_base.clas.abap | 43 +++++++++++---- .../y_check_base.clas.testclasses.abap | 55 ++++++++++++++++++- 2 files changed, 85 insertions(+), 13 deletions(-) diff --git a/src/foundation/y_check_base.clas.abap b/src/foundation/y_check_base.clas.abap index e144ed31..913b2e4c 100644 --- a/src/foundation/y_check_base.clas.abap +++ b/src/foundation/y_check_base.clas.abap @@ -31,6 +31,7 @@ CLASS y_check_base DEFINITION PUBLIC ABSTRACT apply_on_test_code TYPE ycicc_testcode, documentation TYPE c LENGTH 1000, is_threshold_reversed TYPE abap_bool, + run_only_once TYPE abap_bool, END OF settings . METHODS constructor . @@ -47,16 +48,17 @@ CLASS y_check_base DEFINITION PUBLIC ABSTRACT REDEFINITION . PROTECTED SECTION. - DATA check_configurations TYPE y_if_clean_code_manager=>check_configurations . - DATA check_name TYPE seoclsname . - DATA clean_code_exemption_handler TYPE REF TO y_exemption_handler . - DATA clean_code_manager TYPE REF TO y_if_clean_code_manager . - DATA is_testcode TYPE abap_bool . - DATA ref_scan_manager TYPE REF TO y_if_scan_manager . - DATA statistics TYPE REF TO y_if_scan_statistics . - DATA test_code_detector TYPE REF TO y_if_testcode_detector . + DATA check_configurations TYPE y_if_clean_code_manager=>check_configurations. + DATA check_name TYPE seoclsname. + DATA clean_code_exemption_handler TYPE REF TO y_exemption_handler. + DATA clean_code_manager TYPE REF TO y_if_clean_code_manager. + DATA is_testcode TYPE abap_bool. + DATA ref_scan_manager TYPE REF TO y_if_scan_manager. + DATA statistics TYPE REF TO y_if_scan_statistics. + DATA test_code_detector TYPE REF TO y_if_testcode_detector. DATA use_default_attributes TYPE abap_bool VALUE abap_true ##NO_TEXT. - DATA attributes_maintained TYPE abap_bool . + DATA attributes_maintained TYPE abap_bool. + CLASS-DATA already_ran TYPE abap_bool. METHODS check_start_conditions RAISING @@ -125,10 +127,11 @@ CLASS y_check_base DEFINITION PUBLIC ABSTRACT IMPORTING message TYPE itex132. METHODS get_class_description RETURNING VALUE(result) TYPE string. + "! Method to enable run only once feature. + "! It raises the check only once per code inspector execution. + METHODS enable_run_only_once. PRIVATE SECTION. - METHODS do_attributes_exist - RETURNING - VALUE(result) TYPE abap_bool . + METHODS do_attributes_exist RETURNING VALUE(result) TYPE abap_bool . METHODS instantiate_objects. METHODS enable_rfc. @@ -146,6 +149,9 @@ CLASS y_check_base DEFINITION PUBLIC ABSTRACT IMPORTING previous_config TYPE y_if_clean_code_manager=>check_configuration config TYPE y_if_clean_code_manager=>check_configuration RETURNING VALUE(result) TYPE abap_bool. + METHODS run_only_once + RETURNING + value(result) TYPE abap_bool. ENDCLASS. @@ -677,6 +683,8 @@ CLASS Y_CHECK_BASE IMPLEMENTATION. METHOD run. + CHECK run_only_once( ). + instantiate_objects( ). IF attributes_maintained = abap_false AND has_attributes = abap_true. @@ -778,4 +786,15 @@ CLASS Y_CHECK_BASE IMPLEMENTATION. result = xsdbool( ( previous_threshold >= config_threshold AND settings-is_threshold_reversed = abap_false ) OR ( previous_threshold < config_threshold AND settings-is_threshold_reversed = abap_true ) ). ENDMETHOD. + + METHOD run_only_once. + CHECK settings-run_only_once = abap_true. + result = xsdbool( already_ran = abap_false ). + already_ran = abap_true. + ENDMETHOD. + + METHOD enable_run_only_once. + settings-run_only_once = abap_true. + ENDMETHOD. + ENDCLASS. diff --git a/src/foundation/y_check_base.clas.testclasses.abap b/src/foundation/y_check_base.clas.testclasses.abap index 64b6bc93..dd84647d 100644 --- a/src/foundation/y_check_base.clas.testclasses.abap +++ b/src/foundation/y_check_base.clas.testclasses.abap @@ -16,14 +16,28 @@ CLASS ltd_ref_scan_manager IMPLEMENTATION. ENDCLASS. CLASS ltc_check_base_double DEFINITION FOR TESTING INHERITING FROM y_check_base. + PUBLIC SECTION. + METHODS constructor. + METHODS get_already_ran RETURNING VALUE(result) TYPE abap_bool. PROTECTED SECTION. - METHODS: inspect_tokens REDEFINITION. + METHODS inspect_tokens REDEFINITION. ENDCLASS. CLASS ltc_check_base_double IMPLEMENTATION. + + METHOD constructor. + super->constructor( ). + enable_run_only_once( ). + ENDMETHOD. + + METHOD get_already_ran. + result = already_ran. + ENDMETHOD. + METHOD inspect_tokens. RETURN. ENDMETHOD. + ENDCLASS. CLASS ltc_check_configuration DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. @@ -530,3 +544,42 @@ CLASS ltc_check_configuration IMPLEMENTATION. ENDMETHOD. ENDCLASS. + +CLASS ltc_run_only_once DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. + PUBLIC SECTION. + METHODS frist_execution FOR TESTING. + METHODS second_execution FOR TESTING. + PROTECTED SECTION. + METHODS given_instance. + METHODS when_run. + METHODS then_ran. + PRIVATE SECTION. + DATA cut TYPE REF TO ltc_check_base_double. +ENDCLASS. + +CLASS ltc_run_only_once IMPLEMENTATION. + + METHOD frist_execution. + given_instance( ). + when_run( ). + then_ran( ). + ENDMETHOD. + + METHOD second_execution. + given_instance( ). + then_ran( ). + ENDMETHOD. + + METHOD given_instance. + cut = NEW ltc_check_base_double( ). + ENDMETHOD. + + METHOD when_run. + cut->run( ). + ENDMETHOD. + + METHOD then_ran. + cl_abap_unit_assert=>assert_true( cut->get_already_ran( ) ). + ENDMETHOD. + +ENDCLASS. From 60d273c9e433aa3a4c161e8b08188bf4e8d04a3c Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Wed, 7 Oct 2020 21:10:01 +0200 Subject: [PATCH 18/30] execute the profile check only once --- src/checks/y_check_profile_message.clas.abap | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/checks/y_check_profile_message.clas.abap b/src/checks/y_check_profile_message.clas.abap index 6d8a176b..ebdb0ef6 100644 --- a/src/checks/y_check_profile_message.clas.abap +++ b/src/checks/y_check_profile_message.clas.abap @@ -7,7 +7,6 @@ CLASS y_check_profile_message DEFINITION PROTECTED SECTION. METHODS execute_check REDEFINITION. METHODS inspect_tokens REDEFINITION. - PRIVATE SECTION. ENDCLASS. CLASS y_check_profile_message IMPLEMENTATION. @@ -26,6 +25,8 @@ CLASS y_check_profile_message IMPLEMENTATION. settings-apply_on_productive_code = abap_true. settings-prio = c_note. + enable_run_only_once( ). + set_check_message( 'code pal for ABAP Profile is being used.' ). ENDMETHOD. From 232b687f0cbd5370be45dba7530b1cf5432b06df Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Wed, 7 Oct 2020 16:15:53 -0300 Subject: [PATCH 19/30] Update changelog.txt --- changelog.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changelog.txt b/changelog.txt index e9a51c33..0a562350 100644 --- a/changelog.txt +++ b/changelog.txt @@ -10,6 +10,8 @@ Legend 2020-10-10 v1.05.1 ------------------ +* profile check run only once ++ run only once feature + report to activate or deactivate the SCI entries + add/remove all check in profiles From 9ccb045f02ad5ee5a4ee7949d0d8286c1dd6d4fb Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Wed, 7 Oct 2020 17:30:49 -0300 Subject: [PATCH 20/30] Update changelog.txt --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 0a562350..bd9799f5 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,7 +8,7 @@ Legend + : added - : removed -2020-10-10 v1.05.1 +2020-10-10 v1.05.0 ------------------ * profile check run only once + run only once feature From a18fae5dd1061ee990e586961ec5b359dc3c3b98 Mon Sep 17 00:00:00 2001 From: Eugen Guenther Date: Thu, 8 Oct 2020 15:31:39 +0200 Subject: [PATCH 21/30] category decription update --- src/categories/y_category_code_pal.clas.abap | 20 ++++++++++---------- src/categories/y_category_code_pal.clas.xml | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/categories/y_category_code_pal.clas.abap b/src/categories/y_category_code_pal.clas.abap index cd3cbb90..1206d627 100644 --- a/src/categories/y_category_code_pal.clas.abap +++ b/src/categories/y_category_code_pal.clas.abap @@ -1,14 +1,14 @@ -CLASS y_category_code_pal DEFINITION - PUBLIC - INHERITING FROM cl_ci_category_root - CREATE PUBLIC . +class Y_CATEGORY_CODE_PAL definition + public + inheriting from CL_CI_CATEGORY_ROOT + create public . - PUBLIC SECTION. +public section. - METHODS constructor . + methods CONSTRUCTOR . - METHODS if_ci_test~display_documentation - REDEFINITION . + methods IF_CI_TEST~DISPLAY_DOCUMENTATION + redefinition . PROTECTED SECTION. METHODS get_class_description RETURNING VALUE(result) TYPE string. @@ -16,7 +16,8 @@ CLASS y_category_code_pal DEFINITION ENDCLASS. -CLASS y_category_code_pal IMPLEMENTATION. + +CLASS Y_CATEGORY_CODE_PAL IMPLEMENTATION. METHOD constructor. @@ -54,5 +55,4 @@ CLASS y_category_code_pal IMPLEMENTATION. result = 'Description Not Available'. ENDTRY. ENDMETHOD. - ENDCLASS. diff --git a/src/categories/y_category_code_pal.clas.xml b/src/categories/y_category_code_pal.clas.xml index b0d50a8b..12d15ac9 100644 --- a/src/categories/y_category_code_pal.clas.xml +++ b/src/categories/y_category_code_pal.clas.xml @@ -5,7 +5,7 @@ Y_CATEGORY_CODE_PAL E - code pal for ABAP + code pal for ABAP (open source plugin) 1 X X From 5a3bf96874cbed571709a9e93c63737a0db92a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugen=20G=C3=BCnther?= <64586309+eugen-guenther-sap@users.noreply.github.com> Date: Thu, 8 Oct 2020 15:34:49 +0200 Subject: [PATCH 22/30] Update changelog.txt --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index bd9799f5..dd7d7e56 100644 --- a/changelog.txt +++ b/changelog.txt @@ -11,6 +11,7 @@ Legend 2020-10-10 v1.05.0 ------------------ * profile check run only once +! category description + run only once feature + report to activate or deactivate the SCI entries + add/remove all check in profiles From 48949df259881707f7824c86b6da05fae68fa2aa Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Thu, 8 Oct 2020 11:18:54 -0300 Subject: [PATCH 23/30] Update changelog.txt --- changelog.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index dd7d7e56..326b70c7 100644 --- a/changelog.txt +++ b/changelog.txt @@ -10,9 +10,7 @@ Legend 2020-10-10 v1.05.0 ------------------ -* profile check run only once ! category description -+ run only once feature + report to activate or deactivate the SCI entries + add/remove all check in profiles From fb890fcdb27ce38597315763564695f9a3999b1d Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Thu, 8 Oct 2020 16:19:53 +0200 Subject: [PATCH 24/30] reverting run only once --- src/checks/y_check_profile_message.clas.abap | 3 +- src/foundation/y_check_base.clas.abap | 43 ++++----------- .../y_check_base.clas.testclasses.abap | 55 +------------------ 3 files changed, 14 insertions(+), 87 deletions(-) diff --git a/src/checks/y_check_profile_message.clas.abap b/src/checks/y_check_profile_message.clas.abap index ebdb0ef6..6d8a176b 100644 --- a/src/checks/y_check_profile_message.clas.abap +++ b/src/checks/y_check_profile_message.clas.abap @@ -7,6 +7,7 @@ CLASS y_check_profile_message DEFINITION PROTECTED SECTION. METHODS execute_check REDEFINITION. METHODS inspect_tokens REDEFINITION. + PRIVATE SECTION. ENDCLASS. CLASS y_check_profile_message IMPLEMENTATION. @@ -25,8 +26,6 @@ CLASS y_check_profile_message IMPLEMENTATION. settings-apply_on_productive_code = abap_true. settings-prio = c_note. - enable_run_only_once( ). - set_check_message( 'code pal for ABAP Profile is being used.' ). ENDMETHOD. diff --git a/src/foundation/y_check_base.clas.abap b/src/foundation/y_check_base.clas.abap index 913b2e4c..e144ed31 100644 --- a/src/foundation/y_check_base.clas.abap +++ b/src/foundation/y_check_base.clas.abap @@ -31,7 +31,6 @@ CLASS y_check_base DEFINITION PUBLIC ABSTRACT apply_on_test_code TYPE ycicc_testcode, documentation TYPE c LENGTH 1000, is_threshold_reversed TYPE abap_bool, - run_only_once TYPE abap_bool, END OF settings . METHODS constructor . @@ -48,17 +47,16 @@ CLASS y_check_base DEFINITION PUBLIC ABSTRACT REDEFINITION . PROTECTED SECTION. - DATA check_configurations TYPE y_if_clean_code_manager=>check_configurations. - DATA check_name TYPE seoclsname. - DATA clean_code_exemption_handler TYPE REF TO y_exemption_handler. - DATA clean_code_manager TYPE REF TO y_if_clean_code_manager. - DATA is_testcode TYPE abap_bool. - DATA ref_scan_manager TYPE REF TO y_if_scan_manager. - DATA statistics TYPE REF TO y_if_scan_statistics. - DATA test_code_detector TYPE REF TO y_if_testcode_detector. + DATA check_configurations TYPE y_if_clean_code_manager=>check_configurations . + DATA check_name TYPE seoclsname . + DATA clean_code_exemption_handler TYPE REF TO y_exemption_handler . + DATA clean_code_manager TYPE REF TO y_if_clean_code_manager . + DATA is_testcode TYPE abap_bool . + DATA ref_scan_manager TYPE REF TO y_if_scan_manager . + DATA statistics TYPE REF TO y_if_scan_statistics . + DATA test_code_detector TYPE REF TO y_if_testcode_detector . DATA use_default_attributes TYPE abap_bool VALUE abap_true ##NO_TEXT. - DATA attributes_maintained TYPE abap_bool. - CLASS-DATA already_ran TYPE abap_bool. + DATA attributes_maintained TYPE abap_bool . METHODS check_start_conditions RAISING @@ -127,11 +125,10 @@ CLASS y_check_base DEFINITION PUBLIC ABSTRACT IMPORTING message TYPE itex132. METHODS get_class_description RETURNING VALUE(result) TYPE string. - "! Method to enable run only once feature. - "! It raises the check only once per code inspector execution. - METHODS enable_run_only_once. PRIVATE SECTION. - METHODS do_attributes_exist RETURNING VALUE(result) TYPE abap_bool . + METHODS do_attributes_exist + RETURNING + VALUE(result) TYPE abap_bool . METHODS instantiate_objects. METHODS enable_rfc. @@ -149,9 +146,6 @@ CLASS y_check_base DEFINITION PUBLIC ABSTRACT IMPORTING previous_config TYPE y_if_clean_code_manager=>check_configuration config TYPE y_if_clean_code_manager=>check_configuration RETURNING VALUE(result) TYPE abap_bool. - METHODS run_only_once - RETURNING - value(result) TYPE abap_bool. ENDCLASS. @@ -683,8 +677,6 @@ CLASS Y_CHECK_BASE IMPLEMENTATION. METHOD run. - CHECK run_only_once( ). - instantiate_objects( ). IF attributes_maintained = abap_false AND has_attributes = abap_true. @@ -786,15 +778,4 @@ CLASS Y_CHECK_BASE IMPLEMENTATION. result = xsdbool( ( previous_threshold >= config_threshold AND settings-is_threshold_reversed = abap_false ) OR ( previous_threshold < config_threshold AND settings-is_threshold_reversed = abap_true ) ). ENDMETHOD. - - METHOD run_only_once. - CHECK settings-run_only_once = abap_true. - result = xsdbool( already_ran = abap_false ). - already_ran = abap_true. - ENDMETHOD. - - METHOD enable_run_only_once. - settings-run_only_once = abap_true. - ENDMETHOD. - ENDCLASS. diff --git a/src/foundation/y_check_base.clas.testclasses.abap b/src/foundation/y_check_base.clas.testclasses.abap index dd84647d..64b6bc93 100644 --- a/src/foundation/y_check_base.clas.testclasses.abap +++ b/src/foundation/y_check_base.clas.testclasses.abap @@ -16,28 +16,14 @@ CLASS ltd_ref_scan_manager IMPLEMENTATION. ENDCLASS. CLASS ltc_check_base_double DEFINITION FOR TESTING INHERITING FROM y_check_base. - PUBLIC SECTION. - METHODS constructor. - METHODS get_already_ran RETURNING VALUE(result) TYPE abap_bool. PROTECTED SECTION. - METHODS inspect_tokens REDEFINITION. + METHODS: inspect_tokens REDEFINITION. ENDCLASS. CLASS ltc_check_base_double IMPLEMENTATION. - - METHOD constructor. - super->constructor( ). - enable_run_only_once( ). - ENDMETHOD. - - METHOD get_already_ran. - result = already_ran. - ENDMETHOD. - METHOD inspect_tokens. RETURN. ENDMETHOD. - ENDCLASS. CLASS ltc_check_configuration DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. @@ -544,42 +530,3 @@ CLASS ltc_check_configuration IMPLEMENTATION. ENDMETHOD. ENDCLASS. - -CLASS ltc_run_only_once DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. - PUBLIC SECTION. - METHODS frist_execution FOR TESTING. - METHODS second_execution FOR TESTING. - PROTECTED SECTION. - METHODS given_instance. - METHODS when_run. - METHODS then_ran. - PRIVATE SECTION. - DATA cut TYPE REF TO ltc_check_base_double. -ENDCLASS. - -CLASS ltc_run_only_once IMPLEMENTATION. - - METHOD frist_execution. - given_instance( ). - when_run( ). - then_ran( ). - ENDMETHOD. - - METHOD second_execution. - given_instance( ). - then_ran( ). - ENDMETHOD. - - METHOD given_instance. - cut = NEW ltc_check_base_double( ). - ENDMETHOD. - - METHOD when_run. - cut->run( ). - ENDMETHOD. - - METHOD then_ran. - cl_abap_unit_assert=>assert_true( cut->get_already_ran( ) ). - ENDMETHOD. - -ENDCLASS. From afa5944a9a0b7eb474dcba0f7345c30166f011eb Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Fri, 9 Oct 2020 03:17:05 -0300 Subject: [PATCH 25/30] disabling coverages in test code (#166) * disabling coverages in test code * disabling apply on test code --- src/checks/y_check_branch_coverage.clas.abap | 1 + src/checks/y_check_procedure_coverage.clas.abap | 1 + src/checks/y_check_statement_coverage.clas.abap | 1 + 3 files changed, 3 insertions(+) diff --git a/src/checks/y_check_branch_coverage.clas.abap b/src/checks/y_check_branch_coverage.clas.abap index 37bcefa4..ce6077c4 100644 --- a/src/checks/y_check_branch_coverage.clas.abap +++ b/src/checks/y_check_branch_coverage.clas.abap @@ -19,6 +19,7 @@ CLASS y_check_branch_coverage IMPLEMENTATION. settings-is_threshold_reversed = abap_true. settings-disable_on_prodcode_selection = abap_true. settings-disable_on_testcode_selection = abap_true. + settings-apply_on_test_code = abap_false. settings-documentation = |{ c_docs_path-checks }unit-test-coverages.md|. set_check_message( 'Branch Coverage of &1% is under the threshold of &2%.' ). diff --git a/src/checks/y_check_procedure_coverage.clas.abap b/src/checks/y_check_procedure_coverage.clas.abap index 5652f6e6..8a6afb16 100644 --- a/src/checks/y_check_procedure_coverage.clas.abap +++ b/src/checks/y_check_procedure_coverage.clas.abap @@ -19,6 +19,7 @@ CLASS y_check_procedure_coverage IMPLEMENTATION. settings-is_threshold_reversed = abap_true. settings-disable_on_prodcode_selection = abap_true. settings-disable_on_testcode_selection = abap_true. + settings-apply_on_test_code = abap_false. settings-documentation = |{ c_docs_path-checks }unit-test-coverages.md|. set_check_message( 'Procedure Coverage of &1% is under the threshold of &2%.' ). diff --git a/src/checks/y_check_statement_coverage.clas.abap b/src/checks/y_check_statement_coverage.clas.abap index ea02ce31..00f5d56d 100644 --- a/src/checks/y_check_statement_coverage.clas.abap +++ b/src/checks/y_check_statement_coverage.clas.abap @@ -19,6 +19,7 @@ CLASS y_check_statement_coverage IMPLEMENTATION. settings-is_threshold_reversed = abap_true. settings-disable_on_prodcode_selection = abap_true. settings-disable_on_testcode_selection = abap_true. + settings-apply_on_test_code = abap_false. settings-documentation = |{ c_docs_path-checks }unit-test-coverages.md|. set_check_message( 'Statement Coverage of &1% is under the threshold of &2%.' ). From 6f2c34e123bf3c5af9e57de57c778b9f4965675d Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Fri, 9 Oct 2020 03:35:01 -0300 Subject: [PATCH 26/30] &1 attributes reach threshold of &2 (#168) * %261 reach threshold of %262 * reach => reaching * minor fixes --- src/checks/y_check_num_exec_statements.clas.abap | 2 +- src/checks/y_check_num_output_parameter.clas.abap | 6 ++++-- src/checks/y_check_num_public_attributes.clas.abap | 2 +- src/checks/y_check_number_attributes.clas.abap | 2 +- src/checks/y_check_number_events.clas.abap | 2 +- src/checks/y_check_number_interfaces.clas.abap | 2 +- src/checks/y_check_number_methods.clas.abap | 2 +- 7 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/checks/y_check_num_exec_statements.clas.abap b/src/checks/y_check_num_exec_statements.clas.abap index f539b688..b30b35e3 100644 --- a/src/checks/y_check_num_exec_statements.clas.abap +++ b/src/checks/y_check_num_exec_statements.clas.abap @@ -52,7 +52,7 @@ CLASS Y_CHECK_NUM_EXEC_STATEMENTS IMPLEMENTATION. add_obj_type( c_type_program ). - set_check_message( '&1 executable statements in method, exceeds threshold &2' ). + set_check_message( '&1 executable statements in method reaching threshold of &2' ). ENDMETHOD. diff --git a/src/checks/y_check_num_output_parameter.clas.abap b/src/checks/y_check_num_output_parameter.clas.abap index 6b3d56a5..13e58087 100644 --- a/src/checks/y_check_num_output_parameter.clas.abap +++ b/src/checks/y_check_num_output_parameter.clas.abap @@ -21,7 +21,7 @@ CLASS Y_CHECK_NUM_OUTPUT_PARAMETER IMPLEMENTATION. settings-threshold = 2. settings-documentation = |{ c_docs_path-checks }number-output-parameter.md|. - set_check_message( 'Too many output parameters!' ). + set_check_message( '&1 output parameters reaching threshold of &2' ). ENDMETHOD. @@ -67,7 +67,9 @@ CLASS Y_CHECK_NUM_OUTPUT_PARAMETER IMPLEMENTATION. raise_error( statement_level = statement-level statement_index = index statement_from = statement-from + 1 - error_priority = configuration-prio ). + error_priority = configuration-prio + parameter_01 = |{ outputs_of_statement }| + parameter_02 = |{ configuration-threshold }| ). ENDMETHOD. diff --git a/src/checks/y_check_num_public_attributes.clas.abap b/src/checks/y_check_num_public_attributes.clas.abap index b7aae8ae..f9a7868a 100644 --- a/src/checks/y_check_num_public_attributes.clas.abap +++ b/src/checks/y_check_num_public_attributes.clas.abap @@ -83,7 +83,7 @@ CLASS Y_CHECK_NUM_PUBLIC_ATTRIBUTES IMPLEMENTATION. settings-threshold = 1. settings-documentation = |{ c_docs_path-checks }number-public-attributes.md|. - set_check_message( '&1 public attributes. All attributes should be private by default.' ). + set_check_message( '&1 public attributes. All attributes should be private/protected by default.' ). ENDMETHOD. diff --git a/src/checks/y_check_number_attributes.clas.abap b/src/checks/y_check_number_attributes.clas.abap index b03b1fc9..ba94c3cf 100644 --- a/src/checks/y_check_number_attributes.clas.abap +++ b/src/checks/y_check_number_attributes.clas.abap @@ -77,7 +77,7 @@ CLASS Y_CHECK_NUMBER_ATTRIBUTES IMPLEMENTATION. settings-threshold = 12. settings-documentation = |{ c_docs_path-checks }number-attributes.md|. - set_check_message( '&1 attributes, exceeding threshold &2' ). + set_check_message( '&1 attributes reaching threshold of &2' ). ENDMETHOD. diff --git a/src/checks/y_check_number_events.clas.abap b/src/checks/y_check_number_events.clas.abap index b2e31589..7f124697 100644 --- a/src/checks/y_check_number_events.clas.abap +++ b/src/checks/y_check_number_events.clas.abap @@ -45,7 +45,7 @@ CLASS Y_CHECK_NUMBER_EVENTS IMPLEMENTATION. settings-pseudo_comment = '"#EC NUMBER_EVENTS' ##NO_TEXT. settings-documentation = |{ c_docs_path-checks }number-events.md|. - set_check_message( 'There are &1 events, exceeding threshold of &2' ). + set_check_message( '&1 events reaching threshold of &2' ). ENDMETHOD. diff --git a/src/checks/y_check_number_interfaces.clas.abap b/src/checks/y_check_number_interfaces.clas.abap index 03aaf6c9..1d91dfb6 100644 --- a/src/checks/y_check_number_interfaces.clas.abap +++ b/src/checks/y_check_number_interfaces.clas.abap @@ -47,7 +47,7 @@ CLASS Y_CHECK_NUMBER_INTERFACES IMPLEMENTATION. settings-threshold = 4. settings-documentation = |{ c_docs_path-checks }number-interfaces.md|. - set_check_message( 'There are &1 interfaces, exceeding threshold of &2' ). + set_check_message( '&1 interfaces reaching threshold of &2' ). ENDMETHOD. diff --git a/src/checks/y_check_number_methods.clas.abap b/src/checks/y_check_number_methods.clas.abap index 7255754a..8a551bed 100644 --- a/src/checks/y_check_number_methods.clas.abap +++ b/src/checks/y_check_number_methods.clas.abap @@ -49,7 +49,7 @@ CLASS Y_CHECK_NUMBER_METHODS IMPLEMENTATION. settings-threshold = 20. settings-documentation = |{ c_docs_path-checks }number-methods.md|. - set_check_message( '&1 methods, exceeding threshold of &2' ). + set_check_message( '&1 methods reaching threshold of &2' ). ENDMETHOD. From dd7e165a5427aef122ed7cb3fa91fe37bfbd2592 Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Thu, 15 Oct 2020 10:12:59 -0300 Subject: [PATCH 27/30] Disabling "db access in ut" check when the OSQL/CDS UT framework is in use (#173) * fixes #171 * Update changelog.txt --- changelog.txt | 1 + src/checks/y_check_db_access_in_ut.clas.abap | 39 +++---- ...heck_db_access_in_ut.clas.testclasses.abap | 102 ++++++++++++++++++ 3 files changed, 123 insertions(+), 19 deletions(-) diff --git a/changelog.txt b/changelog.txt index 326b70c7..27b8d304 100644 --- a/changelog.txt +++ b/changelog.txt @@ -10,6 +10,7 @@ Legend 2020-10-10 v1.05.0 ------------------ +- db access in ut when OSQL/CDS framework is being used ! category description + report to activate or deactivate the SCI entries + add/remove all check in profiles diff --git a/src/checks/y_check_db_access_in_ut.clas.abap b/src/checks/y_check_db_access_in_ut.clas.abap index c49dfd58..0cce332f 100644 --- a/src/checks/y_check_db_access_in_ut.clas.abap +++ b/src/checks/y_check_db_access_in_ut.clas.abap @@ -1,30 +1,18 @@ -CLASS y_check_db_access_in_ut DEFINITION - PUBLIC - INHERITING FROM y_check_base - CREATE PUBLIC . - +CLASS y_check_db_access_in_ut DEFINITION PUBLIC INHERITING FROM y_check_base CREATE PUBLIC. PUBLIC SECTION. - METHODS constructor . + METHODS constructor. PROTECTED SECTION. METHODS execute_check REDEFINITION. METHODS inspect_tokens REDEFINITION. - + METHODS has_osql_or_cds_framework RETURNING VALUE(result) TYPE abap_bool. PRIVATE SECTION. - - METHODS is_persistent_object - IMPORTING - !obj_name TYPE string - RETURNING - VALUE(result) TYPE abap_bool . - - METHODS check_if_error - IMPORTING - !index TYPE i OPTIONAL - !statement TYPE sstmnt OPTIONAL . + METHODS is_persistent_object IMPORTING obj_name TYPE string + RETURNING VALUE(result) TYPE abap_bool . + METHODS check_if_error IMPORTING index TYPE i OPTIONAL + statement TYPE sstmnt OPTIONAL . ENDCLASS. - CLASS Y_CHECK_DB_ACCESS_IN_UT IMPLEMENTATION. @@ -45,6 +33,9 @@ CLASS Y_CHECK_DB_ACCESS_IN_UT IMPLEMENTATION. METHOD execute_check. + + CHECK has_osql_or_cds_framework( ) = abap_false. + LOOP AT ref_scan_manager->get_structures( ) ASSIGNING FIELD-SYMBOL() WHERE stmnt_type EQ scan_struc_stmnt_type-method. @@ -144,4 +135,14 @@ CLASS Y_CHECK_DB_ACCESS_IN_UT IMPLEMENTATION. parameter_01 = |{ key_word }| ). ENDMETHOD. + + METHOD has_osql_or_cds_framework. + DATA(tokens) = ref_scan_manager->get_tokens( ). + + IF line_exists( tokens[ str = 'IF_OSQL_TEST_ENVIRONMENT' ] ) + OR line_exists( tokens[ str = 'IF_CDS_TEST_ENVIRONMENT' ] ). + result = abap_true. + ENDIF. + ENDMETHOD. + ENDCLASS. diff --git a/src/checks/y_check_db_access_in_ut.clas.testclasses.abap b/src/checks/y_check_db_access_in_ut.clas.testclasses.abap index f07d9cb5..fb04920b 100644 --- a/src/checks/y_check_db_access_in_ut.clas.testclasses.abap +++ b/src/checks/y_check_db_access_in_ut.clas.testclasses.abap @@ -476,3 +476,105 @@ CLASS ltc_commit IMPLEMENTATION. ENDMETHOD. ENDCLASS. + +CLASS ltc_osql_framework DEFINITION INHERITING FROM y_unit_test_base FOR TESTING RISK LEVEL HARMLESS DURATION SHORT. + PROTECTED SECTION. + METHODS get_cut REDEFINITION. + METHODS get_code_with_issue REDEFINITION. + METHODS get_code_without_issue REDEFINITION. + METHODS get_code_with_exemption REDEFINITION. +ENDCLASS. + +CLASS ltc_osql_framework IMPLEMENTATION. + + METHOD get_cut. + result ?= NEW y_check_db_access_in_ut( ). + ENDMETHOD. + + METHOD get_code_with_issue. + result = VALUE #( + ( ' REPORT ut_test. ' ) + + ( ' CLASS lcl_classname DEFINITION FOR TESTING. ' ) + ( ' PUBLIC SECTION. ' ) + ( ' METHODS example FOR TESTING. ' ) + ( ' ENDCLASS.' ) + + ( ' CLASS lcl_classname IMPLEMENTATION. ' ) + ( ' METHOD example. ' ) + ( ' DATA tadir TYPE tadir. ' ) + ( ' SELECT SINGLE * FROM tadir INTO tadir. ' ) + ( ' ENDMETHOD. ' ) + ( ' ENDCLASS. ' ) + ). + ENDMETHOD. + + METHOD get_code_without_issue. + result = VALUE #( + ( ' REPORT ut_test. ' ) + + ( ' CLASS lcl_classname DEFINITION FOR TESTING. ' ) + ( ' PUBLIC SECTION. ' ) + ( ' METHODS scenario FOR TESTING. ' ) + ( ' PROTECTED SECTION. ' ) + ( ' METHODS given_fake_value. ' ) + ( ' METHODS when_select. ' ) + ( ' METHODS then_has_entry. ' ) + ( ' PRIVATE SECTION. ' ) + ( ' CLASS-DATA osql_test_environment TYPE REF TO if_osql_test_environment. ' ) + ( ' DATA cut TYPE tadir. ' ) + ( ' CLASS-METHODS class_setup. ' ) + ( ' CLASS-METHODS class_teardown. ' ) + ( ' ENDCLASS.' ) + + ( ' CLASS lcl_classname IMPLEMENTATION. ' ) + + ( ' METHOD class_setup. ' ) + ( | osql_test_environment = cl_osql_test_environment=>create( VALUE #( ( 'tadir' ) ) ). | ) + ( ' ENDMETHOD. ' ) + + ( ' METHOD class_teardown. ' ) + ( ' osql_test_environment->destroy( ). ' ) + ( ' ENDMETHOD. ' ) + + ( ' METHOD given_fake_value. ' ) + ( ' "osql_test_environment->insert_test_data( data ). ' ) + ( ' ENDMETHOD. ' ) + + ( ' METHOD when_select. ' ) + ( ' SELECT SINGLE * FROM tadir INTO cut. ' ) + ( ' ENDMETHOD. ' ) + + ( ' METHOD then_has_entry. ' ) + ( ' cl_aunit_assert=>assert_not_initial( cut ). ' ) + ( ' ENDMETHOD. ' ) + + ( ' METHOD scenario. ' ) + ( ' given_fake_value( ). ' ) + ( ' when_select( ). ' ) + ( ' then_has_entry( ). ' ) + ( ' ENDMETHOD. ' ) + + ( ' ENDCLASS. ' ) + ). + ENDMETHOD. + + METHOD get_code_with_exemption. + result = VALUE #( + ( ' REPORT ut_test. ' ) + + ( ' CLASS lcl_classname DEFINITION FOR TESTING. ' ) + ( ' PUBLIC SECTION. ' ) + ( ' METHODS example FOR TESTING. ' ) + ( ' ENDCLASS.' ) + + ( ' CLASS lcl_classname IMPLEMENTATION. ' ) + ( ' METHOD example. ' ) + ( ' DATA tadir TYPE tadir. ' ) + ( ' SELECT SINGLE * FROM tadir INTO tadir. "#EC DB_ACCESS_UT ' ) + ( ' ENDMETHOD. ' ) + ( ' ENDCLASS. ' ) + ). + ENDMETHOD. + +ENDCLASS. From 127518a24d10c0f0ef22087c49d1f08f4ad0dee0 Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Thu, 15 Oct 2020 12:57:39 -0300 Subject: [PATCH 28/30] Standardizing Messages (#174) * standardizing messages * reverting external_call_in_ut --- src/checks/y_check_branch_coverage.clas.abap | 2 +- src/checks/y_check_call_method_usage.clas.abap | 2 +- src/checks/y_check_check_stmnt_position.clas.abap | 2 +- src/checks/y_check_comment_usage.clas.abap | 2 +- src/checks/y_check_cyclomatic_complexity.clas.abap | 2 +- src/checks/y_check_deprecated_key_words.clas.abap | 2 +- src/checks/y_check_is_interface_in_class.clas.abap | 2 +- src/checks/y_check_magic_number.clas.abap | 2 +- src/checks/y_check_max_nesting_depth.clas.abap | 2 +- src/checks/y_check_num_exec_statements.clas.abap | 2 +- src/checks/y_check_num_output_parameter.clas.abap | 2 +- src/checks/y_check_num_public_attributes.clas.abap | 2 +- src/checks/y_check_number_attributes.clas.abap | 2 +- src/checks/y_check_number_events.clas.abap | 2 +- src/checks/y_check_number_interfaces.clas.abap | 2 +- src/checks/y_check_number_methods.clas.abap | 2 +- src/checks/y_check_procedure_coverage.clas.abap | 2 +- src/checks/y_check_pseudo_comment_usage.clas.abap | 2 +- src/checks/y_check_statement_coverage.clas.abap | 2 +- src/checks/y_check_test_seam_usage.clas.abap | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/checks/y_check_branch_coverage.clas.abap b/src/checks/y_check_branch_coverage.clas.abap index ce6077c4..d9368322 100644 --- a/src/checks/y_check_branch_coverage.clas.abap +++ b/src/checks/y_check_branch_coverage.clas.abap @@ -22,7 +22,7 @@ CLASS y_check_branch_coverage IMPLEMENTATION. settings-apply_on_test_code = abap_false. settings-documentation = |{ c_docs_path-checks }unit-test-coverages.md|. - set_check_message( 'Branch Coverage of &1% is under the threshold of &2%.' ). + set_check_message( 'Branch Coverage of &1% does not reach the threshold of &2%!' ). ENDMETHOD. diff --git a/src/checks/y_check_call_method_usage.clas.abap b/src/checks/y_check_call_method_usage.clas.abap index cf498fbd..ca1eb8b8 100644 --- a/src/checks/y_check_call_method_usage.clas.abap +++ b/src/checks/y_check_call_method_usage.clas.abap @@ -23,7 +23,7 @@ CLASS y_check_call_method_usage IMPLEMENTATION. settings-threshold = 0. settings-documentation = |{ c_docs_path-checks }call-method-usage.md|. - set_check_message( '"CALL METHOD" Statement should not be used!' ). + set_check_message( '"CALL METHOD" statement should not be used!' ). ENDMETHOD. diff --git a/src/checks/y_check_check_stmnt_position.clas.abap b/src/checks/y_check_check_stmnt_position.clas.abap index b4b210bf..17add468 100644 --- a/src/checks/y_check_check_stmnt_position.clas.abap +++ b/src/checks/y_check_check_stmnt_position.clas.abap @@ -33,7 +33,7 @@ CLASS Y_CHECK_CHECK_STMNT_POSITION IMPLEMENTATION. settings-threshold = 0. settings-documentation = |{ c_docs_path-checks }check-statement-position.md|. - set_check_message( '"CHECK" Statement should be the very first statement.' ). + set_check_message( '"CHECK" statement should be the very first statement!' ). ENDMETHOD. diff --git a/src/checks/y_check_comment_usage.clas.abap b/src/checks/y_check_comment_usage.clas.abap index a7171001..304ab0f0 100644 --- a/src/checks/y_check_comment_usage.clas.abap +++ b/src/checks/y_check_comment_usage.clas.abap @@ -69,7 +69,7 @@ CLASS Y_CHECK_COMMENT_USAGE IMPLEMENTATION. settings-threshold = 10. settings-documentation = |{ c_docs_path-checks }comment-usage.md|. - set_check_message( '&1 comments found! This is &2% of the productive code, exceeding threshold of &3%' ). + set_check_message( '&1 comments found! This is &2% of the productive code reaching threshold of &3%!' ). ENDMETHOD. diff --git a/src/checks/y_check_cyclomatic_complexity.clas.abap b/src/checks/y_check_cyclomatic_complexity.clas.abap index 406a1b54..ee870ac5 100644 --- a/src/checks/y_check_cyclomatic_complexity.clas.abap +++ b/src/checks/y_check_cyclomatic_complexity.clas.abap @@ -60,7 +60,7 @@ CLASS Y_CHECK_CYCLOMATIC_COMPLEXITY IMPLEMENTATION. settings-threshold = 10. settings-documentation = |{ c_docs_path-checks }cyclomatic-complexity.md|. - set_check_message( 'Cyclomatic complexity is &1, exceeding threshold of &2' ). + set_check_message( 'Cyclomatic complexity is &1 reaching threshold of &2!' ). ENDMETHOD. diff --git a/src/checks/y_check_deprecated_key_words.clas.abap b/src/checks/y_check_deprecated_key_words.clas.abap index eb20f3bc..55a0b5a9 100644 --- a/src/checks/y_check_deprecated_key_words.clas.abap +++ b/src/checks/y_check_deprecated_key_words.clas.abap @@ -28,7 +28,7 @@ CLASS Y_CHECK_DEPRECATED_KEY_WORDS IMPLEMENTATION. settings-threshold = 0. settings-documentation = |{ c_docs_path-checks }deprecated-key-word.md|. - set_check_message( '"&1" is deprecated' ). + set_check_message( '"&1" is deprecated!' ). ENDMETHOD. diff --git a/src/checks/y_check_is_interface_in_class.clas.abap b/src/checks/y_check_is_interface_in_class.clas.abap index 8f80e2d1..e7197e7f 100644 --- a/src/checks/y_check_is_interface_in_class.clas.abap +++ b/src/checks/y_check_is_interface_in_class.clas.abap @@ -28,7 +28,7 @@ CLASS Y_CHECK_IS_INTERFACE_IN_CLASS IMPLEMENTATION. settings-prio = c_warning. settings-documentation = |{ c_docs_path-checks }interface-in-class.md|. - set_check_message( '&1 public methods without interface' ). + set_check_message( '&1 public methods without interface!' ). ENDMETHOD. diff --git a/src/checks/y_check_magic_number.clas.abap b/src/checks/y_check_magic_number.clas.abap index a8a9f35a..8fa3a7ae 100644 --- a/src/checks/y_check_magic_number.clas.abap +++ b/src/checks/y_check_magic_number.clas.abap @@ -45,7 +45,7 @@ CLASS Y_CHECK_MAGIC_NUMBER IMPLEMENTATION. settings-apply_on_test_code = abap_false. settings-documentation = |{ c_docs_path-checks }magic-number.md|. - set_check_message( 'Magic Number Violation - &1 is a Magic Number' ). + set_check_message( 'Magic Number Violation - &1 is a Magic Number!' ). ENDMETHOD. diff --git a/src/checks/y_check_max_nesting_depth.clas.abap b/src/checks/y_check_max_nesting_depth.clas.abap index 4e07eabf..3d0f2ccf 100644 --- a/src/checks/y_check_max_nesting_depth.clas.abap +++ b/src/checks/y_check_max_nesting_depth.clas.abap @@ -54,7 +54,7 @@ CLASS Y_CHECK_MAX_NESTING_DEPTH IMPLEMENTATION. settings-pseudo_comment = '"#EC CI_NESTING' ##NO_TEXT. settings-documentation = |{ c_docs_path-checks }maximum-nesting-depth.md|. - set_check_message( 'Maximal nesting depth is &1, exceeding threshold of &2' ). + set_check_message( 'Maximal nesting depth is &1 reaching threshold of &2!' ). ENDMETHOD. diff --git a/src/checks/y_check_num_exec_statements.clas.abap b/src/checks/y_check_num_exec_statements.clas.abap index b30b35e3..c1c9e5e2 100644 --- a/src/checks/y_check_num_exec_statements.clas.abap +++ b/src/checks/y_check_num_exec_statements.clas.abap @@ -52,7 +52,7 @@ CLASS Y_CHECK_NUM_EXEC_STATEMENTS IMPLEMENTATION. add_obj_type( c_type_program ). - set_check_message( '&1 executable statements in method reaching threshold of &2' ). + set_check_message( '&1 executable statements in method reaching threshold of &2!' ). ENDMETHOD. diff --git a/src/checks/y_check_num_output_parameter.clas.abap b/src/checks/y_check_num_output_parameter.clas.abap index 13e58087..618c38cb 100644 --- a/src/checks/y_check_num_output_parameter.clas.abap +++ b/src/checks/y_check_num_output_parameter.clas.abap @@ -21,7 +21,7 @@ CLASS Y_CHECK_NUM_OUTPUT_PARAMETER IMPLEMENTATION. settings-threshold = 2. settings-documentation = |{ c_docs_path-checks }number-output-parameter.md|. - set_check_message( '&1 output parameters reaching threshold of &2' ). + set_check_message( '&1 output parameters reaching threshold of &2!' ). ENDMETHOD. diff --git a/src/checks/y_check_num_public_attributes.clas.abap b/src/checks/y_check_num_public_attributes.clas.abap index f9a7868a..0b88f692 100644 --- a/src/checks/y_check_num_public_attributes.clas.abap +++ b/src/checks/y_check_num_public_attributes.clas.abap @@ -83,7 +83,7 @@ CLASS Y_CHECK_NUM_PUBLIC_ATTRIBUTES IMPLEMENTATION. settings-threshold = 1. settings-documentation = |{ c_docs_path-checks }number-public-attributes.md|. - set_check_message( '&1 public attributes. All attributes should be private/protected by default.' ). + set_check_message( '&1 public attributes. All attributes should be private/protected by default!' ). ENDMETHOD. diff --git a/src/checks/y_check_number_attributes.clas.abap b/src/checks/y_check_number_attributes.clas.abap index ba94c3cf..7ae17806 100644 --- a/src/checks/y_check_number_attributes.clas.abap +++ b/src/checks/y_check_number_attributes.clas.abap @@ -77,7 +77,7 @@ CLASS Y_CHECK_NUMBER_ATTRIBUTES IMPLEMENTATION. settings-threshold = 12. settings-documentation = |{ c_docs_path-checks }number-attributes.md|. - set_check_message( '&1 attributes reaching threshold of &2' ). + set_check_message( '&1 attributes reaching threshold of &2!' ). ENDMETHOD. diff --git a/src/checks/y_check_number_events.clas.abap b/src/checks/y_check_number_events.clas.abap index 7f124697..73a11c00 100644 --- a/src/checks/y_check_number_events.clas.abap +++ b/src/checks/y_check_number_events.clas.abap @@ -45,7 +45,7 @@ CLASS Y_CHECK_NUMBER_EVENTS IMPLEMENTATION. settings-pseudo_comment = '"#EC NUMBER_EVENTS' ##NO_TEXT. settings-documentation = |{ c_docs_path-checks }number-events.md|. - set_check_message( '&1 events reaching threshold of &2' ). + set_check_message( '&1 events reaching threshold of &2!' ). ENDMETHOD. diff --git a/src/checks/y_check_number_interfaces.clas.abap b/src/checks/y_check_number_interfaces.clas.abap index 1d91dfb6..f925bf8e 100644 --- a/src/checks/y_check_number_interfaces.clas.abap +++ b/src/checks/y_check_number_interfaces.clas.abap @@ -47,7 +47,7 @@ CLASS Y_CHECK_NUMBER_INTERFACES IMPLEMENTATION. settings-threshold = 4. settings-documentation = |{ c_docs_path-checks }number-interfaces.md|. - set_check_message( '&1 interfaces reaching threshold of &2' ). + set_check_message( '&1 interfaces reaching threshold of &2!' ). ENDMETHOD. diff --git a/src/checks/y_check_number_methods.clas.abap b/src/checks/y_check_number_methods.clas.abap index 8a551bed..8ec1fe6f 100644 --- a/src/checks/y_check_number_methods.clas.abap +++ b/src/checks/y_check_number_methods.clas.abap @@ -49,7 +49,7 @@ CLASS Y_CHECK_NUMBER_METHODS IMPLEMENTATION. settings-threshold = 20. settings-documentation = |{ c_docs_path-checks }number-methods.md|. - set_check_message( '&1 methods reaching threshold of &2' ). + set_check_message( '&1 methods reaching threshold of &2!' ). ENDMETHOD. diff --git a/src/checks/y_check_procedure_coverage.clas.abap b/src/checks/y_check_procedure_coverage.clas.abap index 8a6afb16..537f4edd 100644 --- a/src/checks/y_check_procedure_coverage.clas.abap +++ b/src/checks/y_check_procedure_coverage.clas.abap @@ -22,7 +22,7 @@ CLASS y_check_procedure_coverage IMPLEMENTATION. settings-apply_on_test_code = abap_false. settings-documentation = |{ c_docs_path-checks }unit-test-coverages.md|. - set_check_message( 'Procedure Coverage of &1% is under the threshold of &2%.' ). + set_check_message( 'Procedure Coverage of &1% does not reach the threshold of &2%!' ). ENDMETHOD. diff --git a/src/checks/y_check_pseudo_comment_usage.clas.abap b/src/checks/y_check_pseudo_comment_usage.clas.abap index cc06e608..ee38e13d 100644 --- a/src/checks/y_check_pseudo_comment_usage.clas.abap +++ b/src/checks/y_check_pseudo_comment_usage.clas.abap @@ -61,7 +61,7 @@ CLASS Y_CHECK_PSEUDO_COMMENT_USAGE IMPLEMENTATION. settings-apply_on_productive_code = abap_true. settings-prio = c_note. - set_check_message( '&1 pseudo comments' ). + set_check_message( '&1 pseudo comments!' ). ENDMETHOD. diff --git a/src/checks/y_check_statement_coverage.clas.abap b/src/checks/y_check_statement_coverage.clas.abap index 00f5d56d..b3a89211 100644 --- a/src/checks/y_check_statement_coverage.clas.abap +++ b/src/checks/y_check_statement_coverage.clas.abap @@ -22,7 +22,7 @@ CLASS y_check_statement_coverage IMPLEMENTATION. settings-apply_on_test_code = abap_false. settings-documentation = |{ c_docs_path-checks }unit-test-coverages.md|. - set_check_message( 'Statement Coverage of &1% is under the threshold of &2%.' ). + set_check_message( 'Statement Coverage of &1% does not reach the threshold of &2%!' ). ENDMETHOD. diff --git a/src/checks/y_check_test_seam_usage.clas.abap b/src/checks/y_check_test_seam_usage.clas.abap index 25038a05..cf341826 100644 --- a/src/checks/y_check_test_seam_usage.clas.abap +++ b/src/checks/y_check_test_seam_usage.clas.abap @@ -25,7 +25,7 @@ CLASS Y_CHECK_TEST_SEAM_USAGE IMPLEMENTATION. settings-threshold = 0. settings-documentation = |{ c_docs_path-checks }test-seam-usage.md|. - set_check_message( '"TEST-SEAM" Statement should no longer be used!' ). + set_check_message( '"TEST-SEAM" statement should no longer be used!' ). ENDMETHOD. From 1062fdca4c7eb4a894011e602d731c0829de4ca4 Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Thu, 15 Oct 2020 12:58:42 -0300 Subject: [PATCH 29/30] Update changelog.txt --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index 27b8d304..7bbf0597 100644 --- a/changelog.txt +++ b/changelog.txt @@ -10,6 +10,7 @@ Legend 2020-10-10 v1.05.0 ------------------ +! check messages - db access in ut when OSQL/CDS framework is being used ! category description + report to activate or deactivate the SCI entries From b0f1341d293399d30cd6736b6695ff16772b2d16 Mon Sep 17 00:00:00 2001 From: Lucas Borin <5233413+lucasborin@users.noreply.github.com> Date: Fri, 16 Oct 2020 09:36:03 -0300 Subject: [PATCH 30/30] Raising profile message only once (#169) * raising the message only once * disabling referece to object * minor fix * Updating temporary branch * disabling coverages in test code (#166) * disabling coverages in test code * disabling apply on test code * &1 attributes reach threshold of &2 (#168) * %261 reach threshold of %262 * reach => reaching * minor fixes * Disabling "db access in ut" check when the OSQL/CDS UT framework is in use (#173) * fixes #171 * Update changelog.txt * Standardizing Messages (#174) * standardizing messages * reverting external_call_in_ut * Update changelog.txt * Update changelog.txt * Update changelog.txt * changing message text * check description --- changelog.txt | 1 + src/checks/y_check_profile_message.clas.abap | 57 +++++++++++++++++++- src/checks/y_check_profile_message.clas.xml | 2 +- 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/changelog.txt b/changelog.txt index 7bbf0597..d576e9cd 100644 --- a/changelog.txt +++ b/changelog.txt @@ -10,6 +10,7 @@ Legend 2020-10-10 v1.05.0 ------------------ +* profile message check runs only once ! check messages - db access in ut when OSQL/CDS framework is being used ! category description diff --git a/src/checks/y_check_profile_message.clas.abap b/src/checks/y_check_profile_message.clas.abap index 6d8a176b..a745b76a 100644 --- a/src/checks/y_check_profile_message.clas.abap +++ b/src/checks/y_check_profile_message.clas.abap @@ -7,7 +7,12 @@ CLASS y_check_profile_message DEFINITION PROTECTED SECTION. METHODS execute_check REDEFINITION. METHODS inspect_tokens REDEFINITION. + METHODS inform REDEFINITION. PRIVATE SECTION. + CLASS-DATA ran TYPE abap_bool. + METHODS get_profiles RETURNING VALUE(result) TYPE y_if_profile_manager=>profile_assignments. + METHODS list_profiles IMPORTING profiles TYPE y_if_profile_manager=>profile_assignments + RETURNING value(result) TYPE string. ENDCLASS. CLASS y_check_profile_message IMPLEMENTATION. @@ -26,12 +31,13 @@ CLASS y_check_profile_message IMPLEMENTATION. settings-apply_on_productive_code = abap_true. settings-prio = c_note. - set_check_message( 'code pal for ABAP Profile is being used.' ). + set_check_message( '&1 Profile(s) in use: &2.' ). ENDMETHOD. METHOD execute_check. + CHECK ran = abap_false. CHECK has_attributes = abap_false. DATA(check_configuration) = detect_check_configuration( VALUE #( level = 1 ) ). @@ -40,10 +46,16 @@ CLASS y_check_profile_message IMPLEMENTATION. RETURN. ENDIF. + DATA(profiles) = get_profiles( ). + raise_error( statement_level = 1 statement_index = 1 statement_from = 1 - error_priority = check_configuration-prio ). + error_priority = check_configuration-prio + parameter_01 = |{ lines( profiles ) }| + parameter_02 = |{ list_profiles( profiles ) }| ). + + ran = abap_true. ENDMETHOD. @@ -53,4 +65,45 @@ CLASS y_check_profile_message IMPLEMENTATION. ENDMETHOD. + METHOD inform. + super->inform( p_sub_obj_type = 'TRAN' + p_sub_obj_name = 'Y_CODE_PAL_PROFILE' + p_position = '' + p_line = '' + p_column = '' + p_errcnt = p_errcnt + p_kind = p_kind + p_test = p_test + p_code = p_code + p_suppress = p_suppress + p_param_1 = p_param_1 + p_param_2 = p_param_2 + p_param_3 = p_param_3 + p_param_4 = p_param_4 + p_inclspec = p_inclspec + p_detail = p_detail + p_checksum_1 = p_checksum_1 + p_comments = p_comments + p_finding_origins = p_finding_origins ). + ENDMETHOD. + + + METHOD get_profiles. + TRY. + result = y_profile_manager=>create( )->select_profiles( sy-uname ). + CATCH ycx_entry_not_found. + RETURN. + ENDTRY. + + ENDMETHOD. + + + METHOD list_profiles. + LOOP AT profiles ASSIGNING FIELD-SYMBOL(). + result = COND #( WHEN result IS INITIAL THEN -profile + ELSE |{ result }, { -profile }| ). + ENDLOOP. + ENDMETHOD. + + ENDCLASS. diff --git a/src/checks/y_check_profile_message.clas.xml b/src/checks/y_check_profile_message.clas.xml index cd776883..84e2a986 100644 --- a/src/checks/y_check_profile_message.clas.xml +++ b/src/checks/y_check_profile_message.clas.xml @@ -5,7 +5,7 @@ Y_CHECK_PROFILE_MESSAGE E - code pal for ABAP Profile Message + Profile Feature Notification (code pal for ABAP) 1 X X