Update C++ style guide to 3.260:

- Add boost::bimap to the list of allowed Boost libraries.
 - C++11: remove mention of constexpr.
 - Remove noun/verb naming rules, and consolidate "General Naming Rules".
 - C++11: allow variadic templates.
 - Revise guidance on function definition comments.
 - Clarify that one space is sufficient before trailing /* */ comments.
 - C++11: allow alias templates.
 - C++11: allow <array>, deprecate Boost array.
 - C++11: allow unique_ptr, deprecate Boost pointer container.
 - C++11: allow braced initializer lists.

Update Objective-C style guide to 2.56:
 - Add details on constant declarations to clarify naming and scope issues.
 - Update link to Apple's Objective-C guide.
 - Allow left-aligning multi-block method invocation segments.
 - Add section on container literals.

Update Python style guide to 2.54:
 - Allow str.format in addition to the % operator.
 - Allow #!/usr/bin/python2 and #!/usr/bin/python3.
 - Move the closing brace example from column 4 to 0.
 - Remove the requirement to use named parameters for arguments with defaults.

Update HTML/CSS style guide to 2.23:
 - No changes.

Update JavaScript style guide to 2.82:
 - Fix typos, whitespace, and character entities.
 - Include property descriptions in the clause about omitting obvious comments.
 - Make file overviews optional.
 - Fix example in "HTML in JSDoc" section.
 - Remove the semicolon-insertion language from the operators section.
 - State that complete sentences are recommended but not required.
 - Document usage of goog.scope to declare new classes.

Update Common Lisp style guide to 1.20:
 - Indicate both variable and function predicates require a "p".
 - Make the abbreviations rules consistent and in one location.
 - Don't allow for the use of &AUX.
 - Allow for "body" and "end" as exceptions to the suffix rule.
 - Use the TODO convention to mark code that needs to be addressed.
 - Remove file maintainership requirements, require a description.
 - Change top-level form requirements to the length of a page.
 - Remove "don't be clever".
This commit is contained in:
mark@chromium.org 2013-07-12 18:53:13 +00:00
parent 884f95419f
commit 5684bbc8b5
6 changed files with 537 additions and 345 deletions

View File

@ -4,7 +4,7 @@
<p align="right">
Revision 3.245
Revision 3.260
</p>
@ -737,6 +737,14 @@ Tashana Landray
<CODE_SNIPPET>
int j = g(); // Good -- declaration has initialization.
</CODE_SNIPPET>
<BAD_CODE_SNIPPET>
vector&lt;int&gt; v;
v.push_back(1); // Prefer initializing using brace initialization.
v.push_back(2);
</BAD_CODE_SNIPPET>
<CODE_SNIPPET>
vector&lt;int&gt; v = {1, 2}; // Good -- v starts initialized.
</CODE_SNIPPET>
<p>
Note that gcc implements <code>for (int i = 0; i
&lt; 10; ++i)</code> correctly (the scope of <code>i</code> is
@ -779,8 +787,6 @@ Tashana Landray
Static or global variables of class type are forbidden: they cause
hard-to-find bugs due to indeterminate order of construction and
destruction.
However, such variables are allowed if they are <code>constexpr</code>:
they have no dynamic initialization or destruction.
</SUMMARY>
<BODY>
<p>
@ -967,6 +973,12 @@ Tashana Landray
exceptions.
Such exceptions should be clearly marked with comments.
</p>
<p>
Finally, constructors that take only an initializer_list may be
non-explicit. This is to permit construction of your type using the
assigment form for brace init lists (i.e. <code>MyType m = {1, 2}
</code>).
</p>
</DECISION>
</BODY>
</STYLEPOINT>
@ -1453,8 +1465,9 @@ Tashana Landray
<STYLEPOINT title="Smart Pointers">
<SUMMARY>
If you actually need pointer semantics, <code>scoped_ptr</code>
is great. You should only use <code>std::tr1::shared_ptr</code>
If you actually need pointer semantics, <code>unique_ptr</code>
is great, and <code>scoped_ptr</code> is fine if you need to support
older versions of C++. You should only use <code>shared_ptr</code>
with a non-const referent when it is truly necessary to share ownership
of an object (e.g. inside an STL container). You should never use
<code>auto_ptr</code>.
@ -1481,11 +1494,15 @@ Tashana Landray
</CONS>
<DECISION>
<dl>
<dt><code>unique_ptr</code></dt>
<dd>See <a href="#unique_ptr">below</a>.</dd>
<dt><code>scoped_ptr</code></dt>
<dd>Straightforward and risk-free. Use wherever appropriate.</dd>
<dd>Prefer <code>unique_ptr</code> unless C++03 compatibility is
required.</dd>
<dt><code>auto_ptr</code></dt>
<dd>Confusing and bug-prone ownership-transfer semantics. Do not use.
</dd>
<dd>Confusing and bug-prone ownership-transfer semantics. Use
<code>unique_ptr</code> instead, if possible.</dd>
<dt><code>shared_ptr</code></dt>
<dd>
Safe with const referents (i.e. <code>shared_ptr&lt;const
@ -2162,8 +2179,6 @@ Tashana Landray
<STYLEPOINT title="Use of const">
<SUMMARY>
Use <code>const</code> whenever it makes sense.
With C++11,
<code>constexpr</code> is a better choice for some uses of const.
</SUMMARY>
<BODY>
<DEFINITION>
@ -2248,51 +2263,6 @@ Tashana Landray
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Use of constexpr">
<SUMMARY>
In C++11, use <code>constexpr</code>
to define true constants or to ensure constant initialization.
</SUMMARY>
<BODY>
<DEFINITION>
Some variables can be declared <code>constexpr</code>
to indicate the variables are true constants,
i.e. fixed at compilation/link time.
Some functions and constructors can be declared <code>constexpr</code>
which enables them to be used
in defining a <code>constexpr</code> variable.
</DEFINITION>
<PROS>
Use of <code>constexpr</code> enables
definition of constants with floating-point expressions
rather than just literals;
definition of constants of user-defined types; and
definition of constants with function calls.
</PROS>
<CONS>
Prematurely marking something as constexpr
may cause migration problems if later on it has to be downgraded.
Current restrictions on what is allowed
in constexpr functions and constructors
may invite obscure workarounds in these definitions.
</CONS>
<DECISION>
<p>
<code>constexpr</code> definitions enable a more robust
specification of the constant parts of an interface.
Use <code>constexpr</code> to specify true constants
and the functions that support their definitions.
Avoid complexifying function definitions to enable
their use with <code>constexpr</code>.
Do not use <code>constexpr</code> to force inlining.
</p>
</DECISION>
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Integer Types">
<SUMMARY>
Of the built-in C++ integer types, the only one used
@ -2735,9 +2705,7 @@ Tashana Landray
</p>
<p>The interaction between <code>auto</code> and C++11
brace-initialization can be confusing. (C++11 brace-initialization
isn't an approved feature, but this may become relevant when and
if it is permitted.) The declarations
brace-initialization can be confusing. The declarations
<CODE_SNIPPET>
auto x(3); // Note: parentheses.
auto y{3}; // Note: curly braces.
@ -2757,7 +2725,8 @@ Tashana Landray
<DECISION>
<p><code>auto</code> is permitted, for local variables only.
Do not use <code>auto</code> for file-scope or namespace-scope
variables, or for class members.</p>
variables, or for class members. Never assign a braced initializer list
to an <code>auto</code>-typed variable.</p>
<p>The <code>auto</code> keyword is also used in an unrelated
C++11 feature: it's part of the syntax for a new kind of
function declaration with a trailing return type. Function
@ -2766,6 +2735,88 @@ Tashana Landray
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Brace Initialization">
<SUMMARY>
You may use brace initialization.
</SUMMARY>
<BODY>
<p>In C++03, aggregate types (arrays and structs with no constructor) could
be initialized using braces.
<CODE_SNIPPET>
struct Point { int x; int y; };
Point p = {1, 2};
</CODE_SNIPPET></p>
<p>In C++11, this syntax has been expanded for use with all other datatypes.
The brace initialization form is called <i>braced-init-list</i>. Here are
a few examples of its use.
<CODE_SNIPPET>
// Vector takes lists of elements.
vector&lt;string&gt; v{"foo", "bar"};
// The same, except this form cannot be used if the initializer_list
// constructor is explicit. You may choose to use either form.
vector&lt;string&gt; v = {"foo", "bar"};
// Maps take lists of pairs. Nested braced-init-lists work.
map&lt;int, string&gt; m = {{1, "one"}, {2, "2"}};
// braced-init-lists can be implicitly converted to return types.
vector&lt;int&gt; test_function() {
return {1, 2, 3};
}
// Iterate over a braced-init-list.
for (int i : {-1, -2, -3}) {}
// Call a function using a braced-init-list.
void test_function2(vector&lt;int&gt; v) {}
test_function2({1, 2, 3});
</CODE_SNIPPET></p>
<p>User data types can also define constructors that take
<code>initializer_list</code>, which is automatically created from
<i>braced-init-list</i>:
<CODE_SNIPPET>
class MyType {
public:
// initializer_list is a reference to the underlying init list,
// so it can be passed by value.
MyType(initializer_list&lt;int&gt; init_list) {
for (int element : init_list) {}
}
};
MyType m{2, 3, 5, 7};
</CODE_SNIPPET></p>
<p>Finally, brace initialization can also call ordinary constructors of
data types that do not have <code>initializer_list</code> constructors.
<CODE_SNIPPET>
double d{1.23};
// Calls ordinary constructor as long as MyOtherType has no
// initializer_list constructor.
class MyOtherType {
public:
explicit MyOtherType(string);
MyOtherType(int, string);
};
MyOtherType m = {1, "b"};
// If the constructor is explicit, you can't use the "= {}" form.
MyOtherType m{"b"};
</CODE_SNIPPET></p>
<p>Never assign a <i>braced-init-list</i> to an auto local variable. In the
single element case, what this means can be confusing.
<BAD_CODE_SNIPPET>
auto d = {1.23}; // d is an initializer_list&lt;double&gt;
</BAD_CODE_SNIPPET>
<CODE_SNIPPET>
auto d = double{1.23}; // Good -- d is a double, not an initializer_list.
</CODE_SNIPPET>
</p>
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Boost">
<SUMMARY>
Use only approved libraries from the Boost library collection.
@ -2801,15 +2852,6 @@ Tashana Landray
<li> <a href="http://www.boost.org/libs/utility/compressed_pair.htm">
Compressed Pair</a> from <code>boost/compressed_pair.hpp</code>
</li>
<li> <a href="http://www.boost.org/libs/ptr_container/">
Pointer Container</a> from <code>boost/ptr_container</code> except
serialization and wrappers for containers not in the C++03
standard (<code>ptr_circular_buffer.hpp</code> and
<code>ptr_unordered*</code>)
</li>
<li> <a href="http://www.boost.org/libs/array/">
Array</a> from <code>boost/array.hpp</code>
</li>
<li> <a href="http://www.boost.org/libs/graph/">
The Boost Graph Library (BGL)</a> from <code>boost/graph</code>,
except serialization (<code>adj_list_serialize.hpp</code>) and
@ -2835,10 +2877,29 @@ Tashana Landray
<code>boost/polygon/voronoi_builder.hpp</code>,
<code>boost/polygon/voronoi_diagram.hpp</code>, and
<code>boost/polygon/voronoi_geometry_type.hpp</code></li>
<li> <a href="http://www.boost.org/libs/bimap/">
Bimap</a> from <code>boost/bimap</code>
</li>
</ul>
We are actively considering adding other Boost features to the list, so
this rule may be relaxed in the future.
this list may be expanded in the future.
</div>
<p>
The following libraries are permitted, but their use is discouraged
because they've been superseded by standard libraries in C++11:
<ul>
<li> <a href="http://www.boost.org/libs/array/">
Array</a> from <code>boost/array.hpp</code>: use
<a href="http://en.cppreference.com/w/cpp/container/array">
<code>std::array</code></a> instead.
</li>
<li> <a href="http://www.boost.org/libs/ptr_container/">
Pointer Container</a> from <code>boost/ptr_container</code>:
use containers of <a href="http://en.cppreference.com/w/cpp/memory/unique_ptr">
<code>std::unique_ptr</code></a> instead.
</li>
</ul>
</p>
</DECISION>
</BODY>
</STYLEPOINT>
@ -2910,14 +2971,21 @@ Tashana Landray
<li>All of the new STL algorithms in the
<a href="http://en.cppreference.com/w/cpp/algorithm">&lt;algorithm&gt;</a>
and <a href="http://en.cppreference.com/w/cpp/numeric">&lt;numeric&gt;</a>
headers, except for the versions of
<code>min</code>, <code>max</code>, and <code>minmax</code>
whose signatures contain initializer lists.</li>
headers.</li>
<li>Use of local types as template parameters.</li>
<li><code>nullptr</code> and <code>nullptr_t</code>.</li>
<li><code>static_assert</code>.</li>
<li>Everything in <a href="http://en.cppreference.com/w/cpp/header/array">&lt;array&gt;</a>.</li>
<li>Everything in <a href="http://en.cppreference.com/w/cpp/header/tuple">&lt;tuple&gt;</a>.
</li>
<li>Variadic templates.</li>
<li>Alias templates (the new <code>using</code> syntax) may be used.
Don't use an alias declaration where a typedef will work.</li>
<li><code>unique_ptr</code>, with restrictions (see
<a href="#unique_ptr">below</a>).</li>
<li>Brace initialization syntax. See
<a href="#Brace_Initialization">the full section</a> for more
detail.</li>
</ul>
Other features will be approved individually as appropriate.
Avoid writing code that is incompatible with C++11 (even though it
@ -2927,6 +2995,59 @@ Tashana Landray
</BODY>
</STYLEPOINT>
<STYLEPOINT title="unique_ptr">
<SUMMARY>
Use <code>unique_ptr</code> freely within classes and functions,
but do not use it to transfer ownership outside of a single .cc/.h
pair.
</SUMMARY>
<BODY>
<DEFINITION>
<code>unique_ptr</code> is a "smart" pointer type which expresses
exclusive ownership of the underlying object. It provides "move
semantics", which enables it to be stored in containers and used
as a function parameter or return value, even though it cannot be
copied (to preserve the unique-ownership property).
</DEFINITION>
<PROS>
<ul>
<li>It fully automates memory management of singly-owned pointers,
virtually eliminating the risk of leaking the underlying memory.</li>
<li>It provides a single, universal abstraction for singly-owned
pointers, replacing close to a dozen overlapping partial solutions
in common use at Google.</li>
<li>It can be passed into and returned from functions, providing
a self-documenting and compiler-enforced way to transfer ownership
between scopes.</li>
<li>Its performance is essentially identical to a plain pointer.</li>
</ul>
</PROS>
<CONS>
<ul>
<li>It cannot be used in code that requires C++03 compatibility.</li>
<li>Move semantics implicitly rely on rvalue references,
a new C++11 feature which is unfamiliar to many Googlers.</li>
<li>Google code currently uses a completely different set of
conventions for ownership transfer. Mixing <code>unique_ptr</code>
with the existing conventions could add complexity and create
confusion.</li>
<li>Best practices for using <code>unique_ptr</code> within Google
have not yet been established.</li>
</ul>
</CONS>
<DECISION>
<p>Use of <code>unique_ptr</code> as a class member or local variable
is encouraged, as is storing <code>unique_ptr</code> in containers
that support it. However, for the time being it is forbidden to use
<code>unique_ptr</code> as a function parameter or return value,
except for functions that are local to a single .cc/.h pair.</p>
<p>Note that the <code>std::move()</code> function, which is often
used to pass <code>unique_ptr</code> into function calls, remains
forbidden.</p>
</DECISION>
</BODY>
</STYLEPOINT>
</CATEGORY>
<CATEGORY title="Naming">
@ -2950,72 +3071,30 @@ Tashana Landray
<STYLEPOINT title="General Naming Rules">
<SUMMARY>
Function names, variable names, and filenames should be
descriptive; eschew abbreviation. Types and variables should be
nouns, while functions should be "command" verbs.
descriptive; eschew abbreviation.
</SUMMARY>
<BODY>
<SUBSECTION title="How to Name">
<p>
Give as descriptive a name as possible, within reason. Do
not worry about saving horizontal space as it is far more
important to make your code immediately understandable by a
new reader. Examples of well-chosen names:
new reader. Do not use abbreviations that are ambiguous or
unfamiliar to readers outside your project, and do not
abbreviate by deleting letters within a word.
</p>
<CODE_SNIPPET>
int num_errors; // Good.
int num_completed_connections; // Good.
</CODE_SNIPPET>
<p>
Poorly-chosen names use ambiguous abbreviations or arbitrary
characters that do not convey meaning:
</p>
<BAD_CODE_SNIPPET>
int n; // Bad - meaningless.
int nerr; // Bad - ambiguous abbreviation.
int n_comp_conns; // Bad - ambiguous abbreviation.
</BAD_CODE_SNIPPET>
<p>
Type and variable names should typically be nouns: e.g.,
<code>FileOpener</code>,
<code>num_errors</code>.
</p>
<p>
Function names should typically be imperative (that is they
should be commands): e.g., <code>OpenFile()</code>,
<code>set_num_errors()</code>. There is an exception for
accessors, which, described more completely in <a HREF="#Function_Names">Function Names</a>, should be named
the same as the variable they access.
</p>
</SUBSECTION>
<SUBSECTION title="Abbreviations">
<p>
Do not use abbreviations unless they are extremely well
known outside your project. For example:
</p>
<CODE_SNIPPET>
// Good
// These show proper names with no abbreviations.
int price_count_reader; // No abbreviation.
int num_errors; // "num" is a widespread convention.
int num_dns_connections; // Most people know what "DNS" stands for.
int price_count_reader; // OK, price count. Makes sense.
</CODE_SNIPPET>
<BAD_CODE_SNIPPET>
// Bad!
// Abbreviations can be confusing or ambiguous outside a small group.
int n; // Meaningless.
int nerr; // Ambiguous abbreviation.
int n_comp_conns; // Ambiguous abbreviation.
int wgc_connections; // Only your group knows what this stands for.
int pc_reader; // Lots of things can be abbreviated "pc".
int cstmr_id; // Deletes internal letters.
</BAD_CODE_SNIPPET>
<p>
Never abbreviate by leaving out letters:
</p>
<CODE_SNIPPET>
int error_count; // Good.
</CODE_SNIPPET>
<BAD_CODE_SNIPPET>
int error_cnt; // Bad.
</BAD_CODE_SNIPPET>
</SUBSECTION>
</BODY>
</STYLEPOINT>
@ -3532,9 +3611,9 @@ Tashana Landray
<SUBSECTION title="Function Definitions">
<p>
Each function definition should have a comment describing
what the function does if there's anything tricky about how it does
its job. For example, in the definition comment you might
If there is anything tricky about how a function does its
job, the function definition should have an explanatory
comment. For example, in the definition comment you might
describe any coding tricks you use, give an overview of the
steps you go through, or explain why you chose to implement
the function in the way you did rather than using a viable
@ -3640,6 +3719,7 @@ Tashana Landray
// thus the comment lines up with the following comments and code.
DoSomethingElse(); // Two spaces before line comments normally.
}
DoSomething(); /* For trailing block comments, one space is fine. */
</CODE_SNIPPET>
</SUBSECTION>
<SUBSECTION title="nullptr/NULL, true/false, 1, 2, 3...">
@ -4067,6 +4147,49 @@ Tashana Landray
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Braced Initializer Lists">
<SUMMARY>
On one line if it fits, otherwise wrap at the open brace.
</SUMMARY>
<BODY>
<p>
Put everything on one line where possible. If everything can't fit
on one line, the open brace should be the last character on its line,
and the close brace should be the first character on its line.
</p>
<CODE_SNIPPET>
// Examples of braced init list on a single line.
return {foo, bar};
functioncall({foo, bar});
pair&lt;int, int&gt; p{foo, bar};
// When you have to wrap.
MyType m = {
superlongvariablename1,
superlongvariablename2,
{short, interior, list},
{
interiorwrappinglist,
interiorwrappinglist2
}
};
// Wrapping inside a function call.
function({
wrapped, long,
list, here
});
// If the variable names are really long.
function(
{
wrapped,
list
});
</CODE_SNIPPET>
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Conditionals">
<SUMMARY>
Prefer no spaces inside parentheses. The <code>else</code>
@ -4354,18 +4477,39 @@ Tashana Landray
<STYLEPOINT title="Variable and Array Initialization">
<SUMMARY>
Your choice of <code>=</code> or <code>()</code>.
Your choice of <code>=</code>, <code>()</code>, or <code>{}</code>.
</SUMMARY>
<BODY>
<p>
You may choose between <code>=</code> and <code>()</code>; the
following are all correct:
You may choose between <code>=</code>, <code>()</code>, and
<code>{}</code>; the following are all correct:
</p>
<CODE_SNIPPET>
int x = 3;
int x(3);
string name("Some Name");
int x{3};
string name = "Some Name";
string name("Some Name");
string name{"Some Name"};
</CODE_SNIPPET>
<p>
Be careful when using the <code>{}</code> on a type that takes an
<code>initializer_list</code> in one of its constructors. The
<code>{}</code> syntax prefers the <code>initializer_list</code>
constructor whenever possible. To get the non-
<code>initializer_list</code> constructor, use <code>()</code>.
</p>
<CODE_SNIPPET>
vector&lt;int&gt; v(100, 1); // A vector of 100 1s.
vector&lt;int&gt; v{100, 1}; // A vector of 100, 1.
</CODE_SNIPPET>
<p>
Also, the brace form prevents narrowing of integral types. This can
prevent some types of programming errors.
</p>
<CODE_SNIPPET>
int pi(3.14); // OK -- pi == 3.
int pi{3.14}; // Compile error: narrowing conversion.
</CODE_SNIPPET>
</BODY>
</STYLEPOINT>
@ -4547,7 +4691,7 @@ Tashana Landray
void f(bool b) { // Open braces should always have a space before them.
...
int i = 0; // Semicolons usually have no space before them.
int x[] = { 0 }; // Spaces inside braces for array initialization are
int x[] = { 0 }; // Spaces inside braces for braced-init-list are
int x[] = {0}; // optional. If you use them, put them on both sides!
// Spaces around the colon in inheritance and initializer lists.
class Foo : public Bar {
@ -4803,7 +4947,7 @@ Tashana Landray
<HR/>
<p align="right">
Revision 3.245
Revision 3.260
</p>

View File

@ -3,7 +3,7 @@
<GUIDE title="Google HTML/CSS Style Guide">
<p class="revision">
Revision 2.21
Revision 2.23
</p>
<OVERVIEW>
@ -1086,6 +1086,8 @@
</STYLEPOINT>
</CATEGORY>
<PARTING_WORDS>
<p>
<em>Be consistent.</em>
@ -1109,7 +1111,7 @@
</PARTING_WORDS>
<p align="right">
Revision 2.21
Revision 2.23
</p>
</GUIDE>

View File

@ -3,7 +3,7 @@
<GUIDE title="Google JavaScript Style Guide">
<p class="revision">
Revision 2.72
Revision 2.82
</p>
<address>
@ -96,8 +96,8 @@
<code>boolean</code>) are constant values.</p>
<p><code>Objects</code>'
immutabilty is more subjective — objects should be
considered immutable only if they do not demonstrate obeserverable
immutability is more subjective — objects should be
considered immutable only if they do not demonstrate observable
state change. This is not enforced by the compiler.</p>
@ -112,7 +112,8 @@
lack of support in Internet Explorer).</p>
<p>A <code>@const</code> annotation on a method additionally
implies that the method should not be overriden in subclasses.</p>
implies that the method should not be overridden in subclasses.
</p>
</SUBSECTION>
<SUBSECTION title="Examples">
@ -209,12 +210,12 @@
</ol>
</SUBSECTION>
<SUBSECTION title="Why?">
<p>JavaScript requires statements to end with a semicolon,
except when it thinks it can safely infer their existence. In each
of these examples, a function declaration or object or array literal
is used inside a statement. The closing brackets are not enough to
signal the end of the statement. Javascript never ends a statement
if the next token is an infix or bracket operator.</p>
<p>JavaScript requires statements to end with a semicolon, except when
it thinks it can safely infer their existence. In each of these
examples, a function declaration or object or array literal is used
inside a statement. The closing brackets are not enough to signal
the end of the statement. Javascript never ends a statement if the
next token is an infix or bracket operator.</p>
<p>This has really surprised people, so make sure your assignments end
with semicolons.</p>
</SUBSECTION>
@ -1147,7 +1148,7 @@
declarations. Instead, continue from the 0 column.</p>
<p>Only alias names that will not be re-assigned to another object
(e.g., most constructors, enums, and namespaces). Do not do
this:</p>
this (see below for how to alias a constructor):</p>
<BAD_CODE_SNIPPET>
goog.scope(function() {
@ -1161,7 +1162,7 @@
are aliasing.</p>
<CODE_SNIPPET>
goog.provide('my.module');
goog.provide('my.module.SomeType');
goog.require('goog.dom');
goog.require('goog.ui.Button');
@ -1169,9 +1170,16 @@
goog.scope(function() {
var Button = goog.ui.Button;
var dom = goog.dom;
var module = my.module;
module.button = new Button(dom.$('my-button'));
// Alias new types <b>after</b> the constructor declaration.
my.module.SomeType = function() { ... };
var SomeType = my.module.SomeType;
// Declare methods on the prototype as usual:
SomeType.prototype.findButton = function() {
// Button as aliased above.
this.button = new Button(dom.getElement('my-button'));
};
...
}); // goog.scope
</CODE_SNIPPET>
@ -1224,10 +1232,12 @@
</CODE_SNIPPET>
</SUBSECTION>
<SUBSECTION title="Binary and Ternary Operators">
<p>Always put the operator on the preceding line, so that you don't
have to think about implicit semi-colon insertion issues. Otherwise,
<p>Always put the operator on the preceding line. Otherwise,
line breaks and indentation follow the same rules as in other
Google style guides.</p>
Google style guides. This operator placement was initially agreed
upon out of concerns about automatic semicolon insertion. In fact,
semicolon insertion cannot happen before a binary operator, but new
code should stick to this style for consistency.</p>
<CODE_SNIPPET>
var x = a ? b : c; // All on one line if it will fit.
@ -1325,7 +1335,7 @@
<p>Note that these semantics differ from those of C++ and Java, in that
they grant private and protected access to all code in the same file,
not just in the same class or class hierarchy. Also, unlike in C++,
private properties cannot be overriden by a subclass.
private properties cannot be overridden by a subclass.
</p>
<CODE_SNIPPET>
// File 1.
@ -1892,12 +1902,12 @@
</CODE_SNIPPET>
</td>
<td>
An Object in which the keys are numbers and the values
are strings. <p/>Note that in JavaScript, the keys are always
An Object in which the keys are numbers and the values are
strings. <p/>Note that in JavaScript, the keys are always
implicitly converted to strings, so
<code>obj['1'] == obj[1]</code>.
So the key wil always be a string in for...in loops. But the
compiler will verify the type if the key when indexing into
So the key will always be a string in for...in loops. But the
compiler will verify the type of the key when indexing into
the object.
</td>
</tr>
@ -2205,15 +2215,16 @@
<p>All files, classes, methods and properties should be documented with
<a href="http://code.google.com/p/jsdoc-toolkit/">JSDoc</a>
comments with the appropriate <a href="#JSDoc_Tag_Reference">tags</a>
and <a href="#JsTypes">types</a>. Textual descriptions for methods,
method parameters and method return values should be included
unless obvious from the method or parameter name.
and <a href="#JsTypes">types</a>. Textual descriptions for properties,
methods, method parameters and method return values should be included
unless obvious from the property, method, or parameter name.
</p>
<p>Inline comments should be of the <code>//</code> variety.</p>
<p>Avoid sentence fragments. Start sentences with a properly
capitalized word, and end them with punctuation.</p>
<p>Complete sentences are recommended but not required.
Complete sentences should use appropriate capitalization
and punctuation.</p>
<SUBSECTION title="Comment Syntax">
<p>The JSDoc syntax is based on
@ -2288,7 +2299,7 @@
<p>It'll come out like this:</p>
<BAD_CODE_SNIPPET>
Computes weight based on three factors: items sent items received items received
Computes weight based on three factors: items sent items received last timestamp
</BAD_CODE_SNIPPET>
<p>Instead, do this:</p>
@ -2313,10 +2324,13 @@
<p>
A <a href="copyright.html">copyright notice</a> and author information are optional.
The top level comment is designed
to orient readers unfamiliar with the code to what is in this file.
It should provide a description of the file's contents and any
dependencies or compatibility information. As an example:</p>
File overviews are generally recommended whenever a file consists of
more than a single class definition. The top level comment is
designed to orient readers unfamiliar with the code to what is in
this file. If present, it should provide a description of the
file's contents and any dependencies or compatibility information.
As an example:
</p>
<CODE_SNIPPET>
/**
@ -2359,7 +2373,7 @@
* Operates on an instance of MyClass and returns something.
* @param {project.MyClass} obj Instance of MyClass which leads to a long
* comment that needs to be wrapped to two lines.
* @return {boolean} Whether something occured.
* @return {boolean} Whether something occurred.
*/
function PR_someMethod(obj) {
// ...
@ -2461,7 +2475,7 @@
* @const
*/
mynamespace.Request.prototype.initialize = function() {
// This method cannot be overriden in a subclass.
// This method cannot be overridden in a subclass.
}
</CODE_SNIPPET>
</td>
@ -2806,7 +2820,9 @@
Polygon.prototype.getSides = function() {};
</CODE_SNIPPET>
</td>
<td>Used to indicate that the function defines an inteface.</td>
<td>
Used to indicate that the function defines an interface.
</td>
</tr>
<tr>
@ -3204,10 +3220,10 @@
</CODE_SNIPPET>
</td>
<td>
Identifies the <a href="#JsTypes">type</a>
of a variable, property, or expression.
Curly braces are not required around most types, but some
projects mandate them for all types, for consistency.
Identifies the <a href="#JsTypes">type</a> of a variable,
property, or expression. Curly braces are not required around
most types, but some projects mandate them for all types, for
consistency.
</td>
</tr>
@ -3237,6 +3253,8 @@
</tbody>
</table>
<p>
You may also see other types of JSDoc annotations in third-party
code. These annotations appear in the
@ -3539,7 +3557,7 @@
</PARTING_WORDS>
<p align="right">
Revision 2.72
Revision 2.82
</p>

View File

@ -5,7 +5,7 @@
<p align="right">
Revision 1.18
Revision 1.20
</p>
@ -313,10 +313,6 @@ Robert Brown
Ideally, there should be no way to look at lines of code
and recognize it as "Fred's code" by its style.
</li>
<li>
Don't be "clever" —
do the simplest thing that could possibly work properly.
</li>
<li>
Be precise.
</li>
@ -454,16 +450,6 @@ Robert Brown
</li>
</ul>
<p>
Note that if you have a "clever" implementation trick,
and your trick really is clever,
then you must definitely not include it in business specific code;
but it may have its place in an open-source library used by the code.
If your idea is not general purpose enough to have any users
beyond your regular business users,
then it is definitely either not clever enough or way too clever,
and in either case does not belong in the code.
</p>
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Open-Sourcing Code">
@ -575,10 +561,10 @@ Robert Brown
you should choose the shorter spelling.
</p>
<p>
You must avoid using abbreviations for words,
unless it's a word that is used very frequently,
in which case you must use
the <em>same</em> abbreviation <em>consistently</em>.
You must use only common and domain-specific abbreviations, and
must be consistent with these abbreviations. You may abbreviate
lexical variables of limited scope in order to avoid overly-long
symbol names.
</p>
</SUMMARY>
<BODY>
@ -712,37 +698,19 @@ Robert Brown
<STYLEPOINT title="File Header">
<SUMMARY>
<p>
You must include maintainership and other important information
at the top of each source file.
You should include a description at the top of each source file.
</p>
<p>
You should not include a copyright statement in source files.
You should include neither authorship nor copyright information in a source file.
</p>
</SUMMARY>
<BODY>
<p>
Every source file may begin with a one-line description of the file.
Every source file should begin with a brief description
of the contents of that file.
</p>
<p>
After that optional description,
every source file may prominently include a statement
about who originally wrote the code,
made major changes, and/or is the current owner/maintainer.
This makes it easier for hackers to locate
whom to ask questions about the code,
or to identify that no one is left to reply to such inquiries.
However, consider that the information
is not very helpful if it is not maintained;
unless it brings information
that cannot be easily extracted from source control,
it is better skipped.
</p>
<p>
After that optional statement, every file should follow with
a brief explanation of what the file contains.
</p>
<p>
After that explanation, every file should start the code itself with an
After that description, every file should start the code itself with an
<code>(in-package :<em>package-name</em>)</code> form.
</p>
<p>
@ -759,6 +727,11 @@ Robert Brown
(in-package #:varint)
(declaim #.*optimize-default*)
</CODE_SNIPPET>
<p>
You should not include authorship information at the top of a file,
that information is available from version control and
<code>OWNERS</code>.
</p>
<p>
You should not include copyright information in individual source code files.
An exception is made for files meant to be disseminated as standalone.
@ -805,9 +778,10 @@ Robert Brown
what each of the separated parts of the function does.
</p>
<p>
Every top-level form
should be fewer than 61 lines long,
including comments but excluding the documentation string.
You should strive to keep top-level forms,
including comments but excluding the documentation string, of
appropriate length; preferrably short. Forms extending beyond a
single page should be rare and their use should be justfied.
This applies to each of the forms in an <code>eval-when</code>,
rather than to the <code>eval-when</code> itself.
Additionally, <code>defpackage</code> forms may be longer,
@ -1114,66 +1088,16 @@ Robert Brown
</STYLEPOINT>
<STYLEPOINT title="Attention Required">
<SUMMARY>
You must follow the convention of using <code>---</code>
for comments requiring special attention,
including unobvious tricks, TODO items, questions, breakage, danger.
You must follow the convention of using TODO comments
for code requiring special attention.
For code using unobvious forms, you must include a comment.
</SUMMARY>
<BODY>
<ul>
<li>
<code>;--- </code> prefixes a cautionary comment,
e.g. explaining why the code in question is particularly
tricky, delicate, or non-obvious.
</li>
<li>
<code>;---??? </code> prefixes a serious question
which needs to be resolved soon,
by fixing either the code or its documentation.
</li>
<li>
<code>;---!!! </code> identifies code which is broken,
but which for some reason you cannot fix at this time.
You should not use this often for new code.
</li>
<li>
<code>;---*** </code> identifies active <em>DANGER</em>,
for instance where important functionality is stubbed out,
or a large design issue remains unresolved.
Anything so marked must be fixed
before code is rolled into production.
</li>
</ul>
<p>
You must sign and date
any of the above "requiring further attention" comments
(but not mere cautionary explanations).
You must use the
<a HREF="http://www.w3.org/TR/NOTE-datetime">YYYY-MM-DD</a>
format for dates to make automated processing of such dates easier.
</p>
<p>
This strategy ensures that grepping for <code>;---</code>
will always yield all the comments that require caution,
as well as whom to talk to about each one.
</p>
<p>
Only use <code>;---</code> on the first line of such a comment.
Other lines should use spaces to align vertically.
This way, grepping will also yield a count of the number of issues.
</p>
<p>
You should insert a space after this comment prefix.
</p>
<p>
You may use these with multiple-semicolon comments as well.
</p>
<p>
Some people like to use words like <code>FIXME</code> or <code>TODO</code>.
You may use these, but they must be preceded with <code>---</code>.
</p>
<p>
Use TODO comments when the code is known to be incomplete
and you want to indicate what work remains to be done.
For comments requiring special attention, such as
incomplete code, todo items, questions, breakage, and danger,
include a TODO comment indicating the type of problem,
its nature, and any notes on how it may be addressed.
</p>
<p>
The comments begin with <code>TODO</code> in all capital letters,
@ -1201,6 +1125,10 @@ Robert Brown
<CODE_SNIPPET>
;;--- TODO(brown): Remove this code after release 1.7 or before November, 2012.
</CODE_SNIPPET>
<p>
For code that uses unobvious forms to accomplish a task, you must include a comment
stating the purpose of the form and the task it accomplishes.
</p>
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Domain-Specific Languages">
@ -1241,7 +1169,7 @@ Robert Brown
<STYLEPOINT title="Symbol guidelines">
<SUMMARY>
You should use lower case.
You should not abbreviate.
You should follow the rules for <a href="#Spelling">Spelling and Abbreviations</a>
You should follow punctuation conventions.
</SUMMARY>
<BODY>
@ -1274,17 +1202,8 @@ Robert Brown
unless you have a well-documented overarching reason to,
and permission from other hackers who review your proposal.
</p>
<p>
Generally, you should do not abbreviate words.
You must avoid using abbreviations for words,
unless it's a word that is used very frequently,
in which case you must use
the <em>same</em> abbreviation <em>consistently</em>.
Abbreviations may also be used sparingly to avoid overly-long symbol names;
it's easy to run into 100-column limit when there are very long names!
You must especially avoid inconsistent abbreviations in exported names.
For lexical variables of limited scope, abbreviations are fine.
</p>
See the section on <a href="#Spelling">Spelling and Abbreviations</a>
for guidelines on using abbreviations.
<p>
</p>
<BAD_CODE_SNIPPET>
@ -1402,12 +1321,12 @@ Robert Brown
</STYLEPOINT>
<STYLEPOINT title="Predicate names">
<SUMMARY>
Names of predicate functions end with a <code>"P"</code>.
Names of predicate functions and variables end with a <code>"P"</code>.
</SUMMARY>
<BODY>
<p>
You should name boolean-valued functions with a trailing
<code>"P"</code> or <code>"-P"</code>,
You should name boolean-valued functions and variables with a
trailing <code>"P"</code> or <code>"-P"</code>,
to indicate they are predicates.
Generally, you should use
<code>"P"</code> when the rest of the function name is one word
@ -2248,7 +2167,7 @@ Robert Brown
without a consensus among the developers of your system.
Reader macros must not leak out of the system that uses them
to clients of that system or other systems used in the same project.
You must software such as
You must use software such as
<code>cl-syntax</code> or <code>named-readtables</code>
to control how reader macros are used.
This clients who desire it may use the same reader macros as you do.
@ -2261,6 +2180,8 @@ Robert Brown
you should name the parameter with the suffix <code>-form</code>.
This convention helps make it clearer to the macro's user
which parameters are Lisp forms to be evaluated, and which are not.
The common names <code>body</code> and <code>end</code> are
exceptions to this rule.
</p>
<p>
You should follow the so-called <code>CALL-WITH</code> style when it applies.
@ -2899,10 +2820,9 @@ Robert Brown
<STYLEPOINT title="Defining Functions">
<SUMMARY>
You should make proper use of
<code>&amp;OPTIONAL</code>,
<code>&amp;KEY</code>,
and
<code>&amp;AUX</code> arguments.
<code>&amp;OPTIONAL</code> and
<code>&amp;KEY</code> arguments.
You should not use <code>&amp;AUX</code> arguments.
</SUMMARY>
<BODY>
<p>
@ -2932,9 +2852,7 @@ Robert Brown
and pass around a plist as a <code>&amp;REST</code> argument.
</p>
<p>
You should avoid using <code>&amp;AUX</code> arguments,
except in very short helper functions
where they allow you to eschew a <code>LET</code>.
You should avoid using <code>&amp;AUX</code> arguments.
</p>
<p>
You should avoid having both <code>&amp;OPTIONAL</code>
@ -3890,7 +3808,7 @@ Robert Brown
</small>
<p align="right">
Revision 1.18
Revision 1.20
</p>

View File

@ -4,7 +4,7 @@
<p align="right">
Revision 2.52
Revision 2.56
</p>
@ -109,8 +109,8 @@ Revision 2.52
Note that this guide is not an Objective-C tutorial. We assume that the
reader is familiar with the language. If you are new to Objective-C or
need a refresher, please read
<a href="http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/index.html">
The Objective-C Programming Language
<a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html">
Programming with Objective-C
</a>.
</p>
</CATEGORY>
@ -366,6 +366,10 @@ Revision 2.52
evenLongerKeyword:arg3
error:arg4];
</CODE_SNIPPET>
<p>
Invocations containing inlined <a href="#Blocks">blocks</a> may have
their segments left-aligned at a four space indent.
</p>
</BODY>
</STYLEPOINT>
@ -467,6 +471,11 @@ Revision 2.52
space between the <code>^(</code> characters, but there is one space
between the <code>) {</code> characters.
</li>
<li>
Invocations containing inlined blocks may have their segments
left-aligned at a four-space indent. This helps when invocations
contain multiple inlined blocks.
</li>
<li>
Two space indents inside blocks are also allowed, but should only
be used when it's consistent with the rest of the project's code.
@ -521,10 +530,102 @@ Revision 2.52
// ...
};
[_operationQueue addOperationWithBlock:largeBlock];
// An example with multiple inlined blocks in one invocation.
[myObject doSomethingWith:arg1
firstBlock:^(Foo *a) {
// ...
}
secondBlock:^(Bar *b) {
// ...
}];
</CODE_SNIPPET>
</BODY>
</STYLEPOINT>
<STYLEPOINT title="Container Literals">
<SUMMARY>
For projects using Xcode 4.4 or later and clang, the use of container
(array and dictionary) literals is encouraged. If split across multiple
lines, the contents should be indented two spaces.
</SUMMARY>
<BODY>
<p>
If the collection fits on one line, put a single space after the opening
and before the closing brackets.
</p>
<CODE_SNIPPET>
NSArray* array = @[ [foo description], @"Another String", [bar description] ];
NSDictionary* dict = @{ NSForegroundColorAttributeName : [NSColor redColor] };
</CODE_SNIPPET>
<p>
Not:
</p>
<BAD_CODE_SNIPPET>
NSArray* array = @[[foo description], [bar description]];
NSDictionary* dict = @{NSForegroundColorAttributeName: [NSColor redColor]};
</BAD_CODE_SNIPPET>
<p>
If the collection spans more than a single line, place the opening
bracket on the same line as the declaration, indent the body by two
spaces, and place the closing bracket on a new line that is indented to
the same level as the opening bracket.
</p>
<CODE_SNIPPET>
NSArray* array = @[
@"This",
@"is",
@"an",
@"array"
];
NSDictionary* dictionary = @{
NSFontAttributeName : [NSFont fontWithName:@"Helvetica-Bold" size:12],
NSForegroundColorAttributeName : fontColor
};
</CODE_SNIPPET>
<p>
For dictionary literals, there should be one space before the colon and
at least one space after it (to optionally align the values).
</p>
<CODE_SNIPPET>
NSDictionary* option1 = @{
NSFontAttributeName : [NSFont fontWithName:@"Helvetica-Bold" size:12],
NSForegroundColorAttributeName : fontColor
};
NSDictionary* option2 = @{
NSFontAttributeName : [NSFont fontWithName:@"Arial" size:12],
NSForegroundColorAttributeName : fontColor
};
</CODE_SNIPPET>
<p>
The following are all incorrect:
</p>
<BAD_CODE_SNIPPET>
// There should be a space before the colon.
NSDictionary* wrong = @{
AKey: @"b",
BLongerKey: @"c",
};
// The items should each be on a new line, or the entire expression
// should fit on one line.
NSDictionary* alsoWrong= @{ AKey : @"a",
BLongerKey : @"b" };
// There should be no variable space before the colon, only after.
NSDictionary* stillWrong = @{
AKey : @"b",
BLongerKey : @"c",
};
</BAD_CODE_SNIPPET>
</BODY>
</STYLEPOINT>
</CATEGORY>
<CATEGORY title="Naming">
@ -794,8 +895,20 @@ Revision 2.52
<p>
Constant names (#defines, enums, const local variables, etc.) should
start with a lowercase <var>k</var> and then use mixed case to
delimit words, i.e. <var>kInvalidHandle</var>,
<var>kWritePerm</var>.
delimit words. For example:
</p>
<CODE_SNIPPET>
const int kNumberOfFiles = 12;
NSString *const kUserKey = @"kUserKey";
enum DisplayTinge {
kDisplayTingeGreen = 1,
kDisplayTingeBlue = 2
};
</CODE_SNIPPET>
<p>
Because Objective-C does not provide namespacing, constants with global
scope should have an appropriate prefix to minimize the chance of name
collision, typically like <var>kClassNameFoo</var>.
</p>
</SUBSECTION>
</BODY>
@ -1838,7 +1951,7 @@ Revision 2.52
<HR/>
<p align="right">
Revision 2.52
Revision 2.56
</p>

View File

@ -136,7 +136,7 @@
<H1>Google Python Style Guide</H1>
<p align="right">
Revision 2.48
Revision 2.54
</p>
<address>
@ -775,7 +775,7 @@ from sound.effects import echo
</P>
<P class="">
<SPAN class="stylepoint_section">Decision: </SPAN>
Okay to use with the following caveats:
Okay to use with the following caveat:
<p>
Do not use mutable objects as default values in the function or method
definition.
@ -785,17 +785,6 @@ from sound.effects import echo
<span class="external"> </span>b = []</PRE></DIV>
<DIV class=""><PRE class="badcode">No: <span class="external"></span>def foo(a, b=[]):
<span class="external"> </span>...</PRE></DIV>
<p>
Calling code must use named values for arguments with a default value.
This helps document the code somewhat and helps prevent and detect
interface breakage when more arguments are added.
</p>
<DIV class=""><PRE>
<span class="external"></span>def foo(a, b=1):
<span class="external"> </span>...</PRE></DIV>
<DIV class=""><PRE>Yes: <span class="external"></span>foo(1)
<span class="external"></span>foo(1, b=2)</PRE></DIV>
<DIV class=""><PRE class="badcode">No: <span class="external"></span>foo(1, 2)</PRE></DIV>
</P>
</DIV></DIV>
</DIV>
@ -1250,6 +1239,7 @@ from sound.effects import echo
<ul>
<li>Long import statements.</li>
<li>URLs in comments.</li>
</ul>
</p>
@ -1476,8 +1466,11 @@ from sound.effects import echo
</A></SPAN><SPAN class="showhide_button" onclick="javascript:ShowHideByName('Shebang_Line')" name="Shebang_Line__button" id="Shebang_Line__button"></SPAN>
<DIV style="display:inline;" class="">
Most <code>.py</code> files do not need to start with a
<code>#!</code> line. Start the main file of a program with
<code>#!/usr/bin/python</code>.
<code>#!</code> line. Start the main file of a
program with
<code>#!/usr/bin/python</code> with an optional single digit
<code>2</code> or <code>3</code> suffix per
<a href="http://www.python.org/dev/peps/pep-0394/">PEP-394</a>.
</DIV>
<DIV class=""><DIV class="stylepoint_body" name="Shebang_Line__body" id="Shebang_Line__body" style="display: none">
@ -1754,16 +1747,20 @@ from sound.effects import echo
link
</A></SPAN><SPAN class="showhide_button" onclick="javascript:ShowHideByName('Strings')" name="Strings__button" id="Strings__button"></SPAN>
<DIV style="display:inline;" class="">
Use the <code>%</code> operator for formatting strings,
even when the parameters are all strings. Use your best judgement
to decide between <code>+</code> and <code>%</code> though.
Use the <code>format</code> method or the <code>%</code> operator for
formatting strings, even when the parameters are all strings. Use your
best judgement to decide between <code>+</code> and <code>%</code>
(or <code>format</code>) though.
</DIV>
<DIV class=""><DIV class="stylepoint_body" name="Strings__body" id="Strings__body" style="display: none">
<DIV class=""><PRE>Yes: <span class="external"></span>x = a + b
<span class="external"></span>x = '%s, %s!' % (imperative, expletive)
<span class="external"></span>x = 'name: %s; score: %d' % (name, n)</PRE></DIV>
<span class="external"></span>x = '{}, {}!'.format(imperative, expletive)
<span class="external"></span>x = 'name: %s; score: %d' % (name, n)
<span class="external"></span>x = 'name: {}; score: {}'.format(name, n)</PRE></DIV>
<DIV class=""><PRE class="badcode">No: <span class="external"></span>x = '%s%s' % (a, b) # use + in this case
<span class="external"></span>x = '{}{}'.format(a, b) # use + in this case
<span class="external"></span>x = imperative + ', ' + expletive + '!'
<span class="external"></span>x = 'name: ' + name + '; score: ' + str(n)</PRE></DIV>
@ -1771,9 +1768,9 @@ from sound.effects import echo
Avoid using the <code>+</code> and <code>+=</code> operators to
accumulate a string within a loop. Since strings are immutable, this
creates unnecessary temporary objects and results in quadratic rather
than linear running time. Instead, add each substring to a list and
<code>''.join</code> the list after the loop terminates (or, write each
substring to a <code>cStringIO.StringIO</code> buffer).
than linear running time. Instead, add each substring to a list
and <code>''.join</code> the list after the loop terminates (or, write
each substring to a <code>io.BytesIO</code> buffer).
</p>
<DIV class=""><PRE>Yes: <span class="external"></span>items = ['&lt;table&gt;']
@ -2236,7 +2233,7 @@ Don'<span class="external"></span>t do this.
<p align="right">
Revision 2.48
Revision 2.54
</p>