Docserver: Display API features that are available to content scripts

BUG=278919
NOTRY=True

Review URL: https://codereview.chromium.org/375133002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@284523 0039d316-1c4b-4281-b951-d872f2087c98
parent b857cda3
...@@ -8,11 +8,12 @@ import os ...@@ -8,11 +8,12 @@ import os
import posixpath import posixpath
from data_source import DataSource from data_source import DataSource
from docs_server_utils import StringIdentity from docs_server_utils import StringIdentity, MarkFirstAndLast
from environment import IsPreviewServer, IsReleaseServer from environment import IsPreviewServer, IsReleaseServer
from extensions_paths import JSON_TEMPLATES, PRIVATE_TEMPLATES from extensions_paths import JSON_TEMPLATES, PRIVATE_TEMPLATES
from file_system import FileNotFoundError from file_system import FileNotFoundError
from future import Future, Collect from future import Future, Collect
from operator import itemgetter
from platform_util import GetPlatforms from platform_util import GetPlatforms
import third_party.json_schema_compiler.json_parse as json_parse import third_party.json_schema_compiler.json_parse as json_parse
import third_party.json_schema_compiler.model as model import third_party.json_schema_compiler.model as model
...@@ -278,12 +279,14 @@ class _JSCModel(object): ...@@ -278,12 +279,14 @@ class _JSCModel(object):
''' '''
def __init__(self, def __init__(self,
content_script_apis,
namespace, namespace,
availability_finder, availability_finder,
json_cache, json_cache,
template_cache, template_cache,
features_bundle, features_bundle,
event_byname_future): event_byname_future):
self._content_script_apis = content_script_apis
self._availability = availability_finder.GetAPIAvailability(namespace.name) self._availability = availability_finder.GetAPIAvailability(namespace.name)
self._current_node = _APINodeCursor(availability_finder, namespace.name) self._current_node = _APINodeCursor(availability_finder, namespace.name)
self._api_availabilities = json_cache.GetFromFile( self._api_availabilities = json_cache.GetFromFile(
...@@ -556,7 +559,7 @@ class _JSCModel(object): ...@@ -556,7 +559,7 @@ class _JSCModel(object):
intro_rows = [ intro_rows = [
self._GetIntroDescriptionRow(), self._GetIntroDescriptionRow(),
self._GetIntroAvailabilityRow() self._GetIntroAvailabilityRow()
] + self._GetIntroDependencyRows() ] + self._GetIntroDependencyRows() + self._GetIntroContentScriptRow()
# Add rows using data from intro_tables.json, overriding any existing rows # Add rows using data from intro_tables.json, overriding any existing rows
# if they share the same 'title' attribute. # if they share the same 'title' attribute.
...@@ -580,6 +583,23 @@ class _JSCModel(object): ...@@ -580,6 +583,23 @@ class _JSCModel(object):
'version': version 'version': version
} }
def _GetIntroContentScriptRow(self):
content_script_support = self._content_script_apis.get(self._namespace.name)
if content_script_support is None:
return []
if content_script_support.restrictedTo:
content_script_support.restrictedTo.sort(key=itemgetter('node'))
MarkFirstAndLast(content_script_support.restrictedTo)
return [{
'title': 'Content Scripts',
'content': [{
'partial': self._template_cache.GetFromFile(
posixpath.join(PRIVATE_TEMPLATES,
'intro_tables',
'content_scripts.html')).Get(),
'contentScriptSupport': content_script_support.__dict__
}]
}]
def _GetAvailabilityTemplate(self): def _GetAvailabilityTemplate(self):
'''Gets availability for the current node and returns an appropriate '''Gets availability for the current node and returns an appropriate
template object. template object.
...@@ -756,13 +776,15 @@ class APIDataSource(DataSource): ...@@ -756,13 +776,15 @@ class APIDataSource(DataSource):
def _GetSchemaModel(self, platform, api_name): def _GetSchemaModel(self, platform, api_name):
object_store_key = '/'.join((platform, api_name)) object_store_key = '/'.join((platform, api_name))
api_models = self._platform_bundle.GetAPIModels(platform)
jsc_model_future = self._model_cache.Get(object_store_key) jsc_model_future = self._model_cache.Get(object_store_key)
model_future = self._platform_bundle.GetAPIModels(platform).GetModel( model_future = api_models.GetModel(api_name)
api_name) content_script_apis_future = api_models.GetContentScriptAPIs()
def resolve(): def resolve():
jsc_model = jsc_model_future.Get() jsc_model = jsc_model_future.Get()
if jsc_model is None: if jsc_model is None:
jsc_model = _JSCModel( jsc_model = _JSCModel(
content_script_apis_future.Get(),
model_future.Get(), model_future.Get(),
self._platform_bundle.GetAvailabilityFinder(platform), self._platform_bundle.GetAvailabilityFinder(platform),
self._json_cache, self._json_cache,
......
...@@ -120,7 +120,8 @@ class APIDataSourceTest(unittest.TestCase): ...@@ -120,7 +120,8 @@ class APIDataSourceTest(unittest.TestCase):
def testCreateId(self): def testCreateId(self):
fake_avail_finder = _FakeAvailabilityFinder(self._fake_availability) fake_avail_finder = _FakeAvailabilityFinder(self._fake_availability)
dict_ = _JSCModel(self._api_models.GetModel('tester').Get(), dict_ = _JSCModel(self._api_models.GetContentScriptAPIs().Get(),
self._api_models.GetModel('tester').Get(),
fake_avail_finder, fake_avail_finder,
self._json_cache, self._json_cache,
_FakeTemplateCache(), _FakeTemplateCache(),
...@@ -136,7 +137,8 @@ class APIDataSourceTest(unittest.TestCase): ...@@ -136,7 +137,8 @@ class APIDataSourceTest(unittest.TestCase):
def DISABLED_testToDict(self): def DISABLED_testToDict(self):
fake_avail_finder = _FakeAvailabilityFinder(self._fake_availability) fake_avail_finder = _FakeAvailabilityFinder(self._fake_availability)
expected_json = self._LoadJSON('expected_tester.json') expected_json = self._LoadJSON('expected_tester.json')
dict_ = _JSCModel(self._api_models.GetModel('tester').Get(), dict_ = _JSCModel(self._api_models.GetContentScriptAPIs().Get(),
self._api_models.GetModel('tester').Get(),
fake_avail_finder, fake_avail_finder,
self._json_cache, self._json_cache,
_FakeTemplateCache(), _FakeTemplateCache(),
...@@ -146,7 +148,8 @@ class APIDataSourceTest(unittest.TestCase): ...@@ -146,7 +148,8 @@ class APIDataSourceTest(unittest.TestCase):
def testAddRules(self): def testAddRules(self):
fake_avail_finder = _FakeAvailabilityFinder(self._fake_availability) fake_avail_finder = _FakeAvailabilityFinder(self._fake_availability)
dict_ = _JSCModel(self._api_models.GetModel('add_rules_tester').Get(), dict_ = _JSCModel(self._api_models.GetContentScriptAPIs().Get(),
self._api_models.GetModel('add_rules_tester').Get(),
fake_avail_finder, fake_avail_finder,
self._json_cache, self._json_cache,
_FakeTemplateCache(), _FakeTemplateCache(),
...@@ -170,7 +173,8 @@ class APIDataSourceTest(unittest.TestCase): ...@@ -170,7 +173,8 @@ class APIDataSourceTest(unittest.TestCase):
def testGetIntroList(self): def testGetIntroList(self):
fake_avail_finder = _FakeAvailabilityFinder(self._fake_availability) fake_avail_finder = _FakeAvailabilityFinder(self._fake_availability)
model = _JSCModel(self._api_models.GetModel('tester').Get(), model = _JSCModel(self._api_models.GetContentScriptAPIs().Get(),
self._api_models.GetModel('tester').Get(),
fake_avail_finder, fake_avail_finder,
self._json_cache, self._json_cache,
_FakeTemplateCache(), _FakeTemplateCache(),
...@@ -206,6 +210,18 @@ class APIDataSourceTest(unittest.TestCase): ...@@ -206,6 +210,18 @@ class APIDataSourceTest(unittest.TestCase):
} }
] ]
}, },
{ 'title': 'Content Scripts',
'content': [
{
'partial': 'handlebar chrome/common/extensions/docs' +
'/templates/private/intro_tables/content_scripts.html',
'contentScriptSupport': {
'name': 'tester',
'restrictedTo': None
}
}
]
},
{ 'title': 'Learn More', { 'title': 'Learn More',
'content': [ 'content': [
{ 'link': 'https://tester.test.com/welcome.html', { 'link': 'https://tester.test.com/welcome.html',
...@@ -219,7 +235,8 @@ class APIDataSourceTest(unittest.TestCase): ...@@ -219,7 +235,8 @@ class APIDataSourceTest(unittest.TestCase):
# Tests the same data with a scheduled availability. # Tests the same data with a scheduled availability.
fake_avail_finder = _FakeAvailabilityFinder( fake_avail_finder = _FakeAvailabilityFinder(
AvailabilityInfo(ChannelInfo('beta', '1453', 27), scheduled=28)) AvailabilityInfo(ChannelInfo('beta', '1453', 27), scheduled=28))
model = _JSCModel(self._api_models.GetModel('tester').Get(), model = _JSCModel(self._api_models.GetContentScriptAPIs().Get(),
self._api_models.GetModel('tester').Get(),
fake_avail_finder, fake_avail_finder,
self._json_cache, self._json_cache,
_FakeTemplateCache(), _FakeTemplateCache(),
...@@ -262,6 +279,7 @@ class APIDataSourceWithoutNodeAvailabilityTest(unittest.TestCase): ...@@ -262,6 +279,7 @@ class APIDataSourceWithoutNodeAvailabilityTest(unittest.TestCase):
} }
for api_name, availability in api_availabilities.iteritems(): for api_name, availability in api_availabilities.iteritems():
model_dict = _JSCModel( model_dict = _JSCModel(
self._api_models.GetContentScriptAPIs().Get(),
self._api_models.GetModel(api_name).Get(), self._api_models.GetModel(api_name).Get(),
self._avail_finder, self._avail_finder,
self._json_cache, self._json_cache,
...@@ -335,6 +353,7 @@ class APIDataSourceWithNodeAvailabilityTest(unittest.TestCase): ...@@ -335,6 +353,7 @@ class APIDataSourceWithNodeAvailabilityTest(unittest.TestCase):
self.assertEquals(node_availabilities[node], actual) self.assertEquals(node_availabilities[node], actual)
model_dict = _JSCModel( model_dict = _JSCModel(
self._api_models.GetContentScriptAPIs().Get(),
self._api_models.GetModel('tabs').Get(), self._api_models.GetModel('tabs').Get(),
self._avail_finder, self._avail_finder,
self._json_cache, self._json_cache,
......
...@@ -7,7 +7,7 @@ from future import Future ...@@ -7,7 +7,7 @@ from future import Future
from operator import itemgetter from operator import itemgetter
from platform_util import GetPlatforms from platform_util import GetPlatforms
from docs_server_utils import MarkLast from docs_server_utils import MarkFirstAndLast, MarkLast
class APIListDataSource(DataSource): class APIListDataSource(DataSource):
""" This class creates a list of chrome.* APIs and chrome.experimental.* APIs """ This class creates a list of chrome.* APIs and chrome.experimental.* APIs
...@@ -31,6 +31,24 @@ class APIListDataSource(DataSource): ...@@ -31,6 +31,24 @@ class APIListDataSource(DataSource):
APIListDataSource, category=self._platform_bundle.GetIdentity()) APIListDataSource, category=self._platform_bundle.GetIdentity())
def _GenerateAPIDict(self): def _GenerateAPIDict(self):
def make_list_for_content_scripts():
content_script_apis = self._platform_bundle.GetAPIModels(
'extensions').GetContentScriptAPIs().Get()
content_script_apis_list = [csa.__dict__ for api_name, csa
in content_script_apis.iteritems()
if self._platform_bundle.GetAPICategorizer(
'extensions').IsDocumented(api_name)]
content_script_apis_list.sort(key=itemgetter('name'))
for csa in content_script_apis_list:
restricted_nodes = csa['restrictedTo']
if restricted_nodes:
restricted_nodes.sort(key=itemgetter('node'))
MarkFirstAndLast(restricted_nodes)
else:
del csa['restrictedTo']
return content_script_apis_list
def make_dict_for_platform(platform): def make_dict_for_platform(platform):
platform_dict = { platform_dict = {
'chrome': {'stable': [], 'beta': [], 'dev': [], 'trunk': []}, 'chrome': {'stable': [], 'beta': [], 'dev': [], 'trunk': []},
...@@ -77,8 +95,10 @@ class APIListDataSource(DataSource): ...@@ -77,8 +95,10 @@ class APIListDataSource(DataSource):
platform_dict[key] = apis platform_dict[key] = apis
return platform_dict return platform_dict
return dict((platform, make_dict_for_platform(platform)) api_dict = dict((platform, make_dict_for_platform(platform))
for platform in GetPlatforms()) for platform in GetPlatforms())
api_dict['contentScripts'] = make_list_for_content_scripts()
return api_dict
def _GetCachedAPIData(self): def _GetCachedAPIData(self):
data_future = self._object_store.Get('api_data') data_future = self._object_store.Get('api_data')
......
...@@ -7,6 +7,7 @@ import unittest ...@@ -7,6 +7,7 @@ import unittest
import json import json
from api_list_data_source import APIListDataSource from api_list_data_source import APIListDataSource
from api_models import ContentScriptAPI
from extensions_paths import CHROME_EXTENSIONS from extensions_paths import CHROME_EXTENSIONS
from server_instance import ServerInstance from server_instance import ServerInstance
from test_file_system import TestFileSystem from test_file_system import TestFileSystem
...@@ -28,7 +29,8 @@ def _ToTestFeatures(names): ...@@ -28,7 +29,8 @@ def _ToTestFeatures(names):
features = dict((name, { features = dict((name, {
'name': name, 'name': name,
'extension_types': platforms_to_extension_types(platforms), 'extension_types': platforms_to_extension_types(platforms),
}) for name, platforms in names) 'contexts': context
}) for name, platforms, context in names)
features['sockets.udp']['channel'] = 'dev' features['sockets.udp']['channel'] = 'dev'
return features return features
...@@ -46,17 +48,21 @@ def _ToTestAPISchema(names, apis): ...@@ -46,17 +48,21 @@ def _ToTestAPISchema(names, apis):
_TEST_API_FEATURES = _ToTestFeatures([ _TEST_API_FEATURES = _ToTestFeatures([
('alarms', ['apps', 'extensions']), ('alarms', ['apps', 'extensions'], ['content_script']),
('app.window', ['apps']), ('app.window', ['apps'], []),
('browserAction', ['extensions']), ('browserAction', ['extensions'], []),
('experimental.bluetooth', ['apps']), ('experimental.bluetooth', ['apps'], []),
('experimental.history', ['extensions'],), ('experimental.history', ['extensions'], []),
('experimental.power', ['apps', 'extensions']), ('experimental.power', ['apps', 'extensions'], []),
('infobars', ['extensions']), ('extension', ['extensions'], ['content_script']),
('something_internal', ['apps']), ('extension.onRequest', ['extensions'], ['content_script']),
('something_else_internal', ['extensions']), ('extension.sendNativeMessage', ['extensions'], []),
('storage', ['apps', 'extensions']), ('extension.sendRequest', ['extensions'], ['content_script']),
('sockets.udp', ['apps', 'extensions']) ('infobars', ['extensions'], []),
('something_internal', ['apps'], []),
('something_else_internal', ['extensions'], []),
('storage', ['apps', 'extensions'], []),
('sockets.udp', ['apps', 'extensions'], [])
]) ])
...@@ -67,6 +73,7 @@ _TEST_API_DATA = _ToTestAPIData([ ...@@ -67,6 +73,7 @@ _TEST_API_DATA = _ToTestAPIData([
('experimental.bluetooth', u'<code>experimental.bluetooth</code>'), ('experimental.bluetooth', u'<code>experimental.bluetooth</code>'),
('experimental.history', u'<code>experimental.history</code>'), ('experimental.history', u'<code>experimental.history</code>'),
('experimental.power', u'<code>experimental.power</code>'), ('experimental.power', u'<code>experimental.power</code>'),
('extension', u'<code>extension</code>'),
('infobars', u'<code>infobars</code>'), ('infobars', u'<code>infobars</code>'),
('something_internal', u'<code>something_internal</code>'), ('something_internal', u'<code>something_internal</code>'),
('something_else_internal', u'<code>something_else_internal</code>'), ('something_else_internal', u'<code>something_else_internal</code>'),
...@@ -82,6 +89,7 @@ _TEST_API_SCHEMA = [ ...@@ -82,6 +89,7 @@ _TEST_API_SCHEMA = [
('experimental.bluetooth', 'experimental_bluetooth.json'), ('experimental.bluetooth', 'experimental_bluetooth.json'),
('experimental.history', 'experimental_history.json'), ('experimental.history', 'experimental_history.json'),
('experimental.power', 'experimental_power.json'), ('experimental.power', 'experimental_power.json'),
('extension', 'extension.json'),
('infobars', 'infobars.json'), ('infobars', 'infobars.json'),
('something_internal', 'something_internal.json'), ('something_internal', 'something_internal.json'),
('something_else_internal', 'something_else_internal.json'), ('something_else_internal', 'something_else_internal.json'),
...@@ -117,6 +125,7 @@ _TEST_DATA = _ToTestAPISchema(_TEST_API_SCHEMA, { ...@@ -117,6 +125,7 @@ _TEST_DATA = _ToTestAPISchema(_TEST_API_SCHEMA, {
'browserAction.html', 'browserAction.html',
'experimental_history.html', 'experimental_history.html',
'experimental_power.html', 'experimental_power.html',
'extension.html',
'infobars.html', 'infobars.html',
'storage.html', 'storage.html',
'sockets_udp.html' 'sockets_udp.html'
...@@ -194,6 +203,11 @@ class APIListDataSourceTest(unittest.TestCase): ...@@ -194,6 +203,11 @@ class APIListDataSourceTest(unittest.TestCase):
'version': 21, 'version': 21,
'description': u'<code>browserAction</code>' 'description': u'<code>browserAction</code>'
}, },
{
'name': 'extension',
'version': 5,
'description': u'<code>extension</code>'
},
{ {
'name': 'infobars', 'name': 'infobars',
'version': 5, 'version': 5,
...@@ -227,5 +241,21 @@ class APIListDataSourceTest(unittest.TestCase): ...@@ -227,5 +241,21 @@ class APIListDataSourceTest(unittest.TestCase):
'last': True 'last': True
}], self._api_list.get('extensions').get('experimental')) }], self._api_list.get('extensions').get('experimental'))
def testContentScripts(self):
self.assertEqual([{
'name': 'alarms',
},
{
'name': 'extension',
'restrictedTo': [{
'node': 'onRequest',
'first': True
},
{
'node': 'sendRequest',
'last': True
}]
}], self._api_list.get('contentScripts'))
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -5,17 +5,42 @@ ...@@ -5,17 +5,42 @@
import posixpath import posixpath
from compiled_file_system import SingleFile, Unicode from compiled_file_system import SingleFile, Unicode
from docs_server_utils import StringIdentity
from extensions_paths import API_PATHS from extensions_paths import API_PATHS
from features_bundle import HasParentFeature from features_bundle import HasParent, GetParentName
from file_system import FileNotFoundError from file_system import FileNotFoundError
from future import Collect, Future from future import Collect, Future
from operator import itemgetter
from platform_util import PlatformToExtensionType from platform_util import PlatformToExtensionType
from schema_util import ProcessSchema from schema_util import ProcessSchema
from third_party.json_schema_compiler.json_schema import DeleteNodes from third_party.json_schema_compiler.json_schema import DeleteNodes
from third_party.json_schema_compiler.model import Namespace, UnixName from third_party.json_schema_compiler.model import Namespace, UnixName
class ContentScriptAPI(object):
'''Represents an API available to content scripts.
|name| is the name of the API or API node this object represents.
|restrictedTo| is a list of dictionaries representing the nodes
of this API that are available to content scripts, or None if the
entire API is available to content scripts.
'''
def __init__(self, name):
self.name = name
self.restrictedTo = None
def __eq__(self, o):
return self.name == o.name and self.restrictedTo == o.restrictedTo
def __ne__(self, o):
return not (self == o)
def __repr__(self):
return '<ContentScriptAPI name=%s, restrictedTo=%s>' % (name, restrictedTo)
def __str__(self):
return repr(self)
class APIModels(object): class APIModels(object):
'''Tracks APIs and their Models. '''Tracks APIs and their Models.
''' '''
...@@ -24,11 +49,13 @@ class APIModels(object): ...@@ -24,11 +49,13 @@ class APIModels(object):
features_bundle, features_bundle,
compiled_fs_factory, compiled_fs_factory,
file_system, file_system,
object_store_creator,
platform): platform):
self._features_bundle = features_bundle self._features_bundle = features_bundle
self._platform = PlatformToExtensionType(platform) self._platform = PlatformToExtensionType(platform)
self._model_cache = compiled_fs_factory.Create( self._model_cache = compiled_fs_factory.Create(
file_system, self._CreateAPIModel, APIModels, category=self._platform) file_system, self._CreateAPIModel, APIModels, category=self._platform)
self._object_store = object_store_creator.Create(APIModels)
@SingleFile @SingleFile
@Unicode @Unicode
...@@ -51,7 +78,7 @@ class APIModels(object): ...@@ -51,7 +78,7 @@ class APIModels(object):
# APIs; runtime.onConnectNative is not). # APIs; runtime.onConnectNative is not).
api_features = self._features_bundle.GetAPIFeatures().Get() api_features = self._features_bundle.GetAPIFeatures().Get()
return [name for name, feature in api_features.iteritems() return [name for name, feature in api_features.iteritems()
if not HasParentFeature(name, feature, api_features)] if not HasParent(name, feature, api_features)]
def GetModel(self, api_name): def GetModel(self, api_name):
# By default |api_name| is assumed to be given without a path or extension, # By default |api_name| is assumed to be given without a path or extension,
...@@ -97,6 +124,45 @@ class APIModels(object): ...@@ -97,6 +124,45 @@ class APIModels(object):
futures[0].Get() futures[0].Get()
return Future(callback=resolve) return Future(callback=resolve)
def GetContentScriptAPIs(self):
'''Creates a dict of APIs and nodes supported by content scripts in
this format:
{
'extension': '<ContentScriptAPI name='extension',
restrictedTo=[{'node': 'onRequest'}]>',
...
}
'''
content_script_apis_future = self._object_store.Get('content_script_apis')
api_features_future = self._features_bundle.GetAPIFeatures()
def resolve():
content_script_apis = content_script_apis_future.Get()
if content_script_apis is not None:
return content_script_apis
api_features = api_features_future.Get()
content_script_apis = {}
for name, feature in api_features.iteritems():
if 'content_script' not in feature.get('contexts', ()):
continue
parent = GetParentName(name, feature, api_features)
if parent is None:
content_script_apis[name] = ContentScriptAPI(name)
else:
# Creates a dict for the individual node.
node = {'node': name[len(parent) + 1:]}
if parent not in content_script_apis:
content_script_apis[parent] = ContentScriptAPI(parent)
if content_script_apis[parent].restrictedTo:
content_script_apis[parent].restrictedTo.append(node)
else:
content_script_apis[parent].restrictedTo = [node]
self._object_store.Set('content_script_apis', content_script_apis)
return content_script_apis
return Future(callback=resolve)
def Cron(self): def Cron(self):
futures = [self.GetModel(name) for name in self.GetNames()] futures = [self.GetModel(name) for name in self.GetNames()]
return Collect(futures, except_pass=(FileNotFoundError, ValueError)) return Collect(futures, except_pass=(FileNotFoundError, ValueError))
......
...@@ -66,6 +66,7 @@ class APIModelsTest(unittest.TestCase): ...@@ -66,6 +66,7 @@ class APIModelsTest(unittest.TestCase):
self._api_models = APIModels(features_bundle, self._api_models = APIModels(features_bundle,
compiled_fs_factory, compiled_fs_factory,
self._mock_file_system, self._mock_file_system,
object_store_creator,
'extensions') 'extensions')
def testGetNames(self): def testGetNames(self):
......
application: chrome-apps-doc application: chrome-apps-doc
version: 3-32-0 version: 3-33-0
runtime: python27 runtime: python27
api_version: 1 api_version: 1
threadsafe: false threadsafe: false
......
...@@ -2,4 +2,4 @@ cron: ...@@ -2,4 +2,4 @@ cron:
- description: Repopulates all cached data. - description: Repopulates all cached data.
url: /_cron url: /_cron
schedule: every 5 minutes schedule: every 5 minutes
target: 3-32-0 target: 3-33-0
...@@ -33,12 +33,24 @@ def StringIdentity(first, *more): ...@@ -33,12 +33,24 @@ def StringIdentity(first, *more):
identity = encode(identity + m) identity = encode(identity + m)
return identity[:8] return identity[:8]
def MarkFirst(dicts):
'''Adds a property 'first' == True to the first element in a list of dicts.
'''
if len(dicts) > 0:
dicts[0]['first'] = True
def MarkLast(dicts): def MarkLast(dicts):
'''Adds a property 'last' == True to the last element in a list of dicts. '''Adds a property 'last' == True to the last element in a list of dicts.
''' '''
if len(dicts) > 0: if len(dicts) > 0:
dicts[-1]['last'] = True dicts[-1]['last'] = True
def MarkFirstAndLast(dicts):
'''Marks the first and last element in a list of dicts.
'''
MarkFirst(dicts)
MarkLast(dicts)
def ToUnicode(data): def ToUnicode(data):
'''Returns the str |data| as a unicode object. It's expected to be utf8, but '''Returns the str |data| as a unicode object. It's expected to be utf8, but
there are also latin-1 encodings in there for some reason. Fall back to that. there are also latin-1 encodings in there for some reason. Fall back to that.
......
...@@ -20,7 +20,7 @@ _MANIFEST_FEATURES = '_manifest_features.json' ...@@ -20,7 +20,7 @@ _MANIFEST_FEATURES = '_manifest_features.json'
_PERMISSION_FEATURES = '_permission_features.json' _PERMISSION_FEATURES = '_permission_features.json'
def HasParentFeature(feature_name, feature, all_feature_names): def HasParent(feature_name, feature, all_feature_names):
# A feature has a parent if it has a . in its name, its parent exists, # A feature has a parent if it has a . in its name, its parent exists,
# and it does not explicitly specify that it has no parent. # and it does not explicitly specify that it has no parent.
return ('.' in feature_name and return ('.' in feature_name and
...@@ -28,11 +28,11 @@ def HasParentFeature(feature_name, feature, all_feature_names): ...@@ -28,11 +28,11 @@ def HasParentFeature(feature_name, feature, all_feature_names):
not feature.get('noparent')) not feature.get('noparent'))
def GetParentFeature(feature_name, feature, all_feature_names): def GetParentName(feature_name, feature, all_feature_names):
'''Returns the name of the parent feature, or None if it does not have a '''Returns the name of the parent feature, or None if it does not have a
parent. parent.
''' '''
if not HasParentFeature(feature_name, feature, all_feature_names): if not HasParent(feature_name, feature, all_feature_names):
return None return None
return feature_name.rsplit('.', 1)[0] return feature_name.rsplit('.', 1)[0]
...@@ -122,7 +122,7 @@ def _ResolveFeature(feature_name, ...@@ -122,7 +122,7 @@ def _ResolveFeature(feature_name,
channel = value.get('channel') channel = value.get('channel')
dependencies = value.get('dependencies', []) dependencies = value.get('dependencies', [])
parent = GetParentFeature( parent = GetParentName(
feature_name, value, features_map[features_type]['all_names']) feature_name, value, features_map[features_type]['all_names'])
if parent is not None: if parent is not None:
# The parent data needs to be resolved so the child can inherit it. # The parent data needs to be resolved so the child can inherit it.
......
...@@ -53,6 +53,7 @@ class PlatformBundle(object): ...@@ -53,6 +53,7 @@ class PlatformBundle(object):
self.GetFeaturesBundle(platform), self.GetFeaturesBundle(platform),
self._compiled_fs_factory, self._compiled_fs_factory,
self._host_fs_at_trunk, self._host_fs_at_trunk,
self._object_store_creator,
platform) platform)
return self._platform_data[platform].api_models return self._platform_data[platform].api_models
......
...@@ -10,7 +10,12 @@ CANNED_TRUNK_FS_DATA = { ...@@ -10,7 +10,12 @@ CANNED_TRUNK_FS_DATA = {
'_api_features.json': json.dumps({ '_api_features.json': json.dumps({
'add_rules_tester': { 'dependencies': ['permission:add_rules_tester'] }, 'add_rules_tester': { 'dependencies': ['permission:add_rules_tester'] },
'ref_test': { 'dependencies': ['permission:ref_test'] }, 'ref_test': { 'dependencies': ['permission:ref_test'] },
'tester': { 'dependencies': ['permission:tester', 'manifest:tester'] } 'tester': {
'dependencies': ['permission:tester', 'manifest:tester'],
'contexts': ['content_script']
},
'tester.test1': {'contexts': ['content_script']},
'tester.test2': {}
}), }),
'_manifest_features.json': json.dumps({'tester': {}, 'ref_test': {}}), '_manifest_features.json': json.dumps({'tester': {}, 'ref_test': {}}),
'_permission_features.json': json.dumps({ '_permission_features.json': json.dumps({
......
/*! Copyright 2014 The Chromium Authors. All rights reserved. /*! Copyright 2014 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
*/article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;font-size:100%;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}button,input,select,textarea{font-family:sans-serif}body{margin:0}a{background:transparent}a:focus{outline:thin dotted}a:active,a:hover{outline:0}p,pre{margin:1.5em 0}blockquote{margin:1.5em 40px}h1{font-size:2em;line-height:1.5em;margin-top:0.75em;margin-bottom:0.75em}h2{font-size:1.5em;line-height:2em;margin-top:1em;margin-bottom:1em}h3{font-size:1.17em;line-height:1.28205em;margin-top:1.28205em;margin-bottom:1.28205em}h4{font-size:1em;line-height:1.5em;margin-top:1.5em;margin-bottom:1.5em}h5{font-size:0.83em;line-height:1.80723em;margin-top:1.80723em;margin-bottom:1.80723em}h6{font-size:0.67em;line-height:2.23881em;margin-top:2.23881em;margin-bottom:2.23881em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace, serif;_font-family:'courier new', monospace;font-size:1em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}dl,menu,ol,ul{margin:1.5em 0}dd{margin:0 0 0 40px}menu,ol,ul{padding:0 0 0 40px}nav ul,nav ol{list-style:none;list-style-image:none}img{border:0;-ms-interpolation-mode:bicubic}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{margin:0 2px;border-color:#c0c0c0;border-top-style:solid;border-top-width:0.0625em;padding-top:0.4625em;border-bottom-style:solid;border-bottom-width:0.0625em;padding-bottom:0.9125em;border-left-style:solid;border-left-width:0.0625em;padding-left:0.875em;border-right-style:solid;border-right-width:0.0625em;padding-right:0.875em}legend{border:0;padding:0;*margin-left:-7px}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;*overflow:visible}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;*height:13px;*width:13px}input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}* html{font-size:100%}html{font-size:16px;line-height:1.5em}* html{font-size:100%}html{font-size:16px;line-height:1.5em}.g-section:after{content:".";display:block;height:0;clear:both;visibility:hidden}.g-unit .g-section:after{clear:none}.g-unit .g-section{width:100%;overflow:hidden}.g-section,.g-unit{zoom:1}.g-split>.g-unit{float:right;text-align:right}.g-split>.g-first{float:left;text-align:left}.g-tpl-160 .g-unit,.g-unit .g-tpl-160 .g-unit,.g-unit .g-unit .g-tpl-160 .g-unit,.g-unit .g-unit .g-unit .g-tpl-160 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-tpl-160 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-160 .g-unit{display:block;margin:0 0 0 160px;width:auto;float:none}.g-tpl-160 .g-first,.g-unit .g-tpl-160 .g-first,.g-unit .g-unit .g-tpl-160 .g-first,.g-unit .g-unit .g-unit .g-tpl-160 .g-first,.g-unit .g-unit .g-unit .g-unit .g-tpl-160 .g-first,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-160 .g-first{display:block;margin:0;width:160px;float:left}.g-tpl-25-75 .g-unit,.g-unit .g-tpl-25-75 .g-unit,.g-unit .g-unit .g-tpl-25-75 .g-unit,.g-unit .g-unit .g-unit .g-tpl-25-75 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-tpl-25-75 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-25-75 .g-unit{width:74.999%;float:right;display:inline;margin:0}.g-tpl-25-75 .g-first,.g-unit .g-tpl-25-75 .g-first,.g-unit .g-unit .g-tpl-25-75 .g-first,.g-unit .g-unit .g-unit .g-tpl-25-75 .g-first,.g-unit .g-unit .g-unit .g-unit .g-tpl-25-75 .g-first,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-25-75 .g-first{width:24.999%;float:left;display:inline;margin:0}.g-tpl-75-25 .g-unit,.g-unit .g-tpl-75-25 .g-unit,.g-unit .g-unit .g-tpl-75-25 .g-unit,.g-unit .g-unit .g-unit .g-tpl-75-25 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-tpl-75-25 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-75-25 .g-unit{width:24.999%;float:right;display:inline;margin:0}.g-tpl-75-25 .g-first,.g-unit .g-tpl-75-25 .g-first,.g-unit .g-unit .g-tpl-75-25 .g-first,.g-unit .g-unit .g-unit .g-tpl-75-25 .g-first,.g-unit .g-unit .g-unit .g-unit .g-tpl-75-25 .g-first,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-75-25 .g-first{width:74.999%;float:left;display:inline;margin:0}.g-tpl-33-67 .g-unit,.g-unit .g-tpl-33-67 .g-unit,.g-unit .g-unit .g-tpl-33-67 .g-unit,.g-unit .g-unit .g-unit .g-tpl-33-67 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-tpl-33-67 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-33-67 .g-unit{width:66.999%;float:right;display:inline;margin:0}.g-tpl-33-67 .g-first,.g-unit .g-tpl-33-67 .g-first,.g-unit .g-unit .g-tpl-33-67 .g-first,.g-unit .g-unit .g-unit .g-tpl-33-67 .g-first,.g-unit .g-unit .g-unit .g-unit .g-tpl-33-67 .g-first,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-33-67 .g-first{width:32.999%;float:left;display:inline;margin:0}.g-tpl-67-33 .g-unit,.g-unit .g-tpl-67-33 .g-unit,.g-unit .g-unit .g-tpl-67-33 .g-unit,.g-unit .g-unit .g-unit .g-tpl-67-33 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-tpl-67-33 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-67-33 .g-unit{width:32.999%;float:right;display:inline;margin:0}.g-tpl-67-33 .g-first,.g-unit .g-tpl-67-33 .g-first,.g-unit .g-unit .g-tpl-67-33 .g-first,.g-unit .g-unit .g-unit .g-tpl-67-33 .g-first,.g-unit .g-unit .g-unit .g-unit .g-tpl-67-33 .g-first,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-67-33 .g-first{width:66.999%;float:left;display:inline;margin:0}.g-tpl-50-50 .g-unit,.g-unit .g-tpl-50-50 .g-unit,.g-unit .g-unit .g-tpl-50-50 .g-unit,.g-unit .g-unit .g-unit .g-tpl-50-50 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-tpl-50-50 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-50-50 .g-unit{width:49.999%;float:right;display:inline;margin:0}.g-tpl-50-50 .g-first,.g-unit .g-tpl-50-50 .g-first,.g-unit .g-unit .g-tpl-50-50 .g-first,.g-unit .g-unit .g-unit .g-tpl-50-50 .g-first,.g-unit .g-unit .g-unit .g-unit .g-tpl-50-50 .g-first,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-50-50 .g-first{width:49.999%;float:left;display:inline;margin:0}.g-tpl-nest .g-unit{float:left;width:auto;display:inline;margin:0}.g-tpl-nest-alt .g-unit{float:right;width:auto;display:inline;margin:0}.g-content{margin-right:30px}.g-last .g-content{margin-right:0}@media only screen and (max-width: 580px){.g-unit.g-unit{float:none !important}.g-content{margin-right:0}}*{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html,body{overflow-x:hidden;overflow-y:auto}img{max-width:100%}#gc-container{max-width:870px;margin:auto;width:90%}#gc-pagecontent>.g-section{margin:40px 0}main{margin-bottom:50px;position:relative}footer[role="contentinfo"]{padding:40px 0 50px}@media only screen and (max-width: 580px){#gc-container{width:auto}#gc-pagecontent{margin:auto;width:90%}#gc-pagecontent>.g-section{margin:20px 0}footer[role="contentinfo"]{padding:20px 30px}}@media only screen and (min-width: 581px) and (max-width: 990px){#gc-container{width:95%}}figure{margin:20px 0}figure img{border:1px solid #dbdbdb}table{width:100%;border-collapse:collapse;margin:2em 0;line-height:1.5em}table caption{margin-bottom:1em;text-align:left;font-weight:bold}th{border:1px solid #dbdbdb;font-weight:bold;background:#e8e8e8}tr{border-bottom:1px solid #dbdbdb}table+tr{border-top:1px solid #dbdbdb}td,th{padding:1em 1.5em;text-align:left;border:1px solid #dbdbdb}pre{background-color:#f7f7f7;box-shadow:0 2px 4px rgba(0,0,0,0.15),0 0 3px rgba(0,0,0,0.15);margin:1em 0 0 0;padding:.99em;position:relative;overflow-x:auto;word-wrap:normal;white-space:pre;font-size:0.95em;line-height:1.8em}pre a{text-decoration:underline !important}pre b{background:yellow;font-weight:normal}pre strike{text-decoration:none;background-image:linear-gradient(transparent 7px,#cc1f1f 7px,#cc1f1f 9px,transparent 9px)}pre[data-filename]::after{visibility:hidden}pre[data-filename]:hover::after{visibility:visible}.element-invisible{position:absolute !important;height:1px;width:1px;overflow:hidden;clip:rect(1px 1px 1px 1px);clip:rect(1px, 1px, 1px, 1px)}.hidden{display:none}.label{color:inherit;text-transform:uppercase;margin-bottom:5px;font-size:11.2px;font-weight:bold}.published{font-size:11.2px;font-style:italic;color:#bebebe;line-height:16.8px}.description{margin:20px 0}.description:last-child{margin-bottom:0}.span-full{background:#f5f5f5;position:relative;padding:3em 0}.span-full::before,.span-full::after{content:'';height:100%;width:100%;top:0;position:absolute;background:#f5f5f5;z-index:-1}.span-full::before{left:-100%}.span-full::after{left:100%}.button{background:#0370ea;background-image:linear-gradient(top, #008dfd 0%,#0370ea 100%);border:1px solid #076bd2;border-radius:3px;color:#fff !important;display:inline-block;font-size:13px;font-weight:700;line-height:1.3;padding:5px 20px;text-align:center;text-decoration:none !important;text-shadow:1px 1px 1px #076bd2}.button:hover{background-image:linear-gradient(top, #008dfd 30%,#0370ea 100%);cursor:pointer}.button a{color:inherit !important}.button-alt{background:#eee;background-image:linear-gradient(bottom, #dcdcdc 46%,#fafafa 87%);border:1px solid #d6d6d6;border-radius:3px;color:#333 !important;display:inline-block;font-size:12px;font-weight:700;line-height:24px;padding:0 15px;text-align:center;text-decoration:none !important;text-shadow:none}.button-alt:hover{background-image:linear-gradient(bottom, #dcdcdc 20%,#fafafa 87%);cursor:pointer}.google-button{background-color:#f5f5f5;border-radius:2px 0 0 0;border:1px solid rgba(0,0,0,0.1);padding:5px 12px;text-align:center;white-space:nowrap}.google-button:hover{border-color:#c6c6c6;box-shadow:0 -1px 1px rgba(0,0,0,0.1)}.google-button:active{background-color:#f1f1f1;box-shadow:inset 0 0px 2px rgba(0,0,0,0.2)}.screenshot,.screenshot img{margin:1em 0}.video-container{position:relative;padding-bottom:56.25%;padding-top:30px;height:0;overflow:hidden;margin:0 0 20px 0}.video-container iframe,.video-container object,.video-container embed{position:absolute;top:0;left:0;width:100%;height:100%}p.note,p.caution,p.warning,div.note,div.caution,div.warning,aside.note,aside.caution,aside.warning{background-color:#f5f5f5;border-bottom:1px solid;border-top:1px solid;overflow:hidden;width:85%;margin:auto;padding:1em}p.note,div.note,aside.note{border-color:#36C}p.caution,div.caution,aside.caution{border-color:#FC3}p.warning,div.warning,aside.warning{border-color:#A03}p.warning em,p.warning strong,div.warning em,div.warning strong,aside.warning em,aside.warning strong{color:#A03}.permalink{display:none;margin-left:5px}.has-permalink:hover .permalink{display:initial}.no-permalink .permalink{display:none !important}#gc-footer .links a{margin-right:20px}#gc-footer #cc-info{font-size:11.2px}#social-buttons{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-box-pack:1;-webkit-justify-content:flex-end;-moz-justify-content:flex-end;-ms-justify-content:flex-end;-o-justify-content:flex-end;justify-content:flex-end;-webkit-box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center}#social-buttons>*{margin-left:10px}#social-buttons img{margin:-4px 0 0 1px}@media only screen and (max-width: 580px){.more-section .g-last .g-content{padding-bottom:0;border:none}.more-section .g-content{border:1px solid #dbdbdb;border-width:0 0 1px 0;padding-bottom:20px;margin-bottom:20px}#gc-footer .links a{display:inline-block}}#scroll-to-top,#send-feedback{border-bottom:none;bottom:0;position:fixed;z-index:5}#scroll-to-top{border-left:0;left:0}#send-feedback{border-right:0;right:0}html{font-family:"Open Sans",Arial,"Lucida Grande",sans-serif;color:#777}body{font-size:13px;color:#777}h1,h2,h3,h4,h5,h6{font-family:"Open Sans",Arial,"Lucida Grande",sans-serif;font-weight:600;color:#000}h1,h2{font-weight:300}h1{font-size:2.625em;line-height:1.14286em}h1+h1{margin-top:0em}h2{font-size:1.875em;line-height:1.6em;margin-top:1.6em;margin-bottom:0em;line-height:1.12em}h3{font-size:1.125em;line-height:1.33333em;margin-top:1.33333em;margin-bottom:0.53333em;line-height:1.12em}h4{font-size:1.1em;line-height:1.36364em;margin-top:0em;margin-bottom:0em}h5{font-size:1em;line-height:1.5em;margin-top:0em;margin-bottom:0em}h6{font-size:1em;line-height:1.5em;margin-top:0em;margin-bottom:0em}p{margin:1.5em 0}p.noindent,p.caption p{text-indent:0}p.caption{text-align:left}.lightbox p.caption{color:#fff}a,a:link,a:visited{color:#39c;font-weight:bold;text-decoration:none;word-wrap:break-word;transition:opacity 0.3s ease 0s}a:hover,a:focus,a:link:hover,a:link:focus,a:visited:hover,a:visited:focus{color:#39f}a.section-anchor{display:block;padding-top:3.33em}footer[role="contentinfo"]{font-size:0.84615385em}footer[role="contentinfo"] a,footer[role="contentinfo"] a:link,footer[role="contentinfo"] a:visited{color:#999;font-weight:normal;font-weight:600;text-decoration:none;word-wrap:break-word}footer[role="contentinfo"] a:hover,footer[role="contentinfo"] a:focus,footer[role="contentinfo"] a:link:hover,footer[role="contentinfo"] a:link:focus,footer[role="contentinfo"] a:visited:hover,footer[role="contentinfo"] a:visited:focus{color:#39f}em{padding-right:2px}img{vertical-align:middle}figcaption{font-family:"Open Sans",Arial,"Lucida Grande",sans-serif;color:#aaa}blockquote{margin:0.75em 0.8em}cite{margin:0.75em 0.8em;color:#c3c3c3;font-style:normal}canvas{background:#fff;margin:1.5em 0}.code,code,pre{color:#080;font-family:"Source Code Pro",sans-serif}a>code{color:#39c}pre{margin:2em 0;word-wrap:break-word;position:relative}pre[data-filename]::after{content:attr(data-filename);background-color:#aaa;color:#fff;padding:2px 12px;position:absolute;right:0;top:0}pre a{text-decoration:underline}.static-code-container{line-height:1em;clear:both}code,kbd,samp{margin:1.5em 0;line-height:1em}dl,menu,ol,ul,.item-list ul{margin:0.8em 0}ul{padding-left:1.28em}ol{padding-left:1.52em}hr{height:1px;border:0;border-bottom:1px solid #dbdbdb;padding-bottom:-1px;margin:1.5em 0}.capitalize{text-transform:uppercase}[data-list-item]{display:list-item}.uncapitalize::first-letter{text-transform:lowercase}.capitalize::first-letter{text-transform:uppercase}.kbd{background-color:#f7f7f7;border:1px solid #ccc;color:#333;font-size:11px;line-height:1.4;text-shadow:0 1px 0 #fff;font-family:Arial,Helvetica,sans-serif;display:inline-block;padding:0.1em 0.6em;margin:0 0.1em;white-space:nowrap;box-shadow:0 1px 0px rgba(0,0,0,0.2),0 0 0 2px #fff inset;border-radius:3px}#topnav{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;height:64px;position:relative}#logo{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-webkit-user-select:none;-moz-user-select:none;-o-user-select:none;-ms-user-select:none;user-select:none}#logo a{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;color:#828282;font-size:2em;font-weight:400;letter-spacing:-1px}#logo a img{margin-bottom:-4px;height:40px;width:123px}#logo .collase-icon{display:none;background:url("../../images/burger-icon.png") 50% 100% no-repeat;background-size:cover;width:20px;height:20px}#logo .collase-icon.active{background-position:50% 0}#fatnav{height:100%;display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-box-pack:1;-webkit-justify-content:flex-end;-moz-justify-content:flex-end;-ms-justify-content:flex-end;-o-justify-content:flex-end;justify-content:flex-end;-webkit-box-flex:1;-webkit-flex:1;-moz-flex:1;-ms-flex:1;-o-flex:1;flex:1;white-space:nowrap}#fatnav li{list-style:none}#fatnav>ul{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;padding:0;margin:0}#fatnav .toplevel{color:#aaa;font-weight:600;text-transform:uppercase;-webkit-user-select:none;-moz-user-select:none;-o-user-select:none;-ms-user-select:none;user-select:none}#fatnav .toplevel::after{content:'';background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPJJREFUeNpiyc/Pn8XAwDATiM8yEAaMQBwBxHxMQMIdiE8D8Vog1sGjyQGqbhkQK4A0PoKaFATEF4F4MRCrImnQBuJtQLwfiI2hYk9AGl2AuB2I/wAxiB8DxNeAeA4QzwXiS0DsCdXwHIj9gHgqSOFPIK4CYksgvgJVwALEyUCcBDWMAeoSkO2bGZAEQeAM1CmtUNth4BkQ+wJxHBC/hwkyoQXALyCuAWILIL4MxIugAbYFI3iNZ54BR4fNtcXo0QEy9B+ywBGtWMzoAAquBWLk6EDXhBIdLNDokINGRwBQAUiiCYhvI0VHN1LIjpjoAAgwAMoSTlKlzAY4AAAAAElFTkSuQmCC) no-repeat;background-size:9px;display:inline-block;height:5px;width:14px;margin-left:10px;margin-bottom:2px}#fatnav .pillar{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;padding:0 20px;cursor:pointer;z-index:1002}#fatnav .expandee{display:none;position:absolute;z-index:1001;left:0;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;background-color:#f5f5f5;padding:20px 0;cursor:initial;margin:0}#fatnav .expandee a{font-weight:600;padding:0.5em 0;display:block;color:#828282}#fatnav .expandee a:hover{background-image:linear-gradient(205deg, rgba(229,229,229,0.7) 0%,rgba(233,233,233,0.7) 20%,rgba(244,244,244,0.7) 100%)}#fatnav .expandee li{white-space:nowrap}#fatnav .expandee li.submenu{color:#333;font-size:1.1em;font-weight:bold;-webkit-box-flex:1;-webkit-flex:1;-moz-flex:1;-ms-flex:1;-o-flex:1;flex:1}#fatnav .expandee li.submenu.active{background-image:linear-gradient(205deg, rgba(229,229,229,0.7) 0%,rgba(233,233,233,0.7) 20%,rgba(244,244,244,0.7) 100%)}#fatnav .expandee li.submenu>ul{font-size:0.8em;padding:15px 0 0 0;margin:0}#fatnav .expandee li.submenu .category{border-bottom:1px solid #e8e8e8}#fatnav .expandee li.submenu .category:last-child{border:none}#fatnav .expandee li.submenu .category a{overflow:hidden;text-overflow:ellipsis}#fatnav .expandee li.submenu .category>ul{display:none}#fatnav .expandee li.submenu .category ul{padding:0}#search{display:-webkit-inline-flex;display:-moz-inline-flex;display:-ms-inline-flex;display:-o-inline-flex;display:inline-flex;-webkit-align-self:stretch;-moz-align-self:stretch;-ms-align-self:stretch;-o-align-self:stretch;align-self:stretch;-webkit-box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;width:auto;padding:0 20px;cursor:pointer}#search img{height:16px;width:16px;-webkit-user-select:none;-moz-user-select:none;-o-user-select:none;-ms-user-select:none;user-select:none}#search .expandee{padding:20px}#search .expandee input[type="search"]{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;background:url("../../images/search.png") no-repeat 15px 55%;background-size:20px;background-color:white;border:1px solid #dbdbdb;padding:10px 10px 10px 40px;font-size:1.4em;-webkit-box-flex:1;-webkit-flex:1;-moz-flex:1;-ms-flex:1;-o-flex:1;flex:1;font-family:inherit;font-weight:300}@media only screen and (min-width: 580px){#topnav{padding:15px 0 0}#fatnav .pillar.active{background:#f5f5f5 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAyCAMAAABI+VrBAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALFQTFRF/////f39/v7+/Pz8+/v7+fn56+vr+vr69PT09vb28/Pz9fX1xcXF9/f3+Pj45+fn8PDwycnJ7+/v6enpzc3N19fX8fHx8vLy7u7u6Ojo7Ozs3Nzc5OTk7e3t4uLi2dnZ39/fxsbG29vb0dHR3d3d4ODg4+Pj6urqyMjI09PT5eXl0NDQ1dXV2NjYysrKx8fH5ubmzs7O3t7exMTE4eHh2tray8vLz8/PzMzM1NTU1tbWhgtdWwAAAOFJREFUeNok0NWSxCAURdFDhCQkMx3tuLe7jP//h829NC+rqIKNAK8hhGEQjmUyrm+ziVTs50O6jkA6b+J3gSCqpWfiGZxL1yKyhbIQEDQLxj7xTYy7SXoCY1RXbwLXy6OgfdevIbYFdulHaBuI7t3SIY5Nbhm4zAdF/Ow5gvTEEaR/W49Ov2eSIvjuW+Y4tdTCXHML+1XI/A7cwmmdM1nHLZwbl+kPPj9lunELq5LuRWy5hUFyC+uKI+hazabgCJpYcws5gsXS5F8qc02i9C9Jn9ejelHoMkJdhrJ5xb8AAwBmihB0TS21nQAAAABJRU5ErkJggg==) no-repeat right 0}#fatnav .pillar.active .toplevel::after{background-position:0% -5px}#fatnav .pillar.active .expandee{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-box-orient:vertical;-webkit-flex-direction:row;-moz-flex-direction:row;-ms-flex-direction:row;-o-flex-direction:row;flex-direction:row}#fatnav .pillar.active .expandee::after{position:absolute;background-image:linear-gradient(bottom, rgba(255,255,255,0) 0%,rgba(211,211,211,0.5) 25%,#d3d3d3 50%,rgba(211,211,211,0.5) 75%,rgba(255,255,255,0) 100%);right:0;top:0;content:'';width:1px !important;height:100%}#fatnav .pillar .expandee{min-height:400px;font-size:0.9em;box-shadow:0 3px 4px rgba(0,0,0,0.12);top:64px}#fatnav .pillar .expandee .submenu{padding:0 20px;border-right:1px solid #e8e8e8}#fatnav .pillar .expandee .submenu:last-child{border:none}#search{margin-right:-4px}#search.active{background:#f5f5f5 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAyCAMAAABI+VrBAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALFQTFRF/////f39/v7+/Pz8+/v7+fn56+vr+vr69PT09vb28/Pz9fX1xcXF9/f3+Pj45+fn8PDwycnJ7+/v6enpzc3N19fX8fHx8vLy7u7u6Ojo7Ozs3Nzc5OTk7e3t4uLi2dnZ39/fxsbG29vb0dHR3d3d4ODg4+Pj6urqyMjI09PT5eXl0NDQ1dXV2NjYysrKx8fH5ubmzs7O3t7exMTE4eHh2tray8vLz8/PzMzM1NTU1tbWhgtdWwAAAOFJREFUeNok0NWSxCAURdFDhCQkMx3tuLe7jP//h829NC+rqIKNAK8hhGEQjmUyrm+ziVTs50O6jkA6b+J3gSCqpWfiGZxL1yKyhbIQEDQLxj7xTYy7SXoCY1RXbwLXy6OgfdevIbYFdulHaBuI7t3SIY5Nbhm4zAdF/Ow5gvTEEaR/W49Ov2eSIvjuW+Y4tdTCXHML+1XI/A7cwmmdM1nHLZwbl+kPPj9lunELq5LuRWy5hUFyC+uKI+hazabgCJpYcws5gsXS5F8qc02i9C9Jn9ejelHoMkJdhrJ5xb8AAwBmihB0TS21nQAAAABJRU5ErkJggg==) no-repeat right 0}#search.active .expandee{display:block;top:64px}}@media only screen and (max-width: 580px){#topnav{-webkit-box-orient:vertical;-webkit-flex-direction:column;-moz-flex-direction:column;-ms-flex-direction:column;-o-flex-direction:column;flex-direction:column;height:auto}#fatnav{width:100%;max-height:0;overflow:hidden;background:#f5f5f5}#fatnav.active{max-height:5000px}#fatnav>ul{-webkit-box-flex:1;-webkit-flex:1;-moz-flex:1;-ms-flex:1;-o-flex:1;flex:1;-webkit-box-orient:vertical;-webkit-flex-direction:column;-moz-flex-direction:column;-ms-flex-direction:column;-o-flex-direction:column;flex-direction:column}#fatnav .toplevel{width:100%;height:50px;-webkit-box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-webkit-box-pack:1;-webkit-justify-content:center;-moz-justify-content:center;-ms-justify-content:center;-o-justify-content:center;justify-content:center;display:-webkit-inline-flex;display:-moz-inline-flex;display:-ms-inline-flex;display:-o-inline-flex;display:inline-flex}#fatnav .pillar{-webkit-box-orient:vertical;-webkit-flex-direction:column;-moz-flex-direction:column;-ms-flex-direction:column;-o-flex-direction:column;flex-direction:column;padding:0;border-bottom:1px solid #dbdbdb}#fatnav .pillar.active .expandee{display:initial}#fatnav .expandee{position:relative;padding:0;background-color:rgba(229,229,229,0.7)}#fatnav .expandee li.submenu{padding:10px 15px}#fatnav .expandee li.submenu:not(:last-child){border-color:#ccc}#fatnav .expandee li.submenu>ul{background-color:inherit}#logo{height:50px;width:90%}#logo a{-webkit-box-flex:1;-webkit-flex:1;-moz-flex:1;-ms-flex:1;-o-flex:1;flex:1}#logo .collase-icon{display:initial}#search{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-webkit-box-ordinal-group:-1;-webkit-order:-1;-moz-order:-1;-ms-order:-1;-o-order:-1;order:-1;padding:15px 15px 0 15px}#search img{display:none}#search .expandee{display:block}}#gc-pagecontent .g-section h1,#gc-pagecontent .g-section h2,#gc-pagecontent .g-section h3{margin:0}#upcoming-events .screenshot,#featured .screenshot{margin-top:0}#upcoming-events article{border:1px solid #dbdbdb;border-width:0 0 1px 0;padding:20px 0}#upcoming-events article:first-child{padding-top:0}#upcoming-events article:last-child{padding-bottom:0;border:none}#site-sections{background-color:#f5f5f5;padding:20px;text-align:center}#site-sections h2{padding-top:20px}#site-sections h2::before{display:block;content:'';background:url("../../images/bucket-icons.png") 12px 50% no-repeat;width:100px;height:65px;background-size:cover;margin:auto;margin-bottom:20px}#site-sections h2.multidevice::before{background-position:-91px 50%}#site-sections h2.platform::before{background-position:-194px 50%}#developer-news{margin-top:4em}#developer-news .g-content{margin-right:20px}#developer-news h1{margin-bottom:40px !important}@media only screen and (min-width: 580px){#featured{padding-right:30px;padding-bottom:10px;border:1px solid #dbdbdb;border-width:0 1px 0 0}#featured img{margin-bottom:20px}}.pillar-content h1{font-size:42px}.pillar-content>.g-section{padding:3em 0}.pillar-content>.g-section:not(:last-of-type){border-bottom:1px solid #dbdbdb}.pillar-content>.g-section>h2{font-size:30px;margin-bottom:1.5em !important}.pillar-content .article-list article{position:relative;overflow:hidden;width:100%;padding:1.9em;background-color:#f5f5f5;box-shadow:0 2px 4px rgba(0,0,0,0.15),0 0 3px rgba(0,0,0,0.15);line-height:1.5em;margin-bottom:1.5em}.pillar-content .article-list article.new::after{content:'new';background:#2e82c9;position:absolute;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg);top:-4px;right:-20px;color:white;font-size:0.9em;width:60px;text-align:center;padding-top:8px}.pillar-content .article-list article p{font-weight:300}.pillar-content #further-resources .g-content h2::before{display:inline-block;content:'';background:url("../../images/further-resources-icons.svg") 0 50% no-repeat;width:50px;height:43px;background-size:cover;margin:auto;margin-bottom:5px;vertical-align:middle}.pillar-content #further-resources .g-content h2.school::before{background-position:0 50%}.pillar-content #further-resources .g-content h2.chat::before{background-position:-54px 50%}.pillar-content #further-resources .g-content h2.puzzle::before{background-position:-108px 50%}@media only screen and (max-width: 580px){.pillar-content>.g-section{padding:2em 0}}@media only screen and (min-width: 580px){.pillar-content .article-list{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-flex-wrap:wrap;-moz-flex-wrap:wrap;-ms-flex-wrap:wrap;-o-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:1;-webkit-justify-content:space-between;-moz-justify-content:space-between;-ms-justify-content:space-between;-o-justify-content:space-between;justify-content:space-between;-webkit-box-align:stretch;-webkit-align-items:stretch;-moz-align-items:stretch;-ms-align-items:stretch;-o-align-items:stretch;align-items:stretch}.pillar-content .article-list article{-webkit-box-flex:auto;-webkit-flex:auto;-moz-flex:auto;-ms-flex:auto;-o-flex:auto;flex:auto;margin-right:1.5em;width:45%}.pillar-content .article-list article:nth-child(2n),.pillar-content .article-list article:last-of-type{margin-right:0}}@media only screen and (min-width: 990px){.pillar-content .article-list article{width:30%}.pillar-content .article-list article:nth-child(2n){margin-right:1.5em}.pillar-content .article-list article:nth-child(3n),.pillar-content .article-list article:last-of-type{margin-right:0}}@supports not (flex-wrap: wrap){.pillar-content .article-list{display:block}@media only screen and (min-width: 580px){.pillar-content .article-list article{flex:none;float:left;width:48%}}@media only screen and (min-width: 990px){.pillar-content .article-list article{width:31.8058%}}}.load-more-articles{overflow:hidden;*zoom:1;margin:2em auto 0.3em;text-align:center;width:100%}.load-more-articles a,.load-more-articles a:hover{color:#000;transition:opacity 0.3s ease 0s}.nav-arrow{background-size:48px 48px;background:top center no-repeat;display:inline-block;opacity:0.5;transition:opacity 0.3s ease 0s;padding-top:50px}.nav-arrow:hover{opacity:1}.down-arrow{background-image:url("../../images/down-arrow.png")}.inline-toc{line-height:1.3em}.inline-toc a,.inline-toc a:link,.inline-toc a:visited{color:#aaa;font-weight:normal}.inline-toc a:hover,.inline-toc a:focus,.inline-toc a:link:hover,.inline-toc a:link:focus,.inline-toc a:visited:hover,.inline-toc a:visited:focus{color:#000}.inline-toc li li a,.inline-toc li li a:link,.inline-toc li li a:visited{color:#aaa}.inline-toc li li a:hover,.inline-toc li li a:focus,.inline-toc li li a:link:hover,.inline-toc li li a:link:focus,.inline-toc li li a:visited:hover,.inline-toc li li a:visited:focus{color:#000}.inline-toc a{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;padding:0.5em 0}.inline-toc .related{display:block;background-color:#f5f5f5;box-shadow:0 3px 4px rgba(0,0,0,0.12);padding:1em 1em 0.5em 1em;margin-bottom:1em}.inline-toc .related h3{margin-top:0}.inline-toc .related li a.active{color:#000}.inline-toc .related li a:hover{background-image:linear-gradient(205deg, rgba(229,229,229,0.7) 0%,rgba(233,233,233,0.7) 20%,rgba(244,244,244,0.7) 100%)}.inline-toc #toc{display:none}.inline-toc #toc .toplevel>a{font-weight:bold;color:#000}.inline-toc #toc .toplevel>a.hastoc::after{content:'+';-webkit-box-flex:1;-webkit-flex:1;-moz-flex:1;-ms-flex:1;-o-flex:1;flex:1;text-align:right}.inline-toc #toc .toplevel.active .toc{display:block}.inline-toc #toc .toplevel.active>a.hastoc::after{content:''}.inline-toc .toc{margin:0;padding:0.3em 0 0 0;border-top:1px solid #dbdbdb}.inline-toc .toc .toc{display:none}.inline-toc .toc .toc li{padding-left:1em;border-bottom:1px solid #dbdbdb}#cc-info{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;font-style:italic;font-size:0.8em;color:#848484}#cc-info .cc-logo img{width:90px;height:32px}#cc-info .last-updated{-webkit-box-flex:1;-webkit-flex:1;-moz-flex:1;-ms-flex:1;-o-flex:1;flex:1}@media only screen and (min-width: 580px){.inline-toc{position:absolute;top:0;width:28%;right:0;overflow:auto;overflow-x:hidden}.inline-toc #toc{display:block}.inline-toc #toc.sticky{top:0;position:fixed;-webkit-transform:translateZ(0)}.article-content{width:70%;padding-right:5%;border-right:1px solid #f5f5f5;min-height:250px}.cc-logo{margin:0 0 0 auto}}@media only screen and (max-width: 580px){.article-content [itemprop="articleBody"]>.collapsible{height:58px;overflow:hidden}.article-content [itemprop="articleBody"]>.collapsible.active{height:auto}.article-content [itemprop="articleBody"]>.collapsible.active h2::before{content:'-'}.article-content [itemprop="articleBody"]>.collapsible h2{position:relative;margin:0;padding:15px 15px 15px 0;border-top:1px solid #dbdbdb;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.article-content [itemprop="articleBody"]>.collapsible h2::before{position:absolute;right:0;content:'+'}.article-content [itemprop="articleBody"] .related{margin:20px 0}}.api{color:#333;font-size:14px}.api .api-summary td,.api .api-summary th{padding:5px 10px}.api .api-reference .description{margin-left:20px}.api .api-reference table.innerTable{margin:10px 0}.api .api-reference table.innerTable td,.api .api-reference table.innerTable th{padding:5px 10px;border:1px solid #eee}.api .api-reference table.innerTable th{background:none}.api .api-reference table.innerTable p{margin:0}.api .api-reference td,.api .api-reference th{vertical-align:top;border:1px solid #eee}.api .api-reference th{background:#fafafa}.api .api-reference h2{background-color:#e8e8e8;padding:20px;margin-left:-20px;margin-right:-20px}.api .api-reference h3{margin-top:3em}.api .availability{color:#A03} */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;font-size:100%;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}button,input,select,textarea{font-family:sans-serif}body{margin:0}a{background:transparent}a:focus{outline:thin dotted}a:active,a:hover{outline:0}p,pre{margin:1.5em 0}blockquote{margin:1.5em 40px}h1{font-size:2em;line-height:1.5em;margin-top:0.75em;margin-bottom:0.75em}h2{font-size:1.5em;line-height:2em;margin-top:1em;margin-bottom:1em}h3{font-size:1.17em;line-height:1.28205em;margin-top:1.28205em;margin-bottom:1.28205em}h4{font-size:1em;line-height:1.5em;margin-top:1.5em;margin-bottom:1.5em}h5{font-size:0.83em;line-height:1.80723em;margin-top:1.80723em;margin-bottom:1.80723em}h6{font-size:0.67em;line-height:2.23881em;margin-top:2.23881em;margin-bottom:2.23881em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace, serif;_font-family:'courier new', monospace;font-size:1em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}dl,menu,ol,ul{margin:1.5em 0}dd{margin:0 0 0 40px}menu,ol,ul{padding:0 0 0 40px}nav ul,nav ol{list-style:none;list-style-image:none}img{border:0;-ms-interpolation-mode:bicubic}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{margin:0 2px;border-color:#c0c0c0;border-top-style:solid;border-top-width:0.0625em;padding-top:0.4625em;border-bottom-style:solid;border-bottom-width:0.0625em;padding-bottom:0.9125em;border-left-style:solid;border-left-width:0.0625em;padding-left:0.875em;border-right-style:solid;border-right-width:0.0625em;padding-right:0.875em}legend{border:0;padding:0;*margin-left:-7px}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;*overflow:visible}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;*height:13px;*width:13px}input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}* html{font-size:100%}html{font-size:16px;line-height:1.5em}* html{font-size:100%}html{font-size:16px;line-height:1.5em}.g-section:after{content:".";display:block;height:0;clear:both;visibility:hidden}.g-unit .g-section:after{clear:none}.g-unit .g-section{width:100%;overflow:hidden}.g-section,.g-unit{zoom:1}.g-split>.g-unit{float:right;text-align:right}.g-split>.g-first{float:left;text-align:left}.g-tpl-160 .g-unit,.g-unit .g-tpl-160 .g-unit,.g-unit .g-unit .g-tpl-160 .g-unit,.g-unit .g-unit .g-unit .g-tpl-160 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-tpl-160 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-160 .g-unit{display:block;margin:0 0 0 160px;width:auto;float:none}.g-tpl-160 .g-first,.g-unit .g-tpl-160 .g-first,.g-unit .g-unit .g-tpl-160 .g-first,.g-unit .g-unit .g-unit .g-tpl-160 .g-first,.g-unit .g-unit .g-unit .g-unit .g-tpl-160 .g-first,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-160 .g-first{display:block;margin:0;width:160px;float:left}.g-tpl-25-75 .g-unit,.g-unit .g-tpl-25-75 .g-unit,.g-unit .g-unit .g-tpl-25-75 .g-unit,.g-unit .g-unit .g-unit .g-tpl-25-75 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-tpl-25-75 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-25-75 .g-unit{width:74.999%;float:right;display:inline;margin:0}.g-tpl-25-75 .g-first,.g-unit .g-tpl-25-75 .g-first,.g-unit .g-unit .g-tpl-25-75 .g-first,.g-unit .g-unit .g-unit .g-tpl-25-75 .g-first,.g-unit .g-unit .g-unit .g-unit .g-tpl-25-75 .g-first,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-25-75 .g-first{width:24.999%;float:left;display:inline;margin:0}.g-tpl-75-25 .g-unit,.g-unit .g-tpl-75-25 .g-unit,.g-unit .g-unit .g-tpl-75-25 .g-unit,.g-unit .g-unit .g-unit .g-tpl-75-25 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-tpl-75-25 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-75-25 .g-unit{width:24.999%;float:right;display:inline;margin:0}.g-tpl-75-25 .g-first,.g-unit .g-tpl-75-25 .g-first,.g-unit .g-unit .g-tpl-75-25 .g-first,.g-unit .g-unit .g-unit .g-tpl-75-25 .g-first,.g-unit .g-unit .g-unit .g-unit .g-tpl-75-25 .g-first,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-75-25 .g-first{width:74.999%;float:left;display:inline;margin:0}.g-tpl-33-67 .g-unit,.g-unit .g-tpl-33-67 .g-unit,.g-unit .g-unit .g-tpl-33-67 .g-unit,.g-unit .g-unit .g-unit .g-tpl-33-67 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-tpl-33-67 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-33-67 .g-unit{width:66.999%;float:right;display:inline;margin:0}.g-tpl-33-67 .g-first,.g-unit .g-tpl-33-67 .g-first,.g-unit .g-unit .g-tpl-33-67 .g-first,.g-unit .g-unit .g-unit .g-tpl-33-67 .g-first,.g-unit .g-unit .g-unit .g-unit .g-tpl-33-67 .g-first,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-33-67 .g-first{width:32.999%;float:left;display:inline;margin:0}.g-tpl-67-33 .g-unit,.g-unit .g-tpl-67-33 .g-unit,.g-unit .g-unit .g-tpl-67-33 .g-unit,.g-unit .g-unit .g-unit .g-tpl-67-33 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-tpl-67-33 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-67-33 .g-unit{width:32.999%;float:right;display:inline;margin:0}.g-tpl-67-33 .g-first,.g-unit .g-tpl-67-33 .g-first,.g-unit .g-unit .g-tpl-67-33 .g-first,.g-unit .g-unit .g-unit .g-tpl-67-33 .g-first,.g-unit .g-unit .g-unit .g-unit .g-tpl-67-33 .g-first,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-67-33 .g-first{width:66.999%;float:left;display:inline;margin:0}.g-tpl-50-50 .g-unit,.g-unit .g-tpl-50-50 .g-unit,.g-unit .g-unit .g-tpl-50-50 .g-unit,.g-unit .g-unit .g-unit .g-tpl-50-50 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-tpl-50-50 .g-unit,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-50-50 .g-unit{width:49.999%;float:right;display:inline;margin:0}.g-tpl-50-50 .g-first,.g-unit .g-tpl-50-50 .g-first,.g-unit .g-unit .g-tpl-50-50 .g-first,.g-unit .g-unit .g-unit .g-tpl-50-50 .g-first,.g-unit .g-unit .g-unit .g-unit .g-tpl-50-50 .g-first,.g-unit .g-unit .g-unit .g-unit .g-unit .g-tpl-50-50 .g-first{width:49.999%;float:left;display:inline;margin:0}.g-tpl-nest .g-unit{float:left;width:auto;display:inline;margin:0}.g-tpl-nest-alt .g-unit{float:right;width:auto;display:inline;margin:0}.g-content{margin-right:30px}.g-last .g-content{margin-right:0}@media only screen and (max-width: 580px){.g-unit.g-unit{float:none !important}.g-content{margin-right:0}}*{padding:0;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html,body{overflow-x:hidden;overflow-y:auto}img{max-width:100%}#gc-container{max-width:870px;margin:auto;width:90%}#gc-pagecontent>.g-section{margin:40px 0}main{margin-bottom:50px;position:relative}footer[role="contentinfo"]{padding:40px 0 50px}@media only screen and (max-width: 580px){#gc-container{width:auto}#gc-pagecontent{margin:auto;width:90%}#gc-pagecontent>.g-section{margin:20px 0}footer[role="contentinfo"]{padding:20px 30px}}@media only screen and (min-width: 581px) and (max-width: 990px){#gc-container{width:95%}}figure{margin:20px 0}figure img{border:1px solid #dbdbdb}table{width:100%;border-collapse:collapse;margin:2em 0;line-height:1.5em}table caption{margin-bottom:1em;text-align:left;font-weight:bold}th{border:1px solid #dbdbdb;font-weight:bold;background:#e8e8e8}tr{border-bottom:1px solid #dbdbdb}table+tr{border-top:1px solid #dbdbdb}td,th{padding:1em 1.5em;text-align:left;border:1px solid #dbdbdb}pre{background-color:#f7f7f7;box-shadow:0 2px 4px rgba(0,0,0,0.15),0 0 3px rgba(0,0,0,0.15);margin:1em 0 0 0;padding:.99em;position:relative;overflow-x:auto;word-wrap:normal;white-space:pre;font-size:0.95em;line-height:1.8em}pre a{text-decoration:underline !important}pre b{background:yellow;font-weight:normal}pre strike{text-decoration:none;background-image:linear-gradient(transparent 7px,#cc1f1f 7px,#cc1f1f 9px,transparent 9px)}pre[data-filename]::after{visibility:hidden}pre[data-filename]:hover::after{visibility:visible}.element-invisible{position:absolute !important;height:1px;width:1px;overflow:hidden;clip:rect(1px 1px 1px 1px);clip:rect(1px, 1px, 1px, 1px)}.hidden{display:none}.label{color:inherit;text-transform:uppercase;margin-bottom:5px;font-size:11.2px;font-weight:bold}.published{font-size:11.2px;font-style:italic;color:#bebebe;line-height:16.8px}.description{margin:20px 0}.description:last-child{margin-bottom:0}.span-full{background:#f5f5f5;position:relative;padding:3em 0}.span-full::before,.span-full::after{content:'';height:100%;width:100%;top:0;position:absolute;background:#f5f5f5;z-index:-1}.span-full::before{left:-100%}.span-full::after{left:100%}.button{background:#0370ea;background-image:linear-gradient(top, #008dfd 0%,#0370ea 100%);border:1px solid #076bd2;border-radius:3px;color:#fff !important;display:inline-block;font-size:13px;font-weight:700;line-height:1.3;padding:5px 20px;text-align:center;text-decoration:none !important;text-shadow:1px 1px 1px #076bd2}.button:hover{background-image:linear-gradient(top, #008dfd 30%,#0370ea 100%);cursor:pointer}.button a{color:inherit !important}.button-alt{background:#eee;background-image:linear-gradient(bottom, #dcdcdc 46%,#fafafa 87%);border:1px solid #d6d6d6;border-radius:3px;color:#333 !important;display:inline-block;font-size:12px;font-weight:700;line-height:24px;padding:0 15px;text-align:center;text-decoration:none !important;text-shadow:none}.button-alt:hover{background-image:linear-gradient(bottom, #dcdcdc 20%,#fafafa 87%);cursor:pointer}.google-button{background-color:#f5f5f5;border-radius:2px 0 0 0;border:1px solid rgba(0,0,0,0.1);padding:5px 12px;text-align:center;white-space:nowrap}.google-button:hover{border-color:#c6c6c6;box-shadow:0 -1px 1px rgba(0,0,0,0.1)}.google-button:active{background-color:#f1f1f1;box-shadow:inset 0 0px 2px rgba(0,0,0,0.2)}.screenshot,.screenshot img{margin:1em 0}.video-container{position:relative;padding-bottom:56.25%;padding-top:30px;height:0;overflow:hidden;margin:0 0 20px 0}.video-container iframe,.video-container object,.video-container embed{position:absolute;top:0;left:0;width:100%;height:100%}p.note,p.caution,p.warning,div.note,div.caution,div.warning,aside.note,aside.caution,aside.warning{background-color:#f5f5f5;border-bottom:1px solid;border-top:1px solid;overflow:hidden;width:85%;margin:auto;padding:1em}p.note,div.note,aside.note{border-color:#36C}p.caution,div.caution,aside.caution{border-color:#FC3}p.warning,div.warning,aside.warning{border-color:#A03}p.warning em,p.warning strong,div.warning em,div.warning strong,aside.warning em,aside.warning strong{color:#A03}.permalink{display:none;margin-left:5px}.has-permalink:hover .permalink{display:initial}.no-permalink .permalink{display:none !important}#gc-footer .links a{margin-right:20px}#gc-footer #cc-info{font-size:11.2px}#social-buttons{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-box-pack:1;-webkit-justify-content:flex-end;-moz-justify-content:flex-end;-ms-justify-content:flex-end;-o-justify-content:flex-end;justify-content:flex-end;-webkit-box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center}#social-buttons>*{margin-left:10px}#social-buttons img{margin:-4px 0 0 1px}@media only screen and (max-width: 580px){.more-section .g-last .g-content{padding-bottom:0;border:none}.more-section .g-content{border:1px solid #dbdbdb;border-width:0 0 1px 0;padding-bottom:20px;margin-bottom:20px}#gc-footer .links a{display:inline-block}}#scroll-to-top,#send-feedback{border-bottom:none;bottom:0;position:fixed;z-index:5}#scroll-to-top{border-left:0;left:0}#send-feedback{border-right:0;right:0}html{font-family:"Open Sans",Arial,"Lucida Grande",sans-serif;color:#777}body{font-size:13px;color:#777}h1,h2,h3,h4,h5,h6{font-family:"Open Sans",Arial,"Lucida Grande",sans-serif;font-weight:600;color:#000}h1,h2{font-weight:300}h1{font-size:2.625em;line-height:1.14286em}h1+h1{margin-top:0em}h2{font-size:1.875em;line-height:1.6em;margin-top:1.6em;margin-bottom:0em;line-height:1.12em}h3{font-size:1.125em;line-height:1.33333em;margin-top:1.33333em;margin-bottom:0.53333em;line-height:1.12em}h4{font-size:1.1em;line-height:1.36364em;margin-top:0em;margin-bottom:0em}h5{font-size:1em;line-height:1.5em;margin-top:0em;margin-bottom:0em}h6{font-size:1em;line-height:1.5em;margin-top:0em;margin-bottom:0em}p{margin:1.5em 0}p.noindent,p.caption p{text-indent:0}p.caption{text-align:left}.lightbox p.caption{color:#fff}a,a:link,a:visited{color:#39c;font-weight:bold;text-decoration:none;word-wrap:break-word;transition:opacity 0.3s ease 0s}a:hover,a:focus,a:link:hover,a:link:focus,a:visited:hover,a:visited:focus{color:#39f}a.section-anchor{display:block;padding-top:3.33em}footer[role="contentinfo"]{font-size:0.84615385em}footer[role="contentinfo"] a,footer[role="contentinfo"] a:link,footer[role="contentinfo"] a:visited{color:#999;font-weight:normal;font-weight:600;text-decoration:none;word-wrap:break-word}footer[role="contentinfo"] a:hover,footer[role="contentinfo"] a:focus,footer[role="contentinfo"] a:link:hover,footer[role="contentinfo"] a:link:focus,footer[role="contentinfo"] a:visited:hover,footer[role="contentinfo"] a:visited:focus{color:#39f}em{padding-right:2px}img{vertical-align:middle}figcaption{font-family:"Open Sans",Arial,"Lucida Grande",sans-serif;color:#aaa}blockquote{margin:0.75em 0.8em}cite{margin:0.75em 0.8em;color:#c3c3c3;font-style:normal}canvas{background:#fff;margin:1.5em 0}.code,code,pre{color:#080;font-family:"Source Code Pro",sans-serif}a>code{color:#39c}pre{margin:2em 0;word-wrap:break-word;position:relative}pre[data-filename]::after{content:attr(data-filename);background-color:#aaa;color:#fff;padding:2px 12px;position:absolute;right:0;top:0}pre a{text-decoration:underline}.static-code-container{line-height:1em;clear:both}code,kbd,samp{margin:1.5em 0;line-height:1em}dl,menu,ol,ul,.item-list ul{margin:0.8em 0}ul{padding-left:1.28em}ol{padding-left:1.52em}hr{height:1px;border:0;border-bottom:1px solid #dbdbdb;padding-bottom:-1px;margin:1.5em 0}.capitalize{text-transform:uppercase}[data-list-item]{display:list-item}.uncapitalize::first-letter{text-transform:lowercase}.capitalize::first-letter{text-transform:uppercase}.kbd{background-color:#f7f7f7;border:1px solid #ccc;color:#333;font-size:11px;line-height:1.4;text-shadow:0 1px 0 #fff;font-family:Arial,Helvetica,sans-serif;display:inline-block;padding:0.1em 0.6em;margin:0 0.1em;white-space:nowrap;box-shadow:0 1px 0px rgba(0,0,0,0.2),0 0 0 2px #fff inset;border-radius:3px}#topnav{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;height:64px;position:relative}#logo{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-webkit-user-select:none;-moz-user-select:none;-o-user-select:none;-ms-user-select:none;user-select:none}#logo a{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;color:#828282;font-size:2em;font-weight:400;letter-spacing:-1px}#logo a img{margin-bottom:-4px;height:40px;width:123px}#logo .collase-icon{display:none;background:url("../../images/burger-icon.png") 50% 100% no-repeat;background-size:cover;width:20px;height:20px}#logo .collase-icon.active{background-position:50% 0}#fatnav{height:100%;display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-box-pack:1;-webkit-justify-content:flex-end;-moz-justify-content:flex-end;-ms-justify-content:flex-end;-o-justify-content:flex-end;justify-content:flex-end;-webkit-box-flex:1;-webkit-flex:1;-moz-flex:1;-ms-flex:1;-o-flex:1;flex:1;white-space:nowrap}#fatnav li{list-style:none}#fatnav>ul{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;padding:0;margin:0}#fatnav .toplevel{color:#aaa;font-weight:600;text-transform:uppercase;-webkit-user-select:none;-moz-user-select:none;-o-user-select:none;-ms-user-select:none;user-select:none}#fatnav .toplevel::after{content:'';background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPJJREFUeNpiyc/Pn8XAwDATiM8yEAaMQBwBxHxMQMIdiE8D8Vog1sGjyQGqbhkQK4A0PoKaFATEF4F4MRCrImnQBuJtQLwfiI2hYk9AGl2AuB2I/wAxiB8DxNeAeA4QzwXiS0DsCdXwHIj9gHgqSOFPIK4CYksgvgJVwALEyUCcBDWMAeoSkO2bGZAEQeAM1CmtUNth4BkQ+wJxHBC/hwkyoQXALyCuAWILIL4MxIugAbYFI3iNZ54BR4fNtcXo0QEy9B+ywBGtWMzoAAquBWLk6EDXhBIdLNDokINGRwBQAUiiCYhvI0VHN1LIjpjoAAgwAMoSTlKlzAY4AAAAAElFTkSuQmCC) no-repeat;background-size:9px;display:inline-block;height:5px;width:14px;margin-left:10px;margin-bottom:2px}#fatnav .pillar{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;padding:0 20px;cursor:pointer;z-index:1002}#fatnav .expandee{display:none;position:absolute;z-index:1001;left:0;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;background-color:#f5f5f5;padding:20px 0;cursor:initial;margin:0}#fatnav .expandee a{font-weight:600;padding:0.5em 0;display:block;color:#828282}#fatnav .expandee a:hover{background-image:linear-gradient(205deg, rgba(229,229,229,0.7) 0%,rgba(233,233,233,0.7) 20%,rgba(244,244,244,0.7) 100%)}#fatnav .expandee li{white-space:nowrap}#fatnav .expandee li.submenu{color:#333;font-size:1.1em;font-weight:bold;-webkit-box-flex:1;-webkit-flex:1;-moz-flex:1;-ms-flex:1;-o-flex:1;flex:1}#fatnav .expandee li.submenu.active{background-image:linear-gradient(205deg, rgba(229,229,229,0.7) 0%,rgba(233,233,233,0.7) 20%,rgba(244,244,244,0.7) 100%)}#fatnav .expandee li.submenu>ul{font-size:0.8em;padding:15px 0 0 0;margin:0}#fatnav .expandee li.submenu .category{border-bottom:1px solid #e8e8e8}#fatnav .expandee li.submenu .category:last-child{border:none}#fatnav .expandee li.submenu .category a{overflow:hidden;text-overflow:ellipsis}#fatnav .expandee li.submenu .category>ul{display:none}#fatnav .expandee li.submenu .category ul{padding:0}#search{display:-webkit-inline-flex;display:-moz-inline-flex;display:-ms-inline-flex;display:-o-inline-flex;display:inline-flex;-webkit-align-self:stretch;-moz-align-self:stretch;-ms-align-self:stretch;-o-align-self:stretch;align-self:stretch;-webkit-box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;width:auto;padding:0 20px;cursor:pointer}#search img{height:16px;width:16px;-webkit-user-select:none;-moz-user-select:none;-o-user-select:none;-ms-user-select:none;user-select:none}#search .expandee{padding:20px}#search .expandee input[type="search"]{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;background:url("../../images/search.png") no-repeat 15px 55%;background-size:20px;background-color:white;border:1px solid #dbdbdb;padding:10px 10px 10px 40px;font-size:1.4em;-webkit-box-flex:1;-webkit-flex:1;-moz-flex:1;-ms-flex:1;-o-flex:1;flex:1;font-family:inherit;font-weight:300}@media only screen and (min-width: 580px){#topnav{padding:15px 0 0}#fatnav .pillar.active{background:#f5f5f5 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAyCAMAAABI+VrBAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALFQTFRF/////f39/v7+/Pz8+/v7+fn56+vr+vr69PT09vb28/Pz9fX1xcXF9/f3+Pj45+fn8PDwycnJ7+/v6enpzc3N19fX8fHx8vLy7u7u6Ojo7Ozs3Nzc5OTk7e3t4uLi2dnZ39/fxsbG29vb0dHR3d3d4ODg4+Pj6urqyMjI09PT5eXl0NDQ1dXV2NjYysrKx8fH5ubmzs7O3t7exMTE4eHh2tray8vLz8/PzMzM1NTU1tbWhgtdWwAAAOFJREFUeNok0NWSxCAURdFDhCQkMx3tuLe7jP//h829NC+rqIKNAK8hhGEQjmUyrm+ziVTs50O6jkA6b+J3gSCqpWfiGZxL1yKyhbIQEDQLxj7xTYy7SXoCY1RXbwLXy6OgfdevIbYFdulHaBuI7t3SIY5Nbhm4zAdF/Ow5gvTEEaR/W49Ov2eSIvjuW+Y4tdTCXHML+1XI/A7cwmmdM1nHLZwbl+kPPj9lunELq5LuRWy5hUFyC+uKI+hazabgCJpYcws5gsXS5F8qc02i9C9Jn9ejelHoMkJdhrJ5xb8AAwBmihB0TS21nQAAAABJRU5ErkJggg==) no-repeat right 0}#fatnav .pillar.active .toplevel::after{background-position:0% -5px}#fatnav .pillar.active .expandee{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-box-orient:vertical;-webkit-flex-direction:row;-moz-flex-direction:row;-ms-flex-direction:row;-o-flex-direction:row;flex-direction:row}#fatnav .pillar.active .expandee::after{position:absolute;background-image:linear-gradient(bottom, rgba(255,255,255,0) 0%,rgba(211,211,211,0.5) 25%,#d3d3d3 50%,rgba(211,211,211,0.5) 75%,rgba(255,255,255,0) 100%);right:0;top:0;content:'';width:1px !important;height:100%}#fatnav .pillar .expandee{min-height:400px;font-size:0.9em;box-shadow:0 3px 4px rgba(0,0,0,0.12);top:64px}#fatnav .pillar .expandee .submenu{padding:0 20px;border-right:1px solid #e8e8e8}#fatnav .pillar .expandee .submenu:last-child{border:none}#search{margin-right:-4px}#search.active{background:#f5f5f5 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAyCAMAAABI+VrBAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALFQTFRF/////f39/v7+/Pz8+/v7+fn56+vr+vr69PT09vb28/Pz9fX1xcXF9/f3+Pj45+fn8PDwycnJ7+/v6enpzc3N19fX8fHx8vLy7u7u6Ojo7Ozs3Nzc5OTk7e3t4uLi2dnZ39/fxsbG29vb0dHR3d3d4ODg4+Pj6urqyMjI09PT5eXl0NDQ1dXV2NjYysrKx8fH5ubmzs7O3t7exMTE4eHh2tray8vLz8/PzMzM1NTU1tbWhgtdWwAAAOFJREFUeNok0NWSxCAURdFDhCQkMx3tuLe7jP//h829NC+rqIKNAK8hhGEQjmUyrm+ziVTs50O6jkA6b+J3gSCqpWfiGZxL1yKyhbIQEDQLxj7xTYy7SXoCY1RXbwLXy6OgfdevIbYFdulHaBuI7t3SIY5Nbhm4zAdF/Ow5gvTEEaR/W49Ov2eSIvjuW+Y4tdTCXHML+1XI/A7cwmmdM1nHLZwbl+kPPj9lunELq5LuRWy5hUFyC+uKI+hazabgCJpYcws5gsXS5F8qc02i9C9Jn9ejelHoMkJdhrJ5xb8AAwBmihB0TS21nQAAAABJRU5ErkJggg==) no-repeat right 0}#search.active .expandee{display:block;top:64px}}@media only screen and (max-width: 580px){#topnav{-webkit-box-orient:vertical;-webkit-flex-direction:column;-moz-flex-direction:column;-ms-flex-direction:column;-o-flex-direction:column;flex-direction:column;height:auto}#fatnav{width:100%;max-height:0;overflow:hidden;background:#f5f5f5}#fatnav.active{max-height:5000px}#fatnav>ul{-webkit-box-flex:1;-webkit-flex:1;-moz-flex:1;-ms-flex:1;-o-flex:1;flex:1;-webkit-box-orient:vertical;-webkit-flex-direction:column;-moz-flex-direction:column;-ms-flex-direction:column;-o-flex-direction:column;flex-direction:column}#fatnav .toplevel{width:100%;height:50px;-webkit-box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-webkit-box-pack:1;-webkit-justify-content:center;-moz-justify-content:center;-ms-justify-content:center;-o-justify-content:center;justify-content:center;display:-webkit-inline-flex;display:-moz-inline-flex;display:-ms-inline-flex;display:-o-inline-flex;display:inline-flex}#fatnav .pillar{-webkit-box-orient:vertical;-webkit-flex-direction:column;-moz-flex-direction:column;-ms-flex-direction:column;-o-flex-direction:column;flex-direction:column;padding:0;border-bottom:1px solid #dbdbdb}#fatnav .pillar.active .expandee{display:initial}#fatnav .expandee{position:relative;padding:0;background-color:rgba(229,229,229,0.7)}#fatnav .expandee li.submenu{padding:10px 15px}#fatnav .expandee li.submenu:not(:last-child){border-color:#ccc}#fatnav .expandee li.submenu>ul{background-color:inherit}#logo{height:50px;width:90%}#logo a{-webkit-box-flex:1;-webkit-flex:1;-moz-flex:1;-ms-flex:1;-o-flex:1;flex:1}#logo .collase-icon{display:initial}#search{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-webkit-box-ordinal-group:-1;-webkit-order:-1;-moz-order:-1;-ms-order:-1;-o-order:-1;order:-1;padding:15px 15px 0 15px}#search img{display:none}#search .expandee{display:block}}#gc-pagecontent .g-section h1,#gc-pagecontent .g-section h2,#gc-pagecontent .g-section h3{margin:0}#upcoming-events .screenshot,#featured .screenshot{margin-top:0}#upcoming-events article{border:1px solid #dbdbdb;border-width:0 0 1px 0;padding:20px 0}#upcoming-events article:first-child{padding-top:0}#upcoming-events article:last-child{padding-bottom:0;border:none}#site-sections{background-color:#f5f5f5;padding:20px;text-align:center}#site-sections h2{padding-top:20px}#site-sections h2::before{display:block;content:'';background:url("../../images/bucket-icons.png") 12px 50% no-repeat;width:100px;height:65px;background-size:cover;margin:auto;margin-bottom:20px}#site-sections h2.multidevice::before{background-position:-91px 50%}#site-sections h2.platform::before{background-position:-194px 50%}#developer-news{margin-top:4em}#developer-news .g-content{margin-right:20px}#developer-news h1{margin-bottom:40px !important}@media only screen and (min-width: 580px){#featured{padding-right:30px;padding-bottom:10px;border:1px solid #dbdbdb;border-width:0 1px 0 0}#featured img{margin-bottom:20px}}.pillar-content h1{font-size:42px}.pillar-content>.g-section{padding:3em 0}.pillar-content>.g-section:not(:last-of-type){border-bottom:1px solid #dbdbdb}.pillar-content>.g-section>h2{font-size:30px;margin-bottom:1.5em !important}.pillar-content .article-list article{position:relative;overflow:hidden;width:100%;padding:1.9em;background-color:#f5f5f5;box-shadow:0 2px 4px rgba(0,0,0,0.15),0 0 3px rgba(0,0,0,0.15);line-height:1.5em;margin-bottom:1.5em}.pillar-content .article-list article.new::after{content:'new';background:#2e82c9;position:absolute;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg);top:-4px;right:-20px;color:white;font-size:0.9em;width:60px;text-align:center;padding-top:8px}.pillar-content .article-list article p{font-weight:300}.pillar-content #further-resources .g-content h2::before{display:inline-block;content:'';background:url("../../images/further-resources-icons.svg") 0 50% no-repeat;width:50px;height:43px;background-size:cover;margin:auto;margin-bottom:5px;vertical-align:middle}.pillar-content #further-resources .g-content h2.school::before{background-position:0 50%}.pillar-content #further-resources .g-content h2.chat::before{background-position:-54px 50%}.pillar-content #further-resources .g-content h2.puzzle::before{background-position:-108px 50%}@media only screen and (max-width: 580px){.pillar-content>.g-section{padding:2em 0}}@media only screen and (min-width: 580px){.pillar-content .article-list{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-flex-wrap:wrap;-moz-flex-wrap:wrap;-ms-flex-wrap:wrap;-o-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:1;-webkit-justify-content:space-between;-moz-justify-content:space-between;-ms-justify-content:space-between;-o-justify-content:space-between;justify-content:space-between;-webkit-box-align:stretch;-webkit-align-items:stretch;-moz-align-items:stretch;-ms-align-items:stretch;-o-align-items:stretch;align-items:stretch}.pillar-content .article-list article{-webkit-box-flex:auto;-webkit-flex:auto;-moz-flex:auto;-ms-flex:auto;-o-flex:auto;flex:auto;margin-right:1.5em;width:45%}.pillar-content .article-list article:nth-child(2n),.pillar-content .article-list article:last-of-type{margin-right:0}}@media only screen and (min-width: 990px){.pillar-content .article-list article{width:30%}.pillar-content .article-list article:nth-child(2n){margin-right:1.5em}.pillar-content .article-list article:nth-child(3n),.pillar-content .article-list article:last-of-type{margin-right:0}}@supports not (flex-wrap: wrap){.pillar-content .article-list{display:block}@media only screen and (min-width: 580px){.pillar-content .article-list article{flex:none;float:left;width:48%}}@media only screen and (min-width: 990px){.pillar-content .article-list article{width:31.8058%}}}.load-more-articles{overflow:hidden;*zoom:1;margin:2em auto 0.3em;text-align:center;width:100%}.load-more-articles a,.load-more-articles a:hover{color:#000;transition:opacity 0.3s ease 0s}.nav-arrow{background-size:48px 48px;background:top center no-repeat;display:inline-block;opacity:0.5;transition:opacity 0.3s ease 0s;padding-top:50px}.nav-arrow:hover{opacity:1}.down-arrow{background-image:url("../../images/down-arrow.png")}.inline-toc{line-height:1.3em}.inline-toc a,.inline-toc a:link,.inline-toc a:visited{color:#aaa;font-weight:normal}.inline-toc a:hover,.inline-toc a:focus,.inline-toc a:link:hover,.inline-toc a:link:focus,.inline-toc a:visited:hover,.inline-toc a:visited:focus{color:#000}.inline-toc li li a,.inline-toc li li a:link,.inline-toc li li a:visited{color:#aaa}.inline-toc li li a:hover,.inline-toc li li a:focus,.inline-toc li li a:link:hover,.inline-toc li li a:link:focus,.inline-toc li li a:visited:hover,.inline-toc li li a:visited:focus{color:#000}.inline-toc a{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;padding:0.5em 0}.inline-toc .related{display:block;background-color:#f5f5f5;box-shadow:0 3px 4px rgba(0,0,0,0.12);padding:1em 1em 0.5em 1em;margin-bottom:1em}.inline-toc .related h3{margin-top:0}.inline-toc .related li a.active{color:#000}.inline-toc .related li a:hover{background-image:linear-gradient(205deg, rgba(229,229,229,0.7) 0%,rgba(233,233,233,0.7) 20%,rgba(244,244,244,0.7) 100%)}.inline-toc #toc{display:none}.inline-toc #toc .toplevel>a{font-weight:bold;color:#000}.inline-toc #toc .toplevel>a.hastoc::after{content:'+';-webkit-box-flex:1;-webkit-flex:1;-moz-flex:1;-ms-flex:1;-o-flex:1;flex:1;text-align:right}.inline-toc #toc .toplevel.active .toc{display:block}.inline-toc #toc .toplevel.active>a.hastoc::after{content:''}.inline-toc .toc{margin:0;padding:0.3em 0 0 0;border-top:1px solid #dbdbdb}.inline-toc .toc .toc{display:none}.inline-toc .toc .toc li{padding-left:1em;border-bottom:1px solid #dbdbdb}#cc-info{display:-webkit-box;display:-webkit-flex;display:-moz-flex;display:-ms-flex;display:-o-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;font-style:italic;font-size:0.8em;color:#848484}#cc-info .cc-logo img{width:90px;height:32px}#cc-info .last-updated{-webkit-box-flex:1;-webkit-flex:1;-moz-flex:1;-ms-flex:1;-o-flex:1;flex:1}@media only screen and (min-width: 580px){.inline-toc{position:absolute;top:0;width:28%;right:0;overflow:auto;overflow-x:hidden}.inline-toc #toc{display:block}.inline-toc #toc.sticky{top:0;position:fixed;-webkit-transform:translateZ(0)}.article-content{width:70%;padding-right:5%;border-right:1px solid #f5f5f5;min-height:250px}.cc-logo{margin:0 0 0 auto}}@media only screen and (max-width: 580px){.article-content [itemprop="articleBody"]>.collapsible{height:58px;overflow:hidden}.article-content [itemprop="articleBody"]>.collapsible.active{height:auto}.article-content [itemprop="articleBody"]>.collapsible.active h2::before{content:'-'}.article-content [itemprop="articleBody"]>.collapsible h2{position:relative;margin:0;padding:15px 15px 15px 0;border-top:1px solid #dbdbdb;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.article-content [itemprop="articleBody"]>.collapsible h2::before{position:absolute;right:0;content:'+'}.article-content [itemprop="articleBody"] .related{margin:20px 0}}.api{color:#333;font-size:14px}.api .api-summary td,.api .api-summary th{padding:5px 10px}.api .api-reference .description{margin-left:20px}.api .api-reference table.innerTable{margin:10px 0}.api .api-reference table.innerTable td,.api .api-reference table.innerTable th{padding:5px 10px;border:1px solid #eee}.api .api-reference table.innerTable th{background:none}.api .api-reference table.innerTable p{margin:0}.api .api-reference td,.api .api-reference th{vertical-align:top;border:1px solid #eee}.api .api-reference th{background:#fafafa}.api .api-reference h2{background-color:#e8e8e8;padding:20px;margin-left:-20px;margin-right:-20px}.api .api-reference h3{margin-top:3em}.api .availability{color:#A03}.api table#intro .title{white-space:nowrap}
...@@ -51,4 +51,10 @@ ...@@ -51,4 +51,10 @@
.availability { .availability {
color: #A03; color: #A03;
} }
table#intro {
.title {
white-space: nowrap;
}
}
} }
...@@ -27,9 +27,20 @@ They <b>cannot</b>: ...@@ -27,9 +27,20 @@ They <b>cannot</b>:
<ul> <ul>
<li> <li>
Use chrome.* APIs Use chrome.* APIs, with the exception of:
(except for parts of <ul id="content_script_supported_nodes">
<a href="extension"><code>chrome.extension</code></a>) {{#api:content_scripts}}
<li>
$(ref:{{api.name}})
{{?api.restrictedTo}}
({{#n:api.restrictedTo}}
$(ref:{{api.name}}.{{n.node}} {{n.node}})
{{^n.last}},{{/n.last}}
{{/api.restrictedTo}})
{{/api.restrictedTo}}
</li>
{{/content_scripts}}
</ul>
</li> </li>
<li> <li>
Use variables or functions defined by their extension's pages Use variables or functions defined by their extension's pages
......
<h2 id="content scripts">Support for content scripts</h2>
<p>
Unlike the other chrome.* APIs,
parts of <code>chrome.extension</code>
can be used by content scripts:
</p>
<dl>
<dt>
$(ref:runtime.sendMessage) and
$(ref:runtime.onMessage)
</dt>
<dd>
Simple communication with extension pages
</dd>
<dt>
$(ref:runtime.connect) and
$(ref:runtime.onConnect)
</dt>
<dd>
Extended communication with extension pages
</dd>
<dt>
$(ref:extension.getURL)
</dt>
<dd>
Access to extension resources such as image files
</dd>
</dl>
<p>
For details, see
<a href="content_scripts">Content Scripts</a>.
</p>
{{?content.contentScriptSupport.restrictedTo}}
{{#n:content.contentScriptSupport.restrictedTo}}
{{^n.first}}
{{^n.last}},{{/n.last}}{{?n.last}} and {{/n.last}}
{{/n.first}}
$(ref:{{content.contentScriptSupport.name}}.{{n.node}} {{n.node}})
{{/content.contentScriptSupport.restrictedTo}} are supported.
{{:}}
Fully supported.
{{/content.contentScriptSupport.restrictedTo}}
<a href="content_scripts">Learn more</a>
{{+partials.standard_extensions_article article:articles.content_scripts/}} {{+partials.standard_extensions_article
article:(articles.content_scripts
content_scripts:api_list.contentScripts)/}}
{{+partials.standard_extensions_api api:apis.extensions.extension intro:intros.extension/}} {{+partials.standard_extensions_api api:apis.extensions.extension/}}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment