summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordtseng@chromium.org <dtseng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-15 08:04:00 +0000
committerdtseng@chromium.org <dtseng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-15 08:04:00 +0000
commitfad5da26587e70751a16b3495ac2a3e136e97f04 (patch)
tree62bd4f618fbbe79f01e5fa96004b95f29500ea2d
parent29bf8f4e29de59621652339a1a39bbf7bfb0d6b1 (diff)
downloadchromium_src-fad5da26587e70751a16b3495ac2a3e136e97f04.zip
chromium_src-fad5da26587e70751a16b3495ac2a3e136e97f04.tar.gz
chromium_src-fad5da26587e70751a16b3495ac2a3e136e97f04.tar.bz2
Convert snakecase enum names to camelcase when stringified.
This cl adds a new attribute to the namespace node "camel_case_enum_to_string". This addresses the need for: - native enums to use snake case (e.g. LOAD_COMPLETE) - stringified values (used in js) to be camel cased (e.g. loadComplete). BUG=309681 Review URL: https://codereview.chromium.org/273323002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@270623 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/renderer/resources/extensions/automation/automation_tree.js2
-rw-r--r--chrome/renderer/resources/extensions/automation_custom_bindings.js2
-rw-r--r--chrome/test/data/extensions/api_test/automation/tests/desktop/desktop.js2
-rw-r--r--chrome/test/data/extensions/api_test/automation/tests/tabs/events.js8
-rw-r--r--chrome/test/data/extensions/api_test/automation/tests/tabs/location.js2
-rw-r--r--chrome/test/data/extensions/api_test/automation/tests/tabs/sanity_check.js18
-rw-r--r--tools/json_schema_compiler/cc_generator.py5
-rw-r--r--tools/json_schema_compiler/cpp_type_generator.py5
-rw-r--r--tools/json_schema_compiler/idl_schema.py12
-rw-r--r--tools/json_schema_compiler/model.py18
-rwxr-xr-xtools/json_schema_compiler/model_test.py15
-rw-r--r--ui/accessibility/ax_enums.idl164
-rw-r--r--ui/accessibility/ax_tree_unittest.cc8
13 files changed, 149 insertions, 112 deletions
diff --git a/chrome/renderer/resources/extensions/automation/automation_tree.js b/chrome/renderer/resources/extensions/automation/automation_tree.js
index 43d5350..e7afd4b 100644
--- a/chrome/renderer/resources/extensions/automation/automation_tree.js
+++ b/chrome/renderer/resources/extensions/automation/automation_tree.js
@@ -136,7 +136,7 @@ AutomationTreeImpl.prototype = {
}
}
- if (nodeData.role == 'root_web_area' || nodeData.role == 'desktop') {
+ if (nodeData.role == 'rootWebArea' || nodeData.role == 'desktop') {
this.root = node;
didUpdateRoot = true;
}
diff --git a/chrome/renderer/resources/extensions/automation_custom_bindings.js b/chrome/renderer/resources/extensions/automation_custom_bindings.js
index dd783b27..9935852 100644
--- a/chrome/renderer/resources/extensions/automation_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/automation_custom_bindings.js
@@ -85,7 +85,7 @@ automationInternal.onAccessibilityEvent.addListener(function(data) {
}
privates(targetTree).impl.update(data);
var eventType = data.eventType;
- if (eventType == 'load_complete' || eventType == 'layout_complete') {
+ if (eventType == 'loadComplete' || eventType == 'layoutComplete') {
// If the tree wasn't available when getTree() was called, the callback will
// have been cached in idToCallback, so call and delete it now that we
// have the complete tree.
diff --git a/chrome/test/data/extensions/api_test/automation/tests/desktop/desktop.js b/chrome/test/data/extensions/api_test/automation/tests/desktop/desktop.js
index fb39309..b260063 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/desktop/desktop.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/desktop/desktop.js
@@ -5,7 +5,7 @@
var allTests = [
function testGetDesktop() {
chrome.automation.getDesktop(function(tree) {
- tree.addEventListener('load_complete', function(e) {
+ tree.addEventListener('loadComplete', function(e) {
assertEq('desktop', tree.root.role);
assertEq('window', tree.root.firstChild().role);
chrome.test.succeed();
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs/events.js b/chrome/test/data/extensions/api_test/automation/tests/tabs/events.js
index 2dddd62..4074dcc 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs/events.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs/events.js
@@ -5,7 +5,7 @@
var allTests = [
function testEventListenerTarget() {
var cancelButton = tree.root.firstChild().children()[2];
- assertEq('Cancel', cancelButton.attributes['ax_attr_name']);
+ assertEq('Cancel', cancelButton.attributes['name']);
cancelButton.addEventListener('focus', function onFocusTarget(event) {
window.setTimeout(function() {
cancelButton.removeEventListener('focus', onFocusTarget);
@@ -16,7 +16,7 @@ var allTests = [
},
function testEventListenerBubble() {
var cancelButton = tree.root.firstChild().children()[2];
- assertEq('Cancel', cancelButton.attributes['ax_attr_name']);
+ assertEq('Cancel', cancelButton.attributes['name']);
var cancelButtonGotEvent = false;
cancelButton.addEventListener('focus', function onFocusBubble(event) {
cancelButtonGotEvent = true;
@@ -33,7 +33,7 @@ var allTests = [
},
function testStopPropagation() {
var cancelButton = tree.root.firstChild().children()[2];
- assertEq('Cancel', cancelButton.attributes['ax_attr_name']);
+ assertEq('Cancel', cancelButton.attributes['name']);
function onFocusStopPropRoot(event) {
tree.root.removeEventListener('focus', onFocusStopPropRoot);
chrome.test.fail("Focus event was propagated to root");
@@ -51,7 +51,7 @@ var allTests = [
},
function testEventListenerCapture() {
var cancelButton = tree.root.firstChild().children()[2];
- assertEq('Cancel', cancelButton.attributes['ax_attr_name']);
+ assertEq('Cancel', cancelButton.attributes['name']);
var cancelButtonGotEvent = false;
function onFocusCapture(event) {
cancelButtonGotEvent = true;
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs/location.js b/chrome/test/data/extensions/api_test/automation/tests/tabs/location.js
index 6b3599e..c05fdad 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs/location.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs/location.js
@@ -19,7 +19,7 @@ var allTests = [
assertTrue('height' in okButton.location, 'no height in location');
assertTrue('width' in okButton.location, 'no width in location');
- tree.root.addEventListener('children_changed', assertOkButtonLocation);
+ tree.root.addEventListener('childrenChanged', assertOkButtonLocation);
chrome.tabs.executeScript({ 'code':
'document.querySelector("button")' +
'.setAttribute("style", "position: absolute; left: 100; top: 200; ' +
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs/sanity_check.js b/chrome/test/data/extensions/api_test/automation/tests/tabs/sanity_check.js
index 0a4afe6..b391c97 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs/sanity_check.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs/sanity_check.js
@@ -12,40 +12,40 @@ var RemoveUntestedStates = function(state) {
var allTests = [
function testSimplePage() {
- var title = tree.root.attributes['ax_attr_doc_title'];
+ var title = tree.root.attributes['docTitle'];
assertEq('Automation Tests', title);
RemoveUntestedStates(tree.root.state);
assertEq(
- {enabled: true, focusable: true, read_only: true},
+ {enabled: true, focusable: true, readOnly: true},
tree.root.state);
var children = tree.root.children();
assertEq(1, children.length);
var body = children[0];
- assertEq('body', body.attributes['ax_attr_html_tag']);
+ assertEq('body', body.attributes['htmlTag']);
RemoveUntestedStates(body.state);
- assertEq({enabled: true, read_only: true},
+ assertEq({enabled: true, readOnly: true},
body.state);
var contentChildren = body.children();
assertEq(3, contentChildren.length);
var okButton = contentChildren[0];
- assertEq('Ok', okButton.attributes['ax_attr_name']);
+ assertEq('Ok', okButton.attributes['name']);
RemoveUntestedStates(okButton.state);
- assertEq({enabled: true, focusable: true, read_only: true},
+ assertEq({enabled: true, focusable: true, readOnly: true},
okButton.state);
var userNameInput = contentChildren[1];
assertEq('Username',
- userNameInput.attributes['ax_attr_description']);
+ userNameInput.attributes['description']);
RemoveUntestedStates(userNameInput.state);
assertEq({enabled: true, focusable: true},
userNameInput.state);
var cancelButton = contentChildren[2];
assertEq('Cancel',
- cancelButton.attributes['ax_attr_name']);
+ cancelButton.attributes['name']);
RemoveUntestedStates(cancelButton.state);
- assertEq({enabled: true, focusable: true, read_only: true},
+ assertEq({enabled: true, focusable: true, readOnly: true},
cancelButton.state);
// Traversal.
diff --git a/tools/json_schema_compiler/cc_generator.py b/tools/json_schema_compiler/cc_generator.py
index eec0e3a..febd7bb 100644
--- a/tools/json_schema_compiler/cc_generator.py
+++ b/tools/json_schema_compiler/cc_generator.py
@@ -893,8 +893,11 @@ class _Generator(object):
(maybe_namespace, classname))
c.Sblock('switch (enum_param) {')
for enum_value in self._type_helper.FollowRef(type_).enum_values:
+ name = enum_value.name
+ if 'camel_case_enum_to_string' in self._namespace.compiler_options:
+ name = enum_value.CamelName()
(c.Append('case %s: ' % self._type_helper.GetEnumValue(type_, enum_value))
- .Append(' return "%s";' % enum_value.name))
+ .Append(' return "%s";' % name))
(c.Append('case %s:' % self._type_helper.GetEnumNoneValue(type_))
.Append(' return "";')
.Eblock('}')
diff --git a/tools/json_schema_compiler/cpp_type_generator.py b/tools/json_schema_compiler/cpp_type_generator.py
index 7088c91..75972fa 100644
--- a/tools/json_schema_compiler/cpp_type_generator.py
+++ b/tools/json_schema_compiler/cpp_type_generator.py
@@ -71,8 +71,9 @@ class CppTypeGenerator(object):
e.g VAR_STRING
"""
value = cpp_util.Classname(enum_value.name.upper())
- if not type_.cpp_omit_enum_type:
- value = '%s_%s' % (self.FollowRef(type_).unix_name.upper(), value)
+ prefix = (type_.cpp_enum_prefix_override or
+ self.FollowRef(type_).unix_name)
+ value = '%s_%s' % (prefix.upper(), value)
# To avoid collisions with built-in OS_* preprocessor definitions, we add a
# trailing slash to enum names that start with OS_.
if value.startswith("OS_"):
diff --git a/tools/json_schema_compiler/idl_schema.py b/tools/json_schema_compiler/idl_schema.py
index 991b1c6..72e4d13 100644
--- a/tools/json_schema_compiler/idl_schema.py
+++ b/tools/json_schema_compiler/idl_schema.py
@@ -319,9 +319,9 @@ class Enum(object):
'type': 'string',
'enum': enum}
for property_name in (
- 'inline_doc', 'noinline_doc', 'nodoc', 'cpp_omit_enum_type',):
+ 'inline_doc', 'noinline_doc', 'nodoc', 'cpp_enum_prefix_override',):
if self.node.GetProperty(property_name):
- result[property_name] = True
+ result[property_name] = self.node.GetProperty(property_name)
if self.node.GetProperty('deprecated'):
result[deprecated] = self.node.GetProperty('deprecated')
return result
@@ -407,7 +407,7 @@ class IDLSchema(object):
internal = False
description = None
platforms = None
- compiler_options = None
+ compiler_options = {}
deprecated = None
for node in self.idl:
if node.cls == 'Namespace':
@@ -418,7 +418,7 @@ class IDLSchema(object):
description = ''
namespace = Namespace(node, description, nodoc, internal,
platforms=platforms,
- compiler_options=compiler_options,
+ compiler_options=compiler_options or None,
deprecated=deprecated)
namespaces.append(namespace.process())
nodoc = False
@@ -437,7 +437,9 @@ class IDLSchema(object):
elif node.name == 'platforms':
platforms = list(node.value)
elif node.name == 'implemented_in':
- compiler_options = {'implemented_in': node.value}
+ compiler_options['implemented_in'] = node.value
+ elif node.name == 'camel_case_enum_to_string':
+ compiler_options['camel_case_enum_to_string'] = node.value
elif node.name == 'deprecated':
deprecated = str(node.value)
else:
diff --git a/tools/json_schema_compiler/model.py b/tools/json_schema_compiler/model.py
index 967e9ab..ed8a2ec 100644
--- a/tools/json_schema_compiler/model.py
+++ b/tools/json_schema_compiler/model.py
@@ -190,7 +190,7 @@ class Type(object):
elif 'enum' in json and json_type == 'string':
self.property_type = PropertyType.ENUM
self.enum_values = [EnumValue(value) for value in json['enum']]
- self.cpp_omit_enum_type = 'cpp_omit_enum_type' in json
+ self.cpp_enum_prefix_override = json.get('cpp_enum_prefix_override', None)
elif json_type == 'any':
self.property_type = PropertyType.ANY
elif json_type == 'binary':
@@ -410,6 +410,9 @@ class EnumValue(object):
self.name = json
self.description = None
+ def CamelName(self):
+ return CamelName(self.name)
+
class _Enum(object):
"""Superclass for enum types with a "name" field, setting up repr/eq/ne.
Enums need to do this so that equality/non-equality work over pickling.
@@ -484,6 +487,19 @@ def UnixName(name):
return ''.join(unix_name)
+@memoize
+def CamelName(snake):
+ ''' Converts a snake_cased_string to a camelCasedOne. '''
+ pieces = snake.split('_')
+ camel = []
+ for i, piece in enumerate(pieces):
+ if i == 0:
+ camel.append(piece)
+ else:
+ camel.append(piece.capitalize())
+ return ''.join(camel)
+
+
def _StripNamespace(name, namespace):
if name.startswith(namespace.name + '.'):
return name[len(namespace.name + '.'):]
diff --git a/tools/json_schema_compiler/model_test.py b/tools/json_schema_compiler/model_test.py
index 0e398a5..75ed9c5 100755
--- a/tools/json_schema_compiler/model_test.py
+++ b/tools/json_schema_compiler/model_test.py
@@ -118,6 +118,21 @@ class ModelTest(unittest.TestCase):
for name in expectations:
self.assertEquals(expectations[name], model.UnixName(name))
+ def testCamelName(self):
+ expectations = {
+ 'foo': 'foo',
+ 'fooBar': 'fooBar',
+ 'foo_bar_baz': 'fooBarBaz',
+ 'FOO_BAR': 'FOOBar',
+ 'FOO_bar': 'FOOBar',
+ '_bar': 'Bar',
+ '_bar_baz': 'BarBaz',
+ 'bar_': 'bar',
+ 'bar_baz_': 'barBaz',
+ }
+ for testcase, expected in expectations.iteritems():
+ self.assertEquals(expected, model.CamelName(testcase))
+
def testPlatforms(self):
self.assertEqual([Platforms.CHROMEOS],
self.idl_namespace_chromeos.platforms)
diff --git a/ui/accessibility/ax_enums.idl b/ui/accessibility/ax_enums.idl
index 1a3d978..9daf73e 100644
--- a/ui/accessibility/ax_enums.idl
+++ b/ui/accessibility/ax_enums.idl
@@ -4,7 +4,7 @@
// These should be kept in sync with third_party/WebKit/public/web/WebAXEnums.h
// until the Chromium and Blink trees are merged.
-namespace ui {
+[camel_case_enum_to_string=true] namespace ui {
enum AXEvent {
activedescendantchanged,
alert,
@@ -193,141 +193,141 @@ namespace ui {
visited
};
- [cpp_omit_enum_type] enum AXStringAttribute {
+ [cpp_enum_prefix_override="ax_attr"] enum AXStringAttribute {
// Document attributes.
- ax_attr_doc_url,
- ax_attr_doc_title,
- ax_attr_doc_mimetype,
- ax_attr_doc_doctype,
+ doc_url,
+ doc_title,
+ doc_mimetype,
+ doc_doctype,
// Attributes that could apply to any node.
- ax_attr_access_key,
- ax_attr_action,
- ax_attr_container_live_relevant,
- ax_attr_container_live_status,
- ax_attr_description,
- ax_attr_display,
- ax_attr_help,
- ax_attr_html_tag,
- ax_attr_name,
- ax_attr_live_relevant,
- ax_attr_live_status,
- ax_attr_role,
- ax_attr_shortcut,
- ax_attr_url,
- ax_attr_value
+ access_key,
+ action,
+ container_live_relevant,
+ container_live_status,
+ description,
+ display,
+ help,
+ html_tag,
+ name,
+ live_relevant,
+ live_status,
+ role,
+ shortcut,
+ url,
+ value
};
- [cpp_omit_enum_type] enum AXIntAttribute {
+ [cpp_enum_prefix_override="ax_attr"] enum AXIntAttribute {
// Scrollable container attributes.
- ax_attr_scroll_x,
- ax_attr_scroll_x_min,
- ax_attr_scroll_x_max,
- ax_attr_scroll_y,
- ax_attr_scroll_y_min,
- ax_attr_scroll_y_max,
+ scroll_x,
+ scroll_x_min,
+ scroll_x_max,
+ scroll_y,
+ scroll_y_min,
+ scroll_y_max,
// Editable text attributes.
- ax_attr_text_sel_start,
- ax_attr_text_sel_end,
+ text_sel_start,
+ text_sel_end,
// Table attributes.
- ax_attr_table_row_count,
- ax_attr_table_column_count,
- ax_attr_table_header_id,
+ table_row_count,
+ table_column_count,
+ table_header_id,
// Table row attributes.
- ax_attr_table_row_index,
- ax_attr_table_row_header_id,
+ table_row_index,
+ table_row_header_id,
// Table column attributes.
- ax_attr_table_column_index,
- ax_attr_table_column_header_id,
+ table_column_index,
+ table_column_header_id,
// Table cell attributes.
- ax_attr_table_cell_column_index,
- ax_attr_table_cell_column_span,
- ax_attr_table_cell_row_index,
- ax_attr_table_cell_row_span,
+ table_cell_column_index,
+ table_cell_column_span,
+ table_cell_row_index,
+ table_cell_row_span,
// Tree control attributes.
- ax_attr_hierarchical_level,
+ hierarchical_level,
// Relationships between this element and other elements.
- ax_attr_title_ui_element,
- ax_attr_activedescendant_id,
+ title_ui_element,
+ activedescendant_id,
// Color value for AX_ROLE_COLOR_WELL, each component is 0..255
- ax_attr_color_value_red,
- ax_attr_color_value_green,
- ax_attr_color_value_blue,
+ color_value_red,
+ color_value_green,
+ color_value_blue,
// Inline text attributes.
- ax_attr_text_direction
+ text_direction
};
- [cpp_omit_enum_type] enum AXFloatAttribute {
+ [cpp_enum_prefix_override="ax_attr"] enum AXFloatAttribute {
// Document attributes.
- ax_attr_doc_loading_progress,
+ doc_loading_progress,
// Range attributes.
- ax_attr_value_for_range,
- ax_attr_min_value_for_range,
- ax_attr_max_value_for_range
+ value_for_range,
+ min_value_for_range,
+ max_value_for_range
};
- [cpp_omit_enum_type] enum AXBoolAttribute {
+ [cpp_enum_prefix_override="ax_attr"] enum AXBoolAttribute {
// Document attributes.
- ax_attr_doc_loaded,
+ doc_loaded,
// True if a checkbox or radio button is in the "mixed" state.
- ax_attr_button_mixed,
+ button_mixed,
// Live region attributes.
- ax_attr_container_live_atomic,
- ax_attr_container_live_busy,
- ax_attr_live_atomic,
- ax_attr_live_busy,
+ container_live_atomic,
+ container_live_busy,
+ live_atomic,
+ live_busy,
// ARIA readonly flag.
- ax_attr_aria_readonly,
+ aria_readonly,
// Writeable attributes
- ax_attr_can_set_value,
+ can_set_value,
// If this is set, all of the other fields in this struct should
// be ignored and only the locations should change.
- ax_attr_update_location_only,
+ update_location_only,
// Set on a canvas element if it has fallback content.
- ax_attr_canvas_has_fallback
+ canvas_has_fallback
};
- [cpp_omit_enum_type] enum AXIntListAttribute {
+ [cpp_enum_prefix_override="ax_attr"] enum AXIntListAttribute {
// Ids of nodes that are children of this node logically, but are
// not children of this node in the tree structure. As an example,
// a table cell is a child of a row, and an 'indirect' child of a
// column.
- ax_attr_indirect_child_ids,
+ indirect_child_ids,
// Relationships between this element and other elements.
- ax_attr_controls_ids,
- ax_attr_describedby_ids,
- ax_attr_flowto_ids,
- ax_attr_labelledby_ids,
- ax_attr_owns_ids,
+ controls_ids,
+ describedby_ids,
+ flowto_ids,
+ labelledby_ids,
+ owns_ids,
// Character indices where line breaks occur.
- ax_attr_line_breaks,
+ line_breaks,
// For a table, the cell ids in row-major order, with duplicate entries
// when there's a rowspan or colspan, and with -1 for missing cells.
// There are always exactly rows * columns entries.
- ax_attr_cell_ids,
+ cell_ids,
// For a table, the unique cell ids in row-major order of their first
// occurrence.
- ax_attr_unique_cell_ids,
+ unique_cell_ids,
// For inline text. This is the pixel position of the end of this
// character within the bounding rectangle of this object, in the
@@ -335,18 +335,18 @@ namespace ui {
// text, the first offset is the right coordinate of the first character
// within the object's bounds, the second offset is the right coordinate
// of the second character, and so on.
- ax_attr_character_offsets,
+ character_offsets,
// For inline text. These int lists must be the same size; they represent
// the start and end character index of each word within this text.
- ax_attr_word_starts,
- ax_attr_word_ends
+ word_starts,
+ word_ends
};
- [cpp_omit_enum_type] enum AXTextDirection {
- ax_text_direction_lr,
- ax_text_direction_rl,
- ax_text_direction_tb,
- ax_text_direction_bt
+ [cpp_enum_prefix_override="ax"] enum AXTextDirection {
+ text_direction_lr,
+ text_direction_rl,
+ text_direction_tb,
+ text_direction_bt
};
};
diff --git a/ui/accessibility/ax_tree_unittest.cc b/ui/accessibility/ax_tree_unittest.cc
index 9d734f8..05369de 100644
--- a/ui/accessibility/ax_tree_unittest.cc
+++ b/ui/accessibility/ax_tree_unittest.cc
@@ -110,9 +110,9 @@ TEST(AXTreeTest, SerializeSimpleAXTree) {
EXPECT_EQ(checkbox.role, checkbox_node->data().role);
EXPECT_EQ(
- "id=1 root_web_area FOCUSABLE FOCUSED (0, 0)-(800, 600) child_ids=2,3\n"
+ "id=1 rootWebArea FOCUSABLE FOCUSED (0, 0)-(800, 600) child_ids=2,3\n"
" id=2 button (20, 20)-(200, 30)\n"
- " id=3 check_box (20, 50)-(200, 30)\n",
+ " id=3 checkBox (20, 50)-(200, 30)\n",
dst_tree.ToString());
}
@@ -148,8 +148,8 @@ TEST(AXTreeTest, SerializeAXTreeUpdate) {
EXPECT_EQ(
"id=3 list (0, 0)-(0, 0) child_ids=4,5,6\n"
- " id=5 list_item (0, 0)-(0, 0)\n"
- " id=6 list_item (0, 0)-(0, 0)\n"
+ " id=5 listItem (0, 0)-(0, 0)\n"
+ " id=6 listItem (0, 0)-(0, 0)\n"
"id=7 button (0, 0)-(0, 0)\n",
update.ToString());
}