<jupyter_start><jupyter_text>Vector Geometry IntroThis is how we described the 3D geometry we were using 40 years ago. I've been looking for a betterdescription of what this really is and the best I can find is linear algebra applied to 3D geometry.In thelast section we were initially trying to find the target position relative to the camera; then mappingthat back to the target position relative to the robot; and then mapping that back to the robotposition relative to the field. This required a lot of special math derived for the specificgeometry of the current robot with the currentcamera mounting. This is really complicated; hard to wrap your head around; and if things change in themounting of the camera on the robot, then we need to re-derive the equations and reprogram the calculations.We want a more generalized and simple way to describe this system of frames of reference and mappingbetween them that is simple to customize for any camera mounting, or for multiple cameras. And this is wherevector geometry comes in. It lets us use constants for the camera position and angles relative to the centerof the robot, etc.; and, if we change the mounting of the camera we merely change those constants, and therest of the math just works. The Elements of Vector GeometryThere are several elements of vector geometry that we will talk about:* **local coordinate systems** - coordinate systems where the origin and axes are generally *attached* to  an object (like the camera, the robot, the game field), and if you move the object, the coordinate system  moves with it and all the bits associated with the object move together and stay in the same configuration  relative to the coordinate system;* **point** - a position expressed in term of a coordinate system;* **vector** - expresses moving from one point to another point in terms of direction and distance;* **plane** - a surface that divides space into an *inside* and an *outside*;* **transformation** - a mapping from the coordinate system of one object (the robot) to another  coordinate system (the field).  Local Coordinate SystemsCoordinate systems consist of an origin, and X, Y, and X axes which are mutually perpendicular. We have 3local coordinate systems we are worried about for figuring out where our robot is on the field:* ***the camera*** - All the limelight feedback is relative to the camera (relative to the coordinate system  of the camera);* ***the robot*** - All the bits and pieces of the robot (including the camera) are located relative to the  coordinate system of the robot;* ***the field*** - Ultimately, everything relevant to the game, like the game field, game elements, our  robot, and other robots have a position on the field. We need to know where we are on the field to make  good decisions about what our robot should be doing. The Camera Axis SystemSo, lets take a closed look at what a coordinate system is, and how it works in the formalization of vectorgeometry. We start by looking at the limelight and its software. The first thing we notice is that the limelighthas an +X axis to the right and a +Y axis up relative to the screen, and we usually think of distance from thelens as the +Z axiz. The limelight software expresses everything relative to the screen, so we get a horizontal angle (which is really a rotation around the Y axis), and an elevation angle (which is really a rotation aboutthe X axis):![alt text](./resources/camera_coordinates.jpg "limelight camera coordinates")This is a *left-handed* axis system. If you hold out your left hand and point your thumb in the +X direction;point your index finger in the +Y direction; and bend the rest of your fingers to about 90&deg; from the palmof your hand - they are pointing away from you, in the +Z direction. If you do the same with your right handthe +Z will be pointing towards you. To flip a left handed coordinate system into a right handed coordinatesystem we can just multiply Z by -1. The Robot Axis System***Write This*** The field Axis System***Write This***  PointA point is simply the position of a point in space specified by the X, Y, and Z position relative to thecoordinate system (2D graphing extended to 3D). To represent it we need a class that contains theX, Y, and Z coordinates.<jupyter_code>class Point3d 
{
    double m_x = 0.0;
    double m_y = 0.0;
    double m_z = 0.0;
    
    public Point3d()
    {
    
    }
    
    public Point3d(double x, double y, double z)
    {
        m_x = x;
        m_y = y;
        m_z = z;
    }
    
    public double getX()
    {
        return m_x;
    }
    
    public double getY()
    {
        return m_y;
    }
    
    public double getZ()
    {
        return m_z;
    }
    
    /**
     */
    public double distance(Point3d pt)
    {
        double dx = m_x - pt.getX();
        double dy = m_y - pt.getY();
        double dz = m_z - pt.getZ();
        return Math.sqrt((dx * dx) + (dy * dy) + (dz * dz));
    }
}
// a point at the origin
Point3d pt1 = new Point3d();
// a point at some position
Point3d pt2 = new Point3d(-3.0,3.0,5.0);
// get the distance between the points
pt1.distance(pt2);<jupyter_output><empty_output><jupyter_text>VectorA vector represents a displacement (direction and distance) between two points. While vectors of this type areuseful, it is far more common to express vectors as unit vectors or direction vectors (vectors of length = 1.0),and then talk about the displacement between two points as a dirction (the unit or direction vector) and adistance. One really good reason to do this is because directions can be transformed between coordinate systems(which we will talk about in the next lecture).What follows is some code for a vector. We use i, j, and k as the direction elements of the vector as these arethe multipliers for the unit vectors I, J, and K in the direction of the X, Y, and Z axes respectively:<jupyter_code>class Vector3d {
    double m_i = 1.0;
    double m_j = 0.0;
    double m_k = 0.0;
    
    /**
     * Instantiate a unit vector in the X direction.
     */
    public Vector3d()
    {
    }
    
    /**
     * Instantiate a vector set to some i, j, k.
     */
    public Vector3d(double i, double j, double k)
    {
        m_i = i;
        m_j = j;
        m_k = k;
    }
    
    /**
     * Instnatiate a copy of a vector
     */
    public Vector3d(Vector3d v)
    {
        m_i = v.m_i;
        m_j = v.m_j;
        m_k = v.m_k;
    }
    
    /**
     * Instantiate a vector from a start point to and end point. This will be an
     * unnormalized vector.
     */
    public Vector3d(Point3d start, Point3d end)
    {
        m_i = end.getX() - start.getX();
        m_j = end.getY() - start.getY();
        m_k = end.getZ() - start.getZ();
    }
    
    /**
     * Get the I component of the vector
     */
    public double getI()
    {
        return m_i;
    }
    
    /**
     * Get the J component of the vector
     */
    public double getJ()
    {
        return m_j;
    }
    
    /**
     * Get the K component of the vector
     */
    public double getK()
    {
        return m_k;
    }

    /**
     * Get the length of this vector.
     */
    public double length()
    {
        return Math.sqrt((m_i * m_i) + (m_j * m_j) + (m_k * m_k));
    }

    /**
     * Normalized this vector to a unit or direction vector.
     */
    public Vector3d normalize()
    {
        return scale(1.0/length());
    }
    
    /**
     * Scale the components of this vector by the specified scale.
     */
    public Vector3d scale(double scale)
    {
        m_i *= scale;
        m_j *= scale;
        m_k *= scale;
        return this;
    }
    
    /**
     * Gets the dot product between this vector and another vector, <tt>v</tt>.
     * @param v The vector against which we take the dot product.  The value of this vector is unchanged.
     * @return Returns the dot product between this vector and vector <tt>v</tt>.
     */
    public double dot(final Vector3d v) {
        return (m_i * v.m_i) + (m_j * v.m_j) + (m_k * v.m_k);
    }
}<jupyter_output><empty_output><jupyter_text>Now that we have a basic `Vector3d` class, let's create a vector between `pt1` and `pt2` from the last section,and check out how normalization works:<jupyter_code>Vector3d targetDir = new Vector3d(pt1, pt2);
System.out.println("initial i,j,k = " + targetDir.getI() + ", " + targetDir.getJ() + ", " + targetDir.getK());
System.out.println("initial length = " + targetDir.length());
targetDir.normalize();
System.out.println("normalized i,j,k = " + targetDir.getI() + ", " + targetDir.getJ() + ", " + targetDir.getK());
System.out.println("normalized length = " + targetDir.length());<jupyter_output>initial i,j,k = -3.0, 3.0, 5.0
initial length = 6.557438524302
normalized i,j,k = -0.457495710997814, 0.457495710997814, 0.7624928516630234
normalized length = 1.0<jupyter_text>A really interesting property of unit vectors is the *dot product*, which is the sum of the componentsmultiplied together. That is, for vectors `V1` and `V2` the dot product is `(V1.m_i * V2.m_i) + (V1.m_j * V2.m_j) + (V1.m_k * V2.m_k)` which is the cosine of the angle between the two vectors regardless of their orientationin space. Let's test this out. We can use some points in the XY plane to generate fome vectors. we will use`(0.0,0.0,0.0)` as the origin, and the end points `(1.0,0.0,0.0)` - straight ahead for the robot; `(1.0,-1.0,0.0)`-to the left at 45&deg; `(0.0,-1.0,0.0)` - to the left at 90&deg;; and `(-1.0,0.0,0.0)` - directly backwards:<jupyter_code>Point3d ptOrigin = new Point3d(0.0, 0.0, 0.0);
Point3d ptForward = new Point3d(1.0, 0.0, 0.0);
Point3d ptLeft45 = new Point3d(1.0, -1.0, 0.0);
Point3d ptLeft90 = new Point3d(0.0, -1.0, 0.0);
Point3d ptLeft180 = new Point3d(-1.0, 0.0, 0.0);

// These are the normalized (unit) vectors generated from the origin to the points
Vector3d vForward = new Vector3d(ptOrigin,ptForward).normalize();
Vector3d vLeft45 = new Vector3d(ptOrigin,ptLeft45).normalize();
Vector3d vLeft90 = new Vector3d(ptOrigin,ptLeft90).normalize();
Vector3d vLeft180 = new Vector3d(ptOrigin,ptLeft180).normalize();

// and these are the dot products
System.out.println("dot forward = " + vForward.dot(vForward) + ", expected " + Math.cos(Math.toRadians(0.0)));
System.out.println("dot left 45 = " + vForward.dot(vLeft45) + ", expected " + Math.cos(Math.toRadians(-45.0)));
System.out.println("dot left 90 = " + vForward.dot(vLeft90) + ", expected " + Math.cos(Math.toRadians(-90.0)));
System.out.println("dot left 180 = " + vForward.dot(vLeft180) + ", expected " + Math.cos(Math.toRadians(-180.0)));<jupyter_output>dot forward = 1.0, expected 1.0
dot left 45 = 0.7071067811865475, expected 0.7071067811865476
dot left 90 = 0.0, expected 6.123233995736766E-17
dot left 180 = -1.0, expected -1.0<jupyter_text>Note that this exposes one of the problems with digital computations - there is round off error incomputations. So you see the `dot left 45` and `dot left 90` do not exactly match the expected, butonly differ by the 15th or 16th decimal digit. So, they can be considered to be equal.To demonstrate the usefulness of the dot product, let's twist the previous example so our forward is`(1.0,1.0,0.0)`; our 45&deg; is `(1.0,1.0,1.0)`; our 90&deg; is `(0.0,0.0,1.0)`; and our backwards is`(-1.0,-1.0,0.0)`:<jupyter_code>Point3d pt2Origin = new Point3d(0.0, 0.0, 0.0);
Point3d pt2Forward = new Point3d(1.0, 1.0, 0.0);
Point3d pt2Left45 = new Point3d(Math.cos(Math.toRadians(45.0)), Math.cos(Math.toRadians(45.0)), 1.0);
Point3d pt2Left90 = new Point3d(0.0, 0.0, 1.0);
Point3d pt2Left180 = new Point3d(-1.0, -1.0, 0.0);

// These are the normalized (unit) vectors generated from the origin to the points
Vector3d v2Forward = new Vector3d(pt2Origin,pt2Forward).normalize();
Vector3d v2Left45 = new Vector3d(pt2Origin,pt2Left45).normalize();
Vector3d v2Left90 = new Vector3d(pt2Origin,pt2Left90).normalize();
Vector3d v2Left180 = new Vector3d(pt2Origin,pt2Left180).normalize();

// and these are the dot products
System.out.println("dot forward = " + v2Forward.dot(v2Forward) + ", expected " + Math.cos(Math.toRadians(0.0)));
System.out.println("dot left 45 = " + v2Forward.dot(v2Left45) + ", expected " + Math.cos(Math.toRadians(-45.0)));
System.out.println("dot left 90 = " + v2Forward.dot(v2Left90) + ", expected " + Math.cos(Math.toRadians(-90.0)));
System.out.println("dot left 180 = " + v2Forward.dot(v2Left180) + ", expected " + Math.cos(Math.toRadians(-180.0)));<jupyter_output>dot forward = 0.9999999999999998, expected 1.0
dot left 45 = 0.7071067811865475, expected 0.7071067811865476
dot left 90 = 0.0, expected 6.123233995736766E-17
dot left 180 = -0.9999999999999998, expected -1.0<jupyter_text>Once again, we see there is roundoff error and that the dot products are within the 15th or 16th decimal digitof the expected value.  LineA line has been a missing piece in our discussion so far. There are a couple ways to think about a line, andthey both revolve around thequestion of why are you representing the line and what do you want to do with that representation. For example, ifwe want to generate points on a line we probably want an *explicit* representation, and the most useful I've found is a parametric representation which has a start point (like the camera lens), a unit direction, and if you specify the distance, it generates the coordinates of the point at that distance from the start point. The next most usefulis an *implicit*represention which lets you test a point for closeness to the line (in the computation world there is always some round-off error, so there is a question of how close is *ON* the line).In the 2020-2021 season the path generator used set of lines to represent the path the robot position is the start of a line and the robot moves in some direction for the duration of a command, which generates the start point for the next segment of the path.Let's write a little code for a `Line3d`:<jupyter_code>public class Line3d {
    /**
     * The starting point of the line.
     */
    final Point3d m_origin = new Point3d();

    /**
     * The direction of the line.  NOTE: in typical use, the direction vector is
     * normalized so that points a given distance from the starting point can be simply
     * generated by adding the direction vector scaled by the distance to the starting
     * point.  However, normalization of the direction vector is not enforced by the
     * <code>Line3d</code> class, and must be controlled by the user of the class.
     */
    final Vector3d m_direction = new Vector3d();

    /**
     * Creates a new instance of <code>Line3d</code>.
     */
    public Line3d() {
    }

    /**
     * Creates a new instance of <code>Line3d</code>.
     *
     * @param ptOrg The origin of the line.
     * @param vDir  The direction of the line. NOTE: the direction is used as given and is not normalized
     *              during initialization.
     */
    public Line3d(final Point3d ptOrg, final Vector3d vDir) {
        m_origin.m_x = ptOrg.m_x;
        m_origin.m_y = ptOrg.m_y;
        m_origin.m_z = ptOrg.m_z;
        m_direction.m_i = vDir.m_i;
        m_direction.m_j = vDir.m_j;
        m_direction.m_k = vDir.m_k;
      }

    /**
     * Creates a new instance of <code>Line3d</code>.
     *
     * @param ptOrg  The origin of the line.
     * @param ptThru A point the line passes through.  The direction of the line is from the origin to this
     *               point, and is normalized during initialization.
     */
    public Line3d(final Point3d ptOrg, final Point3d ptThru) {
        origin.m_x = ptOrg.m_x;
        origin.m_y = ptOrg.m_y;
        origin.m_z = ptOrg.m_z;
        m_direction.m_i = ptThru.getX() - ptOrg.getX();
        m_direction.m_j = ptThru.getY() - ptOrg.getY();
        m_direction.m_k = ptThru.getZ() - ptOrg.getZ();
        m_direction.normalize();
    }

    public Point3d getPointOnLine(double distance) {
        return new Point3d(m_origin.m_x + (distance * m_direction.m_i),
                           m_origin.m_y + (distance * m_direction.m_j),
                           m_origin.m_z + (distance * m_direction.m_k));
    }
 }<jupyter_output><empty_output><jupyter_text>OK, so what can we do with this? Let's make some simple examples that are hopefully relevant to robots. We can start by asuming our robot starts at `(0.0,0.0,0.0)` on the field and ask where is it if it moves 3m in X, Y, or Z (not likely unless our robot is a drone), or at 45&deg; between X and Y; or towards `(1.0,1.0,1.0)` on the field (again, not likely):<jupyter_code>Point3d origin = new Point3d(0.0, 0.0, 0.0);
Line3d lineX = new Line3d(origin, new Vector3d(1.0,0.0,0.0));
System.out.print("On X:       ");
for (double dist = 0; dist < 5; dist += 1.0) {
    Point3d pt =  lineX.getPointOnLine(dist);
    System.out.print(String.format("(%5.3f,%5.3f,%5.3f)", pt.getX(), pt.getY(), pt.getZ()));
}
Line3d lineY = new Line3d(origin, new Vector3d(0.0,1.0,0.0));
System.out.print("\nOn Y:       ");
for (double dist = 0; dist < 5; dist += 1.0) {
    Point3d pt =  lineY.getPointOnLine(dist);
    System.out.print(String.format("(%5.3f,%5.3f,%5.3f)", pt.getX(), pt.getY(), pt.getZ()));
}
Line3d lineZ = new Line3d(origin, new Vector3d(0.0,0.0,1.0));
System.out.print("\nOn Z:       ");
for (double dist = 0; dist < 5; dist += 1.0) {
    Point3d pt =  lineZ.getPointOnLine(dist);
    System.out.print(String.format("(%5.3f,%5.3f,%5.3f)", pt.getX(), pt.getY(), pt.getZ()));
}
Line3d lineXYZ = new Line3d(origin, new Point3d(1.0,1.0,1.0));
System.out.print("\nBisect XYZ: ");
for (double dist = 0; dist < 5; dist += 1.0) {
    Point3d pt =  lineXYZ.getPointOnLine(dist);
    System.out.print(String.format("(%5.3f,%5.3f,%5.3f)", pt.getX(), pt.getY(), pt.getZ()));
}<jupyter_output>On X:       (0.000,0.000,0.000)(1.000,0.000,0.000)(2.000,0.000,0.000)(3.000,0.000,0.000)(4.000,0.000,0.000)
On Y:       (0.000,0.000,0.000)(0.000,1.000,0.000)(0.000,2.000,0.000)(0.000,3.000,0.000)(0.000,4.000,0.000)
On Z:       (0.000,0.000,0.000)(0.000,0.000,1.000)(0.000,0.000,2.000)(0.000,0.000,3.000)(0.000,0.000,4.000)
Bisect XYZ: (0.000,0.000,0.000)(0.577,0.577,0.577)(1.155,1.155,1.155)(1.732,1.732,1.732)(2.309,2.309,2.309)<jupyter_text>PlaneIn 3D a plane divides space into the space in front of the plane and the space behind the plane. The plane equation is `Ax + By + Cz + D = 0.0` and all of the coefficients have a physical significance. `A`, `B`,and `C` are the vector perpendicular to the plane. If this perpendicular vector is normalized, then `D` is thedistance from the origin to the plane along the perpendicular vector. Yeah, that was a lot to digest.Let's try a simple example, let's think about the YZ plane in 3D, that is the plane that the Y and Z axislie on (in field geometry, this would correspond to a side wall). The X axis is perpendicular to the YZplane. So let's think about why we would use a plane in 3d. One thing that comes to mind is that it wouldbe bad if the robot crashes into the wall or an obsticle on the field. In the 2020-2021 swerve planner wecolored the robot red if the path was outside the field - how did we do that? We tested the positions of the corners of the robot against the planes of the walls of the field - if any corner when outside the wallsof the field (with some tolerance) then we colored the robot red.OK, time to build a little code for this:<jupyter_code>public class Plane3d{
    /**
     * The <b>A</b> coefficient of the plane equation.
     */
    public double m_A;

    /**
     * The <b>B</b> coefficient of the plane equation.
     */
    public double m_B;

    /**
     * The <b>C</b> coefficient of the plane equation.
     */
    public double m_C;

    /**
     * The <b>D</b> coefficient of the plane equation.
     */
    public double m_D;

    /**
     * Instantiates an initialized instance of <code>Plane3d</code>.
     *
     * @param A The <b>A</b> coefficient of the plane equation.
     * @param B The <b>B</b> coefficient of the plane equation.
     * @param C The <b>C</b> coefficient of the plane equation.
     * @param D The <b>D</b> coefficient of the plane equation.
     */
    public Plane3d(final double A, final double B, final double C, final double D) {
        m_A = A;
        m_B = B;
        m_C = C;
        m_D = D;
    }

    /**
     * Instantiates an initialized instance of <code>Plane3d</code> for a plane that has
     * the specified normal and passes through the specified point.
     *
     * @param normal The normal of the plane. NOTE: the normal is not re-normalized as part of the
     *               initialization.  If there is any question about whether the normal is a unit vector,
     *               then the plane should be normalized after instantiation.
     * @param pt     A point on the plane
     */
    public Plane3d(final Vector3d normal, final Point3d pt) {
        m_A = normal.m_i;
        m_B = normal.m_j;
        m_C = normal.m_k;
        m_D = -((m_A * pt.m_x) + (m_B * pt.m_y) + (m_C * pt.m_z));
    }

    /**
     * Normalizes the plane equation coefficients so that the normal, <b>A</b>,<b>B</b>,<b>C</b>, is a unit vector.
     *
     * @return Returns this plane after normalization.
     */
    public Plane3d normalize() {
        final double dLength = Math.sqrt((m_A * m_A) + (m_B * m_B) + (m_C * m_C));
        final double dScale = 1.0f / dLength;
        m_A *= dScale;
        m_B *= dScale;
        m_C *= dScale;
        m_D *= dScale;
        return this;
    }
    
    /** Get the perpendicular distance from a plane to a point
     *
     * @param pt The point to test.
     * @return The distance from the point to the plane.
     */
    public double distance(Point3d pt) {
        return (m_A * pt.m_x) + (m_B * pt.m_y) + (m_C * pt.m_z) + m_D;
    }
}<jupyter_output><empty_output><jupyter_text>Now we have a class that represents a plane, let's create the YZ plane we talked about earlier and test acouple points for distance:<jupyter_code>Plane3d planeYZ = new Plane3d(new Vector3d(1.0, 0.0, 0.0), new Point3d(0.0, 0.0, 0.0));
// Let's build a line along the X axis and check distance from points on the line to the plane
Line3d lineX = new Line3d(origin, new Vector3d(1.0,0.0,0.0));
System.out.println("Distance for points on X:");
for (double dist = -5; dist < 5; dist += 1.0) {
    Point3d pt =  lineX.getPointOnLine(dist);
    System.out.println(String.format("    pt: (%6.3f,%6.3f,%6.3f); distance: %6.3f",
        pt.getX(), pt.getY(), pt.getZ(), planeYZ.distance(pt)));
}<jupyter_output>Distance for points on X:
    pt: (-5.000, 0.000, 0.000); distance: -5.000
    pt: (-4.000, 0.000, 0.000); distance: -4.000
    pt: (-3.000, 0.000, 0.000); distance: -3.000
    pt: (-2.000, 0.000, 0.000); distance: -2.000
    pt: (-1.000, 0.000, 0.000); distance: -1.000
    pt: ( 0.000, 0.000, 0.000); distance:  0.000
    pt: ( 1.000, 0.000, 0.000); distance:  1.000
    pt: ( 2.000, 0.000, 0.000); distance:  2.000
    pt: ( 3.000, 0.000, 0.000); distance:  3.000
    pt: ( 4.000, 0.000, 0.000); distance:  4.000<jupyter_text>And let's try this again for a plane normal from the origin to `(1.0,1.0,1.0)` at a distance of 4 fromthe origin, which would be through the point`(2.309,2.309,2.309)` from our previous line example:<jupyter_code>Plane3d planeYZ = new Plane3d(new Vector3d(1.0, 1.0, 1.0).normalize(), new Point3d(2.309,2.309,2.309));
// Let's build a line along the X axis and check distance from points on the line to the plane
Line3d lineXYZ = new Line3d(origin, new Point3d(1.0,1.0,1.0));
System.out.println("Distance for points on the XYZ trisection:");
for (double dist = 0; dist < 10; dist += 1.0) {
    Point3d pt =  lineXYZ.getPointOnLine(dist);
    System.out.println(String.format("    pt: (%6.3f,%6.3f,%6.3f); distance: %6.3f",
        pt.getX(), pt.getY(), pt.getZ(), planeYZ.distance(pt)));
}<jupyter_output>Distance for points on the XYZ trisection:
    pt: ( 0.000, 0.000, 0.000); distance: -3.999
    pt: ( 0.577, 0.577, 0.577); distance: -2.999
    pt: ( 1.155, 1.155, 1.155); distance: -1.999
    pt: ( 1.732, 1.732, 1.732); distance: -0.999
    pt: ( 2.309, 2.309, 2.309); distance:  0.001
    pt: ( 2.887, 2.887, 2.887); distance:  1.001
    pt: ( 3.464, 3.464, 3.464); distance:  2.001
    pt: ( 4.041, 4.041, 4.041); distance:  3.001
    pt: ( 4.619, 4.619, 4.619); distance:  4.001
    pt: ( 5.196, 5.196, 5.196); distance:  5.001
{'fraction_non_alphanumeric': 0.11454411523981012, 'fraction_numerical': 0.05790636765428057, 'mean_word_length': 3.093985592226504, 'pattern_counts': {'":': 0, '<': 79, '<?xml version=': 0, '>': 73, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '217917', 'license': 'Apache-2.0', 'n_tokens_mistral': 8837, 'n_tokens_neox': 8069, 'n_words': 3014, 'path': 'jupyter/13 - Vector Geometry - Intro, Points, Vectors, Lines, and Planes.ipynb', 'repo_name': 'STHobbes/Java_for_FRC', 'size': '24436'}