Package epydoc :: Package docwriter :: Module html_css
[hide private]
[frames] | no frames]

Source Code for Module epydoc.docwriter.html_css

  1  # 
  2  # epydoc.css: default epydoc CSS stylesheets 
  3  # Edward Loper 
  4  # 
  5  # Created [01/30/01 05:18 PM] 
  6  # $Id: html_css.py 1517 2007-02-16 06:13:56Z edloper $ 
  7  # 
  8   
  9  """ 
 10  Predefined CSS stylesheets for the HTML outputter (L{epydoc.docwriter.html}). 
 11   
 12  @type STYLESHEETS: C{dictionary} from C{string} to C{(string, string)} 
 13  @var STYLESHEETS: A dictionary mapping from stylesheet names to CSS 
 14      stylesheets and descriptions.  A single stylesheet may have 
 15      multiple names.  Currently, the following stylesheets are defined: 
 16        - C{default}: The default stylesheet (synonym for C{white}). 
 17        - C{white}: Black on white, with blue highlights (similar to 
 18          javadoc). 
 19        - C{blue}: Black on steel blue. 
 20        - C{green}: Black on green. 
 21        - C{black}: White on black, with blue highlights 
 22        - C{grayscale}: Grayscale black on white. 
 23        - C{none}: An empty stylesheet. 
 24  """ 
 25  __docformat__ = 'epytext en' 
 26   
 27  import re 
 28   
 29  ############################################################ 
 30  ## Basic stylesheets 
 31  ############################################################ 
 32   
 33  # [xx] Should I do something like: 
 34  # 
 35  #    @import url(html4css1.css); 
 36  # 
 37  # But then where do I get that css file from?  Hm. 
 38  # Also, in principle I'm mangling classes, but it looks like I'm 
 39  # failing. 
 40  # 
 41   
 42  # Black on white, with blue highlights.  This is similar to how 
 43  # javadoc looks. 
 44  TEMPLATE = """ 
 45   
 46  /* Epydoc CSS Stylesheet 
 47   * 
 48   * This stylesheet can be used to customize the appearance of epydoc's 
 49   * HTML output. 
 50   * 
 51   */ 
 52   
 53  /* Default Colors & Styles 
 54   *   - Set the default foreground & background color with 'body'; and  
 55   *     link colors with 'a:link' and 'a:visited'. 
 56   *   - Use bold for decision list terms. 
 57   *   - The heading styles defined here are used for headings *within* 
 58   *     docstring descriptions.  All headings used by epydoc itself use 
 59   *     either class='epydoc' or class='toc' (CSS styles for both 
 60   *     defined below). 
 61   */ 
 62  body                        { background: $body_bg; color: $body_fg; } 
 63  a:link                      { color: $body_link; } 
 64  a:visited                   { color: $body_visited_link; } 
 65  dt                          { font-weight: bold; } 
 66  h1                          { font-size: +140%; font-style: italic; 
 67                                font-weight: bold; } 
 68  h2                          { font-size: +125%; font-style: italic; 
 69                                font-weight: bold; } 
 70  h3                          { font-size: +110%; font-style: italic; 
 71                                font-weight: normal; } 
 72  code                        { font-size: 100%; } 
 73    
 74  /* Page Header & Footer 
 75   *   - The standard page header consists of a navigation bar (with 
 76   *     pointers to standard pages such as 'home' and 'trees'); a 
 77   *     breadcrumbs list, which can be used to navigate to containing 
 78   *     classes or modules; options links, to show/hide private 
 79   *     variables and to show/hide frames; and a page title (using 
 80   *     <h1>).  The page title may be followed by a link to the 
 81   *     corresponding source code (using 'span.codelink'). 
 82   *   - The footer consists of a navigation bar, a timestamp, and a 
 83   *     pointer to epydoc's homepage. 
 84   */  
 85  h1.epydoc                   { margin: 0; font-size: +140%; font-weight: bold; } 
 86  h2.epydoc                   { font-size: +130%; font-weight: bold; } 
 87  h3.epydoc                   { font-size: +115%; font-weight: bold; } 
 88  td h3.epydoc                { font-size: +115%; font-weight: bold; 
 89                                margin-bottom: 0; } 
 90  table.navbar                { background: $navbar_bg; color: $navbar_fg; 
 91                                border: $navbar_border; } 
 92  table.navbar table          { color: $navbar_fg; } 
 93  th.navbar-select            { background: $navbar_select_bg; 
 94                                color: $navbar_select_fg; }  
 95  table.navbar a              { text-decoration: none; }   
 96  table.navbar a:link         { color: $navbar_link; } 
 97  table.navbar a:visited      { color: $navbar_visited_link; } 
 98  span.breadcrumbs            { font-size: 85%; font-weight: bold; } 
 99  span.options                { font-size: 70%; } 
100  span.codelink               { font-size: 85%; } 
101  td.footer                   { font-size: 85%; } 
102   
103  /* Table Headers 
104   *   - Each summary table and details section begins with a 'header' 
105   *     row.  This row contains a section title (marked by 
106   *     'span.table-header') as well as a show/hide private link 
107   *     (marked by 'span.options', defined above). 
108   *   - Summary tables that contain user-defined groups mark those 
109   *     groups using 'group header' rows. 
110   */ 
111  td.table-header             { background: $table_hdr_bg; color: $table_hdr_fg; 
112                                border: $table_border; } 
113  td.table-header table       { color: $table_hdr_fg; } 
114  td.table-header table a:link      { color: $table_hdr_link; } 
115  td.table-header table a:visited   { color: $table_hdr_visited_link; } 
116  span.table-header           { font-size: 120%; font-weight: bold; } 
117  th.group-header             { background: $group_hdr_bg; color: $group_hdr_fg; 
118                                text-align: left; font-style: italic;  
119                                font-size: 115%;  
120                                border: $table_border; } 
121   
122  /* Summary Tables (functions, variables, etc) 
123   *   - Each object is described by a single row of the table with 
124   *     two cells.  The left cell gives the object's type, and is 
125   *     marked with 'code.summary-type'.  The right cell gives the 
126   *     object's name and a summary description. 
127   *   - CSS styles for the table's header and group headers are 
128   *     defined above, under 'Table Headers' 
129   */ 
130  table.summary               { border-collapse: collapse; 
131                                background: $table_bg; color: $table_fg; 
132                                border: $table_border; 
133                                margin-bottom: 0.5em; } 
134  td.summary                  { border: $table_border; } 
135  code.summary-type           { font-size: 85%; } 
136  table.summary a:link        { color: $table_link; } 
137  table.summary a:visited     { color: $table_visited_link; } 
138   
139   
140  /* Details Tables (functions, variables, etc) 
141   *   - Each object is described in its own div. 
142   *   - A single-row summary table w/ table-header is used as 
143   *     a header for each details section (CSS style for table-header 
144   *     is defined above, under 'Table Headers'). 
145   */ 
146  table.details               { border-collapse: collapse; 
147                                background: $table_bg; color: $table_fg; 
148                                border: $table_border; 
149                                margin: .2em 0 0 0; } 
150  table.details table         { color: $table_fg; } 
151  table.details a:link        { color: $table_link; } 
152  table.details a:visited     { color: $table_visited_link; } 
153   
154  /* Fields */ 
155  dl.fields                   { margin-left: 2em; margin-top: 1em; 
156                                margin-bottom: 1em; } 
157  dl.fields dd ul             { margin-left: 0em; padding-left: 0em; } 
158  div.fields                  { margin-left: 2em; } 
159  div.fields p                { margin-bottom: 0.5em; } 
160   
161  /* Index tables (identifier index, term index, etc) 
162   *   - link-index is used for indices containing lists of links 
163   *     (namely, the identifier index & term index). 
164   *   - index-where is used in link indices for the text indicating 
165   *     the container/source for each link. 
166   *   - metadata-index is used for indices containing metadata 
167   *     extracted from fields (namely, the bug index & todo index). 
168   */ 
169  table.link-index            { border-collapse: collapse; 
170                                background: $table_bg; color: $table_fg; 
171                                border: $table_border; } 
172  td.link-index               { border-width: 0px; } 
173  table.link-index a:link     { color: $table_link; } 
174  table.link-index a:visited  { color: $table_visited_link; } 
175  span.index-where            { font-size: 70%; } 
176  table.metadata-index        { border-collapse: collapse; 
177                                background: $table_bg; color: $table_fg; 
178                                border: $table_border;  
179                                margin: .2em 0 0 0; } 
180  td.metadata-index           { border-width: 1px; border-style: solid; } 
181  table.metadata-index a:link { color: $table_link; } 
182  table.metadata-index a:visited  { color: $table_visited_link; } 
183   
184  /* Function signatures 
185   *   - sig* is used for the signature in the details section. 
186   *   - .summary-sig* is used for the signature in the summary  
187   *     table, and when listing property accessor functions. 
188   * */ 
189  .sig-name                   { color: $sig_name; } 
190  .sig-arg                    { color: $sig_arg; } 
191  .sig-default                { color: $sig_default; } 
192  .summary-sig                { font-family: monospace; } 
193  .summary-sig-name           { color: $summary_sig_name; font-weight: bold; } 
194  table.summary a.summary-sig-name:link 
195                              { color: $summary_sig_name; font-weight: bold; } 
196  table.summary a.summary-sig-name:visited 
197                              { color: $summary_sig_name; font-weight: bold; } 
198  .summary-sig-arg            { color: $summary_sig_arg; } 
199  .summary-sig-default        { color: $summary_sig_default; } 
200   
201  /* To render variables, classes etc. like functions */ 
202  table.summary .summary-name { color: $summary_sig_name; font-weight: bold; 
203                                font-family: monospace; } 
204  table.summary 
205       a.summary-name:link    { color: $summary_sig_name; font-weight: bold; 
206                                font-family: monospace; } 
207  table.summary 
208      a.summary-name:visited  { color: $summary_sig_name; font-weight: bold; 
209                                font-family: monospace; } 
210   
211  /* Variable values 
212   *   - In the 'variable details' sections, each varaible's value is 
213   *     listed in a 'pre.variable' box.  The width of this box is 
214   *     restricted to 80 chars; if the value's repr is longer than 
215   *     this it will be wrapped, using a backslash marked with 
216   *     class 'variable-linewrap'.  If the value's repr is longer 
217   *     than 3 lines, the rest will be ellided; and an ellipsis 
218   *     marker ('...' marked with 'variable-ellipsis') will be used. 
219   *   - If the value is a string, its quote marks will be marked 
220   *     with 'variable-quote'. 
221   *   - If the variable is a regexp, it is syntax-highlighted using 
222   *     the re* CSS classes. 
223   */ 
224  pre.variable                { padding: .5em; margin: 0; 
225                                background: $variable_bg; color: $variable_fg; 
226                                border: $variable_border; } 
227  .variable-linewrap          { color: $variable_linewrap; font-weight: bold; } 
228  .variable-ellipsis          { color: $variable_ellipsis; font-weight: bold; } 
229  .variable-quote             { color: $variable_quote; font-weight: bold; } 
230  .variable-group             { color: $variable_group; font-weight: bold; } 
231  .variable-op                { color: $variable_op; font-weight: bold; } 
232  .variable-string            { color: $variable_string; } 
233  .variable-unknown           { color: $variable_unknown; font-weight: bold; } 
234  .re                         { color: $re; } 
235  .re-char                    { color: $re_char; } 
236  .re-op                      { color: $re_op; } 
237  .re-group                   { color: $re_group; } 
238  .re-ref                     { color: $re_ref; } 
239   
240  /* Base tree 
241   *   - Used by class pages to display the base class hierarchy. 
242   */ 
243  pre.base-tree               { font-size: 80%; margin: 0; } 
244   
245  /* Frames-based table of contents headers 
246   *   - Consists of two frames: one for selecting modules; and 
247   *     the other listing the contents of the selected module. 
248   *   - h1.toc is used for each frame's heading 
249   *   - h2.toc is used for subheadings within each frame. 
250   */ 
251  h1.toc                      { text-align: center; font-size: 105%; 
252                                margin: 0; font-weight: bold; 
253                                padding: 0; } 
254  h2.toc                      { font-size: 100%; font-weight: bold;  
255                                margin: 0.5em 0 0 -0.3em; } 
256   
257  /* Syntax Highlighting for Source Code 
258   *   - doctest examples are displayed in a 'pre.py-doctest' block. 
259   *     If the example is in a details table entry, then it will use 
260   *     the colors specified by the 'table pre.py-doctest' line. 
261   *   - Source code listings are displayed in a 'pre.py-src' block. 
262   *     Each line is marked with 'span.py-line' (used to draw a line 
263   *     down the left margin, separating the code from the line 
264   *     numbers).  Line numbers are displayed with 'span.py-lineno'. 
265   *     The expand/collapse block toggle button is displayed with 
266   *     'a.py-toggle' (Note: the CSS style for 'a.py-toggle' should not 
267   *     modify the font size of the text.) 
268   *   - If a source code page is opened with an anchor, then the 
269   *     corresponding code block will be highlighted.  The code 
270   *     block's header is highlighted with 'py-highlight-hdr'; and 
271   *     the code block's body is highlighted with 'py-highlight'. 
272   *   - The remaining py-* classes are used to perform syntax 
273   *     highlighting (py-string for string literals, py-name for names, 
274   *     etc.) 
275   */ 
276  pre.py-doctest              { padding: .5em; margin: 1em; 
277                                background: $doctest_bg; color: $doctest_fg; 
278                                border: $doctest_border; } 
279  table pre.py-doctest        { background: $doctest_in_table_bg; 
280                                color: $doctest_in_table_fg; } 
281  pre.py-src                  { border: $pysrc_border;  
282                                background: $pysrc_bg; color: $pysrc_fg; } 
283  .py-line                    { border-left: $pysrc_sep_border;  
284                                margin-left: .2em; padding-left: .4em; } 
285  .py-lineno                  { font-style: italic; font-size: 90%; 
286                                padding-left: .5em; } 
287  a.py-toggle                 { text-decoration: none; } 
288  div.py-highlight-hdr        { border-top: $pysrc_border; 
289                                border-bottom: $pysrc_border; 
290                                background: $pysrc_highlight_hdr_bg; } 
291  div.py-highlight            { border-bottom: $pysrc_border; 
292                                background: $pysrc_highlight_bg; } 
293  .py-prompt                  { color: $py_prompt; font-weight: bold;} 
294  .py-more                    { color: $py_more; font-weight: bold;} 
295  .py-string                  { color: $py_string; } 
296  .py-comment                 { color: $py_comment; } 
297  .py-keyword                 { color: $py_keyword; } 
298  .py-output                  { color: $py_output; } 
299  .py-name                    { color: $py_name; } 
300  .py-name:link               { color: $py_name !important; } 
301  .py-name:visited            { color: $py_name !important; } 
302  .py-number                  { color: $py_number; } 
303  .py-defname                 { color: $py_def_name; font-weight: bold; } 
304  .py-def-name                { color: $py_def_name; font-weight: bold; } 
305  .py-base-class              { color: $py_base_class; } 
306  .py-param                   { color: $py_param; } 
307  .py-docstring               { color: $py_docstring; } 
308  .py-decorator               { color: $py_decorator; } 
309  /* Use this if you don't want links to names underlined: */ 
310  /*a.py-name                   { text-decoration: none; }*/ 
311   
312  /* Graphs & Diagrams 
313   *   - These CSS styles are used for graphs & diagrams generated using 
314   *     Graphviz dot.  'img.graph-without-title' is used for bare 
315   *     diagrams (to remove the border created by making the image 
316   *     clickable). 
317   */ 
318  img.graph-without-title     { border: none; } 
319  img.graph-with-title        { border: $graph_border; } 
320  span.graph-title            { font-weight: bold; } 
321  span.graph-caption          { } 
322   
323  /* General-purpose classes 
324   *   - 'p.indent-wrapped-lines' defines a paragraph whose first line 
325   *     is not indented, but whose subsequent lines are. 
326   *   - The 'nomargin-top' class is used to remove the top margin (e.g. 
327   *     from lists).  The 'nomargin' class is used to remove both the 
328   *     top and bottom margin (but not the left or right margin -- 
329   *     for lists, that would cause the bullets to disappear.) 
330   */ 
331  p.indent-wrapped-lines      { padding: 0 0 0 7em; text-indent: -7em;  
332                                margin: 0; } 
333  .nomargin-top               { margin-top: 0; } 
334  .nomargin                   { margin-top: 0; margin-bottom: 0; } 
335   
336  /* HTML Log */ 
337  div.log-block               { padding: 0; margin: .5em 0 .5em 0; 
338                                background: $log_bg; color: $log_fg; 
339                                border: $log_border; } 
340  div.log-error               { padding: .1em .3em .1em .3em; margin: 4px; 
341                                background: $log_error_bg; color: $log_error_fg; 
342                                border: $log_error_border; } 
343  div.log-warning             { padding: .1em .3em .1em .3em; margin: 4px; 
344                                background: $log_warn_bg; color: $log_warn_fg; 
345                                border: $log_warn_border; } 
346  div.log-info               { padding: .1em .3em .1em .3em; margin: 4px; 
347                                background: $log_info_bg; color: $log_info_fg; 
348                                border: $log_info_border; } 
349  h2.log-hdr                  { background: $log_hdr_bg; color: $log_hdr_fg; 
350                                margin: 0; padding: 0em 0.5em 0em 0.5em; 
351                                border-bottom: $log_border; font-size: 110%; } 
352  p.log                       { font-weight: bold; margin: .5em 0 .5em 0; } 
353  tr.opt-changed              { color: $opt_changed_fg; font-weight: bold; } 
354  tr.opt-default              { color: $opt_default_fg; } 
355  pre.log                     { margin: 0; padding: 0; padding-left: 1em; } 
356  """  
357   
358  ############################################################ 
359  ## Derived stylesheets 
360  ############################################################ 
361  # Use some simple manipulations to produce a wide variety of color 
362  # schemes.  In particular, use th _COLOR_RE regular expression to 
363  # search for colors, and to transform them in various ways. 
364   
365  _COLOR_RE = re.compile(r'#(..)(..)(..)') 
366   
367 -def _set_colors(template, *dicts):
368 colors = dicts[0].copy() 369 for d in dicts[1:]: colors.update(d) 370 return re.sub(r'\$(\w+)', lambda m:colors[m.group(1)], template)
371
372 -def _rv(match):
373 """ 374 Given a regexp match for a color, return the reverse-video version 375 of that color. 376 377 @param match: A regular expression match. 378 @type match: C{Match} 379 @return: The reverse-video color. 380 @rtype: C{string} 381 """ 382 rgb = [int(grp, 16) for grp in match.groups()] 383 return '#' + ''.join(['%02x' % (255-c) for c in rgb])
384
385 -def _darken_darks(match):
386 rgb = [int(grp, 16) for grp in match.groups()] 387 return '#' + ''.join(['%02x' % (((c/255.)**2) * 255) for c in rgb])
388 389 _WHITE_COLORS = dict( 390 # Defaults: 391 body_bg = '#ffffff', 392 body_fg = '#000000', 393 body_link = '#0000ff', 394 body_visited_link = '#204080', 395 # Navigation bar: 396 navbar_bg = '#a0c0ff', 397 navbar_fg = '#000000', 398 navbar_border = '2px groove #c0d0d0', 399 navbar_select_bg = '#70b0ff', 400 navbar_select_fg = '#000000', 401 navbar_link = '#0000ff', 402 navbar_visited_link = '#204080', 403 # Tables (summary tables, details tables, indices): 404 table_bg = '#e8f0f8', 405 table_fg = '#000000', 406 table_link = '#0000ff', 407 table_visited_link = '#204080', 408 table_border = '1px solid #608090', 409 table_hdr_bg = '#70b0ff', 410 table_hdr_fg = '#000000', 411 table_hdr_link = '#0000ff', 412 table_hdr_visited_link = '#204080', 413 group_hdr_bg = '#c0e0f8', 414 group_hdr_fg = '#000000', 415 # Function signatures: 416 sig_name = '#006080', 417 sig_arg = '#008060', 418 sig_default = '#602000', 419 summary_sig_name = '#006080', 420 summary_sig_arg = '#006040', 421 summary_sig_default = '#501800', 422 # Variable values: 423 variable_bg = '#dce4ec', 424 variable_fg = '#000000', 425 variable_border = '1px solid #708890', 426 variable_linewrap = '#604000', 427 variable_ellipsis = '#604000', 428 variable_quote = '#604000', 429 variable_group = '#008000', 430 variable_string = '#006030', 431 variable_op = '#604000', 432 variable_unknown = '#a00000', 433 re = '#000000', 434 re_char = '#006030', 435 re_op = '#600000', 436 re_group = '#003060', 437 re_ref = '#404040', 438 # Python source code: 439 doctest_bg = '#e8f0f8', 440 doctest_fg = '#000000', 441 doctest_border = '1px solid #708890', 442 doctest_in_table_bg = '#dce4ec', 443 doctest_in_table_fg = '#000000', 444 pysrc_border = '2px solid #000000', 445 pysrc_sep_border = '2px solid #000000', 446 pysrc_bg = '#f0f0f0', 447 pysrc_fg = '#000000', 448 pysrc_highlight_hdr_bg = '#d8e8e8', 449 pysrc_highlight_bg = '#d0e0e0', 450 py_prompt = '#005050', 451 py_more = '#005050', 452 py_string = '#006030', 453 py_comment = '#003060', 454 py_keyword = '#600000', 455 py_output = '#404040', 456 py_name = '#000050', 457 py_number = '#005000', 458 py_def_name = '#000060', 459 py_base_class = '#000060', 460 py_param = '#000060', 461 py_docstring = '#006030', 462 py_decorator = '#804020', 463 # Graphs 464 graph_border = '1px solid #000000', 465 # Log block 466 log_bg = '#e8f0f8', 467 log_fg = '#000000', 468 log_border = '1px solid #000000', 469 log_hdr_bg = '#70b0ff', 470 log_hdr_fg = '#000000', 471 log_error_bg = '#ffb0b0', 472 log_error_fg = '#000000', 473 log_error_border = '1px solid #000000', 474 log_warn_bg = '#ffffb0', 475 log_warn_fg = '#000000', 476 log_warn_border = '1px solid #000000', 477 log_info_bg = '#b0ffb0', 478 log_info_fg = '#000000', 479 log_info_border = '1px solid #000000', 480 opt_changed_fg = '#000000', 481 opt_default_fg = '#606060', 482 ) 483 484 _BLUE_COLORS = _WHITE_COLORS.copy() 485 _BLUE_COLORS.update(dict( 486 # Body: white text on a dark blue background 487 body_bg = '#000070', 488 body_fg = '#ffffff', 489 body_link = '#ffffff', 490 body_visited_link = '#d0d0ff', 491 # Tables: cyan headers, black on white bodies 492 table_bg = '#ffffff', 493 table_fg = '#000000', 494 table_hdr_bg = '#70b0ff', 495 table_hdr_fg = '#000000', 496 table_hdr_link = '#000000', 497 table_hdr_visited_link = '#000000', 498 table_border = '1px solid #000000', 499 # Navigation bar: blue w/ cyan selection 500 navbar_bg = '#0000ff', 501 navbar_fg = '#ffffff', 502 navbar_link = '#ffffff', 503 navbar_visited_link = '#ffffff', 504 navbar_select_bg = '#70b0ff', 505 navbar_select_fg = '#000000', 506 navbar_border = '1px solid #70b0ff', 507 # Variable values & doctest blocks: cyan 508 variable_bg = '#c0e0f8', 509 variable_fg = '#000000', 510 doctest_bg = '#c0e0f8', 511 doctest_fg = '#000000', 512 doctest_in_table_bg = '#c0e0f8', 513 doctest_in_table_fg = '#000000', 514 )) 515 516 _WHITE = _set_colors(TEMPLATE, _WHITE_COLORS) 517 _BLUE = _set_colors(TEMPLATE, _BLUE_COLORS) 518 519 # Black-on-green 520 _GREEN = _COLOR_RE.sub(_darken_darks, _COLOR_RE.sub(r'#\1\3\2', _BLUE)) 521 522 # White-on-black, with blue highlights. 523 _BLACK = _COLOR_RE.sub(r'#\3\2\1', _COLOR_RE.sub(_rv, _WHITE)) 524 525 # Grayscale 526 _GRAYSCALE = _COLOR_RE.sub(r'#\2\2\2', _WHITE) 527 528 ############################################################ 529 ## Stylesheet table 530 ############################################################ 531 532 STYLESHEETS = { 533 'white': (_WHITE, "Black on white, with blue highlights"), 534 'blue': (_BLUE, "Black on steel blue"), 535 'green': (_GREEN, "Black on green"), 536 'black': (_BLACK, "White on black, with blue highlights"), 537 'grayscale': (_GRAYSCALE, "Grayscale black on white"), 538 'default': (_WHITE, "Default stylesheet (=white)"), 539 # 'none': (_LAYOUT, "A base stylesheet (no color modifications)"), 540 } 541