1
------------------------------------------------------------------------------
2
--                                                                          --
3
--                           OCARINA COMPONENTS                             --
4
--                                                                          --
5
--                 OCARINA.BACKENDS.CONNECTION_MATRIX.MAIN                  --
6
--                                                                          --
7
--                                 B o d y                                  --
8
--                                                                          --
9
--         Copyright (C) 2011-2019 ESA & ISAE, 2019-2020 OpenAADL           --
10
--                                                                          --
11
-- Ocarina  is free software; you can redistribute it and/or modify under   --
12
-- terms of the  GNU General Public License as published  by the Free Soft- --
13
-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
14
-- sion. Ocarina is distributed in the hope that it will be useful, but     --
15
-- WITHOUT ANY WARRANTY; without even the implied warranty of               --
16
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                     --
17
--                                                                          --
18
-- As a special exception under Section 7 of GPL version 3, you are granted --
19
-- additional permissions described in the GCC Runtime Library Exception,   --
20
-- version 3.1, as published by the Free Software Foundation.               --
21
--                                                                          --
22
-- You should have received a copy of the GNU General Public License and    --
23
-- a copy of the GCC Runtime Library Exception along with this program;     --
24
-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
25
-- <http://www.gnu.org/licenses/>.                                          --
26
--                                                                          --
27
--                    Ocarina is maintained by OpenAADL team                --
28
--                              (info@openaadl.org)                         --
29
--                                                                          --
30
------------------------------------------------------------------------------
31

32
with Ocarina.ME_AADL;
33
with Ocarina.ME_AADL.AADL_Instances.Nodes;
34
with Ocarina.ME_AADL.AADL_Instances.Nutils;
35
with Ocarina.ME_AADL.AADL_Instances.Entities;
36

37
with Ocarina.Instances.Queries;
38

39
with Ocarina.ME_AADL.AADL_Tree.Nodes;
40

41
with Ocarina.Backends.Properties;
42
with Ocarina.Backends.XML_Tree.Nodes;
43
with Ocarina.Backends.XML_Tree.Nutils;
44

45
with Ocarina.Namet; use Ocarina.Namet;
46

47 1
package body Ocarina.Backends.Connection_Matrix.Main is
48

49
   use Ocarina.ME_AADL;
50
   use Ocarina.ME_AADL.AADL_Instances.Nodes;
51
   use Ocarina.ME_AADL.AADL_Instances.Entities;
52
   use Ocarina.Backends.Properties;
53
   use Ocarina.Backends.XML_Tree.Nutils;
54

55
   use Ocarina.Instances.Queries;
56

57
   package ATN renames Ocarina.ME_AADL.AADL_Tree.Nodes;
58
   package AIN renames Ocarina.ME_AADL.AADL_Instances.Nodes;
59
   package AINU renames Ocarina.ME_AADL.AADL_Instances.Nutils;
60
   package XTN renames Ocarina.Backends.XML_Tree.Nodes;
61

62
   procedure Visit_Architecture_Instance (E : Node_Id);
63
   procedure Visit_Component_Instance (E : Node_Id);
64
   procedure Visit_System_Instance (E : Node_Id);
65

66 1
   Current_Parent_Node : Node_Id;
67 1
   My_Root             : Node_Id;
68

69
   -----------
70
   -- Visit --
71
   -----------
72

73 1
   procedure Visit (E : Node_Id) is
74
   begin
75
      case Kind (E) is
76 1
         when K_Architecture_Instance =>
77 1
            Visit_Architecture_Instance (E);
78

79 1
         when K_Component_Instance =>
80 1
            Visit_Component_Instance (E);
81

82 0
         when others =>
83 0
            null;
84
      end case;
85 1
   end Visit;
86

87
   ---------------------------------
88
   -- Visit_Architecture_Instance --
89
   ---------------------------------
90

91 1
   procedure Visit_Architecture_Instance (E : Node_Id) is
92 1
      N     : constant Node_Id := New_Node (XTN.K_HI_Node);
93 1
      D     : constant Node_Id := New_Node (XTN.K_HI_Distributed_Application);
94 1
      U     : Node_Id;
95 1
      T     : Node_Id;
96 1
      P     : Node_Id;
97 1
      Q     : Node_Id;
98 1
      Tmp   : Node_Id;
99 1
      H1    : Node_Id;
100 1
      Title : Node_Id;
101
   begin
102 1
      My_Root := Root_System (E);
103

104 1
      XML_Root := D;
105

106 1
      Get_Name_String (To_XML_Name (AIN.Name (AIN.Identifier (My_Root))));
107

108 1
      XTN.Set_Name (D, Name_Find);
109 1
      XTN.Set_Units (D, New_List (XTN.K_List_Id));
110 1
      XTN.Set_HI_Nodes (D, New_List (XTN.K_List_Id));
111

112 1
      Push_Entity (D);
113

114 1
      Set_Str_To_Name_Buffer ("general");
115 1
      XTN.Set_Name (N, Name_Find);
116

117 1
      XTN.Set_Units (N, New_List (XTN.K_List_Id));
118

119
      --  Append the partition N to the node list
120

121 1
      Append_Node_To_List (N, XTN.HI_Nodes (Current_Entity));
122 1
      XTN.Set_Distributed_Application (N, Current_Entity);
123

124 1
      Push_Entity (N);
125

126 1
      U := New_Node (XTN.K_HI_Unit, AIN.Identifier (My_Root));
127 1
      Get_Name_String (To_XML_Name (Display_Name (Identifier (My_Root))));
128 1
      Add_Str_To_Name_Buffer ("_connection_matrix");
129 1
      T := Make_Defining_Identifier (Name_Find);
130 1
      P := Make_XML_File (T);
131

132
      --  This is a special XML file, we specify .html extension
133 1
      XTN.Set_Is_HTML (P, True);
134 1
      XTN.Set_Distributed_Application_Unit (P, U);
135 1
      XTN.Set_XML_File (U, P);
136

137
      --   Make the main <html> node in the XML file.
138 1
      XTN.Set_Root_Node (P, Make_XML_Node ("html"));
139

140 1
      Append_Node_To_List (U, XTN.Units (Current_Entity));
141 1
      XTN.Set_Entity (U, Current_Entity);
142

143 1
      Push_Entity (U);
144

145 1
      Current_Parent_Node := XTN.Root_Node (XTN.XML_File (U));
146

147
      --  Make the <head> node of the HTML file.
148 1
      Tmp := Make_XML_Node ("head");
149

150 1
      Append_Node_To_List (Tmp, XTN.Subitems (Current_Parent_Node));
151

152
      --  Add a title in the <head> section node
153 1
      Title := Make_XML_Node ("title");
154

155 1
      Set_Str_To_Name_Buffer ("Connectivity Matrix for System ");
156 1
      Get_Name_String_And_Append (Display_Name (Identifier (My_Root)));
157

158 1
      XTN.Set_Node_Value (Title, Make_Defining_Identifier (Name_Find));
159

160 1
      Append_Node_To_List (Title, XTN.Subitems (Tmp));
161

162
      --  Make the <body>...</body> node of the HTML file.
163 1
      Tmp := Make_XML_Node ("body");
164 1
      Append_Node_To_List (Tmp, XTN.Subitems (Current_Parent_Node));
165 1
      Current_Parent_Node := Tmp;
166

167
      --  Title of the document, using a <h1>...</h1> node
168 1
      Tmp := Make_XML_Node ("h1");
169 1
      Append_Node_To_List (Tmp, XTN.Subitems (Current_Parent_Node));
170

171
      --  Style of the <h1> node
172 1
      Set_Str_To_Name_Buffer
173
        ("font-family: Arial;" &
174
         "text-align: center; font-weight: bold; font-size: 1.2em");
175 1
      P := Make_Defining_Identifier (Name_Find);
176 1
      Set_Str_To_Name_Buffer ("style");
177 1
      Q := Make_Defining_Identifier (Name_Find);
178 1
      Append_Node_To_List (Make_Assignement (Q, P), XTN.Items (Tmp));
179

180
      --  Title of the document
181 1
      Set_Str_To_Name_Buffer ("Connectivity Matrix for System ");
182 1
      Get_Name_String_And_Append (Display_Name (Identifier (My_Root)));
183 1
      H1 := Make_Defining_Identifier (Name_Find);
184

185 1
      XTN.Set_Node_Value (Tmp, H1);
186

187 1
      Visit (My_Root);
188

189 1
      Pop_Entity;
190 1
      Pop_Entity;
191 1
      Pop_Entity;
192 1
   end Visit_Architecture_Instance;
193

194
   ------------------------------
195
   -- Visit_Component_Instance --
196
   ------------------------------
197

198 1
   procedure Visit_Component_Instance (E : Node_Id) is
199 1
      Category : constant Component_Category := Get_Category_Of_Component (E);
200
   begin
201
      case Category is
202
         when CC_System =>
203 1
            Visit_System_Instance (E);
204

205
         when others =>
206
            null;
207
      end case;
208 1
   end Visit_Component_Instance;
209

210
   ---------------------------
211
   -- Visit_System_Instance --
212
   ---------------------------
213

214 1
   procedure Visit_System_Instance (E : Node_Id) is
215 1
      S                : Node_Id;
216 1
      N                : Node_Id;
217 1
      Conn             : Node_Id;
218 1
      T                : Node_Id;
219 1
      TR               : Node_Id;
220 1
      TD               : Node_Id;
221 1
      UL               : Node_Id;
222 1
      LI               : Node_Id;
223 1
      H2               : Node_Id;
224 1
      Table            : Node_Id;
225 1
      P                : Node_Id;
226 1
      Q                : Node_Id;
227 1
      Connected        : Boolean;
228 1
      Source_Component : Node_Id;
229 1
      Dest_Component   : Node_Id;
230 1
      Bandwidth        : Unsigned_Long_Long;
231 1
      Bandwidth_Unit   : Name_Id;
232 1
      Latency          : Unsigned_Long_Long;
233 1
      Latency_Unit     : Name_Id;
234 1
      Associated_Bus   : Node_Id;
235 1
      Has_Bus          : Boolean := False;
236 1
      Bus_Instance     : Node_Id;
237
   begin
238
      --  Declare the table node that will contain the connectivity matrix.
239 1
      Table := Make_XML_Node ("table");
240

241
      --  Some CSS style to apply on the table.
242 1
      Set_Str_To_Name_Buffer ("border-style: solid; border-width: 1px;");
243 1
      P := Make_Defining_Identifier (Name_Find);
244 1
      Set_Str_To_Name_Buffer ("style");
245 1
      Q := Make_Defining_Identifier (Name_Find);
246 1
      Append_Node_To_List (Make_Assignement (Q, P), XTN.Items (Table));
247

248 1
      if not AINU.Is_Empty (Subcomponents (E)) then
249

250
         --  Add a <tr> node that represent a line.
251 1
         TR := Make_XML_Node ("tr");
252

253
         --  Add a <td> node that represent a colon in the line.
254 1
         TD := Make_XML_Node ("td");
255

256 1
         Append_Node_To_List (TD, XTN.Subitems (TR));
257

258 1
         S := First_Node (Subcomponents (E));
259

260
         --  In the following loop, we build a complete line
261
         --  that contains the name of all system subcomponents.
262 1
         while Present (S) loop
263 1
            if Get_Category_Of_Component (S) = CC_Bus then
264 1
               Has_Bus := True;
265
            else
266

267 1
               TD := Make_XML_Node ("td");
268

269 1
               Set_Str_To_Name_Buffer
270
                 ("font-family: Arial; background-color: #0a97ac;" &
271
                  "text-align: center; font-weight: bold; font-size: 0.8em");
272 1
               P := Make_Defining_Identifier (Name_Find);
273 1
               Set_Str_To_Name_Buffer ("style");
274 1
               Q := Make_Defining_Identifier (Name_Find);
275 1
               Append_Node_To_List (Make_Assignement (Q, P), XTN.Items (TD));
276

277 1
               Get_Name_String (Display_Name (Identifier (S)));
278

279 1
               N := Make_Defining_Identifier (Name_Find);
280 1
               XTN.Set_Node_Value (TD, N);
281

282 1
               Append_Node_To_List (TD, XTN.Subitems (TR));
283
            end if;
284 1
            S := Next_Node (S);
285 1
         end loop;
286

287 1
         Append_Node_To_List (TR, XTN.Subitems (Table));
288
      end if;
289

290 1
      if not AINU.Is_Empty (Subcomponents (E)) then
291 1
         S := First_Node (Subcomponents (E));
292

293
         --  In the following loop, we iterate on each subcomponents
294
         --  and analyzes which one is connected.
295 1
         while Present (S) loop
296 1
            if Get_Category_Of_Component (S) /= CC_Bus then
297
               --  Create a new line (<tr> node).
298 1
               TR := Make_XML_Node ("tr");
299

300
               --  Create a new colon that contain the name of the
301
               --  sub-component being analyzed.
302 1
               TD := Make_XML_Node ("td");
303

304 1
               Set_Str_To_Name_Buffer
305
                 ("font-family: Arial; background-color: #0a97ac;" &
306
                  "text-align: center; font-weight: bold; font-size: 0.8em");
307 1
               P := Make_Defining_Identifier (Name_Find);
308 1
               Set_Str_To_Name_Buffer ("style");
309 1
               Q := Make_Defining_Identifier (Name_Find);
310 1
               Append_Node_To_List (Make_Assignement (Q, P), XTN.Items (TD));
311

312 1
               Get_Name_String (Display_Name (Identifier (S)));
313

314 1
               N := Make_Defining_Identifier (Name_Find);
315 1
               XTN.Set_Node_Value (TD, N);
316

317 1
               Append_Node_To_List (TD, XTN.Subitems (TR));
318

319 1
               T := First_Node (Subcomponents (E));
320

321
               --  Here, we iterate again on all system sub-components
322
               --  and try to see which one is connected to the component
323
               --  actually analyzed (S).
324

325 1
               while Present (T) loop
326

327 1
                  if Get_Category_Of_Component (T) /= CC_Bus then
328 1
                     TD := Make_XML_Node ("td");
329

330
                     --  Default initialization.
331 1
                     Connected      := False;
332 1
                     Bandwidth      := 0;
333 1
                     Associated_Bus := No_Node;
334

335 1
                     if not AINU.Is_Empty (AIN.Connections (E)) then
336 1
                        Conn := First_Node (AIN.Connections (E));
337 1
                        while Present (Conn) loop
338 1
                           if Kind (Conn) = K_Connection_Instance then
339 1
                              if Get_Category_Of_Connection (Conn) =
340
                                CT_Port_Connection
341
                              then
342
                                 Source_Component :=
343 1
                                   Item
344 1
                                     (AIN.First_Node (Path (Source (Conn))));
345

346
                                 Dest_Component :=
347 1
                                   Item
348 1
                                     (AIN.First_Node
349 1
                                        (Path (Destination (Conn))));
350 1
                                 if Dest_Component = T
351 1
                                   and then Source_Component = S
352
                                 then
353

354
                                    Associated_Bus :=
355 1
                                      Get_Bound_Bus (Conn, False);
356

357 1
                                    if Is_Defined_Property
358
                                        (Conn,
359
                                         "bus_properties::required_bandwidth")
360
                                    then
361
                                       Bandwidth :=
362 1
                                         Get_Integer_Property
363
                                           (Conn,
364
                                            "bus_properties:" &
365
                                            ":required_bandwidth");
366

367
                                       Bandwidth_Unit :=
368 1
                                         ATN.Name
369 1
                                           (ATN.Unit_Identifier
370 1
                                            (Get_Value_Of_Property_Association
371
                                               (Conn,
372 1
                                                Get_String_Name
373
                                                  ("bus_properties:" &
374
                                                     ":required_bandwidth"))));
375 1
                                       Connected := True;
376
                                    end if;
377
                                 end if;
378
                              end if;
379
                           end if;
380 1
                           Conn := Next_Node (Conn);
381 1
                        end loop;
382
                     end if;
383

384 1
                     N := No_Node;
385

386
                     --  If S = T, then, the component analyzed and the
387
                     --  component on which we iterate are the same. So,
388
                     --  we just put the cell in grey.
389

390 1
                     if S = T then
391 1
                        Set_Str_To_Name_Buffer ("background-color: grey;");
392 1
                        P := Make_Defining_Identifier (Name_Find);
393 1
                        Set_Str_To_Name_Buffer ("style");
394 1
                        Q := Make_Defining_Identifier (Name_Find);
395 1
                        Append_Node_To_List
396 1
                          (Make_Assignement (Q, P),
397 1
                           XTN.Items (TD));
398

399
                     --  If Connected is true, the component being analyzed
400
                     --  and the component on which we iterate are not the
401
                     --  same AND are connected. In that case, we put the cell
402
                     --  in green and print the required bandwidth and (if
403
                     --  specified) the bus associated to the connection.
404

405 1
                     elsif Connected then
406 1
                        if Bandwidth /= 0 then
407 1
                           Set_Str_To_Name_Buffer ("<strong>");
408 1
                           Add_Str_To_Name_Buffer
409 1
                             (Unsigned_Long_Long'Image (Bandwidth));
410 1
                           Get_Name_String_And_Append (Bandwidth_Unit);
411 1
                           Add_Str_To_Name_Buffer ("</strong>");
412

413
                           --  Put information about the associated
414
                           --  bus if specified.
415

416 1
                           if Associated_Bus /= No_Node then
417 1
                              Add_Str_To_Name_Buffer ("<br/><em>(");
418 1
                              Get_Name_String_And_Append
419 1
                                (Display_Name (Identifier (Associated_Bus)));
420 1
                              Add_Str_To_Name_Buffer (")</em>");
421
                           else
422 0
                              Add_Str_To_Name_Buffer
423
                                ("<br/>(<em>unknwon bus</em>)");
424
                           end if;
425 1
                           N := Make_Defining_Identifier (Name_Find);
426

427 1
                           Set_Str_To_Name_Buffer
428
                             ("font-family: Arial; " &
429
                              "background-color: #91ff94;" &
430
                              "text-align: center; font-size: 0.8em");
431 1
                           P := Make_Defining_Identifier (Name_Find);
432 1
                           Set_Str_To_Name_Buffer ("style");
433 1
                           Q := Make_Defining_Identifier (Name_Find);
434 1
                           Append_Node_To_List
435 1
                             (Make_Assignement (Q, P),
436 1
                              XTN.Items (TD));
437
                        else
438

439
                           --  We put N/A in the cell as a text when
440
                           --  the required bandwidth size is not specified.
441

442 0
                           Set_Str_To_Name_Buffer ("N/A");
443 0
                           N := Make_Defining_Identifier (Name_Find);
444
                        end if;
445
                     else
446
                        --  Components are not connected, we put
447
                        --  the cell to red.
448 1
                        Set_Str_To_Name_Buffer
449
                          ("font-family: Arial; " &
450
                           "background-color: #b83f3f;" &
451
                           "text-align: center; font-size: 0.8em");
452 1
                        P := Make_Defining_Identifier (Name_Find);
453 1
                        Set_Str_To_Name_Buffer ("style");
454 1
                        Q := Make_Defining_Identifier (Name_Find);
455 1
                        Append_Node_To_List
456 1
                          (Make_Assignement (Q, P),
457 1
                           XTN.Items (TD));
458
                     end if;
459

460 1
                     if N /= No_Node then
461 1
                        XTN.Set_Node_Value (TD, N);
462
                     end if;
463

464 1
                     Append_Node_To_List (TD, XTN.Subitems (TR));
465
                  end if;
466 1
                  T := Next_Node (T);
467 1
               end loop;
468

469 1
               Append_Node_To_List (TR, XTN.Subitems (Table));
470
            end if;
471 1
            S := Next_Node (S);
472 1
         end loop;
473
      end if;
474

475
      --  Add the table to the main HTML node (<body/>).
476 1
      Append_Node_To_List (Table, XTN.Subitems (Current_Parent_Node));
477

478
      --  Now, we are enumerating all buses that are used
479
      --  in the model.
480

481 1
      if Has_Bus then
482

483
         --  Make a subtitle for the list of buses.
484 1
         H2 := Make_XML_Node ("h2");
485

486 1
         Set_Str_To_Name_Buffer
487
           ("font-family: Arial;" & "font-weight: bold; font-size: 1.2em");
488 1
         P := Make_Defining_Identifier (Name_Find);
489 1
         Set_Str_To_Name_Buffer ("style");
490 1
         Q := Make_Defining_Identifier (Name_Find);
491 1
         Append_Node_To_List (Make_Assignement (Q, P), XTN.Items (H2));
492

493 1
         Set_Str_To_Name_Buffer ("Buses used");
494 1
         N := Make_Defining_Identifier (Name_Find);
495 1
         XTN.Set_Node_Value (H2, N);
496

497 1
         Append_Node_To_List (H2, XTN.Subitems (Current_Parent_Node));
498

499
         --  Add a <ul> node that represent a line.
500 1
         UL := Make_XML_Node ("ul");
501

502 1
         S := First_Node (Subcomponents (E));
503

504
         --  In the following loop, we build a complete line
505
         --  that contains the name of all system subcomponents.
506 1
         while Present (S) loop
507 1
            if Get_Category_Of_Component (S) = CC_Bus then
508 1
               Bus_Instance := Corresponding_Instance (S);
509 1
               LI           := Make_XML_Node ("li");
510

511 1
               Set_Str_To_Name_Buffer
512
                 ("font-family: Arial;" & "font-size: 0.8em");
513 1
               P := Make_Defining_Identifier (Name_Find);
514 1
               Set_Str_To_Name_Buffer ("style");
515 1
               Q := Make_Defining_Identifier (Name_Find);
516 1
               Append_Node_To_List (Make_Assignement (Q, P), XTN.Items (LI));
517

518 1
               Bandwidth := 0;
519 1
               Latency   := 0;
520

521
               --  Try to find the bus properties: bandwidth and latency.
522 1
               if Is_Defined_Property
523
                   (Bus_Instance,
524
                    "bus_properties::bandwidth")
525
               then
526

527
                  Bandwidth :=
528 0
                    Get_Integer_Property
529
                      (Bus_Instance,
530
                       "bus_properties::bandwidth");
531

532
                  Bandwidth_Unit :=
533 0
                    ATN.Name
534 0
                      (ATN.Unit_Identifier
535 0
                         (Get_Value_Of_Property_Association
536
                            (Bus_Instance,
537 0
                             Get_String_Name ("bus_properties::bandwidth"))));
538
               end if;
539

540 1
               if Is_Defined_Property
541
                   (Bus_Instance,
542
                    "bus_properties::max_latency")
543
               then
544

545
                  Latency :=
546 0
                    Get_Integer_Property
547
                      (Bus_Instance,
548
                       "bus_properties::max_latency");
549

550
                  Latency_Unit :=
551 0
                    ATN.Name
552 0
                      (ATN.Unit_Identifier
553 0
                         (Get_Value_Of_Property_Association
554
                            (Bus_Instance,
555 0
                             Get_String_Name
556
                               ("bus_properties::max_latency"))));
557
               end if;
558

559
               --  First, display the name of the bus in bold
560
               --  using <strong/> tag.
561

562 1
               Set_Str_To_Name_Buffer ("<strong>");
563 1
               Get_Name_String_And_Append
564 1
                 (Display_Name (Identifier (Bus_Instance)));
565 1
               Add_Str_To_Name_Buffer ("</strong> (<em>");
566

567
               --  Then, put its properties between parenthesis.
568 1
               if Bandwidth = 0 and then Latency = 0 then
569 1
                  Add_Str_To_Name_Buffer ("bus properties are not declared");
570
               end if;
571

572 1
               if Bandwidth > 0 then
573 0
                  Add_Str_To_Name_Buffer ("bandwidth: ");
574 0
                  Add_Str_To_Name_Buffer
575 0
                    (Unsigned_Long_Long'Image (Bandwidth));
576 0
                  Get_Name_String_And_Append (Bandwidth_Unit);
577
               end if;
578

579 1
               if Latency > 0 then
580 0
                  Add_Str_To_Name_Buffer (" latency: ");
581 0
                  Add_Str_To_Name_Buffer (Unsigned_Long_Long'Image (Latency));
582 0
                  Get_Name_String_And_Append (Latency_Unit);
583
               end if;
584

585 1
               Add_Str_To_Name_Buffer ("</em>)");
586

587 1
               N := Make_Defining_Identifier (Name_Find);
588 1
               XTN.Set_Node_Value (LI, N);
589

590 1
               Append_Node_To_List (LI, XTN.Subitems (UL));
591
            end if;
592 1
            S := Next_Node (S);
593 1
         end loop;
594

595 1
         Append_Node_To_List (UL, XTN.Subitems (Current_Parent_Node));
596
      end if;
597

598 1
   end Visit_System_Instance;
599 1
end Ocarina.Backends.Connection_Matrix.Main;

Read our documentation on viewing source code .

Loading