<s> from time import time <EOL> from StringIO import StringIO <EOL> import string <EOL> import wx <EOL> from wx import stc <EOL> from robotide import robotapi <EOL> from robotide . context import IS_WINDOWS , IS_MAC <EOL> from robotide . controller . commands import SetDataFile <EOL> from robotide . publish . messages import RideMessage <EOL> from robotide . widgets import VerticalSizer , HorizontalSizer , ButtonWithHandler <EOL> from robotide . pluginapi import Plugin , RideSaving , TreeAwarePluginMixin , RideTreeSelection , RideNotebookTabChanging , RideDataChanged , RideOpenSuite , RideDataChangedToDirty <EOL> from robotide . widgets import TextField , Label , HtmlDialog <EOL> try : <EOL> from . import robotframeworklexer <EOL> except Exception as e : <EOL> robotframeworklexer = None <EOL> class TextEditorPlugin ( Plugin , TreeAwarePluginMixin ) : <EOL> title = '<STR_LIT>' <EOL> def __init__ ( self , application ) : <EOL> Plugin . __init__ ( self , application ) <EOL> self . _editor_component = None <EOL> @ property <EOL> def _editor ( self ) : <EOL> if not self . _editor_component : <EOL> self . _editor_component = SourceEditor ( self . notebook , <EOL> self . title , <EOL> DataValidationHandler ( self ) ) <EOL> self . _refresh_timer = wx . Timer ( self . _editor_component ) <EOL> self . _editor_component . Bind ( wx . EVT_TIMER , self . _on_timer ) <EOL> return self . _editor_component <EOL> def enable ( self ) : <EOL> self . add_self_as_tree_aware_plugin ( ) <EOL> self . subscribe ( self . OnSaving , RideSaving ) <EOL> self . subscribe ( self . OnTreeSelection , RideTreeSelection ) <EOL> self . subscribe ( self . OnDataChanged , RideMessage ) <EOL> self . subscribe ( self . OnTabChange , RideNotebookTabChanging ) <EOL> self . _register_shortcuts ( ) <EOL> self . _open ( ) <EOL> def _register_shortcuts ( self ) : <EOL> def focused ( func ) : <EOL> def f ( event ) : <EOL> if self . is_focused ( ) and self . _editor . is_focused ( ) : <EOL> func ( event ) <EOL> return f <EOL> self . register_shortcut ( '<STR_LIT>' , focused ( lambda e : self . _editor . cut ( ) ) ) <EOL> self . register_shortcut ( '<STR_LIT>' , focused ( lambda e : self . _editor . copy ( ) ) ) <EOL> if IS_MAC : <EOL> self . register_shortcut ( '<STR_LIT>' , focused ( lambda e : self . _editor . select_all ( ) ) ) <EOL> if IS_WINDOWS or IS_MAC : <EOL> self . register_shortcut ( '<STR_LIT>' , focused ( lambda e : self . _editor . paste ( ) ) ) <EOL> self . register_shortcut ( '<STR_LIT>' , focused ( lambda e : self . _editor . undo ( ) ) ) <EOL> self . register_shortcut ( '<STR_LIT>' , focused ( lambda e : self . _editor . redo ( ) ) ) <EOL> self . register_shortcut ( '<STR_LIT>' , focused ( lambda e : self . _editor . delete ( ) ) ) <EOL> self . register_shortcut ( '<STR_LIT>' , lambda e : self . _editor . _search_field . SetFocus ( ) ) <EOL> self . register_shortcut ( '<STR_LIT>' , lambda e : self . _editor . OnFind ( e ) ) <EOL> self . register_shortcut ( '<STR_LIT>' , lambda e : self . _editor . OnFindBackwards ( e ) ) <EOL> def disable ( self ) : <EOL> self . remove_self_from_tree_aware_plugins ( ) <EOL> self . unsubscribe_all ( ) <EOL> self . unregister_actions ( ) <EOL> self . delete_tab ( self . _editor ) <EOL> self . _editor_component = None <EOL> def OnOpen ( self , event ) : <EOL> self . _open ( ) <EOL> def _open ( self ) : <EOL> datafile_controller = self . tree . get_selected_datafile_controller ( ) <EOL> if datafile_controller : <EOL> self . _open_data_for_controller ( datafile_controller ) <EOL> self . show_tab ( self . _editor ) <EOL> def OnSaving ( self , message ) : <EOL> if self . is_focused ( ) : <EOL> self . _editor . save ( ) <EOL> def OnDataChanged ( self , message ) : <EOL> if self . _should_process_data_changed_message ( message ) : <EOL> if isinstance ( message , RideOpenSuite ) : <EOL> self . _editor . reset ( ) <EOL> if self . _editor . dirty : <EOL> self . _apply_txt_changes_to_model ( ) <EOL> self . _refresh_timer . Start ( <NUM_LIT> , True ) <EOL> def _on_timer ( self , event ) : <EOL> self . _open_tree_selection_in_editor ( ) <EOL> event . Skip ( ) <EOL> def _should_process_data_changed_message ( self , message ) : <EOL> return isinstance ( message , RideDataChanged ) and not isinstance ( message , RideDataChangedToDirty ) <EOL> def OnTreeSelection ( self , message ) : <EOL> self . _editor . store_position ( ) <EOL> if self . is_focused ( ) : <EOL> next_datafile_controller = message . item and message . item . datafile_controller <EOL> if self . _editor . dirty : <EOL> if not self . _apply_txt_changes_to_model ( ) : <EOL> if self . _editor . datafile_controller != next_datafile_controller : <EOL> self . tree . select_controller_node ( self . _editor . datafile_controller ) <EOL> return <EOL> if next_datafile_controller : <EOL> self . _open_data_for_controller ( next_datafile_controller ) <EOL> self . _editor . set_editor_caret_position ( ) <EOL> def _open_tree_selection_in_editor ( self ) : <EOL> datafile_controller = self . tree . get_selected_datafile_controller ( ) <EOL> if datafile_controller : <EOL> self . _editor . open ( DataFileWrapper ( datafile_controller , <EOL> self . global_settings ) ) <EOL> def _open_data_for_controller ( self , datafile_controller ) : <EOL> self . _editor . selected ( DataFileWrapper ( datafile_controller , <EOL> self . global_settings ) ) <EOL> def OnTabChange ( self , message ) : <EOL> if message . newtab == self . title : <EOL> self . _open ( ) <EOL> self . _editor . set_editor_caret_position ( ) <EOL> elif message . oldtab == self . title : <EOL> self . _editor . remove_and_store_state ( ) <EOL> def _apply_txt_changes_to_model ( self ) : <EOL> if not self . _editor . save ( ) : <EOL> return False <EOL> self . _editor . reset ( ) <EOL> return True <EOL> def is_focused ( self ) : <EOL> return self . notebook . current_page_title == self . title <EOL> class DataValidationHandler ( object ) : <EOL> def __init__ ( self , plugin ) : <EOL> self . _plugin = plugin <EOL> self . _last_answer = None <EOL> self . _last_answer_time = <NUM_LIT:0> <EOL> def set_editor ( self , editor ) : <EOL> self . _editor = editor <EOL> def validate_and_update ( self , data , text ) : <EOL> if not self . _sanity_check ( data , text ) : <EOL> self . _handle_sanity_check_failure ( ) <EOL> return False <EOL> else : <EOL> self . _editor . reset ( ) <EOL> data . update_from ( text ) <EOL> return True <EOL> def _sanity_check ( self , data , text ) : <EOL> formatted_text = data . format_text ( text ) . encode ( '<STR_LIT>' ) <EOL> c = self . _normalize ( formatted_text ) <EOL> e = self . _normalize ( text ) <EOL> return len ( c ) == len ( e ) <EOL> def _normalize ( self , text ) : <EOL> for item in tuple ( string . whitespace ) + ( '<STR_LIT>' , '<STR_LIT:*>' ) : <EOL> if item in text : <EOL> text = text . replace ( item , '<STR_LIT>' ) <EOL> return text <EOL> def _handle_sanity_check_failure ( self ) : <EOL> if self . _last_answer == wx . ID_NO and time ( ) - self . _last_answer_time <= <NUM_LIT> : <EOL> self . _editor . _mark_file_dirty ( ) <EOL> return <EOL> id = wx . MessageDialog ( self . _editor , <EOL> '<STR_LIT>' '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> style = wx . YES | wx . NO ) . ShowModal ( ) <EOL> self . _last_answer = id <EOL> self . _last_answer_time = time ( ) <EOL> if id == wx . ID_NO : <EOL> self . _editor . _mark_file_dirty ( ) <EOL> else : <EOL> self . _editor . _revert ( ) <EOL> class DataFileWrapper ( object ) : <EOL> def __init__ ( self , data , settings ) : <EOL> self . _data = data <EOL> self . _settings = settings <EOL> def __eq__ ( self , other ) : <EOL> if other is None : <EOL> return False <EOL> return self . _data == other . _data <EOL> def update_from ( self , content ) : <EOL> self . _data . execute ( SetDataFile ( self . _create_target_from ( content ) ) ) <EOL> def _create_target_from ( self , content ) : <EOL> src = StringIO ( content ) <EOL> target = self . _create_target ( ) <EOL> FromStringIOPopulator ( target ) . populate ( src ) <EOL> return target <EOL> def format_text ( self , text ) : <EOL> return self . _txt_data ( self . _create_target_from ( text ) ) <EOL> def mark_data_dirty ( self ) : <EOL> self . _data . mark_dirty ( ) <EOL> def _create_target ( self ) : <EOL> data = self . _data . data <EOL> target_class = type ( data ) <EOL> if isinstance ( data , robotapi . TestDataDirectory ) : <EOL> target = robotapi . TestDataDirectory ( source = self . _data . directory ) <EOL> target . initfile = data . initfile <EOL> return target <EOL> return target_class ( source = self . _data . source ) <EOL> @ property <EOL> def content ( self ) : <EOL> return self . _txt_data ( self . _data . data ) <EOL> def _txt_data ( self , data ) : <EOL> output = StringIO ( ) <EOL> data . save ( output = output , format = '<STR_LIT>' , <EOL> txt_separating_spaces = self . _settings [ '<STR_LIT>' ] ) <EOL> return output . getvalue ( ) . decode ( '<STR_LIT>' ) <EOL> class SourceEditor ( wx . Panel ) : <EOL> def __init__ ( self , parent , title , data_validator ) : <EOL> wx . Panel . __init__ ( self , parent ) <EOL> self . _syntax_colorization_help_exists = False <EOL> self . _data_validator = data_validator <EOL> self . _data_validator . set_editor ( self ) <EOL> self . _parent = parent <EOL> self . _create_ui ( title ) <EOL> self . _data = None <EOL> self . _dirty = False <EOL> self . _positions = { } <EOL> def is_focused ( self ) : <EOL> foc = wx . Window . FindFocus ( ) <EOL> return any ( elem == foc for elem in [ self ] + list ( self . GetChildren ( ) ) ) <EOL> def _create_ui ( self , title ) : <EOL> self . SetSizer ( VerticalSizer ( ) ) <EOL> self . _create_editor_toolbar ( ) <EOL> self . _create_editor_text_control ( ) <EOL> self . _parent . add_tab ( self , title , allow_closing = False ) <EOL> def _create_editor_toolbar ( self ) : <EOL> self . editor_toolbar = HorizontalSizer ( ) <EOL> default_components = HorizontalSizer ( ) <EOL> default_components . add_with_padding ( <EOL> ButtonWithHandler ( self , '<STR_LIT>' , handler = lambda e : self . save ( ) ) ) <EOL> self . _create_search ( default_components ) <EOL> self . editor_toolbar . add_expanding ( default_components ) <EOL> self . Sizer . add_expanding ( self . editor_toolbar , propotion = <NUM_LIT:0> ) <EOL> def _create_search ( self , container_sizer ) : <EOL> container_sizer . AddSpacer ( <NUM_LIT:20> ) <EOL> self . _search_field = TextField ( self , '<STR_LIT>' , process_enters = True ) <EOL> self . _search_field . Bind ( wx . EVT_TEXT_ENTER , self . OnFind ) <EOL> container_sizer . add_with_padding ( self . _search_field ) <EOL> container_sizer . add_with_padding ( <EOL> ButtonWithHandler ( self , '<STR_LIT>' , handler = self . OnFind ) ) <EOL> self . _search_field_notification = Label ( self , label = '<STR_LIT>' ) <EOL> container_sizer . add_with_padding ( self . _search_field_notification ) <EOL> def create_syntax_colorization_help ( self ) : <EOL> if self . _syntax_colorization_help_exists : <EOL> return <EOL> label = Label ( self , label = "<STR_LIT>" ) <EOL> link = wx . HyperlinkCtrl ( self , - <NUM_LIT:1> , label = "<STR_LIT>" , url = "<STR_LIT>" ) <EOL> link . Bind ( wx . EVT_HYPERLINK , self . show_help_dialog ) <EOL> flags = wx . ALIGN_CENTER_VERTICAL | wx . ALIGN_RIGHT <EOL> syntax_colorization_help_sizer = wx . BoxSizer ( wx . VERTICAL ) <EOL> syntax_colorization_help_sizer . AddMany ( [ <EOL> ( label , <NUM_LIT:0> , flags ) , <EOL> ( link , <NUM_LIT:0> , flags ) <EOL> ] ) <EOL> self . editor_toolbar . add_expanding ( syntax_colorization_help_sizer ) <EOL> self . Layout ( ) <EOL> self . _syntax_colorization_help_exists = True <EOL> def show_help_dialog ( self , event ) : <EOL> content = """<STR_LIT>""" <EOL> HtmlDialog ( "<STR_LIT>" , content ) . Show ( ) <EOL> def store_position ( self ) : <EOL> if self . _editor : <EOL> self . _positions [ self . datafile_controller ] = self . _editor . GetCurrentPos ( ) <EOL> def set_editor_caret_position ( self ) : <EOL> position = self . _positions . get ( self . datafile_controller , None ) <EOL> if position : <EOL> self . _editor . SetFocus ( ) <EOL> self . _editor . SetCurrentPos ( position ) <EOL> self . _editor . SetSelection ( position , position ) <EOL> @ property <EOL> def dirty ( self ) : <EOL> return self . _dirty <EOL> @ property <EOL> def datafile_controller ( self ) : <EOL> return self . _data . _data if self . _data else None <EOL> def OnFind ( self , event ) : <EOL> if self . _editor : <EOL> self . _find ( ) <EOL> def OnFindBackwards ( self , event ) : <EOL> if self . _editor : <EOL> self . _find ( forward = False ) <EOL> def _find ( self , forward = True ) : <EOL> txt = self . _search_field . GetValue ( ) <EOL> position = self . _find_text_position ( forward , txt ) <EOL> self . _show_search_results ( position , txt ) <EOL> def _find_text_position ( self , forward , txt ) : <EOL> file_end = len ( self . _editor . utf8_text ) <EOL> search_end = file_end if forward else <NUM_LIT:0> <EOL> anchor = self . _editor . GetAnchor ( ) <EOL> anchor += <NUM_LIT:1> if forward else <NUM_LIT:0> <EOL> position = self . _editor . FindText ( anchor , search_end , txt , <NUM_LIT:0> ) <EOL> if position == - <NUM_LIT:1> : <EOL> start , end = ( <NUM_LIT:0> , file_end ) if forward else ( file_end - <NUM_LIT:1> , <NUM_LIT:0> ) <EOL> position = self . _editor . FindText ( start , end , txt , <NUM_LIT:0> ) <EOL> return position <EOL> def _show_search_results ( self , position , txt ) : <EOL> if position != - <NUM_LIT:1> : <EOL> self . _editor . SetSelection ( position , position + len ( txt ) ) <EOL> self . _search_field_notification . SetLabel ( '<STR_LIT>' ) <EOL> else : <EOL> self . _search_field_notification . SetLabel ( '<STR_LIT>' ) <EOL> def open ( self , data ) : <EOL> self . reset ( ) <EOL> self . _data = data <EOL> if not self . _editor : <EOL> self . _stored_text = self . _data . content <EOL> else : <EOL> self . _editor . set_text ( self . _data . content ) <EOL> self . set_editor_caret_position ( ) <EOL> def selected ( self , data ) : <EOL> if not self . _editor : <EOL> self . _create_editor_text_control ( self . _stored_text ) <EOL> if self . _data == data : <EOL> return <EOL> self . open ( data ) <EOL> def reset ( self ) : <EOL> self . _dirty = False <EOL> def save ( self , * args ) : <EOL> if self . dirty : <EOL> if not self . _data_validator . validate_and_update ( self . _data , <EOL> self . _editor . utf8_text ) : <EOL> return False <EOL> return True <EOL> def delete ( self ) : <EOL> if self . _editor . GetSelectionStart ( ) == self . _editor . GetSelectionEnd ( ) : <EOL> self . _editor . CharRight ( ) <EOL> self . _editor . DeleteBack ( ) <EOL> def cut ( self ) : <EOL> self . _editor . Cut ( ) <EOL> def copy ( self ) : <EOL> self . _editor . Copy ( ) <EOL> def paste ( self ) : <EOL> focus = wx . Window . FindFocus ( ) <EOL> if focus == self . _editor : <EOL> self . _editor . Paste ( ) <EOL> elif focus == self . _search_field : <EOL> self . _search_field . Paste ( ) <EOL> def select_all ( self ) : <EOL> self . _editor . SelectAll ( ) <EOL> def undo ( self ) : <EOL> self . _editor . Undo ( ) <EOL> def redo ( self ) : <EOL> self . _editor . Redo ( ) <EOL> def remove_and_store_state ( self ) : <EOL> if self . _editor : <EOL> self . store_position ( ) <EOL> self . _stored_text = self . _editor . GetText ( ) <EOL> self . _editor . Destroy ( ) <EOL> self . _editor = None <EOL> def _create_editor_text_control ( self , text = None ) : <EOL> self . _editor = RobotDataEditor ( self ) <EOL> self . Sizer . add_expanding ( self . _editor ) <EOL> self . Sizer . Layout ( ) <EOL> if text is not None : <EOL> self . _editor . set_text ( text ) <EOL> self . _editor . Bind ( wx . EVT_KEY_UP , self . OnEditorKey ) <EOL> self . _editor . Bind ( wx . EVT_KILL_FOCUS , self . LeaveFocus ) <EOL> self . _editor . Bind ( wx . EVT_SET_FOCUS , self . GetFocus ) <EOL> def LeaveFocus ( self , event ) : <EOL> self . _editor . SetCaretPeriod ( <NUM_LIT:0> ) <EOL> self . save ( ) <EOL> def GetFocus ( self , event ) : <EOL> self . _editor . SetCaretPeriod ( <NUM_LIT> ) <EOL> event . Skip ( ) <EOL> def _revert ( self ) : <EOL> self . reset ( ) <EOL> self . _editor . set_text ( self . _data . content ) <EOL> def OnEditorKey ( self , event ) : <EOL> if not self . dirty and self . _editor . GetModify ( ) : <EOL> self . _mark_file_dirty ( ) <EOL> event . Skip ( ) <EOL> def _mark_file_dirty ( self ) : <EOL> if self . _data : <EOL> self . _dirty = True <EOL> self . _data . mark_data_dirty ( ) <EOL> class RobotDataEditor ( stc . StyledTextCtrl ) : <EOL> def __init__ ( self , parent ) : <EOL> stc . StyledTextCtrl . __init__ ( self , parent ) <EOL> self . SetMarginType ( <NUM_LIT:0> , stc . STC_MARGIN_NUMBER ) <EOL> self . SetMarginWidth ( <NUM_LIT:0> , self . TextWidth ( stc . STC_STYLE_LINENUMBER , '<STR_LIT>' ) ) <EOL> self . SetReadOnly ( True ) <EOL> self . SetLexer ( stc . STC_LEX_CONTAINER ) <EOL> self . Bind ( stc . EVT_STC_STYLENEEDED , self . OnStyle ) <EOL> self . stylizer = RobotStylizer ( self , parent . _parent . _app . settings ) <EOL> def set_text ( self , text ) : <EOL> self . SetReadOnly ( False ) <EOL> self . SetText ( text ) <EOL> self . stylizer . stylize ( ) <EOL> self . EmptyUndoBuffer ( ) <EOL> @ property <EOL> def utf8_text ( self ) : <EOL> return self . GetText ( ) . encode ( '<STR_LIT>' ) <EOL> def OnStyle ( self , event ) : <EOL> self . stylizer . stylize ( ) <EOL> class FromStringIOPopulator ( robotapi . FromFilePopulator ) : <EOL> def populate ( self , content ) : <EOL> robotapi . TxtReader ( ) . read ( content , self ) <EOL> class RobotStylizer ( object ) : <EOL> def __init__ ( self , editor , settings ) : <EOL> self . editor = editor <EOL> self . lexer = None <EOL> self . settings = settings <EOL> self . font_size = settings [ '<STR_LIT>' ] . get ( '<STR_LIT>' , <NUM_LIT:8> ) <EOL> if robotframeworklexer : <EOL> self . lexer = robotframeworklexer . RobotFrameworkLexer ( ) <EOL> self . _set_styles ( ) <EOL> else : <EOL> self . editor . GetParent ( ) . create_syntax_colorization_help ( ) <EOL> def _set_styles ( self ) : <EOL> color_settings = self . settings . get_without_default ( '<STR_LIT>' ) <EOL> styles = { <EOL> robotframeworklexer . ARGUMENT : { <EOL> '<STR_LIT>' : color_settings [ '<STR_LIT>' ] <EOL> } , <EOL> robotframeworklexer . COMMENT : { <EOL> '<STR_LIT>' : color_settings [ '<STR_LIT>' ] <EOL> } , <EOL> robotframeworklexer . ERROR : { <EOL> '<STR_LIT>' : color_settings [ '<STR_LIT:error>' ] <EOL> } , <EOL> robotframeworklexer . GHERKIN : { <EOL> '<STR_LIT>' : color_settings [ '<STR_LIT>' ] <EOL> } , <EOL> robotframeworklexer . HEADING : { <EOL> '<STR_LIT>' : color_settings [ '<STR_LIT>' ] , <EOL> '<STR_LIT>' : '<STR_LIT:true>' <EOL> } , <EOL> robotframeworklexer . IMPORT : { <EOL> '<STR_LIT>' : color_settings [ '<STR_LIT>' ] <EOL> } , <EOL> robotframeworklexer . KEYWORD : { <EOL> '<STR_LIT>' : color_settings [ '<STR_LIT>' ] , <EOL> '<STR_LIT>' : '<STR_LIT:true>' <EOL> } , <EOL> robotframeworklexer . SEPARATOR : { <EOL> '<STR_LIT>' : color_settings [ '<STR_LIT>' ] <EOL> } , <EOL> robotframeworklexer . SETTING : { <EOL> '<STR_LIT>' : color_settings [ '<STR_LIT>' ] , <EOL> '<STR_LIT>' : '<STR_LIT:true>' <EOL> } , <EOL> robotframeworklexer . SYNTAX : { <EOL> '<STR_LIT>' : color_settings [ '<STR_LIT>' ] <EOL> } , <EOL> robotframeworklexer . TC_KW_NAME : { <EOL> '<STR_LIT>' : color_settings [ '<STR_LIT>' ] <EOL> } , <EOL> robotframeworklexer . VARIABLE : { <EOL> '<STR_LIT>' : color_settings [ '<STR_LIT>' ] <EOL> } <EOL> } <EOL> self . tokens = { } <EOL> for index , token in enumerate ( styles ) : <EOL> self . tokens [ token ] = index <EOL> self . editor . StyleSetSpec ( index , self . _get_style_string ( ** styles [ token ] ) ) <EOL> def _get_word_and_length ( self , current_position ) : <EOL> word = self . editor . GetTextRange ( current_position , self . editor . WordEndPosition ( current_position , False ) ) <EOL> return word , len ( word ) <EOL> def _get_style_string ( self , back = '<STR_LIT>' , face = '<STR_LIT>' , fore = '<STR_LIT>' , bold = '<STR_LIT>' , underline = '<STR_LIT>' ) : <EOL> settings = locals ( ) <EOL> settings . update ( size = self . font_size ) <EOL> return '<STR_LIT:U+002C>' . join ( '<STR_LIT>' % ( name , value ) for name , value in settings . items ( ) if value ) <EOL> def stylize ( self ) : <EOL> if not self . lexer : <EOL> return <EOL> self . editor . ConvertEOLs ( <NUM_LIT:2> ) <EOL> shift = <NUM_LIT:0> <EOL> for position , token , value in self . lexer . get_tokens_unprocessed ( self . editor . GetText ( ) ) : <EOL> self . editor . StartStyling ( position + shift , <NUM_LIT> ) <EOL> self . editor . SetStyling ( len ( value . encode ( '<STR_LIT:utf-8>' ) ) , self . tokens [ token ] ) <EOL> shift += len ( value . encode ( '<STR_LIT:utf-8>' ) ) - len ( value ) </s>
