[chronojump] Encoder gtk graph colors copied to CairoBars graph (also implemented discardFirstN...)
- From: Xavier de Blas <xaviblas src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [chronojump] Encoder gtk graph colors copied to CairoBars graph (also implemented discardFirstN...)
- Date: Thu, 17 Mar 2022 15:47:58 +0000 (UTC)
commit 191282c79b479e27f7b4c793c79fdc5fc26eed20
Author: Xavier de Blas <xaviblas gmail com>
Date: Thu Mar 17 16:47:15 2022 +0100
Encoder gtk graph colors copied to CairoBars graph (also implemented discardFirstN...)
src/gui/app1/chronojump.cs | 5 +-
src/gui/app1/encoder.cs | 15 ++++--
src/gui/cairo/bars.cs | 47 +++++++++++++---
src/gui/cairo/generic.cs | 3 +-
src/gui/eventExecute.cs | 131 ++++++++++++++++++++++++++++++++++++++++-----
src/gui/usefulObjects.cs | 10 +++-
6 files changed, 185 insertions(+), 26 deletions(-)
---
diff --git a/src/gui/app1/chronojump.cs b/src/gui/app1/chronojump.cs
index 4bef3ec11..3c47fdaf3 100644
--- a/src/gui/app1/chronojump.cs
+++ b/src/gui/app1/chronojump.cs
@@ -7821,7 +7821,10 @@ LogB.Debug("mc finished 5");
encoderCaptureListStore,
preferences.encoderCaptureMainVariableThisSetOrHistorical,
sendMaxPowerSpeedForceIntersession(preferences.encoderCaptureMainVariable),
-
sendMaxPowerSpeedForceIntersessionDate(preferences.encoderCaptureMainVariable));
+
sendMaxPowerSpeedForceIntersessionDate(preferences.encoderCaptureMainVariable),
+
preferences.encoderCaptureInertialDiscardFirstN,
+ preferences.volumeOn,
+ preferences.gstreamer);
prepareEncoderBarplotCairo ();
}
} else
diff --git a/src/gui/app1/encoder.cs b/src/gui/app1/encoder.cs
index 9c560108a..bd5190b2f 100644
--- a/src/gui/app1/encoder.cs
+++ b/src/gui/app1/encoder.cs
@@ -5908,7 +5908,10 @@ public partial class ChronoJumpWindow
encoderCaptureListStore,
preferences.encoderCaptureMainVariableThisSetOrHistorical,
sendMaxPowerSpeedForceIntersession(preferences.encoderCaptureMainVariable),
-
sendMaxPowerSpeedForceIntersessionDate(preferences.encoderCaptureMainVariable));
+
sendMaxPowerSpeedForceIntersessionDate(preferences.encoderCaptureMainVariable),
+ preferences.encoderCaptureInertialDiscardFirstN,
+ preferences.volumeOn,
+ preferences.gstreamer);
prepareEncoderBarplotCairo ();
}
}
@@ -6776,7 +6779,10 @@ public partial class ChronoJumpWindow
encoderCaptureListStore,
preferences.encoderCaptureMainVariableThisSetOrHistorical,
sendMaxPowerSpeedForceIntersession(preferences.encoderCaptureMainVariable),
-
sendMaxPowerSpeedForceIntersessionDate(preferences.encoderCaptureMainVariable));
+
sendMaxPowerSpeedForceIntersessionDate(preferences.encoderCaptureMainVariable),
+ preferences.encoderCaptureInertialDiscardFirstN,
+ preferences.volumeOn,
+ preferences.gstreamer);
prepareEncoderBarplotCairo ();
}
//}
@@ -7375,7 +7381,10 @@ public partial class ChronoJumpWindow
encoderCaptureListStore,
preferences.encoderCaptureMainVariableThisSetOrHistorical,
sendMaxPowerSpeedForceIntersession(preferences.encoderCaptureMainVariable),
-
sendMaxPowerSpeedForceIntersessionDate(preferences.encoderCaptureMainVariable));
+
sendMaxPowerSpeedForceIntersessionDate(preferences.encoderCaptureMainVariable),
+ preferences.encoderCaptureInertialDiscardFirstN,
+ preferences.volumeOn,
+ preferences.gstreamer);
prepareEncoderBarplotCairo ();
}
diff --git a/src/gui/cairo/bars.cs b/src/gui/cairo/bars.cs
index 77cfaa73c..51a463f78 100644
--- a/src/gui/cairo/bars.cs
+++ b/src/gui/cairo/bars.cs
@@ -248,7 +248,8 @@ public abstract class CairoBars : CairoGeneric
}
public abstract void GraphDo (List<PointF> pointMain_l, List<List<PointF>> pointSecondary_ll, bool
mainAtLeft,
- List<string> names_l, int fontHeightForBottomNames, int marginForBottomNames, string
title);
+ List<Cairo.Color> colorMain_l, List<Cairo.Color> colorSecondary, List<string> names_l,
+ int fontHeightForBottomNames, int marginForBottomNames, string title);
protected void initGraph(string font, double widthPercent1)
{
@@ -662,6 +663,7 @@ public abstract class CairoBars : CairoGeneric
public class CairoBars1Series : CairoBars
{
private List<PointF> pointMain_l;
+ private List<Cairo.Color> colorMain_l;
private List<string> names_l;
//constructor when there are no points
@@ -722,8 +724,11 @@ public class CairoBars1Series : CairoBars
double x = (graphWidth - (leftMargin+rightMargin)) * (p.X-.5)/pointMain_l.Count -
barDesplLeft + leftMargin;
double y = calculatePaintY(p.Y);
- drawRoundedRectangle (true, x, y, barWidth, graphHeight -y -bottomMargin, 4, g,
colorSerieA);
-LogB.Information(string.Format("y: {0}, alto: {1}", y, graphHeight -y - bottomMargin));
+ Cairo.Color barColor = colorSerieA;
+ if(colorMain_l != null && colorMain_l.Count == pointMain_l.Count)
+ barColor = colorMain_l[i];
+
+ drawRoundedRectangle (true, x, y, barWidth, graphHeight -y -bottomMargin, 4, g,
barColor);
plotResultOnBar(x + barWidth/2, y, graphHeight -bottomMargin, p.Y, resultFontHeight,
barWidth, -1);
//print the type at bottom
@@ -737,11 +742,14 @@ LogB.Information(string.Format("y: {0}, alto: {1}", y, graphHeight -y - bottomMa
}
public override void GraphDo (List<PointF> pointMain_l, List<List<PointF>> pointSecondary_ll, bool
mainAtLeft,
- List<string> names_l, int fontHeightForBottomNames, int marginForBottomNames, string
title)
+ List<Cairo.Color> colorMain_l, List<Cairo.Color> colorSecondary, List<string> names_l,
+ int fontHeightForBottomNames, int marginForBottomNames, string title)
{
LogB.Information("at CairoBars1Series.Do");
this.pointMain_l = pointMain_l;
- //this.pointB_l = pointB_l; unused here
+ //this.pointSecondary_l = pointSecondary_l; //unused in this class
+ this.colorMain_l = colorMain_l;
+ //this.colorSecondary_l = colorSecondary_l; //unused in this class
this.names_l = names_l;
this.fontHeightForBottomNames = fontHeightForBottomNames;
this.marginForBottomNames = marginForBottomNames;
@@ -774,6 +782,8 @@ public class CairoBarsNHSeries : CairoBars
{
private List<List<PointF>> pointSecondary_ll;
private List<PointF> pointMain_l;
+ private List<Cairo.Color> colorMain_l;
+ private List<Cairo.Color> colorSecondary_l;
private List<string> names_l;
private Cairo.Color colorSerieB;
@@ -978,7 +988,18 @@ public class CairoBarsNHSeries : CairoBars
if(pS.Y > 0)
{
double y = calculatePaintY(pS.Y);
- drawRoundedRectangle (true, x + adjustX, y, barWidth, graphHeight -y
-bottomMargin, 4, g, colorSerieA);
+
+ Cairo.Color barColor = colorSerieA;
+ /*
+ LogB.Information("colorSecondary_l is null: " + (colorSecondary_l ==
null).ToString());
+ LogB.Information("colorSecondary_l.Count: " +
colorSecondary_l.Count.ToString());
+ LogB.Information("pointSecondary_ll[j].Count: " +
pointSecondary_ll[j].Count.ToString());
+ */
+ //only implemented for 1 secondary_l right now
+ if(colorSecondary_l != null && colorSecondary_l.Count ==
pointSecondary_ll[j].Count)
+ barColor = colorSecondary_l[i];
+
+ drawRoundedRectangle (true, x + adjustX, y, barWidth, graphHeight -y
-bottomMargin, 4, g, barColor);
resultOnBarsThisIteration_l.Add(new Point3F(x + adjustX + barWidth/2,
y, pS.Y));
secondaryHasData = true;
@@ -994,7 +1015,14 @@ public class CairoBarsNHSeries : CairoBars
adjustX = -barDesplLeft;
double y = calculatePaintY(pB.Y);
- drawRoundedRectangle (true, x+adjustX, y, barWidth, graphHeight -y
-bottomMargin, 4, g, colorSerieB);
+
+ Cairo.Color barColor = colorSerieB;
+ //LogB.Information("colorMain_l.Count: " + colorMain_l.Count.ToString());
+ //LogB.Information("pointMain_l.Count: " + pointMain_l.Count.ToString());
+ if(colorMain_l != null && colorMain_l.Count == pointMain_l.Count)
+ barColor = colorMain_l[i];
+
+ drawRoundedRectangle (true, x+adjustX, y, barWidth, graphHeight -y
-bottomMargin, 4, g, barColor);
resultOnBarsThisIteration_l.Add(new Point3F(x + adjustX + barWidth/2, y,
pB.Y));
}
@@ -1017,10 +1045,13 @@ public class CairoBarsNHSeries : CairoBars
}
public override void GraphDo (List<PointF> pointMain_l, List<List<PointF>> pointSecondary_ll, bool
mainAtLeft,
- List<string> names_l, int fontHeightForBottomNames, int marginForBottomNames, string
title)
+ List<Cairo.Color> colorMain_l, List<Cairo.Color> colorSecondary_l, List<string>
names_l,
+ int fontHeightForBottomNames, int marginForBottomNames, string title)
{
this.pointSecondary_ll = pointSecondary_ll;
this.pointMain_l = pointMain_l;
+ this.colorMain_l = colorMain_l;
+ this.colorSecondary_l = colorSecondary_l;
this.names_l = names_l;
this.fontHeightForBottomNames = fontHeightForBottomNames;
this.marginForBottomNames = marginForBottomNames;
diff --git a/src/gui/cairo/generic.cs b/src/gui/cairo/generic.cs
index 15e487f77..2cbe4f60d 100644
--- a/src/gui/cairo/generic.cs
+++ b/src/gui/cairo/generic.cs
@@ -116,7 +116,8 @@ public abstract class CairoGeneric
{
return new Cairo.Color(red/256.0, green/256.0, blue/256.0);
}
- protected Cairo.Color colorFromGdk(Gdk.Color color)
+ //protected Cairo.Color colorFromGdk(Gdk.Color color)
+ public static Cairo.Color colorFromGdk(Gdk.Color color)
{
return new Cairo.Color(color.Red/65536.0, color.Green/65536.0, color.Blue/65536.0);
}
diff --git a/src/gui/eventExecute.cs b/src/gui/eventExecute.cs
index 714a7fc28..187b5d57b 100644
--- a/src/gui/eventExecute.cs
+++ b/src/gui/eventExecute.cs
@@ -2632,13 +2632,16 @@ public class CairoPaintBarsPreJumpSimple : CairoPaintBarsPre
List<List<PointF>> pointSecondary_ll = new List<List<PointF>>();
pointSecondary_ll.Add(pointA_l);
- cb.GraphDo (pointB_l, pointSecondary_ll, false, names_l,
+ cb.GraphDo (pointB_l, pointSecondary_ll, false,
+ new List<Cairo.Color>(), new List<Cairo.Color>(), names_l,
fontHeightForBottomNames, bottomMargin, title);
} else if (showBarA) //takeOff, takeOffWeight
- cb.GraphDo (pointA_l, new List<List<PointF>>(), false, names_l,
+ cb.GraphDo (pointA_l, new List<List<PointF>>(), false,
+ new List<Cairo.Color>(), new List<Cairo.Color>(), names_l,
fontHeightForBottomNames, bottomMargin, title);
else //rest of the jumps: sj, cmj, ..
- cb.GraphDo (pointB_l, new List<List<PointF>>(), false, names_l,
+ cb.GraphDo (pointB_l, new List<List<PointF>>(), false,
+ new List<Cairo.Color>(), new List<Cairo.Color>(), names_l,
fontHeightForBottomNames, bottomMargin, title);
}
}
@@ -2765,7 +2768,8 @@ public class CairoPaintBarsPreJumpReactive : CairoPaintBarsPre
List<List<PointF>> pointSecondary_ll = new List<List<PointF>>();
pointSecondary_ll.Add(pointA1_l);
- cb.GraphDo (pointB_l, pointSecondary_ll, false, names_l,
+ cb.GraphDo (pointB_l, pointSecondary_ll, false,
+ new List<Cairo.Color>(), new List<Cairo.Color>(), names_l,
fontHeightForBottomNames, bottomMargin, title);
}
}
@@ -2864,7 +2868,8 @@ public class CairoPaintBarsPreRunSimple : CairoPaintBarsPre
eventGraphRunsStored.personAVGAtSQL,
eventGraphRunsStored.personMINAtSQL));
- cb.GraphDo (point_l, new List<List<PointF>>(), false, names_l,
+ cb.GraphDo (point_l, new List<List<PointF>>(), false,
+ new List<Cairo.Color>(), new List<Cairo.Color>(), names_l,
fontHeightForBottomNames, bottomMargin, title);
}
}
@@ -2973,7 +2978,8 @@ public class CairoPaintBarsPreRunInterval : CairoPaintBarsPre
eventGraphRunsIntervalStored.personAVGAtSQL,
eventGraphRunsIntervalStored.personMINAtSQL));
- cb.GraphDo (point_l, new List<List<PointF>>(), false, names_l,
+ cb.GraphDo (point_l, new List<List<PointF>>(), false,
+ new List<Cairo.Color>(), new List<Cairo.Color>(), names_l,
fontHeightForBottomNames, bottomMargin, title);
}
}
@@ -3100,7 +3106,8 @@ public class CairoPaintBarsPreJumpReactiveRealtimeCapture : CairoPaintBarsPre
List<List<PointF>> pointSecondary_ll = new List<List<PointF>>();
pointSecondary_ll.Add(pointA_l);
- cb.GraphDo (pointB_l, pointSecondary_ll, false, names_l,
+ cb.GraphDo (pointB_l, pointSecondary_ll, false,
+ new List<Cairo.Color>(), new List<Cairo.Color>(), names_l,
14, 8, title);
}
}
@@ -3270,7 +3277,8 @@ public class CairoPaintBarsPreRunIntervalRealtimeCapture : CairoPaintBarsPre
sum / speed_l.Count,
min));
- cb.GraphDo (point_l, new List<List<PointF>>(), false, names_l,
+ cb.GraphDo (point_l, new List<List<PointF>>(), false,
+ new List<Cairo.Color>(), new List<Cairo.Color>(), names_l,
14, 22, title); //22 because there are two rows
}
}
@@ -3360,6 +3368,8 @@ public class CairoPaintBarplotPreEncoder : CairoPaintBarsPre
private ArrayList dataWorkJ;
private ArrayList dataImpulse;
+ private List<Cairo.Color> colorMain_l;
+ private List<Cairo.Color> colorSecondary_l;
private List<string> names_l;
//just blank the screen
@@ -3408,8 +3418,18 @@ public class CairoPaintBarplotPreEncoder : CairoPaintBarsPre
bool lastIsEcc = false;
//int count = 0;
+ colorMain_l = new List<Cairo.Color>();
+ colorSecondary_l = new List<Cairo.Color>();
names_l = new List<string>();
+ //Gdk colors from (soon deleted) encoderGraphDoPlot()
+ Gdk.Color color_ecc_con_e = new Gdk.Color();
+ Gdk.Color color_ecc_con_c = new Gdk.Color();
+ Gdk.Color color_con = new Gdk.Color();
+
+ //final color of the bar
+ Cairo.Color colorBar = new Cairo.Color();
+
//discard repetitions according to showNRepetitions
//int countToDraw = pegbe.data9Variables.Count;
//foreach(EncoderBarsData ebd in pegbe.data9Variables)
@@ -3419,21 +3439,106 @@ public class CairoPaintBarplotPreEncoder : CairoPaintBarsPre
{
EncoderBarsData ebd = (EncoderBarsData) pegbe.data9Variables[count];
+ //get phase (for color)
+ Preferences.EncoderPhasesEnum phaseEnum = Preferences.EncoderPhasesEnum.BOTH; //
(eccon == "c")
+ if (pegbe.eccon == "ec" || pegbe.eccon == "ecS") {
+ bool isEven = Util.IsEven(count +1); //TODO: check this (as for is reversed)
+ if(isEven)
+ phaseEnum = Preferences.EncoderPhasesEnum.CON;
+ else
+ phaseEnum = Preferences.EncoderPhasesEnum.ECC;
+ }
+
+ //select pen color for bars and sounds
+ string myColor = pegbe.repetitiveConditionsWin.AssignColorAutomatic(
+ RepetitiveConditionsWindow.BestSetValueEnum.CAPTURE_MAIN_VARIABLE,
ebd.GetValue(pegbe.mainVariable), phaseEnum);
+
+ bool discarded = false;
+ if(pegbe.hasInertia) {
+ if(pegbe.eccon == "c" && pegbe.discardFirstN > 0 && count <
pegbe.discardFirstN)
+ discarded = true;
+ else if(pegbe.eccon != "c" && pegbe.discardFirstN > 0 && count <
pegbe.discardFirstN * 2)
+ discarded = true;
+ }
+
+ if( ! discarded && ( myColor == UtilGtk.ColorGood || (pegbe.mainVariableHigher != -1
&& ebd.GetValue(pegbe.mainVariable) >= pegbe.mainVariableHigher) ) )
+ {
+ color_ecc_con_e = UtilGtk.GREEN_DARK;
+ color_ecc_con_c = UtilGtk.GREEN_LIGHT;
+ color_con = UtilGtk.GREEN_PLOTS;
+ //play sound if value is high, volumeOn == true, is last value, capturing
+//TODO implement later, check how we pass this variables, as cairo should not play again n times the same
while capturing
+// if(preferences.volumeOn && count == data.Count -1 && capturing)
+// Util.PlaySound(Constants.SoundTypes.GOOD, preferences.volumeOn,
preferences.gstreamer);
+ }
+ else if( ! discarded && ( myColor == UtilGtk.ColorBad || (pegbe.mainVariableLower !=
-1 && ebd.GetValue(pegbe.mainVariable) <= pegbe.mainVariableLower) ) )
+ {
+ color_ecc_con_e = UtilGtk.RED_DARK;
+ color_ecc_con_c = UtilGtk.RED_LIGHT;
+ color_con = UtilGtk.RED_PLOTS;
+ //play sound if value is low, volumeOn == true, is last value, capturing
+ if(pegbe.volumeOn && count == 0 -1 && pegbe.capturing)
+ Util.PlaySound(Constants.SoundTypes.BAD, pegbe.volumeOn,
pegbe.gstreamer);
+ }
+ else if(myColor == UtilGtk.ColorGray)
+ {
+ /*
+ * on ecS when feedback is only in the opposite phase,
+ * AssignColorAutomatic will return ColorGray
+ * this helps to distinguins the phase that we want
+ */
+ color_ecc_con_e = UtilGtk.GRAY;
+ color_ecc_con_c = UtilGtk.GRAY;
+ color_con = UtilGtk.GRAY;
+ }
+ else {
+ color_ecc_con_e = UtilGtk.BLUE_DARK;
+ color_ecc_con_c = UtilGtk.BLUE_LIGHT;
+ color_con = UtilGtk.BLUE_PLOTS;
+ }
+
+ //know if ecc or con to paint with dark or light pen
+ if (pegbe.eccon == "ec" || pegbe.eccon == "ecS") {
+ bool isEven = Util.IsEven(count +1);
+
+ //on inertial if discardFirstN , they have to be gray
+ if( pegbe.hasInertia && pegbe.discardFirstN > 0 &&
+ ((pegbe.eccon == "c" && count < pegbe.discardFirstN) ||
(pegbe.eccon != "c" && count < pegbe.discardFirstN * 2)) )
+ colorBar = CairoGeneric.colorFromGdk(UtilGtk.GRAY);
+ else {
+ if(isEven) //par, concentric
+ colorBar = CairoGeneric.colorFromGdk(color_ecc_con_c);
+ else
+ colorBar = CairoGeneric.colorFromGdk(color_ecc_con_e);
+ }
+ } else {
+ if( pegbe.hasInertia && pegbe.discardFirstN > 0 &&
+ ((pegbe.eccon == "c" && count < pegbe.discardFirstN) ||
(pegbe.eccon != "c" && count < pegbe.discardFirstN * 2)) )
+ colorBar = CairoGeneric.colorFromGdk(UtilGtk.GRAY);
+ else
+ colorBar = CairoGeneric.colorFromGdk(color_con);
+ }
+
+
if(pegbe.eccon == "c")
{
dataA_l.Add(new PointF(count +1, ebd.GetValue(pegbe.mainVariable)));
+ colorMain_l.Add(colorBar);
names_l.Add((count +1).ToString());
} else
{
if(! Util.IsEven(count +1)) //if it is "impar"
{
dataA_l.Add(new PointF(UtilAll.DivideSafe(count+1,2),
ebd.GetValue(pegbe.mainVariable)));
+ colorSecondary_l.Add(colorBar);
names_l.Add((UtilAll.DivideSafe(count,2) +1).ToString());
- } else // "par"
+ } else {// "par"
dataB_l.Add(new PointF(UtilAll.DivideSafe(count+1,2),
ebd.GetValue(pegbe.mainVariable)));
+ colorMain_l.Add(colorBar);
+ }
}
- //TODO: copy stuff from /gui/encoderGraphObjects fillDataVariables()
+ //TODO: copy more stuff from /gui/encoderGraphObjects fillDataVariables()
}
}
@@ -3466,13 +3571,15 @@ public class CairoPaintBarplotPreEncoder : CairoPaintBarsPre
cb.Decs = decs;
if(pegbe.eccon == "c")
- cb.GraphDo (dataA_l, new List<List<PointF>>(), false, names_l,
+ cb.GraphDo (dataA_l, new List<List<PointF>>(), false,
+ colorMain_l, new List<Cairo.Color>(), names_l,
14, 8, "my title");
else {
List<List<PointF>> pointSecondary_ll = new List<List<PointF>>();
pointSecondary_ll.Add(dataA_l);
- cb.GraphDo (dataB_l, pointSecondary_ll, false, names_l,
+ cb.GraphDo (dataB_l, pointSecondary_ll, false,
+ colorMain_l, colorSecondary_l, names_l,
14, 8, "my title");
}
}
diff --git a/src/gui/usefulObjects.cs b/src/gui/usefulObjects.cs
index 240272ba7..bfdaf05df 100644
--- a/src/gui/usefulObjects.cs
+++ b/src/gui/usefulObjects.cs
@@ -402,6 +402,9 @@ public class PrepareEventGraphBarplotEncoder
public bool relativeToSet;
public double maxPowerSpeedForceIntersession; //it will be one of these 3
public string maxPowerSpeedForceIntersessionDate;
+ public int discardFirstN;
+ public bool volumeOn;
+ public Preferences.GstreamerTypes gstreamer;
public PrepareEventGraphBarplotEncoder () {
}
@@ -414,7 +417,9 @@ public class PrepareEventGraphBarplotEncoder
bool hasInertia, bool playSoundsFromFile,
ArrayList data9Variables, Gtk.ListStore encoderCaptureListStore,
bool relativeToSet,
- double maxPowerSpeedForceIntersession, string maxPowerSpeedForceIntersessionDate)
+ double maxPowerSpeedForceIntersession, string maxPowerSpeedForceIntersessionDate,
+ int discardFirstN, bool volumeOn, Preferences.GstreamerTypes gstreamer)
+
{
this.mainVariable = mainVariable;
this.mainVariableHigher = mainVariableHigher;
@@ -431,6 +436,9 @@ public class PrepareEventGraphBarplotEncoder
this.relativeToSet = relativeToSet;
this.maxPowerSpeedForceIntersession = maxPowerSpeedForceIntersession;
this.maxPowerSpeedForceIntersessionDate = maxPowerSpeedForceIntersessionDate;
+ this.discardFirstN = discardFirstN;
+ this.volumeOn = volumeOn;
+ this.gstreamer = gstreamer;
}
~PrepareEventGraphBarplotEncoder () {}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]