public void Hours()
        {
            System.IO.StreamReader sr = new System.IO.StreamReader("TestWAG.txt");
            sr.ReadLine();
            sr.ReadLine();

            BarListImpl bl        = new BarListImpl(BarInterval.Hour, "WAG");
            Tick        k         = new TickImpl();
            int         tickcount = 0;

            while (!sr.EndOfStream)
            {
                k = eSigTick.FromStream(bl.Symbol, sr);
                if (tickcount == 0)
                {
                    Assert.IsTrue(k.isValid);
                    Assert.AreEqual(20070926041502, k.datetime);
                    Assert.AreEqual(20070926, k.date);
                    Assert.AreEqual(041502, k.time);
                    Assert.AreEqual(43.81m, k.bid);
                    Assert.AreEqual(51.2m, k.ask);
                    Assert.AreEqual(1, k.bs);
                    Assert.AreEqual(1, k.os);
                    Assert.IsTrue(k.be.Contains("PSE"));
                    Assert.IsTrue(k.oe.Contains("PSE"));
                }
                tickcount++;
                bl.newTick(k);
            }
            // hour is what we asked for
            Assert.AreEqual(BarInterval.Hour, bl.DefaultInterval);
            // there are 4 trades on hour intervals, 6/7/8/9
            Assert.AreEqual(4, bl.Count);
        }
Exemple #2
0
        public void PointMinute()
        {
            // prepare barlist
            BarListImpl bl = new BarListImpl(BarInterval.Minute);

            // reset count
            int newbars = 0;

            // build bars from ticks available
            foreach (TickImpl k in SampleData())
            {
                // add tick to bar
                bl.NewPoint(k.Symbol, k.Trade, k.Time, k.Date, k.Size);
                // count if it's a new bar
                if (bl.RecentBar.IsNew)
                {
                    newbars++;
                }
            }

            // verify expected # of bars are present
            Assert.Equal(9, newbars);

            // verify barcount is same as newbars
            Assert.Equal(newbars, bl.Count);
        }
Exemple #3
0
        public void PointHour()
        {
            // get data
            Tick[] tape = SampleData();

            // count new hour bars
            _newbars = 0;

            // setup hour bar barlist
            BarListImpl bl = new BarListImpl(BarInterval.Hour, Sym);

            // handle new bar events
            bl.GotNewBar += bl_GotNewBar;

            // add ticks to bar
            foreach (Tick k in tape)
            {
                // add ticks
                bl.NewPoint(k.Symbol, k.Trade, k.Time, k.Date, k.Size);
            }

            // make sure we have at least 1 bars
            Assert.True(bl.Has(1));

            // make sure we actually have two bars
            Assert.Equal(2, bl.Count);
        }
Exemple #4
0
        private void button2_Click(object sender, EventArgs e)
        {
            OpenFileDialog od = new OpenFileDialog();

            od.CheckFileExists  = true;
            od.CheckPathExists  = true;
            od.DefaultExt       = "*.EPF";
            od.Filter           = "TickFiles|*.EPF";
            od.InitialDirectory = "c:\\program files\\tradelink\\tickdata\\";
            od.Multiselect      = false;
            od.ShowDialog();
            BarList   bl = BarListImpl.FromEPF(od.FileName);
            ChartImpl c  = new ChartImpl(bl, false);

            c.Symbol = bl.Symbol;
            try
            {
                c.StartPosition = FormStartPosition.Manual;
                c.Location      = Chartographer.Properties.Settings.Default.chartstart;
            }
            catch (NullReferenceException) { }
            newChartData += new BarListUpdated(c.NewBarList);
            c.Move       += new EventHandler(c_Move);
            c.Icon        = Chartographer.Properties.Resources.chart;
            if (maxchartbox.Checked)
            {
                c.WindowState = FormWindowState.Maximized;
            }
            if (blackbackground.Checked)
            {
                c.BackColor = Color.Black;
            }
            c.Show();
        }
Exemple #5
0
        public void InsertBar_HistoricalPlusNewBarsPresent()
        {
            string sym = "FTI";
            int    d   = 20070926;
            // historical bar filename
            string filename = sym + d + TikConst.DOT_EXT;
            // case 3 - middle insertion aka (some historical and some new bars already present)
            var org = BarListImpl.FromTIK(filename);

            Assert.IsTrue(org.isValid, "your original bar is not valid 3");
            var orgcount = org.Count;

            Assert.Greater(orgcount, 0);
            // create bar to insert
            var insert = new BarImpl(30, 30, 30, 30, 10000, d, 75500, sym, (int)BarInterval.FiveMin);

            Assert.IsTrue(insert.isValid, "your bar to insert is not valid 3");
            int insertpos = BarListImpl.GetBarIndexPreceeding(org, insert.Bardate);
            var inserted  = BarListImpl.InsertBar(org, insert, insertpos);

            Assert.AreEqual(inserted.Count, orgcount + 1);
            var actualinsert = inserted[insertpos];

            Assert.IsTrue(actualinsert.isValid);
            Assert.AreEqual(insert.Close, actualinsert.Close);
            Assert.AreEqual(insert.Open, actualinsert.Open);
            Assert.AreEqual(insert.High, actualinsert.High);
            Assert.AreEqual(insert.Low, actualinsert.Low);
            Assert.AreEqual(insert.Symbol, actualinsert.Symbol);
        }
Exemple #6
0
        public void FiveMin()
        {
            // get some sample data to fill barlist
            Tick[] ticklist = SampleData();

            // prepare barlist
            BarListImpl bl = new BarListImpl(BarInterval.FiveMin);

            bl.GotNewBar += bl_GotNewBar;

            // reset count
            _newbars = 0;

            // create bars from all ticks available
            foreach (TickImpl k in ticklist)
            {
                // add tick to bar
                bl.NewTick(k);
            }

            // verify we had expected number of bars
            Assert.Equal(3, _newbars);

            // verify symbol was set
            Assert.Equal(Sym, bl.Symbol);

            // verify each bar symbol matches barlist
            foreach (Bar b in bl)
            {
                Assert.Equal(bl.Symbol, b.Symbol);
            }
        }
Exemple #7
0
        public void SpoolIntraBars()
        {
            BarListImpl bl = (BarListImpl)_intraBarTracker["SPY", (int)BarInterval.FiveMin];

            for (int x = 0; x < _spyIntra.Length; x++)
            {
                Bar b = BarImpl.Deserialize(_spyIntra[x]);

                bl.NewPoint(b.Symbol, b.Open, b.Bartime, b.Bardate, 0);
                bl.NewPoint(b.Symbol, b.High, b.Bartime, b.Bardate, 0);
                bl.NewPoint(b.Symbol, b.Low, b.Bartime, b.Bardate, 0);
                bl.NewPoint(b.Symbol, b.Close, b.Bartime, b.Bardate, (int)b.Volume);
            }

            Console.WriteLine("Count: " + bl.Count);

            Assert.Equal(_spyIntra.Length, bl.Count);
            for (int x = 0; x < _spyIntra.Length; x++)
            {
                Bar t = BarImpl.Deserialize(_spyIntra[x]);
                Assert.Equal(bl[x].Bardate, t.Bardate);
                Assert.Equal(bl[x].Close, t.Close);
            }

            DisplayTrackerContent(_intraBarTracker["SPY"]);
        }
Exemple #8
0
        public void DailyMixedTickAndBars()
        {
            BarListImpl bl = (BarListImpl)_dailyBarTracker["SPY", (int)BarInterval.Day];

            for (int x = 0; x < _spyDaily.Length; x++)
            {
                BarImpl b = (BarImpl)BarImpl.Deserialize(_spyDaily[x]);
                bl.NewPoint(b.Symbol, b.Open, b.Bartime, b.Bardate, 0);
                bl.NewPoint(b.Symbol, b.High, b.Bartime, b.Bardate, 0);
                bl.NewPoint(b.Symbol, b.Low, b.Bartime, b.Bardate, 0);
                bl.NewPoint(b.Symbol, b.Close, b.Bartime, b.Bardate, (int)b.Volume);

                // interleave ticks with the bars to simulate datafeed asynchronous-ness
                int      baseTime = 144500;
                TickImpl k        = new TickImpl("SPY");
                k.Ask   = 101;
                k.Bid   = 100;
                k.Date  = 20110208;
                k.Trade = 100.5m;
                k.Size  = 5000;
                k.Time  = baseTime + x;
                _dailyBarTracker.NewTick(k);
            }

            Console.WriteLine("Count: " + bl.Count);
            DisplayTrackerContent(_dailyBarTracker["SPY"]);
            Assert.Equal(_spyDaily.Length, bl.Count);
            for (int x = 0; x < _spyDaily.Length - 1; x++)
            {
                Bar t = BarImpl.Deserialize(_spyDaily[x]);
                Assert.Equal(bl[x].Bardate, t.Bardate);
                Assert.Equal(bl[x].Close, t.Close);
            }
        }
Exemple #9
0
        public void DefaultIntervalAndReset()
        {
            // get some data
            Tick[] tape = SampleData();

            // setup an hour barlist
            BarListImpl bl = new BarListImpl();

            bl.DefaultInterval = BarInterval.Hour;

            // build the barlist
            foreach (Tick k in tape)
            {
                bl.NewTick(k);
            }

            // make sure we have 2 hour bars
            Assert.Equal(2, bl.Count);

            // switch default
            bl.DefaultInterval = BarInterval.FiveMin;

            // make sure we have 3 5min bars
            Assert.Equal(3, bl.Count);

            // reset it
            bl.Reset();

            // verify we have no data
            Assert.Equal(0, bl.Count);
        }
Exemple #10
0
        public void HourTest()
        {
            // get data
            Tick[] tape = SampleData();

            // count new hour bars
            _newbars = 0;

            // setup hour bar barlist
            BarListImpl bl = new BarListImpl(BarInterval.Hour, Sym);

            // handle new bar events
            bl.GotNewBar += bl_GotNewBar;

            // add ticks to bar
            foreach (Tick k in tape)
            {
                // add ticks
                bl.NewTick(k);
            }

            // make sure we have at least 1 bars
            Assert.True(bl.Has(1));

            // make sure we actually have two bars
            Assert.Equal(2, _newbars);
            Assert.Equal(bl.Count, _newbars);
        }
Exemple #11
0
        public void InsertBar_HistoricalBarsPresent()
        {
            string sym = "FTI";
            int    d   = 20070926;
            // historical bar filename
            string filename = sym + d + TikConst.DOT_EXT;

            // unit test case 2 existing bars with front insertion (aka historical bar insert)

            var org = BarListImpl.FromTIK(filename);

            Assert.IsTrue(org.isValid, "your original bar is not valid 2");
            var orgcount = org.Count;

            Assert.Greater(orgcount, 0);
            // create bar to insert
            var insert = new BarImpl(30, 30, 30, 30, 10000, d, 75500, sym, (int)BarInterval.FiveMin);

            Assert.IsTrue(insert.isValid, "your bar to insert is not valid 2");
            var inserted = BarListImpl.InsertBar(org, insert, 0);

            Assert.AreEqual(inserted.Count, orgcount + 1);
            var actualinsert = inserted[0];

            Assert.IsTrue(actualinsert.isValid);
            Assert.AreEqual(insert.Close, actualinsert.Close);
            Assert.AreEqual(insert.Open, actualinsert.Open);
            Assert.AreEqual(insert.High, actualinsert.High);
            Assert.AreEqual(insert.Low, actualinsert.Low);
            Assert.AreEqual(insert.Symbol, actualinsert.Symbol);
        }
Exemple #12
0
        public void InsertBar_NoexistingBars()
        {
            string sym = "FTI";
            int    d   = 20070926;

            // historical bar filename
            string filename = sym + d + TikConst.DotExt;

            // test for the parameter's prescence
            Assert.NotEmpty(filename);

            // unit test case 1 no existing bars aka (empty or brand-new insertion)
            BarList org = new BarListImpl(BarInterval.FiveMin, sym);

            Assert.True(org.IsValid, "your original barlist is not valid 1");
            int orgcount = org.Count;

            Assert.Equal(0, orgcount);

            // make up a bar here  (eg at 755 in FTI there are no ticks so this should add a new bar in most scenarios)
            Bar insert = new BarImpl(30, 30, 30, 30, 10000, d, 75500000, sym, (int)BarInterval.FiveMin);

            Assert.True(insert.IsValid, "your bar to insert is not valid 1");
            BarList inserted = BarListImpl.InsertBar(org, insert, org.Count);

            Assert.Equal(inserted.Count, orgcount + 1);
            Bar actualinsert = inserted.RecentBar;

            Assert.True(actualinsert.IsValid);
            Assert.Equal(insert.Close, actualinsert.Close);
            Assert.Equal(insert.Open, actualinsert.Open);
            Assert.Equal(insert.High, actualinsert.High);
            Assert.Equal(insert.Low, actualinsert.Low);
            Assert.Equal(insert.Symbol, actualinsert.Symbol);
        }
Exemple #13
0
        public void InsertBar_MultipleInsert()
        {
            string  sym = "FTI";
            int     d   = 20070926;
            BarList org = new BarListImpl(BarInterval.FiveMin, sym);

            Assert.IsTrue(org.isValid, "your original barlist is not valid 1");
            int orgcount = org.Count;

            Assert.AreEqual(0, orgcount);

            int h = 7;
            int m = 55;

            for (int i = 0; i < 10; i++)
            {
                int t      = h * 10000 + m * 100;
                Bar insert = new BarImpl(30, 30, 30, 30, 10000, d, t, sym, (int)BarInterval.FiveMin);
                Assert.IsTrue(insert.isValid, "your bar to insert is not valid 1");
                int insertpos = BarListImpl.GetBarIndexPreceeding(org, insert.Bardate, insert.Bartime);
                Assert.AreEqual(i - 1, insertpos, "insertion position");
                BarList inserted = BarListImpl.InsertBar(org, insert, insertpos);
                Assert.AreEqual(i + 1, inserted.Count, "element count after insertion");
                m += 5;
                if (m >= 60)
                {
                    h += m / 60;
                    m  = m % 60;
                }
                org = inserted;
            }
            Assert.AreEqual(orgcount + 10, org.Count, "total element count after insertion");
        }
Exemple #14
0
        public void ReadAndOverwrite()
        {
            const string tf = @"SPX20070926.TIK";

            // read a barlist
            var bl = BarListImpl.FromTIK(tf);

            // get new bars
            var newbl = BarListImpl.DayFromGoogle("FTI");

            // append
            for (int i = 0; i < newbl.Count; i++)
            {
                foreach (var k in BarImpl.ToTick(newbl[i]))
                {
                    bl.newTick(k);
                }
            }



            // write the barlist
            Assert
            .IsTrue(BarListImpl.ChartSave(bl, Environment.CurrentDirectory, 20070926), "error saving new data");
        }
Exemple #15
0
        public void FromEPF()
        {
            // get sample tick data
            BarList bl = BarListImpl.FromEPF("FTI20070926.EPF");

            // verify expected number of 5min bars exist (78 in 9:30-4p)
            Assert.AreEqual(83, bl.Count);
        }
Exemple #16
0
 private void downloaddata()
 {
     while (newchartsyms.hasItems)
     {
         string sym   = newchartsyms.Read();
         var    chart = BarListImpl.GetChart(sym, usecachenow, 200, debug);
         newChart(chart);
     }
 }
Exemple #17
0
        public void FromTIK()
        {
            const string tf = "FTI20070926.TIK";
            // get sample tick data
            BarList bl = BarListImpl.FromTIK(tf);

            // verify expected number of 5min bars exist (78 in 9:30-4p)
            Assert.Greater(bl.Count, 82, "not enough bars from: " + tf);
        }
Exemple #18
0
        public void Basics()
        {
            const string sym = "TST";
            const int    d   = 20080509;
            const int    t   = 93500;
            const string x   = "NYSE";

            TickImpl[] ticklist = new TickImpl[] {
                TickImpl.NewTrade(sym, d, t, 10, 100, x),
                TickImpl.NewTrade(sym, d, t + 100, 10, 100, x),
                TickImpl.NewTrade(sym, d, t + 200, 10, 100, x),
                TickImpl.NewTrade(sym, d, t + 300, 10, 100, x),
                TickImpl.NewTrade(sym, d, t + 400, 15, 100, x),  // blade up
                TickImpl.NewTrade(sym, d, t + 500, 16, 100, x),  // new bar (blades reset)
                TickImpl.NewTrade(sym, d, t + 600, 16, 100, x),
                TickImpl.NewTrade(sym, d, t + 700, 10, 100, x),  // blade down
                TickImpl.NewTrade(sym, d, t + 700, 10, 100, x),  // still a blade down (same bar)
                TickImpl.NewTrade(sym, d, t + 800, 15, 100, x),
                TickImpl.NewTrade(sym, d, t + 1500, 15, 800, x), // volume spike
                TickImpl.NewTrade(sym, d, t + 2000, 15, 100, x),
                TickImpl.NewTrade(sym, d, t + 2500, 15, 100, x),
            };

            BarListImpl bl = new BarListImpl(BarInterval.FiveMin, sym);
            Blade       b  = new Blade();

            Assert.That(b.BladePercentage != 0);
            b = new Blade(.2m); // 20 percent move is a blade
            int up = 0, down = 0, newbar = 0, bigvol = 0;

            foreach (TickImpl k in ticklist)
            {
                bl.newTick(k);
                b.newBar(bl);
                if (bl.NewBar)
                {
                    newbar++;
                }
                if (b.isBladeUP)
                {
                    up++;
                }
                if (b.isBladeDOWN)
                {
                    down++;
                }
                if (b.isBigVolume)
                {
                    bigvol++;
                }
            }

            Assert.AreEqual(1, up);
            Assert.AreEqual(2, down);
            Assert.AreEqual(5, newbar);
            Assert.AreEqual(1, bigvol);
        }
Exemple #19
0
        public void TestMaximumHistory()
        {
            const string tf = @"Common\EURUSD20080826.TIK";

            // get sample tick data
            BarList bl = BarListImpl.FromTIK(tf);

            // verify that the max amount is set to 200
            Assert.True(bl.Count == 200);
        }
Exemple #20
0
        public void FromTIK()
        {
            const string tf = @"Common\EURUSD20080826.TIK";

            // get sample tick data
            BarList bl = BarListImpl.FromTIK(tf);

            // verify expected number of 5min bars exist (78 in 9:30-4p)
            Assert.True(bl.Count > 82);
        }
Exemple #21
0
        public void FromGoogle()
        {
            // get a year chart
            BarList bl = BarListImpl.DayFromGoogle("IBM");

            // make sure it's there
            Assert.IsTrue(bl.isValid);
            // verify we have at least a year of bar data
            Assert.GreaterOrEqual(bl.Count, 199);
        }
        private void DrawLabelsPrice()
        {
            Graphics gd = CreateGraphics();

            if (hastextlabels)
            {
                Font font = new Font(FontFamily.GenericSerif, 8, FontStyle.Regular);
                // draw the text-only labels first
                foreach (Color c in _colpoints.Keys)
                {
                    List <Label> points = _colpoints[c];
                    for (int i = 0; i < points.Count; i++)
                    {
                        // draw labels
                        if (!points[i].isLine)
                        {
                            gd.DrawString(points[i].Text, font, new SolidBrush(c), getX(BarListImpl.GetNearestIntraBar(bl, points[i].Time, bl.DefaultInterval)), getY(points[i].Price));
                        }
                    }
                }
            }
            // draw price lines
            foreach (Color c in _collineend.Keys)
            {
                List <Label> points  = _colpoints[c];
                List <int>   lineidx = _collineend[c];
                for (int i = 0; i < lineidx.Count; i++)
                {
                    // get point indicies
                    // get previous point first (must be used for line)
                    var p1i = getpreceedingnonlabelindex(i, points);
                    // can't draw if we don't have two non-label points
                    if (p1i < 0)
                    {
                        continue;
                    }
                    int p2i = lineidx[i];
                    if (!points[p2i].isLine)
                    {
                        continue;
                    }
                    // get points
                    int x1 = getX(BarListImpl.GetNearestIntraBar(bl, points[p1i].Time, bl.DefaultInterval));
                    int y1 = getY(points[p1i].Price);
                    int x2 = getX(BarListImpl.GetNearestIntraBar(bl, points[p2i].Time, bl.DefaultInterval));
                    int y2 = getY(points[p2i].Price);
                    // draw from previous point
                    gd.DrawLine(new Pen(c), x1, y1, x2, y2);
                }
            }
        }
Exemple #23
0
        private void ChartMain_DragDrop(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Copy;
            string[] s = (string[])e.Data.GetData(DataFormats.FileDrop, false);
            string   f = s[0];

            if (!f.Contains(TikConst.DOT_EXT))
            {
                return;
            }
            BarList bl = BarListImpl.FromTIK(f);

            newChart(bl);
        }
Exemple #24
0
        void ar_GotTick(Tick t)
        {
            if (spillTick != null)
            {
                spillTick(t);
            }
            RefreshRow(t);
            BarListImpl bl = null;

            if (bardict.TryGetValue(t.symbol, out bl))
            {
                bardict[t.symbol].newTick(t);
            }
        }
Exemple #25
0
        public void NegativeBars()
        {
            // get sample tick data
            BarList bl = BarListImpl.FromEPF("FTI20070926.EPF");

            // verify expected number of 5min bars exist (78 in 9:30-4p)
            Assert.AreEqual(83, bl.Count);
            // verify that 5th bar from end is same as 77th bar
            Assert.AreEqual(bl[-5].High, bl[77].High);
            Assert.AreEqual(bl[-5].Open, bl[77].Open);
            Assert.AreEqual(bl[-5].Low, bl[77].Low);
            Assert.AreEqual(bl[-5].Close, bl[77].Close);
            Assert.AreEqual(bl[-5].Bardate, bl[77].Bardate);
            Assert.AreEqual(bl[-5].Bartime, bl[77].Bartime);
        }
Exemple #26
0
        /// <summary>
        /// give any ticks (trades) to this symbol and tracker will create barlists automatically
        /// </summary>
        /// <param name="k"></param>
        public void NewTick(Tick k)
        {
            BarListImpl bl;

            if (!_bdict.TryGetValue(k.Symbol, out bl))
            {
                bl = new BarListImpl(k.Symbol, _requested, _reqtype)
                {
                    DefaultCustomInterval = _default
                };
                bl.GotNewBar += bl_GotNewBar;
                _bdict.Add(k.Symbol, bl);
            }
            bl.NewTick(k);
        }
Exemple #27
0
        /// <summary>
        /// add any data point to bar
        /// </summary>
        /// <param name="symbol"></param>
        /// <param name="p"></param>
        /// <param name="time"></param>
        /// <param name="date"></param>
        /// <param name="size"></param>
        public void NewPoint(string symbol, decimal p, int time, int date, int size)
        {
            BarListImpl bl;

            if (!_bdict.TryGetValue(symbol, out bl))
            {
                bl = new BarListImpl(symbol, _requested, _reqtype)
                {
                    DefaultCustomInterval = _default
                };
                bl.GotNewBar += bl_GotNewBar;
                _bdict.Add(symbol, bl);
            }
            bl.NewPoint(symbol, p, time, date, size);
        }
Exemple #28
0
        private void button2_Click(object sender, EventArgs e)
        {
            OpenFileDialog od = new OpenFileDialog();

            od.CheckFileExists = true;
            od.CheckPathExists = true;
            od.DefaultExt      = TikConst.WILDCARD_EXT;
            od.Filter          = "TickFiles|" + TikConst.WILDCARD_EXT;
            od.Multiselect     = false;
            if (od.ShowDialog() == DialogResult.OK)
            {
                BarList bl = BarListImpl.FromTIK(od.FileName, _uselast, _usebid);
                newChart(bl);
            }
        }
Exemple #29
0
        public void VolInterval()
        {            // request 300 volume bars
            const int MYINTERVAL = 300;
            BarList   bl         = new BarListImpl(sym, MYINTERVAL, BarInterval.CustomVol);

            // verify custom interval
            Assert.AreEqual(MYINTERVAL, bl.DefaultCustomInterval);
            Assert.AreEqual(MYINTERVAL, bl.CustomIntervals[0]);
            // iterate ticks
            foreach (Tick k in SampleData())
            {
                bl.newTick(k);
            }
            // count em
            Assert.AreEqual(4, bl.Count);
        }
Exemple #30
0
        public void FromGoogle()
        {
            string[] testsyms = new string[] { "IBM", "AAPL" };
            foreach (var sym in testsyms)
            {
                // get a year chart
                BarList bl = BarListImpl.DayFromGoogle(sym, false, g.d);
                // make sure it's there
                Assert.IsTrue(bl.isValid, "invalid barlist: " + sym);
                // verify we have at least a year of bar data
                Assert.GreaterOrEqual(bl.Count, 199, "not enough data in barlist: " + sym);

                // show bars
                //g.d(sym+" "+bl.Count.ToString());
            }
        }