anchor.diff:      _add '.repo_tab td.cmd span    { display: block; }'.
       _add '.repo_tab td.cmd a       { display: block; }'.
   
  -  ENDMETHOD.
  -
  -  METHOD render_repo_menu.
  -
  -    DATA: lo_toolbar     TYPE REF TO lcl_html_toolbar,
  -          lo_tb_advanced TYPE REF TO lcl_html_toolbar,
  -          lo_tb_branch   TYPE REF TO lcl_html_toolbar,
  -          lv_key         TYPE lcl_persistence_db=>ty_value,
  -          lv_wp_opt      LIKE gc_html_opt-crossout,
  -          lv_pull_opt    LIKE gc_html_opt-crossout,
  -          lo_repo_online TYPE REF TO lcl_repo_online.
  -
  -    CREATE OBJECT ro_html.
  -    CREATE OBJECT lo_toolbar.
  -    CREATE OBJECT lo_tb_branch.
  -    CREATE OBJECT lo_tb_advanced.
  -
  -    lv_key = io_repo->get_key( ).
  -    IF io_repo->is_offline( ) = abap_false.
  -      lo_repo_online ?= io_repo.
  -    ENDIF.
  -
  -    IF io_repo->is_write_protected( ) = abap_true.
  -      lv_wp_opt   = gc_html_opt-crossout.
  -      lv_pull_opt = gc_html_opt-crossout.
  -    ELSE.
  -      lv_pull_opt = gc_html_opt-emphas.
  -    ENDIF.
  -
  -    " Build branch drop-down ========================
  -    IF io_repo->is_offline( ) = abap_false. " Online ?
  -      lo_tb_branch->add( iv_txt = 'Overview'
  -                         iv_act = |{ gc_action-go_branch_overview }?{ lv_key }| ).
  -      lo_tb_branch->add( iv_txt = 'Switch'
  -                         iv_act = |{ gc_action-git_branch_switch }?{ lv_key }|
  -                         iv_opt = lv_wp_opt ).
  -      lo_tb_branch->add( iv_txt = 'Create'
  -                         iv_act = |{ gc_action-git_branch_create }?{ lv_key }| ).
  -      lo_tb_branch->add( iv_txt = 'Delete'
  -                         iv_act = |{ gc_action-git_branch_delete }?{ lv_key }| ).
  -    ENDIF.
  -
  -    " Build advanced drop-down ========================
  -    IF io_repo->is_offline( ) = abap_false. " Online ?
  -      lo_tb_advanced->add( iv_txt = 'Reset local'
  -                           iv_act = |{ gc_action-git_reset }?{ lv_key }|
  -                           iv_opt = lv_wp_opt ).
  -      lo_tb_advanced->add( iv_txt = 'Background mode'
  -                           iv_act = |{ gc_action-go_background }?{ lv_key }| ).
  -      lo_tb_advanced->add( iv_txt = 'Change remote'
  -                           iv_act = |{ gc_action-repo_remote_change }?{ lv_key }| ).
  -      lo_tb_advanced->add( iv_txt = 'Make off-line'
  -                           iv_act = |{ gc_action-repo_remote_detach }?{ lv_key }| ).
  -    ELSE.
  -      lo_tb_advanced->add( iv_txt = 'Make on-line'
  -                           iv_act = |{ gc_action-repo_remote_attach }?{ lv_key }| ).
  -    ENDIF.
  -    lo_tb_advanced->add( iv_txt = 'Remove'
  -                         iv_act = |{ gc_action-repo_remove }?{ lv_key }| ).
  -    lo_tb_advanced->add( iv_txt = 'Uninstall'
  -                         iv_act = |{ gc_action-repo_purge }?{ lv_key }|
  -                         iv_opt = lv_wp_opt ).
  -
  -    " Build main toolbar ==============================
  -    IF io_repo->is_offline( ) = abap_false. " Online ?
  -      TRY.
  -          IF lo_repo_online->get_sha1_remote( ) <> lo_repo_online->get_sha1_local( ).
  -            lo_toolbar->add( iv_txt = 'Pull'
  -                             iv_act = |{ gc_action-git_pull }?{ lv_key }|
  -                             iv_opt = lv_pull_opt ).
  -          ENDIF.
  -          IF lcl_stage_logic=>count( lo_repo_online ) > 0.
  -            lo_toolbar->add( iv_txt = 'Stage'
  -                             iv_act = |{ gc_action-go_stage }?{ lv_key }|
  -                             iv_opt = gc_html_opt-emphas ).
  -          ENDIF.
  -        CATCH lcx_exception ##NO_HANDLER.
  -          " authorization error or repository does not exist
  -          " ignore error
  -      ENDTRY.
  -      lo_toolbar->add( iv_txt = 'Branch'
  -                       io_sub = lo_tb_branch ) ##NO_TEXT.
  -    ELSE.
  -      lo_toolbar->add( iv_txt = 'Import ZIP'
  -                       iv_act = |{ gc_action-zip_import }?{ lv_key }|
  -                       iv_opt = gc_html_opt-emphas ).
  -      lo_toolbar->add( iv_txt = 'Export ZIP'
  -                       iv_act = |{ gc_action-zip_export }?{ lv_key }|
  -                       iv_opt = gc_html_opt-emphas ).
  -    ENDIF.
  -
  -    lo_toolbar->add( iv_txt = 'Advanced'
  -                     io_sub = lo_tb_advanced ) ##NO_TEXT.
  -    lo_toolbar->add( iv_txt = 'Refresh'
  -                     iv_act = |{ gc_action-repo_refresh }?{ lv_key }| ).
  -
  -    " Render ==========================================
  -    ro_html->add( '<div class="paddings right">' ).
  -    ro_html->add( lo_toolbar->render( ) ).
  -    ro_html->add( '</div>' ).
  -
  -  ENDMETHOD.
  -
  -  METHOD render_repo.
  -
  -    DATA: lt_repo_items TYPE tt_repo_items,
  -          lo_tab_menu   TYPE REF TO lcl_html_toolbar,
  -          lx_error      TYPE REF TO lcx_exception,
  -          lo_log        TYPE REF TO lcl_log.
  -
  -    FIELD-SYMBOLS <ls_item> LIKE LINE OF lt_repo_items.
  -
  -    CREATE OBJECT lo_tab_menu.
  -    CREATE OBJECT ro_html.
  -
  -    ro_html->add( |<div class="repo" id="repo{ io_repo->get_key( ) }">| ).
  -    ro_html->add( render_repo_top( io_repo = io_repo iv_interactive_branch = abap_true ) ).
  -
  -    TRY.
  -        extract_repo_content( EXPORTING io_repo       = io_repo
  -                              IMPORTING et_repo_items = lt_repo_items
  -                                        eo_log        = lo_log ).
  -
  -        " extract_repo_content must be called before rendering the menu
  -        " so that lo_log is filled with errors from the serialization
  -        ro_html->add( render_repo_menu( io_repo ) ).
  -
  -        IF io_repo->is_offline( ) = abap_false and lo_log->count( ) > 0.
  -          ro_html->add( '<div class="log">' ).
  -          ro_html->add( lo_log->to_html( ) ). " shows eg. list of unsupported objects
  -          ro_html->add( '</div>' ).
  -        ENDIF.
  -
  -        ro_html->add( '<div class="repo_container">' ).
  -        IF io_repo->is_offline( ) = abap_false.
  -          IF mv_hide_files = abap_true.
  -            lo_tab_menu->add( iv_txt = 'Show files' iv_act = c_actions-toggle_hide_files ).
  -          ELSE.
  -            lo_tab_menu->add( iv_txt = 'Hide files' iv_act = c_actions-toggle_hide_files ).
  -          ENDIF.
  -          ro_html->add( lo_tab_menu->render( iv_as_angle = abap_true ) ).
  -        ENDIF.
  -
  -        ro_html->add( '<table width="100%" class="repo_tab">' ).
  -        IF lines( lt_repo_items ) = 0.
  -          ro_html->add( '<tr class="unsupported firstrow"><td class="paddings">'
  -                       && '<center>Empty package</center>'
  -                       && '</td></tr>' ) ##NO_TEXT.
  -        ELSE.
  -          LOOP AT lt_repo_items ASSIGNING <ls_item>.
  -            ro_html->add( render_repo_item( io_repo = io_repo is_item = <ls_item> ) ).
  -          ENDLOOP.
  -        ENDIF.
  -        ro_html->add( '</table>' ).
  -        ro_html->add( '</div>' ).
  -
  -      CATCH lcx_exception INTO lx_error.
  -        ro_html->add( render_repo_menu( io_repo ) ).
  -        ro_html->add( render_error( lx_error ) ).
  -    ENDTRY.
  -
  -    ro_html->add( '</div>' ).
  -
  -  ENDMETHOD.
  -
  -  METHOD extract_repo_content.
  -
  -    DATA: lo_repo_online TYPE REF TO lcl_repo_online,
  -          lt_tadir       TYPE ty_tadir_tt,
  -          ls_file        TYPE ty_repo_file,
  -          lt_results     TYPE ty_results_tt.
  -
  -    FIELD-SYMBOLS: <ls_result>    LIKE LINE OF lt_results,
  -                   <ls_repo_item> LIKE LINE OF et_repo_items,
  -                   <ls_tadir>     LIKE LINE OF lt_tadir.
  -
  -
  -    CLEAR et_repo_items.
  -
  -    IF io_repo->is_offline( ) = abap_true.
  -      lt_tadir = lcl_tadir=>read( io_repo->get_package( ) ).
  -      LOOP AT lt_tadir ASSIGNING <ls_tadir>.
  -        APPEND INITIAL LINE TO et_repo_items ASSIGNING <ls_repo_item>.
  -        IF sy-tabix = 1.
  -          <ls_repo_item>-is_first = abap_true.
  -        ENDIF.
  -        <ls_repo_item>-obj_type = <ls_tadir>-object.
  -        <ls_repo_item>-obj_name = <ls_tadir>-obj_name.
  -      ENDLOOP.
  -
  -    ELSE.
  -      CREATE OBJECT eo_log.
  -      lo_repo_online ?= io_repo.
  -      lt_results      = lo_repo_online->status( eo_log ).
  -      LOOP AT lt_results ASSIGNING <ls_result>.
  -        AT NEW obj_name. "obj_type + obj_name
  -          APPEND INITIAL LINE TO et_repo_items ASSIGNING <ls_repo_item>.
  -          <ls_repo_item>-obj_type = <ls_result>-obj_type.
  -          <ls_repo_item>-obj_name = <ls_result>-obj_name.
  -          <ls_repo_item>-sortkey  = c_default_sortkey. " Default sort key
  -          <ls_repo_item>-changes  = 0.
  -        ENDAT.
  -
  -        IF <ls_result>-filename IS NOT INITIAL.
  -          ls_file-path        = <ls_result>-path.
  -          ls_file-filename    = <ls_result>-filename.
  -          ls_file-is_changed  = boolc( NOT <ls_result>-match = abap_true ).
  -          ls_file-new         = <ls_result>-new.
  -          APPEND ls_file TO <ls_repo_item>-files.
  -
  -          IF ls_file-is_changed = abap_true OR ls_file-new IS NOT INITIAL.
  -            <ls_repo_item>-sortkey = 2. " Changed files
  -            <ls_repo_item>-changes = <ls_repo_item>-changes + 1.
  -          ENDIF.
  -        ENDIF.
  -
  -        AT END OF obj_name. "obj_type + obj_name
  -          IF <ls_repo_item>-obj_type IS INITIAL.
  -            <ls_repo_item>-sortkey = 0. "Virtual objects
  -          ELSEIF lines( <ls_repo_item>-files ) = 0.
  -            <ls_repo_item>-sortkey = 1. "New object to commit
  -          ENDIF.
  -        ENDAT.
  -      ENDLOOP.
  -
  -      SORT et_repo_items BY sortkey obj_type obj_name ASCENDING.
  -      READ TABLE et_repo_items ASSIGNING <ls_repo_item> INDEX 1.
  -      IF sy-subrc IS INITIAL.
  -        <ls_repo_item>-is_first = abap_true.
  -      ENDIF.
  -    ENDIF.
  -
  -
  -  ENDMETHOD.
  -
  -  METHOD render_repo_item.
  -    DATA:
  -      lv_link     TYPE string,
  -      lv_icon     TYPE string,
  -      lv_difflink TYPE string,
  -      ls_file     LIKE LINE OF is_item-files,
  -      lv_trclass  TYPE string.
  -
  -    CREATE OBJECT ro_html.
  -
  -    IF is_item-is_first = abap_true. " TR class
  -      lv_trclass = 'firstrow' ##NO_TEXT.
  -    ENDIF.
  -    IF is_item-obj_name IS INITIAL.
  -      lv_trclass = lv_trclass && ' unsupported' ##NO_TEXT.
  -    ENDIF.
  -    IF is_item-sortkey > 0 AND is_item-sortkey < c_default_sortkey.
  -      lv_trclass = lv_trclass && ' modified' ##NO_TEXT.
  -    ENDIF.
  -    IF lv_trclass IS NOT INITIAL.
  -      SHIFT lv_trclass LEFT DELETING LEADING space.
  -      lv_trclass = | class="{ lv_trclass }"|.
  -    ENDIF.
  -
  -    ro_html->add( |<tr{ lv_trclass }>| ).
  -
  -    IF is_item-obj_name IS INITIAL.
  -      ro_html->add( '<td colspan="2"></td>'
  -                 && '<td class="object"><i class="grey">non-code and meta files</i></td>' ).
  -    ELSE.
  -      CASE is_item-obj_type. "TODO ??
  -        WHEN 'PROG' OR 'CLAS' OR 'FUGR'.
  -          lv_icon = |<img src="img/code">|.
  -        WHEN 'W3MI' OR 'W3HT'.
  -          lv_icon = |<img src="img/bin">|.
  -        WHEN ''.
  -          lv_icon = space. " no icon
  -        WHEN OTHERS.
  -          lv_icon = |<img src="img/obj">|.
  -      ENDCASE.
  -
  -      lv_link = render_obj_jump_link( iv_obj_name = is_item-obj_name
  -                                      iv_obj_type = is_item-obj_type ).
  -      ro_html->add( |<td class="icon">{ lv_icon }</td>| ).
  -      ro_html->add( |<td class="type">{ is_item-obj_type }</td>| ).
  -      ro_html->add( |<td class="object">{ lv_link }</td>| ).
  -    ENDIF.
  -
  -    IF io_repo->is_offline( ) = abap_false. " Files for online repos only
  -
  -      ro_html->add( '<td class="files">' ).
  -      IF mv_hide_files = abap_false OR is_item-obj_type IS INITIAL.
  -        LOOP AT is_item-files INTO ls_file.
  -          ro_html->add( |<span>{ ls_file-path && ls_file-filename }</span>| ).
  -        ENDLOOP.
  -      ENDIF.
  -      ro_html->add( '</td>' ).
  -
  -      ro_html->add( '<td class="cmd">' ).
  -      IF lines( is_item-files ) = 0.
  -        ro_html->add( '<span class="grey">new @local</span>' ).
  -      ELSEIF is_item-changes > 0.
  -        IF mv_hide_files = abap_true AND is_item-obj_name IS NOT INITIAL.
  -          lv_difflink = lcl_html_action_utils=>obj_encode(
  -            iv_key    = io_repo->get_key( )
  -            ig_object = is_item ).
  -          ro_html->add_anchor(
  -            iv_txt = |diff ({ is_item-changes })|
  -            iv_act = |{ gc_action-go_diff }?{ lv_difflink }| ).
  -        ELSE.
  -          LOOP AT is_item-files INTO ls_file.
  -            IF ls_file-new = gc_new-remote.
  -              ro_html->add( '<span class="grey">new @remote</span>' ).
  -            ELSEIF ls_file-new = gc_new-local.
  -              ro_html->add( '<span class="grey">new @local</span>' ).
  -            ELSEIF ls_file-is_changed = abap_true.
  -              lv_difflink = lcl_html_action_utils=>file_encode(
  -                iv_key  = io_repo->get_key( )
  -                ig_file = ls_file ).
  -              ro_html->add_anchor(
  -                iv_txt = 'diff'
  -                iv_act = |{ gc_action-go_diff }?{ lv_difflink }| ).
  -            ELSE.
  -              ro_html->add( |<span>&nbsp;</span>| ).
  -            ENDIF.
  -          ENDLOOP.
  -        ENDIF.
  -      ENDIF.
  -      ro_html->add( '</td>' ).
  -
  -    ENDIF.
  -
  -    ro_html->add( '</tr>' ).
  -
  -  ENDMETHOD.
  -
  -  METHOD render_toc.
  -
  -    DATA: lo_pback      TYPE REF TO lcl_persistence_background,
  -          lt_repo_bkg   TYPE lcl_persistence_background=>tt_background,
  -          lo_repo       LIKE LINE OF it_list,
  -          lv_opt        TYPE c LENGTH 1,
  -          lo_online     TYPE REF TO lcl_html_toolbar,
  -          lo_background TYPE REF TO lcl_html_toolbar,
  -          lo_offline    TYPE REF TO lcl_html_toolbar.
  -
  -
  -    CREATE OBJECT ro_html.
  -    CREATE OBJECT lo_online.
  -    CREATE OBJECT lo_offline.
  -    CREATE OBJECT lo_background.
  -    CREATE OBJECT lo_pback.
  -    lt_repo_bkg = lo_pback->list( ).
  -
  -    IF lines( it_list ) = 0.
  -      RETURN.
  -    ENDIF.
  -
  -    LOOP AT it_list INTO lo_repo.
  -      IF mv_show = lo_repo->get_key( ).
  -        lv_opt = gc_html_opt-emphas.
  -      ELSE.
  -        CLEAR lv_opt.
  -      ENDIF.
  -
  -      IF lo_repo->is_offline( ) = abap_true.
  -        lo_offline->add( iv_txt = lo_repo->get_name( )
  -                         iv_act = |{ c_actions-show }?{ lo_repo->get_key( ) }|
  -                         iv_opt = lv_opt ).
  -      ELSE.
  -        READ TABLE lt_repo_bkg WITH KEY key = lo_repo->get_key( )
  -          TRANSPORTING NO FIELDS.
  -        IF sy-subrc = 0.
  -          lo_background->add( iv_txt = lo_repo->get_name( )
  -                              iv_act = |{ c_actions-show }?{ lo_repo->get_key( ) }|
  -                              iv_opt = lv_opt ).
  -        ELSE.
  -          lo_online->add( iv_txt = lo_repo->get_name( )
  -                          iv_act = |{ c_actions-show }?{ lo_repo->get_key( ) }|
  -                          iv_opt = lv_opt ).
  -        ENDIF.
  -      ENDIF.
  -
  -    ENDLOOP.
  -
  -    ro_html->add( '<div id="toc"><div class="toc_grid">' ) ##NO_TEXT.
  -
  -    IF lo_online->count( ) > 0.
  -      ro_html->add( render_toc_line( io_toolbar   = lo_online
  -                                     iv_image_url = 'img/repo_online' ) ).
  -    ENDIF.
  -
  -    IF lo_offline->count( ) > 0.
  -      ro_html->add( render_toc_line( io_toolbar   = lo_offline
  -                                     iv_image_url = 'img/repo_offline' ) ).
  -    ENDIF.
  -
  -    IF lo_background->count( ) > 0.
  -      ro_html->add( render_toc_line( io_toolbar   = lo_background
  -                                     iv_image_url = 'img/sync' ) ).
  -    ENDIF.
  -
  -    ro_html->add( '</div></div>' ).
  -
  -  ENDMETHOD.  "render_toc
  -
  -  METHOD render_toc_line.
  -    CREATE OBJECT ro_html.
  -
  -    ro_html->add( '<div class="toc_row"><table><tr>' ).
  -
  -    ro_html->add( '<td>' ).
  -    ro_html->add( |<img src="{ iv_image_url }">| ).
  -    ro_html->add( '</td>' ).
  -
  -    ro_html->add( '<td>' ).
  -    ro_html->add( io_toolbar->render( iv_sort = abap_true ) ).
  -    ro_html->add( '</td>' ).
  -
  -    ro_html->add( '</tr></table></div>' ).
  -
  -  ENDMETHOD.  "render_toc_line
  -
  -  METHOD render_error.
  -
  -    CREATE OBJECT ro_html.
  -
  -    ro_html->add( '<div class="dummydiv attention">' ).
  -    ro_html->add( |Error: { ix_error->mv_text }| ).
  -    ro_html->add( '</div>' ).
  -
  -  ENDMETHOD.
  -
  -  METHOD render_explore.
  -
  -    DATA lo_toolbar TYPE REF TO lcl_html_toolbar.
  -
  -    CREATE OBJECT ro_html.
  -    CREATE OBJECT lo_toolbar.
  -
  -    lo_toolbar->add( iv_txt = 'Explore new projects'
  -                     iv_act = gc_action-go_explore ) ##NO_TEXT.
  -
  -    ro_html->add( '<div class="dummydiv">' ).
  -    ro_html->add( lo_toolbar->render( ) ).
  -    ro_html->add( '</div>' ).
  -
  -  ENDMETHOD.
  -
  -  METHOD lif_gui_page~on_event.
  -
  -    DATA: lv_key  TYPE lcl_persistence_repo=>ty_repo-key,
  -          lv_url  TYPE string.
  -
  -    lv_key   = iv_getdata.
  -
  -    CASE iv_action.
  -      WHEN gc_action-repo_newoffline.   " New offline repo
  -        lcl_services_repo=>new_offline( ).
  -        ev_state = gc_event_state-re_render.
  -      WHEN gc_action-git_branch_delete. " Delete remote branch
  -        lcl_services_git=>delete_branch( lv_key ).
  -        ev_state = gc_event_state-re_render.
  -      WHEN gc_action-git_branch_switch. " Switch branch
  -        lcl_services_git=>switch_branch( lv_key ).
  -        ev_state = gc_event_state-re_render.
  -      WHEN c_actions-show.              " Change displayed repo
  -        lcl_app=>user( )->set_repo_show( lv_key ).
  -        ev_state = gc_event_state-re_render.
  -      WHEN c_actions-toggle_hide_files. " Toggle file diplay
  -        lcl_app=>user( )->toggle_hide_files( ).
  -        ev_state = gc_event_state-re_render.
  -    ENDCASE.
  -
  -  ENDMETHOD.
  -
  -  METHOD lif_gui_page~render.
  -
  -    DATA: lt_repos   TYPE lcl_repo_srv=>ty_repo_tt,
  -          lx_error   TYPE REF TO lcx_exception,
  -          lo_repo    LIKE LINE OF lt_repos.
  -
  -    retrieve_active_repo( ). " Get and validate key of user default repo
  -    mv_hide_files = lcl_app=>user( )->get_hide_files( ).
  -
  -    CREATE OBJECT ro_html.
  -
  -    ro_html->add( header( io_include_style = styles( ) ) ).
  -    ro_html->add( title( iv_title = 'HOME'
  -                         io_menu  = build_main_menu( ) ) ).
  -
  -    TRY.
  -        lt_repos = lcl_app=>repo_srv( )->list( ).
  -      CATCH lcx_exception INTO lx_error.
  -        ro_html->add( render_error( lx_error ) ).
  -    ENDTRY.
  -
  -    ro_html->add( render_toc( lt_repos ) ).
  -
  -    IF lines( lt_repos ) = 0 AND lx_error IS INITIAL.
  -      ro_html->add( render_explore( ) ).
  -    ELSE.
  -      lo_repo = lcl_app=>repo_srv( )->get( mv_show ).
  -      ro_html->add( render_repo( lo_repo ) ).
  -    ENDIF.
  -
  -    ro_html->add( footer( ) ).
  -
  -  ENDMETHOD.
  +  ENDMETHOD.  "styles
   
     METHOD lif_gui_page~get_assets.
   * http://fa2png.io/r/octicons/
  
positive.code:       && '1gQQfzKDhgCSPFw9Kg2yZ9WqAgBWJBENLk6V3AAAAABJRU5ErkJggg=='.
      APPEND ls_image TO rt_assets.
  
    ENDMETHOD.
  
  ENDCLASS.
negative.code:     lo_html->add_anchor( iv_txt = |{ iv_obj_name }| iv_act = |{ gc_action-jump }?{ lv_encode }| ).
      rv_html = lo_html->mv_html.
  
    ENDMETHOD.  "render_obj_jump_link
  
    METHOD build_main_menu.
  
  