You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
744 lines
22 KiB
744 lines
22 KiB
#define DEBUG //ДЕРЕКТИВЫ ПРЕПРОЦЕССОРА |
|
#define TESTING |
|
using System; |
|
using System.IO; |
|
using System.Text; |
|
using System.ComponentModel; |
|
using System.Collections.Generic; |
|
using System.Runtime.CompilerServices; |
|
using static System.Console; |
|
|
|
namespace test_4th_chapter_ |
|
{ |
|
using System.Dynamic; |
|
using RandomNamespace; |
|
class Program |
|
{ |
|
static void Main(string[] args) |
|
{ |
|
string nullstr = null; //норм ТИПЫ ДОПУСКАЮЩИЕ NULL |
|
//int n = null; - ошибка |
|
int? intnll = null; //норм |
|
WriteLine("{0}\t{1}\t{2}\t{3}", nullstr == null, intnll == null, intnll = 10, intnll = null); |
|
int? ni = null; |
|
int? nni = 5, dopnull = 7; |
|
int inn = 6; |
|
WriteLine("null == 5: {0}, 5? == 6: {1}, null > 4: {2}, 5? > 4: {3}, \n6 + null: {4}, 5? + null: {5}, 5? + 6: {6}\n", |
|
ni == nni, nni == inn, ni > 4, nni > 4, inn + ni, nni + ni, inn + nni); |
|
bool? n = null; |
|
bool? f = false; |
|
bool? t = true; |
|
WriteLine("n | n " + (n | n)); // (null) |
|
WriteLine("n | f " + (n | f)); // (null) |
|
WriteLine("n | t " + (n | t)); // True |
|
WriteLine("n & n " + (n & n)); // (null) |
|
WriteLine("n & f " + (n & f)); // False |
|
WriteLine("n & t " + (n & t)); // (null) |
|
|
|
WriteLine("5 ?? null: {0}, null ?? 7 ?? 6: {1}", ni ?? nni, ni ?? dopnull ?? nni); |
|
StringBuilder sb = null; |
|
int length = sb?.ToString().Length ?? 0; //ЕСЛИ SB = NULL, ТО LENGTH = 0 |
|
WriteLine(length); |
|
Otstup(); |
|
|
|
|
|
|
|
// Transformer t = new Transformer(Square); - Идентично со следующей строкой |
|
Transformer trns = Square; //ПРИСВОЕНИЕ ДЕЛЕГАТУ МЕТОДА |
|
trns += Sqrt; //СОЗДАНИЕ ГРУППОВОГО ДЕЛЕАТА |
|
trns -= Sqrt; |
|
TransformerR r = Square2; |
|
r += Square2; |
|
//t += Square; |
|
int x = 3; |
|
// t(3) == t.Invoke(3) -идентичные методы вызова метода square |
|
WriteLine("{0} {1} {2} {3}", trns(x), x, r(ref x), x); |
|
|
|
int[] values = { 1, 2, 3, 4 }; |
|
Util.Transform(values, Square); |
|
foreach (int i in values) |
|
Write("{0} ", i); |
|
Otstup(); |
|
|
|
string[] strings = { "aa", "bb", "cc" }; |
|
Util.Transform(strings, Dobavka); |
|
|
|
for (int i = 0; i < strings.Length; i++) |
|
Write("{0} ", strings[i]); |
|
WriteLine(); |
|
|
|
foreach (string s in strings) |
|
Write("{0} ", s); |
|
Otstup(); |
|
|
|
|
|
ProgressReporter p = Progress; |
|
p += Progress2; |
|
Util.HardWork(p); |
|
Otstup(); |
|
|
|
Check tr = Check; |
|
WriteLine("{0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10}", |
|
tr(-2), tr(-1), tr(0), tr(1), tr(2), tr(3), tr(4), tr(5), tr(6), tr(8), tr(16)); |
|
Otstup(); |
|
|
|
ObjectD objectD = Stringa; |
|
objectD += Square; |
|
object obj = objectD(); |
|
Write(obj + "\t"); |
|
objectD -= Square; |
|
Write(obj = objectD()); |
|
Otstup(); |
|
|
|
|
|
var stock = new Stock("STK"); |
|
stock.PChanged += ReportPrice; |
|
stock.Price = 123; |
|
stock.Price = 321; |
|
Otstup(); |
|
|
|
|
|
var s2tock = new Stock2("STK2"); |
|
s2tock.PChanged += PriceChn; |
|
s2tock.Price = 123; |
|
s2tock.Price = 125; |
|
s2tock.Price = 153; |
|
Otstup(); |
|
|
|
|
|
var s3tock = new Stock3("STK3"); |
|
s3tock.ChangedPrice += Price3Stock; |
|
s3tock.Price = 123; |
|
s3tock.Price = 321; |
|
Otstup(); |
|
|
|
|
|
var testo = new Testo(); |
|
testo.X = 20; |
|
testo.X = 30; |
|
testo.X = 20; |
|
testo.X = 50; |
|
Otstup(); |
|
|
|
|
|
Transformer lambda = z => z * z; //ЛЯМБДА ВЫРАЖЕНИЕ |
|
WriteLine(lambda(3)); |
|
|
|
Func<int, int> funcLambda = fla => { return fla * fla; }; |
|
WriteLine(funcLambda(3)); |
|
|
|
Func<string, string, int> totalLambda = (s1, s2) => s1.Length + s2.Length; |
|
WriteLine(totalLambda("hellp", "world")); |
|
|
|
Transformer lambdaV = z => z * lambda(10); |
|
WriteLine(lambdaV(5)); |
|
|
|
int buf = 2; |
|
Func<int, int, int> incr = (f1, f2) => buf = f1 * f2; |
|
WriteLine("{0} {1} {2}", buf, incr(20, 5), buf); |
|
|
|
int seed = 0; |
|
Func<int> nat = () => ++seed; |
|
WriteLine("{0} {1} {2}", nat(), nat(), seed); |
|
Otstup(); |
|
|
|
|
|
Action[] actions = new Action[3]; |
|
Action[] actions2 = new Action[3]; |
|
for (int i = 0; i < actions.Length; i++) |
|
{ |
|
int te = i; |
|
actions2[i] = () => Write(te); |
|
actions[i] = () => Write(i); |
|
} |
|
foreach (Action a in actions) a(); |
|
WriteLine(); |
|
foreach (Action a in actions2) a(); |
|
Otstup(); |
|
|
|
|
|
|
|
Transformer anon = delegate (int an) { return an * an; }; //АНОНИМНЫЙ МЕТОД |
|
WriteLine(anon(3)); |
|
Otstup(); |
|
|
|
|
|
try |
|
{ |
|
int zero = 0; |
|
x = 10 / zero; |
|
WriteLine("sdsd"); |
|
int inta = int.MaxValue; |
|
int inta2 = inta++; |
|
} |
|
catch (DivideByZeroException ex) |
|
{ |
|
// throw new Exception("asdasd", ex); Повторная генерация исключения с определённым сообщением |
|
WriteLine("Деление на 0"); |
|
ex.ToString(); |
|
} |
|
catch (OverflowException) |
|
{ |
|
WriteLine("Переполнение"); |
|
} |
|
catch |
|
{ |
|
WriteLine("Общее исключение"); |
|
} |
|
finally |
|
{ |
|
WriteLine("Завершено"); |
|
} |
|
Otstup(); |
|
|
|
|
|
using (FileStream fs = File.Create("text.txt")) |
|
{ |
|
byte[] vs = new UTF8Encoding(true).GetBytes("This is amarica\nama\nri"); |
|
fs.Write(vs, 0, vs.Length); |
|
} |
|
|
|
using (StreamReader sr = File.OpenText("text.txt")) |
|
{ |
|
string s = string.Empty; |
|
while ((s = sr.ReadLine()) != null) |
|
WriteLine(s); |
|
} |
|
Otstup(); |
|
|
|
|
|
foreach (int fib in Fibs(6)) //ИТЕРАТОР |
|
Write("{0}\t", fib); |
|
WriteLine(); |
|
|
|
foreach (string str in Foo(false)) |
|
Write("{0}\t", str); |
|
WriteLine(); |
|
|
|
foreach (string str in Foo(true)) |
|
Write("{0}\t", str); |
|
WriteLine(); |
|
|
|
foreach (int fib in EvenFib(Fibs(20))) |
|
Write("{0}\t", fib); |
|
Otstup(); |
|
|
|
|
|
Note B = new Note(2); |
|
Note A = new Note(2); |
|
A += 2; //ПЕРЕОПРЕДЕЛЁННЫЙ ОПЕРАТОР + |
|
WriteLine(A.value); |
|
Otstup(); |
|
|
|
WriteLine("Pdbas".IsCapitalized()); //РАСШИРЯЮЩИЙ МЕТОД |
|
WriteLine("Pdbas".IsCapitalizedR()); //РАСШИРЯЮЩИЙ МЕДО ИЗ ДРУГОГО ПРОСТРАНСТВА ИМЁН |
|
Otstup(); |
|
|
|
|
|
|
|
var dude = new { Name = "Bob", Age = 23 }; //АНОНИМНЫЙ ТИП |
|
int Age = 23; |
|
var dude2 = new { Name = "Carl", Age, Age.ToString().Length }; |
|
|
|
var dudes = new[] |
|
{ |
|
new {Name = "First", Age = 30}, |
|
new {Name = "Second", Age = 40} |
|
}; |
|
WriteLine(dudes[0].Name); |
|
Otstup(); |
|
|
|
|
|
dynamic d = new Duck(); //ДИНАМИЧНОЕ СВЯЗЫВАНИЕ (СПЕЦИАЛЬНОЕ ЧЕРЕЗ IDMOP) |
|
d.Quack(); |
|
d.Waddle(); |
|
d.Duak(); |
|
WriteLine(Mean(5, 9.5)); //ЯЗЫКОВОЕ СВЯЗЫВАНИЕ |
|
Otstup(); |
|
|
|
dynamic Dynamic = "hello"; |
|
WriteLine(Dynamic.GetType()); |
|
Dynamic = 123; |
|
WriteLine(Dynamic.GetType()); |
|
Otstup(); |
|
|
|
|
|
Paft(); //АТРИБУТЫ информации о вызывающем объекте |
|
AtrChange atrChange = new AtrChange(); |
|
atrChange.CustomerName = "First"; |
|
atrChange.CustomerName = "Second"; |
|
Otstup(); |
|
|
|
|
|
|
|
int[,] bitmap = { { 0x101010, 0x808080, 0xFFFFFF }, { 0x101010, 0x808080, 0xFFFFFF } }; |
|
for (int i = 0; i < 2; i++) |
|
{ |
|
for (int j = 0; j < 3; j++) |
|
Write(bitmap[i, j] + " "); |
|
WriteLine(); |
|
} |
|
WriteLine(); |
|
BlueFilter(bitmap); |
|
for (int i = 0; i < 2; i++) |
|
{ |
|
for (int j = 0; j < 3; j++) |
|
Write(bitmap[i, j] + " "); |
|
WriteLine(); |
|
} |
|
WriteLine(); |
|
WriteLine(int.MaxValue + "\n" + 0x7FFFFFFF); |
|
new UnsafeClass("sfsd sfasdf"); |
|
Otstup(); |
|
|
|
MyClass mc = new MyClass(5); |
|
mc.Foo(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Otstup(3); |
|
int[] array = { 1, 6, 4, 0, 2 }; |
|
quicksort(array, 0, 4); |
|
|
|
foreach (int i in array) |
|
Write("{0} ", i); |
|
ReadKey(); |
|
} |
|
|
|
static int Square(int x) => x *= x; |
|
static object Square() => 10; |
|
static int Sqrt(int x) => (int)Math.Sqrt(x); |
|
static int Square2(ref int x) => x *= x; |
|
static bool Check(int x) => (x & (x - 1)) == 0; |
|
static string Dobavka(string str) => str + "123"; |
|
static string Stringa() => "hello"; |
|
static void Otstup() { WriteLine("\n"); } |
|
static void Otstup(int x) |
|
{ |
|
for (int i = 0; i <= x; i++) WriteLine(); |
|
} |
|
|
|
public class Util |
|
{ |
|
// public static void Transform(int[] values, Transformer t) |
|
public static void Transform<T>(T[] values, Func<T, T> t) |
|
{ |
|
for (int i = 0; i < values.Length; i++) |
|
values[i] = t(values[i]); |
|
} |
|
|
|
public static void HardWork(ProgressReporter p) |
|
{ |
|
for (int i = 0; i <= 10; i++) |
|
{ |
|
p(i * 10); |
|
System.Threading.Thread.Sleep(10); |
|
} |
|
} |
|
} |
|
|
|
public class Stock |
|
{ |
|
decimal price; |
|
string symbol; |
|
public Stock(string symbol) { this.symbol = symbol; } |
|
public event PriceChangedH PChanged; |
|
public decimal Price |
|
{ |
|
get { return price; } |
|
set |
|
{ |
|
if (price == value) return; // Exit if nothing has changed |
|
decimal oldPrice = price; |
|
price = value; |
|
if (PChanged != null) // If invocation list not empty, |
|
PChanged(oldPrice, price); // fire event. |
|
} |
|
} |
|
} |
|
|
|
public class Stock2 |
|
{ |
|
decimal price; |
|
string symbol; |
|
public Stock2(string symbol) { this.symbol = symbol; } |
|
public event EventHandler<PriceCEventArgs> PChanged; |
|
protected virtual void OnPChanged(PriceCEventArgs e) |
|
{ |
|
PChanged?.Invoke(this, e); |
|
} |
|
public decimal Price |
|
{ |
|
get { return price; } |
|
set |
|
{ |
|
if (price == value) return; // Exit if nothing has changed |
|
decimal oldPrice = price; |
|
price = value; |
|
OnPChanged(new PriceCEventArgs(oldPrice, price)); |
|
} |
|
} |
|
} |
|
static void ReportPrice(decimal oldPrice, decimal newPrice) => WriteLine("Price changed from " + oldPrice + " to " + newPrice); |
|
|
|
public class PriceCEventArgs : EventArgs |
|
{ |
|
public readonly decimal LastPrice; |
|
public readonly decimal NewPrice; |
|
public PriceCEventArgs(decimal lPr, decimal nPr) |
|
{ |
|
LastPrice = lPr; |
|
NewPrice = nPr; |
|
} |
|
} |
|
|
|
static void PriceChn(object source, PriceCEventArgs e) |
|
{ |
|
if (e.LastPrice != 0) |
|
{ |
|
if ((e.NewPrice - e.LastPrice) / e.LastPrice > 0.1M) WriteLine("Увеличение цены более чем на 10%"); |
|
else ReportPrice(e.LastPrice, e.NewPrice); |
|
} |
|
else ReportPrice(e.LastPrice, e.NewPrice); |
|
} |
|
|
|
public class Stock3 |
|
{ |
|
string str; |
|
decimal price; |
|
public Stock3(string str) { this.str = str; } |
|
public event EventHandler ChangedPrice; |
|
protected virtual void OnChangedPrice(EventArgs e) |
|
{ |
|
ChangedPrice?.Invoke(this, e); |
|
} |
|
public decimal Price |
|
{ |
|
get { return price; } |
|
set |
|
{ |
|
if (price == value) return; |
|
price = value; |
|
OnChangedPrice(EventArgs.Empty); |
|
} |
|
} |
|
} |
|
|
|
static void Price3Stock(object sender, EventArgs args) |
|
{ |
|
WriteLine("Новая цена " + ((Stock3)sender).Price); |
|
} |
|
|
|
public class Testo |
|
{ |
|
int x; |
|
public int X |
|
{ |
|
get { return x; } |
|
set |
|
{ |
|
if (x == value) return; |
|
if (x > value) |
|
{ |
|
int temp = x; |
|
x = value; |
|
WriteLine("X уменьшился с {0} до {1}", temp, x); |
|
} |
|
if (x < value) |
|
{ |
|
int temp = x; |
|
x = value; |
|
WriteLine("X увеличился с {0} до {1}", temp, x); |
|
} |
|
} |
|
} |
|
} |
|
|
|
static void Progress(int percentComplete) => Write(percentComplete); |
|
static void Progress2(int percentComplete) => WriteLine(" выполнено"); |
|
|
|
static IEnumerable<int> Fibs(int fibCount) //ПЕРЕЧИСЛИТЕЛЬ |
|
{ |
|
for (int i = 0, prev = 1, cur = 1; i < fibCount; i++) |
|
{ |
|
yield return prev; |
|
int nfib = prev + cur; |
|
prev = cur; |
|
cur = nfib; |
|
} |
|
} |
|
|
|
static IEnumerable<string> Foo(bool st) |
|
{ |
|
yield return "one"; |
|
yield return "two"; |
|
if (st) |
|
yield break; |
|
yield return "three"; |
|
} |
|
|
|
static IEnumerable<int> EvenFib(IEnumerable<int> fb) |
|
{ |
|
foreach (int x in fb) |
|
if ((x % 2) == 0) |
|
yield return x; |
|
} |
|
|
|
public struct Note //ПЕРЕГРУЗКА ОПЕРАТОРА + В СТРУКТУРЕ |
|
{ |
|
public int value; |
|
public Note(int sem) { value = sem; } |
|
public static Note operator +(Note x, int tone) => new Note(x.value + tone); |
|
} |
|
|
|
|
|
public class Duck : DynamicObject //СПЕЦИАЛЬНОЕ ДИНАМИЧЕСКОЕ СВЯЗЫВАНИЕ ЧЕРЕЗ IDMOP |
|
{ |
|
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) |
|
{ |
|
if (binder.Name == "Duak") |
|
{ |
|
WriteLine("Quak Quak"); |
|
result = null; |
|
return true; |
|
} |
|
WriteLine(binder.Name + " method"); |
|
result = null; |
|
return true; |
|
} |
|
} |
|
|
|
static dynamic Mean(dynamic x, dynamic y) => x * y / 2; //ЯЗЫКОВОЕ СВЯЗЫВАНИЕ |
|
|
|
static void Paft( |
|
[CallerMemberName] string memberName = null, //АТРИБУТ ИМЯ ВЫЗЫВАЮЩЕГО КОМПОНЕНТА (main) |
|
[CallerFilePath] string filePath = null, //АТРИБУТ ПУТИ ФАЙЛА |
|
[CallerLineNumber] int lineNumber = 0) //АТРИБУТ НОМЕРА СТРОКИ ВЫЗВАВШЕЙ ФУНКЦИИ |
|
{ |
|
WriteLine(memberName); |
|
WriteLine(filePath); |
|
WriteLine(lineNumber); |
|
} |
|
|
|
public class AtrChange : INotifyPropertyChanged |
|
{ |
|
public event PropertyChangedEventHandler PropertyChanged = delegate { }; |
|
void RaisePropertyChanged([CallerMemberName] string propertyName = null) |
|
{ |
|
PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); |
|
} |
|
string customerName; |
|
public string CustomerName |
|
{ |
|
get { return customerName; } |
|
set |
|
{ |
|
if (value == customerName) return; |
|
customerName = value; |
|
RaisePropertyChanged(); |
|
} |
|
} |
|
} |
|
|
|
|
|
unsafe static void BlueFilter(int[,] bitmap) //НЕБЕЗОПАСНЫЙ КОД И УКАЗАТЕЛИ |
|
{ |
|
int length = bitmap.Length; |
|
fixed (int* b = bitmap) |
|
{ |
|
int* p = b; |
|
for (int i = 0; i < length; i++) |
|
*p++ &= 0xFF; |
|
} |
|
} |
|
|
|
unsafe struct UnsafeUnicodeString |
|
{ |
|
public short Length; |
|
public fixed byte Buffer[30]; |
|
} |
|
|
|
unsafe class UnsafeClass |
|
{ |
|
UnsafeUnicodeString uus; |
|
public UnsafeClass(string s) |
|
{ |
|
uus.Length = (short)s.Length; |
|
fixed (byte* p = uus.Buffer) |
|
for (int i = 0; i < s.Length; i++) |
|
p[i] = (byte)s[i]; |
|
} |
|
} |
|
|
|
unsafe static void Zap(void* memory, int byteCount) |
|
{ |
|
byte* b = (byte*)memory; |
|
for (int i = 0; i < byteCount; i++) |
|
*b++ = 0; |
|
} |
|
|
|
public class MyClass |
|
{ |
|
int x; |
|
public MyClass(int f) => x = f; |
|
public void Foo() |
|
{ |
|
#if DEBUG && TESTING && !SMTHELSE //ДИРЕКТИВЫ ПРЕПРОЦЕССОРА |
|
WriteLine("{0} ???",x); |
|
#endif |
|
|
|
#if DEBUG |
|
WriteLine("DEBUG"); |
|
#endif |
|
} |
|
} |
|
|
|
|
|
public class MyClass2 |
|
{ |
|
int x; |
|
public MyClass2(int f) => x = f; |
|
|
|
//XML документакция |
|
|
|
/// <summary> |
|
/// Запрашивает переменную |
|
/// </summary> |
|
|
|
public void Foo() |
|
{ |
|
WriteLine("{0} ???", x); |
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int partition<T>(T[] m, int a, int b) where T : IComparable<T> |
|
{ |
|
int i = a; |
|
for (int j = a; j <= b; j++) // просматриваем с a по b |
|
{ |
|
if (m[j].CompareTo(m[b]) <= 0) // если элемент m[j] не превосходит m[b], |
|
{ |
|
T t = m[i]; // меняем местами m[j] и m[a], m[a+1], m[a+2] и так далее... |
|
m[i] = m[j]; // то есть переносим элементы меньшие m[b] в начало, |
|
m[j] = t; // а затем и сам m[b] «сверху» |
|
i++; // таким образом последний обмен: m[b] и m[i], после чего i++ |
|
} |
|
} |
|
return i - 1; // в индексе i хранится <новая позиция элемента m[b]> + 1 |
|
} |
|
|
|
static void quicksort<T>(T[] m, int a, int b) where T : IComparable<T>// a - начало подмножества, b - конец |
|
{ // для первого вызова: a = 0, b = <элементов в массиве> - 1 |
|
if (a >= b) return; |
|
int c = partition(m, a, b); |
|
quicksort(m, a, c - 1); |
|
quicksort(m, c + 1, b); |
|
} |
|
|
|
} |
|
|
|
public static class StringHelper //РАСШИРЯЮЩИЙ МЕТОД |
|
{ |
|
public static bool IsCapitalized(this string s) |
|
{ |
|
if (string.IsNullOrEmpty(s)) return false; |
|
return char.IsUpper(s[0]); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
delegate int Transformer(int x); //ДЕЛЕГАТ |
|
delegate int Transformer2(int x, int y); |
|
delegate bool Check(int x); |
|
delegate void ProgressReporter(int percentComplete); |
|
delegate T Transformer<T>(T arg); |
|
delegate int TransformerR(ref int x); |
|
delegate object ObjectD(); |
|
delegate void PriceChangedH(decimal oldPrice, decimal newPrice); |
|
delegate void EventHandler<TEventArgs>(object source, TEventArgs e) where TEventArgs : EventArgs; |
|
|
|
delegate TResult Func<out TResult>(); //ДЕЛЕГАТЫ FUNC И ACTION (могут принимать до 16 аргументов) |
|
delegate TResult Func<in T, out TResult>(T arg); |
|
delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2); |
|
|
|
delegate void Action(); |
|
delegate void Action<in T>(T arg); |
|
delegate void Action<in T1, in T2>(T1 arg1, T2 arg2); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
namespace RandomNamespace |
|
{ |
|
public static class StringHelper //РАСШИРЯЮЩИЙ МЕТОД |
|
{ |
|
public static bool IsCapitalizedR(this string s) |
|
{ |
|
if (string.IsNullOrEmpty(s)) return false; |
|
return char.IsUpper(s[0]); |
|
} |
|
} |
|
}
|
|
|