.NET 4.0 FAQ 第一部分—DLR

简介

本篇文章中我们将讨论.NET FrameWork 4.0提供了哪些新特性。然后再探讨DLR特性 中的动态对象和Expando对象。我们也将会创建一个Exp
ando对象来看我们可以从中获得哪些益处。很多的开发人员误以为动态对象是用来替代反射和object类型的,我们也将会纠正这种错误的概念。

.NET 4.0中有哪些重要的新特性?

与其去浏览.NET 4.0冗长的新特性列表,我们还是专注于我们认为最重要的三项新特性上吧。

• WF和WCF 4.0:这是.NET

阅读全文 »

昨天遇到了一个 Bug ,如果在浏览器中打开多个标签,并把其中一个标签拖拽到主窗口的一侧来划分出独立的一个区域,然后在新区域中通过点击加号键添加的新标签内不会被添加上 WebBrowser 。

说得好绕嘴啊,截张图吧:

而且没有加上 WebBrowser 的标签的标题是 new content (我们在 AvalonDock 中给新标签的默认标题)而不是 New Tab (客户代码中重新赋的值)。

OK ,问题明了了,是不是新添加的标签的 Got_Focus 没能够挂到客户代码中的方法上去呢?

的确是这样,当我们把一个标签( DocumentContent )拖拽到一侧从而划分出一个新区域的时候, AvalonDock 会创建一个新的 DocumentPane 来代表这个新区域。

阅读全文 »

闲话少叙,书接上文。

现在我们已经通过 ReStyle 给 DocumentPane 加上了一个加号的按钮,并且可以通过点击该按钮给 DocumentPane 的
Items 添加一个 DocumentContent 了。

不过每个新添加进来的 DocumentContent 内部都是空的,而我们需要的是每个新标签中都有一个 WebBrowser
,要实现这一点很简单,只要给 DocumentContent 的 Content ( DocumentContent 是
ContentControl 的子类)属性赋值为一个 WebBrowser 的实例就 OK 了。

但是这不应该是 AvalonDock 的默认行为,所以我们要把这部分写到客户端 – 也就是引用 AvalonDock.dll
文件或者直接引用 AvalonDock 工程的 Solution 中去。

如何可以在客户端得知有一个新的 DocumentContent 被添加进 DocumentPane 中去了呢?自然是用事件了。

首先来写一个自定义的 EventArgs 吧:

阅读全文 »

AvalonDock 是 CodePlex 上的一个开源项目,利用它可以很容易的做出类似于 VS 的 UI 效果。

下图是 AvalonDock 源码中自带的一个 Demo :

我们可以用这款第三方控件为基础来制作多标签浏览器。

下面是最终效果图:

甚至可以把其中一个标签拖出主窗体成为一个独立的窗口:

阅读全文 »

Words Via Subtitle 改进:视频播放例句、加快生成 WPS 文档的速度

关于 Words Via Subtitle 的介绍:

1
http://blog.csdn.net/cuipengfei1/archive/2009/09/03/4516588.aspx

2
http://blog.csdn.net/cuipengfei1/archive/2009/09/10/4539180.aspx

最近给这个小程序添加了视频播放例句的功能,使用方法如下:

载入字幕文件并指定了与之对应的视频文件之后,选中某个感觉生疏的单词,然后点击播放例句按钮,该单词所在句子就会以视频的方式开始播放,播完该句子视频暂停。其实这
个功能写起来也挺简单的,就是在字幕中找到一个单词所在句子对应的时间信息,然后依照该时间段播放视频。

阅读全文 »

上周写了一个
通过英文剧集、电影学单词的小工具
,这几天又做了一点小的改进。主要是下面这两点:

  1. 显示单词解释的同时显示其在剧中出现的语境,关键单词红色显示。效果如下:

  1. 导出文档。可以把列表中的单词,其简明解释和在剧中出现的语境保存到文档中。关键词开头绿色显示,例句中红色显示。效果如下:

为什么要写这个功能呢?因为九月中下旬有很多美剧要回归,包括 TBBT , Lie to me , Heroes , Fringe 。到时候每
一集出来之后可以用这个程序迅速的把一集中出现的生词,其音标及解释还有语境总结出来。可以把它发到博客里,或者发到美剧对应的社区或者贴吧里去,会比一般的影迷手工
总结的快很多。

阅读全文 »

我平时很喜欢看美剧和电影。而如果看中文字幕(看英文字幕也是一样)的话,注意力就会集中于阅读文字、理解剧情,练习听力的目的就落空了。而如果不看字幕的话,对话中
的很多生词就会随着对句子的大致理解而溜过去了,所以最好的办法就是看之前把对白中会出现的单词预览一次以为预习,看的过程中再熟悉一次,看完之后还可以针对用得到的
单词再记一次。为了实现这个目的,我写了一个小程序。

使用方式如下:

运行 WordsViaSubtitle.exe

可以通过程序中的搜索框搜索字幕文件(是射手网提供的,赞美射手 O(∩_∩)O哈!!)

阅读全文 »

前几天发的程序只可以用于easyMule1.X版本,今天改写了一下,可以适用于2.0

使用方法:

运行 EasyMulePowerOff.exe

会提示您设置电驴的安装路径,设置好之后会检查到有没有未完成的任务:

显示我有一个未完的任务,看一下电驴中

阅读全文 »

由于电驴官方鼓励尽量多的上传,所以不提供下载完关机的功能。于是我自己写了个小工具来实现这个功能。

使用方法:

运行 EasyMulePowerOff.exe

会提示您设置电驴的安装路径,设置好之后会检查到有没有未完成的任务:

阅读全文 »

近日闻悉国内某出版社即将出版《 Head First C# 》的中文版,为避免版权纠纷,本“山寨”系列将停止翻译和更新。

从去年 10 月开始利用课余时间翻译这本书,到现在翻译完了将近 13 章,总计 12 万余字。

剩余的正文内容已不足百页,无法做到有始有终,颇为遗憾。

感谢 CSDN 和 VeryCD 各位朋友一直以来的关注、支持、鼓励和批评。

2009 年 8 月 7 日

阅读全文 »

欲验证的结论: 接口引用指向装箱后的值类型时无需拆箱 。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
interface SomeInterface

{
void MethodInInterface();
}

struct OneValueType : SomeInterface

{
public void MethodInInterface()

{
Console.WriteLine("get called");
}
}

class TestUnBox

{
public static void Main()

{
}

private static void CastStruct()

{
OneValueType ovt = new OneValueType();

object o = ovt; //Box

((OneValueType) o).MethodInInterface();
}

private static void CastInterface()

{
OneValueType ovt = new OneValueType();

object o = ovt; //Box

((SomeInterface) o).MethodInInterface();
}
}

其中 OneValueType 是值类型,它实现了 SomeInterface 。

两个方法 CastStruct 和 CastInterface 分别把装箱之后的值类型转型为 OneValueType 和
SomeInterface 。预计的结果是第二个方法无需拆箱,查看 IL 来验证:

这是 CastStruct ():

阅读全文 »

原地址在我的CSDN
Blog:http://blog.csdn.net/cuipengfei1/archive/2009/07/19/4362245.aspx

① Object 的静态方法 ReferenceEquals :

只适用于判断两个引用是否指向同一个实例,不适用于值类型(或者说用于值类型是没意义的,因为永远返回 false )。如下:

1
2
3
4
5
TestEqual  te =  new  TestEqual  ();

bool b1= object .ReferenceEquals(te,te);

bool b2 = object .ReferenceEquals(1, 1);

b1 为 true , b2 为 false 。 b2 为 false 的原因是两个整型值 1 装箱之后是两个不同的
Object 实例。

② Object 中定义的实例级虚方法 Equals :

阅读全文 »

as 看起来很好用的样子,不会抛出异常,只要根据返回值是否为 null来做不同的处理就可以了。但是它也不是万金油,以下的情况 as 就不适用:

①值类型

比如:

1
2
3
double  d = 100.0;

int valueType = d as int ;

这两句代码就直接通不过编译,给出的原因是: as 运算符必须用于引用类型或可以为 null类型 (“int” 是一种不可以为 null
值的类型 )

想一下也合理, as 在失败时会返回 null,而值类型是不可以为 null的( INullable 除外)。

阅读全文 »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Collections;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string str = "aaeaabbebbccececddeddd";

List<char> charList = new List<char>(str.ToCharArray());
int len = charList.Count;

Dictionary<char, int> charD = new Dictionary<char, int>();

int lastTime = 0;

while (charList.Count != 0)
{
int count = CountAChar(charList);

if (count > lastTime)
{
charD.Clear();
charD.Add(charList[0], count);
lastTime = count;
}

else if (count == lastTime)
{
charD.Add(charList[0], count);
lastTime = count;
}

DeleteAChar(count, charList);
}

foreach (KeyValuePair<char, int> kv in charD)
{
Console.WriteLine("{1}有{0}个", kv.Value.ToString(), kv.Key.ToString());
}

Console.WriteLine("----------------------------------------");
SecondProgram.SecondWay(str);
Console.WriteLine("----------------------------------------");
ThirdClass.ThirdWay(str);
Console.Read();
}

static void DeleteAChar(int num, List<char> cl)
{
char c = cl[0];

for (int i = 0; i < num; i++)
{
cl.Remove(c);
}
}

static int CountAChar(List<char> cl)
{
int ret = 0;

foreach (char c in cl)
{
if (c == cl[0])
{
ret++;
}
}

return ret;
}
}

//-----------------------------------------------------------------
class SecondProgram
{
public static void SecondWay(string str)
{
int len = str.Length;
char[] strArray = str.ToCharArray();
int[] count = new int[len];
for (int y = 0; y < len; y++) //将count数组的每个单元初始为0
count[y] = 0;

for (int y = 0; y < len; y++) //将当前字符与之后的字符进行比较,相同count数组中对应索引处++
{
for (int yy = y; yy < len; yy++)
{
if (strArray[y].Equals(strArray[yy]))
{
count[y]++;
}
}
}

ArrayList maxCountArr = new ArrayList();
int maxCount = count[0];

for (int y = 0; y < len; y++) //获得出现次数的最大值
{
if (count[y] > maxCount)
{
maxCount = count[y];
}
}

for (int y = 0; y < len; y++)
//最大值与count数组中的每个数进行比较,相同则出现次数相同,把索引加入到maxCountArr
{
if (count[y] == maxCount)
{
maxCountArr.Add(y);
}
}

for (int y = 0; y < maxCountArr.Count; y++) //输出
{
Console.Write("Str" + (y + 1) + ":" + strArray[(int) maxCountArr[y]] + "/n");
}
}
}

/// <summary>
/// 第三种方式
/// </summary>
class ThirdClass
{
/// <summary>
/// 还是LinQ最简便
/// </summary>
/// <param name="str"></param>
public static void ThirdWay(string str)
{
var resultGroup = from aChar in str.ToCharArray()
group aChar by aChar;

int max = 0;

foreach (var one in resultGroup)
{
if (one.Count() > 0)
{
max = one.Count();
}
}

foreach (var one in resultGroup)
{
if (one.Count() == max)
{
Console.WriteLine("{0}字符出现了{1}次", one.Key, max);
}
}
}
}
}

今天成都血液中心来采血。我去献了300CC的血,今天才知道自己是O型血~~

手里拿着送我的一把天堂伞和《无偿献血证》回寝室。门口大爷(大概60岁)正在择菜,看到我,说:“你们去献血了?好同学!为社会主义献血!”

O(∩_∩)O 年代的烙印啊

刚才在食堂吃完午饭回寝室的路上听广播,大意是:学校组织全校党员、领导、干部,本着实践科学发展观的精神进行了深入的调查研究,仅专题座谈会就召开了192场。终于
得出一个重要结论:就业率对于我们学校是很重要的。

TMD……彻底被雷了一把…

今天公布了CET-SET(口语)的成绩,在去上课的路上用手机查询。得了一个A。

到教室,没过几分钟收到一封邮包。是O‘reilly寄来的笔记本(是真的笔记本,不是laptop……)

封面是这样的

O(∩_∩)O哈哈~

阅读全文 »

刘义军老师留的作业

代码简单,一看就懂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace GDI_DDA
{
public partial class Form1 : Form
{
int pointSize = 22;
int width = Screen.PrimaryScreen.WorkingArea.Width;
int height = Screen.PrimaryScreen.WorkingArea.Height;

public Form1()
{
InitializeComponent();
}

void DrawGrid(Graphics gra)
{
for (int i = 0; i <= Width; i += pointSize)
{
gra.DrawLine(Pens.Black, i, 0, i, height);
}

for (int i = 0; i <= height; i += pointSize)
{
gra.DrawLine(Pens.Black, 0, i, Width, i);
}
}

void MyDrawLine(Graphics gra, float startX, float startY, float endX, float endY)
{
float dx = endX - startX;
float dy = endY - startY;
float delta = dy / dx;
float
y = startY;
for (int x = (int) startX; x <= endX; x++, y += delta)
{
DrawEllipseByCenter(gra, Pens.Red, x * pointSize, y * pointSize, pointSize * 0.5f);
}
}

void DrawEllipseByCenter(Graphics g, Pen p, float centerX, float centerY, float r)
{
g.FillEllipse(Brushes.Red, centerX - r * 0.5f, centerY - 0.5f, 2 * r, 2 * r);
}

private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics myGra = e.Graphics;
DrawGrid(myGra);
MyDrawLine(myGra, 3, 5, 47, 25);
myGra.DrawLine(Pens.Red, 3 * pointSize, 5 * pointSize, 47 * pointSize, 25 * pointSize);
myGra.Dispose();
}
}
}

昨天读了《Effective C#》的第一个条款“使用属性代替可访问的数据成员”,讲到要把公有字段修改为私有字段,并用公有属性把它封装起来。这一点不难理解,
不过里面提到了一个关于二进制兼容性的问题,很是有趣,今天来验证一下。

验证思路:创建一个类库内有一个public的类,该类内有一个public的字段。另外创建一个WinForm程序去读区该字段并显示。然后修改类库中的字段为属性
。再去运行WinForm,就应该会出错了。出错具体原因请参看《Effective C#》讲解。

开始吧!

创建一个ClassLibrary,叫做TheDLL。代码如下:

1
2
3
4
public class DataHolder
{
public String Data = "Hey! Hey!You!You!";
}

用它生成一个dll。

阅读全文 »

所谓女生版就是指的GUI稍微美化了一点点,我承认是标题党….

注意:需要有.net Framework 2.0才可以运行

.net Framework 2.0下载地址(如果你的电脑没有请在这儿下载):
http://www.gougou.com/search?search=.net%20Framework%202.0&id=0

学分绩点计算器下载地址:
http://download.csdn.net/source/993661
(要有CSDN账号才可以下载)

没有CSDN账号请向 397649079@QQ.com 索取

阅读全文 »

注意:需要有.net Framework 2.0才可以运行

.net Framework 2.0下载地址(如果你的电脑没有请在这儿下载):
http://www.gougou.com/search?search=.net%20Framework%202.0&id=0

学分绩点计算器下载地址:
http://download.csdn.net/source/973619
(要有CSDN账号才可以下载)

运行效果(示例而已):

效果

——————————————分割线下面是类关系图、代码———————-

阅读全文 »

遍历只做了先序,递归实现的,中序和后序都类似.代码比较简单,就不写注释,直接贴出来了

代码:

TreeNode:结点类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
using System.Collections.Generic;
using System.Text;

namespace 二叉树的建立和遍历
{
class TreeNode
{
public char data;
public TreeNode left, right;

public TreeNode(char c, TreeNode l, TreeNode r)
{
data = c;
left = l;
right = r;
}

public TreeNode()
{
left = right = null;
}
}
}

Tree:树类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
using System;
using System.Collections.Generic;
using System.Text;

namespace 二叉树的建立和遍历
{
class Tree
{
public TreeNode root;
Stack<TreeNode> stack = new Stack<TreeNode>();

public void CreateTree(String description)
{
bool left = true;
char[] descriptionarray = description.ToCharArray();
root = new TreeNode();
root.data = descriptionarray[0];
TreeNode temp = root;
for (int i = 1; i <= descriptionarray.Length - 1; i++)
{
if (descriptionarray[i] == '(')
{
left = true;
stack.Push(temp);
}
else if (descriptionarray[i] == ',')
{
left = false;
}
else if (descriptionarray[i] == ')')
{
stack.Pop();
}
else
{
temp = new TreeNode();
temp.data = descriptionarray[i];
if (left == true)
{
stack.Peek().left = temp;
}
else
{
stack.Peek().right = temp;
}
}
}
}

public void PreOrder(TreeNode t, String sign)
{
if (t != null)
{
Console.WriteLine(sign + t.data);
sign += sign;
if (t.left != null)
{
PreOrder(t.left, sign);
}

if (t.right != null)
{
PreOrder(t.right, sign);
}
}
}
}
}
阅读全文 »

题目内容:使用的排队现象,通过仿真手法评估其营业状况。
*基本要求:设某理发馆有N把理发椅,可同时为N位顾客进行理发。
*当顾客进门时,若有空椅,则可以立即坐下理发,否则需要依次排队等候。
*一旦有顾客理完发离去时,排在队头的顾客便可开始理发。
*若理发馆每天连续营业T小时,求一天内顾客在理发馆内的平均逗留时间
*顾客排队等候的队列平均长度

N和T在运行的时候输入

用C#写的,有注释,很混乱,请高人指教~~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace 队列应用
{
class Seat
{
public bool IsFree;
public Customer cus = null;

public Seat(bool b)
{
IsFree = b;
}
}

class Customer
{
public int cometime;
public int timetogo;
public int cost = 30 - new Random().Next(10); //理发需要20~30分钟

public Customer()
{
}
}

class Program
{
static void Main(string[] args)
{
System.Console.WriteLine("每天营业多少小时?");
int workinghours = int.Parse(Console.ReadLine());
System.Console.WriteLine("有多少个椅子?");
int seats = int.Parse(Console.ReadLine());
Process(seats, workinghours);
Console.ReadLine();
}

static void Process(int num, int time)
{
//------------准备变量------------------------
Queue q = new Queue(); //队列
Seat[] S = new Seat[num]; //所有的椅子
for (int i = 0; i < num; i++) //初始化椅子
{
S[i] = new Seat(true);
S[i].cus = null;
}

int somebodycome = 1; //第一个顾客来的时间
//int count = 0;//顾客计数器
List<Customer> cuslist = new List<Customer>();
int st = num; //椅子数
int Qlen = 0; //队列长度
int Qchangetime = 0; //队列长度改变次数
//------------准备变量--------------------------
for (int t = 1; t <= time * 60; t++) //时间从第一分钟开始流逝,每分钟检查状态
{
//--------检查现在有没有人需要离开--------------
CheckLeave(S, t);
//--------检查现在有没有人需要离开--------------
//-------检查排队的人是否可以找到座位---------
CheckSeat(q, S, ref Qlen, ref Qchangetime, t);
//-------检查排队的人是否可以找到座位---------
//-------------如果来人了,有座位就坐下,没座位就排队-------------------
if (t == somebodycome)
{
bool IsSitted = false; //当前刚来的顾客是否找到了座位
Customer c = new Customer();
c.cometime = t;
cuslist.Add(c);
foreach (Seat s in S)
{
if (s.IsFree == true)
{
s.IsFree = false;
s.cus = c;
s.cus.timetogo = t + s.cus.cost;
IsSitted = true;
break;
}
}

if (IsSitted == false)
{
q.Enqueue(c);
Qlen += q.Count;
Qchangetime++;
}
else
{
IsSitted = false;
}

somebodycome += 10 - new Random().Next(5); //下一个顾客来的时间,假设5~10分钟之内会有一个
}

//------如果来人了,有座位就坐下,没座位就排队---------
}

//---------加班----------
bool Inseat = true;
//bool InQ = true;
bool KeepWorking = true;
int curtime = time * 60 + 1;
while (KeepWorking)
{
CheckLeave(S, curtime);
CheckSeat(q, S, ref Qlen, ref Qchangetime, curtime);
foreach (Seat s in S)
{
if (s.IsFree == false)
{
Inseat = true;
break;
}
else
{
Inseat = false;
}
}

KeepWorking = Inseat;
curtime++;
}

//---------加班----------
//--------------
int no = 1;
foreach (Customer c in cuslist)
{
Console.Write("第{0}个顾客  ", no);
Console.Write("来的时间:" + c.cometime);
Console.WriteLine("  走的时间:" + c.timetogo);
no++;
} //------------------

//--------打印结果-------------
int totalstaytime = 0;
foreach (Customer c in cuslist)
{
int staytime = c.timetogo - c.cometime;
totalstaytime += staytime;
}

int averragestay = totalstaytime / cuslist.Count;
System.Console.WriteLine("平均逗留时间:" + averragestay);
System.Console.WriteLine("顾客数量:" + cuslist.Count);
if (Qchangetime != 0)
{
int averagelen = Qlen / Qchangetime;
Console.WriteLine("队列平均长度:" + averagelen);
}
else
{
Console.WriteLine("椅子充足,不用排队");
}

Console.WriteLine("加班时间:" + (curtime - time * 60) + "分钟");
//--------打印结果------------
}

private static void CheckSeat(Queue q, Seat[] S, ref int Qlen, ref int Qchangetime, int t)
{
if (q.Count != 0) //如果有人排队
{
foreach (Seat s in S)
{
if (s.IsFree == true)
{
s.IsFree = false;
s.cus = (Customer) q.Dequeue();
Qlen += q.Count;
Qchangetime++;
s.cus.timetogo = t + s.cus.cost; //
}
}
}
}

private static void CheckLeave(Seat[] S, int t)
{
foreach (Seat s in S)
{
if (s.cus != null)
{
if (s.cus.timetogo == t)
{
s.IsFree = true;
}
}
}
}
}
}