File: image-viewer.js.page

package info (click to toggle)
gnome-devel-docs 40.3-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 79,188 kB
  • sloc: javascript: 2,514; xml: 2,407; ansic: 2,229; python: 1,854; makefile: 805; sh: 499; cpp: 131
file content (347 lines) | stat: -rw-r--r-- 24,134 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
<?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="image-viewer.js" xml:lang="sv">

  <info>
  <title type="text">Bildvisare (Javascript)</title>
    <link type="guide" xref="js#examples"/>

    <desc>Lite mer än ett enkelt ”Hej världen”-program - skriv en bildvisare i GTK+. Inkluderar en introduktion till språket Javascript.</desc>

    <revision pkgversion="0.1" version="0.1" date="2011-03-19" status="review"/>
    <credit type="author">
      <name>Jonh Wendell</name>
      <email its:translate="no">jwendell@gnome.org</email>
    </credit>
    <credit type="author">
      <name>Johannes Schmid</name>
      <email its:translate="no">jhs@gnome.org</email>
    </credit>
    <credit type="editor">
      <name>Marta Maria Casetti</name>
      <email its:translate="no">mmcasettii@gmail.com</email>
      <years>2013</years>
    </credit>
  
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
      <mal:name>Sebastian Rasmussen</mal:name>
      <mal:email>sebras@gmail.com</mal:email>
      <mal:years>2019</mal:years>
    </mal:credit>
  
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
      <mal:name>Anders Jonsson</mal:name>
      <mal:email>anders.jonsson@norsjovallen.se</mal:email>
      <mal:years>2021</mal:years>
    </mal:credit>
  </info>

<title>Bildvisare</title>

<synopsis>
  <p>I denna handledning kommer vi skriva ett väldigt enkelt GTK-program som läser in och visar en bildfil. Du kommer lära dig hur du:</p>
  <list>
    <item><p>Skriver ett enkelt GTK-användargränssnitt i Javascript</p></item>
    <item><p>Hanterar händelser genom att ansluta signaler till signalhanterare</p></item>
    <item><p>Gör layouter för GTK-användargränssnitt genom att använda behållare</p></item>
    <item><p>Läser in och visar bildfiler</p></item>
  </list>
  <p>Du behöver följande för att kunna följa denna handledning:</p>
  <list>
    <item><p>En installerad kopia av den <link xref="getting-ready">integrerade utvecklingsmiljön Anjuta</link></p></item>
    <item><p>En installerad kopia av <em>gjs</em>-tolken</p></item>
    <item><p>Grundläggande kunskap i något objektorienterat programmeringsspråk</p></item>
  </list>
</synopsis>

<media type="image" mime="image/png" src="media/image-viewer.png"/>

<section id="anjuta">
  <title>Skapa ett projekt i Anjuta</title>
  <p>Innan du börjar koda kommer du behöva konfigurera ett nytt projekt i Anjuta. Detta kommer skapa alla filer som du behöver för att bygga och köra koden senare. Det är också användbart för att hålla allting samlat.</p>
  <steps>
    <item>
    <p>Starta Anjuta och klicka på <guiseq><gui>Arkiv</gui><gui>Ny</gui><gui>Projekt</gui></guiseq> för att öppna projektguiden.</p>
    </item>
    <item>
    <p>Välj <gui>Allmän Javascript</gui> från fliken <gui>JS</gui>, klicka på <gui>Framåt</gui>, och fyll i dina detaljer på de nästkommande sidorna. Använd <file>image-viewer</file> som projektnamn och katalog.</p>
   	</item>
    <item>
    <p>Klicka på <gui>Verkställ</gui> så kommer projektet skapas åt dig. Öppna <file>src/main.js</file> från flikarna <gui>Projekt</gui> eller <gui>Filer</gui>. Den innehåller väldigt enkel exempelkod.</p>
    </item>
  </steps>
</section>


<section id="js">
  <title>Javascript-grunder: Hej världen</title>
  <p>Låt oss innan vi börjar skriva bildvisaren ta reda på mer om hur Javascript används i GNOME. Din första kontakt med alla programmeringsspråk bör förstås vara Hej världen-programmet vilket redan kan hittas i <file>main.js</file>:</p>
  <code mime="application/javascript">print ("Hej världen!");</code>
  <p>Detta bör se naturligt ut för dig om du är bekant med nästan vilket annat programmeringsspråk som helst. Funktionen <code>print</code> anropas med argumentet <code>"Hej världen!"</code>, vilket kommer att skrivas ut på skärmen. Observera att varje rad kod avslutas med ett semikolon.</p>
</section>

<section id="classes">
  <title>Klasser i Javascript</title>
  <p>Detta är standardsättet att definiera en klass i Javascript:</p>
  <code mime="application/javascript" style="numbered">
function MyClass () {
  this._init ();
}

MyClass.prototype = {

  _init: function () {
    this.propertyA = "Det här är ett objekts fält";
    this.propertyB = 10;
  },

  aMethod: function (arg1, arg2) {
    print ("inuti aMethod: " + arg1 + " " + arg2);
  },

  dumpProperties: function () {
    print (this.propertyA);
    print (this.propertyB);
  }

}</code>
  <p>Detta definierar en klass med namnet <code>MyClass</code>. Låt oss gå igenom varje del av klassdefinitionen:</p>
  <steps>
    <item>
    <p><code>function MyClass</code> är klassens konstruktor — dess namn måste matcha klassens namn. Du kan komma åt alla medlemmar i klassen genom att använda objektet <code>this</code>; här anropar konstruktorn klassens <code>_init</code>-metod.</p>
    </item>
    <item>
    <p>The <code>MyClass.prototype</code> block is where you define the <em>structure</em> of the class. Each class is made up of methods (functions) and fields (variables); there are three methods and two fields in this example.</p>
    </item>
    <item>
    <p>Den första metoden som definieras här kallas <code>_init</code>, och vi anger att det är en funktion utan några argument:</p>
    <code>_init: function ()</code>
    <p>We write the function inside some curly braces. Two fields are defined here, <code>propertyA</code> and <code>propertyB</code>. The first is set to a string and the second is set to an integer (10). The function doesn't return any value.</p>
    </item>
    <item>
    <p>The next method is called <code>aMethod</code> and has two arguments, which it prints out when you call it. The final method is <code>dumpProperties</code>, and prints the fields <code>propertyA</code> and <code>propertyB</code>.</p>
    </item>
    <item>
    <p>Note how the class definition (prototype) is arranged; each function definition is separated by a comma.</p>
    </item>
  </steps>

  <p>Nu då MyClass har definierats så kan vi leka med den:</p>
  <code mime="application/javascript" style="numbered">
var o = new MyClass ();
o.aMethod ("Hej", "världen");
o.propertyA = "Ändrade just dess värde!";
o.dumpProperties ();</code>
  <p>This code creates a new instance of the class called <code>o</code>, runs <code>aMethod</code>, changes <code>propertyA</code> to a different string, and then calls <code>dumpProperties</code> (which outputs the fields).</p>
  <p>Save the code in the <file>main.js</file> and then run it by using
  <guiseq><gui>Run</gui><gui>Execute</gui></guiseq> from the menu or using the toolbar.</p>
</section>

<section id="gtk">
  <title>Ett första Gtk-program</title>
  <p>Låt oss se hur ett väldigt enkelt Gtk-program ser ut i Javascript:</p>
  <code mime="application/javascript" style="numbered">
const Gtk = imports.gi.Gtk;

Gtk.init (null, null);

var w = new Gtk.Window ({title: "Bildvisardemonstration"});
w.show ();

Gtk.main ();</code>
  <p>Låt oss ta en titt på vad som händer:</p>
  <list>
    <item>
    <p>Den första raden importerar Gtk-namnrymden (d.v.s. inkluderar Gtk-biblioteket). Biblioteken tillhandahålls av GObject Introspection (gi), vilket tillhandahåller språkbindningar för många GNOME-bibliotek.</p>
    </item>
    <item>
    <p><code>Gtk.init</code> initierar Gtk-biblioteket; denna sats är obligatorisk för alla Gtk-program.</p>
    </item>
    <item>
    <p>Nästa rad skapar huvudfönstret genom att skapa ett nytt <code>Gtk.Window</code>-objekt. Du kan skicka flera egenskaper till fönstrets konstruktor genom att använda syntaxen <code>{egenskap: värde, egenskap: värde, …}</code>. I detta fall ställer vi in fönstrets titel.</p></item>
    <item><p>Nästa rad visar explicit fönstret. I Gtk är varje komponent dold som standard.</p></item>
    <item><p>Finally, <code>Gtk.main</code> runs the main loop — in other words, it executes the program. The main loop listens for events (signals) from the user interface and then calls a signal handler which will do something useful. We'll learn more about signals shortly.</p></item>
  </list>

  <p>Save the code in <file>main.js</file> and run it. You will notice that the application does not quit when you close the window. This is because we haven't set up a signal handler to deal with the window's <code>destroy</code> (close) signal yet. We'll do this shortly, but for now you can just hit <keyseq><key>Ctrl</key><key>C</key></keyseq> in the terminal window to quit the program.</p>

</section>

<section id="classes2">
  <title>Lägga till klasser</title>
  <p>Det korrekta sättet att programmera med Gtk är att använda klasser. Låt oss skriva om den enkla koden du just skrev med klasser:</p>
  <code mime="application/javascript" style="numbered">
const Gtk = imports.gi.Gtk;

function ImageViewer () {
  this._init ();
}

ImageViewer.prototype = {
  _init: function () {
    this.window = new Gtk.Window ({title: "Bildvisardemonstration"});
    this.window.show ();
  }
}

Gtk.init (null, null);
var iv = new ImageViewer ();
Gtk.main ();</code>
  <!-- FIXME: Throws an error, "JS ERROR: !!!   Unhandled type int32 releasing GArgument" on Ubuntu 10.10 -->
  <p>Notice that the program is the same; we just moved the window creation code to our own <code>ImageViewer</code> class. The class's constructor calls the <code>_init</code> method, which creates and shows the window. We then create an instance of the class before running the main loop (<code>Gtk.main</code>).</p>
  <p>This code is modular and can be split into multiple files easily. This makes it cleaner and easier to read.</p>
</section>

<section id="signals">
  <title>Signaler</title>
  <p>Signals are one of the key concepts in Gtk programming. Whenever something happens to an object, it emits a signal; for example, when a button is clicked it gives off the <code>clicked</code> signal. If you want your program to do something when that event occurs, you must connect a function (a "signal handler") to that signal. Here's an example:</p>
  <code mime="application/javascript" style="numbered">
function button_clicked () {
  print ("du klickade på mig!");
}
var b = new Gtk.Button ({label:"Klicka på mig"});
b.connect ("clicked", button_clicked);</code>
  <p>The last two lines create a <code>Gtk.Button</code> called <code>b</code> and connect its <code>clicked</code> signal to the <code>button_clicked</code> function, which is defined above. Every time the button is clicked, the code in the <code>button_clicked</code> function will be executed. It just prints a message here.</p>
  <p>Syntax för att ansluta en godtycklig signal till en funktion är:</p>
  <code mime="application/javascript">
object.connect (&lt;signalnamn&gt;, &lt;funktion_att_anropa&gt;);</code>
  <p>Du kan hitta signaldefinitioner för alla objekt i <link href="https://developer.gnome.org/gtk3/stable/gtkobjects.html">GTK-klassreferensen</link>.</p>

  <note>
    <p>You can simplify the code by making use of an inline function definition:</p>
    <code mime="application/javascript">
b.connect ("clicked", function () { print ("du klickade på mig!"); });</code>
  </note>

</section>

<section id="close">
  <title>Stänga fönstret</title>
  <p>When you close a Gtk window it's not really closed, it's hidden. This allows you to keep the window around (which is useful if you want to ask the user if they really want to close the window, for example).</p>
  <p>In our case, we really do just want to close the window. The simplest way of doing this is by connecting the <code>hide</code> signal of the GtkWindow object to a function that closes the application. Go back to the <file>image-viewer.js</file> file and add the following code to the <code>_init</code> method, on the line above <code>this.window.show</code>:</p>
  <code mime="application/javascript" style="numbered">this.window.connect ("hide", Gtk.main_quit);</code>
  <p>This connects the <code>hide</code> signal of the window to Gtk's <code>main_quit</code> function, which ends the execution of the Gtk main loop. Once the main loop finishes, the function <code>Gtk.main</code> returns. Our program would continue to run any code written after the <code>Gtk.main ();</code> line, but since we don't have any code after that point, the program just ends.</p>
</section>

<section id="containers2">
  <title>Behållare: göra en layout för användargränssnittet</title>
  <p>Widgets (controls, such as buttons and labels) can be arranged in the window by making use of <em>containers</em>. You can organize the layout by mixing different types of containers, like boxes and grids.</p>
  <p>A <code>Gtk.Window</code> is itself a type of container, but you can only put one widget directly into it. We would like to have two widgets, an image and a button, so we must put a "higher-capacity" container inside the window to hold the other widgets. A number of <link href="http://library.gnome.org/devel/gtk/stable/GtkContainer.html">container types</link> are available, but we will use a <code>Gtk.Box</code> here. A <code>Gtk.Box</code> can hold several widgets, organized horizontally or vertically. You can do more complicated layouts by putting several boxes inside another box and so on.</p>
  <note>
  <p>There is a graphical user interface designer called <app>Glade</app> integrated in <app>Anjuta</app> which makes UI design really easy. For this simple example, however, we will code everything manually.</p>
  </note>
  <p>Let's add the box and widgets to the window. Insert the following code into the <code>_init</code> method, immediately above the <code>this.window.show</code> line:</p>
  <code mime="application/javascript" style="numbered">
var main_box = new Gtk.Box ({orientation: Gtk.Orientation.VERTICAL, spacing: 0});
this.window.add (main_box);</code>
  <p>The first line creates a <code>Gtk.Box</code> called <code>main_box</code> and sets two of its properties: the <code>orientation</code> is set to vertical (so widgets are arranged in a column), and the <code>spacing</code> between the widgets is set to 0 pixels. The next line then adds the newly-created <code>Gtk.Box</code> to the window.</p>
  <p>So far the window only contains an empty <code>Gtk.Box</code>, and if you run the program now you will see no changes at all (the <code>Gtk.Box</code> is a transparent container, so you can't see that it's there).</p>
</section>

<section id="packing2">
  <title>Packning: Lägga till komponenter till behållaren</title>
  <p>To add some widgets to the <code>Gtk.Box</code>, insert the following code directly below the <code>this.window.add (main_box)</code> line:</p>
  <code mime="application/javascript" style="numbered">
this.image = new Gtk.Image ();
main_box.pack_start (this.image, true, true, 0);</code>
  <p>The first line creates a new <code>Gtk.Image</code> called <code>image</code>, which will be used to display an image file. Then, the image widget is added (<em>packed</em>) into the <code>main_box</code> container using <code>Gtk.Box</code>'s <link href="http://library.gnome.org/devel/gtk/stable/GtkBox.html#gtk-box-pack-start"><code>pack_start</code></link> method.</p>
  <p><code>pack_start</code> takes 4 arguments: the widget that is to be added to the <code>Gtk.Box</code> (<code>child</code>); whether the <code>Gtk.Box</code> should grow larger when the new widget is added (<code>expand</code>); whether the new widget should take up all of the extra space created if the <code>Gtk.Box</code> gets bigger (<code>fill</code>); and how much space there should be, in pixels, between the widget and its neighbors inside the <code>Gtk.Box</code> (<code>padding</code>).</p>
  <p>Gtk containers (and widgets) dynamically expand to fill the available space, if you let them. You don't position widgets by giving them a precise x,y-coordinate location in the window; rather, they are positioned relative to one another. This makes handling window resizing much easier, and widgets should automatically take a sensible size in most situations.</p>
  <p>Also note how the widgets are organized in a hierarchy. Once packed in the <code>Gtk.Box</code>, the <code>Gtk.Image</code> is considered a <em>child</em> of the <code>Gtk.Box</code>. This allows you to treat all of the children of a widget as a group; for example, you could hide the <code>Gtk.Box</code>, which would also hide all of its children at the same time.</p>
  <p>Infoga nu dessa två rader under de två du just lade till:</p>
  <code mime="application/javascript" style="numbered">
var open_button = new Gtk.Button ({label: "Öppna en bild…"});
main_box.pack_start (open_button, false, false, 0);</code>
  <p>These lines are similar to the first two, but this time they create a <code>Gtk.Button</code> and add it to <code>main_box</code>. Notice that we are setting the <code>expand</code> argument (the second one) to <code>false</code> here, whereas it was set to <code>true</code> for the <code>Gtk.Image</code>. This will cause the image to take up all available space and the button to take only the space it needs. When you maximize the window, the button size will remain the same, but the image size will increase, taking up all of the rest of the window.</p>
  <p>Slutligen måste vi ändra raden <code>this.window.show ();</code> så att den säger:</p>
  <code>this.window.show_all ();</code>
  <p>This will show the child of the Gtk window, and all of its children, and its children's children, and so on. (Remember that Gtk widgets are all hidden by default.)</p>
</section>

<section id="loading2">
  <title>Läsa in bilden: ansluta till knappens <code>clicked</code>-signal</title>
  <p>When the user clicks on the <gui>Open</gui> button, a dialog should appear so that the user can choose a picture. Once chosen, the picture should be loaded and shown in the image widget.</p>
  <p>The first step is to connect the <code>clicked</code> signal of the button to a signal handler function, which we call <code>_openClicked</code>. Put this code immediately after the <code>var open_button = new Gtk.Button</code> line where the button was created:</p>
  <code mime="application/javascript">
open_button.connect ("clicked", Lang.bind (this, this._openClicked));</code>
  <p>We are using the <em>Lang</em> JavaScript helper here. It allows us to connect a <em>class method</em> to the signal, rather than a plain function (without a class) which we had used before for the window's <code>hide</code> signal. Don't worry about this for now, it's just a technical detail. For it to work, you also need to put the following line at the top of the file:</p>
  <code mime="application/javascript">const Lang = imports.lang;</code>
</section>

<section id="loading3">
  <title>Läsa in bilden: skriva signalens återanrop</title>
  <p>Now we can create the <code>_openClicked()</code> method. Insert the following into the <code>ImageViewer.prototype</code> code block, after the <code>_init</code> method (and not forgetting the comma):</p>
    <code mime="application/javascript" style="numbered">
  _openClicked: function () {
    var chooser = new Gtk.FileChooserDialog ({title: "Välj en bild",
                                              action: Gtk.FileChooserAction.OPEN,
                                              transient_for: this.window,
                                              modal: true});
    chooser.add_button (Gtk.STOCK_CANCEL, 0);
    chooser.add_button (Gtk.STOCK_OPEN, 1);
    chooser.set_default_response (1);

    var filter = new Gtk.FileFilter ();
    filter.add_pixbuf_formats ();
    chooser.filter = filter;

    if (chooser.run () == 1)
      this.image.file = chooser.get_filename ();

    chooser.destroy ();
  }</code>
  <p>Det här är lite mer komplicerat än något som vi försökt så här långt, så låt oss dela upp det:</p>
  <list>
    <item>
      <p>The line beginning with <code>var chooser</code> creates an <gui>Open</gui> dialog, which the user can use to choose files. We set four properties: the title of the dialog; the action (type) of the dialog (it's an "open" dialog, but we could have used <code>SAVE</code> if the intention was to save a file; <code>transient_for</code>, which sets the parent window of the dialog; and <code>modal</code> which, if set to <code>true</code>, prevents the user from clicking on another area of the application until the dialog is closed.</p>
    </item>
    <item>
    <p>The next two lines add <gui>Cancel</gui> and <gui>Open</gui> buttons to the dialog. The second argument of the <code>add_button</code> method is the (integer) value that is returned when the button is pressed: 0 for <gui>Cancel</gui> and 1 for <gui>Open</gui>.</p>
    <p>Observera att vi använder <em>standard</em>knappnamn från Gtk, istället för att manuellt skriva in ”Avbryt” eller ”Öppna”. Fördelen med att använda standardnamn är att knappetiketterna redan kommer vara översatta till användarens språk.</p>
    </item>
    <item>
    <p><code>set_default_response</code> determines the button that will be activated if the user double-clicks a file or presses <key>Enter</key>. In our case, we are using the <gui>Open</gui> button as default (which has the value 1).</p>
    </item>
    <item>
    <p>The next three lines restrict the <gui>Open</gui> dialog to only display files which can be opened by <code>Gtk.Image</code>. A filter object is created first; we then add all kinds of files supported by <code>Gdk.Pixbuf</code> (which includes most image formats like PNG and JPEG) to the filter. Finally, we set this filter to be the <gui>Open</gui> dialog's filter.</p>
    </item>
    <item>
    <p><code>chooser.run</code> displays the <gui>Open</gui> dialog. The dialog will wait for the user to choose an image; when they do, <code>chooser.run</code> will return the value <output>1</output> (it would return <output>0</output> if the user clicked <gui>Cancel</gui>). The <code>if</code> statement tests for this.</p>
    </item>
    <item><p>Assuming that the user did click <gui>Open</gui>, the next line sets the <code>file</code> property of the <code>Gtk.Image</code> to the filename of the image selected by the user. The <code>Gtk.Image</code> will then load and display the chosen image.</p>
    </item>
    <item>
    <p>In the final line of this method, we destroy the <gui>Open</gui> dialog because we don't need it any more.</p>
    </item>
  </list>

  </section>

<section id="run">
  <title>Kör programmet</title>
  <p>All kod som du behöver bör nu vara på plats, så testa att köra koden. Det var det, en fullt fungerande bildvisare (och en snabb rundtur av Javascript och Gtk) på inte mycket tid alls!</p>
</section>

<section id="impl">
 <title>Referensimplementation</title>
 <p>Om du stöter på problem med handledningen kan du jämföra din kod med denna <link href="image-viewer/image-viewer.js">referenskod</link>.</p>
</section>

<section id="next">
  <title>Nästa steg</title>
  <p>Här är några idéer på hur du kan utöka denna enkla demonstration:</p>
  <list>
   <item>
   <p>Låt användaren välja en katalog snarare än en fil, och tillhandahåll kontroller för att gå igenom alla bilderna i en katalog.</p>
   </item>
   <item>
   <p>Tillämpa slumpmässiga filter och effekter till bilden då den läses in och låt användaren spara den ändrade bilden.</p>
   <p><link href="http://www.gegl.org/api.html">GEGL</link> har kraftfulla bildmanipuleringsförmågor.</p>
   </item>
   <item>
   <p>Allow the user to load images from network shares, scanners, and other more complicated sources.</p>
   <p>You can use <link href="http://library.gnome.org/devel/gio/unstable/">GIO</link> to handle network file transfers and the like, and <link href="http://library.gnome.org/devel/gnome-scan/unstable/">GNOME Scan</link> to handle scanning.</p>
   </item>
  </list>
</section>

</page>