Bỏ qua

Đối tượng biểu đồ và hình vẽ

Đối tượng biểu đồ (hình vẽ) cho phép vẽ đường thẳng hoặc hình học trên biểu đồ cTrader. Bằng cách sử dụng chúng, bạn có thể vẽ các mẫu hoặc hiển thị các sự kiện nhất định trên biểu đồ dựa trên dữ liệu cBot hoặc chỉ báo của bạn.

Đối tượng biểu đồ sử dụng tọa độ X và Y để định vị.

  • Trục X đại diện cho thời gian biểu đồ hoặc chỉ số thanh.
  • Trục Y là giá của ký hiệu.

Tất cả các đối tượng biểu đồ đều được kế thừa từ lớp cơ sở ChartObject, nghĩa là tất cả chúng đều kế thừa một số tính năng cơ bản nhất định.

Mẫu mã đối tượng biểu đồ

Vẽ bên trong cửa sổ chỉ báo

Khi tạo đối tượng biểu đồ, bạn không bị giới hạn trong biểu đồ ký hiệu chính. Trên thực tế, bạn có thể vẽ đối tượng biểu đồ bên trong bất kỳ cửa sổ nào chứa đầu ra của chỉ báo.

Lớp Chart có bộ sưu tập IndicatorAreas. Nó chứa tất cả các cửa sổ không chồng lấp hoặc riêng biệt mà trong đó các chỉ báo có thể hiển thị đầu ra của chúng.

Bạn cũng có thể truy cập khu vực chỉ báo hiện tại của mình bằng cách sử dụng thuộc tính IndicatorArea của lớp Indicator.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = false, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var verticalLine = IndicatorArea.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);
        }

        public override void Calculate(int index)
        {
        }
    }
}

Khi bạn chạy một thực thể của chỉ báo trên, bạn sẽ thấy một đường màu đỏ trong cửa sổ chỉ báo riêng biệt. Khi tạo biểu đồ trong các khu vực chỉ báo riêng biệt, bạn có thể sử dụng tất cả các phương thức vẽ vì cả ChartIndicatorArea đều kế thừa từ lớp cơ sở ChartArea.

Văn bản tĩnh

Thay vì sử dụng tọa độ X và Y để định vị, văn bản tĩnh sử dụng căn chỉnh ngang và dọc tĩnh. Để hiển thị hoặc vẽ văn bản tĩnh, hãy sử dụng phương thức DrawStaticText().

1
var staticText = Chart.DrawStaticText("static", "This is the text that will be shown", VerticalAlignment.Center, HorizontalAlignment.Center, Color.Red);

Nếu bạn gắn đối tượng biểu đồ này vào một chỉ báo và chạy một thực thể, bạn sẽ thấy văn bản sau trong biểu đồ chính.

Image title

Đường dọc

Sử dụng phương thức DrawVerticalLine() để vẽ một đường dọc.

1
2
3
var verticalLine = Chart.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);
// Or
var verticalLine = Chart.DrawVerticalLine("line", Bars.OpenTimes[Chart.LastVisibleBarIndex], Color.Red);

Đường ngang

Sử dụng phương thức DrawHorizontalLine() để vẽ một đường ngang.

1
2
3
/* We use the maximum of the high prices
of the last ten bars as the Y coordinate. */ 
var horizontalLine = Chart.DrawHorizontalLine("line", Bars.HighPrices.Maximum(10), Color.Red);

Đường xu hướng

Đường xu hướng bắt đầu từ một điểm nhất định trên biểu đồ và kết thúc tại một điểm khác. Đường xu hướng rất hữu ích để tạo các hình dạng khác nhau hoặc các mẫu phức tạp.

Để vẽ đường xu hướng, hãy sử dụng phương thức DrawTrendLine().

1
2
3
4
5
6
7
/* We draw a line from the low price
 of the first visible bar to the high price
 of the last visible bar on the chart. */
var trendLine = Chart.DrawTrendLine("line", Chart.FirstVisibleBarIndex, Bars.LowPrices[Chart.FirstVisibleBarIndex], Chart.LastVisibleBarIndex, Bars.HighPrices[Chart.LastVisibleBarIndex], Color.Red);

// Alternatively, consider the following.
var trendLine = Chart.DrawTrendLine("line", Bars.OpenTimes[Chart.FirstVisibleBarIndex], Bars.LowPrices[Chart.FirstVisibleBarIndex], Bars.OpenTimes[Chart.LastVisibleBarIndex], Bars.HighPrices[Chart.LastVisibleBarIndex], Color.Red);

Hình chữ nhật

Sử dụng phương thức DrawRectangle() để vẽ hình chữ nhật.

1
2
3
4
5
6
7
var rectangle = Chart.DrawRectangle("rectangle", Chart.FirstVisibleBarIndex + 1, Bars.LowPrices[Chart.FirstVisibleBarIndex + 1], Chart.LastVisibleBarIndex, Bars.HighPrices[Chart.LastVisibleBarIndex], Color.Red);

/* We fill the rectangle with a transparent color.
By using its current color, we only change the alpha
channel. */
rectangle.IsFilled = true;
rectangle.Color = Color.FromArgb(80, rectangle.Color);

Tam giác

Sử dụng phương thức DrawTriangle() để vẽ tam giác.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var middleX = Chart.FirstVisibleBarIndex + (Chart.LastVisibleBarIndex - Chart.FirstVisibleBarIndex) / 2;
var middleY = Bars.LowPrices[Chart.FirstVisibleBarIndex] + (Bars.HighPrices[Chart.LastVisibleBarIndex] - Bars.LowPrices[Chart.FirstVisibleBarIndex]) / 2;

var triangle = Chart.DrawTriangle("triangle", Chart.FirstVisibleBarIndex, Bars.LowPrices[Chart.FirstVisibleBarIndex], middleX, middleY, Chart.LastVisibleBarIndex, Bars.LowPrices[Chart.FirstVisibleBarIndex], Color.Red);

// We fill the triangle with a transparent color
// by using it's current color, we change only the alpha channel

/* We fill the triangle with a transparent color.
By using its current color, we only change the alpha
channel. */
triangle.IsFilled = true;
triangle.Color = Color.FromArgb(80, triangle.Color);

Các đối tượng biểu đồ khác

Để ngắn gọn, chúng tôi không đề cập đến một số đối tượng biểu đồ khác trong các đoạn mã trên. Các đối tượng này bao gồm nhưng không giới hạn ở những đối tượng sau:

  • Hình elip
  • Biểu tượng
  • Mô hình Andrews pitchfork
  • Kênh cách đều
  • Fibonacci mở rộng
  • Fibonacci quạt
  • Fibonacci thoái lui

Tất cả các đối tượng này có thể được vẽ bằng cách sử dụng các phương thức Draw...() có tên tương tự và chấp nhận các tham số tương tự.

Rủi ro/lợi nhuận

Giao diện ChartRiskReward cung cấp các loại cho phép bạn tạo và quản lý các đối tượng rủi ro/lợi nhuận theo chương trình trên biểu đồ.

Đoạn mã dưới đây cho bạn thấy cách tạo một chỉ báo vẽ một đối tượng rủi ro/lợi nhuận:

 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
using System;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo
{
    [Indicator(AccessRights = AccessRights.None, IsOverlay = true)]
    public class SimpleRiskReward : Indicator
    {
        protected override void Initialize()
        {
            var type = new ChartRiskRewardFixedRiskType(
                ChartRiskRewardAmountType.BalancePercentage, 
                1                                            
            );
            var tradeType = TradeType.Buy;
            var orderType = OrderType.Market;

            var entryPrice = Chart.Bars.LastBar.Close;
            var time1 = Chart.LastVisibleBarIndex - 20; 
            var time2 = Chart.LastVisibleBarIndex;      

            var rr = Chart.DrawRiskReward(
                "SimpleRR",     
                time1,           
                time2,            
                entryPrice,       
                orderType,        
                tradeType,        
                type              
            );

            rr.IsInteractive = true;

            rr.RiskColor = Color.Yellow;
            rr.RiskLineStyle = LineStyle.DotsRare;
            rr.RiskThickness = 3;

            rr.RewardColor = Color.Blue;
            rr.RewardLineStyle = LineStyle.LinesDots;
            rr.RewardThickness = 2;

            PrintRRInfo(rr);
        }

        private void PrintRRInfo(ChartRiskReward rr)
        {
            Print($"Name: {rr.Name} | Type: {rr.Type.GetType().Name} | Order Type: {rr.OrderType} | Trade Type: {rr.TradeType} | Time 1: {rr.Time1:o} | Time 2: {rr.Time2:o} | Entry: {rr.EntryPrice} | SL: {rr.StopLossPrice} | TP: {rr.TakeProfitPrice} | RR: {rr.RiskRewardRatio} | Volume: {rr.VolumeInUnits}");
        }

        public override void Calculate(int index)
        {
        }
    }
}

Cài đặt đối tượng chính

Đặt tên các đối tượng biểu đồ

Bất cứ khi nào bạn cố gắng vẽ một đối tượng biểu đồ, bạn phải cung cấp tên của nó làm đối số cho phương thức vẽ.

Tất cả tên đối tượng biểu đồ phải là duy nhất. Nếu yêu cầu này không được đáp ứng, bạn có nguy cơ các đối tượng biểu đồ ghi đè lên các đối tượng biểu đồ có cùng tên tùy thuộc vào thời gian thực thi của chúng. Bạn có thể sử dụng giá trị chỉ số thanh hiện tại hoặc thời gian hiện tại để tạo tên duy nhất cho mỗi đối tượng.

Truy cập các đối tượng biểu đồ

Tất cả các đối tượng biểu đồ được chứa trong bộ sưu tập Objects. Bộ sưu tập này bao gồm các đối tượng do người dùng vẽ. Do đó, bộ sưu tập Objects có thể được truy cập để xóa các đối tượng khỏi biểu đồ hoặc sửa đổi thuộc tính của chúng.

Ví dụ dưới đây truy cập các thành viên của bộ sưu tập Objects:

 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
using cAlgo.API;
using System.Linq;
namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            foreach (var chartObject in Chart.Objects)
            {
                /* If the object is a trend line 
                we change its Y1/2 properties */
                if (chartObject is ChartTrendLine trendLine)
                {
                    trendLine.Y1 = Chart.BottomY;
                    trendLine.Y2 = Chart.TopY;
                }
            }

            /* Here, we filter all objects of the 'ChartRectangle'
            type. */
            var rectangles = from chartObject in Chart.Objects
                             where chartObject is ChartRectangle
                             select chartObject as ChartRectangle;

            /* We select only the chart objects with a name that
            begins with "MyObjects". */
            var myObjects = from chartObject in Chart.Objects
                            where chartObject.Name.StartsWith("MyObjects", System.StringComparison.OrdinalIgnoreCase)
                            select chartObject;

            /* We select only interactive objects. If an object
            is interactive, it will not be removed when the 
            indicator is removed or reloaded. */
            var interactiveObjects = from chartObject in Chart.Objects
                                     where chartObject.IsInteractive
                                     select chartObject;

            /* We remove all objects with a name 
            that begins with "ToRemove". */
            var chartObjectsCopy = Chart.Objects.ToArray();

            foreach (var chartObject in chartObjectsCopy)
            {
                if (chartObject.Name.StartsWith("ToRemove", System.StringComparison.OrdinalIgnoreCase))
                {
                    /* Chart 'RemoveObject' gets the object name
                    as a parameter. */
                    Chart.RemoveObject(chartObject.Name);
                }

            }
        }

        public override void Calculate(int index)
        {
        }
    }
}

Sự kiện

Các đối tượng biểu đồ có một số sự kiện mà bạn có thể sử dụng để biết những đối tượng nào được vẽ, cập nhật hoặc xóa:

  • ObjectsAdded - được kích hoạt khi một hoặc nhiều đối tượng biểu đồ được thêm vào biểu đồ.
  • ObjectsRemoved - được kích hoạt khi một hoặc nhiều đối tượng biểu đồ bị xóa khỏi biểu đồ.
  • ObjectsUpdated - được kích hoạt khi một hoặc nhiều đối tượng biểu đồ được cập nhật (một trong các thuộc tính của chúng được thay đổi bởi người dùng hoặc chỉ báo hoặc cBot đang hoạt động).
  • ObjectsSelectionChanged - được kích hoạt khi một hoặc nhiều đối tượng biểu đồ được người dùng chọn.
  • ObjectHoverChanged - được kích hoạt khi con trỏ chuột di chuyển qua một đối tượng biểu đồ.

Ví dụ sau sử dụng cả năm loại sự kiện:

 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
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            Chart.ObjectsAdded += Chart_ObjectsAdded;
            Chart.ObjectsRemoved += Chart_ObjectsRemoved;
            Chart.ObjectsUpdated += Chart_ObjectsUpdated;
            Chart.ObjectsSelectionChanged += Chart_ObjectsSelectionChanged;
            Chart.ObjectHoverChanged += Chart_ObjectHoverChanged;
        }

        private void Chart_ObjectHoverChanged(ChartObjectHoverChangedEventArgs obj) => throw new System.NotImplementedException();

        private void Chart_ObjectsSelectionChanged(ChartObjectsSelectionChangedEventArgs obj) => throw new System.NotImplementedException();

        private void Chart_ObjectsUpdated(ChartObjectsUpdatedEventArgs obj) => throw new System.NotImplementedException();

        private void Chart_ObjectsRemoved(ChartObjectsRemovedEventArgs obj) => throw new System.NotImplementedException();

        private void Chart_ObjectsAdded(ChartObjectsAddedEventArgs obj) => throw new System.NotImplementedException();

        public override void Calculate(int index)
        {
        }
    }
}

Đối tượng tương tác và không tương tác

Khi làm việc với các đối tượng tương tác, người dùng có thể thay đổi các thuộc tính của chúng như vị trí đối tượng, màu sắc, bình luận, v.v. Tất cả các đối tượng do người dùng vẽ đều tương tác theo mặc định.

Ghi chú

Thuộc tính ChartStaticText không thể thay đổi bất kể đối tượng liên quan của nó có tương tác hay không.

Để làm cho một đối tượng tương tác, hãy đặt thuộc tính IsInteractive của nó thành true như được hiển thị bên dưới:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var verticalLine = Chart.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);

            verticalLine.IsInteractive = true;
        }

        public override void Calculate(int index)
        {
        }
    }
}

Tất cả các đối tượng biểu đồ đều có thuộc tính IsInteractive. Giá trị mặc định của nó là false.

Nếu một đối tượng biểu đồ là tương tác, nó sẽ không bị xóa khi một phiên bản chỉ báo hoặc cBot bị xóa hoặc dừng lại. Ngược lại, các đối tượng không tương tác sẽ tự động bị xóa khi một chỉ báo hoặc cBot ngừng hoạt động.

Để tránh lộn xộn, hãy đảm bảo làm sạch các đối tượng tương tác sau khi phiên bản liên quan của chúng bị xóa bằng cách sử dụng phương thức Destroy của chỉ báo hoặc phương thức OnStop của cBot.

Nếu một đối tượng biểu đồ không tương tác, nó cũng sẽ không hiển thị trong danh sách và bộ sưu tập các đối tượng biểu đồ.

Đối tượng bị khóa và không bị khóa

Khóa một đối tượng biểu đồ ngăn người dùng sửa đổi hoặc cập nhật nó. Bạn có thể làm điều này thông qua hộp Trader (Thuộc tính biểu đồ) hoặc bằng cách đặt thuộc tính IsLocked thành true. Giá trị mặc định là false.

Bạn có thể sử dụng khóa để làm cho một đối tượng tương tác nhưng đồng thời ngăn người dùng cập nhật nó. Ví dụ sau khóa một đối tượng đường thẳng dọc:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var verticalLine = Chart.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);

            verticalLine.IsLocked = true;
        }

        public override void Calculate(int index)
        {
        }
    }
}

Hiển thị và ẩn

Bạn có thể vẽ một đối tượng trên biểu đồ và sau đó ẩn nó. Mặc dù đối tượng vẫn sẽ hiện diện trên biểu đồ, nhưng nó sẽ hoàn toàn không nhìn thấy được.

Để làm điều này, hãy đặt thuộc tính IsHidden thành true.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var verticalLine = Chart.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);

            verticalLine.IsHidden = true;
        }

        public override void Calculate(int index)
        {
        }
    }
}

Việc sử dụng tài nguyên là cân nhắc chính cho việc sử dụng tính năng này. Nếu có một đối tượng thường xuyên xuất hiện trên biểu đồ (nhưng không phải lúc nào cũng vậy), tốt hơn là ẩn nó thay vì xóa và vẽ lại nó mỗi khi cần.

Chọn đối tượng và chỉ số xuất hiện (ZIndex)

Tự nhiên, có thể có những trường hợp nhiều đối tượng giao nhau trên biểu đồ, khiến việc chọn một đối tượng cụ thể trở nên khó khăn hoặc hoàn toàn không thể. Chỉ đối tượng được vẽ cuối cùng mới có thể được chọn khi bạn di chuột qua một nhóm đối tượng biểu đồ giao nhau.

Để thay đổi hành vi này, bạn có thể sử dụng thuộc tính ZIndex. Nó có thể hữu ích khi cố gắng hiển thị các mẫu phức tạp của các đối tượng biểu đồ.

 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
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var firstVerticalLine = Chart.DrawVerticalLine("line1", Chart.LastVisibleBarIndex, Color.Red);

            firstVerticalLine.IsInteractive = true;

            var secondVerticalLine = Chart.DrawVerticalLine("line2", Chart.LastVisibleBarIndex, Color.Yellow);

            secondVerticalLine.IsInteractive = true;

            firstVerticalLine.ZIndex = secondVerticalLine.ZIndex + 1;
        }

        public override void Calculate(int index)
        {
        }
    }
}

Khi được gắn vào biểu đồ, chỉ báo trên sẽ hiển thị một đường thẳng dọc màu đỏ thay vì màu vàng. Vì giá trị của thuộc tính ZIndex của đường đầu tiên cao hơn giá trị tương ứng của đường thứ hai, nó được ưu tiên hơn đường thứ hai (màu vàng).

Nói cách khác, thuộc tính ZIndex xác định đối tượng biểu đồ nào được hiển thị trước khi chúng chồng lên nhau. Tất cả các đối tượng biểu đồ được vẽ đều được gán một giá trị nhất định cho thuộc tính ZIndex một cách tự động.

Biết liệu một đối tượng có bị xóa hay không

Tất cả các đối tượng biểu đồ kế thừa thuộc tính IsAlive từ lớp cơ sở ChartObject. Giá trị của thuộc tính này là true miễn là một đối tượng hiện diện trên biểu đồ (bất kể nó có thể nhìn thấy hay không thể nhìn thấy). Giá trị được đặt thành false ngay khi một đối tượng bị xóa khỏi biểu đồ.

Nếu bạn lưu một tham chiếu đến một đối tượng biểu đồ và đối tượng này bị người dùng xóa, bạn có thể kiểm tra thuộc tính IsAlive để kiểm tra xem đối tượng có còn sống hay đã chết.

 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
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        private ChartVerticalLine _verticalLine;

        protected override void Initialize()
        {
            _verticalLine = Chart.DrawVerticalLine("line1", Chart.LastVisibleBarIndex, Color.Red);
            _verticalLine.IsInteractive = true;

            Chart.ObjectsRemoved += Chart_ObjectsRemoved;

            Print(_verticalLine.IsAlive);
        }

        private void Chart_ObjectsRemoved(ChartObjectsRemovedEventArgs obj)
        {
            Print(_verticalLine.IsAlive);

            /* If the object is removed, we should rid of its
            reference. Otherwise, it will remain in memory. */
            if (_verticalLine.IsAlive is false)
            {
                _verticalLine = null;

                Print("Object reference removed");
            }
        }

        public override void Calculate(int index)
        {
        }
    }
}

Nếu bạn chạy một phiên bản của chỉ báo này, nhấp chuột phải vào đường màu đỏ và xóa nó. Sau đó, nhật ký sẽ xuất ra thông báo "Object reference removed".

Nếu bạn giữ một tham chiếu đến một đối tượng biểu đồ (đã chết), một rò rỉ bộ nhớ sẽ xảy ra. Trong quá trình thu gom rác, đối tượng của bạn vẫn sẽ được coi là còn sống, có nghĩa là nó sẽ tồn tại qua quá trình thu gom.

Để tránh vấn đề này, hãy sử dụng sự kiện ObjectsRemoved kết hợp với thuộc tính IsAlive.

Bar index hoặc thời gian

Khi lập trình các đối tượng biểu đồ, bạn có thể sử dụng thời gian biểu đồ hoặc chỉ số thanh cho trục X.

Theo chúng tôi, thời gian biểu đồ là lựa chọn tốt hơn. Khi sử dụng chỉ số thanh, bạn không thể lập kế hoạch cho các giá trị trong tương lai (vì các chỉ số cần thiết chưa tồn tại) và không thể tính đến bất kỳ khoảng trống nào giữa các thanh. Tuy nhiên, chỉ số thanh có thể dễ sử dụng hơn, đặc biệt là trong trường hợp các đối tượng biểu đồ tương đối đơn giản.

Tất cả các phương thức Chart.Draw đều có các overload khác nhau cho chỉ số thanh và thời gian biểu đồ.