{"action":"created","comment":{"url":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/comments/44279075","id":44279075,"diff_hunk":"@@ -732,26 +757,48 @@ def __init__(self, spaces, name=None):\n             ME  = MixedFunctionSpace([P2v, P1, P1, P1])\n         \"\"\"\n \n-        if self._initialized:\n-            return\n-        self._spaces = [IndexedFunctionSpace(s, i, self)\n-                        for i, s in enumerate(flatten(spaces))]\n-        self._mesh = self._spaces[0].mesh()\n-        self._ufl_element = ufl.MixedElement(*[fs.ufl_element() for fs in self._spaces])\n-        self.name = name or '_'.join(str(s.name) for s in self._spaces)\n-        self.rank = 1\n-        self._index = None\n-        self._initialized = True\n-        dm = PETSc.DMShell().create()\n-        from firedrake.function import Function\n-        with Function(self).dat.vec_ro as v:\n-            dm.setGlobalVector(v.duplicate())\n-        dm.setAttr('__fs__', weakref.ref(self))\n-        dm.setCreateFieldDecomposition(self.create_field_decomp)\n-        dm.setCreateSubDM(self.create_subdm)\n-        self._dm = dm\n-        self._ises = self.dof_dset.field_ises\n-        self._subspaces = []\n+        # Check that function spaces are on the same mesh\n+        meshes = [space.mesh() for space in spaces]\n+        for i in xrange(1, len(meshes)):\n+            if meshes[i] is not meshes[0]:\n+                raise ValueError(\"All function spaces must be defined on the same mesh!\")","path":"firedrake/functionspace.py","position":624,"original_position":624,"commit_id":"d16f9d1a82b4454779de721ca3f72c26b21ad960","original_commit_id":"fd4ed9f02c75767a092448a210af68e6bd0e72d0","user":{"login":"miklos1","id":4210841,"avatar_url":"https://avatars.githubusercontent.com/u/4210841?v=3","gravatar_id":"","url":"https://api.github.com/users/miklos1","html_url":"https://github.com/miklos1","followers_url":"https://api.github.com/users/miklos1/followers","following_url":"https://api.github.com/users/miklos1/following{/other_user}","gists_url":"https://api.github.com/users/miklos1/gists{/gist_id}","starred_url":"https://api.github.com/users/miklos1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/miklos1/subscriptions","organizations_url":"https://api.github.com/users/miklos1/orgs","repos_url":"https://api.github.com/users/miklos1/repos","events_url":"https://api.github.com/users/miklos1/events{/privacy}","received_events_url":"https://api.github.com/users/miklos1/received_events","type":"User","site_admin":false},"body":"Currently every function space class is topological, and `WithGeometry` adds a mesh geometry. Therefore `MixedFunctionSpace` is topological, so it has topological function spaces as subspaces. A `WithGeometry` can surround a `MixedFunctionSpace` to add a mesh geometry.\r\n\r\nI didn't know Firedrake can solve problems on different meshes. Can we add a test that exercises the feature that the Leeds people use?","created_at":"2015-11-09T14:22:48Z","updated_at":"2015-11-09T14:22:48Z","html_url":"https://github.com/firedrakeproject/firedrake/pull/627#discussion_r44279075","pull_request_url":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/627","_links":{"self":{"href":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/comments/44279075"},"html":{"href":"https://github.com/firedrakeproject/firedrake/pull/627#discussion_r44279075"},"pull_request":{"href":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/627"}}},"pull_request":{"url":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/627","id":49698554,"html_url":"https://github.com/firedrakeproject/firedrake/pull/627","diff_url":"https://github.com/firedrakeproject/firedrake/pull/627.diff","patch_url":"https://github.com/firedrakeproject/firedrake/pull/627.patch","issue_url":"https://api.github.com/repos/firedrakeproject/firedrake/issues/627","number":627,"state":"open","locked":false,"title":"Bootstrapping","user":{"login":"miklos1","id":4210841,"avatar_url":"https://avatars.githubusercontent.com/u/4210841?v=3","gravatar_id":"","url":"https://api.github.com/users/miklos1","html_url":"https://github.com/miklos1","followers_url":"https://api.github.com/users/miklos1/followers","following_url":"https://api.github.com/users/miklos1/following{/other_user}","gists_url":"https://api.github.com/users/miklos1/gists{/gist_id}","starred_url":"https://api.github.com/users/miklos1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/miklos1/subscriptions","organizations_url":"https://api.github.com/users/miklos1/orgs","repos_url":"https://api.github.com/users/miklos1/repos","events_url":"https://api.github.com/users/miklos1/events{/privacy}","received_events_url":"https://api.github.com/users/miklos1/received_events","type":"User","site_admin":false},"body":"A mesh has coordinates which is a function. A function has a function space. A function space has a mesh. A mesh has coordinates which is a function. A function has a function space. A function space has a mesh. A mesh has coordinates which is a function. A function has a function space. A function space has a mesh. A mesh has coordinates which is a function. ...\r\n\r\nWhile this circular dependency is very nice for certain reasons (coordinates are no special), our implementation in Firedrake barely works, and it actually does not work in some cases (periodic meshes with fancy function spaces, higher-order meshes). This patch aims to change that by using robust design that works.\r\n\r\n## Design principles\r\n\r\nThe idea is to break the cyclic dependency *under the hood*, by making a distinction between *topological* (without coordinates) and *geometric* (with coordinates) versions of mesh, function space, and function.\r\n\r\nA mesh topology is *self-contained*. One can define coordinateless function space on a mesh topology, and then a coordinateless function on a coordinateless function space. A coordinateless function is a perfect candidate for describing the coordinate field; in fact, a coordinateless function has all the data to define a mesh geometry. Then a function space is a coordinateless function space with a mesh geometry, and a function is a coordinateless function with a mesh geometry. (A function can also be interpreted as a pair of coordinateless functions, one for the coordinates and one for the actual values.)\r\n\r\n#### - But then the coordinate field of a mesh is special again?!\r\n\r\nIt is not that special (it can still be of any function space), and it is all under the hood. Using the \"official\" API, a mesh still returns a regular function as its coordinates. By creating a function which references the the actual coordinate field (which is coordinateless function) both as values and coordinates, we are even memory efficient.\r\n\r\nIn fact, `mesh.coordinates.function_space().mesh() is mesh` still holds.\r\n\r\n#### - Martin may not like it.\r\n\r\nThis is about refactoring **Firedrake**, and Martin does not care about that. In fact, these changes make it easier to cooperate with current and future UFL, since it is mostly parallel to UFL's design. ('current' and 'future' in our reference frame.)\r\n\r\n## API changes\r\n\r\nI argue for the removal of the \"changing mesh coordinates by assignment\" approach, in favour of a [referentially transparent](https://en.wikipedia.org/wiki/Referential_transparency) solution. While the new infrastructure makes it easier to change mesh coordinates in proper way, it would require more work to avoid the invalidation of existing function spaces and functions on that mesh. (Note: this is not about changing the coordinate values, but about changing the coordinate function, generally with a function which has a different function space.)\r\n\r\nAs far as I know, there are currently two uses of changing coordinates:\r\n\r\n##### 1. Creating a mesh from an arbitrary coordinate field\r\n\r\nThere is a new API to achieve this. If `f` is a `Function`, then `f.as_coordinates()` returns a mesh geometry whose coordinate field is the values of `f`. No data is duplicated.\r\n\r\nI wonder if the method shall be named `as_coordinates()`, `as_mesh()`, `as_geometry()` or something else. Suggestions are welcome.\r\n\r\n##### 2. Changing the coordinates of an existing function\r\n\r\nCurrently, there is no public API to do this. However, thanks to the flexibility of the design, if `f` is a `Function` and `mesh` is a mesh geometry, then\r\n\r\n    Function(functionspace.WithGeometry(f.function_space(), mesh), val=f.topological)\r\n\r\nwill return a new `Function` object which refers to `f`'s data values and has `mesh` as its geometry. Again, no data duplication.\r\n\r\nI can add a public API if we agree what that should be.\r\n\r\n## Required changes outside Firedrake\r\n\r\n##### Spurious UFL check in MixedElement\r\n\r\nIf a `ufl.MixedElement` is reconstructed over another domain, it checks that the value shape of the subelements remains the same. This does not hold, if one of the subelements is vector-valued (e.g. RT, BDM, etc.) and the geometric dimension changes.\r\n\r\n##### UFL cell reconstruction does not work for `OuterProductCell`s\r\n\r\nWho would have thought that a cell name and geometric dimension is not enough to create a cell? (Or what is a `ufl.Cell('OuterProductCell', 3)`?)\r\n\r\n##### `ufl.OuterProductCell` equality is too strict\r\n\r\nCurrently we use the following `ufl.OuterProductCell`s:\r\n\r\n    OuterProductCell(Cell(\"interval\"), Cell(\"interval\"))\r\n    OuterProductCell(Cell(\"interval\", 2), Cell(\"interval\"))\r\n    OuterProductCell(Cell(\"interval\", 2), Cell(\"interval\"), gdim=3)\r\n    OuterProductCell(Cell(\"interval\", 3), Cell(\"interval\"))\r\n    OuterProductCell(Cell(\"triangle\"), Cell(\"interval\"))\r\n    OuterProductCell(Cell(\"triangle\", 3), Cell(\"interval\"))\r\n    OuterProductCell(Cell(\"quadrilateral\"), Cell(\"interval\"))\r\n    OuterProductCell(Cell(\"quadrilateral\", 3), Cell(\"interval\"))\r\n\r\nAfter this patch, we use the following `ufl.OuterProductCell`s:\r\n\r\n    OuterProductCell(Cell(\"interval\"), Cell(\"interval\"))\r\n    OuterProductCell(Cell(\"interval\"), Cell(\"interval\"), gdim=3)\r\n    OuterProductCell(Cell(\"triangle\"), Cell(\"interval\"))\r\n    OuterProductCell(Cell(\"quadrilateral\"), Cell(\"interval\"))\r\n\r\nWe should either loosen equality in UFL, _or_ simplify `ffc/codesnippets.py`, `firedrake/io.py`, and who knows what else...","created_at":"2015-11-04T14:59:33Z","updated_at":"2015-11-09T14:22:48Z","closed_at":null,"merged_at":null,"merge_commit_sha":"bbdd7273830bb67f3c488f948adcccf65c4f686a","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/627/commits","review_comments_url":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/627/comments","review_comment_url":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/comments{/number}","comments_url":"https://api.github.com/repos/firedrakeproject/firedrake/issues/627/comments","statuses_url":"https://api.github.com/repos/firedrakeproject/firedrake/statuses/d16f9d1a82b4454779de721ca3f72c26b21ad960","head":{"label":"firedrakeproject:bootstrapping","ref":"bootstrapping","sha":"d16f9d1a82b4454779de721ca3f72c26b21ad960","user":{"login":"firedrakeproject","id":5558005,"avatar_url":"https://avatars.githubusercontent.com/u/5558005?v=3","gravatar_id":"","url":"https://api.github.com/users/firedrakeproject","html_url":"https://github.com/firedrakeproject","followers_url":"https://api.github.com/users/firedrakeproject/followers","following_url":"https://api.github.com/users/firedrakeproject/following{/other_user}","gists_url":"https://api.github.com/users/firedrakeproject/gists{/gist_id}","starred_url":"https://api.github.com/users/firedrakeproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/firedrakeproject/subscriptions","organizations_url":"https://api.github.com/users/firedrakeproject/orgs","repos_url":"https://api.github.com/users/firedrakeproject/repos","events_url":"https://api.github.com/users/firedrakeproject/events{/privacy}","received_events_url":"https://api.github.com/users/firedrakeproject/received_events","type":"Organization","site_admin":false},"repo":{"id":13384052,"name":"firedrake","full_name":"firedrakeproject/firedrake","owner":{"login":"firedrakeproject","id":5558005,"avatar_url":"https://avatars.githubusercontent.com/u/5558005?v=3","gravatar_id":"","url":"https://api.github.com/users/firedrakeproject","html_url":"https://github.com/firedrakeproject","followers_url":"https://api.github.com/users/firedrakeproject/followers","following_url":"https://api.github.com/users/firedrakeproject/following{/other_user}","gists_url":"https://api.github.com/users/firedrakeproject/gists{/gist_id}","starred_url":"https://api.github.com/users/firedrakeproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/firedrakeproject/subscriptions","organizations_url":"https://api.github.com/users/firedrakeproject/orgs","repos_url":"https://api.github.com/users/firedrakeproject/repos","events_url":"https://api.github.com/users/firedrakeproject/events{/privacy}","received_events_url":"https://api.github.com/users/firedrakeproject/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/firedrakeproject/firedrake","description":"Firedrake is an automated system for the portable solution of partial differential equations using the finite element method (FEM)","fork":false,"url":"https://api.github.com/repos/firedrakeproject/firedrake","forks_url":"https://api.github.com/repos/firedrakeproject/firedrake/forks","keys_url":"https://api.github.com/repos/firedrakeproject/firedrake/keys{/key_id}","collaborators_url":"https://api.github.com/repos/firedrakeproject/firedrake/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/firedrakeproject/firedrake/teams","hooks_url":"https://api.github.com/repos/firedrakeproject/firedrake/hooks","issue_events_url":"https://api.github.com/repos/firedrakeproject/firedrake/issues/events{/number}","events_url":"https://api.github.com/repos/firedrakeproject/firedrake/events","assignees_url":"https://api.github.com/repos/firedrakeproject/firedrake/assignees{/user}","branches_url":"https://api.github.com/repos/firedrakeproject/firedrake/branches{/branch}","tags_url":"https://api.github.com/repos/firedrakeproject/firedrake/tags","blobs_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/refs{/sha}","trees_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/trees{/sha}","statuses_url":"https://api.github.com/repos/firedrakeproject/firedrake/statuses/{sha}","languages_url":"https://api.github.com/repos/firedrakeproject/firedrake/languages","stargazers_url":"https://api.github.com/repos/firedrakeproject/firedrake/stargazers","contributors_url":"https://api.github.com/repos/firedrakeproject/firedrake/contributors","subscribers_url":"https://api.github.com/repos/firedrakeproject/firedrake/subscribers","subscription_url":"https://api.github.com/repos/firedrakeproject/firedrake/subscription","commits_url":"https://api.github.com/repos/firedrakeproject/firedrake/commits{/sha}","git_commits_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/commits{/sha}","comments_url":"https://api.github.com/repos/firedrakeproject/firedrake/comments{/number}","issue_comment_url":"https://api.github.com/repos/firedrakeproject/firedrake/issues/comments{/number}","contents_url":"https://api.github.com/repos/firedrakeproject/firedrake/contents/{+path}","compare_url":"https://api.github.com/repos/firedrakeproject/firedrake/compare/{base}...{head}","merges_url":"https://api.github.com/repos/firedrakeproject/firedrake/merges","archive_url":"https://api.github.com/repos/firedrakeproject/firedrake/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/firedrakeproject/firedrake/downloads","issues_url":"https://api.github.com/repos/firedrakeproject/firedrake/issues{/number}","pulls_url":"https://api.github.com/repos/firedrakeproject/firedrake/pulls{/number}","milestones_url":"https://api.github.com/repos/firedrakeproject/firedrake/milestones{/number}","notifications_url":"https://api.github.com/repos/firedrakeproject/firedrake/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/firedrakeproject/firedrake/labels{/name}","releases_url":"https://api.github.com/repos/firedrakeproject/firedrake/releases{/id}","created_at":"2013-10-07T13:07:44Z","updated_at":"2015-10-23T16:06:10Z","pushed_at":"2015-11-09T14:09:16Z","git_url":"git://github.com/firedrakeproject/firedrake.git","ssh_url":"git@github.com:firedrakeproject/firedrake.git","clone_url":"https://github.com/firedrakeproject/firedrake.git","svn_url":"https://github.com/firedrakeproject/firedrake","homepage":"http://firedrakeproject.org","size":18871,"stargazers_count":21,"watchers_count":21,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":13,"mirror_url":null,"open_issues_count":68,"forks":13,"open_issues":68,"watchers":21,"default_branch":"master"}},"base":{"label":"firedrakeproject:master","ref":"master","sha":"7ee8c18a23cf9d7dfd887e974492a7b8514b3f9f","user":{"login":"firedrakeproject","id":5558005,"avatar_url":"https://avatars.githubusercontent.com/u/5558005?v=3","gravatar_id":"","url":"https://api.github.com/users/firedrakeproject","html_url":"https://github.com/firedrakeproject","followers_url":"https://api.github.com/users/firedrakeproject/followers","following_url":"https://api.github.com/users/firedrakeproject/following{/other_user}","gists_url":"https://api.github.com/users/firedrakeproject/gists{/gist_id}","starred_url":"https://api.github.com/users/firedrakeproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/firedrakeproject/subscriptions","organizations_url":"https://api.github.com/users/firedrakeproject/orgs","repos_url":"https://api.github.com/users/firedrakeproject/repos","events_url":"https://api.github.com/users/firedrakeproject/events{/privacy}","received_events_url":"https://api.github.com/users/firedrakeproject/received_events","type":"Organization","site_admin":false},"repo":{"id":13384052,"name":"firedrake","full_name":"firedrakeproject/firedrake","owner":{"login":"firedrakeproject","id":5558005,"avatar_url":"https://avatars.githubusercontent.com/u/5558005?v=3","gravatar_id":"","url":"https://api.github.com/users/firedrakeproject","html_url":"https://github.com/firedrakeproject","followers_url":"https://api.github.com/users/firedrakeproject/followers","following_url":"https://api.github.com/users/firedrakeproject/following{/other_user}","gists_url":"https://api.github.com/users/firedrakeproject/gists{/gist_id}","starred_url":"https://api.github.com/users/firedrakeproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/firedrakeproject/subscriptions","organizations_url":"https://api.github.com/users/firedrakeproject/orgs","repos_url":"https://api.github.com/users/firedrakeproject/repos","events_url":"https://api.github.com/users/firedrakeproject/events{/privacy}","received_events_url":"https://api.github.com/users/firedrakeproject/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/firedrakeproject/firedrake","description":"Firedrake is an automated system for the portable solution of partial differential equations using the finite element method (FEM)","fork":false,"url":"https://api.github.com/repos/firedrakeproject/firedrake","forks_url":"https://api.github.com/repos/firedrakeproject/firedrake/forks","keys_url":"https://api.github.com/repos/firedrakeproject/firedrake/keys{/key_id}","collaborators_url":"https://api.github.com/repos/firedrakeproject/firedrake/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/firedrakeproject/firedrake/teams","hooks_url":"https://api.github.com/repos/firedrakeproject/firedrake/hooks","issue_events_url":"https://api.github.com/repos/firedrakeproject/firedrake/issues/events{/number}","events_url":"https://api.github.com/repos/firedrakeproject/firedrake/events","assignees_url":"https://api.github.com/repos/firedrakeproject/firedrake/assignees{/user}","branches_url":"https://api.github.com/repos/firedrakeproject/firedrake/branches{/branch}","tags_url":"https://api.github.com/repos/firedrakeproject/firedrake/tags","blobs_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/refs{/sha}","trees_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/trees{/sha}","statuses_url":"https://api.github.com/repos/firedrakeproject/firedrake/statuses/{sha}","languages_url":"https://api.github.com/repos/firedrakeproject/firedrake/languages","stargazers_url":"https://api.github.com/repos/firedrakeproject/firedrake/stargazers","contributors_url":"https://api.github.com/repos/firedrakeproject/firedrake/contributors","subscribers_url":"https://api.github.com/repos/firedrakeproject/firedrake/subscribers","subscription_url":"https://api.github.com/repos/firedrakeproject/firedrake/subscription","commits_url":"https://api.github.com/repos/firedrakeproject/firedrake/commits{/sha}","git_commits_url":"https://api.github.com/repos/firedrakeproject/firedrake/git/commits{/sha}","comments_url":"https://api.github.com/repos/firedrakeproject/firedrake/comments{/number}","issue_comment_url":"https://api.github.com/repos/firedrakeproject/firedrake/issues/comments{/number}","contents_url":"https://api.github.com/repos/firedrakeproject/firedrake/contents/{+path}","compare_url":"https://api.github.com/repos/firedrakeproject/firedrake/compare/{base}...{head}","merges_url":"https://api.github.com/repos/firedrakeproject/firedrake/merges","archive_url":"https://api.github.com/repos/firedrakeproject/firedrake/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/firedrakeproject/firedrake/downloads","issues_url":"https://api.github.com/repos/firedrakeproject/firedrake/issues{/number}","pulls_url":"https://api.github.com/repos/firedrakeproject/firedrake/pulls{/number}","milestones_url":"https://api.github.com/repos/firedrakeproject/firedrake/milestones{/number}","notifications_url":"https://api.github.com/repos/firedrakeproject/firedrake/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/firedrakeproject/firedrake/labels{/name}","releases_url":"https://api.github.com/repos/firedrakeproject/firedrake/releases{/id}","created_at":"2013-10-07T13:07:44Z","updated_at":"2015-10-23T16:06:10Z","pushed_at":"2015-11-09T14:09:16Z","git_url":"git://github.com/firedrakeproject/firedrake.git","ssh_url":"git@github.com:firedrakeproject/firedrake.git","clone_url":"https://github.com/firedrakeproject/firedrake.git","svn_url":"https://github.com/firedrakeproject/firedrake","homepage":"http://firedrakeproject.org","size":18871,"stargazers_count":21,"watchers_count":21,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":13,"mirror_url":null,"open_issues_count":68,"forks":13,"open_issues":68,"watchers":21,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/627"},"html":{"href":"https://github.com/firedrakeproject/firedrake/pull/627"},"issue":{"href":"https://api.github.com/repos/firedrakeproject/firedrake/issues/627"},"comments":{"href":"https://api.github.com/repos/firedrakeproject/firedrake/issues/627/comments"},"review_comments":{"href":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/627/comments"},"review_comment":{"href":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/firedrakeproject/firedrake/pulls/627/commits"},"statuses":{"href":"https://api.github.com/repos/firedrakeproject/firedrake/statuses/d16f9d1a82b4454779de721ca3f72c26b21ad960"}}}}