Utilisez les propriétés et les méthodes de la classe NativeWindow pour gérer l’aspect, le comportement et le cycle de vie des fenêtres du poste de travail.
Remarque :
si vous faites appel à la structure Flex, il est généralement préférable de gérer le comportement d’une fenêtre à l’aide des classes framework. Vous pouvez accéder à la plupart des propriétés et méthodes NativeWindow par le biais des classes mx:WindowedApplication et mx:Window.
Obtention d’une occurrence de NativeWindow
Pour manipuler une fenêtre, vous devez tout d’abord obtenir l’occurrence de la fenêtre. Vous pouvez obtenir une occurrence de fenêtre à partir de l’un des emplacements suivants :
-
Le constructeur de fenêtre natif utilisé pour créer la fenêtre :
var win:NativeWindow = new NativeWindow(initOptions);
-
La propriété
nativeWindow
de la scène de la fenêtre :
var win:NativeWindow = stage.nativeWindow;
-
La propriété
stage
d’un objet d’affichage de la fenêtre :
var win:NativeWindow = displayObject.stage.nativeWindow;
-
La propriété
target
d’un événement de fenêtre native distribué par la fenêtre :
private function onNativeWindowEvent(event:NativeWindowBoundsEvent):void
{
var win:NativeWindow = event.target as NativeWindow;
}
-
La propriété
nativeWindow
d’une page HTML affichée dans la fenêtre :
var win:NativeWindow = htmlLoader.window.nativeWindow;
-
Les propriétés
activeWindow
et
openedWindows
de l’objet NativeApplication :
var nativeWin:NativeWindow = NativeApplication.nativeApplication.activeWindow;
var firstWindow:NativeWindow = NativeApplication.nativeApplication.openedWindows[0];
NativeApplication.nativeApplication.activeWindow
référence la fenêtre active d’une application (mais renvoie
null
si la fenêtre active n’est pas une fenêtre de cette application AIR). Le tableau
NativeApplication.nativeApplication.openedWindows
contient toutes les fenêtres d’une application AIR n’ayant pas été fermée.
Les objets Flex mx:WindowedApplication et mx:Window étant des objets d’affichage, vous pouvez aisément référencer la fenêtre d’application dans un fichier MXML à l’aide de la propriété
stage
, comme suit :
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" applicationComplete="init();">
<mx:Script>
<![CDATA[
import flash.display.NativeWindow;
public function init():void{
var appWindow:NativeWindow = this.stage.nativeWindow;
//set window properties
appWindow.visible = true;
}
]]>
</mx:Script>
</WindowedApplication
Remarque :
tant que le composant WindowedApplication ou Window n’est pas ajouté à la scène de la fenêtre à l’aide de la structure d’application Flex, la propriété
stage
du composant est
null
. Ce comportement correspond à celui du composant Flex Application ; cela signifie qu’il n’est pas possible d’accéder à la scène ou à l’occurrence de NativeWindow dans les écouteurs pour les événements qui se produisent avec antériorité dans le cycle d’initialisation des composants WindowedApplication et Window, tels que
creationComplete
. Il est recommandé d’accéder à la scène et à l’occurrence de NativeWindow lorsque l’événement
applicationComplete
est distribué.
Activation, affichage et masquage des fenêtres
Pour activer une fenêtre, appelez la méthode NativeWindow
activate()
. Lorsque vous activez une fenêtre, celle-ci s’affiche au premier plan, la souris et le clavier reçoivent le focus et, le cas échéant, il est possible de rendre visible la fenêtre en la restaurant ou en définissant la propriété
visible
sur
true
. L’activation d’une fenêtre ne modifie pas l’ordre des autres fenêtres dans l’application. Lorsque vous appelez la méthode
activate()
, la fenêtre distribue un événement
activate
.
Pour afficher une fenêtre masquée sans l’activer, définissez la propriété
visible
sur
true
. Cette action amène la fenêtre au premier plan, mais ne lui donne pas le focus.
Pour masquer une fenêtre, définissez sa propriété
visible
sur
false
. Le masquage d’une fenêtre supprime l’affichage de la fenêtre et des icônes de la barre des tâches associées et, sous Mac OS X, l’entrée dans le menu Fenêtre.
Lorsque vous modifiez la visibilité d’une fenêtre, la visibilité des fenêtres dont elle est propriétaire est également modifiée. Ainsi, si vous masquez une fenêtre, toutes les fenêtres qui lui appartiennent sont également masquées.
Remarque :
sous Mac OS X, il n’est pas possible de masquer entièrement une fenêtre réduite qui possède une icône dans la partie de la fenêtre du Dock. Si la propriété
visible
est définie sur
false
sur une fenêtre minimisée, l’icône de la fenêtre dans le Dock est toujours affichée. Si l’utilisateur clique sur l’icône, la fenêtre est restaurée à un état visible et s’affiche.
Modification de l’ordre d’affichage des fenêtres
AIR propose plusieurs méthodes pour modifier directement l’ordre d’affichage des fenêtres. Vous pouvez placer une fenêtre au premier plan ou à l’arrière-plan ; vous pouvez en outre placer une fenêtre sur ou sous une autre fenêtre. L’utilisateur peut simultanément réorganiser les fenêtres en les activant.
Il est possible de maintenir une fenêtre au premier plan en définissant sa propriété
alwaysInFront
sur
true
. Si ce même paramètre est défini dans plusieurs fenêtres, l’ordre d’affichage est à nouveau déterminé au sein des ces fenêtres ; toutefois, ces fenêtres sont toujours placées au-dessus des fenêtres dont la propriété
alwaysInFront
est définie sur false.
Les fenêtres du groupe de premier niveau sont toujours affichées devant les fenêtres d’autres applications, même si l’application AIR n’est pas active. Etant donné que ce comportement peut perturber les utilisateurs, définissez la propriété
alwaysInFront
sur
true
uniquement lorsque cela est nécessaire. Exemples de cas dans lesquels cet emploi est justifié :
-
Fenêtres contextuelles temporaires, notamment infos-bulles, listes déroulantes, menus personnalisés ou zones déroulantes. Ces fenêtres doivent se fermer lorsqu’elles perdent le focus ; or, il est possible d’éviter qu’un utilisateur ne puisse pas afficher une autre fenêtre.
-
Messages et alertes extrêmement urgents. Lorsqu’une modification irrévocable risque de se produire si l’utilisateur ne répond pas à temps, il peut être justifié d’afficher au premier plan une fenêtre d’alerte. Néanmoins, la plupart des erreurs et des alertes peuvent être gérées dans l’ordre d’affichage normal des fenêtres.
-
Fenêtres affichées temporairement l’une derrière l’autre.
Remarque :
AIR n’impose pas l’utilisation correcte de la propriété
alwaysInFront
. Néanmoins, si votre application interrompt le flux de travail d’un utilisateur, il est probable qu’elle termine dans la corbeille de cet utilisateur.
Si une fenêtre est propriétaire d’autres fenêtres, celles-ci s’affichent devant elle dans un ordre déterminé. Si vous appelez
orderToFront()
ou définissez
alwaysInFront
sur
true
pour une fenêtre propriétaire d’autres fenêtres, l’ordre d’affichage de ces dernières et celui de la fenêtre propriétaire est modifié devant d’autres fenêtres, mais elles continuent à s’afficher devant la fenêtre propriétaire.
Appeler les méthodes de classement pour des fenêtres qui appartiennent à une autre fenêtre fonctionne normalement si elles appartiennent toutes à un même propriétaire, mais risque également de modifier l’ordre d’affichage du groupe entier de fenêtres. Ainsi, si vous appelez
orderToFront()
pour une fenêtre appartenant à une autre fenêtre, la fenêtre, son propriétaire et toute fenêtre appartenant éventuellement au même propriétaire sont affichées devant les autres fenêtres.
La classe NativeWindow fournit les propriétés et les méthodes suivantes pour définir l’ordre d’affichage d’une fenêtre par rapport à d’autres fenêtres :
Membre
|
Description
|
alwaysInFront, propriété
|
Indique si la fenêtre est affichée dans le groupe de fenêtres de premier niveau.
Dans la plupart des cas, le paramètre
false
est recommandé. Si vous modifiez la valeur de
false
à
true
, la fenêtre est placée devant toutes les autres fenêtres (mais elle n’est pas activée). Si vous modifiez la valeur de
true
à
false
, la fenêtre est placée derrière les fenêtres restantes du groupe de premier niveau, mais reste devant les autres fenêtres. Si vous définissez la propriété sur sa valeur actuelle pour une fenêtre, vous ne modifiez pas l’ordre d’affichage de cette dernière.
Le paramètre
alwaysInFront
n’affecte pas les fenêtres qui appartiennent à une autre fenêtre.
|
orderToFront()
|
Place la fenêtre au premier plan.
|
orderInFrontOf()
|
Place la fenêtre directement devant une fenêtre spécifique.
|
orderToBack()
|
Envoie la fenêtre derrière les autres fenêtres.
|
orderBehind()
|
Envoie la fenêtre directement derrière une fenêtre spécifique.
|
activate()
|
Place la fenêtre au premier plan (tout en la rendant visible et en lui donnant le focus).
|
Remarque :
si une fenêtre est masquée (la propriété
visible
est définie sur
false
) ou minimisée, l’appel des méthodes de l’ordre d’affichage est sans effet.
Dans le système d’exploitation Linux, les différents gestionnaires de fenêtres imposent des règles différentes quant à l’ordre d’affichage des fenêtres :
-
Dans certains gestionnaires de fenêtres, les fenêtres d’utilitaires sont toujours affichées devant les fenêtres normales.
-
Dans certains gestionnaires de fenêtres, une fenêtre plein écran dont la propriété
alwaysInFront
est définie sur
true
s’affiche toujours devant les autres fenêtres dont la propriété
alwaysInFront
est également définie sur
true
.
Fermeture d’une fenêtre
Pour fermer une fenêtre, utilisez la méthode
NativeWindow.close()
.
La fermeture d’une fenêtre décharge le contenu de la fenêtre, mais si les autres objets possèdent des références à ce contenu, les objets de contenu ne sont pas détruits. La méthode
NativeWindow.close()
s’exécute de façon asynchrone, et l’application contenue dans la fenêtre continue de fonctionner lors de la fermeture. La méthode de fermeture distribue un événement close lorsque l’opération de fermeture est terminée. Techniquement, l’objet NativeWindow est toujours valide, mais l’accès à la plupart des propriétés et des méthodes sur une fenêtre fermée génère un erreur IllegalOperationError. Vous ne pouvez pas ouvrir à nouveau une fenêtre fermée. Vérifiez la propriété
closed
d’une fenêtre pour vous assurer que la fenêtre a été fermée. Pour simplement masquer une fenêtre, définissez la propriété
NativeWindow
sur
false
.
Si la propriété
Nativeapplication.autoExit
est définie sur
true
(valeur par défaut), l’application se ferme lors de la fermeture de sa dernière fenêtre.
La fermeture d’une fenêtre qui possède d’autres fenêtres entraîne la fermeture de ces dernières. Etant donné que les fenêtres qui appartiennent à la fenêtre propriétaire ne distribuent pas d’événement closing, il est impossible d’interdire leur fermeture. Un événement close est distribué.
Autorisation d’annulation des opérations sur les fenêtres
Lorsqu’une fenêtre utilise le chrome système, l’interaction de l’utilisateur avec la fenêtre peut être annulée en écoutant les événements appropriés et en annulant leur comportement par défaut. Par exemple, lorsqu’un utilisateur clique sur le bouton de fermeture du chrome système, l’événement
closing
est distribué. Si l’un des écouteurs enregistrés appelle la méthode
preventDefault()
de l’événement, la fenêtre ne se ferme pas.
Si une fenêtre n’utilise pas le chrome système, les événements de notification des modifications désirées ne sont pas automatiquement distribués avant que la modification ait lieu. Donc, si vous appelez les méthodes qui permettent de fermer une fenêtre, d’en modifier l’état ou d’en définir les propriétés de limite, la modification ne peut pas être annulée. Pour notifier les composants dans votre application avant d’effectuer une modification, votre logique d’application peut distribuer l’événement de notification adéquat à l’aide de la méthode
dispatchEvent()
de la fenêtre.
Par exemple, la logique suivante implémente un gestionnaire d’événement pouvant être annulé pour le bouton de fermeture d’une fenêtre :
public function onCloseCommand(event:MouseEvent):void{
var closingEvent:Event = new Event(Event.CLOSING,true,true);
dispatchEvent(closing);
if(!closingEvent.isDefaultPrevented()){
win.close();
}
}
La méthode
dispatchEvent()
renvoie
false
si la méthode
preventDefault()
de l’événement est appelée par un écouteur. Toutefois, elle peut également renvoyer
false
pour d’autres raisons ; par conséquent, il convient d’utiliser explicitement la méthode
isDefaultPrevented()
afin de vérifier si la modification doit ou non être annulée.
Agrandissement, réduction et restauration d’une fenêtre
Pour agrandir la fenêtre, utilisez la méthode
maximize()
de la classe NativeWindow.
myWindow.maximize();
Pour réduire la fenêtre, utilisez la méthode
minimize()
de la classe NativeWindow.
myWindow.minimize();
Pour restaurer la fenêtre (c’est-à-dire rétablir la taille de la fenêtre avant l’agrandissement ou la réduction), utilisez la méthode
restore()
de la classe NativeWindow.
myWindow.restore();
Une fenêtre appartenant à une autre fenêtre est réduite en icône ou restaurée lorsque la fenêtre propriétaire est réduite en icône ou restaurée. Etant donné que sa propriétaire est réduite en icône, aucun événement n’est distribué par la fenêtre lorsqu’elle est réduite en icône.
Remarque :
le comportement résultant de l’agrandissement d’une fenêtre AIR est différent du comportement standard de Mac OS X. Plutôt que de basculer entre la taille « standard » définie par l’application et la dernière taille définie par l’utilisateur, les fenêtres AIR basculent entre la dernière taille définie par l’application ou l’utilisateur et la totalité de la zone utilisable de l’écran.
Dans le système d’exploitation Linux, les différents gestionnaires de fenêtres imposent des règles différentes quant à la définition de l’état d’affichage des fenêtres :
-
Avec certains gestionnaires de fenêtres, les fenêtres d’utilitaires ne peuvent pas être agrandies.
-
Si une taille maximale est définie pour la fenêtre, certains gestionnaires n’autorisent pas l’agrandissement de la fenêtre. D’autres gestionnaires de fenêtres définissent l’état d’affichage sur l’état maximal, mais ne redimensionnent pas la fenêtre. Dans tous les cas, aucun événement de modification d’état d’affichage n’est distribué.
-
Certains gestionnaires de fenêtres ne respectent pas les paramètres
maximizable
ou
minimizable
des fenêtres.
Remarque :
sous Linux, les propriétés des fenêtres sont modifiées de façon asynchrone. Si vous modifiez l’état d’affichage sur une ligne de votre programme et que vous lisez la valeur à la ligne suivante, la modification n’est pas répercutée. Sur toutes les plates-formes, l’objet NativeWindow distribue l’événement
displayStateChange
lors de la modification de l’état d’affichage. Si vous devez exécuter une action basée sur le nouvel état de la fenêtre, faites systématiquement appel à un gestionnaire d’événement
displayStateChange
. Pour plus d’informations, voir
Ecoute des événements d’une fenêtre
.
Exemple : Réduction, agrandissement, restauration et fermeture d’une fenêtre
La brève application MXML suivante illustre les méthodes
maximize()
,
minimize()
,
restore()
et
close()
de la classe Window :
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical">
<mx:Script>
<![CDATA[
public function minimizeWindow():void
{
this.stage.nativeWindow.minimize();
}
public function maximizeWindow():void
{
this.stage.nativeWindow.maximize();
}
public function restoreWindow():void
{
this.stage.nativeWindow.restore();
}
public function closeWindow():void
{
this.stage.nativeWindow.close();
}
]]>
</mx:Script>
<mx:VBox>
<mx:Button label="Minimize" click="minimizeWindow()"/>
<mx:Button label="Restore" click="restoreWindow()"/>
<mx:Button label="Maximize" click="maximizeWindow()"/>
<mx:Button label="Close" click="closeWindow()"/>
</mx:VBox>
</mx:WindowedApplication>
L’exemple ActionScript suivant pour Flash crée quatre champs de texte cliquables qui déclenchent les méthodes
minimize()
,
maximize()
,
restore()
et
close()
de la classe NativeWindow :
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.text.TextField;
public class MinimizeExample extends Sprite
{
public function MinimizeExample():void
{
var minTextBtn:TextField = new TextField();
minTextBtn.x = 10;
minTextBtn.y = 10;
minTextBtn.text = "Minimize";
minTextBtn.background = true;
minTextBtn.border = true;
minTextBtn.selectable = false;
addChild(minTextBtn);
minTextBtn.addEventListener(MouseEvent.CLICK, onMinimize);
var maxTextBtn:TextField = new TextField();
maxTextBtn.x = 120;
maxTextBtn.y = 10;
maxTextBtn.text = "Maximize";
maxTextBtn.background = true;
maxTextBtn.border = true;
maxTextBtn.selectable = false;
addChild(maxTextBtn);
maxTextBtn.addEventListener(MouseEvent.CLICK, onMaximize);
var restoreTextBtn:TextField = new TextField();
restoreTextBtn.x = 230;
restoreTextBtn.y = 10;
restoreTextBtn.text = "Restore";
restoreTextBtn.background = true;
restoreTextBtn.border = true;
restoreTextBtn.selectable = false;
addChild(restoreTextBtn);
restoreTextBtn.addEventListener(MouseEvent.CLICK, onRestore);
var closeTextBtn:TextField = new TextField();
closeTextBtn.x = 340;
closeTextBtn.y = 10;
closeTextBtn.text = "Close Window";
closeTextBtn.background = true;
closeTextBtn.border = true;
closeTextBtn.selectable = false;
addChild(closeTextBtn);
closeTextBtn.addEventListener(MouseEvent.CLICK, onCloseWindow);
}
function onMinimize(event:MouseEvent):void
{
this.stage.nativeWindow.minimize();
}
function onMaximize(event:MouseEvent):void
{
this.stage.nativeWindow.maximize();
}
function onRestore(event:MouseEvent):void
{
this.stage.nativeWindow.restore();
}
function onCloseWindow(event:MouseEvent):void
{
this.stage.nativeWindow.close();
}
}
}
Redimensionnement et déplacement d’une fenêtre
Lorsqu’une fenêtre utilise le chrome système, le chrome fournit des commandes de glissement pour redimensionner la fenêtre et la déplacer dans le poste de travail. Si une fenêtre n’utilise pas le chrome système, vous devez ajouter vos propres commandes pour permettre à l’utilisateur de redimensionner et de déplacer la fenêtre.
Remarque :
pour redimensionner ou déplacer une fenêtre, vous devez tout d’abord obtenir une référence à l’occurrence de NativeWindow. Pour plus d’informations sur la méthode d’obtention d’une référence de fenêtre, voir la section
Obtention d’une occurrence de NativeWindow
.
Redimensionnement d’une fenêtre
Pour que l’utilisateur puisse interagir avec la taille d’une fenêtre, utilisez la méthode
startResize()
de la classe NativeWindow. Lorsque cette méthode est appelée depuis un événement
mouseDown
, l’opération de redimensionnement est effectuée par la souris et se termine lorsque le système d’exploitation reçoit un événement
mouseUp
. Lors de l’appel de la méthode
startResize()
, vous transmettez un argument qui indique le bord ou le coin à partir duquel la fenêtre doit être redimensionnée.
Pour définir la taille de la fenêtre par programmation, définissez les propriétés
width
,
height
ou
bounds
de la fenêtre sur les dimensions désirées. Lorsque vous définissez les limites, la taille et la position de la fenêtre peuvent changer simultanément. Toutefois, l’ordre de ces changements n’est pas garanti. Certains gestionnaires de fenêtres Linux ne permettent pas aux fenêtres de dépasser les limites de l’écran. Dans ce cas, la taille finale de la fenêtre peut être limitée du fait de l’ordre dans lequel les propriétés sont définies, même si l’impact des modifications aurait autrement résulté en une fenêtre valide. Par exemple, si vous modifiez à la fois la hauteur et la position y d’une fenêtre à proximité du bas de l’écran, la modification en pleine hauteur peut ne pas survenir lorsque la hauteur est modifiée avant la position y.
Remarque :
sous Linux, les propriétés des fenêtres sont modifiées de façon asynchrone. Si vous redimensionnez une fenêtre sur une ligne de votre programme et que vous lisez les dimensions à la ligne suivante, la modification n’est pas répercutée. Sur toutes les plates-formes, l’objet NativeWindow distribue l’événement
resize
lors du redimensionnement de la fenêtre. Si vous devez exécuter une action basée sur les nouvelles dimensions ou le nouvel état de la fenêtre (mettre en forme les contrôles de la fenêtre, par exemple), faites systématiquement appel à un gestionnaire d’événement
resize
. Pour plus d’informations, voir
Ecoute des événements d’une fenêtre
.
Le mode d’échelle de la scène indique le comportement de la scène de la fenêtre et de son contenu lorsqu’une fenêtre est redimensionnée. N’oubliez pas que les modes d’échelle de la scène sont conçus pour les situations où l’application ne contrôle pas la taille ou le format de son espace d’affichage (notamment dans le cas d’un navigateur Web). En règle générale, vous obtenez les meilleurs résultats en définissant la propriété
scaleMode
de la scène sur
StageScaleMode.NO_SCALE
. Pour mettre à l’échelle le contenu d’une fenêtre, vous pouvez toujours définir les paramètres
scaleX
et
scaleY
du contenu lors des modifications des limites de la fenêtre.
Déplacement d’une fenêtre
Pour déplacer une fenêtre sans la redimensionner, utilisez la méthode
startMove()
de la classe NativeWindow. A l’instar de la méthode
startResize()
, lorsque la méthode
startMove()
est appelée à partir d’un événement
mouseDown
, le déplacement est effectué avec la souris et se termine lorsque le système d’exploitation reçoit un événement
mouseUp
.
Pour plus d’informations sur les méthodes
startResize()
et
startMove()
, voir le manuel
Guide de référence ActionScript 3.0 pour la plate-forme Adobe Flash
.
Pour déplacer une fenêtre par programmation, définissez les propriétés
x
,
y
ou
bounds
de la fenêtre sur la position requise. Lorsque vous définissez les limites, la taille et la position de la fenêtre peuvent changer simultanément.
Remarque :
sous Linux, les propriétés des fenêtres sont modifiées de façon asynchrone. Si vous déplacez une fenêtre sur une ligne de votre programme et que vous lisez la position à la ligne suivante, la modification n’est pas répercutée. Sur toutes les plates-formes, l’objet NativeWindow distribue l’événement
move
lors du repositionnement de la fenêtre. Si vous devez exécuter une action basée sur la nouvelle position de la fenêtre, faites systématiquement appel à un gestionnaire d’événement
move
. Pour plus d’informations, voir
Ecoute des événements d’une fenêtre
.
Exemple : Redimensionnement et déplacement des fenêtres
L’exemple suivant montre comment lancer les opérations de redimensionnement et de déplacement sur une fenêtre :
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.display.NativeWindowResize;
public class NativeWindowResizeExample extends Sprite
{
public function NativeWindowResizeExample():void
{
// Fills a background area.
this.graphics.beginFill(0xFFFFFF);
this.graphics.drawRect(0, 0, 400, 300);
this.graphics.endFill();
// Creates a square area where a mouse down will start the resize.
var resizeHandle:Sprite =
createSprite(0xCCCCCC, 20, this.width - 20, this.height - 20);
resizeHandle.addEventListener(MouseEvent.MOUSE_DOWN, onStartResize);
// Creates a square area where a mouse down will start the move.
var moveHandle:Sprite = createSprite(0xCCCCCC, 20, this.width - 20, 0);
moveHandle.addEventListener(MouseEvent.MOUSE_DOWN, onStartMove);
}
public function createSprite(color:int, size:int, x:int, y:int):Sprite
{
var s:Sprite = new Sprite();
s.graphics.beginFill(color);
s.graphics.drawRect(0, 0, size, size);
s.graphics.endFill();
s.x = x;
s.y = y;
this.addChild(s);
return s;
}
public function onStartResize(event:MouseEvent):void
{
this.stage.nativeWindow.startResize(NativeWindowResize.BOTTOM_RIGHT);
}
public function onStartMove(event:MouseEvent):void
{
this.stage.nativeWindow.startMove();
}
}
}
|
|
|