|
Thanks, but i a second question (sorry)...
What's with the following code:
Test t1 = new Test();
Test t2 = t1;
What is 't2'? Is it also a copy of t1 or a reference?
Thanks!!!
MFG Daniel.
|
|
|
|
|
I'm not sure what those classes are, but:
class Test1
{
public int _i =-1;
public Test1(int i)
{_i=i;}
public override string ToString()
{return _i.ToString();}
}
Test1 t1 = new Test1(100);
Test1 t2 = t1;
Console.WriteLine(t1.ToString());
t2._i=200;
Console.WriteLine(t2.ToString());
Console.WriteLine(t1.ToString());
Console.ReadLine(); Proves that t2 and t1 point to the same location in mem.
Does that help you?
Cheers,
Simon
"Sign up for a chance to be among the first to experience the wrath of the gods.", Microsoft's home page (24/06/2002)
|
|
|
|
|
I how can i make a full copy of a object, so that when i change the member in object 1, the member in object 2 will not be changed???? So, as a deep copy in c++!!!
MFG Daniel.
|
|
|
|
|
I'm pretty sure there's a copy and a clone method for this type of thing, but I have a feeling that you're going to have to implement it yourself.
I'll have a look though.
modified: do a search for ICloneable.Clone Method in MSDN. The ICloneable interface looks like what you're looking for.
HTH
Cheers,
Simon
"Sign up for a chance to be among the first to experience the wrath of the gods.", Microsoft's home page (24/06/2002)
|
|
|
|
|
To get a deep copy in C# do this:
public static object Clone(object objectToClone)
{
if (objectToClone == null)
{
throw new ArgumentNullException("objectToClone", "Parameter can not be null.");
}
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, objectToClone);
stream.Seek(0, SeekOrigin.Begin);
return formatter.Deserialize(stream);
}
To deep copy an object with this method, use:
MyTest originalObject = new MyTest(a, lot, of, stuff);
MyTest cloneObject = (MyTest)Clone(originalObject);
The best part is that this is generic: extend MyTest with properties and you don't have to change the clone method.
Øyvind
|
|
|
|
|
SimonS wrote:
"Sign up for a chance to be among the first to experience the wrath of the gods.", Microsoft's home page (24/06/2002)
This beats them all.
|
|
|
|
|
O will be an Object that points to a new System.Int32 with the value of i, and if you change the value of O to 2, i will still be 1.
So the short answer is that it is a copy.
/Bo
|
|
|
|
|
And the follwing code:
Test t1 = new Test();
Test t2 = t1;
What is 't2'? Is it also a copy of t1 or a reference?
Thanks!!!
MFG Daniel.
|
|
|
|
|
Both t1 and t2 will be references to the new Test object created. No copy is made - and yes they are "pointers" - even if somebody tells you that C# ´don't have pointers.
/Bo
|
|
|
|
|
have you heard about boxing and unboxing?
i'm not 100% but pretty sure it goes like this:
* i is an int and placed on the stack.
* o is an object and therefore placed on the heap - i is "boxed" and the boxed copy is referenced by o - i believe, o is a COPY of i
* you can check with object.ReferenceEquals(a,o) that a and o point to the same object
as said before - i'm not 100 percent sure about it...(still a beginner to C# and .NET)
:wq
|
|
|
|
|
Oh boy am I tired, but glad I read your post because I was just getting ready to respond with the explanation you gave.
To my knowledge, any time you instansiate an object of a class in C# you are doing so on the heap, however when you use static methods, objects aren't required for this and therefore they process on the stack. Hopefully I am not mumbling here as I have been up for way to long.
HTH
Nick Parker
|
|
|
|
|
my experiences and deductions lead me to believe that any class inheriting from object is passed by reference.
READ MSDN
|
|
|
|
|
int and string both inherit from object, but are passed by val.
I think it has more to do with boxing than their hierarchy. I could be wrong though.
Cheers,
Simon
"Sign up for a chance to be among the first to experience the wrath of the gods.", Microsoft's home page (24/06/2002)
|
|
|
|
|
int is passed by value; string is passed by reference (but strings are immutable).
Any class that inherits from ValueType is passed by value; any other class is passed by reference. A struct is a special kind of class, it inherits from ValueType.
James
"Java is free - and worth every penny." - Christian Graus
|
|
|
|
|
To clear it all up since there have been either incorrect or misleading statements mentioned.
o is a reference to a copy of i; a is a reference to whatever o is referencing.
Here is a small program which illustrates that
using System;
namespace test
{
public class Test
{
public static void Main(string [] args)
{
int a = 1;
object o = a;
object o2 = o;
Console.WriteLine("a = {0}, o = {1}, o2 = {2}", a, o, o2);
a = 2;
Console.WriteLine("a = {0}, o = {1}, o2 = {2}", a, o, o2);
o = 3;
Console.WriteLine("a = {0}, o = {1}, o2 = {2}", a, o, o2);
}
}
} The output should be
a = 1, o = 1, o2 = 1<br />
a = 2, o = 1, o2 = 1<br />
a = 2, o = 3, o2 = 1
HTH,
James
"Java is free - and worth every penny." - Christian Graus
|
|
|
|
|
Hi James, sorry, but i have a question to you about your sample program.
In your sample program is 'a' an 'int' with the value '1' and 'o' a reference to a copy of 'a', is that right? And 'o2' is a reference to 'o', is that also right?
But why is the last 'Console.WriteLine' Function the output value of 'o2' '1' and not '3' ???
I don't understand why the value of 'o2' is '1' and not '3' like the value of 'o'.
(Sorry for my bad english )
MFG Daniel.
|
|
|
|
|
jb_dani wrote:
Sorry for my bad english
Thats ok, I was able to read everything just fine
jb_dani wrote:
In your sample program is 'a' an 'int' with the value '1' and 'o' a reference to a copy of 'a', is that right?
Correct.
jb_dani wrote:
And 'o2' is a reference to 'o', is that also right?
What happens here would be much clearer if we had the C++ syntax.
object *o, *o2;
int i;
i = 1;
o = __box(i);
o2 = o;
i = 3;
o = __box(i);
If you don't understand C++ I hope the comments clarify it for you
James
"Java is free - and worth every penny." - Christian Graus
|
|
|
|
|
Thank you very much!
(I am happy that my english is not so bad!)
MFG Daniel.
|
|
|
|
|
I had no any c# experience, but some java
maybe sometime copy, sometime reference
eg, reference:
----------------------------------------------
CMyCustObj i = new CMyCustObj()
object o = i;
object a = o;
---------------------------------------------
you can compare the address of i,o,a
|
|
|
|
|
hi,
i have a connection dialog and put some labels in there. there's a picturebox in front of each label with an icon signaling that the operation described in the corresponding label has been finished. should look something like:
* connecting
* receiving
* saving
copying
calculating
etc etc
this should tell the user, that the first three activities were finished and the fourth is in progress (it's all a little niftier, but you get the point).
now the problem: i have the function, that does all the operations in sequence and activates the pictures appropriately. but they don't show. only after all operations have been finished, all symbols are shown. i've set the pictures (which are of type System.Windows.Forms.PictureBox) to visible=false in the dialog-editor and just turn them on with visible=true during processing. when i enable/disable the corresponding labels, they DO change their state on the fly - so there IS some dialog-drawing function active in the background - why doesn't it draw the pictures, when it is able to redraw the labels?
moreover: i've put the operation-function in a different thread and signaled the eventchange via event/delegate to the dialog but it just doesn't help.
any suggestions? thank you boys (and girls?) i rely on you
Edit:
if someone wants to check out a minimum-demo-project about my problem he can download and try this
|
|
|
|
|
hmm
simply calling the forms Update() function solves the problem.
but why is the Label.Enabled-setter calling it itself and the PictureBox.Visible-setter doesn't?
anyways.
thx everyone for reading...
:wq
|
|
|
|
|
Hi there
Changing the pictures should not be a problem if you have events firing for your "functions". So if there are no events defined for them yet, just create an event for each "function". I did this a while back to show diferent pictures for "Offline, Connecting, Online". Pretty easy stuff once you grasp events.
Hope this helps
READ MSDN
|
|
|
|
|
ok. thx. would be another idea to split the long sequence into seperate functions. but i have to use a lot of variables in all of the parts of this long sequence - so splitting it up would result in a lot of !=null testing of class-members which only have the task to pass data from one private function to another ...
hmm. too much overhead in the code i think...
but thx anyway for the idea
:wq
|
|
|
|
|
Hi ,
How to access an EXCEL File and read the cells within it?
Can anyone show me a light?
thanks in advance
|
|
|
|
|
I never write c# code, but In c++ or java, I ever had access Excel, send the c++ codes, hope some help to you!
----------------------------------------------------------
package snsoftx.win;
import snsoft.util.*;
import com.jacob.com.*;
import com.jacob.activeX.*;
import java.util.*;
import java.io.File;
/**
* Company: 南北公司
* @author: Grant
* @email: wang_yi_ming@263.net
* @version 5.0
*
* MSExcelApp类用来操作Ms Excel文件:
* 新建,删除文件, Sheet, Row, Col
* comments:
* 要使用MSExcelApp类, 必须jacob.dll的支持
*
* expamples:
* 1. 只读打开文件,读数据:
* MSExcelApp excelApp = null;
* try
{
excelApp = new MSExcelApp();
if( excelApp.openExcel("c:\\temp\\cc.xls","Sheet1") )
{
int rowCount = excelApp.getRowCount();
int colCount = excelApp.getColumnCount();
System.out.println("rowCount=" + rowCount+",colCount=" + colCount);
// get column info
for (int col = 0; col < colCount; col++)
System.out.println("colName:" + excelApp.getColumnName(col) + "\r\n");
excelApp.prepareFetchData(); // 为了提高查询速度
for (int r = 0; r < rowCount; r++)
{
excelApp.gotoRow( r );
for (int c = 0; c < colCount; c++)
{
Object ob = excelApp.getValue(c);
// or ob = excelApp.getCellValue(r,c);
s += (ob == null) ? "" : ob.toString() + ",";
}
System.out.println(s + "\r\n");
}
excelApp.endFetchData();
excelApp.close();
}
}
catch (Exception ex) { ex.printStackTrace(); }
* 2. 打开文件,修改文件 :
* MSExcelApp excelApp = null;
* try
{
excelApp = new MSExcelApp();
if( excelApp.openExcel("c:\\temp\\cc.xls","学生成绩单",false,false,true) )
{
excelApp.addField("学号",0)
excelApp.addField("姓名",0)
excelApp.addField("语文",1)
excelApp.addField("数学",1)
excelApp.addField("英语",1)
excelApp.insertRow(true);
excelApp.setValue(0,"01");
excelApp.setValue(1,"张三");
excelApp.setValue(2,new Double("85.0") );
excelApp.setValue("数学",new Double("95.0") );
excelApp.setValue(4,new Double("90.5") );
excelApp.insertRow(true);
excelApp.setValue(0,"02");
excelApp.setValue(1,"李四");
excelApp.setValue(2,new Double("80.0") );
excelApp.setValue(3,new Double("90.0") );
excelApp.setValue(4,new Double("85.5") );
excelApp.saveChanges(); // 保存
excelApp.close();
}
}
catch (Exception ex) { ex.printStackTrace(); }
*
*/
public class MSExcelApp // extends AbstractDataSet
{
public ActiveXComponent excelApp;
private Dispatch workbooks;
private Dispatch workbook; // private Dispatch sheets;
private Dispatch sheet;
String m_szFileName;
String m_szSheetName;
boolean m_bNewFile;
boolean m_bReadOnly;
boolean m_bValidate;
boolean bPreparedFectch;
int rowCount, colCount;
int curRow;
Vector fldNames = new Vector();
boolean bCreateFile = false;
boolean visible;
public MSExcelApp()
{
this( false );
}
public MSExcelApp(boolean visible)
{
this.visible = visible;
}
/**
* Open for readOnly
*/
public boolean openExcel(String szFileName,String szSheetName)
{
return openExcel( szFileName,szSheetName, false,false,false);
}
public boolean openExcel(String szFileName,String szSheetName,boolean bReadOnly)
{
return openExcel(szFileName, szSheetName, bReadOnly,false,false);
}
public boolean openExcel(String szFileName,String szSheetName,
boolean bReadOnly, boolean bNewFile, boolean bNewSheet)
{
if( excelApp == null )
{
excelApp = new ActiveXComponent("Excel.Application");
if( visible )
excelApp.setProperty("Visible", new Variant(true));
}
workbooks = Dispatch.get(excelApp,"Workbooks").toDispatch();
bPreparedFectch = false;
curRow = -1;
rowCount = colCount = 0;
if( szFileName.indexOf('/') >= 0 )
szFileName = szFileName.replace('/','\\');
m_szFileName = szFileName;
m_bReadOnly = bReadOnly;
m_bNewFile = bNewFile;
try
{
// if( bNewFile
if( !bNewFile && isFileExist(szFileName) )
{
workbook = Dispatch.call(workbooks,"Open",szFileName).toDispatch();
m_bValidate = true;
}
else
{
workbook = Dispatch.call(workbooks,"Add").toDispatch();
bCreateFile = true;
m_bValidate = true;
}
if( bNewSheet && !isSheetExist(szSheetName) )
m_bValidate = newSheet( szSheetName );
else
{
m_bValidate = activeSheet( szSheetName );
if( m_bValidate )
{
innerGetRowColCount();
//PrepareFetchData();
for(int i=0; i<colcount; i++)
="" fldnames.addelement(="" innergetcolumnname(i)="" );
="" endfetchdata();
="" }
="" catch(exception="" ex)
="" {
="" m_bvalidate="false;
" ex.printstacktrace();
="" return="" m_bvalidate;
="" }
="" public="" boolean="" isfileexist(="" string="" szfilename="" )
="" try
="" file="" file(szfilename);
="" file.isfile();
="" ex)="" {}
="" false;
="" }
="" safearray="" sa;
="" int="" nametoindex(string="" szfldname)
="" for(int="" i="0;" i<fldnames.size();="" if(="" fldnames.elementat(i).tostring().equalsignorecase(="" szfldname="" )="" i;
="" -1;
="" addfield(string="" szcolname,="" ncoltype)
="" setcellvalue(-1,="" colcount,="" szcolname)="" szcolname="" set="" column="" attribute
="" *
="" selection.numberformatlocal="@"
="" *="" szformat="@" ;
="" if="" (="" ncoltype="=" com.borland.dx.dataset.variant.int="" ||="" com.borland.dx.dataset.variant.short
="" com.borland.dx.dataset.variant.byte="" com.borland.dx.dataset.variant.long="" else="" com.borland.dx.dataset.variant.bigdecimal="" com.borland.dx.dataset.variant.float="" com.borland.dx.dataset.variant.double="" com.borland.dx.dataset.variant.date="" com.borland.dx.dataset.variant.timestamp="" ;
="" colname="getCellColName(colCount);
//Message.out.println(colName+","+szColName+","+szFormat);
" object="" a1="Dispatch.invoke(sheet," "columns",="" dispatch.get,
="" new="" object[]="" {colname+":"+colname},
="" int[1]).todispatch();
="" end
="" dispatch.put(="" a1,="" "numberformatlocal",="" szformat);
="" colcount++;
="" true;
="" else
="" getcolumnname(int="" col)
="" col="">=0 && col < fldNames.size() )
return fldNames.elementAt(col).toString();
return "";
}
public int getColumnType(int col) { return 0; }
protected String getCellColName(int col)
{
col++;
int count = 0;
String s = "";
while( col > 0 )
{
int m = (col-1)%26;
col = (col-1)/26;
s = (char)('A'+m) + s;
}
return s;
}
protected String getCellName(int row, int col)
{
return getCellColName(col)+(row+2);
}
// zsb 11-29 cancel
/* static public void closeExcelApp()
{
if( excelApp != null )
{
Dispatch workbook = Dispatch.get(excelApp,"ActiveWorkbook").toDispatch();
Dispatch.call(workbook,"Close", new Variant(false) );
excelApp.invoke("Quit", new Variant[] {});
excelApp.release();
excelApp = null;
}
}
*/
public void close()
{
fldNames.removeAllElements();
if( excelApp != null && workbook != null )
{
endFetchData();
Dispatch.call(workbook,"Close", new Variant(false) );
workbook = null;
excelApp.invoke("Quit", new Variant[] {});
excelApp.release();
excelApp = null;
}
}
public String getFileName()
{
return m_szFileName;
}
boolean isReadOnly() { return m_bReadOnly; };
public void prepareFetchData()
{
if( !bPreparedFectch )
{
String cell1 = getCellName(-1,0);
String cell2 = getCellName(rowCount,colCount);
Dispatch range = Dispatch.invoke(sheet, "Range", Dispatch.Get,
new Object[] {cell1+":"+cell2},
new int[1]).toDispatch();
Variant ret = Dispatch.get(range,"Value");
sa = ret.toSafeArray();
bPreparedFectch = true;
}
}
public void endFetchData()
{
if( bPreparedFectch )
{
if( sa != null )
{
sa.release();
sa = null;
}
bPreparedFectch = false;
}
}
boolean activeSheet(String szSheetName)
{
// Dispatch workbook = Dispatch.get(excelApp,"ActiveWorkbook").toDispatch();
Dispatch sheets = Dispatch.get(workbook,"Sheets").toDispatch();
int count = Dispatch.get(sheets,"Count").toInt();
for(int i=0; i<count; i++)
="" {
="" sheet="Dispatch.call(sheets," "item",="" new="" variant(i+1)).todispatch();
="" if(="" szsheetname.equalsignorecase(="" dispatch.get(sheet,"name").tostring()="" )="" )
="" dispatch.call(sheet,"activate");
="" return="" true;
="" }
="" false;
="" }
="" boolean="" issheetexist(string="" szsheetname)
="" dispatch="" workbook="Dispatch.get(excelApp,"ActiveWorkbook").toDispatch();
" sheets="Dispatch.get(workbook,"Sheets").toDispatch();
" int="" count="Dispatch.get(sheets,"Count").toInt();
" for(int="" i="0;" i<count;="" deletesheet(string="" variant(i+1)).todispatch();
="" try
="" dispatch.call(sheet,"delete");
="" catch(exception="" ex)="" {="" break;="" newsheet(string="" message.out.println("new="" sheet"+szsheetname);
="" "add").todispatch();
="" dispatch.put(sheet,"name",szsheetname);
="" ex)
="" protected="" void="" finalize()="" throws="" throwable="" close();="" public="" getrowcount()
="" rowcount;
="" getcolumncount()
="" colcount;
="" getrow()
="" currow;
="" gotorow(int="" row)
="" row="">=0 && row < rowCount )
curRow = row;
}
public Object getValue(int row,int columnIndex)
{
return getCellValue(row, columnIndex);
}
public Object getValue(int columnIndex)
{
return getCellValue(curRow, columnIndex);
}
public void insertRow(boolean after)
{
if( m_bReadOnly || !m_bValidate )
return;
try
{
if( !after )
curRow = rowCount++;
else
{
String cell1 = getCellName(curRow,0);
String cell2 = getCellName(curRow,colCount-1);
Dispatch range = Dispatch.invoke(sheet, "Range", Dispatch.Get,
new Object[] {cell1+":"+cell2},
new int[1]).toDispatch();
// value = Dispatch.get(a1, "Value");
//Dispatch range = Dispatch.call(excelApp,"GetRange", new Variant(cell1),new Variant(cell2) ).toDispatch();
boolean bRet = Dispatch.call(range,"Insert", new Variant( (long)-4121 )).toBoolean();
if( bRet )
rowCount++;
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
public void postRow()
{
if( m_bReadOnly || !m_bValidate || excelApp == null )
return ;
try
{
// Dispatch workbook = Dispatch.get(excelApp,"ActiveWorkbook").toDispatch();
if( bCreateFile )
Dispatch.call(workbook,"SaveAs",m_szFileName);
else
Dispatch.call(workbook,"Save");
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
public boolean isRowChanged()
{
return false;
}
public boolean isNewRow()
{
return false;
}
public boolean deleteIndexRow(int row)
{
if( m_bReadOnly || !m_bValidate || row >= rowCount || row < 0 )
return false;
boolean bRet = false;
try
{
// Dispatch range = Dispatch.call(excelApp,"GetRange", GetCellName(row,0), GetCellName(row,colCount-1) ).toDispatch();
Dispatch range = Dispatch.invoke(sheet, "Range", Dispatch.Get,
new Object[] { getCellName(row,0), getCellName(row,colCount-1) },
new int[1]).toDispatch();
bRet = Dispatch.call(range, "Delete", new Variant( (long)-4162 )).toBoolean();
}
catch(Exception ex) { }
if( bRet )
{
rowCount--;
if( curRow >= rowCount )
curRow = rowCount-1;
}
return bRet;
}
public void deleteRow()
{
deleteIndexRow(curRow);
}
public void saveChanges()
{
postRow();
}
/*
public boolean isChanged()
{
return false;
}
public boolean find(int findType,String filter)
{
return false;
}
public boolean find(String filter)
{
return false;
}
public boolean findNext(String filter)
{
return false;
}
public boolean seek(String comparision,Object keys[])
{
return false;
}
public void setCurrentIndex(String indexName)
{
}
*/
public boolean gotoFirst()
{
curRow = 0;
return rowCount > 0;
}
public boolean gotoLast()
{
curRow = rowCount-1;
return rowCount > 0;
}
public boolean gotoNext()
{
if( curRow < rowCount-1 )
{
curRow++;
return true;
}
return false;
}
public boolean gotoPrev()
{
if( curRow > 0 )
{
curRow--;
return true;
}
return false;
}
public void edit()
{
}
public void update()
{
postRow();
}
void innerGetRowColCount()
{
rowCount = colCount = 0;
if( !m_bValidate ) return;
Dispatch range = Dispatch.get(excelApp, "ActiveCell").toDispatch();
range = Dispatch.call(range, "SpecialCells", new Variant(11)).toDispatch();
Dispatch.call(range,"Select");
rowCount = Dispatch.get(range, "Row").toInt() - 1;
colCount = Dispatch.get(range, "Column").toInt();
}
String innerGetColumnName(int col)
{
Object o = getCellValue(-1,col);
return ( o == null ) ? "" : o.toString();
}
public Object getCellValue(int row, int col)
{
Object value = null;
if( m_bValidate && row >= -1 && col >= 0 && row < rowCount && col < colCount )
{
try
{
if( bPreparedFectch && sa != null )
value = sa.getVariant(row+2,col+1);
else
{
String cellName = getCellName(row,col);
Object a1 = Dispatch.invoke(sheet, "Range", Dispatch.Get,
new Object[] {cellName},
new int[1]).toDispatch();
value = Dispatch.get(a1, "Value");
}
}
catch(Exception ex){ ex.printStackTrace(); }
}
Variant vTemp =(Variant)value;
if (vTemp.isNull())
value=null;
return value;
}
public boolean setCellValue(int row, int col,Object val)
{
if( !m_bValidate || m_bReadOnly )
return false;
if( row >= -1 && col >= 0 )
{
try
{
String cellName = getCellName(row,col);
Object a1 = Dispatch.invoke(sheet, "Range", Dispatch.Get,
new Object[] {cellName},
new int[1]).toDispatch();
String text;
if( val == null )
text = "";
else if( val instanceof java.util.Date )
text = snsoft.util.Utilities.dateToString((java.util.Date)val);
else
text = val.toString();
Dispatch.put( a1, "FormulaR1C1", text); // Dispatch.put( a1, "Value", text);
return true;
}
catch(Exception ex) {}
}
return false;
}
public void setValue(int columnIndex,Object value)
{
setCellValue(curRow, columnIndex, value);
}
public void setValue(String colName,Object value)
{
setCellValue(curRow, nameToIndex(colName), value);
}
public static boolean newExcelSheet(String szFileName, String szSheetName)
{
boolean bFileExist = false;
try
{
File file = new File(szFileName);
bFileExist = file.isFile();
}
catch(Exception ex) { }
MSExcelApp excel = new MSExcelApp();
if( excel.openExcel(szFileName,szSheetName,true,bFileExist,true) )
{
try { excel.update(); return true; } catch(Exception ex) { return false; }
}
else
return false;
}
public static boolean isSheetExist(String szFileName, String szSheetName)
{
MSExcelApp excel = new MSExcelApp();
boolean bRet = excel.openExcel(szFileName,szSheetName,false);
excel.close();
return bRet;
}
public static boolean deleteSheet(String szFileName, String szSheetName)
{
MSExcelApp excel = new MSExcelApp();
if( excel.openExcel(szFileName,szSheetName, true) && excel.deleteSheet(szSheetName) )
{
try { excel.postRow(); return true; } catch(Exception ex) { return false; }
}
else
return false;
}
};
|
|
|
|
|