Home | | Internet & World Wide Web HOW TO PROGRAM | | Internet Programming | | Web Programming | Creating a Simple User Interface - Adobe Flex 2

Chapter: Internet & World Wide Web HOW TO PROGRAM - Rich Internet Application Client Technologies - Adobe Flex 2 and Rich Internet Applications

Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail

Creating a Simple User Interface - Adobe Flex 2

Our first example application is a simple image viewer (Fig. 18.1) that displays thumbnail (i.e., small) images of several Deitel book covers.

Creating a Simple User Interface

 

Our first example application is a simple image viewer (Fig. 18.1) that displays thumbnail (i.e., small) images of several Deitel book covers. In this example, we specify the images with a static array within the MXML, but you could load this type of data dynamically from a web service. You can select a thumbnail to view a larger cover image, or use the horizontal slider to select an image. These two elements are bound to each other, meaning that when the user changes one, the other is updated. The image viewer also allows you to zoom the image. You can try this application at test.deitel.com/examples/iw3htp4/ flex/coverViewer/ (Fig. 18.2).

 

1    <?xml version = "1.0" encoding = "utf-8"?>

 

2    <!-- Fig. 18.1: coverViewer.mxml -->

 

3    <!-- Creating a simple book cover viewer in Flex 2 -->

 

4    <mx:Application xmlns:mx = "http://www.adobe.com/2006/mxml">

 

5          <!-- an array of images -->

 

6          <mx:ArrayCollection id = "bookCovers">

 

7                 <!-- each image has a name and source attribute -->

 

8                 <mx:Object name = "C How to Program" source = "chtp5.jpg" />

 

9                 <mx:Object name = "C++ How to Program" source = "cpphtp6.jpg" />

 

10               <mx:Object name = "Internet How to Program"

 

11                      source = "iw3htp4.jpg" />

 

12               <mx:Object name = "Java How to Program" source = "jhtp7.jpg" />

 

13               <mx:Object name = "VB How to Program" source = "vbhtp3.jpg" />

 

14               <mx:Object name = "Visual C# How to Program"

 

15                      source = "vcsharphtp2.jpg" />

 

16               <mx:Object name = "Simply C++" source = "simplycpp.jpg" />

 

<mx:Object name = "Simply VB 2005" source = "simplyvb2005.jpg" />

 

18                <mx:Object name = "Simply Java" source = "simplyjava.jpg" />

 

19                <mx:Object name = "Small C++ How to Program"

 

20                      source = "smallcpphtp5.jpg" />

 

21                <mx:Object name = "Small Java" source = "smalljavahtp6.jpg" />

 

22         </mx:ArrayCollection>

23

24         <!-- bind largeImage's source to the slider and selected thumbnail -->

 

25         <mx:Binding

 

26                source = "'fullsize/' +

 

27                  bookCovers.getItemAt( selectCoverSlider.value ).source"

 

28                destination = "largeImage.source" />

 

29         <mx:Binding source = "'fullsize/' + thumbnailList.selectedItem.source"

 

30                destination = "largeImage.source" />

31

32         <!-- user interface begins here -->

 

33         <mx:Panel id = "viewPanel" title = "Deitel Book Cover Viewer"

 

34                width = "100%" height = "100%" horizontalAlign = "center">

35          

36                <mx:HBox height = "100%" width = "100%">

 

<mx:VSlider id = "zoomSlider" value = "100" minimum = "0"

38        maximum = "100"     liveDragging = "true"

39        change = "largeImage.percentWidth = zoomSlider.value;      

40        largeImage.percentHeight = zoomSlider.value;"           

41        height = "100%"       width = "0%"

42                            labels = "[ '0%', 'Zoom', '100%' ]" />

 

<mx:VBox width = "100%" height = "100%"

44        horizontalAlign = "center">

45                                                       

46        <!-- We bind the source of this image to the source of -->

47        <!-- the selected thumbnail, and center it in the VBox. -->

48        <!-- completeEffect tells Flex to fade the image in -->

49                    <mx:Image id = "largeImage"                    

50                    source = ""

51                    horizontalAlign = "center"

52                    verticalAlign = "middle"

53                    width = "100%" height = "100%"

54                                completeEffect = "Fade" />

55                                                       

56        <!-- bind this Label to the name of the selected thumbnail -->

57                            <mx:Label text = "{ thumbnailList.selectedItem.name }" />

 

58                      </mx:VBox>

 

59                </mx:HBox>

60

61                <!-- slider can switch between images -->

 

<mx:HSlider id = "selectCoverSlider" height = "0%"

63        minimum = "0" maximum = "{ bookCovers.length - 1 }"

64        showDataTip = "false" snapInterval = "1" tickInterval = "1"

65        liveDragging = "true"

66                    change = "thumbnailList.selectedIndex =          

67                    selectCoverSlider.value;   

68                    thumbnailList.scrollToIndex( selectCoverSlider.value )" />     

69                               

 

70                <!-- display thumbnails of the images in bookCovers horizontally -->

 

71                <mx:HorizontalList id = "thumbnailList"

 

72                      dataProvider = "{ bookCovers }" width = "100%" height = "160"

 

73                      selectedIndex = "0"

 

74                      change = "selectCoverSlider.value = thumbnailList.selectedIndex">

75          

76                      <!-- define how each item is displayed -->

 

<mx:itemRenderer>

78        <mx:Component>

79        <mx:VBox width = "140" height = "160"

80        horizontalAlign = "center" verticalAlign = "middle"

81        verticalScrollPolicy = "off"

82        horizontalScrollPolicy = "off" paddingBottom = "20">

83                               

84        <!-- display a thumbnail of each image -->

85                    <mx:Image source = "{ 'thumbs/' + data.source }"         

86                    verticalAlign = "middle" />

87                               

88        <!-- display the name of each image -->

89        <mx:Label text = "{ data.name }" />

90        </mx:VBox>

91                            </mx:Component>

 

92                      </mx:itemRenderer>

 

93                </mx:HorizontalList>

 

94         </mx:Panel>

 

95   </mx:Application>

 

 

Fig. 18.1 | Creating a simple book cover viewer in Flex 2.

Line 1 of Fig. 18.1 declares the document to be an XML document, because MXML is a type of XML. The mx prefix, defined in line 4, is commonly associated with the  "http://www.adobe.com/2006/mxml" namespace, which is used for the Flex elements in an MXML document. The Panel element (lines 33–94 is a container, and is generally the outermost container of a Flex application. This element has many attributes, including title, width, height, horizontalAlign and verticalAlign. The id = "viewPanel" attribute allows us to reference this item in ActionScript using the identifier viewPanel. Flex elements can contain an id attribute, so that their properties can be accessed progra-matically. The value of the title attribute is displayed at the top of the Panel, in the border. Inside the Panel element, there is an HBox element (lines 36–59), which is a con-tainer that organizes its enclosed elements horizontally. There is also a VBox element available for organizing elements vertically, which we will use later.

 

In the HBox, we have a VSlider (lines 37–42) and a VBox (lines 43–58) containing an Image element (lines 49–54) and a Label element (line 57). The VSlider element pro-vides a vertically oriented slider user interface element. The VSlider controls the zoom level of the image. The value attribute sets the slider’s initial value (100 in this example). The minimum and maximum attributes set the range of values you can select with the slider. The change attribute (lines 39–40) allows ActionScript to execute whenever the user changes the slider’s value. Lines 39–40 scale the image by setting its percentWidth and percentHeight properties to the slider’s value. The liveDragging attribute with the value "true" indicates that the ActionScript in the change attribute executes immediately


when the user changes the slider value, even if the user is still clicking it. The labels attribute places text next to the slider. You can give it any number of labels, and it will equidistantly space them.

 

The Image element has the attribute source = "" (line 50). This is because in lines 25–28, we use a Binding element to bind the value of largeImage’s source attribute (line 50) to the value of the source attribute of an element in the bookCovers ArrayCollection (defined in lines 6–22). In line 27, we use the horizontal slider’s value to select an element from bookCovers and set the largeImage’s source. Lines 29–30 set up a second Binding element that binds the image’s source to the source of the selected item in thumb-nailList (defined in lines 71–74). For each binding, we prepend 'fullsize/', the direc-

tory  containing  the  full-sized  images.  When  the  user  selects  an  image  with  the selectCoverSlider or thumbnailList, largeImage shows the full-size version of the corresponding image.

 

The Image element’s other attributes specify that the element is centered (lines 51– 52) and takes up as much space in the containing element as possible (line 53). The com-pleteEffect attribute of the Image element is set to "Fade" (line 54), which means that when the image is loaded, it will be presented using Flex’s built-in Fade effect. You can view the list of built-in effects at livedocs.adobe.com/flex/201/langref/mx/effects/

package-detail.html.

 

The Label element (line 57) has a text attribute, in which we indicate that the string displayed by the Label is bound to the name of thumbnailList’s selectedItem. The curly braces surrounding this ActionScript are another way to indicate data binding. Following the HBox is an HSlider (lines 62–68) that gives the user another way to navigate through the images. The HSlider element is the horizontal equivalent of the VSlider. The change attribute (lines 66–68) changes the selected thumbnail from the thumbnailList based on the value of the HSlider and ensures that the thumbnailList is showing the selected thumbnail by scrolling to the HSlider’s value. We set the HSlider’s maximum value to { bookCovers.length - 1 }, the index of the last element of the book-Covers array. We set showDataTip to "false" (line 64) to turn off the tool tip showing the HSlider’s current value while the user is dragging the slider. Finally, we set snap-Interval and tickInterval to "1" (line 64), so that the slider’s values increment by 1, and the tick marks are displayed at intervals of 1.

 

The HorizontalList element with id thumbnailList (lines 71–93) takes an array of items from a dataProvider and displays them in a horizontal configuration. This  HorizontalList’s dataProvider is the ArrayCollection of Objects called bookCovers (lines 6–22). Object is the root class of the ActionScript hierarchy, and is used here to simply hold attributes. An ArrayCollection is a type of Array that provides methods for manipulating an Array. Each of the items in the HorizontalList is selectable, and the selectedIndex attribute dictates that the first array element is selected initially.

 

The thumbnailList contains an inline itemRenderer (lines 77–92), which gives you complete control over the contents of the list. At runtime, the HorizontalList will create an instance of the itemRenderer for each of the elements in the dataProvider array. If you don’t provide an itemRenderer, Flex will render each item with the default item ren-derer, which depends on the item’s type. An itemRenderer can also be defined externally by giving the HorizontalList an itemRenderer attribute equal to the filename (without the extension) of an external MXML file containing the elements you want.

 

This itemRenderer contains a Component element (lines 78–91), which encloses the item to render. Inside the Component element, there is a VBox containing an Image (lines 85–86) and a Label (line 89). The verticalScrollPolicy and horizontalScrollPolicy attributes (lines 81–82) are set to off so that even if the Image or Label elements don’t fit in the VBox, they won’t show scroll bars. The paddingBottom attribute (line 82) ensures that there is 20 pixels of space for the HorizontalList’s horizontal scroll bar. The Image element’s source attribute has the specifies the location of the image file. The thumbs/ directory contains the thumbnails we want to display, and data refers to the corresponding item from the list’s dataProvider, in this case the bookCovers ArrayCollection. We must use the keyword data because everything inside the Component element is located in a new, separate scope, meaning that it cannot access the variables of the enclosing program. The Label element displays the name element of the corresponding item in the ArrayCollection. The Spacer element ensures that there will be enough room for a horizontal scroll bar at the bottom of the thumbnailList in case the window is not wide enough to display all of the thumbnails.

 

Compiling an Application

 

Flex applications are converted from MXML into ActionScript, which is then compiled and output as SWF files. We’ll compile our applications using the mxmlc command-line compiler, included in the Flex SDK. If you do not want to specify the compiler’s path ev-ery time you run it, you can add the directory to your Path system variable. To do this in Windows XP, first right click My Computer, click Properties, select the Advanced tab, click Environment Variables, select Path in the list of System variables, and append your path to the flex_sdk_2\bin directory (e.g. C:\flex_sdk_2\bin if you extracted it into the C:\ di-rectory). For Mac OS X and Linux, visit  www.linuxheadquarters.com/howto/basic  path.shtml for instructions. The simplest syntax of the mxmlc command is mxmlc filename. You can see a full list of the compiler’s parameters by executing mxmlc -help. For instance, if we’re in the directory containing coverViewer.mxml, and we have added the bin direc-tory to the Path system variable, the command for compiling coverViewer.mxml would be mxmlc coverViewer.mxml (Fig. 18.3).

 

This command creates coverViewer.swf in the current directory. If you’d like, you can test coverViewer.swf in the standalone Flash 9 Player by double clicking the file coverViewer.swf. If this does not work, you can locate the Flash 9 Player at flex_sdk_2\player\debug\SAFlashPlayer.exe for Windows or flex_sdk_2/player/ debug/SAFlashPlayer.dmg for Mac OS X.


Running a Flex Application in the Browser

Because Flex applications run using the Flash Player, they can be embedded into a web page, then run with the Flash Player browser plug-in. The Flex SDK install includes a fold-er of HTML templates for embedding your application. You can copy a template and edit it to point to your SWF file. These templates are located in the folder flex_sdk_2/ resources/html-templates/. The six templates give you different combinations of Flash installation and version detection (checks the user’s Flash Player version) as well as browser history support. For our examples, we use the no-player-detection template. If you would like to implement the install and history features, more information is available at livedocs.adobe.com/flex/201/html/wrapper_131_05.html.

 

To create an HTML wrapper for the application, first copy the files AC_OETags.js and index.template.html from flex_sdk_2/resources/html-templates/no-player-detection to your Flex application’s base directory. Rename index.template.html to index.html if you want it to be the default HTML file of the directory on a web server. Now, open the HTML file in your text editor, and replace the variables ${title}, ${swf}, and ${application} with your application’s filename without .swf (in this case, cover Viewer). For ${height} and ${width}, use 100%. For ${bgcolor}, use #869ca7 (this is Flex’s default color). The modified HTML wrapper for coverViewer is shown in Fig. 18.4.

 

 

1     <!-- Fig. 18.4: index.html -->

 

2     <!-- HTML wrapper for coverViewer.swf -->

 

3     <!-- saved from url=(0014)about:internet -->

 

4     <html lang="en">

 

5     <head>

 

6     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

 

7     <title>coverViewer</title>

 

8     <script src="AC_OETags.js" language="javascript"></script>

 

9     <style>

 

10          body { margin: 0px; overflow: hidden; }

 

11    </style>

 

12    </head>

13

14    <body scroll='no'>

 

15    <script language="JavaScript" type="text/javascript">

16    <!--

 

17          AC_FL_RunContent(

 

18                 "src", "coverViewer",

 

19                 "width", "100%",

 

20                 "height", "100%",

 

21                 "align", "middle",

 

22                 "id", "coverViewer",

 

23                 "quality", "high",

 

24                 "bgcolor", "#869ca7",

 

25                 "name", "coverViewer",

 

26                 "allowScriptAccess","sameDomain",

 

27                 "type", "application/x-shockwave-flash",

 

28                 "pluginspage", "http://www.adobe.com/go/getflashplayer"

29          );

30    // -->

 

31    </script>

 

32    <noscript>

 

33          <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"

 

34                 id="coverViewer" width="100%" height="100%"

 

35                 codebase="http://fpdownload.macromedia.com/get/

 

36                       flashplayer/current/swflash.cab">

 

37                 <param name="movie" value="coverViewer.swf" />

 

38                 <param name="quality" value="high" />

 

39                 <param name="bgcolor" value="#869ca7" />

 

40                 <param name="allowScriptAccess" value="sameDomain" />

 

41                 <embed src="coverViewer.swf" quality="high" bgcolor="#869ca7"

 

42                       width="100%" height="100%" name="coverViewer" align="middle"

 

43                       play="true"

 

44                       loop="false"

 

45                       quality="high"

 

allowScriptAccess="sameDomain

47                       type="application/x-shockwave-flash"

 

48                       pluginspage="http://www.adobe.com/go/getflashplayer">

 

49                 </embed>

 

50          </object>

 

51    </noscript>

 

52    </body>

 

53    </html>

 

Fig. 18.4 | HTML wrapper for coverViewer.swf.

Embedding Images

 

Instead of referencing external images, we could embed the images into the SWF file to make it more portable. We specify that an image is embedded by enclosing the source attribute inside an @Embed directive, as in source = "@Embed( 'image.jpg' )". This tells the compiler to include the image in the SWF file, which results in a program that not only loads faster, but also is less dependent on external resources, since the SWF includes all resources it needs. In this case, embedding images would significantly increase the size of the SWF. Also, we may later want to update or change the images.

 

Using View States

Next, we’ll add the ability to hide the thumbnail HorizontalList and to increase the size of the current image. We’ll accomplish this using view states (Fig. 18.5), which enable us to change an application’s layout on the fly, allowing for more usable interfaces. You can test this application at test.deitel.com/examples/iw3htp4/flex/coverViewerStates/ (Fig. 18.6).

 

1     <?xml version = "1.0" encoding = "utf-8"?>

 

2     <!-- Fig. 18.5: coverViewerStates.mxml -->

 

3     <!-- Using States to dynamically modify a user interface -->

 

4     <mx:Application xmlns:mx = "http://www.adobe.com/2006/mxml">

5              

6           <!-- ActionScript goes in this section -->

 

7           <mx:Script>

 

8                  // import the Cubic easing function for state transitions

 

9                  import mx.effects.easing.Cubic;

 

10          </mx:Script>

11

12          <!-- an array of images -->

 

13          <mx:ArrayCollection id = "bookCovers">

 

14                 <!-- each image has a name and source attribute -->

 

15                 <mx:Object name = "C How to Program" source = "chtp5.jpg" />

 

16                 <mx:Object name = "C++ How to Program" source = "cpphtp6.jpg" />

 

17                 <mx:Object name = "Internet How to Program"

 

18                       source = "iw3htp4.jpg" />

 

19                 <mx:Object name = "Java How to Program" source = "jhtp7.jpg" />

 

20                 <mx:Object name = "VB How to Program" source = "vbhtp3.jpg" />

 

21                 <mx:Object name = "Visual C# How to Program"

 

22                       source = "vcsharphtp2.jpg" />

 

<mx:Object name = "Simply C++" source = "simplycpp.jpg" />

24                 <mx:Object name = "Simply VB 2005" source = "simplyvb2005.jpg" />

 

25                 <mx:Object name = "Simply Java" source = "simplyjava.jpg" />

 

26                 <mx:Object name = "Small C++ How to Program"

 

27                       source = "smallcpphtp5.jpg" />

 

28                 <mx:Object name = "Small Java" source = "smalljavahtp6.jpg" />

 

29          </mx:ArrayCollection>

30

31          <!-- define the application's states -->

 

32          <mx:states>

 

33                 <mx:State name = "HideThumbnails">

 

34                       <mx:RemoveChild target = "{ thumbnailList }" />

35           

36                       <!-- switch the showHideButton to hide -->

 

37                       <mx:SetEventHandler target = "{ showHideButton }" name = "click"

38                              handler = "currentState = ''" />

 

39                 </mx:State>

 

40          </mx:states>

41

42          <!-- define the transition effect for application state changes -->

 

43          <mx:transitions>

 

<mx:Transition>

45 <mx:Resize

46        target = "{ largeImage }"       

47        duration = "750" easingFunction = "Cubic.easeOut" />

48                 </mx:Transition>

 

49          </mx:transitions>

50           

51          <!-- bind the source of largeImage to the selected thumbnail -->

 

52          <mx:Binding

 

53                 source = "'fullsize/' +

 

54                       bookCovers.getItemAt( selectCoverSlider.value ).source"

 

55                 destination = "largeImage.source" />

 

56          <mx:Binding source = "'fullsize/' + thumbnailList.selectedItem.source"

 

57                 destination = "largeImage.source" />

58

59          <!-- user interface begins here -->

 

60          <mx:Panel id = "viewPanel" title = "Deitel Book Cover Viewer"

 

61                 width = "100%" height = "100%" horizontalAlign = "center">

62           

63                 <mx:HBox height = "100%" width = "100%">

 

<mx:VSlider id = "zoomSlider" value = "100" minimum = "0"

65        maximum = "100"       liveDragging = "true"

66        change =         "largeImage.percentWidth = zoomSlider.value;

67        largeImage.percentHeight = zoomSlider.value;"

68        height =           "100%"            width = "0%"

69                              labels = "[ '0%', 'Zoom', '100%' ]" />

 

<mx:VBox width = "100%" height = "100%"

71        horizontalAlign = "center">

72       

73        <!-- We bind the source of this image to the source of -->

74        <!-- the selected thumbnail, and center it in the VBox. -->

75        <!-- completeEffect tells Flex to fade the image in -->

76        <mx:Image id = "largeImage"

77        source = ""     

78        horizontalAlign = "center"     

79        verticalAlign = "middle"        

80        width = "100%" height = "100%"       

81        completeEffect = "Fade" />   

82                   

83        <!-- bind this Label to the name of the selected thumbnail -->

84                              <mx:Label text = "{ thumbnailList.selectedItem.name }" />

 

85                       </mx:VBox>

 

86                 </mx:HBox>

87

88                 <!-- slider can switch between images -->

 

<mx:HSlider id = "selectCoverSlider" height = "0%"

90        minimum = "0" maximum = "{ bookCovers.length - 1 }"

91        showDataTip = "false" snapInterval = "1" tickInterval = "1"

92        liveDragging = "true"

93        change = "thumbnailList.selectedIndex =

94        selectCoverSlider.value;

95        thumbnailList.scrollToIndex( selectCoverSlider.value )" />

96       

97                 <!-- display thumbnails of the images in bookCovers horizontally -->

 

98                 <mx:HorizontalList id = "thumbnailList"

 

99        dataProvider = "{ bookCovers }" width = "100%" height = "160" 100 selectedIndex = "0"

101 change = "selectCoverSlider.value = thumbnailList.selectedIndex">

102

103                     <!-- define how each item is displayed -->

 

104                     <mx:itemRenderer>

 

<mx:Component>

106      <mx:VBox width = "140" height = "160"

107      horizontalAlign = "center" verticalAlign = "middle"

108      verticalScrollPolicy = "off"

109      horizontalScrollPolicy = "off" paddingBottom = "20">

110     

111      <!-- display a thumbnail of each image -->

112      <mx:Image source = "{ 'thumbs/' + data.source }"

113      verticalAlign = "middle" />

114     

115      <!-- display the name of each image -->

116      <mx:Label text = "{ data.name }" />

117      </mx:VBox>

118                           </mx:Component>

 

119                     </mx:itemRenderer>

 

120               </mx:HorizontalList>

121        

122               <!-- this will exist in the bottom border of the Panel -->

 

123               <mx:ControlBar>

 

124                     <mx:LinkButton label = "Show/Hide Thumbnails"

 

125                           click = "currentState = 'HideThumbnails';"

126                           id = "showHideButton" />

 

127               </mx:ControlBar>

 

128        </mx:Panel>

 

</mx:Application>


Fig. 18.5 | Using States to dynamically modify a user interface.

We define an application’s states in a states element (lines 32–40). An application has a default state that contains its initial elements, layout and properties. Each additional state is enclosed in a State element, with a name attribute, which is the identifier for the State. View states allow you to add elements via the AddChild element, remove elements via the RemoveChild element, modify elements’ properties via the SetProperty element, set style via the SetStyle element, and set event handlers via the SetEventHandler element. The RemoveChild element in line 34 removes the thumbnailList. After the RemoveChild element, there is a SetEventHandler element (lines 39–38). Whenever the State is activated, this event handler will be registered. In this case, we change the click event handler of the showHideButton LinkButton (lines 124–126) to set the current- State to an empty string, signifying the application’s default state (with the thumbnail viewer displayed). This LinkButton is enclosed in a ControlBar element (lines 123– 127)—this embeds the elements it encloses into the bottom border of the Panel.

After we define the application’s states, we define a transition effect for the State change. Any State transition effects are enclosed in the transitions element (lines 43–49). For each Transition, you can specify a fromState and toState, using the State’s name. In this case, we leave out these attributes so that the transition effect applies to all State changes. Inside the Transition, we have a Resize effect (lines 45–47). This effect has a targets attribute that specifies which elements it applies to. It also has a duration attribute, which defines how long the effect lasts in milliseconds. Finally, we define the optional easingFunction attribute. Normally, the Resize effect would go at a linear speed. Instead, we have specified that it should use the Cubic.easeOut function2 (line 47), which controls the acceleration of the Resize animation. We import this function from the Flex library using ActionScript. A Script element (lines 7–10) encapsulates the application’s ActionScript code. Line 9 allows the Cubic function to be used anywhere in the program.

 

Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail


Copyright © 2018-2020 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.