﻿package TableWidget{
	

	import flash.display.MovieClip;
	import fl.containers.ScrollPane;
	import flash.events.*;
	import flash.events.KeyboardEvent;
	import flash.net.FileFilter;
	import flash.net.FileReference;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import TableWidget.comp.textformatter.TextPropertiesComponent;
	import TableWidget.comp.textformatter.SizeSelector;
	import flash.display.SimpleButton;
	import TableWidget.CSVParser;
	
	/**
	* This class is a starting point of Table widget.
	* It will load config XML, set movieclip references and draw table as per the
	* XML fed by Captivate. If there is a blank XML given it will draw the default table.
	*
	* @author Devender Gupta
	*/
	public class WidgetController{
		
		private static var instance:WidgetController;
		public var spane:ScrollPane;
		
		public var mcRef:MovieClip
		public var mcCells:MovieClip;
		public var mcGrid:MovieClip;
		
		public var objConfigXML:XML;
		public var xmlCaptivateParams:XML;
		public var xmlTextFormatter:XML;
		public var wm:String = "Stage";
		
		private var objColumnClass:ColumnClass;
		private var objRowClass:RowClass;
		public var currentSelectedCell:CellClass;
		private var objColumnHeaderStack:ColumnHeaderStack;
		public var objCursor:mcCursor;
		
		private var offSet:int;
		public var creationComplete:Boolean;
		private var currentSelectedCellText:String;
		public var objTextPropertiesComponent:TextPropertiesComponent;
		private var objRootRef:MovieClip;
		private var textEntry:Boolean = true;
		public var rootRef;
		
		private var browseBut:SimpleButton;
		private var fileRef:FileReference;
		private var fileNameTxt:TextField;
		private var csvParser:CSVParser;
		
		public function WidgetController(){
			
		}
				
		public static function getInstance():WidgetController{
			if(instance == null){
				instance =  new WidgetController();
			}
			return instance;
		}
		
		/**
		* This function set the reference of the movieclip in scrollpane in which whole table will be created.
		*
		*/
		public function setReference(sp:ScrollPane):void{
			offSet = 10;
			spane = sp;
			
			mcRef = new MovieClip();
			sp.source = mcRef;
			
			objRootRef = MovieClip(sp.parent);
			browseBut = objRootRef.browseBut;
			fileNameTxt = objRootRef.fileNameTxt
			fileNameTxt.text = "";
			
			mcCells = new MovieClip();
			mcCells.name = "mcCells";
			mcRef.addChild(mcCells);
			
			var cellBlocker = new MovieClip();
			cellBlocker.graphics.beginFill(0xFFF000, 0);
			cellBlocker.graphics.drawRect(0, 0, 100, 100);
			cellBlocker.graphics.endFill();
			
			mcRef.cellBlocker = cellBlocker
			mcRef.cellBlocker.visible = false;
			mcRef.addChild(cellBlocker);
			
			mcGrid = new MovieClip();
			mcGrid.name = "mcGrid";
			mcRef.addChild(mcGrid);
			
			objTextPropertiesComponent = objRootRef.textFormatterMc
			
			browseBut.addEventListener(MouseEvent.CLICK, browseButtonHandler);
			objTextPropertiesComponent.addEventListener(TextPropertiesComponent.VALUECHANGED, TextFormatHandler);
			objTextPropertiesComponent.addEventListener(SizeSelector.SIZECLICKED, sizeClickdHandler);
			objTextPropertiesComponent.addEventListener(SizeSelector.SIZECHANGED, sizeChangeHandler);
			
			csvParser = new CSVParser("table");
			csvParser.addEventListener(IOErrorEvent.IO_ERROR, IOErrorHandler)
			csvParser.addEventListener(Event.COMPLETE, CSVParsed);
		}
		
		private function browseButtonHandler(e:MouseEvent):void 
		{
			fileRef = new FileReference();
			fileRef.addEventListener(Event.COMPLETE, onLoaded);
			fileRef.addEventListener(Event.SELECT, fileSelectHandler);
			fileRef.browse(getFileTypes());
		}
		
		private function getFileTypes():Array
		{
			return new Array(new FileFilter("CSV Files (*.csv)", "*.csv"));
		}
		
		private function fileSelectHandler(e:Event):void 
		{
			fileRef.load();
			fileRef.removeEventListener(Event.SELECT, fileSelectHandler);
		}
		
		private function onLoaded(e:Event){
			
			var myText = fileRef["data"].readUTFBytes(fileRef["data"].length);
			var file:FileReference = FileReference(e.target);
			fileNameTxt.text = file.name;
			csvParser.loadFile(myText);
			
		}
		
		private function IOErrorHandler(e:IOErrorEvent):void 
		{
			//fileNameTxt.text = "An IOError";
		}
		
		private function CSVParsed(e:Event):void 
		{
			xmlCaptivateParams.table = csvParser.xml;
			createTable();
		}
		
		private function sizeChangeHandler(e:Event):void 
		{
			textEntry = true;
		}
		
		private function sizeClickdHandler(e:Event):void 
		{
			textEntry = false;
		}
		
		/**
		* This function sets and stores the configurations passed by TableWidget FLA
		* as a XML string. To make it non-dependable on loading delay, a hard-coded
		* XML has been passed.
		* @param configXML Description This parameter is xml. This sets the configurations like formatting etc.
		*/
		public function setConfigurations(strConfigXML:String):void {
			XML.prettyIndent = 0;
			XML.prettyPrinting = false;
			objConfigXML = new XML(strConfigXML);
			csvParser.setProperties(objConfigXML.textProperties);
		}
		
		/**
		* This function sets the XML data according to which the table is to be drawn.
		* If there is empty string passed, that means a default table is to be drawn.
		* @param strCaptivateXML Description This is xml in the form of string and carries all the parameters last set by the user. The data for each cell and modification done to the table resides in this xml only.
		*/
		public function setData(strCaptivateXML:String):void{
			xmlCaptivateParams = new XML(strCaptivateXML);
			
		}
		
		/**
		* This function sets the mode which is directly related to the widget mode.
		* @param widgetMode Description This parameters tell in which mode the widget is. The possible values may be "Edit" or "Preview" else the table will be rendered considering it is being viewed in Live Preview/in Captivate runtime player.
		*/
		public function setMode(widgetMode:String){
			if(wm != widgetMode){
				wm = widgetMode;
				if(wm == "Edit"){
					//in property dialog box
					mcGrid.visible = true;
					objTextPropertiesComponent.visible = true
					spane.x = 15.5
					spane.y = 78.5
					spane.setSize(530, 205)
					browseBut.visible = true;
					fileNameTxt.visible = true;
					
					var arr = [objTextPropertiesComponent.sizeSelectorMc];
					objRootRef.initCursor(arr);
				/*}else if(wm == "Preview"){
					mcGrid.visible = false;
					objTextPropertiesComponent.visible = false*/
				}else{
					// in Live preview, Web preview and runtime
					//mcGrid.visible = false;
					browseBut.visible = false;
					fileNameTxt.visible = false;
					objTextPropertiesComponent.visible = false
					spane.x = 0;
					spane.y = 0;
					spane.setSize(411, 155)
				}
			}
		}
		
		/**
		* This function initializes the WidgetController class to start drawing the table.
		*/
		public function createTable():void{
			createTextFormatter();
			deleteTable();
			objColumnHeaderStack = ColumnHeaderStack.getInstance();
			spane.stage.addEventListener(KeyboardEvent.KEY_DOWN, deleteKeyPressed);
			mcCells.cellSelected = cellSelected;
			createRows();
			createColumns();
			enableAllCells();
			if(wm != "Edit"){
				mcRef.removeChild(mcGrid);
				mcCells.x = -int(objConfigXML.rowColumnGrid.@rowWidth);
				mcCells.y = -int(objConfigXML.rowColumnGrid.@columnHeight);
			}
			spane.update();
			creationComplete = true;
		}
		
		private function DisplayTextFormatter(evt:Event){
			//objTextPropertiesComponent.SetState("enable")
			//objTextPropertiesComponent.disable_mc.visible = false;
		}
		private function HideTextFormatter(evt:Event){
			//objTextPropertiesComponent.SetState("disable")
			//objTextPropertiesComponent.disable_mc.visible = true;
		}
		public function createTextFormatter():void{
			
			//trace("xmlCaptivateParams.textProperties: "+xmlCaptivateParams.textProperties);
			objTextPropertiesComponent.setData(objConfigXML.textProperties);
			objTextPropertiesComponent.init();
		}
		/**
		* This function always returns the latest XML whenever called.
		*/
		public function getModifiedXML():String{
			
			XML.prettyIndent = 0;
			XML.prettyPrinting = false;
			return xmlCaptivateParams.toString();
		}
		
		
		private function createColumns(){
			objColumnClass = ColumnClass.getInstance();
			objColumnClass.setReferences(mcRef);
			objColumnClass.init();
			objColumnClass.addEventListener("hideopenedmenu", hideRowMenu);
			spane.update();
		}
		
		private function createRows(){
			
			objRowClass = RowClass.getInstance();
			objRowClass.setReferences(mcRef);
			objRowClass.init();
			objRowClass.addEventListener("hideopenedmenu", hideColumnMenu);
		}
		
		public function htmlize(txt, nodeName):String{
			var xmlNode = objConfigXML.child(nodeName);
			var fontStr = '<font face="'+xmlNode.@face+'" size="'+xmlNode.@size+'" color="'+xmlNode.@color+'">' + txt + '</font>';
			return fontStr;
					
		}
		
		private function hideRowMenu(evt:Event){
			objRowClass.hideDisplayedRow();
		}
		private function hideColumnMenu(evt:Event){
			objColumnClass.hideDisplayedColumn();
		}
		
		private function cellSelected(evt:Event):void{
			//trace("cellSelected");;
			//trace("xmlCaptivateParams"+xmlCaptivateParams);
			currentSelectedCellText = null;
			var currentCell:CellClass = evt.currentTarget as CellClass;
			
			if(currentSelectedCell != null && currentSelectedCell != currentCell){
				currentSelectedCell.setSelection(false);
				
			}
			objColumnClass.setSelection(evt.target.columnRef.index, evt.target.rowRef.index);
			objRowClass.setSelection(evt.target.rowRef.index, evt.target.columnRef.index);
			mcCells.setChildIndex(currentCell, mcCells.numChildren-1);
			currentSelectedCell = currentCell;

			textSelectionEvent(null);
			currentSelectedCell.addEventListener("SetTextSelectionEvent", textSelectionEvent);
			
			if(currentSelectedCell.cellText.type == "dynamic")// && currentSelectedCell.cellText.text=="")
			{
				//getPreviousTextFormatting(currentSelectedCell.cellText.htmlText);
				
				currentSelectedCellText = currentSelectedCell.cellText.htmlText;
				//objTextPropertiesComponent.SetState("disable")
				objTextPropertiesComponent.highlightColorMc.enabled=true
			}
			else
			{
				//objTextPropertiesComponent.SetState("enable")
				objTextPropertiesComponent.highlightColorMc.enabled=false
			}
			var dtf = currentSelectedCell.cellText.getTextFormat();
			if( dtf.align == null){
				dtf = currentSelectedCell.cellText.defaultTextFormat;
			}
			if( dtf.align != null){
				objTextPropertiesComponent.leftAlignMc.gotoAndStop(1)
				objTextPropertiesComponent.centerAlignMc.gotoAndStop(1)
				objTextPropertiesComponent.rightAlignMc.gotoAndStop(1)
				var buttonName = dtf.align + "AlignMc";
				var alignMc = objTextPropertiesComponent.getChildByName(buttonName);
				alignMc.gotoAndStop(2);
			}
			if(dtf.size != null){
				objTextPropertiesComponent.setDefaultFormat(dtf, xmlCaptivateParams.table.column[currentSelectedCell.columnRef.index].row[currentSelectedCell.rowRef.index].cell[0].@borderColor)
			}
			
			
			currentSelectedCell.addEventListener("DisplayTextFormatter", DisplayTextFormatter);
			currentSelectedCell.addEventListener("HideTextFormatter", HideTextFormatter);
		}
		private function textSelectionEvent(evt:Event):void
		{
			
				//
				if(objTextPropertiesComponent.initialize!=false)
				{
					var xmlTextFormat:XMLList = new XMLList();
					if(currentSelectedCell.cellText.htmlText!="")
					{
					xmlTextFormat=XMLList(currentSelectedCell.getCurrentCellFormat());
					objTextPropertiesComponent.setData(xmlTextFormat);
					objTextPropertiesComponent.setDefaultData()
					}
					else
					{
					
					/*xmlTextFormat=objTextPropertiesComponent.getData();
					var cellStyle:TextFormat= new TextFormat();
					cellStyle.size=Number(xmlTextFormat.font.attribute("size"));
					cellStyle.italic=xmlTextFormat.textDecoration.attribute("italic")=="true"?true:false;
					cellStyle.bold=xmlTextFormat.textDecoration.attribute("bold")=="true"?true:false;
					cellStyle.font=xmlTextFormat.font.attribute("face");
					cellStyle.underline=xmlTextFormat.textDecoration.attribute("underline")=="true"?true:false;
					currentSelectedCell.cellText.setTextFormat(cellStyle)*/
					}
					
				}
				
				
		}
		private function getPreviousTextFormatting(cellString:String):void{
			
			var fontStr:String = "<data>"+cellString.split(">")[1]+"/></data>"
			var fontXMLNode:XML;
			fontXMLNode = XML(fontStr);
			var fontColorStr:String = "0x" + fontXMLNode.FONT.@COLOR.split("#")[1]; 
			xmlTextFormatter.font.@face= fontXMLNode.FONT.@FACE;
			xmlTextFormatter.font.@size = fontXMLNode.FONT.@SIZE;
			xmlTextFormatter.color.@textColor = fontColorStr;
		}
		// whenever any prpo in text comp is changed this function is called
		private function TextFormatHandler(evt:Event){
			xmlTextFormatter = new XML();
			xmlTextFormatter = XML(evt.target.getData());
			var cellStyle:TextFormat= new TextFormat();
			switch(evt.target.propChanged)
			{
				case "size":
				cellStyle.size=Number(xmlTextFormatter.font.attribute("size"));
				break;
				case "italic":
				cellStyle.italic=xmlTextFormatter.textDecoration.attribute("italic")=="true"?true:false;
				break;
				case "bold":
				cellStyle.bold=xmlTextFormatter.textDecoration.attribute("bold")=="true"?true:false;
				break;
				case "style":
				cellStyle.italic=xmlTextFormatter.textDecoration.attribute("italic")=="true"?true:false;
				cellStyle.bold=xmlTextFormatter.textDecoration.attribute("bold")=="true"?true:false;
				break;
				case "font":
				cellStyle.font=xmlTextFormatter.font.attribute("face");
				break;
				case "textcolor":
				cellStyle.color=xmlTextFormatter.color.attribute("textColor");
				break;
				case "bgcolor":
				currentSelectedCell.ApplyBgColor(xmlTextFormatter.color.@highlightColor);
				//currentSelectedCell.Holder.backgroundColor=xmlTextFormatter.color.@highlightColor
				//var colRef=arrRowsAssets
				xmlCaptivateParams.table.column[currentSelectedCell.columnRef.index].row[currentSelectedCell.rowRef.index].cell[0].@bgColor=xmlTextFormatter.color.@highlightColor
				break;
				case "underline":
				cellStyle.underline=xmlTextFormatter.textDecoration.attribute("underline")=="true"?true:false;
				case "align":
				cellStyle.align=xmlTextFormatter.textDecoration.attribute("align");
				break;
				case "borderColor":
				currentSelectedCell.ApplyBorderColor(xmlTextFormatter.color.@borderColor);
				xmlCaptivateParams.table.column[currentSelectedCell.columnRef.index].row[currentSelectedCell.rowRef.index].cell[0].@borderColor=xmlTextFormatter.color.@borderColor
				break;
			}
						
			if(currentSelectedCell.cellText.selectionBeginIndex != currentSelectedCell.cellText.selectionEndIndex)
			{
				currentSelectedCell.cellText.setTextFormat(cellStyle,currentSelectedCell.cellText.selectionBeginIndex,currentSelectedCell.cellText.selectionEndIndex);
			}
			else
			{
				currentSelectedCell.cellText.setTextFormat(cellStyle);
			}
			if(currentSelectedCell.cellText.text == ""){
				currentSelectedCell.cellText.defaultTextFormat = cellStyle
			}
			
			//currentSelectedCell.cellText.setTextFormat(cellStyle);
			currentSelectedCell.updateTableOnFontSizeChange()
			//spane.update();
		}
		
		private function setHtmlText(cellStr:String, decorationStyle:String):String
		{
			var cellText:String = cellStr;
			trace("selectionBeginIndex:", currentSelectedCell.cellText.selectionBeginIndex);
            trace("selectionEndIndex:", currentSelectedCell.cellText.selectionEndIndex);
			var selectedStr:String;
			switch(decorationStyle)
			{
				case "bold":
				selectedStr = "<B>"+ cellText.substring(currentSelectedCell.cellText.selectionBeginIndex, currentSelectedCell.cellText.selectionEndIndex)+"</B>";
				break;
				case "italic":
				selectedStr = "<I>"+ cellText.substring(currentSelectedCell.cellText.selectionBeginIndex, currentSelectedCell.cellText.selectionEndIndex)+"</I>";
				break;
				case "underline":
				selectedStr = "<U>"+ cellText.substring(currentSelectedCell.cellText.selectionBeginIndex, currentSelectedCell.cellText.selectionEndIndex)+"</U>";
				
				break;
			}
			var strStart:String;
			var strEnd:String;
			var returnText:String;
			if(currentSelectedCell.cellText.selectionBeginIndex !=0)
			{
				strStart = cellText.slice(0,currentSelectedCell.cellText.selectionBeginIndex);
				returnText = strStart + selectedStr;
			}
			else
			{
				returnText = selectedStr;
			}
			if(currentSelectedCell.cellText.selectionEndIndex != cellStr.length)
			{
				strEnd = cellText.slice((currentSelectedCell.cellText.selectionEndIndex), (cellStr.length));
				returnText = returnText + strEnd;
			}
			//trace("selectedStr: "+selectedStr+"::::strStart: "+ strStart+"::::strEnd: "+ strEnd+":::cellStr.length: "+cellStr.length);
			trace("returnText: "+returnText);
			return returnText;
		}
		private function setTextFormatter(cellStyle:TextFormat):TextFormat
		{
			cellStyle.underline=xmlTextFormatter.textDecoration.attribute("underline")=="true"?true:false;
			cellStyle.italic=xmlTextFormatter.textDecoration.attribute("italic")=="true"?true:false;
			cellStyle.bold=xmlTextFormatter.textDecoration.attribute("bold")=="true"?true:false;
			cellStyle.align=xmlTextFormatter.textDecoration.attribute("align");
			cellStyle.font=xmlTextFormatter.font.attribute("face");
			cellStyle.size=Number(xmlTextFormatter.font.attribute("size"));
			cellStyle.color=xmlTextFormatter.color.attribute("textColor");
			return cellStyle;
		}
		private function deleteKeyPressed(evt:KeyboardEvent):void{
			if(currentSelectedCellText != null)
			{
				/*getPreviousTextFormatting(currentSelectedCellText);
				var cellStyle:TextFormat= new TextFormat();
				setTextFormatter(cellStyle);
				currentSelectedCell.cellText.defaultTextFormat = cellStyle;*/
			}
			var i;
			var eachCell;
			var rowRef;
			var colRef;
			var arrCellsReference;
			var nextCell;
			var whichRow
			if(evt.keyCode == 46){
				for(i=0; i<mcCells.numChildren; i++){
					eachCell = MovieClip(mcCells.getChildAt(i));
					if(eachCell.isSelected && eachCell.cellText.type == "dynamic"){
						if(eachCell.isHeader){
							objColumnHeaderStack.putBack(eachCell.txtContent)
						}
						eachCell.txtContent = ""
					}
				}
			}else if(evt.keyCode == 113 ){
				for(i=0; i<mcCells.numChildren; i++){
					eachCell = MovieClip(mcCells.getChildAt(i));
					if(eachCell.isSelected){
						eachCell.setSelection(true);
						eachCell.callEditor(null);
						break;
					}
				}
			}else if(evt.keyCode == 39 || evt.keyCode == 9){
				
				evt.preventDefault();
				for(i=0; i<mcCells.numChildren; i++){
					eachCell = MovieClip(mcCells.getChildAt(i));
					if(eachCell.isSelected){
						if((evt.keyCode == 39 && eachCell.cellText.type == "dynamic" && textEntry) || evt.keyCode == 9){
							rowRef = eachCell.rowRef;
							arrCellsReference = rowRef.arrCellsReference
							if(rowRef.currentSelectedCell+1 < arrCellsReference.length){
								nextCell = arrCellsReference[rowRef.currentSelectedCell+1]
								nextCell.setSelection(true);
							}
						}
						break;
					}
				}
			}else if(evt.keyCode == 37){
				evt.preventDefault();
				for(i=0; i<mcCells.numChildren; i++){
					eachCell = MovieClip(mcCells.getChildAt(i));
					if(eachCell.isSelected && eachCell.cellText.type == "dynamic" && textEntry){
						rowRef = eachCell.rowRef;
						arrCellsReference = rowRef.arrCellsReference
						if(rowRef.currentSelectedCell > 0){
							nextCell = arrCellsReference[rowRef.currentSelectedCell-1]
							nextCell.setSelection(true);
						}
						break;
					}
				}
			}else if(evt.keyCode == 38){
				evt.preventDefault();
				for(i=0; i<mcCells.numChildren; i++){
					eachCell = MovieClip(mcCells.getChildAt(i));
					if(eachCell.isSelected && eachCell.cellText.type == "dynamic" && textEntry){
						colRef = eachCell.columnRef;
						rowRef = eachCell.rowRef;
						if(rowRef.index > 0){
							whichRow = rowRef.index - 1;
							arrCellsReference = colRef.arrCellsReference
							nextCell = arrCellsReference[whichRow]
							nextCell.setSelection(true);
						}
						break;
					}
				}
			}else if(evt.keyCode == 40){
				evt.preventDefault();
				for(i=0; i<mcCells.numChildren; i++){
					eachCell = MovieClip(mcCells.getChildAt(i));
					if(eachCell.isSelected && eachCell.cellText.type == "dynamic" && textEntry){
						colRef = eachCell.columnRef;
						rowRef = eachCell.rowRef;
						trace((rowRef.index+1) + ":"+ rowRef.arrRowReferences.length)
						if(rowRef.index+1 < rowRef.arrRowReferences.length){
							whichRow = rowRef.index + 1;
							arrCellsReference = colRef.arrCellsReference
							nextCell = arrCellsReference[whichRow]
							nextCell.setSelection(true);
						}
						break;
					}
				}
			}else if((evt.keyCode >= 48 && evt.keyCode <= 57)||(evt.keyCode >= 65 && evt.keyCode<=90)){
				
				var multipleCellSelection = 0;
				var whichCell = null;
				for(i=0; i<mcCells.numChildren; i++){
					eachCell = MovieClip(mcCells.getChildAt(i));
					if (eachCell.isSelected && eachCell.cellText.type == "dynamic" && textEntry) {
						multipleCellSelection++;
						whichCell = eachCell;
					}
				}
				if (multipleCellSelection == 1 && textEntry) {
					eachCell = whichCell;
					objRowClass.hideDisplayedRow();
					objColumnClass.hideDisplayedColumn()
					eachCell.setSelection(true);
					eachCell.callEditor(null);
				}
			}
		}
		
		private function enableAllCells(){
			var bln = false
			if(wm == "Edit"){
				bln = true;
			}
			for(var i=0; i<mcCells.numChildren; i++){
				var eachCell = MovieClip(mcCells.getChildAt(i));
				eachCell.enableIt = bln;
				if(eachCell.isSelected){
					eachCell.setSelection(false);
				}
			}			
		}
		
		private function deleteTable(){
			for(i=mcGrid.numChildren-1; i>=0; i--){
				eachCell = MovieClip(mcGrid.getChildAt(i));
				mcGrid.removeChild(eachCell)
			}
			for(var i=mcCells.numChildren-1; i>=0; i--){
				var eachCell = MovieClip(mcCells.getChildAt(i));
				mcCells.removeChild(eachCell)
			}
			if(objColumnHeaderStack != null){
				objColumnHeaderStack.killSingleton()
				objColumnHeaderStack = null;
			}
			if(objColumnClass != null){
				objColumnClass.removeEventListener("hideopenedmenu", hideRowMenu);
				objColumnClass.killSingleton()
				objColumnClass= null
			}
			if(objRowClass != null){
				objRowClass.removeEventListener("hideopenedmenu", hideColumnMenu);
				objRowClass.killSingleton()
				objRowClass = null
			}
			
			
		}
		
		public function setRootRef(inRef)
		{
			rootRef= inRef;
		}
	}
	
}