diff options
Diffstat (limited to 'www-client')
-rw-r--r-- | www-client/chromium/chromium-66.0.3359.139.ebuild | 1 | ||||
-rw-r--r-- | www-client/chromium/files/add-missing-blink-tools.patch | 1071 |
2 files changed, 0 insertions, 1072 deletions
diff --git a/www-client/chromium/chromium-66.0.3359.139.ebuild b/www-client/chromium/chromium-66.0.3359.139.ebuild index a08c4441..2ec84a21 100644 --- a/www-client/chromium/chromium-66.0.3359.139.ebuild +++ b/www-client/chromium/chromium-66.0.3359.139.ebuild @@ -154,7 +154,6 @@ PATCHES=( "${FILESDIR}/chromium-clang-r4.patch" "${FILESDIR}/chromium-ffmpeg-r1.patch" "${FILESDIR}/chromium-ffmpeg-clang.patch" - "${FILESDIR}/add-missing-blink-tools.patch" ) pre_build_checks() { diff --git a/www-client/chromium/files/add-missing-blink-tools.patch b/www-client/chromium/files/add-missing-blink-tools.patch deleted file mode 100644 index 4eddd8c7..00000000 --- a/www-client/chromium/files/add-missing-blink-tools.patch +++ /dev/null @@ -1,1071 +0,0 @@ -Description: add back contents of third-party/blink/tools that went missing in the source tarball for 66.0.3359.106 -Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=832283 - ---- /dev/null -+++ b/third_party/blink/tools/OWNERS -@@ -0,0 +1 @@ -+file://third_party/WebKit/Tools/OWNERS ---- /dev/null -+++ b/third_party/blink/tools/blinkpy/__init__.py -@@ -0,0 +1,3 @@ -+# Copyright 2017 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. ---- /dev/null -+++ b/third_party/blink/tools/blinkpy/common/__init__.py -@@ -0,0 +1,3 @@ -+# Copyright 2017 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. ---- /dev/null -+++ b/third_party/blink/tools/blinkpy/common/name_style_converter.py -@@ -0,0 +1,128 @@ -+# Copyright 2017 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+# pylint: disable=import-error,print-statement,relative-import -+ -+import re -+ -+SPECIAL_TOKENS = [ -+ # This list should be sorted by length. -+ 'CString', -+ 'Float32', -+ 'Float64', -+ 'Base64', -+ 'IFrame', -+ 'Latin1', -+ 'PlugIn', -+ 'SQLite', -+ 'Uint16', -+ 'Uint32', -+ 'WebGL2', -+ 'ASCII', -+ 'CType', -+ 'DList', -+ 'Int16', -+ 'Int32', -+ 'MPath', -+ 'OList', -+ 'TSpan', -+ 'UList', -+ 'UTF16', -+ 'Uint8', -+ 'WebGL', -+ 'XPath', -+ 'ETC1', -+ 'HTML', -+ 'Int8', -+ 'S3TC', -+ 'SPv2', -+ 'UTF8', -+ 'API', -+ 'CSS', -+ 'DOM', -+ 'EXT', -+ 'RTC', -+ 'SVG', -+ '2D', -+ 'AX', -+ 'V0', -+ 'V8', -+] -+ -+MATCHING_EXPRESSION = '((?:[A-Z][a-z]+)|[0-9]D?$)' -+ -+ -+class SmartTokenizer(object): -+ """Detects special cases that are not easily discernible without additional -+ knowledge, such as recognizing that in SVGSVGElement, the first two SVGs -+ are separate tokens, but WebGL is one token.""" -+ -+ def __init__(self, name): -+ self.remaining = name -+ -+ def tokenize(self): -+ name = self.remaining -+ tokens = [] -+ while len(name) > 0: -+ matched_token = None -+ for token in SPECIAL_TOKENS: -+ if name.startswith(token): -+ matched_token = token -+ break -+ if not matched_token: -+ match = re.search(MATCHING_EXPRESSION, name) -+ if not match: -+ matched_token = name -+ elif match.start(0) != 0: -+ matched_token = name[:match.start(0)] -+ else: -+ matched_token = match.group(0) -+ tokens.append(name[:len(matched_token)]) -+ name = name[len(matched_token):] -+ return tokens -+ -+ -+class NameStyleConverter(object): -+ """Converts names from camelCase to various other styles. -+ """ -+ -+ def __init__(self, name): -+ self.tokens = self.tokenize(name) -+ -+ def tokenize(self, name): -+ tokenizer = SmartTokenizer(name) -+ return tokenizer.tokenize() -+ -+ def to_snake_case(self): -+ """Snake case is the file and variable name style per Google C++ Style -+ Guide: -+ https://google.github.io/styleguide/cppguide.html#Variable_Names -+ -+ Also known as the hacker case. -+ https://en.wikipedia.org/wiki/Snake_case -+ """ -+ return '_'.join([token.lower() for token in self.tokens]) -+ -+ def to_upper_camel_case(self): -+ """Upper-camel case is the class and function name style per -+ Google C++ Style Guide: -+ https://google.github.io/styleguide/cppguide.html#Function_Names -+ -+ Also known as the PascalCase. -+ https://en.wikipedia.org/wiki/Camel_case. -+ """ -+ return ''.join([token[0].upper() + token[1:] for token in self.tokens]) -+ -+ def to_macro_case(self): -+ """Macro case is the macro name style per Google C++ Style Guide: -+ https://google.github.io/styleguide/cppguide.html#Macro_Names -+ """ -+ return '_'.join([token.upper() for token in self.tokens]) -+ -+ def to_all_cases(self): -+ return { -+ 'snake_case': self.to_snake_case(), -+ 'upper_camel_case': self.to_upper_camel_case(), -+ 'macro_case': self.to_macro_case(), -+ } ---- /dev/null -+++ b/third_party/blink/tools/blinkpy/common/name_style_converter_test.py -@@ -0,0 +1,178 @@ -+# Copyright 2017 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+# pylint: disable=import-error,print-statement,relative-import,protected-access -+ -+"""Unit tests for name_style_converter.py.""" -+ -+import unittest -+ -+from name_style_converter import NameStyleConverter -+from name_style_converter import SmartTokenizer -+ -+ -+class SmartTokenizerTest(unittest.TestCase): -+ def test_simple_cases(self): -+ tokenizer = SmartTokenizer('foo') -+ self.assertEqual(tokenizer.tokenize(), ['foo']) -+ -+ tokenizer = SmartTokenizer('fooBar') -+ self.assertEqual(tokenizer.tokenize(), ['foo', 'Bar']) -+ -+ tokenizer = SmartTokenizer('fooBarBaz') -+ self.assertEqual(tokenizer.tokenize(), ['foo', 'Bar', 'Baz']) -+ -+ tokenizer = SmartTokenizer('Baz') -+ self.assertEqual(tokenizer.tokenize(), ['Baz']) -+ -+ tokenizer = SmartTokenizer('') -+ self.assertEqual(tokenizer.tokenize(), []) -+ -+ tokenizer = SmartTokenizer('FOO') -+ self.assertEqual(tokenizer.tokenize(), ['FOO']) -+ -+ tokenizer = SmartTokenizer('foo2') -+ self.assertEqual(tokenizer.tokenize(), ['foo', '2']) -+ -+ def test_tricky_cases(self): -+ tokenizer = SmartTokenizer('XMLHttpRequest') -+ self.assertEqual(tokenizer.tokenize(), ['XML', 'Http', 'Request']) -+ -+ tokenizer = SmartTokenizer('HTMLElement') -+ self.assertEqual(tokenizer.tokenize(), ['HTML', 'Element']) -+ -+ tokenizer = SmartTokenizer('WebGLRenderingContext') -+ self.assertEqual(tokenizer.tokenize(), -+ ['WebGL', 'Rendering', 'Context']) -+ -+ tokenizer = SmartTokenizer('CanvasRenderingContext2D') -+ self.assertEqual(tokenizer.tokenize(), -+ ['Canvas', 'Rendering', 'Context', '2D']) -+ tokenizer = SmartTokenizer('CanvasRenderingContext2DAPITest') -+ self.assertEqual(tokenizer.tokenize(), -+ ['Canvas', 'Rendering', 'Context', '2D', 'API', 'Test']) -+ -+ tokenizer = SmartTokenizer('SVGSVGElement') -+ self.assertEqual(tokenizer.tokenize(), ['SVG', 'SVG', 'Element']) -+ -+ tokenizer = SmartTokenizer('CanvasRenderingContext2D') -+ self.assertEqual(tokenizer.tokenize(), ['Canvas', 'Rendering', 'Context', '2D']) -+ -+ tokenizer = SmartTokenizer('CSSURLImageValue') -+ self.assertEqual(tokenizer.tokenize(), ['CSS', 'URL', 'Image', 'Value']) -+ tokenizer = SmartTokenizer('CSSPropertyAPID') -+ self.assertEqual(tokenizer.tokenize(), ['CSS', 'Property', 'API', 'D']) -+ tokenizer = SmartTokenizer('AXARIAGridCell') -+ self.assertEqual(tokenizer.tokenize(), ['AX', 'ARIA', 'Grid', 'Cell']) -+ -+ tokenizer = SmartTokenizer('CDATASection') -+ self.assertEqual(tokenizer.tokenize(), ['CDATA', 'Section']) -+ -+ tokenizer = SmartTokenizer('ASCIICType') -+ self.assertEqual(tokenizer.tokenize(), ['ASCII', 'CType']) -+ tokenizer = SmartTokenizer('CString') -+ self.assertEqual(tokenizer.tokenize(), ['CString']) -+ -+ tokenizer = SmartTokenizer('HTMLDListElement') -+ self.assertEqual(tokenizer.tokenize(), ['HTML', 'DList', 'Element']) -+ tokenizer = SmartTokenizer('HTMLOListElement') -+ self.assertEqual(tokenizer.tokenize(), ['HTML', 'OList', 'Element']) -+ tokenizer = SmartTokenizer('HTMLIFrameElement') -+ self.assertEqual(tokenizer.tokenize(), ['HTML', 'IFrame', 'Element']) -+ tokenizer = SmartTokenizer('HTMLPlugInElement') -+ self.assertEqual(tokenizer.tokenize(), ['HTML', 'PlugIn', 'Element']) -+ -+ # No special handling for OptGroup, FieldSet, and TextArea. -+ tokenizer = SmartTokenizer('HTMLOptGroupElement') -+ self.assertEqual(tokenizer.tokenize(), ['HTML', 'Opt', 'Group', 'Element']) -+ tokenizer = SmartTokenizer('HTMLFieldSetElement') -+ self.assertEqual(tokenizer.tokenize(), ['HTML', 'Field', 'Set', 'Element']) -+ tokenizer = SmartTokenizer('HTMLTextAreaElement') -+ self.assertEqual(tokenizer.tokenize(), ['HTML', 'Text', 'Area', 'Element']) -+ -+ tokenizer = SmartTokenizer('Path2D') -+ self.assertEqual(tokenizer.tokenize(), ['Path', '2D']) -+ tokenizer = SmartTokenizer('Point2D') -+ self.assertEqual(tokenizer.tokenize(), ['Point', '2D']) -+ tokenizer = SmartTokenizer('CanvasRenderingContext2DState') -+ self.assertEqual(tokenizer.tokenize(), ['Canvas', 'Rendering', 'Context', '2D', 'State']) -+ -+ tokenizer = SmartTokenizer('RTCDTMFSender') -+ self.assertEqual(tokenizer.tokenize(), ['RTC', 'DTMF', 'Sender']) -+ -+ tokenizer = SmartTokenizer('WebGLCompressedTextureS3TCsRGB') -+ self.assertEqual(tokenizer.tokenize(), ['WebGL', 'Compressed', 'Texture', 'S3TC', 'sRGB']) -+ tokenizer = SmartTokenizer('WebGL2CompressedTextureETC1') -+ self.assertEqual(tokenizer.tokenize(), ['WebGL2', 'Compressed', 'Texture', 'ETC1']) -+ tokenizer = SmartTokenizer('EXTsRGB') -+ self.assertEqual(tokenizer.tokenize(), ['EXT', 'sRGB']) -+ -+ tokenizer = SmartTokenizer('SVGFEBlendElement') -+ self.assertEqual(tokenizer.tokenize(), ['SVG', 'FE', 'Blend', 'Element']) -+ tokenizer = SmartTokenizer('SVGMPathElement') -+ self.assertEqual(tokenizer.tokenize(), ['SVG', 'MPath', 'Element']) -+ tokenizer = SmartTokenizer('SVGTSpanElement') -+ self.assertEqual(tokenizer.tokenize(), ['SVG', 'TSpan', 'Element']) -+ tokenizer = SmartTokenizer('SVGURIReference') -+ self.assertEqual(tokenizer.tokenize(), ['SVG', 'URI', 'Reference']) -+ -+ tokenizer = SmartTokenizer('UTF16TextIterator') -+ self.assertEqual(tokenizer.tokenize(), ['UTF16', 'Text', 'Iterator']) -+ tokenizer = SmartTokenizer('UTF8Decoder') -+ self.assertEqual(tokenizer.tokenize(), ['UTF8', 'Decoder']) -+ tokenizer = SmartTokenizer('Uint8Array') -+ self.assertEqual(tokenizer.tokenize(), ['Uint8', 'Array']) -+ tokenizer = SmartTokenizer('DOMWindowBase64') -+ self.assertEqual(tokenizer.tokenize(), ['DOM', 'Window', 'Base64']) -+ tokenizer = SmartTokenizer('TextCodecLatin1') -+ self.assertEqual(tokenizer.tokenize(), ['Text', 'Codec', 'Latin1']) -+ tokenizer = SmartTokenizer('V8BindingForCore') -+ self.assertEqual(tokenizer.tokenize(), ['V8', 'Binding', 'For', 'Core']) -+ tokenizer = SmartTokenizer('V8DOMRect') -+ self.assertEqual(tokenizer.tokenize(), ['V8', 'DOM', 'Rect']) -+ -+ tokenizer = SmartTokenizer('V0InsertionPoint') -+ self.assertEqual(tokenizer.tokenize(), ['V0', 'Insertion', 'Point']) -+ tokenizer = SmartTokenizer('ShadowDOMV0Test') -+ self.assertEqual(tokenizer.tokenize(), ['Shadow', 'DOM', 'V0', 'Test']) -+ tokenizer = SmartTokenizer('ElementShadowV0') -+ self.assertEqual(tokenizer.tokenize(), ['Element', 'Shadow', 'V0']) -+ tokenizer = SmartTokenizer('StubChromeClientForSPv2') -+ self.assertEqual(tokenizer.tokenize(), ['Stub', 'Chrome', 'Client', 'For', 'SPv2']) -+ -+ tokenizer = SmartTokenizer('SQLiteAuthorizer') -+ self.assertEqual(tokenizer.tokenize(), ['SQLite', 'Authorizer']) -+ tokenizer = SmartTokenizer('XPathEvaluator') -+ self.assertEqual(tokenizer.tokenize(), ['XPath', 'Evaluator']) -+ -+ tokenizer = SmartTokenizer('IsXHTMLDocument') -+ self.assertEqual(tokenizer.tokenize(), ['Is', 'XHTML', 'Document']) -+ -+ tokenizer = SmartTokenizer('Animation.idl') -+ self.assertEqual(tokenizer.tokenize(), ['Animation', '.idl']) -+ -+ -+class NameStyleConverterTest(unittest.TestCase): -+ def test_snake_case(self): -+ converter = NameStyleConverter('HTMLElement') -+ self.assertEqual(converter.to_snake_case(), 'html_element') -+ -+ def test_upper_camel_case(self): -+ converter = NameStyleConverter('someSuperThing') -+ self.assertEqual(converter.to_upper_camel_case(), 'SomeSuperThing') -+ -+ converter = NameStyleConverter('SVGElement') -+ self.assertEqual(converter.to_upper_camel_case(), 'SVGElement') -+ -+ def test_macro_case(self): -+ converter = NameStyleConverter('WebGLBaz2D') -+ self.assertEqual(converter.to_macro_case(), 'WEBGL_BAZ_2D') -+ -+ def test_all_cases(self): -+ converter = NameStyleConverter('SVGScriptElement') -+ self.assertEqual(converter.to_all_cases(), { -+ 'snake_case': 'svg_script_element', -+ 'upper_camel_case': 'SVGScriptElement', -+ 'macro_case': 'SVG_SCRIPT_ELEMENT', -+ }) ---- /dev/null -+++ b/third_party/blink/tools/compile_devtools_frontend.py -@@ -0,0 +1,20 @@ -+#!/usr/bin/env vpython -+# Copyright 2017 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+"""Compile DevTools frontend code with Closure compiler. -+ -+This script wraps devtools/scripts/compile_frontend.py. -+DevTools bot kicks this script. -+""" -+ -+import os -+import sys -+ -+sys.path.append(os.path.join( -+ os.path.dirname(__file__), '..', '..', 'WebKit', 'Source', 'devtools', 'scripts')) -+import compile_frontend -+ -+if __name__ == '__main__': -+ sys.exit(compile_frontend.main()) ---- /dev/null -+++ b/third_party/blink/tools/move_blink_source.py -@@ -0,0 +1,615 @@ -+#!/usr/bin/env vpython -+# Copyright 2017 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+"""Tool to move Blink source from third_party/WebKit to third_party/blink. -+ -+See https://docs.google.com/document/d/1l3aPv1Wx__SpRkdOhvJz8ciEGigNT3wFKv78XiuW0Tw/edit?usp=sharing#heading=h.o225wrxp242h -+for the details. -+""" -+ -+import argparse -+import logging -+import os -+import re -+import sys -+from functools import partial -+ -+# Without abspath(), PathFinder can't find chromium_base correctly. -+sys.path.append(os.path.abspath( -+ os.path.join(os.path.dirname(__file__), '..', '..', '..', -+ 'third_party', 'WebKit', 'Tools', 'Scripts'))) -+from blinkpy.common.name_style_converter import NameStyleConverter -+from plan_blink_move import plan_blink_move -+from plan_blink_move import relative_dest -+from webkitpy.common.checkout.git import Git -+from webkitpy.common.path_finder import get_chromium_src_dir -+from webkitpy.common.path_finder import get_scripts_dir -+from webkitpy.common.system.executive import Executive -+from webkitpy.common.system.executive import ScriptError -+from webkitpy.common.system.filesystem import FileSystem -+ -+_log = logging.getLogger('move_blink_source') -+ -+ -+class FileType(object): -+ NONE = 0 -+ BUILD = 1 -+ BLINK_BUILD = 2 -+ OWNERS = 3 -+ DEPS = 4 -+ MOJOM = 5 -+ TYPEMAP = 6 -+ BLINK_BUILD_PY = 7 -+ LAYOUT_TESTS_WITH_MOJOM = 8 -+ -+ @staticmethod -+ def detect(path): -+ slash_dir, basename = os.path.split(path) -+ slash_dir = slash_dir.replace(os.path.sep, '/') -+ if basename == 'DEPS': -+ return FileType.DEPS -+ if basename == 'OWNERS': -+ return FileType.OWNERS -+ if basename.endswith('.mojom'): -+ return FileType.MOJOM -+ if basename.endswith('.typemap'): -+ return FileType.TYPEMAP -+ if basename.endswith('.py') and 'third_party/WebKit/Source/build' in slash_dir: -+ return FileType.BLINK_BUILD_PY -+ if basename.endswith(('.gn', '.gni')): -+ if 'third_party/WebKit' in path or 'third_party/blink' in slash_dir: -+ return FileType.BLINK_BUILD -+ if 'third_party' in slash_dir: -+ return FileType.NONE -+ return FileType.BUILD -+ if basename.endswith('.html') and re.search( -+ r'third_party/WebKit/LayoutTests/(geolocation-api|installedapp|' + -+ r'media/mediasession|payments|presentation|webshare)', slash_dir): -+ return FileType.LAYOUT_TESTS_WITH_MOJOM -+ return FileType.NONE -+ -+ -+class MoveBlinkSource(object): -+ -+ def __init__(self, fs, options, repo_root): -+ self._fs = fs -+ self._options = options -+ _log.debug(options) -+ self._repo_root = repo_root -+ -+ # The following fields are initialized in _create_basename_maps. -+ self._basename_map = None -+ self._basename_re = None -+ self._idl_generated_impl_headers = None -+ # _checked_in_header_re is used to distinguish checked-in header files -+ # and generated header files. -+ self._checked_in_header_re = None -+ -+ self._updated_files = [] -+ -+ def update(self, apply_only=None): -+ """Updates contents of files affected by Blink source move. -+ -+ Args: -+ apply_only: If it's None, updates all affected files. Otherwise, -+ it should be a set of file paths and this function updates -+ only the files in |apply_only|. -+ """ -+ _log.info('Planning renaming ...') -+ file_pairs = plan_blink_move(self._fs, []) -+ _log.info('Will move %d files', len(file_pairs)) -+ -+ self._create_basename_maps(file_pairs) -+ dirs = self._update_file_content(apply_only) -+ -+ # Updates #includes in files in directories with updated DEPS + -+ # third_party/WebKit/{Source,common,public}. -+ self._append_unless_upper_dir_exists(dirs, self._fs.join(self._repo_root, 'third_party', 'WebKit', 'Source')) -+ self._append_unless_upper_dir_exists(dirs, self._fs.join(self._repo_root, 'third_party', 'WebKit', 'common')) -+ self._append_unless_upper_dir_exists(dirs, self._fs.join(self._repo_root, 'third_party', 'WebKit', 'public')) -+ self._append_unless_upper_dir_exists(dirs, self._fs.join(self._repo_root, 'mojo', 'public', 'tools', -+ 'bindings', 'generators', 'cpp_templates')) -+ self._update_cpp_includes_in_directories(dirs, apply_only) -+ -+ # Content update for individual files. -+ # The following is a list of tuples. -+ # Tuple: (<file path relative to repo root>, [replacement commands]) -+ # Command: a callable object, or -+ # a tuple of (<original string>, <new string>). -+ file_replacement_list = [ -+ ('DEPS', -+ [('src/third_party/WebKit/Source/devtools', -+ 'src/third_party/blink/renderer/devtools')]), -+ ('WATCHLISTS', -+ [('third_party/WebKit/Source', 'third_party/blink/renderer'), -+ ('third_party/WebKit/public', 'third_party/blink/renderer/public')]), -+ ('build/check_gn_headers_whitelist.txt', -+ [('third_party/WebKit/Source', 'third_party/blink/renderer'), -+ ('third_party/WebKit/public', 'third_party/blink/renderer/public'), -+ self._update_basename]), -+ ('testing/buildbot/gn_isolate_map.pyl', -+ [('third_party/WebKit/Source', 'third_party/blink/renderer')]), -+ ('third_party/WebKit/Source/BUILD.gn', -+ [('$root_gen_dir/third_party/WebKit', -+ '$root_gen_dir/third_party/blink/renderer')]), -+ ('third_party/WebKit/Source/config.gni', -+ [('snake_case_source_files = false', -+ 'snake_case_source_files = true')]), -+ ('third_party/WebKit/Source/core/css/CSSProperties.json5', -+ [self._update_basename]), -+ ('third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5', -+ [self._update_basename]), -+ ('third_party/WebKit/Source/core/css/ComputedStyleFieldAliases.json5', -+ [self._update_basename]), -+ ('third_party/WebKit/Source/core/html/parser/create-html-entity-table', -+ [self._update_basename]), -+ ('third_party/WebKit/Source/core/inspector/inspector_protocol_config.json', -+ [self._update_basename]), -+ ('third_party/WebKit/Source/core/probe/CoreProbes.json5', -+ [self._update_basename]), -+ ('third_party/WebKit/Source/core/testing/InternalSettings.h', -+ [('InternalSettingsGenerated.h', 'internal_settings_generated.h')]), -+ ('third_party/WebKit/Source/core/testing/Internals.cpp', -+ [('InternalRuntimeFlags.h', 'internal_runtime_flags.h')]), -+ ('third_party/WebKit/Source/platform/probe/PlatformProbes.json5', -+ [self._update_basename]), -+ ('third_party/WebKit/public/BUILD.gn', -+ [('$root_gen_dir/third_party/WebKit', -+ '$root_gen_dir/third_party/blink/renderer')]), -+ ('third_party/WebKit/public/blink_resources.grd', -+ [('../Source/', '../')]), -+ ('tools/android/eclipse/.classpath', -+ [('third_party/WebKit/public', 'third_party/blink/renderer/public')]), -+ ('tools/android/loading/cloud/backend/deploy.sh', -+ [('third_party/WebKit/Source', 'third_party/blink/renderer')]), -+ ('tools/android/loading/emulation_unittest.py', -+ [('third_party/WebKit/Source', 'third_party/blink/renderer')]), -+ ('tools/android/loading/options.py', -+ [('third_party/WebKit/Source', 'third_party/blink/renderer')]), -+ ('tools/android/loading/request_track.py', -+ [('third_party/WebKit/Source', 'third_party/blink/renderer')]), -+ ('tools/gritsettings/resource_ids', -+ [('third_party/WebKit/public', 'third_party/blink/renderer/public'), -+ ('third_party/WebKit/Source', 'third_party/blink/renderer')]), -+ ('tools/metrics/actions/extract_actions.py', -+ [('third_party/WebKit/Source', 'third_party/blink/renderer')]), -+ ('tools/metrics/histograms/update_editor_commands.py', -+ [('third_party/WebKit/Source/core/editing/EditorCommand.cpp', -+ 'third_party/blink/renderer/core/editing/editor_command.cc')]), -+ ('tools/metrics/histograms/update_use_counter_css.py', -+ [('third_party/WebKit/Source/core/frame/UseCounter.cpp', -+ 'third_party/blink/renderer/core/frame/use_counter.cc')]), -+ ('tools/metrics/histograms/update_use_counter_feature_enum.py', -+ [('third_party/WebKit/public', 'third_party/blink/renderer/public')]), -+ ] -+ for file_path, replacement_list in file_replacement_list: -+ if not apply_only or file_path in apply_only: -+ self._update_single_file_content(file_path, replacement_list, should_write=self._options.run) -+ -+ if self._options.run: -+ _log.info('Formatting updated %d files ...', len(self._updated_files)) -+ git = Git(cwd=self._repo_root) -+ # |git cl format| can't handle too many files at once. -+ while len(self._updated_files) > 0: -+ end_index = 100 -+ if end_index > len(self._updated_files): -+ end_index = len(self._updated_files) -+ git.run(['cl', 'format'] + self._updated_files[:end_index]) -+ self._updated_files = self._updated_files[end_index:] -+ -+ if not apply_only: -+ _log.info('Make a local commit ...') -+ git.commit_locally_with_message("""The Great Blink mv for source files, part 1. -+ -+Update file contents without moving files. -+ -+NOAUTOREVERT=true -+Bug: 768828 -+""") -+ -+ def move(self, apply_only=None): -+ """Move Blink source files. -+ -+ Args: -+ apply_only: If it's None, move all affected files. Otherwise, -+ it should be a set of file paths and this function moves -+ only the files in |apply_only|. -+ """ -+ _log.info('Planning renaming ...') -+ file_pairs = plan_blink_move(self._fs, []) -+ -+ if apply_only: -+ file_pairs = [(src, dest) for (src, dest) in file_pairs -+ if 'third_party/WebKit/' + src.replace('\\', '/') in apply_only] -+ print 'Update file_pairs = ', file_pairs -+ _log.info('Will move %d files', len(file_pairs)) -+ -+ git = Git(cwd=self._repo_root) -+ files_set = self._get_checked_in_files(git) -+ for i, (src, dest) in enumerate(file_pairs): -+ src_from_repo = self._fs.join('third_party', 'WebKit', src) -+ if src_from_repo.replace('\\', '/') not in files_set: -+ _log.info('%s is not in the repository', src) -+ continue -+ dest_from_repo = self._fs.join('third_party', 'blink', dest) -+ self._fs.maybe_make_directory(self._repo_root, 'third_party', 'blink', self._fs.dirname(dest)) -+ if self._options.run_git: -+ git.move(src_from_repo, dest_from_repo) -+ _log.info('[%d/%d] Git moved %s', i + 1, len(file_pairs), src) -+ else: -+ self._fs.move(self._fs.join(self._repo_root, src_from_repo), -+ self._fs.join(self._repo_root, dest_from_repo)) -+ _log.info('[%d/%d] Moved %s', i + 1, len(file_pairs), src) -+ if apply_only: -+ return -+ -+ self._update_single_file_content( -+ 'build/get_landmines.py', -+ [('\ndef main', ' print \'The Great Blink mv for source files (crbug.com/768828)\'\n\ndef main')]) -+ -+ _log.info('Run run-bindings-tests ...') -+ Executive().run_command(['python', -+ self._fs.join(get_scripts_dir(), 'run-bindings-tests'), -+ '--reset-results'], -+ cwd=self._repo_root) -+ -+ if self._options.run_git: -+ _log.info('Make a local commit ...') -+ git.commit_locally_with_message("""The Great Blink mv for source files, part 2. -+ -+Move and rename files. -+ -+NOAUTOREVERT=true -+Bug: 768828 -+""") -+ -+ def fix_branch(self): -+ git = Git(cwd=self._repo_root) -+ status = self._get_local_change_status(git) -+ if len(status) == 0: -+ _log.info('No local changes.') -+ return -+ modified_files = {f for (s, f) in status if s != 'D'} -+ deleted_files = {f for (s, f) in status if s == 'D'} -+ -+ self.update(apply_only=modified_files) -+ self.move(apply_only=modified_files) -+ try: -+ git.commit_locally_with_message('This commit should be squashed.') -+ except ScriptError: -+ _log.info('move_blink_source.py modified nothing.') -+ -+ # TODO(tkent): Show a message about deleted_files. -+ -+ def _get_local_change_status(self, git): -+ """Returns a list of tuples representing local change summary. -+ -+ Each tuple contains two strings. The first one is file change status -+ such as "M", "D". See --diff-filter section of git-diff manual page. -+ The second one is file name relative to the repository top. -+ """ -+ -+ base_commit = git.run(['show-branch', '--merge-base', 'master', 'HEAD']).strip() -+ # Note that file names in the following command result are always -+ # slash-separated, even on Windows. -+ status_lines = git.run(['diff', '--name-status', '--no-renames', base_commit]).split('\n') -+ status_tuple_list = [] -+ for l in status_lines: -+ items = l.split('\t') -+ if len(items) == 2: -+ status_tuple_list.append(tuple(items)) -+ elif len(l) > 0: -+ _log.warning('Unrecognized diff output: "%s"', l) -+ return status_tuple_list -+ -+ def _get_checked_in_files(self, git): -+ files_text = git.run(['ls-files', -+ 'third_party/WebKit/Source', -+ 'third_party/WebKit/common', -+ 'third_party/WebKit/public']) -+ return set(files_text.split('\n')) -+ -+ def _create_basename_maps(self, file_pairs): -+ basename_map = {} -+ # Generated inspector/protocol/* contains a lot of names duplicated with -+ # checked-in core files. We don't want to rename them, and don't want to -+ # replace them in BUILD.gn and #include accidentally. -+ pattern = r'(?<!inspector/protocol/)\b(' -+ idl_headers = set() -+ header_pattern = r'(?<!inspector/protocol/)\b(' -+ for source, dest in file_pairs: -+ _, source_base = self._fs.split(source) -+ _, dest_base = self._fs.split(dest) -+ # OriginTrialFeaturesForCore.h in bindings/tests/results/modules/ -+ # confuses generated/checked-in detection in _replace_include_path(). -+ if 'bindings/tests' in source.replace('\\', '/'): -+ continue -+ if source_base.endswith('.h'): -+ header_pattern += re.escape(source_base) + '|' -+ if source_base == dest_base: -+ continue -+ basename_map[source_base] = dest_base -+ pattern += re.escape(source_base) + '|' -+ # IDL sometimes generates implementation files as well as -+ # binding files. We'd like to update #includes for such files. -+ if source_base.endswith('.idl'): -+ source_header = source_base.replace('.idl', '.h') -+ basename_map[source_header] = dest_base.replace('.idl', '.h') -+ pattern += re.escape(source_header) + '|' -+ idl_headers.add(source_header) -+ _log.info('Rename %d files for snake_case', len(basename_map)) -+ self._basename_map = basename_map -+ self._basename_re = re.compile(pattern[0:len(pattern) - 1] + ')(?=["\']|$)') -+ self._idl_generated_impl_headers = idl_headers -+ self._checked_in_header_re = re.compile(header_pattern[0:len(header_pattern) - 1] + ')$') -+ -+ def _shorten_path(self, path): -+ if path.startswith(self._repo_root): -+ return path[len(self._repo_root) + 1:] -+ return path -+ -+ @staticmethod -+ def _filter_file(fs, dirname, basename): -+ return FileType.detect(fs.join(dirname, basename)) != FileType.NONE -+ -+ def _update_build(self, content): -+ content = content.replace('//third_party/WebKit/Source', '//third_party/blink/renderer') -+ content = content.replace('//third_party/WebKit/common', '//third_party/blink/common') -+ content = content.replace('//third_party/WebKit/public', '//third_party/blink/renderer/public') -+ # export_header_blink exists outside of Blink too. -+ content = content.replace('export_header_blink = "third_party/WebKit/public/platform/WebCommon.h"', -+ 'export_header_blink = "third_party/blink/renderer/public/platform/web_common.h"') -+ return content -+ -+ def _update_blink_build(self, content): -+ content = self._update_build(content) -+ -+ # Update visibility=[...] -+ content = content.replace('//third_party/WebKit/*', '//third_party/blink/*') -+ content = content.replace('//third_party/WebKit/Source/*', '//third_party/blink/renderer/*') -+ content = content.replace('//third_party/WebKit/public/*', '//third_party/blink/renderer/public/*') -+ -+ # Update mojom variables -+ content = content.replace('export_header = "third_party/WebKit/common', -+ 'export_header = "third_party/blink/common') -+ content = content.replace('export_header_blink = "third_party/WebKit/Source', -+ 'export_header_blink = "third_party/blink/renderer') -+ return self._update_basename(content) -+ -+ def _update_owners(self, content): -+ content = content.replace('//third_party/WebKit/Source', '//third_party/blink/renderer') -+ content = content.replace('//third_party/WebKit/common', '//third_party/blink/common') -+ content = content.replace('//third_party/WebKit/public', '//third_party/blink/renderer/public') -+ return content -+ -+ def _update_deps(self, content): -+ original_content = content -+ content = content.replace('third_party/WebKit/Source', 'third_party/blink/renderer') -+ content = content.replace('third_party/WebKit/common', 'third_party/blink/common') -+ content = content.replace('third_party/WebKit/public', 'third_party/blink/renderer/public') -+ content = content.replace('third_party/WebKit', 'third_party/blink') -+ if original_content == content: -+ return content -+ return self._update_basename(content) -+ -+ def _update_mojom(self, content): -+ content = content.replace('third_party/WebKit/public', 'third_party/blink/renderer/public') -+ content = content.replace('third_party/WebKit/common', 'third_party/blink/common') -+ return content -+ -+ def _update_typemap(self, content): -+ content = content.replace('//third_party/WebKit/Source', '//third_party/blink/renderer') -+ content = content.replace('//third_party/WebKit/common', '//third_party/blink/common') -+ content = content.replace('//third_party/WebKit/public', '//third_party/blink/renderer/public') -+ return self._update_basename(content) -+ -+ def _update_blink_build_py(self, content): -+ # We don't prepend 'third_party/blink/renderer/' to matched basenames -+ # because it won't affect build and manual update after the great mv is -+ # enough. -+ return self._update_basename(content) -+ -+ def _update_layout_tests(self, content): -+ return content.replace('file:///gen/third_party/WebKit/', 'file:///gen/third_party/blink/renderer/') -+ -+ def _update_basename(self, content): -+ return self._basename_re.sub(lambda match: self._basename_map[match.group(1)], content) -+ -+ @staticmethod -+ def _append_unless_upper_dir_exists(dirs, new_dir): -+ for i in range(0, len(dirs)): -+ if new_dir.startswith(dirs[i]): -+ return -+ if dirs[i].startswith(new_dir): -+ dirs[i] = new_dir -+ return -+ dirs.append(new_dir) -+ -+ def _update_file_content(self, apply_only): -+ _log.info('Find *.gn, *.mojom, *.py, *.typemap, DEPS, and OWNERS ...') -+ files = self._fs.files_under( -+ self._repo_root, dirs_to_skip=['.git', 'out'], file_filter=self._filter_file) -+ _log.info('Scan contents of %d files ...', len(files)) -+ updated_deps_dirs = [] -+ for file_path in files: -+ file_type = FileType.detect(file_path) -+ original_content = self._fs.read_text_file(file_path) -+ content = original_content -+ if file_type == FileType.BUILD: -+ content = self._update_build(content) -+ elif file_type == FileType.BLINK_BUILD: -+ content = self._update_blink_build(content) -+ elif file_type == FileType.OWNERS: -+ content = self._update_owners(content) -+ elif file_type == FileType.DEPS: -+ if self._fs.dirname(file_path) == self._repo_root: -+ _log.info("Skip //DEPS") -+ continue -+ content = self._update_deps(content) -+ elif file_type == FileType.MOJOM: -+ content = self._update_mojom(content) -+ elif file_type == FileType.TYPEMAP: -+ content = self._update_typemap(content) -+ elif file_type == FileType.BLINK_BUILD_PY: -+ content = self._update_blink_build_py(content) -+ elif file_type == FileType.LAYOUT_TESTS_WITH_MOJOM: -+ content = self._update_layout_tests(content) -+ -+ if original_content == content: -+ continue -+ if self._options.run and (not apply_only or file_path.replace('\\', '/') in apply_only): -+ self._fs.write_text_file(file_path, content) -+ self._updated_files.append(file_path) -+ if file_type == FileType.DEPS: -+ self._append_unless_upper_dir_exists(updated_deps_dirs, self._fs.dirname(file_path)) -+ _log.info('Updated %s', self._shorten_path(file_path)) -+ return updated_deps_dirs -+ -+ def _update_cpp_includes_in_directories(self, dirs, apply_only): -+ for dirname in dirs: -+ _log.info('Processing #include in %s ...', self._shorten_path(dirname)) -+ files = self._fs.files_under( -+ dirname, file_filter=lambda fs, _, basename: basename.endswith( -+ ('.h', '.cc', '.cpp', '.mm', '.cc.tmpl', '.cpp.tmpl', -+ '.h.tmpl', 'XPathGrammar.y', '.gperf'))) -+ for file_path in files: -+ posix_file_path = file_path.replace('\\', '/') -+ original_content = self._fs.read_text_file(file_path) -+ -+ content = self._update_cpp_includes(original_content) -+ if file_path.endswith('.h') and '/third_party/WebKit/public/' in posix_file_path: -+ content = self._update_basename_only_includes(content, file_path) -+ if file_path.endswith('.h') and '/third_party/WebKit/' in posix_file_path: -+ content = self._update_include_guard(content, file_path) -+ -+ if original_content == content: -+ continue -+ if self._options.run and (not apply_only or posix_file_path in apply_only): -+ self._fs.write_text_file(file_path, content) -+ self._updated_files.append(file_path) -+ _log.info('Updated %s', self._shorten_path(file_path)) -+ -+ def _replace_include_path(self, match): -+ include_or_import = match.group(1) -+ path = match.group(2) -+ -+ # If |path| starts with 'third_party/WebKit', we should adjust the -+ # directory name for third_party/blink, and replace its basename by -+ # self._basename_map. -+ # -+ # If |path| starts with a Blink-internal directory such as bindings, -+ # core, modules, platform, public, it refers to a checked-in file, or a -+ # generated file. For the former, we should add -+ # 'third_party/blink/renderer/' and replace the basename. For the -+ # latter, we should update the basename for a name mapped from an IDL -+ # renaming, and should not add 'third_party/blink/renderer'. -+ -+ if path.startswith('third_party/WebKit'): -+ path = path.replace('third_party/WebKit/Source', 'third_party/blink/renderer') -+ path = path.replace('third_party/WebKit/common', 'third_party/blink/common') -+ path = path.replace('third_party/WebKit/public', 'third_party/blink/renderer/public') -+ path = self._update_basename(path) -+ return '#%s "%s"' % (include_or_import, path) -+ -+ match = self._checked_in_header_re.search(path) -+ if match: -+ if match.group(1) in self._basename_map: -+ path = 'third_party/blink/renderer/' + path[:match.start(1)] + self._basename_map[match.group(1)] -+ else: -+ path = 'third_party/blink/renderer/' + path -+ elif 'core/inspector/protocol/' not in path: -+ basename_start = path.rfind('/') + 1 -+ basename = path[basename_start:] -+ if basename in self._idl_generated_impl_headers: -+ path = path[:basename_start] + self._basename_map[basename] -+ elif basename.startswith('V8'): -+ path = path[:basename_start] + NameStyleConverter(basename[:len(basename) - 2]).to_snake_case() + '.h' -+ return '#%s "%s"' % (include_or_import, path) -+ -+ def _update_cpp_includes(self, content): -+ pattern = re.compile(r'#(include|import)\s+"((bindings|core|modules|platform|public|' + -+ r'third_party/WebKit/(Source|common|public))/[-_\w/.]+)"') -+ return pattern.sub(self._replace_include_path, content) -+ -+ def _replace_basename_only_include(self, subdir, source_path, match): -+ source_basename = match.group(1) -+ if source_basename in self._basename_map: -+ return '#include "third_party/blink/renderer/public/%s/%s"' % (subdir, self._basename_map[source_basename]) -+ _log.warning('Basename-only %s in %s', match.group(0), self._shorten_path(source_path)) -+ return match.group(0) -+ -+ def _update_basename_only_includes(self, content, source_path): -+ if not source_path.endswith('.h') or '/third_party/WebKit/public/' not in source_path.replace('\\', '/'): -+ return -+ # In public/ header files, we should replace |#include "WebFoo.h"| -+ # with |#include "third_party/blink/renderer/public/platform-or-web/web_foo.h"| -+ subdir = self._fs.basename(self._fs.dirname(source_path)) -+ # subdir is 'web' or 'platform'. -+ return re.sub(r'#include\s+"(\w+\.h)"', -+ partial(self._replace_basename_only_include, subdir, source_path), content) -+ -+ def _update_include_guard(self, content, source_path): -+ current_guard = re.sub(r'[.]', '_', self._fs.basename(source_path)) -+ new_path = relative_dest(self._fs, self._fs.relpath( -+ source_path, start=self._fs.join(self._repo_root, 'third_party', 'WebKit'))) -+ new_guard = 'THIRD_PARTY_BLINK_' + re.sub(r'[\\/.]', '_', new_path.upper()) + '_' -+ content = re.sub(r'#ifndef\s+(WTF_)?' + current_guard, '#ifndef ' + new_guard, content); -+ content = re.sub(r'#define\s+(WTF_)?' + current_guard, '#define ' + new_guard, content); -+ content = re.sub(r'#endif\s+//\s+(WTF_)?' + current_guard, '#endif // ' + new_guard, content); -+ return content -+ -+ def _update_single_file_content(self, file_path, replace_list, should_write=True): -+ full_path = self._fs.join(self._repo_root, file_path) -+ original_content = self._fs.read_text_file(full_path) -+ content = original_content -+ for command in replace_list: -+ if isinstance(command, tuple): -+ src, dest = command -+ content = content.replace(src, dest) -+ elif callable(command): -+ content = command(content) -+ else: -+ raise TypeError('A tuple or a function is expected.') -+ if content != original_content: -+ if should_write: -+ self._fs.write_text_file(full_path, content) -+ self._updated_files.append(full_path) -+ _log.info('Updated %s', file_path) -+ else: -+ _log.warning('%s does not contain specified source strings.', file_path) -+ -+ -+def main(): -+ logging.basicConfig(level=logging.DEBUG, -+ format='[%(asctime)s %(levelname)s %(name)s] %(message)s', -+ datefmt='%H:%M:%S') -+ parser = argparse.ArgumentParser(description='Blink source mover') -+ sub_parsers = parser.add_subparsers() -+ -+ update_parser = sub_parsers.add_parser('update') -+ update_parser.set_defaults(command='update') -+ update_parser.add_argument('--run', dest='run', action='store_true', -+ help='Update file contents') -+ -+ move_parser = sub_parsers.add_parser('move') -+ move_parser.set_defaults(command='move') -+ move_parser.add_argument('--git', dest='run_git', action='store_true', -+ help='Run |git mv| command instead of |mv|.') -+ -+ fixbranch_parser = sub_parsers.add_parser('fixbranch') -+ fixbranch_parser.set_defaults(command='fixbranch', run=True, run_git=True) -+ -+ options = parser.parse_args() -+ mover = MoveBlinkSource(FileSystem(), options, get_chromium_src_dir()) -+ if options.command == 'update': -+ mover.update() -+ elif options.command == 'move': -+ mover.move() -+ elif options.command == 'fixbranch': -+ mover.fix_branch() -+ -+ -+if __name__ == '__main__': -+ main() ---- /dev/null -+++ b/third_party/blink/tools/plan_blink_move.py -@@ -0,0 +1,96 @@ -+#!/usr/bin/env vpython -+# Copyright 2017 The Chromium Authors. All rights reserved. -+# Use of this source code is governed by a BSD-style license that can be -+# found in the LICENSE file. -+ -+import os -+import re -+import sys -+ -+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..', -+ 'third_party', 'WebKit', 'Tools', 'Scripts')) -+from blinkpy.common.name_style_converter import NameStyleConverter -+from webkitpy.common.system.filesystem import FileSystem -+ -+ -+def relative_dest(fs, filename): -+ """Returns a destination path string for given filename. -+ -+ |filename| is a path relative to third_party/WebKit, and the resultant path -+ is relative to third_party/blink. -+ """ -+ dest = None -+ if filename.startswith('public'): -+ dest = re.sub(r'^public', 'renderer' + fs.sep + 'public', filename) -+ elif filename.startswith('Source'): -+ dest = re.sub(r'^Source', 'renderer', filename) -+ elif filename.startswith('common'): -+ dest = filename -+ else: -+ raise ValueError('|filename| must start with "common", "public", or "Source": %s' % filename) -+ if filename.endswith(('.h', '.cpp', '.mm', '.idl', '.typemap', 'Settings.json5')): -+ dirname, basename = fs.split(dest) -+ basename, ext = fs.splitext(basename) -+ # Skip some inspector-related files. #includes for these files are -+ # generated by a script outside of Blink. -+ if (re.match(r'Inspector.*Agent', basename) -+ or basename == 'InspectorTraceEvents' -+ or basename == 'PerformanceMonitor' -+ or basename == 'PlatformTraceEventsAgent'): -+ return dest -+ # Skip CSSProperty*. Some files are generated, and some files are -+ # checked-in. It's hard to handle them automatically. -+ if re.search(r'css[\\/]properties$', dirname): -+ return dest -+ if filename.endswith('.cpp'): -+ ext = '.cc' -+ # WebKit.h should be renamed to blink.h. -+ if basename == 'WebKit' and ext == '.h': -+ basename = 'blink' -+ if basename.lower() != basename: -+ basename = NameStyleConverter(basename).to_snake_case() -+ return fs.join(dirname, basename + ext) -+ return dest -+ -+ -+def start_with_list(name, prefixes): -+ if len(prefixes) == 0: -+ return True -+ for prefix in prefixes: -+ if name.startswith(prefix): -+ return True -+ return False -+ -+ -+def plan_blink_move(fs, prefixes): -+ """Returns (source, dest) path pairs. -+ -+ The source paths are relative to third_party/WebKit, -+ and the dest paths are relative to third_party/blink. -+ The paths use os.sep as the path part separator. -+ """ -+ blink_dir = fs.join(fs.dirname(__file__), '..') -+ webkit_dir = fs.join(blink_dir, '..', '..', 'third_party', 'WebKit') -+ source_files = fs.files_under(fs.join(webkit_dir, 'Source')) -+ source_files += fs.files_under(fs.join(webkit_dir, 'common')) -+ source_files += fs.files_under(fs.join(webkit_dir, 'public')) -+ -+ # It's possible to check git.exists() here, but we don't do it due to slow -+ # performance. We should check it just before executing git command. -+ -+ source_files = [f[len(webkit_dir) + 1:] for f in source_files] -+ return [(f, relative_dest(fs, f)) for f in source_files -+ if f.find('node_modules') == -1 and start_with_list(f, prefixes)] -+ -+ -+def main(): -+ fs = FileSystem() -+ file_pairs = plan_blink_move(fs, sys.argv[1:]) -+ print 'Show renaming plan. It contains files not in the repository.' -+ print '<Source path relative to third_party/WebKit> => <Destination path relative to third_party/blink>' -+ for pair in file_pairs: -+ print '%s\t=>\t%s' % pair -+ -+ -+if __name__ == '__main__': -+ main() |