Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save juliandescottes/e23ce75aa2345f5cd13e7ba825032a60 to your computer and use it in GitHub Desktop.
Save juliandescottes/e23ce75aa2345f5cd13e7ba825032a60 to your computer and use it in GitHub Desktop.
                                                                ┌────────────────────────────┐                                         
 ╔═════════════════════════════════════╗                        │ domainA page               │                                         
 ║                                     ║                        │                            │                                         
 ║    LISTING REMOTE FRAMES BEFORE     ║                        │     ┌────────────────────┐ │                                         
 ║                                     ║                        │     │ domainB iframe     │ │                                         
 ╚═════════════════════════════════════╝                        │     │                    │ │                                         
                                                                │     └────────────────────┘ │                                         
                                                                └────────────────────────────┘                                         
                                                                                                                                       
                                                                                                                                       
                                                                                                                                       
                    ┌────────────────────────────────┐           ┌───────────────────────────┐        ┌───────────────────────────────┐
                    │ Client                         │           │ Server Parent             │        │   Server Content domainA      │
                    │                                │           │                           │        │                               │
                    │   ┌───────────────────┐        │           │  ┌───────────────────┐    │        │                               │
                    │   │       Root        │        │           │  │       Root        │    │        │                               │
                   ┌┼──▶│       Front       │────────┼───────────┼─▶│       Actor       │────┼┐       │                               │
                   ││   └───────────────────┘        │           │  └───────────────────┘    ││       │                               │
                   ││                                │           │                           ││       │                               │
                   ││                                │           │                           ││       │   ┌───────────────────┐       │
                   ││   ┌───────────────────┐        │           │  ┌───────────────────┐    ││       │   │  BrowsingContext  │       │
       list remote ││   │   TabDescriptor   │        │           │  │   TabDescriptor   │    ││       │   │    TargetActor    │       │
          frames   ││   │       Front       │        │           │  │       Actor       │    ││       │   │   (for domainA)   │       │
                   ││   └─────────┬─────────┘        │           │  └─────────┬─────────┘    ││       │   └───────────────────┘       │
                   ││             │                  │           │            │              ││       │                               │
                   ││   ┌─────────┴─────────┐        │           │  ┌─────────┴─────────┐    ││       │                               │
                   ││   │  BrowsingContext  │        │           │  │ FrameConnector +  │    ││       │                               │
                   └┼───│    TargetFront    │        │           │  │  MessageManager   │    ││       │                               │
                    │   │   (for domainA)   │        │           │  └───────────────────┘    ││       └───────────────────────────────┘
                    │   └───────────────────┘        │           │                           ││                                        
                    │                                │           │                           ││                                        
                    │   ┌───────────────────┐        │           │  ┌───────────────────┐    ││       ┌───────────────────────────────┐
                    │   │  FrameDescriptor  │◀───────┼───────────┼──│  FrameDescriptor  │◀───┼┘       │   Server Content domainB      │
                    │   │       Front       │────────┼───────────┼─▶│       Actor       │────┼┐       │                               │
                    │   └─────────┬─────────┘        │get target │  └─────────┬─────────┘    ││       │                               │
                    │             │                  │           │  ┌─────────┴─────────┐    ││       │                               │
                    │             │                  │           │  │ FrameConnector +  │◀───┼┘       │                               │
                    │             │                  │           │  │  JsWindowActors   │────┼┐       │                               │
                    │             │                  │           │  └─────────┬─────────┘    ││       │                               │
                    │             │                  │           │  ┌─────────┴─────────┐    ││       │   ┌───────────────────┐       │
                    │             │                  │           │  │   DevToolsFrame   │◀───┼┘       │   │   DevToolsFrame   │       │
                    │             │                  │           │  │    Parent.jsm     │────┼────────┼──▶│     Child.jsm     │─────┐ │
                    │   ┌─────────┴─────────┐        │           │  └───────────────────┘    │        │   └───────────────────┘     │ │
                    │   │  BrowsingContext  │        │           │                           │        │   ┌───────────────────┐     │ │
                    │   │    TargetFront    │◀───────┼───────────┼───────────────────────────┼────────┼───│  BrowsingContext  │◀────┘ │
                    │   │   (for domainB)   │        │           │                           │        │   │    TargetActor    │       │
                    │   └───────────────────┘        │           │                           │        │   │   (for domainB)   │       │
                    │                                │           │                           │        │   └───────────────────┘       │
                    └────────────────────────────────┘           └───────────────────────────┘        └───────────────────────────────┘
                                                                                                                                       
                                                                                                                                       
                                                                                                                                       
                                                                                                                                       
                                                                                                                                       
                                                                                                                                       
                                                                                                                                       
                                                               ┌────────────────────────────┐                                          
╔═════════════════════════════════════╗                        │ domainA page               │                                          
║                                     ║                        │                            │                                          
║    "LISTING" REMOTE FRAMES AFTER    ║                        │     ┌────────────────────┐ │                                          
║                                     ║                        │     │ domainB iframe     │ │                                          
╚═════════════════════════════════════╝                        │     │                    │ │                                          
                                                               │     └────────────────────┘ │                                          
                                                               └────────────────────────────┘                                          
                                                                                                                                       
                                                                                                                                       
                                                                                                                                       
                      ┌────────────────────────────────┐        ┌───────────────────────────┐        ┌───────────────────────────────┐ 
                      │ Client                         │        │ Server Parent             │        │   Server Content domainA      │ 
                      │                                │        │                           │        │                               │ 
                      │   ┌───────────────────┐        │        │  ┌───────────────────┐    │        │                               │ 
                      │   │       Root        │        │        │  │       Root        │    │        │                               │ 
                      │   │       Front       │        │        │  │       Actor       │    │        │                               │ 
                      │   └───────────────────┘        │        │  └───────────────────┘    │        │                               │ 
                      │                                │        │                           │        │                               │ 
                      │   ┌───────────────────┐        │        │                           │        │   ┌───────────────────┐       │ 
                      │   │  BrowsingContext  │        │        │  ┌───────────────────┐    │        │   │  BrowsingContext  │       │ 
                      │   │    TargetFront    │        │        │  │ FrameConnector +  │    │        │   │    TargetActor    │       │ 
                      │   │   (for domainA)   │        │        │  │  MessageManager   │    │        │   │   (for domainA)   │       │ 
                      │   └─────────┬─────────┘        │        │  └─────────┬─────────┘    │        │   └───────────────────┘       │ 
                      │             │                  │        │            │              │        │                               │ 
                      │   ┌─────────┴─────────┐       get watcher  ┌─────────┴─────────┐    │        │                               │ 
                      │   │   TabDescriptor   │────────┼────────┼─▶│   TabDescriptor   │────┼┐       │                               │ 
                      │   │       Front       │        │        │  │       Actor       │    ││       │                               │ 
                      │   └─────────╦─────────┘        │        │  └─────────╦─────────┘    ││       └───────────────────────────────┘ 
                      │   ┌─────────╩─────────┐        │        │  ┌─────────╩─────────┐    ││                                         
                      │   │      Watcher      │◀───────┼────────┼──│      Watcher      │◀───┼┘       ┌───────────────────────────────┐ 
                      │   │       Front       │────────┼────────┼─▶│       Actor       │────┼┐       │   Server Content domainB      │ 
                      │   └───────────────────┘     watch targets  └───────────────────┘    ││       │                               │ 
                      │                                │        │                       register +   │                               │ 
                      │                                │        │                   update sharedData│                               │ 
                      │                                │        │                           ││       │                               │ 
                      │                                │        │  ┌───────────────────┐    ││       │   ┌───────────────────┐       │ 
                      │                                │        │  │ FrameWatchers.jsm │◀───┼┘      ┌┼──▶│   DevToolsFrame   │────┐  │ 
                      │                                │        │  │                   │────┼┐      ││   │     Child.jsm     │    │  │ 
                      │                                │        │  └───────────────────┘  create    ││   └─────────┬─────────┘    │  │ 
                      │                                │        │  ┌───────────────────┐    ││      ││           create           │  │ 
                      │                                │        │  │   DevToolsFrame   │◀───┼┘      ││      server + target       │  │ 
                      │   ┌───────────────────┐        │        │  │    Parent.jsm     │────┼───────┘│             │              │  │ 
                      │   │  BrowsingContext  │        │        │  └───────────────────┘ "instantiate│   ┌─────────▼─────────┐    │  │ 
                      │   │    TargetFront    │        │        │                        -already    │   │  BrowsingContext  │    │  │ 
                      │   │   (for domainB)   │        │        │                        -available" │   │    TargetActor    │    │  │ 
                      │   └───────────────────┘        │        │                           │        │   │   (for domainB)   │    │  │ 
                      │             ▲                  │        │                           │        │   └───────────────────┘    │  │ 
                      └─────────────┼──────────────────┘        └───────────────────────────┘        └────────────────────────────┼──┘ 
                                    └─────────────────────────────────────────────────────────────────────────────────────────────┘    
                                     The "way back" is more complicated than this:                                                     
                                     - the Child JsWindowActor sends the form of the target to the Parent JsWindowActor                
                                     - parent JsWindowActor finds the corresponding WatcherActor via FrameWatchers                     
                                     - a "target-form-available" is finally  emitted from the WatcherActor                             
                                                                                                                                       
                                                                                                                                       
                                            ┌──────────────────────────────────────────────────────────────────────┐                   
                                            │ Shared Data: perPrefixMap (updated by WatcherActor, read by DevToolsFrameChild)          
                                            ├─────────────────────┬───────────────┬────────────────────────────────┤                   
                                            │ conn.prefix.12      │ ["frames"]    │ browsingContextId for domainA  │                   
                                            ├─────────────────────┼───────────────┼────────────────────────────────┤                   
                                            │  ...                │  ...          │  ...                           │                   
                                            └─────────────────────┴───────────────┴────────────────────────────────┘                   
                                            ┌──────────────────────────────────────────────────────────────────────┐                   
                                            │ FrameWatchers.jsm:                                                   │                   
                                            │                                                                      │                   
                                            │ Parent process singleton which can create Parent DevTools            │                   
                                            │ JsWindowActors for existing remote frames.                           │                   
                                            │                                                                      │                   
                                            │ It also contains a map of WatcherActors keyed by "parent connection  │                   
                                            │ prefix". Combined with the info in SharedData:perPrefixMap, this     │                   
                                            │ allows to find existing watchers when new remote frames are created. │                   
                                            │                                                                      │                   
                                            │ Finally it is responsible for registering the DevTools               │                   
                                            │ JsWindowActors in the global ActorParentRegistry of the Browser.     │                   
                                            └──────────────────────────────────────────────────────────────────────┘                   
                                                                                                                                       
                                                                                                                                       
                                                                                                                                       
                                                                                                                                       
                                                                                                                                       
        ╔══════════════════════════════════════════╗                                                                                   
        ║                                          ║                                                                                   
        ║   IF THE FRAME NAVIGATES TO DOMAIN C?    ║                                                                                   
        ║                                          ║                                                                                   
        ╚══════════════════════════════════════════╝                                                                                   
                                                                                                                                       
                     ┌────────────────────────────────┐        ┌───────────────────────────┐        ┌───────────────────────────────┐  
                     │ Client                         │        │ Server Parent             │        │   Server Content domainA      │  
                     │                                │        │                           │        │                               │  
                     │   ┌───────────────────┐        │        │  ┌───────────────────┐    │        │                               │  
                     │   │       Root        │        │        │  │       Root        │    │        │                               │  
                     │   │       Front       │        │        │  │       Actor       │    │        │                               │  
                     │   └───────────────────┘        │        │  └───────────────────┘    │        │                               │  
                     │                                │        │                           │        │                               │  
                     │   ┌───────────────────┐        │        │                           │        │   ┌───────────────────┐       │  
                     │   │  BrowsingContext  │        │        │  ┌───────────────────┐    │        │   │  BrowsingContext  │       │  
                     │   │    TargetFront    │        │        │  │ FrameConnector +  │    │        │   │    TargetActor    │       │  
                     │   │   (for domainA)   │        │        │  │  MessageManager   │    │        │   │   (for domainA)   │       │  
                     │   └─────────┬─────────┘        │        │  └─────────┬─────────┘    │        │   └───────────────────┘       │  
                     │             │                  │        │            │              │        │                               │  
                     │   ┌─────────┴─────────┐        │        │  ┌─────────┴─────────┐    │        │                               │  
                     │   │   TabDescriptor   │        │        │  │   TabDescriptor   │    │        │                               │  
                     │   │       Front       │        │        │  │       Actor       │    │        │                               │  
                     │   └─────────╦─────────┘        │        │  └─────────╦─────────┘    │        └───────────────────────────────┘  
                     │   ┌─────────╩─────────┐        │        │  ┌─────────╩─────────┐    │                                           
                     │   │      Watcher      │        │        │  │      Watcher      │    │        ┌───────────────────────────────┐  
                     │   │       Front       │        │        │  │       Actor       │    │        │                               │  
                     │   └───────────────────┘        │        │  └───────────────────┘    │        │   Server Content domainB      │  
                     │                                │        │                           │        │                               │  
                     │                                │        │                           │        │                               │  
                     │                                │        │                           │        │                               │  
                     │                                │        │  ┌───────────────────┐    │        │   ┌───────────────────┐       │  
                     │                                │        │  │ FrameWatchers.jsm │    │        │   │   DevToolsFrame   │       │  
                     │                                │        │  │                   │    │        │   │     Child.jsm     │       │  
                     │                                │        │  └───────────────────┘    │        │   └───────────────────┘       │  
                     │                                │        │  ┌───────────────────┐    │        │                               │  
                     │                                │        │  │   DevToolsFrame   │    │        │                               │  
                     │   ┌───────────────────┐        │        │  │    Parent.jsm     │    │        │                               │  
                     │   │  BrowsingContext  │        │        │  └───────────────────┘    │        │   ┌───────────────────┐       │  
                     │   │    TargetFront    │        │        │                           │        │   │  BrowsingContext  │       │  
                     │   │   (for domainB)   │        │        │                           │        │   │    TargetActor    │       │  
                     │   └───────────────────┘        │        │                           │        │   │   (for domainB)   │       │  
                     │                                │        │                           │        │   └───────────────────┘       │  
                     └────────────────────────────────┘        └───────────────────────────┘        └───────────────────────────────┘  
                                                                                                                                       
                                                                                                                                       
                                                                                                                                       
            First the JsWindowActors related to the domainB WindowGlobal will be destroyed.                                            
            Everything in red disappears.                                                                                              
                                                                                                                                       
                                                                                                                                       
                                                                                                                                       
                     ┌────────────────────────────────┐        ┌───────────────────────────┐        ┌───────────────────────────────┐  
                     │ Client                         │        │ Server Parent             │        │   Server Content domainA      │  
                     │                                │        │                           │        │                               │  
                     │   ┌───────────────────┐        │        │  ┌───────────────────┐    │        │                               │  
                     │   │       Root        │        │        │  │       Root        │    │        │                               │  
                     │   │       Front       │        │        │  │       Actor       │    │        │                               │  
                     │   └───────────────────┘        │        │  └───────────────────┘    │        │                               │  
                     │                                │        │                           │        │                               │  
                     │   ┌───────────────────┐        │        │                           │        │   ┌───────────────────┐       │  
                     │   │  BrowsingContext  │        │        │  ┌───────────────────┐    │        │   │  BrowsingContext  │       │  
                     │   │    TargetFront    │        │        │  │ FrameConnector +  │    │        │   │    TargetActor    │       │  
                     │   │   (for domainA)   │        │        │  │  MessageManager   │    │        │   │   (for domainA)   │       │  
                     │   └─────────┬─────────┘        │        │  └─────────┬─────────┘    │        │   └───────────────────┘       │  
                     │             │                  │        │            │              │        │                               │  
                     │   ┌─────────┴─────────┐        │        │  ┌─────────┴─────────┐    │        │                               │  
                     │   │   TabDescriptor   │        │        │  │   TabDescriptor   │    │        │                               │  
                     │   │       Front       │        │        │  │       Actor       │    │        │                               │  
                     │   └─────────╦─────────┘        │        │  └─────────╦─────────┘    │        └───────────────────────────────┘  
                     │   ┌─────────╩─────────┐        │        │  ┌─────────╩─────────┐    │                                           
                     │   │      Watcher      │        │        │  │      Watcher      │    │                                           
                     │   │       Front       │        │        │  │       Actor       │    │                                           
                     │   └───────────────────┘        │        │  └───────────────────┘    │                                           
                     │                                │        │                           │                                           
                     │                                │        │                           │                                           
                     │                                │        │                           │                                           
                     │                                │        │  ┌───────────────────┐    │                                           
                     │                                │        │  │ FrameWatchers.jsm │    │                                           
                     │                                │        │  │                   │    │                                           
                     │                                │        │  └───────────────────┘    │                                           
                     │                                │        │                           │                                           
                     │                                │        │                           │                                           
                     │                                │        │                           │                                           
                     │                                │        │                           │                                           
                     │                                │        │                           │                                           
                     │                                │        │                           │                                           
                     │                                │        │                           │                                           
                     │                                │        │                           │                                           
                     └────────────────────────────────┘        └───────────────────────────┘                                           
                                                                                                                                       
                                                                                                                                       
             A new window global is created for domainC. When FrameWatchers.jsm registered the DevTools JS                             
             Window actors, it specified that the DevToolsWindowChild should be created for any                                        
             DOMWindowCreated event.                                                                                                   
                                                                                                                                       
             So here a new DevToolsFrameChild will automatically be created.                                                           
                                                                                                                                       
                                                                                                                                       
                                                                                                                                       
                    ┌────────────────────────────────┐        ┌───────────────────────────┐        ┌───────────────────────────────┐   
                    │ Client                         │        │ Server Parent             │        │   Server Content domainA      │   
                    │                                │        │                           │        │                               │   
                    │   ┌───────────────────┐        │        │  ┌───────────────────┐    │        │                               │   
                    │   │       Root        │        │        │  │       Root        │    │        │                               │   
                    │   │       Front       │        │        │  │       Actor       │    │        │                               │   
                    │   └───────────────────┘        │        │  └───────────────────┘    │        │                               │   
                    │                                │        │                           │        │                               │   
                    │   ┌───────────────────┐        │        │                           │        │   ┌───────────────────┐       │   
                    │   │  BrowsingContext  │        │        │  ┌───────────────────┐    │        │   │  BrowsingContext  │       │   
                    │   │    TargetFront    │        │        │  │ FrameConnector +  │    │        │   │    TargetActor    │       │   
                    │   │   (for domainA)   │        │        │  │  MessageManager   │    │        │   │   (for domainA)   │       │   
                    │   └─────────┬─────────┘        │        │  └─────────┬─────────┘    │        │   └───────────────────┘       │   
                    │             │                  │        │            │              │        │                               │   
                    │   ┌─────────┴─────────┐        │        │  ┌─────────┴─────────┐    │        │                               │   
                    │   │   TabDescriptor   │        │        │  │   TabDescriptor   │    │        │                               │   
                    │   │       Front       │        │        │  │       Actor       │    │        │                               │   
                    │   └─────────╦─────────┘        │        │  └─────────╦─────────┘    │        └───────────────────────────────┘   
                    │   ┌─────────╩─────────┐        │        │  ┌─────────╩─────────┐    │                                            
                    │   │      Watcher      │        │        │  │      Watcher      │    │                                            
                    │   │       Front       │        │        │  │       Actor       │    │        ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐   
                    │   └───────────────────┘        │        │  └───────────────────┘    │          WindowGlobal for domainC          
                    │                                │        │                           │        │                               │   
                    │                                │        │                           │                                            
                    │                                │        │                           │        │                               │   
                    │                                │        │  ┌───────────────────┐    │            ┌───────────────────┐           
                    │                                │        │  │ FrameWatchers.jsm │    │        │   │   DevToolsFrame   │       │   
                    │                                │        │  │                   │    │            │     Child.jsm     │           
                    │                                │        │  └───────────────────┘    │        │   └───────────────────┘       │   
                    │                                │        │                           │                                            
                    │                                │        │                           │        │                               │   
                    │                                │        │                           │                                            
                    │                                │        │                           │        │                               │   
                    │                                │        │                           │                                            
                    │                                │        │                           │        │                               │   
                    │                                │        │                           │                                            
                    │                                │        │                           │        │                               │   
                    └────────────────────────────────┘        └───────────────────────────┘         ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─    
                                                                                                                                       
                                                                                                                                       
              DevToolsFrameChild will now check SharedData:perPrefixMap to know if a Server and Target should                          
              be created for this new WindowGlobal.                                                                                    
                                                                                                                                       
              It will find that we are watching "frames" for the BrowsingContextID that corresponds to its                             
              parent BrowsingContext (domainA), and will proceed to create a Server, Target and forward it to                          
              its parent actor.                                                                                                        
                                                                                                                                       
                                                                                                                                       
                    ┌──────────────────────────────────────────────────────────────────────┐                                           
                    │ Shared Data: perPrefixMap (updated by WatcherActor, read by DevToolsFrameChild)                                  
                    ├─────────────────────┬───────────────┬────────────────────────────────┤                                           
                    │ conn.prefix.12      │ ["frames"]    │ browsingContextId for domainA  │                                           
                    ├─────────────────────┼───────────────┼────────────────────────────────┤                                           
                    │  ...                │  ...          │  ...                           │                                           
                    └─────────────────────┴───────────────┴────────────────────────────────┘                                           
                                                                                                                                       
                                                                                                                                       
                                                              ┌───────────────────────────┐        ┌───────────────────────────────┐   
                   ┌──Client────────────────────────┐         │ Server Parent             │        │   Server Content domainA      │   
                   │                                │         │                           │        │                               │   
                   │    ┌───────────────────┐       │         │  ┌───────────────────┐    │        │                               │   
                   │    │       Root        │       │         │  │       Root        │    │        │                               │   
                   │    │       Front       │       │         │  │       Actor       │    │        │                               │   
                   │    └───────────────────┘       │         │  └───────────────────┘    │        │                               │   
                   │                                │         │                           │        │                               │   
                   │    ┌───────────────────┐       │         │                           │        │   ┌───────────────────┐       │   
                   │    │  BrowsingContext  │       │         │  ┌───────────────────┐    │        │   │  BrowsingContext  │       │   
                   │    │    TargetFront    │       │         │  │ FrameConnector +  │    │        │   │    TargetActor    │       │   
                   │    │   (for domainA)   │       │         │  │  MessageManager   │    │        │   │   (for domainA)   │       │   
                   │    └─────────┬─────────┘       │         │  └─────────┬─────────┘    │        │   └───────────────────┘       │   
                   │              │                 │         │            │              │        │                               │   
                   │    ┌─────────┴─────────┐       │         │  ┌─────────┴─────────┐    │        │                               │   
                   │    │   TabDescriptor   │       │         │  │   TabDescriptor   │    │        │                               │   
                   │    │       Front       │       │         │  │       Actor       │    │        │                               │   
                   │    └─────────╦─────────┘       emit:     │  └─────────╦─────────┘    │        └───────────────────────────────┘   
                   │    ┌─────────╩─────────┐    target-form  │  ┌─────────╩─────────┐    │                                            
                   │    │      Watcher      │◀───-available───┼──│      Watcher      │    │                                            
                   │    │       Front       │       │        ┌┼─▶│       Actor       │    │        ┌───────────────────────────────┐   
                   │    └───────────────────┘       │        ││  └───────────────────┘    │        │  Server Content domainC       │   
                   │              │                 │        ││                           │        │                               │   
                   │              │                 │   watchers.get(..)                  │        │                               │   
                   │              │                 │        ││                           │        │                               │   
                   │            create              │        ││  ┌───────────────────┐    │        │   ┌───────────────────┐       │   
                   │              │                 │        └┼──│ FrameWatchers.jsm │    │        │   │   DevToolsFrame   │       │   
                   │              │                 │        ┌┼─▶│                   │    │   ┌────┼───│     Child.jsm     │       │   
                   │              │                 │        ││  └───────────────────┘    │   │    │   └───────────────────┘       │   
                   │              ▼                 │   get watcher                       │  connect from                          │   
                   │    ┌───────────────────┐       │        ││  ┌───────────────────┐    │   │content                             │   
                   │    │  BrowsingContext  │       │        └┼──│   DevToolsFrame   │    │   │    │   ┌───────────────────┐       │   
                   │    │    TargetFront    │       │         │  │    Parent.jsm     │◀───┼───┘    │   │  BrowsingContext  │       │   
                   │    │   (for domainC)   │       │         │  └───────────────────┘    │        │   │    TargetActor    │       │   
                   │    └───────────────────┘       │         │                           │        │   │   (for domainC)   │       │   
                   │                                │         │                           │        │   └───────────────────┘       │   
                   │                                │         │                           │        │                               │   
                   │                                │         └───────────────────────────┘        └───────────────────────────────┘   
                   └────────────────────────────────┘                                                                                  
                   
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment