text:
<file_sep># FTC Rover Ruckus
> Rover Ruckus robot code created by the programmers of Team Blue Shift [FTC5549].

[![Build Status](https://travis-ci.org/BlueShift-FTC5549/Rover-Ruckus.svg?branch=master)](https://travis-ci.org/BlueShift-FTC5549/Rover-Ruckus)

![](BlueShiftLogo.png)

This repository is the version control hub of Team Blue Shift [FTC5549] for the FIRST Tech Challenge 2018-2019 event "Rover Ruckus". Updating nearly daily, the repository will include a collection of Autonomous and TeleOP programs as well as custom libraries and objects used during our team's competition matches.

Blue Shift shares all of our code so that other teams may learn from our programming and so that we may also learn from others. We are completely transparent with our progress.

## Release History

* 0.11.0
    * Added the auxiliary autonomous library
    * Includes liftDrop functionality
* 0.10.0
    * Autonomous Library Reorganization
    * Cube Finder Update with Scanning
    * Robot Constant Tuning
* 0.9.0
    * Auto-Diagnostics Fix
    * Auto-Calibration Creation
    * Encoder Drive Fix
* 0.8.0
    * DogeCV Integration
    * Verbose Autonomous Loops (Telemetry)
    * Gold-Cube Alignment Function
* 0.7.0
    * Four wheel drive Update
    * Turning drive timeout function
    * Autonomous abort motion function
* 0.6.0
    * Encoder drive fix
    * Encoder drive timeout function
    * AutoTwoWheelDrive constructor fix
* 0.5.0
    * Archival Structure Implementation
    * All Three TeleOP Variations
    * Name Refactor for TeleOP Variations
* 0.4.0
    * Turning Code Pre-Final
* 0.3.0
    * Autonomous Linear Conversion
    * Gyro Turning Method Examples
    * Blue Shift Utilities Fix
* 0.2.0
    * Auto Encoder Drive
    * IMU Code Update
    * Blue Shift Utilities
* 0.1.0
    * TeleOP Skeleton
    * Autonomous Library Skeleton
    * IMU & PID Controller Skeleton

Base application [ftc_app]: https://github.com/ftctechnh/ftc_app.

## Meta

<NAME> – [gabrieljw1](https://github.com/gabrieljw1/) – <EMAIL>

<NAME>  - [robo19](https://github.com/robo19/) - <EMAIL>

<NAME>  - [jjoon137](https://github.com/jjoon137/) - <EMAIL>

[https://github.com/BlueShift-FTC5549/Rover-Ruckus](https://github.com/BlueShift-FTC5549/)
<file_sep>/* Copyright (c) 2018 Blue Shift Robotics
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.blueshiftrobotics.ftc;

/**
 * A collection of utilities useful in the Blue Shift libraries.
 *
 * @author <NAME>
 */
public class BlueShiftUtil {

    /**
     * @param theta_1 The first angle
     * @param theta_2 The second angle
     * @return the difference between to angles in the range [-180, 180].
     */
    public static double getDegreeDifference(double theta_1, double theta_2) {
        double rawDifference = theta_2 - theta_1;

        if (rawDifference > 180) {
            return rawDifference - 360;
        } else if (rawDifference < -180) {
            return rawDifference + 360;
        } else {
            return rawDifference;
        }
    }

    /**
     * Calculate the Mean Absolute Error of a given array from a given target value. Useful for
     * getting the average deviation from some target value for every value in an array. Modified
     * by also taking the absolute value of the array value and target before computing difference.
     *
     * @param array Array of values
     * @param target Target Value
     * @return Mean Absolute Eror
     */
    public static double modifiedMeanAbsoluteError(int[] array, int target) {
        double sum = 0;
        double signedSum = 0;

        //Motor indeces 1 and 2 move backward compared to 0 and 4, so they are negative
        sum += Math.abs(array[0] - target);
        sum += Math.abs(-array[1] - target);
        sum += Math.abs(-array[2] - target);
        sum += Math.abs(array[3] - target);
        signedSum += array[0] - target;
        signedSum += -array[1] - target;
        signedSum += -array[2] - target;
        signedSum += array[3] - target;

        return Math.signum(signedSum) * (sum / ((double)array.length));
    }

    /**
     * Perform the sigmoid function for a given value `x`. Equal to (1 / (1+e^(-x))). Useful because
     * it is a smooth logistic curve.
     *
     * @param x Value to sigmoid.
     * @return Sigmoid value of x.
     */
    public static double sigmoid(double x) {
        return Math.pow(1.0 + Math.exp(-x), -1.0);
    }

    /**
     * Perform the derivative of the sigmoid function for a given value `x`. Equal to sigmoid *
     * (1 - sigmoid). Shifted to the right by 0.5 to have the peak at 0.5, `x` is scaled by 5 to
     * compress the curve horizontally, and the entire function is multiplied by 3.0 to have `y`
     * peak at 0.75.
     *
     * @param x
     * @return
     */
    public static double modifiedSigmoidPrime(double x) {
        return 3.0*sigmoid(5.0*(x-0.5)) * (1.0 - sigmoid(5.0*(x-0.5)));
    }
}
<file_sep>package com.blueshiftrobotics.ftc.archive;

import com.blueshiftrobotics.ftc.IMU;
import com.qualcomm.hardware.bosch.BNO055IMU;
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.DcMotorSimple;
import com.qualcomm.robotcore.util.ElapsedTime;

import org.firstinspires.ftc.robotcore.external.navigation.AngleUnit;
import org.firstinspires.ftc.robotcore.external.navigation.AxesOrder;
import org.firstinspires.ftc.robotcore.external.navigation.AxesReference;

/**
 * This file contains an example of an iterative (Non-Linear) "OpMode".
 * An OpMode is a 'program' that runs in either the autonomous or the teleop period of an FTC match.
 * The names of OpModes appear on the menu of the FTC Driver Station.
 * When an selection is made from the menu, the corresponding OpMode
 * class is instantiated on the Robot Controller and executed.
 *
 * This particular OpMode just executes a basic Tank Drive Teleop for a two wheeled robot
 * It includes all the skeletal structure that all iterative OpModes contain.
 *
 * Use Android Studios to Copy this Class, and Paste it into your team's code folder with a new name.
 * Remove or comment out the @Disabled line to add this opmode to the Driver Station OpMode list
 */

@Disabled
@TeleOp(name="Kevin IMU", group="Sense")
public class Sense_IMU_Kevin extends OpMode
{
    // Declare OpMode members.
    private ElapsedTime runtime = new ElapsedTime();
    DcMotor left, right;
    IMU imu;

    /*
     * Code to run ONCE when the driver hits INIT
     */
    @Override
    public void init() {
        imu = new IMU(hardwareMap, "imu");
        left = hardwareMap.get(DcMotor.class, "left");
        right = hardwareMap.get(DcMotor.class, "right");

        left.setDirection(DcMotorSimple.Direction.FORWARD);
        right.setDirection(DcMotorSimple.Direction.REVERSE);
    }

    /*
     * Code to run REPEATEDLY after the driver hits INIT, but before they hit PLAY
     */
    @Override
    public void init_loop() {
    }

    /*
     * Code to run ONCE when the driver hits PLAY
     */
    @Override
    public void start() {
        runtime.reset();
    }

    /*
     * Code to run REPEATEDLY after the driver hits PLAY but before they hit STOP
     */
    @Override
    public void loop() {
        left.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        right.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);

        left.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
        right.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
    }

    /*
     * Code to run ONCE after the driver hits STOP
     */
    @Override
    public void stop() {
    }
}

<file_sep>/* Copyright (c) 2018 Blue Shift Robotics
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.blueshiftrobotics.ftc;

import com.disnodeteam.dogecv.CameraViewDisplay;
import com.disnodeteam.dogecv.DogeCV;
import com.disnodeteam.dogecv.detectors.roverrukus.GoldAlignDetector;
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.util.ElapsedTime;
import com.qualcomm.robotcore.util.Range;

import org.firstinspires.ftc.robotcore.external.Telemetry;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Name Breakdown
 *   Auto - Autonomous related.
 *   FourWheel - Uses a 4-wheel-drive robot.
 *   Drive - Includes code for moving the robot.
 *
 * Necessary Sensors
 *   IMU (REV Expansion Hub)
 *   Motor Encoders
 *   Positioned Back-Facing Phone Camera
 *
 * Function Catalog
 *   turn               - Use the REV IMU to precisely turn
 *   encoderDrive       - Use the motor encoders to drive a precise distance
 *   initDogeCV         - Activate the DogeCV Libraries for Gold Cube centering
 *   cubeRemovalAndReturn - Position the Gold Cube in the center of the phone camera view
 *
 * A compilation of useful functions for use during the thirty-second autonomous phase of a FIRST
 * Tech Challenge competition. Created by the programming team of Blue Shift, a function catalog is
 * included above.
 *
 * @version 1.3
 * @author <NAME>
 */
public class AutoFourWheelDrive {
    //Robot Motors
    private DcMotor motorDriveLeftBack;
    private DcMotor motorDriveLeftFront;
    private DcMotor motorDriveRightBack;
    private DcMotor motorDriveRightFront;

    //Important Objects to Manipulate
    private IMU imu;
    private Telemetry telemetry;
    private LinearOpMode opMode;
    private ElapsedTime elapsedTime = new ElapsedTime();

    //Computer Vision Variables
    private GoldAlignDetector goldAlignDetector; //Detector Object

    //Instance Variables
    private boolean hasAborted;
    private boolean verboseLoops;
    private List<Float> headingStorage;

    //Turning Constants
    private static final float TURN_Kp = 0.75f;
    private static final float TURN_ERROR_ALLOWANCE = (float)5; //In Degrees
    private static final float TURN_POWER_OFFSET_STEP = (float)0.015;

    //Encoder Constants
    private static final double COUNTS_PER_MOTOR_REV    = 1120;    // Andymark Neverest 40
    private static final double DRIVE_GEAR_REDUCTION    = 24.0/32.0;     // This is < 1.0 if geared UP
    private static final double WHEEL_DIAMETER_INCHES   = 4.0;     // For figuring circumference
    private static final double COUNTS_PER_INCH         = (COUNTS_PER_MOTOR_REV * DRIVE_GEAR_REDUCTION) / (WHEEL_DIAMETER_INCHES * 3.1415);
    private static final float  ENCODER_DRIVE_Kp        = 0.85f;
    private static final int    ENCODER_DRIVE_ERROR_ALLOWANCE = 200;
    private static final float  ENCODER_DRIVE_POWER_OFFSET_STEP = (float)0.013;
    private static final int    ENCODER_NO_MOVEMENT_THRESHOLD = 12;

    /**
     * Create a new instance of a four wheel drive library using the current hardware map and names
     * of components of interest.
     *
     * @param opMode The Linear Op Mode that constructs this library
     * @param motorDriveLeftName Name of the left drive motor
     * @param motorDriveRightName Name of the right drive motor
     * @param IMUName Name of the IMU sensor on the REV Expansion Hub
     * @param verboseLoops Whether or not to use verbose loops
     */
    public AutoFourWheelDrive(LinearOpMode opMode, String motorDriveLeftName, String motorDriveRightName, String IMUName, boolean verboseLoops) {
        //Bring in all objects from the OpMode and hardwareMap
        this.motorDriveLeftBack = opMode.hardwareMap.get(DcMotor.class, motorDriveLeftName + "Back");
        this.motorDriveLeftFront = opMode.hardwareMap.get(DcMotor.class, motorDriveLeftName + "Front");
        this.motorDriveRightBack = opMode.hardwareMap.get(DcMotor.class, motorDriveRightName + "Back");
        this.motorDriveRightFront = opMode.hardwareMap.get(DcMotor.class, motorDriveRightName + "Front");
        this.imu = new IMU(opMode.telemetry, opMode.hardwareMap, IMUName);

        this.telemetry = opMode.telemetry;
        this.opMode = opMode;

        this.hasAborted = false;
        this.verboseLoops = verboseLoops;
        this.headingStorage = new ArrayList<>();

        //Motor Calibration (Direction and Zero Power Behavior)
        motorDriveLeftBack.setDirection(DcMotor.Direction.FORWARD);
        motorDriveLeftFront.setDirection(DcMotor.Direction.FORWARD);
        motorDriveRightBack.setDirection(DcMotor.Direction.REVERSE);
        motorDriveRightFront.setDirection(DcMotor.Direction.REVERSE);

        motorDriveLeftBack.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE); //TODO: Decide whether to brake or not
        motorDriveLeftFront.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
        motorDriveRightBack.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
        motorDriveRightFront.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);

        resetEncoders();
    }

    /**
     * Turn the robot using the REV Expansion Hub IMU using a certain `dTheta` as a parameter. The
     * sign of the dTheta will denote direction, and there is a low-level PID Controller used to
     * control the speed of the motors as the destination is approached at different rates to
     * reduce final error rates from overshoot and undershoot.
     *
     * The turning power P is:
     *              P = s * k * (x) * (1-x)
     * Where s is the desired direction (sign of the error), k is some constant, and x is the
     * percentage error.
     *
     * @param dTheta The angular displacement target
     * @param secondsTimeout The maximum amount of seconds to run the loop for
     */
    public void turn(float dTheta, double secondsTimeout) {
        hasAborted = false;

        int[] previousEncoders = new int[4];
        float thetaInit = imu.getHeading();
        float thetaTarget = (thetaInit + dTheta) % 360;
        float turningPowerOffset = 0.16f;

        telemetry.addData("Turning", "Starting at " + thetaInit + " degrees");
        telemetry.update();

        resetEncoders();
        elapsedTime.reset();

        if (!verboseLoops) {
            while (Math.abs(thetaTarget - imu.getHeading()) % 360.0 > TURN_ERROR_ALLOWANCE
                    && opMode.opModeIsActive()
                    && elapsedTime.seconds() <= secondsTimeout
                    && !hasAborted
                    && !opMode.isStopRequested()) {

                int[] currentEncoders = getEncoderValues();

                double thetaCurrent = (double)imu.getHeading();

                double thetaError = BlueShiftUtil.getDegreeDifference(thetaCurrent, thetaTarget);
                double thetaPercentError = Math.abs(thetaError / dTheta);

                double turnPower = Math.signum(thetaError) * (TURN_Kp * thetaPercentError * (1.0 - thetaPercentError) + turningPowerOffset);

                setTurnPower(turnPower);

                if (!hasAllEncodersMoved(previousEncoders, currentEncoders)) {
                    turningPowerOffset += thetaPercentError * TURN_POWER_OFFSET_STEP; //TODO: Decide whether or not to make offset proportional
                }

                previousEncoders = currentEncoders;
            }
        } else {
            while (Math.abs(thetaTarget - imu.getHeading()) % 360.0 > TURN_ERROR_ALLOWANCE
                    && opMode.opModeIsActive()
                    && elapsedTime.seconds() <= secondsTimeout
                    && !hasAborted
                    && !opMode.isStopRequested()) {

                int[] currentEncoders = getEncoderValues();

                double thetaCurrent = (double)imu.getHeading();

                double thetaError = BlueShiftUtil.getDegreeDifference(thetaCurrent, thetaTarget);
                double thetaPercentError = Math.abs(thetaError / dTheta);

                double turnPower = Math.signum(thetaError) * (TURN_Kp * thetaPercentError * (1.0 - thetaPercentError) + turningPowerOffset);

                setTurnPower(turnPower);

                if (!hasAllEncodersMoved(previousEncoders, currentEncoders)) {
                    turningPowerOffset += thetaPercentError * TURN_POWER_OFFSET_STEP;
                }

                previousEncoders = currentEncoders;

                telemetry.addData("Theta Error", thetaError);
                telemetry.addData("Percent Error", thetaPercentError);
                telemetry.addData("Current Heading", thetaCurrent);
                telemetry.addData("Target Heading", thetaTarget);
                telemetry.addData("Motor Power", turnPower);
                telemetry.update();
            }
        }

        abortMotion();

        telemetry.addData("Turning", "Complete at " + imu.getHeading() + " degrees");
        telemetry.update();
    }

    /**
     * Drive the robot to a certain encoder value on the drive train motors. For use with MECANUM
     * drive trains only. This function strafes instead of drives, meaning it drives left and right
     * laterally instead of forward and backwards as a tank drive would.
     *
     * @param targetDistance The distance in inches to travel
     * @param secondsTimeout The maximum seconds to run the loop
     */
    public void encoderStrafe(double targetDistance, double secondsTimeout) {
        hasAborted = false;

        //Reset encoder values to zero
        resetEncoders();

        //Find desired encoder value and initialize placeholder array
        int[] currentEncoders = getEncoderValues();
        int[] previousEncoders = new int[4];
        int encoderTarget = (int)(targetDistance * COUNTS_PER_INCH);
        double ENCODER_DRIVE_POWER_OFFSET = 0.18;

        //Telemetry Information
        telemetry.addData("Encoder Driving", "Starting at %7d : %7d", motorDriveLeftBack.getCurrentPosition(), motorDriveRightBack.getCurrentPosition());
        telemetry.update();

        //Set the current time to zero
        elapsedTime.reset();

        if (!verboseLoops) {
            while (elapsedTime.seconds() <= secondsTimeout
                    && (Math.abs(BlueShiftUtil.modifiedMeanAbsoluteError(currentEncoders, encoderTarget)) - encoderTarget) > ENCODER_DRIVE_ERROR_ALLOWANCE
                    && opMode.opModeIsActive()
                    && !hasAborted
                    && !opMode.isStopRequested()) {

                currentEncoders = getEncoderValues();

                double encoderMeanAbsoluteError = BlueShiftUtil.modifiedMeanAbsoluteError(currentEncoders, encoderTarget);
                float percentEncoderError = (float)Range.clip(Math.abs((float)encoderMeanAbsoluteError / (float)encoderTarget), 0.0, 1.0);

                double motorPower = Math.signum(encoderMeanAbsoluteError) * (ENCODER_DRIVE_Kp * percentEncoderError * (1 - percentEncoderError) + ENCODER_DRIVE_POWER_OFFSET);

                strafe(motorPower);

                if (!hasAllEncodersMoved(previousEncoders, currentEncoders)) {
                    ENCODER_DRIVE_POWER_OFFSET += ENCODER_DRIVE_POWER_OFFSET_STEP;
                }

                previousEncoders = currentEncoders;
            }
        } else {
            while (elapsedTime.seconds() <= secondsTimeout
                    && Math.abs(BlueShiftUtil.modifiedMeanAbsoluteError(currentEncoders, encoderTarget)) > ENCODER_DRIVE_ERROR_ALLOWANCE
                    && opMode.opModeIsActive()
                    && !hasAborted
                    && !opMode.isStopRequested()) {

                currentEncoders = getEncoderValues();

                double encoderMeanAbsoluteError = BlueShiftUtil.modifiedMeanAbsoluteError(currentEncoders, encoderTarget);
                float percentEncoderError = (float)Range.clip(Math.abs((float)encoderMeanAbsoluteError / (float)encoderTarget), 0.0, 1.0);

                double motorPower = Math.signum(encoderMeanAbsoluteError) * (ENCODER_DRIVE_Kp * percentEncoderError * (1 - percentEncoderError) + ENCODER_DRIVE_POWER_OFFSET);

                strafe(motorPower);

                if (!hasAllEncodersMoved(previousEncoders, currentEncoders)) {
                    ENCODER_DRIVE_POWER_OFFSET += ENCODER_DRIVE_POWER_OFFSET_STEP;
                }

                previousEncoders = currentEncoders;

                telemetry.addData("Front Encoders", "(%7d):(%7d)", motorDriveLeftFront.getCurrentPosition(), motorDriveRightFront.getCurrentPosition());
                telemetry.addData("Back Encoders", "(%7d):(%7d)", motorDriveLeftBack.getCurrentPosition(), motorDriveRightBack.getCurrentPosition());
                telemetry.addLine()
                        .addData("Encoder Target ", encoderTarget + "\n")
                        .addData("Encoder MAE", encoderMeanAbsoluteError + "\n")
                        .addData("Percent Errors", percentEncoderError + "\n")
                        .addData("Power", motorPower + "\n");
                telemetry.update();
            }
        }

        //Stop the robot and terminate any loops running
        abortMotion();

        telemetry.addData("Encoder Driving", "Complete");
        telemetry.update();
    }

    /**
     * Drive the robot to a certain encoder value on the drive train motors.
     *
     * @param targetDistance The distance in inches to travel
     * @param secondsTimeout The maximum seconds to run the loop
     */
    public void encoderDrive(double targetDistance, double secondsTimeout) {
        hasAborted = false;

        //Reset encoder values to zero
        resetEncoders();

        //Find desired encoder value and initialize placeholder array
        int[] previousEncoders = new int[4];
        int encoderTarget = (int)(targetDistance * COUNTS_PER_INCH);
        double ENCODER_DRIVE_POWER_OFFSET = 0.15;

        //Telemetry Information
        telemetry.addData("Encoder Driving", "Starting at %7d : %7d", motorDriveLeftBack.getCurrentPosition(), motorDriveRightBack.getCurrentPosition());
        telemetry.update();

        //Set the current time to zero
        elapsedTime.reset();

        if (!verboseLoops) {
            while (elapsedTime.seconds() <= secondsTimeout
                    && (Math.abs(motorDriveLeftBack.getCurrentPosition() - encoderTarget) > ENCODER_DRIVE_ERROR_ALLOWANCE
                    || Math.abs(motorDriveRightBack.getCurrentPosition() - encoderTarget) > ENCODER_DRIVE_ERROR_ALLOWANCE)
                    && opMode.opModeIsActive()
                    && !hasAborted
                    && !opMode.isStopRequested()) {

                int[] currentEncoders = getEncoderValues();

                int motorDriveLeftEncoderError = encoderTarget - motorDriveLeftBack.getCurrentPosition();
                int motorDriveRightEncoderError = encoderTarget - motorDriveRightBack.getCurrentPosition();
                double motorDriveLeftPercentEncoderError = (double)(motorDriveLeftEncoderError) / (double)encoderTarget;
                double motorDriveRightPercentEncoderError = (double)(motorDriveRightEncoderError) / (double)encoderTarget;

                double motorDriveLeftPower = Math.signum(motorDriveLeftEncoderError) * (ENCODER_DRIVE_Kp * Math.abs(motorDriveLeftPercentEncoderError) * (1 - Math.abs(motorDriveLeftPercentEncoderError)) + ENCODER_DRIVE_POWER_OFFSET);
                double motorDriveRightPower = Math.signum(motorDriveRightEncoderError) * (ENCODER_DRIVE_Kp * Math.abs(motorDriveRightPercentEncoderError) * (1 - Math.abs(motorDriveRightPercentEncoderError)) + ENCODER_DRIVE_POWER_OFFSET);

                setSplitPower(motorDriveLeftPower, motorDriveRightPower);

                if (!hasAllEncodersMoved(previousEncoders, currentEncoders)) {
                    ENCODER_DRIVE_POWER_OFFSET += (motorDriveLeftPercentEncoderError + motorDriveRightPercentEncoderError)/2.0 * ENCODER_DRIVE_POWER_OFFSET_STEP;
                }

                previousEncoders = currentEncoders;
            }
        } else {
            while (elapsedTime.seconds() <= secondsTimeout
                    && (Math.abs(motorDriveLeftBack.getCurrentPosition() - encoderTarget) > ENCODER_DRIVE_ERROR_ALLOWANCE
                    || Math.abs(motorDriveRightBack.getCurrentPosition() - encoderTarget) > ENCODER_DRIVE_ERROR_ALLOWANCE)
                    && opMode.opModeIsActive()
                    && !hasAborted
                    && !opMode.isStopRequested()) {

                int[] currentEncoders = getEncoderValues();

                int motorDriveLeftEncoderError = encoderTarget - motorDriveLeftBack.getCurrentPosition();
                int motorDriveRightEncoderError = encoderTarget - motorDriveRightBack.getCurrentPosition();
                double motorDriveLeftPercentEncoderError = (double)(motorDriveLeftEncoderError) / (double)encoderTarget;
                double motorDriveRightPercentEncoderError = (double)(motorDriveRightEncoderError) / (double)encoderTarget;

                double motorDriveLeftPower = Math.signum(motorDriveLeftEncoderError) * (ENCODER_DRIVE_Kp * Math.abs(motorDriveLeftPercentEncoderError) * (1 - Math.abs(motorDriveLeftPercentEncoderError)) + ENCODER_DRIVE_POWER_OFFSET);
                double motorDriveRightPower = Math.signum(motorDriveRightEncoderError) * (ENCODER_DRIVE_Kp * Math.abs(motorDriveRightPercentEncoderError) * (1 - Math.abs(motorDriveRightPercentEncoderError)) + ENCODER_DRIVE_POWER_OFFSET);

                setSplitPower(motorDriveLeftPower, motorDriveRightPower);

                if (!hasAllEncodersMoved(previousEncoders, currentEncoders)) {
                    ENCODER_DRIVE_POWER_OFFSET += (motorDriveLeftPercentEncoderError + motorDriveRightPercentEncoderError)/2.0 * ENCODER_DRIVE_POWER_OFFSET_STEP;
                }

                previousEncoders = currentEncoders;

                telemetry.addData("Boolean checks", (Math.abs(motorDriveLeftBack.getCurrentPosition() - encoderTarget) > ENCODER_DRIVE_ERROR_ALLOWANCE
                        || Math.abs(motorDriveRightBack.getCurrentPosition() - encoderTarget) > ENCODER_DRIVE_ERROR_ALLOWANCE));
                telemetry.addData("Front Encoders", "(%7d):(%7d)", motorDriveLeftFront.getCurrentPosition(), motorDriveRightFront.getCurrentPosition());
                telemetry.addData("Back Encoders", "(%7d):(%7d)", motorDriveLeftBack.getCurrentPosition(), motorDriveRightBack.getCurrentPosition());
                telemetry.addData("Encoder Target", encoderTarget);
                telemetry.addData("Encoder Errors", "(%7d):(%7d)", motorDriveLeftEncoderError, motorDriveRightEncoderError);
                telemetry.addData("Percent Errors", "(%.2f):(%.2f)", motorDriveLeftPercentEncoderError, motorDriveRightPercentEncoderError);
                telemetry.addData("Power", "Left (%.2f), Right (%.2f)", motorDriveLeftPower, motorDriveRightPower);
                telemetry.addData("Timing", "(%.2f) of (%.2f)", elapsedTime.seconds(), secondsTimeout);
                telemetry.update();
            }
        }

        //Stop the robot and terminate any loops running
        abortMotion();

        telemetry.addData("Encoder Driving", "Complete");
        telemetry.update();
    }

    /**
     * Initialize the gold (cube) alignment detector from DogeCV.
     */
    public void initDogeCV() {
        telemetry.addData("DogeCV", "Initializing");

        // Set up goldAlignDetector
        goldAlignDetector = new GoldAlignDetector(); // Create goldAlignDetector
        goldAlignDetector.init(opMode.hardwareMap.appContext, CameraViewDisplay.getInstance()); // Initialize it with the app context and camera
        goldAlignDetector.useDefaults(); // Set goldAlignDetector to use default settings

        // Optional tuning
        goldAlignDetector.alignSize = 75; // How wide (in pixels) is the range in which the gold object will be aligned. (Represented by green bars in the preview)
        goldAlignDetector.alignPosOffset = 0; // How far from center frame to offset this alignment zone.
        goldAlignDetector.downscale = 0.4; // How much to downscale the input frames

        goldAlignDetector.areaScoringMethod = DogeCV.AreaScoringMethod.MAX_AREA; // Can also be PERFECT_AREA
        goldAlignDetector.maxAreaScorer.weight = 0.005; //

        goldAlignDetector.ratioScorer.weight = 5; // Determines the power applied to the motors, the further away it is the faster it turnorer.weight = 5; //
        goldAlignDetector.ratioScorer.perfectRatio = 1.0; // Ratio adjustment

        goldAlignDetector.enable();

        telemetry.addData("DogeCV", "Initialization Complete");
    }

    /**
     * Assuming the robot's side is aligned with the center debris (position 2). Depending on the
     * given cube position, navigate to the side of that cube and remove it. Then, return back
     * to aligned with the center.
     *
     * @param secondsTimeout The maximum seconds to run the loop for
     * @param cubePosition The position (1, 2, or 3) of the cube
     * @return If successful
     */
    public boolean cubeRemovalAndReturn(double secondsTimeout, int cubePosition) {
        elapsedTime.reset();

        if (elapsedTime.seconds() >= secondsTimeout
                || opMode.isStopRequested()) {
            abortMotion();
            return false;
        }

        if (cubePosition == 1) {
            encoderDrive(18.5, 10);
        } else if (cubePosition == 3) {
            encoderDrive(-17, 10);
        }

        //Move the gold block and back up
        encoderStrafe(-15, 10);
        encoderStrafe(15, 10);

        if (cubePosition == 1) {
            encoderDrive(-12, 10);
        } else if (cubePosition == 3) {
            encoderDrive(22, 10);
        }

        return true;
    }

    public boolean cubeRemovalAndPark(double secondsTimeout, int cubePosition) {
        elapsedTime.reset();

        if (elapsedTime.seconds() >= secondsTimeout
                || opMode.isStopRequested()) {
            abortMotion();
            return false;
        }

        if (cubePosition == 1) {
            encoderDrive(18.5, 10);
        } else if (cubePosition == 3) {
            encoderDrive(-17, 10);
        }

        //Move the gold block and park
        encoderStrafe(-16, 10);
        return true;
    }

    public void disableDogeCV() {
        goldAlignDetector.disable();
    }

    //Utility Functions

    /**
     * Turn to a certain recorded heading.
     *
     * @param headingIndex The index of the stored heading
     * @param secondsTimeout The maximum time to run the `turn` loops for
     */
    public void turnToRecordedHeading(int headingIndex, double secondsTimeout) {
        float dTheta = readHeading(headingIndex) - imu.getHeading();

        turn(dTheta, secondsTimeout);
    }

    /**
     * Turn to a certain recorded heading with an offset.
     *
     * @param headingIndex The index of the stored heading
     * @param headingOffset How much to offset theta by
     * @param secondsTimeout The maximum time to run the `turn` loops for
     */
    public void turnToRecordedHeading(int headingIndex, float headingOffset, double secondsTimeout) {
        float dTheta = (readHeading(headingIndex) - imu.getHeading() + headingOffset) % 360;

        turn(dTheta, secondsTimeout);
    }

    /**
     * Store the current IMU heading.
     *
     * @return The index of the stored heading
     */
    public int recordHeading() {
        if (headingStorage.isEmpty()) {
            headingStorage = Arrays.asList(imu.getHeading());
            return 0;
        }

        headingStorage.add(imu.getHeading());
        return headingStorage.size() - 1;
    }

    /**
     * Read an IMU heading written by the `recordHeading` method.
     *
     * @param index The index of the stored heading
     * @return The stored heading
     */
    public float readHeading(int index) {
        if (headingStorage.isEmpty()
                || index >= headingStorage.size()) {
            return 0;
        }

        return headingStorage.get(index);
    }

    /**
     * Compile all encoder values of all four motors into one array and return that array.
     *
     * @return The array of all four motor encoder values
     */
    private int[] getEncoderValues() {
        return new int[] {
                motorDriveLeftBack.getCurrentPosition(),
                motorDriveLeftFront.getCurrentPosition(),
                motorDriveRightBack.getCurrentPosition(),
                motorDriveRightFront.getCurrentPosition()
        };
    }

    /**
     * Compares two arrays of encoder values and determines whether or not all motors haved moved.
     *
     * @param encoders_1 The first array of encoder values
     * @param encoders_2 The second array of encoder values
     * @return Whether or not all motors have moved
     */
    private boolean hasAllEncodersMoved(int[] encoders_1, int[] encoders_2) {
        if (Math.abs(encoders_1[0] - encoders_2[0]) < ENCODER_NO_MOVEMENT_THRESHOLD
                || Math.abs(encoders_1[1] - encoders_2[1]) < ENCODER_NO_MOVEMENT_THRESHOLD
                || Math.abs(encoders_1[2] - encoders_2[2]) < ENCODER_NO_MOVEMENT_THRESHOLD
                || Math.abs(encoders_1[3] - encoders_2[3]) < ENCODER_NO_MOVEMENT_THRESHOLD) {
            return false;
        }

        return true;
    }

    /**
     * Set the left side to one power and the right side to another
     *
     * @param leftPower The power for the left motors
     * @param rightPower The power for the right motors
     */
    private void setSplitPower(double leftPower, double rightPower) {
        motorDriveLeftBack.setPower(leftPower);
        motorDriveLeftFront.setPower(leftPower);
        motorDriveRightBack.setPower(rightPower);
        motorDriveRightFront.setPower(rightPower);
    }

    /**
     * Set the power of every motor to one power.
     *
     * @param power Desired motor power
     */
    private void setAllPower(double power) {
        motorDriveLeftBack.setPower(power);
        motorDriveLeftFront.setPower(power);
        motorDriveRightBack.setPower(power);
        motorDriveRightFront.setPower(power);
    }

    /**
     * Set the power of every motor to one power except the right side is reversed to turn
     *
     * @param power Desired motor power
     */
    private void setTurnPower(double power) {
        motorDriveLeftBack.setPower(power);
        motorDriveLeftFront.setPower(power);
        motorDriveRightBack.setPower(-power);
        motorDriveRightFront.setPower(-power);
    }

    /**
     * Stop all motion and reset the 'hasAborted' variable for use in while loops. This is used for
     * a sudden halt of the robot and ALL loops that may be running in the autonomous library.
     *
     * Useful for when a stop is requested by the operator.
     */
    private void abortMotion() {
        hasAborted = true;

        setAllPower(0);

        telemetry.addData("Status", "Drive Motion Aborted");
        telemetry.update();
    }

    /**
     * Stop all motors and reset the current encoder value to zero on each motor. Then, change the
     * motor run modes back to running without the encoder so that we can set the power to them
     * again.
     */
    private void resetEncoders() {
        motorDriveLeftBack.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        motorDriveLeftFront.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        motorDriveRightBack.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        motorDriveRightFront.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);

        motorDriveLeftBack.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
        motorDriveLeftFront.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
        motorDriveRightBack.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
        motorDriveRightFront.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
    }

    public void strafe(double power) {
        motorDriveLeftFront.setPower(power);
        motorDriveRightBack.setPower(power);

        motorDriveRightFront.setPower(-power);
        motorDriveLeftBack.setPower(-power);
    }

    public boolean isCubeFound() {
        return goldAlignDetector.isFound();
    }
}
<file_sep>/* Copyright (c) 2018 Blue Shift Robotics
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package org.firstinspires.ftc.teamcode;

import com.qualcomm.robotcore.eventloop.opmode.OpMode;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.hardware.CRServo;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.util.ElapsedTime;

@TeleOp(name="TeleOP", group="Main")
public class Drive_TeleOP extends OpMode {
    private ElapsedTime runtime = new ElapsedTime();
    private DcMotor motorDriveLeftBack;
    private DcMotor motorDriveLeftFront;
    private DcMotor motorDriveRightBack;
    private DcMotor motorDriveRightFront;

    private DcMotor motorBucket;
    private DcMotor motorFlipper;
    private DcMotor motorLift;
    private DcMotor motorSlider;

    private CRServo servoSweeper;

    //Arm Deployment Constants
    private static final int SLIDER_HOME_ENCODER_VALUE     = -1900;
    private static final int SLIDER_DEPLOYED_ENCODER_VALUE = -3200;
    private static final float SLIDER_MOVEMENT_POWER = -0.6f;

    private static final int BUCKET_HOME_ENCODER_VALUE     = -63;
    private static final int BUCKET_DEPLOYED_ENCODER_VALUE = -420;
    private static final float BUCKET_MOVEMENT_POWER = -0.23f;

    private static final int FLIPPER_HOME_ENCODER_VALUE    = 0;
    private static final int FLIPPER_DEPLOYED_ENCODER_VALUE = 950;
    private static final float FLIPPER_MOVEMENT_POWER = 0.5f;

    //Driving constants and variables
    private static final float SERVO_MAX_POWER = 0.8f;

    private boolean manualControl = false;

    @Override public void init() {
        telemetry.clearAll();
        telemetry.addData("Status", "TeleOP Initialization In Progress");
        telemetry.update();

        // Retrieve the motor objects from the hardware map. These names come from the configuration in the robot controller.
        motorDriveLeftBack = hardwareMap.get(DcMotor.class,   "motorDriveLeftBack");
        motorDriveLeftFront = hardwareMap.get(DcMotor.class,  "motorDriveLeftFront");
        motorDriveRightBack = hardwareMap.get(DcMotor.class,  "motorDriveRightBack");
        motorDriveRightFront = hardwareMap.get(DcMotor.class, "motorDriveRightFront");

        motorBucket = hardwareMap.get(DcMotor.class, "motorBucket");
        motorFlipper = hardwareMap.get(DcMotor.class, "motorFlipper");
        motorLift = hardwareMap.get(DcMotor.class, "motorLift");
        motorSlider = hardwareMap.get(DcMotor.class, "motorSlider");

        servoSweeper = hardwareMap.get(CRServo.class, "servoSweeper");

        // Since one motor is reversed in relation to the other, we must reverse the motor on the right so positive powers mean forward.
        motorDriveLeftBack.setDirection(DcMotor.Direction.FORWARD);
        motorDriveLeftFront.setDirection(DcMotor.Direction.FORWARD);
        motorDriveRightBack.setDirection(DcMotor.Direction.REVERSE);
        motorDriveRightFront.setDirection(DcMotor.Direction.REVERSE);

        motorDriveLeftBack.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        motorDriveLeftFront.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        motorDriveRightBack.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        motorDriveRightFront.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);

        motorDriveLeftBack.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
        motorDriveLeftFront.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
        motorDriveRightBack.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
        motorDriveRightFront.setMode(DcMotor.RunMode.RUN_USING_ENCODER);

        //Set auxiliary motors parameters
        motorBucket.setDirection(DcMotor.Direction.FORWARD);
        motorFlipper.setDirection(DcMotor.Direction.FORWARD);
        motorLift.setDirection(DcMotor.Direction.FORWARD);
        motorSlider.setDirection(DcMotor.Direction.FORWARD);

        motorBucket.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        motorFlipper.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        motorLift.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        motorSlider.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);

        motorBucket.setMode(DcMotor.RunMode.RUN_TO_POSITION);
        motorFlipper.setMode(DcMotor.RunMode.RUN_TO_POSITION);
        motorLift.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
        motorSlider.setMode(DcMotor.RunMode.RUN_TO_POSITION);

        motorBucket.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
        motorFlipper.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
        motorLift.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
        motorSlider.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);

        // Tell the driver that initialization is complete.
        telemetry.addData("Status", "Initialized");
        telemetry.update();
    }

    @Override public void init_loop() { }

    @Override public void start() {
        runtime.reset();
        telemetry.clearAll();

        telemetry.addData("Status", "Started");
    }

    @Override public void loop() {
        //Driving Code
        double speed = Math.sqrt(2) * Math.pow(Math.pow(gamepad1.left_stick_x, 4) + Math.pow(gamepad1.left_stick_y, 4), 0.5);
        double angle = Math.atan2(gamepad1.left_stick_y, gamepad1.left_stick_x);
        double rotation = Math.signum(gamepad1.right_stick_x) * Math.pow(gamepad1.right_stick_x, 2);

        float primaryDiagonalSpeed = (float)(speed * Math.sin(angle - (Math.PI/4.0)));
        float secondaryDiagonalSpeed = (float)(speed * Math.cos(angle - (Math.PI/4.0)));

        motorDriveLeftBack.setPower(secondaryDiagonalSpeed - rotation);
        motorDriveRightFront.setPower(secondaryDiagonalSpeed + rotation);
        motorDriveLeftFront.setPower(primaryDiagonalSpeed - rotation);
        motorDriveRightBack.setPower(primaryDiagonalSpeed + rotation);

        //Lift Code
        if (gamepad1.dpad_up || gamepad2.dpad_up) {
            motorLift.setPower(1.0);
        } else if (gamepad1.dpad_down || gamepad2.dpad_down) {
            motorLift.setPower(-1.0);
        } else {
            motorLift.setPower(0);
        }

        //Flipper Code
        if (gamepad1.left_bumper) {
            extendFlipper();
        } else if (gamepad1.left_trigger > 0) {
            retractFlipper();
        }

        //Servo Code
        if (gamepad1.right_bumper) {
            servoSweeper.setPower(SERVO_MAX_POWER);
        } else if (gamepad1.right_trigger > 0) {
            servoSweeper.setPower(-SERVO_MAX_POWER);
        } else {
            servoSweeper.setPower(0);
        }

        if (gamepad2.a) {
            manualControl = true;
        } else {
            manualControl = false;
        }

        if (manualControl) {
            motorBucket.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
            motorFlipper.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
            motorSlider.setMode(DcMotor.RunMode.RUN_USING_ENCODER);

            motorBucket.setPower(gamepad2.right_stick_x);
            motorSlider.setPower(gamepad2.right_stick_y);
            motorFlipper.setPower(gamepad2.left_stick_y);
        } else {
            motorBucket.setMode(DcMotor.RunMode.RUN_TO_POSITION);
            motorFlipper.setMode(DcMotor.RunMode.RUN_TO_POSITION);
            motorSlider.setMode(DcMotor.RunMode.RUN_TO_POSITION);
        }

        //Bucket and Slider Code
        if (gamepad1.a) {
            extendArm();
            extendBucket();
        } else if (gamepad1.b) {
            retractArm();
            retractBucket();
        }
    }

    private void extendArm() {
        if (!manualControl) {
            motorSlider.setTargetPosition(SLIDER_DEPLOYED_ENCODER_VALUE);
            motorSlider.setPower(SLIDER_MOVEMENT_POWER);
        }
    }

    private void retractArm() {
        if (!manualControl) {
            motorSlider.setTargetPosition(SLIDER_HOME_ENCODER_VALUE);
            motorSlider.setPower(-SLIDER_MOVEMENT_POWER);
        }
    }

    private void extendBucket() {
            if (!manualControl) {
                motorBucket.setTargetPosition(BUCKET_DEPLOYED_ENCODER_VALUE);
                motorBucket.setPower(BUCKET_MOVEMENT_POWER);
            }
    }

    private void retractBucket() {
            if (!manualControl) {
                motorBucket.setTargetPosition(BUCKET_HOME_ENCODER_VALUE);
                motorBucket.setPower(-BUCKET_MOVEMENT_POWER);
            }
    }

    private void extendFlipper() {
            if (!manualControl) {
                motorFlipper.setTargetPosition(FLIPPER_DEPLOYED_ENCODER_VALUE);
                motorFlipper.setPower(FLIPPER_MOVEMENT_POWER);
            }
    }

    private void retractFlipper() {
            if (!manualControl) {
                motorFlipper.setTargetPosition(FLIPPER_HOME_ENCODER_VALUE);
                motorFlipper.setPower(-FLIPPER_MOVEMENT_POWER);
            }
    }

    @Override public void stop() {
        motorDriveLeftBack.setPower(0);
        motorDriveLeftFront.setPower(0);
        motorDriveRightBack.setPower(0);
        motorDriveRightFront.setPower(0);

        motorBucket.setPower(0);
        motorFlipper.setPower(0);
        motorLift.setPower(0);
        motorSlider.setPower(0);
    }
}
<file_sep>/* Copyright (c) 2018 Blue Shift Robotics
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.blueshiftrobotics.ftc;

import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.hardware.CRServo;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.DcMotorSimple;
import com.qualcomm.robotcore.util.ElapsedTime;
import com.qualcomm.robotcore.util.Range;

import org.firstinspires.ftc.robotcore.external.Telemetry;

/**
 * Name Breakdown
 *   Auto - Autonomous Related
 *   Auxiliary - Uses auxiliary motors
 *
 * Necessary Sensors
 *   Encoders:
 *     Lift Motor
 *
 * Function Catalog
 *   liftDrop - Drop the robot from the lander
 *
 * A compilation of functions used during autonomous related to all non-drive motors.
 *
 * @version 0.8
 * @author <NAME>
 */
public class AutoAuxiliary {
    //Robot Motors
    private DcMotor motorLift;
    private DcMotor motorBucket;
    private DcMotor motorSlider;

    //Servos
    private CRServo servoSweeper;

    //Instance Variables
    private boolean hasAborted;
    private boolean verboseLoops;

    //Important Objects to Manipulate
    private Telemetry telemetry;
    private LinearOpMode opMode;
    private ElapsedTime elapsedTime = new ElapsedTime();

    //Arm Deployment Constants
    private static final int SLIDER_HOME_ENCODER_VALUE     = 0;
    private static final int SLIDER_DEPLOYED_ENCODER_VALUE = -3200;
    private static final int BUCKET_HOME_ENCODER_VALUE     = 0;
    private static final int BUCKET_DEPLOYED_ENCODER_VALUE = -435;
    private static final float SLIDER_MOVEMENT_POWER = -0.55f;
    private static final float BUCKET_MOVEMENT_POWER = -0.25f;

    //Lift Constants
    private static final double COUNTS_PER_LIFT_MOTOR_REV = 1680;
    private static final double SHAFT_DIAMETER_INCHES     = 0.23622; //6mm in inches
    private static final double COUNTS_PER_INCH           = COUNTS_PER_LIFT_MOTOR_REV / (SHAFT_DIAMETER_INCHES * 3.1415);
    private static final double DROP_DISTANCE             = 4.69; //Distance needed to drop to ground
    private static final double COUNTS_TO_DROP            = DROP_DISTANCE * COUNTS_PER_INCH;
    private static final float  DROP_POWER                = 1.0f;

    //Misc Constants
    private static final double LOADED_DIRECTION_TEST_POWER = 1.0;
    private static final long   LOADED_DIRECTION_TIME_INTERVAL = 100; //In ms
    private static final float  SERVO_MAX_POWER = 0.8f;
    private static final long   MARKER_EJECTION_TIME_INTERVAL = 1000; //In ms

    /**
     * Create a new instance of an auxiliary autonomous library using all necessary objects and
     * variables.
     *
     * @param opMode The Linear Op Mode that constructs this library
     * @param motorLiftName Name of the lift motor
     * @param verboseLoops Whether or not to use verbose loops
     */
    public AutoAuxiliary(LinearOpMode opMode, String motorLiftName, String motorBucketName, String motorSliderName, String servoSweeperName, boolean verboseLoops) {
        this.motorLift = opMode.hardwareMap.get(DcMotor.class, motorLiftName);
        this.motorBucket = opMode.hardwareMap.get(DcMotor.class, motorBucketName);
        this.motorSlider = opMode.hardwareMap.get(DcMotor.class, motorSliderName);
        this.servoSweeper = opMode.hardwareMap.get(CRServo.class, servoSweeperName);

        this.telemetry = opMode.telemetry;
        this.opMode = opMode;

        this.hasAborted = false;
        this.verboseLoops = verboseLoops;

        motorLift.setDirection(DcMotorSimple.Direction.FORWARD);
        motorBucket.setDirection(DcMotorSimple.Direction.FORWARD);
        motorSlider.setDirection(DcMotorSimple.Direction.FORWARD);

        motorLift.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
        motorBucket.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
        motorSlider.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);

        resetEncoders();
    }

    /**
     * Deploy the arm from the original position to the extended position so that the robot can
     * eject the team marker.
     *
     * @param secondsTimeout The maximum amount of seconds to run the loop for
     */
    public void deployArm(double secondsTimeout) {
        hasAborted = false;

        telemetry.addData("Arm", "Deploying");
        telemetry.update();

        resetEncoderAndRunToPos(motorSlider);
        resetEncoderAndRunToPos(motorBucket);

        motorSlider.setTargetPosition(SLIDER_DEPLOYED_ENCODER_VALUE);
        motorBucket.setTargetPosition(BUCKET_DEPLOYED_ENCODER_VALUE);
        motorSlider.setPower(SLIDER_MOVEMENT_POWER);

        elapsedTime.reset();

        while (elapsedTime.seconds() < secondsTimeout
                && motorSlider.isBusy()
                && !opMode.isStopRequested()
                && !hasAborted) {
            opMode.idle();
        }

        motorSlider.setPower(0);

        motorBucket.setPower(BUCKET_MOVEMENT_POWER);

        while (elapsedTime.seconds() < secondsTimeout
                && motorBucket.isBusy()
                && !opMode.isStopRequested()
                && !hasAborted) {
            opMode.idle();
        }

        motorBucket.setPower(0);

        abortMotion();

        telemetry.addData("Arm", "Deployment Complete");
        telemetry.update();
    }

    /**
     * Retract the arm from a deployed state.
     *
     * @param secondsTimeout The maximum amount of seconds to run the loop for
     */
    public void retractArm(double secondsTimeout) {
        hasAborted = false;

        telemetry.addData("Arm", "Deploying");
        telemetry.update();

        motorSlider.setTargetPosition(SLIDER_HOME_ENCODER_VALUE);
        motorBucket.setTargetPosition(BUCKET_HOME_ENCODER_VALUE);

        elapsedTime.reset();

        motorBucket.setPower(-BUCKET_MOVEMENT_POWER);

        while (elapsedTime.seconds() < secondsTimeout
                && motorBucket.isBusy()
                && !opMode.isStopRequested()
                && !hasAborted) {
            opMode.idle();
        }

        motorBucket.setPower(0);

        motorSlider.setPower(-SLIDER_MOVEMENT_POWER);

        while (elapsedTime.seconds() < secondsTimeout
                && motorSlider.isBusy()
                && !opMode.isStopRequested()
                && !hasAborted) {
            opMode.idle();
        }

        motorSlider.setPower(0);

        abortMotion();

        telemetry.addData("Arm", "Retraction Complete");
        telemetry.update();
    }

    /**
     * Eject the team marker that has been placed inside of the sweeper.
     *
     * @param secondsTimeout The maximum amount of seconds to run the loop for
     */
    public void ejectMarker(double secondsTimeout) {
        hasAborted = false;

        telemetry.addData("Marker Ejection", "Starting");
        telemetry.update();

        elapsedTime.reset();

        while (elapsedTime.seconds() < secondsTimeout
                && elapsedTime.seconds() < MARKER_EJECTION_TIME_INTERVAL
                && !opMode.isStopRequested()
                && !hasAborted) {
            servoSweeper.setPower(SERVO_MAX_POWER);
        }

        abortMotion();

        telemetry.addData("Marker Ejection", "Complete");
    }

    /**
     * Assumes the robot is currently latched onto the lander. Lowers the robot from a latched
     * position onto the game field and then shuts off the lift motor.
     *
     * @param secondsTimeout The maximum amount of seconds to run the loop for
     */
    public void liftDrop(double secondsTimeout) {
        //Set up all variables and do telemetry
        hasAborted = false;

        int loadedDirection = findLoadedDirection(motorLift);
        int dropDirection   = -1 * loadedDirection;
        int previousEncoder = 0;
        int flagCount       = 0; //How many unexpected no-movements has happened
        boolean onGround = false;

        telemetry.addData("Lift Drop", "Starting");
        telemetry.update();

        resetEncoders();
        elapsedTime.reset();

        if (!verboseLoops) {
            while (!onGround
                    && opMode.opModeIsActive()
                    && !opMode.isStopRequested()
                    && !hasAborted
                    && elapsedTime.seconds() <= secondsTimeout) {

                int currentEncoder = motorLift.getCurrentPosition();

                motorLift.setPower(dropDirection * DROP_POWER);

                if (Math.abs(motorLift.getCurrentPosition()) >= COUNTS_TO_DROP) {
                    onGround = true;
                } else if (currentEncoder == previousEncoder) {
                    telemetry.addData("Lift Drop", "WARNING, No movement");
                    telemetry.update();

                    flagCount++;
                }

                if (flagCount > 10) {
                    abortMotion();
                }

                previousEncoder = currentEncoder;
            }
        } else {
            while (!onGround
                    && opMode.opModeIsActive()
                    && !opMode.isStopRequested()
                    && !hasAborted
                    && elapsedTime.seconds() <= secondsTimeout) {

                int currentEncoder = motorLift.getCurrentPosition();

                motorLift.setPower(dropDirection * DROP_POWER);

                if (Math.abs(motorLift.getCurrentPosition()) >= COUNTS_TO_DROP) {
                    onGround = true;
                } else if (currentEncoder == previousEncoder) {
                    telemetry.addData("Lift Drop", "WARNING, No movement");
                    telemetry.update();

                    flagCount++;
                }

                if (flagCount > 10) {
                    abortMotion();
                }

                previousEncoder = currentEncoder;

                telemetry.addData("Current Encoder: ",  currentEncoder);
                telemetry.addData("Target Encoder: ", COUNTS_TO_DROP);
                telemetry.addData("Flag Count", flagCount);
                telemetry.update();
            }
        }

        abortMotion();
    }

    /**
     * Determines the loaded direction of the motor (which power direction requires more power) and
     * returns the sign of that direction (+1 if positive, -1 if negative, 0 if unsure).
     *
     * @param motor The motor for which to find the loaded direction
     * @return The loaded direction of the motor in sign (-1, 1, 0)
     */
    private int findLoadedDirection(DcMotor motor) {
        telemetry.addData("Find Loaded Direction", "Starting for motor: " + getMotorName(motor));
        telemetry.update();

        double negativeEncoderMovement;
        double positiveEncoderMovement;
        int loadedDirection;

        double powerMagnitude = Range.clip(Math.abs(LOADED_DIRECTION_TEST_POWER), 0, 1);

        //Test the negative direction
        resetEncoder(motor);

        motor.setPower(-powerMagnitude);
        opMode.sleep(LOADED_DIRECTION_TIME_INTERVAL);
        motor.setPower(0);

        negativeEncoderMovement = Math.abs(motor.getCurrentPosition());

        //Sleep Interval
        opMode.sleep(LOADED_DIRECTION_TIME_INTERVAL);

        //Test the Positive direction
        resetEncoder(motor);

        motor.setPower(powerMagnitude);
        opMode.sleep(LOADED_DIRECTION_TIME_INTERVAL);
        motor.setPower(0);

        positiveEncoderMovement = Math.abs(motor.getCurrentPosition());

        //Find the value
        if (negativeEncoderMovement < positiveEncoderMovement) {
            loadedDirection = -1;
        } else if (positiveEncoderMovement < negativeEncoderMovement) {
            loadedDirection =  1;
        } else {
            loadedDirection = 0;
        }

        //Telemetry and return the value
        telemetry.addData("Find Loaded Direction", "Finished, loaded direction (" + loadedDirection + ") with -/+ (" + negativeEncoderMovement + ")/(" + positiveEncoderMovement + ")");
        telemetry.update();

        return loadedDirection;
    }

    /**
     * Stop all motion and reset the 'hasAborted' variable for use in while loops. This is used for
     * a sudden halt of the robot and ALL loops that may be running in the autonomous library.
     *
     * Useful for when a stop is requested by the operator.
     */
    private void abortMotion() {
        hasAborted = true;

        motorLift.setPower(0);
        motorBucket.setPower(0);
        motorSlider.setPower(0);

        servoSweeper.setPower(0);

        telemetry.addData("Status", "Auxiliary Motion Aborted");
        telemetry.update();
    }

    /**
     * Stop all motors and reset the current encoder value to zero on each motor. Then, change the
     * motor run modes back to running without the encoder so that we can set the power to them
     * again.
     */
    private void resetEncoders() {
        motorLift.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        motorBucket.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
        motorSlider.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);

        motorLift.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
        motorBucket.setMode(DcMotor.RunMode.RUN_TO_POSITION);
        motorSlider.setMode(DcMotor.RunMode.RUN_TO_POSITION);
    }

    /**
     * Stop a single motor and reset the encoder value to zero. Then change the run mode back so
     * that power can be set.
     *
     * @param motor The motor whose encoder is to be reset
     */
    private void resetEncoder(DcMotor motor) {
        motor.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);

        motor.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
    }

    /**
     * Stop a single motor and reset the encoder value to zero. Then change the run mode back so
     * that power can be set. Different from the regular `resetEncoder` method as it sets the motor
     * to RUN_TO_POSITION.
     *
     * @param motor The motor whose encoder is to be reset
     */
    private void resetEncoderAndRunToPos(DcMotor motor) {
        motor.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);

        motor.setMode(DcMotor.RunMode.RUN_TO_POSITION);
    }

    /**
     * @param motor The motor in question
     * @return the name of a motor in user-readable format.
     */
    private String getMotorName(DcMotor motor) {
        if (motor == motorLift) {
            return "motorLift";
        } else {
            return "unknown";
        }
    }
}

languages: Java Markdown

repo_language: Java


text:
<repo_name>yaochang-zjuici/cdss-test-case<file_sep>/神经科case.md
## case1

诊断：伴钙化与囊变的脑白质病（1eukoencephalopathy with brain calcifications and cysts，LCC）

患者女，54岁，黑龙江人，汉族，已婚，因“犯困7年，头痛伴右侧肢体无力半年”于2014-03-13入院。患者2007年1月无明显诱因发现自己思睡，表现为入睡迅速，于外院就诊，诊断为“中枢神经系统脱髓鞘”，给予规律激素冲击治疗后症状好转。后病情较平稳。偶有睡眠增多现象。2013年10月出现头痛、间断性，同时伴有右侧肢体力弱，同时伴有发作性言语障碍，找词困难。于外院行头颅核磁检查，发现“颅内多发占位”，与2007年对比，左额叶囊变增大，大脑镰向右侧移位，右额顶出现新发占位，增强后有明显强化。患者症状呈缓慢持续进展，右侧肢体力弱加重，近期出现反应迟钝，间断思维混乱。为求进一步诊治来我院就诊，门诊以“颅内多发占位性病变”收入院。患病以来，患者精神可，饮食无明显异常，二便正常，体重无明显减轻。

既往史：平素体健，否认肝炎、结核病史，否认冠心病、糖尿病等病史。否认外伤、输血史，否认药物过敏。预防接种史随社会。个人史：生于原籍。无毒物和放射线接触史。无烟酒嗜好。按期预防接种。婚育史：已婚，爱人及子女体健，月经史：已绝经。家族史无特殊。
一般内科查体未见明显异常。神经系统查体：神志清楚，言语欠流利，偶有找词困难，余高级皮层功能活动大致正常。颅神经检查正常。四肢感觉检查基本正常；右上肢肌力Ⅳ级，右下肢肌力IV+级，肌张力增高。左侧肢体肌力正常。右侧腱反射较左侧稍活跃；右侧病理征（+）。共济运动稳准。脑膜刺激征（-）。

辅助检查：
血、生化及免疫检查未见异常。2007年外院脑脊液检查正常。
头颅CT示双侧白质低密度伴右侧点状高密度改变（图A, 2007年）；头MRI示双侧大脑半球白质区长T1、T2异常信号（图B,C, 2007年）；增强示点片状及环形强化（图D, 2007年）；头MRA未见异常（图I, 2007年）。
7年后患者的头颅CT、MR结果示颅内病变部位出现囊变，大脑镰向右侧移位，可见到强化及明显的效应（图E,F,G,H, 2014年）为明确诊断与2014年3月行左额叶囊肿切除减压术。

![](http://img.dxycdn.com/upload/2014/10/18/25/21491075.snap.jpg)

## case2

神经白塞病

女性，24岁，学生，主因“发作性左侧半身麻木、意识丧失8年”以“症状性部分性癫痫”入院。
现病史：患者8年前无明显诱因日间感左下肢麻木，继之左上肢、左面部麻木，持续数分钟后觉头晕，双眼及头部向左偏斜，意识逐渐丧失，双眼上吊，双上肢屈曲，双下肢伸直，持续约1-2分钟缓解。每月发作1次，表现类似，发作间期如常。7年前服用丙戊酸钠效果欠佳，后改用中药治疗（具体不详），之后3年未再发作。4年前至今每年发作1-3次，均在感冒、疲劳或停药后出现，发作表现同前，仍服用中药治疗。2周前自行停药2天，上述症状再次发作，意识丧失，左侧头部着地，缝合3针，拆线后到我院就诊。患者自发病以来，饮食及睡眠可，二便正常，体重无明显减轻。
既往史：第1胎，足月顺产。无高热惊厥史，幼时精神智力、运动发育正常。17年前（7岁）玩耍时从桌上摔下，头部着地，当时感局部疼痛，无意识丧失，未予重视，后头痛自行缓解。否认家族癫痫病史。否认颅内感染史。有反复口腔溃疡和外阴溃疡病史。
入院查体：血压105/75mmHg，神清语利，高级皮层功能检查正常。双瞳孔等大同圆，直径3.0mm，对光反应灵敏，眼动充分，无眼震。额纹对称，双侧示齿对称，伸舌居中，双侧软腭上抬有力，悬雍垂居中，双侧咽反射存在，转颈、耸肩有力。四肢肌力、肌张力正常，左侧肢体腱反射活跃，左侧病理征阳性。左侧指鼻、跟膝胫试验较右侧差, 深浅感觉无异常。颈软，脑膜刺激征阴性。
辅助检查：头颅MRI(外院）：右额颞多发点状异常信号；DSA（外院）：未见异常；短程脑电图（我院门诊）：右额颞为著慢波。

入院后检查：血、尿、便常规、血沉、凝血象、C反应蛋白、生化全项均在正常范围内；乙肝六项提示乙肝表面抗体阳性，余阴性。乳酸试验：空腹3.0mmol/L，运动后10分钟3.4mmol/L。免疫全套及抗中性粒细胞抗体谱检查均为阴性。
腰穿：压力135mmH2O；脑脊液常规：无色清亮，细胞总数4个/ul，白细胞数2个/ul；脑脊液生化在正常范围；脑脊液病理涂片未见明显细胞成分；脑脊液MBP正常（0.31nmol/L），IgG-24小时合成率4.452mg/24hr，高于正常。
长程脑电监测：患者多次诉左侧肢体麻木，同期脑电图未见变化。监测中有一次大发作，脑电图示右额高波幅慢波及尖慢波，波幅渐增，频率减快至尖波节律。考虑为症状性部分性癫痫可能性大，右侧额叶起源？
头颅MR：右额顶、右底节区多发片状长T1、长T2异常信号，FLAIR示右额颞顶片状高信号影，脑室系统略扩大，右侧为著，MRA未见明显异常。

增强头颅MR：右侧额颞顶、岛叶、基底节区、丘脑（大脑中动脉部分分布区）脑梗塞；左侧小脑半球皮层缺血性改变可能性大。

诱发电位：BEAP正常；SEP-上肢：提示右顶皮层及皮层下深感觉传导通路障碍；请结合临床除外左顶病变，建议定期复查；SEP-下肢：提示T12以上至右顶皮层深感觉传导通路障碍；VEP：大致正常。
韦氏成人智力量表测查：智商103分，言语智商显著高于操作智商。
眼科会诊（2次）：右眼视力0.25，左眼视力0.4，右鼻侧视野缺损，左颞下部分视野缺损，无虹膜睫状体炎改变。
诊疗经过：患者入院后逐渐减少原有中药治疗，行长程脑电监测，监测结束后给予得理多100mg，Bid治疗，逐渐增加至200mg，Bid。住院期间仍间断有大发作，共4次，转入神外行开颅手术活检。

## case3

第三例：
中枢神经系统肉芽肿性血管炎

患者女性，54岁，主因“右侧颈部疼痛4月，右侧枕部疼痛2月，右侧肢体力弱、记忆力下降1月”收入院。
现病史：患者4月前无明显诱因出现右侧颈部疼痛，持续性胀痛，久坐久立后加重，平躺休息后缓解，并伴左上肢麻木，未予特殊处理。2月前出现右枕部疼痛，呈胀痛，无恶心、呕吐，无肢体活动障碍，肢体抽搐，无精神异常，无意识障碍、二便失禁，就诊于当地医院，以“颈椎病”收入疼痛科。住院期间行头颅CT（2013-12-20）：右侧顶枕叶低密度影待查，增强CT提示右侧颞顶枕叶交界处病灶。头颅MRI增强扫描（（2013-12-24）），提示右侧顶枕叶异常信号影，考虑胶质瘤可能性大，于1个半月前行右枕颞叶占位切除术。术后予以甘露醇脱水、脑蛋白水解物营养神经。病理检查（右侧枕叶）：慢性肉芽肿性炎症，结核可能性大，行TB-SPOT阴性，抗结核抗体阳性，患者无低热、盗汗、乏力等，未予以抗结核治疗。患者1月前出现精神异常，情绪不稳定，间断躁动、吵闹、拒绝进食，反复拔出输液针头，右侧肢体力弱，右上肢抬举费力，持物不稳，伴记忆力下降，性格改变，行头颅CT：右侧枕部术后改变，右枕水肿范围稍扩大，左侧额叶斑片状低密度影。头颅MRI：右侧颅脑术后改变，术区未见确切异常强化灶，伴周围胶质增生改变。双侧额叶、顶叶多发异常信号灶。2周前，另一医院神经疾病讨论会考虑“结核可能性大”，口服抗结核治疗，现为进一步诊治，收住我院。患者自发病以来，精神弱，饮食可，睡眠差，大小便如常，近期无体重变化。
既往史：腰椎间盘突出症病史20年，颈椎病病史2月。有高血压史2月。
传染病史：否认肝炎、结核、SARS、禽流感等传染病史。
家族史：否认家族遗传病史及类似疾病史。
入院查体：血压130/80mmHg，神志淡漠，查体欠合作，定向力、计算力、记忆力下降，双侧瞳孔等大等圆，对光反射灵敏，双侧鼻唇沟对称，口角不偏，伸舌居中，右上肢近端肌力III级，远端肌力IV级，左上肢肌力V级，右下肢肌力IV级，左下肢肌力V级，肌张力正常，右侧hoffmann阳性，双侧babinski阳性。共济运动、感觉欠配合。
辅助检查：
凝血四项、甲功全项、生化全项大致正常，同型半胱氨酸7.0umol/L。
肿瘤全项(女)：肿瘤相关抗原15-3 31.42U/ml↑；余正常。动态红细胞沉降率12mm/h。
风湿三项_免疫五项：均正常。抗核抗体谱检测：均阴性。抗中性粒细胞胞浆抗体阴性。
多次染色均未见抗酸杆菌、新型隐球菌，未见细菌。
免疫球蛋白(IgG IgM IgA)：免疫球蛋白G 21.30g/l↑，免疫球蛋白A 4.83g/l↑，免疫球蛋白M 5.15g/l↑。脑脊液特异IgG寡克隆区带阳性。
脑脊液TORCH8项：阴性。
血：淋巴细胞培养+干扰素（刺激水平T) 34，淋巴细胞培养+干扰素（基础水平T) 33，结核杆菌r-干扰素释放试验33（3+）。脑脊液：淋巴细胞培养+干扰素（刺激水平T) 0，淋巴细胞培养+干扰素（基础水平T) 0，结核杆菌r-干扰素释放试验0（-）。结明三项阴性。血ADA 51U/L↑，脑脊液ADA 1 U/L。
脑脊液Hu Ri Yo：阴性
腹部超声（2014-2-16）：肝、胆、胰、脾、双肾未见明显异常。
胸部CT：未见明显异常。
<file_sep>/内分泌.md
患者男性，61岁，因“颈部活动受限3年，躯干僵直2年，间断四肢肌肉痉挛1年”收入院。

患者3年前无明显诱因自觉后颈部肌肉酸胀， 左右旋转受限，睡眠时多汗；2 年前出现颈背部和 躯干肌肉紧张与僵直，躺下后起身困难；1 年前出 现颈部前屈，左右侧屈不能，头后仰位，精神紧张时 间断出现四肢肌肉痛性痉挛，每次持续数秒，jingzuo时多见，以双上肢为主。起病以来身高降低5 cm， 体重减轻26 kg。

既往史：“2型糖尿病（T2DM）”史 2 年，口服“二甲双胍 500 mg 3 次/d、阿卡波糖 100 mg 3 次/d”，自测空腹血糖（FPG）6~7 mmol/L， 餐后2 h血糖8~10 mmol/L。“高血压病”史20年，血 压最高 150/100 mmHg（1 mmHg=0.133 kPa），口服 “氯沙坦钾 80 mg 1 次/d”后，血压控制在 130~ 140/90 mmHg。“颈椎病和腰椎病”史3年。有“磺胺 类”药物过敏史。无类似疾病家族史。

 入院时查体：血压140/80 mmHg，身高1.65 m， 体重46 kg，体质指数（BMI）16.9 kg/m2 。神志清楚， 言语流利。甲状腺未触及肿大。腹部肌肉张力增 高。脊柱前凸，颈后部、背部肌肉肌张力明显增高； 四肢肌力5级，四肢肌张力略增高；深浅感觉无异 常；双侧腱反射活跃；病理反射未引出；自主神经功 能正常。

入院后对患者进行相应辅助检查，实验室检查结果 FPG 15.29 mmol/L；糖 化 血 红 蛋 白（HbA1c ） 10.60%（正常范围 4%~6%），尿糖+4，尿酮体阴性。 血电解质、肝肾功能、血脂、心肌酶谱、D-3 羟丁酸 等未见异常。垂体激素、甲状旁腺激素、甲状腺功 能未见异常。胰岛功能（馒头餐试验）检查结果如 表 1。

抗甲状腺球蛋白（thyroid globulin，TG）抗体 1 044 mU/L（正常范围 5~100 mU/L）；抗甲状腺过氧 化物酶（thyroid peroxidase，TPO）抗体正常。GADA 39.0 mU/L（正常范围<0.5 mU/L）；蛋白酪氨酸磷酸 酶2（IA-2A）抗体、胰岛细胞抗体（ICA)、胰岛素自身 抗体（IAA）均为阴性。抗神经元抗体（如抗Ri、Hu、 Yo、谷氨酸受体、CV2、Amphiphysin 和抗副肿瘤 MA2 抗 体 等）均 为 阴 性 。 人 类 白 细 胞 抗 原 HLA-B27、抗核抗体、抗双链 DNA 抗体、可提取性核抗原谱、抗中性粒细胞胞浆抗体（antineutrophil cytoplasmic antibodies，ANCA）均为阴性。肿瘤系列 未见异常。影像学检查结果 头颅MRI未见异常。脊柱MRI提示颈、腰椎轻 度退行性变。骶髂关节CT未见异常。彩超提示双 叶甲状腺结节。肌电图提示双侧胸锁乳突肌、斜方 肌松弛时呈自发放电状态，静脉注射5 mg地 西泮后自发电位较前明显减少。
![](https://img1.dxycdn.com/2017/1106/137/3242584443153075141-8w.png)

诊断：僵人综合征合并LADA 和自身免疫性甲状腺炎（甲状腺功能正 常）。 病例来源于：中华糖尿病杂志 2017 年1月第 9 卷第1期：僵人综合征合并成人隐匿性自身免疫 糖尿病一例及文献回顾
<file_sep>/儿科case.md
### 案例一
http://www.dxy.cn/bbs/topic/25110870?keywords=%E9%97%A8%E8%AF%8A%E7%96%91%E9%9A%BE%E7%97%85%E4%BE%8B%E8%AE%A8%E8%AE%BA

一般情况：患儿，男，1岁2个月，汉族，2013年3月8号入我院
主诉：全身皮疹伴间断性发热20天
现病史：患儿于入院前20天（2月14日）无明显诱因下出现颜面部散在红色斑丘疹，至夜间3点，全身出现皮疹，稍高出皮面，压之褪色，伴有瘙痒，当地医生给予抗过敏治疗，三天后发热，热峰40.5℃，无抽搐，当地医院门诊输液2天，发热皮疹缓解（用药不详），2月24日，再次发热、全身皮疹，稍有咳嗽，继续当地门诊输液3天，效果不佳，在当地上级医院以“败血症、过敏性皮炎、支气管肺炎、化脓性腮腺炎”住院治疗，期间，皮疹进一步增多，融合成片状，伴有左侧腮腺肿大，发热症状稍有缓解，家属为进一步治疗，入住我院。病程中，患儿神情，精神可，稍有烦躁，呼吸稍促，食纳佳，二便调。
（目前情况：发热、咳嗽、全身皮疹，轻度烦躁。）
既往个人：无类似相关病史。否认传染病、否认过敏、无手术外伤输血史、个人史无特殊（简单化没特别）
母孕史：无特殊
家族史：无特殊
查体： T37 P150 次/分 R20次/分 血压 90/50 WT 8kg
神情，精神佳，稍有烦躁，呼吸平，全身可见大小基本均等的充血性丘疹，稍高出皮面，疹间皮肤颜色正常，部分融合成片，无明显脱皮，无黄染，双侧颈前颈后淋巴结肿大，1.0*0.5cm，活动良好，无你粘连，头颅正常，双侧瞳孔对光好，耳鼻无特殊，唇红稍有干裂，无紫绀，口腔黏膜完整，咽充血，扁桃体无肿大，舌头居中，舌苔均匀。颈软无强直，无颈静脉怒张，甲状腺无肿大，胸廓正常，呼吸运动对称，呼吸音稍粗，少量干啰音，心率齐，心音有力，腹软，稍膨隆，叩诊鼓音，移动性浊音(-),肝脏剑突下5cm，肋下3cm，质地中等，脾脏肋下2cm，双肾叩击痛(-)，神经系统检查无异常

入院时外院辅助检查：
1.左侧腮腺彩超：左侧腮腺炎？
2.胸部CT：支气管炎
3.支原体衣原体阴性
4.血尿淀粉酶：810U/L 和 1278U/L
入院后我院的辅助检查结果：
1.血常规+CRP：白细胞 15.09*109/L 血小板 182*109/L 中性42% 淋巴39% 嗜酸 11% 单核 7% 血红蛋白93g/L 异常白细胞 未见 CRP<8
2.肝功能：谷丙 763U/L 谷草 593U/L
3.DIC：PT 13.1s APTT 31.6 s FIB 1.51g/L
4.铁蛋白：1090ug/L
5.白介素2受体测定：>7500ug/L
6.其他：肾功能、血沉、抗o 、类风湿因子、尿粪常规、血糖血脂、电解质、血气分析、痰培养血培养、脑脊液常规生化、血尿淀粉酶脂肪酶、IGA IGG IGM IGE、CD3 4 8 NK、骨穿检查都正常。
7。B超检查：颈部淋巴结肿大、肠系膜淋巴结肿大，最大1.2*0.5cm，肠腔充气明显，肝胆胰脾肾无异常
8.胸片：两肺纹理增粗

http://www.dxy.cn/bbs/topic/40121509?keywords=%E6%98%93%E8%AF%AF%E8%AF%8A%E7%97%85%E4%BE%8B
<file_sep>/急诊.md
患者，某某，男，３７岁．
主诉：上腹疼痛１小时．
现病史：患者于１小时前晚餐进食较多剩饭后，出现上腹部疼痛，呈持续性，无放射，伴返酸，恶心，未呕吐．急来诊，门诊测血压１２０／９０mmHg，行心电图：如图示．心脏听诊无杂音，肺部听诊无异常．上腹轻压痛，无反跳痛，余无殊．患者自诉以前高考体检时发现过早搏，平素胃不好，经常胃痛，无其他病史．自感此次主要是饮食不洁，胃病所致，故强烈反对检查输液观察，要求开些治胃病的药物回家治疗．于一小时后，病人再次急来诊，诉回家后上腹疼痛程度渐加重，性质同前，门诊呈端坐呼吸，呼吸费力，大汗，血压１００／７０mmHg，两肺呼吸音粗，两肺底可闻及湿罗音，心电图如图所示．心脏未闻及杂音，心率快，律不齐，腹平软，中上腹有压痛，无反跳痛，肝脾未触及，无移动性浊音，双下肢无水肿，神经系统查体无殊．
门诊治疗经过：门诊急吸氧，心电血压监护，并按心衰给予对症治疗，应用抗心律失常药物，观察后复查心电图如图．症状改善不很明显．请相关科室会诊后转科治疗．
门诊检查回归：血常规：WBC:11.6*109 　N:87%　余正常．电解质血糖大致正常．血淀粉酶正常．心肌酶:AST 37 U/L LDH 169U/L HBDH 153U/L CK 279 U/L (24~170) CK-MB 44U/L(正常<25).　血气分析pH:7.47, pco2: 21.4mmHg po2:104mmHg ,BE:-3.1

第一次来诊时心电图如下：
![](http://img.dxycdn.com/upload/2007/04/11/91755413.snap.jpg)

 第二次来诊时心电图：
 ![](http://img.dxycdn.com/upload/2007/04/11/31162551.snap.jpg)

  应用药物后复查心电图：
  ![](http://img.dxycdn.com/upload/2007/04/11/43595454.snap.jpg)

典型的容易误诊为急性心肌梗死的急性重症病毒性心肌炎

患者，男性，60岁。因腹胀，左下肢活动后疼痛、麻木1周入院。

平素体健，新发糖尿病。

患者1周前于搬重物后出现腹胀，左下肢活动后疼痛、麻木，就诊于消化科门诊，建议行胃镜检查，患者拒绝。因症状反复，伴发热，体温最高达38.6℃，伴腰部酸痛而急诊。急诊血常规WBC升高，随机血糖12.3mmol/L，糖化血红蛋白7.5％。尿常规尿糖阳性，酮体1+，心肌酶及电解质正常。彩超下肢动脉硬化，足背动脉多发粥样硬化斑块，脂肪肝。以糖尿病酮症，泌尿系感染收住内分泌科。

查体：T37.9℃，BP154/86mmHg，心肺未及异常，腹部未及异常。左足背动脉搏动减弱，余未发现明确阳性体征。

入院诊断：糖尿病酮症，糖尿病周围血管病变，糖尿病自主神经和周围神经病变？泌尿系统感染，脂肪肝，高血压1级？

入院后予以降糖、抗感染、改善循环、营养神经治疗，患者症状好转。次日血压162/94mmHg，加用ARB类药物降压。

入院相关检测结果回报D-二聚体 4514 ng/ml，纤维蛋白原 7.92 g/L。急查血气分析：PH 7.4, PO2 77 mmHg，PCO2 41 mmHg。红细胞 4.09×1012/L，Hb 123g/L。余结果正常。

公布结果：

入院的第三天，胸部CT回报：主动脉弓降移行部扩张，降主动脉腔内密度欠均，建议结合临床必要时增强CT检查，左侧胸腔积液，左肺轻度不张。

紧急行主动脉强化CT，主动脉弓、降主动脉至双侧髂总及右侧髂内动脉上段盆腔内可见膜状低密度影，将其分为真假两腔，诊断主动脉夹层（stafford B型），主动脉弓降结合部主动脉瘤，左侧胸腔积液，左肺局部受压实变不张。

http://www.dxy.cn/bbs/topic/34141243?keywords=%E7%96%91%E9%9A%BE%E7%97%85%E4%BE%8B%E8%AE%A8%E8%AE%BA

患者男，47岁，农民。

突发上腹痛10小时，伴意识障碍1小时。

10小时前突发上腹部疼痛，可忍受，无腰背放射痛，无恶心呕吐，至当地诊所输液抗炎、解痉治疗后症状缓解不明显，回家休息。1小时前出现意识障碍，大汗淋漓，皮肤湿冷，120急送诊我院急诊中心。

既往无特殊病史。

PE：HR102次/min，R20次/min，BP60/40mmHg。神志淡漠，皮肤湿冷，双下肺湿性啰音，心律齐。腹肌紧张，压痛、反跳痛（+）。神经系统无定位体征。

立即行腹腔穿刺见暗红色血性液，导尿尿量少。

辅助检查：血常规：ＷＢＣ１８×１０^9，NEU87%。ECG：T波改变。

床旁超声：床边胸腔B超（-），腹部B超仅见腹腔少量积液，肝胆胰脾肾（-）

ＩＭＰ：急性胃肠道穿孔？ 感染性休克。

立即予液体复苏+多巴胺，血压回升不明显。

讨论：临床诊断？（一周左右公布结果）

公布结果：

胸部、上腹部CT平扫+增强示：主动脉夹层Debakey I型，撕裂范围广泛，从升主动脉-主动脉弓-降主动脉-胸主动脉-腹主动脉-一直撕到双侧髂总动脉。
<file_sep>/README.md
# cdss-test-case
收集的疑难病例，供市面上cdss产品测评使用
<file_sep>/普外.md
http://www.dxy.cn/bbs/topic/34038573?keywords=%E6%98%93%E8%AF%AF%E8%AF%8A%E7%97%85%E4%BE%8B

病例一

患者性别：女

患者年龄：20 岁

简要病史：以「阵发性腹痛 3 天」入院，3 天前在夜市吃串串香后出现上腹痛，阵发性加剧，自觉最痛部位为剑突下，无转移性疼痛，呕吐后缓解。查妇科超声：盆腔积液约为 1 cm，子宫附件未见异常；血常规：WBC 10.2×10^9/L；腹部立位平片未见异常。先后给予「头孢哌酮舒巴坦，6542 针」后腹痛缓解，仍有阵发性加剧疼痛，难以耐受。10 小时前自排大便1次，成型。

查体：右下腹有一长约 3 cm麦氏切口，剑突下压痛，下腹压痛明显伴反跳痛，最疼痛部位为下腹部正中脐下四横指下方。双合诊子宫体压痛。余无明显异常。

辅助检查：血淀粉酶阴性。全腹 CT：子宫稍大，右下腹含液气性包块。

病例一答案：肠扭转

病例二

患者性别：女

患者年龄：7 岁

简要病史：患者以「晨起出现腹痛 2 小时」入院。无发热，无呕吐，无腹泻。女孩为留守儿童，由爷爷奶奶照看。
查体：患儿痛苦状，呼吸急促。询问不应答，口唇干燥，无发绀。腹部可见肠型，可触及大量包块，肠鸣音未闻及。
治疗：入院后予生理盐水加开塞露灌肠导便，腹痛无明显缓解。

辅助检查：腹部超声：大肠内可见大量的大积便，未见肠蠕动。
病例二答案：糖尿病酮症酸中毒
<file_sep>/疼痛科.md
http://www.dxy.cn/bbs/topic/30619922?keywords=%E9%97%A8%E8%AF%8A%E7%96%91%E9%9A%BE%E7%97%85%E4%BE%8B%E8%AE%A8%E8%AE%BA

疑难病例讨论（宣武医院疼痛科）
患者xxx，女，32岁， 入院时间2015年3月23日10点
病例特点：
1患者：中年，女性，缓慢起病。
2主诉：发作性头面痛8年，加重半年。
3现病史：患者8年前无明显诱因出现头面痛，双眼及头顶部为重，性质为胀痛，针刺痛，每月数次， VAS评分：7-8分，可自行缓解，缓解期仍有头面痛VAS评分：1-2分，四肢活动可。此后8余年间断性疼痛，并逐渐加重，频率大约每月1-2次，口服止痛药，针灸，按摩无显效。半年前头面痛加剧，疼痛范围同前，右眼先发，可向牙床放射，平卧及睁眼加重眼痛，VAS评分：7-8分，因痛影响睡眠。曾就诊多个科室，神经内科查头MRT无明显异常，诊断“偏头痛”给予止痛药及抗抑郁药无显效；到北京同仁医院及北京武警三院眼科检查无明显异常；2014-11月在我科疼痛门诊行颈2椎旁神经阻滞，无效。于2014-12到北京中日友好医院疼痛门诊行星状神经节阻滞，效果不佳且述治疗后右眼部疼痛较前加重，出现过电感。近10天，疼痛频繁发作，且右眼及眶后剧痛，VAS评分：9-10分针刺痛，过电样痛，可串入牙周，加重时双眼，上颌部，头顶部均有疼痛，口服加巴喷丁无效，缓解期评分仍为5-6分，伴颈部不适，左肩酸痛，不伴头晕，不伴流泪、流涕、鼻塞，眼红等，月经周期正常。患者起病以来神志清，精神、饮食、睡眠均受疼痛影响，大小便如常，体重无明显变化。
4既往史：否认高血压、糖尿病史，否认冠心病史，否认药物过敏史。
9年前被人搬动颈椎后出现颈部及左肩疼痛，常年颈椎酸胀不适。于08年2月到北医三院行鼻窦部手术（具体术式不详），自述术后鼻部症状有部分改善。
5、入院检查：T：36.5 P ：75次/分 R：18次/分 BP：115/80mmg 发育正常，身高155cm 体重51kg
双侧瞳孔等大同圆，对光反射存在，鼻唇沟对称，伸舌居中，面部无压痛，右侧面部痛觉明显减退，嘴角无歪斜，面部肌力无异常。
颈椎旁C2左轻压痛，颈椎椎体前右侧深压痛，eaton征（-）spurting（—），生理反射存在，病理反射：双侧肱二头肌反射（+++），双侧肱三头肌反射（+++），双桡骨膜反射（++），双侧Rossolimo征（+），闭目难立征（+），双巴氏征（-），双上肢肌力感觉均正常。
6、辅助检查：
已查：心电图，血常规，查耳血，血生化，凝血四项，胸片，颈椎正侧位+双斜位，颈椎MRI，颈椎CT环枢椎三维重建（2015-3-27做）
其中尿常规： 高倍镜下白细胞增高，红细胞增高，自述无尿频尿急尿痛等症状，嘱多饮水。
头颅MRI；平扫未见明显异常（中国人民解放军309医院2012-6-29）
眼部MRI：眼眶平扫未见明显异常（邯郸市中心医院2015-3-13）
颈椎MRI：颈5-6椎间盘轻度突出（2015-3-24）
7初步诊断：1、蝶腭神经痛（右）2、颈源性头痛（双侧）

讨论：1诊断？
2治疗？蝶腭神经阻滞？颈椎旁神经阻滞？颈上神经阻滞？颈椎硬模外置管连续给药？蝶腭神经阻滞射频热凝？

 该患者于2015-3-25在局麻下行蝶腭神经阻滞（经腭大孔）术，术后疼痛明显缓解伴麻木感3小时，VAS评分1分，3小时后恢复原疼痛，另外左眼疼痛较前加重。治疗仍给泰勒宁口服，对症处理。

branch_name: refs/heads/master

repo_language: Markdown

repo_name: yaochang-zjuici/cdss-test-case


text:
<file_sep>package Game.Server.model;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;

/*
** Creating a rand word by getting a random word from the resource file word.txt
 */

public class Word {

    private static ArrayList<String> lOfWords = new ArrayList<>();

    public static String randomWord(){
        try( Scanner sc = new Scanner(new File("C:\\Users\\Ahmad\\Desktop\\homework1\\Hangman-Game\\res\\words.txt"))) {
            while(sc.hasNext()){
                String str=sc.next();
                lOfWords.add(str);
            }
        } catch (FileNotFoundException e) {
            System.out.println("FILE IO ERROR: " + e.getMessage());
        }
        int index=new Random().nextInt(lOfWords.size());
        return lOfWords.get(index);
    }
}
<file_sep>package Game.Client.net;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/*
** The part of the client that is responsible of
** the connection, sending and receiving data to and from
** the server
 */
public class ServerConnector {
    private Socket socket;
    private Scanner input;
    private PrintWriter output;
    private static InetAddress host;
    private static final int PORT_NO = 8080;

    public void connectToServer (){

        try{
            host = InetAddress.getLocalHost();
        }
        catch (UnknownHostException uhEX){
            System.out.println("Host ID not found!");
            System.exit(1);
        }

        try { // check this out one more time
            socket = new Socket(host, PORT_NO);
        }
        catch (IOException ioe){
            System.out.println("couldn't connect to host");
        }
    }

    public void sendToServer ( String sentData) throws IOException {
        output = new PrintWriter(socket.getOutputStream(), true);
        output.println(sentData);

        if(sentData.contains("disconnect")){
            disconnect();
        }
    }

    public String receiveFromServer () throws IOException {
        input = new Scanner(socket.getInputStream());
        return input.nextLine();
    }

    private void disconnect(){
        System.out.println("Disconnecting from server");
        try{
            socket.close();
            System.exit(0);
        }
        catch (IOException ioe){
            System.out.println(ioe);
        }
    }

}
<file_sep>package Game.Server.net;

import Game.Server.controller.Controller;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class ClientHandler implements Runnable {
    private final Socket clientSocket;
    private Scanner input;
    private PrintWriter output;
    private final Controller contr = new Controller();
    private boolean conncet = true;

    public ClientHandler(Socket clientSocket) {
        this.clientSocket = clientSocket;
    }

    // method called from the startConnection
    @Override
    public void run() {

        while(conncet){
            try {
                input = new Scanner(clientSocket.getInputStream());
                output =  new PrintWriter(clientSocket.getOutputStream(), true);
            }
            catch (IOException e) {
                e.printStackTrace();
            }

            // receiving data from network
            String received = input.nextLine();

            if(received.contains("disconnect"))
                disconnect();
            else{
                try {
                    contr.setInput(received);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // sending data to network
                output.println(contr.getOutput());
            }
        }

    }

    private void disconnect(){
        conncet = false;
        System.out.println("Client is disconnected " + clientSocket.toString());
        try{
            clientSocket.close();
        }
        catch (IOException ioe){
            System.out.println(ioe);
        }
    }
}


text:
<file_sep># **************************************************************************** #
#                                                                              #
#                                                         :::      ::::::::    #
#    Makefile                                           :+:      :+:    :+:    #
#                                                     +:+ +:+         +:+      #
#    By: obounri <<EMAIL>>            +#+  +:+       +#+         #
#                                                 +#+#+#+#+#+   +#+            #
#    Created: 2021/06/14 16:20:43 by obounri           #+#    #+#              #
#    Updated: 2021/06/17 17:07:01 by obounri          ###   ########.fr        #
#                                                                              #
# **************************************************************************** #

CC = gcc
CFLAGS = -Wall -Wextra -Werror
HEADER = includes/minitalk.h

PROG1 = client
PROG2 = server

SRCS = srcs/utils.c

LIBFT_MAKEFILE_PATH = srcs/libft/
LIBFT = srcs/libft/libft.a

all: $(PROG1) $(PROG2)

$(PROG1): $(SRCS) $(LIBFT) $(HEADER) client.c
	$(CC) $(CFLAGS) client.c $(SRCS) $(LIBFT) -o $(PROG1)

$(PROG2): $(SRCS) $(LIBFT) $(HEADER) server.c
	$(CC) $(CFLAGS) server.c $(SRCS) $(LIBFT) -o $(PROG2)

$(LIBFT): $(LIBFT_SRCS)
	make -C $(LIBFT_MAKEFILE_PATH)

clean:
	make -C $(LIBFT_MAKEFILE_PATH) clean

fclean: clean
	rm -f $(PROG1) $(PROG2) $(LIBFT)

re: fclean all

repo_language: Makefile

repo_name: obounri/minitalk


text:
<file_sep>![image](https://user-images.githubusercontent.com/89521166/132383950-2b27150f-57fc-4d77-9549-26f52abd55ed.png)
<file_sep>### <NAME>
<file_sep>- 1. Item 1
- 2. Item 2
- 3. Item 3
<file_sep>:smile:
**Bold**

_Italic_
<file_sep>[Github](https://github.com/BillArico)

branch_name: refs/heads/main

repo_name: BillArico/markdown-portfolio