Snippets Collections
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : MonoBehaviour
{
    public float speed;
    public Vector3 moveOffset;
    private Vector3 targetPos;
    private Vector3 startPos;


    // Start is called before the first frame update
    void Start()
    {
        startPos = transform.position;
        targetPos = startPos;
    }

    // Update is called once per frame
    void Update()
    {
        transform.position = Vector3.MoveTowards(transform.position, targetPos, speed * Time.deltaTime);
        if (transform.position == targetPos)
        {
            if (startPos == targetPos)
            {
                targetPos = startPos + moveOffset;

            }
            else
            {
                targetPos = startPos;

            }
        }
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            other.GetComponent<PlayerController>().GameOver();
        }

    }


}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Coin : MonoBehaviour
{
    public float rotateSpeed = 180.0f;

    
        // Update is called once per frame
        void Update()
        {
            transform.Rotate(Vector3.up, rotateSpeed * Time.deltaTime);
        }

        private void OnTriggerEnter(Collider other)
        {
            if (other.CompareTag("Player"))
        
            {
                other.GetComponent<PlayerController>().AddScore(1);
                Destroy(gameObject);
            }
        }
}
    

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraFollow : MonoBehaviour
{
  public Transform target;
  public Vector3 offset;

  void Update()
   {
     transform.position = target.position + offset;
   } 
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;


public class PlayerController : MonoBehaviour
{
    public Rigidbody rig;
    public float moveSpeed;
    public int score;
    public float jumpForce;
    private bool isGrounded;

    void Update()

    {

        float x = Input.GetAxisRaw("Horizontal") * moveSpeed;
        float z = Input.GetAxisRaw("Vertical") * moveSpeed;

        rig.velocity = new Vector3(x, rig.velocity.y, z);

        Vector3 vel = rig.velocity;

        vel.y = 0;

        if (vel.x != 0 || vel.z != 0)
        {
            transform.forward = vel;

        }

        if (Input.GetKeyDown(KeyCode.Space) && isGrounded == true)
        {
            isGrounded = false;
            rig.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
        }
        if (transform.position.y < -5)
        {
          GetComponent<PlayerController>().GameOver();
        }


    }

    void OnCollisionEnter(Collision collision)
    {
        if (collision.GetContact(0).normal == Vector3.up)
        {
            isGrounded = true;

        }


    }
    public void GameOver()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
    }
    
    public void AddScore(int amount)
    {
        score += amount; 

    }
}
using System;
 
using System.Collections.Generic;
 
using System.Linq;
 
using System.Reflection;
 
using System.Runtime.InteropServices;
 
using System.Security.Claims;
 
using System.Security.Cryptography.X509Certificates;
 
using System.Text;
 
using System.Threading.Tasks;
 
using System.Xml.Linq;
 
using Unit4.CollectionsLib;
 
 
 
namespace OpenS
 
{
 
    internal class Program
 
    {
 
        static void Main(string[] args)
 
        {
 
            // יצירת שרשרת חוליות (של מספרים שלמים) חדשה בעלת איבר אחד, איבר הבא נאל
 
            Node<int> node = new Node<int>(1);
 
            Console.WriteLine("Chain: " + node); // הדפסת השרשרת       
 
 
 
            node.SetValue(2); // עדכון ערך השרשרת
 
            Console.WriteLine("New Chain: " + node); // הדפסת השרשרת החדשה  
 
 
 
            // יצירת שרשרת חוליות (של מספרים שלמים) חדשה בעלת איבר אחד, איבר הבא נאל
 
            Node<int> chain = new Node<int>(1);
 
            Console.Write("New Chain: "); PrintChain(chain); // הדפסת (כל) השרשרת
 
 
 
            // יצירת שרשרת חוליות (של מספרים שלמים), איבר הבא נאל
 
            Node<int> chain1 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            Console.Write("New Chain: "); PrintChain(chain1); ; // הדפסת השרשרת
 
 
 
            // גישה לערכים
 
            Console.WriteLine("First Node Value: " + chain1.GetValue()); // קבלת הערך של האיבר הראשון
 
            Console.WriteLine("Second Node Value: " + chain1.GetNext().GetValue()); // קבלת הערך של האיבר השני
 
            Console.WriteLine("Third Node Value: " + chain1.GetNext().GetNext().GetValue()); // קבלת הערך של האיבר השלישי
 
            //...
 
 
 
            Node<int> chain2 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5))))); // יצירת שרשרת חדשה
 
            Console.Write("New Chain: "); PrintChainReverse(chain2); // הפעלת פונקציה שלוקחת שרשרת מקושרת ומחזירה את איברי השרשרת בסדר הפוך
 
 
 
            Node<int> chain3 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5))))); // יצירת שרשרת חדשה
 
            int size = SizeOfChain(chain3); // הפעלת פונקציה שלוקחת שרשרת ומחזירה את כמות האיברים בשרשרשת מקושרת
 
            Console.WriteLine("Size Of Chain: " + size); // הדפסת השרשרת החדשה
 
 
 
            Node<int> chain4 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            int NodeValue1 = 1;
 
            int NodeValue2 = 0;
 
 
 
            bool IsNodeExists1 = IsNodeExists(chain4, NodeValue1); // הפעלת פונקציה שבודקת אם ערך ווליו שמתקבל קיים בשרשרת
 
            Console.WriteLine("Is The Value " + NodeValue1 + " Exist? " + IsNodeExists1);
 
 
 
            bool IsNodeExists2 = IsNodeExists(chain4, NodeValue2); // הפעלת פונקציה שבודקת אם ערך ווליו שמתקבל קיים בשרשרת
 
            Console.WriteLine("Is The Value " + NodeValue2 + " Exist? " + IsNodeExists2);
 
 
 
            Node<int> chain5 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            chain5 = RemoveFirst(chain5); // הפעלת פונקציה שלוקחת שרשרת ומסירה את האיבר הראשון בשרשרת מקושרת
 
            Console.Write("New Chain: "); PrintChain(chain5); // הדפסת השרשרת החדשה
 
 
 
            Node<int> chain6 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            chain5 = RemoveLast(chain6); // הפעלת פונקציה שלוקחת שרשרת ומסירה את האיבר האחרון בשרשרת מקושרת
 
            Console.Write("New Chain: "); PrintChain(chain6); // הדפסת השרשרת החדשה
 
 
 
            Node<int> chain7 = new Node<int>(1, new Node<int>(3, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            int value1 = 3;
 
            bool IsNodeExists3 = IsNodeExists(chain7, value1); // בדיקה אם הערך שאנחנו רוצים להוציא מהשרשרת המקושרת בכלל קיים
 
 
 
            if (IsNodeExists3 == true) // אם הערך קיים
 
            {
 
                chain6 = RemoveByValue(chain6, value1); // הפעלת הפונקציה שמסירה איבר לפי ערך
 
                Console.Write("New Chain: "); PrintChain(chain6); // הדפסת השרשרת החדשה
 
            }
 
 
 
            Node<int> chain8 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            int index = 3;
 
            chain8 = RemoveByIndex(chain8, index); // הפעלת הפונקציה שמירה איבר לפי אינדקס
 
            Console.Write("New Chain: "); PrintChain(chain8); // הדפסת השרשרת החדשה
 
 
 
            // יצירת שרשרת חוליות של מספרים שלמים. נקסט אחרון שווה נאל
 
            Node<int> chain9 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5))))); // יצירת שרשרת חוליות של מספרים שלמים. נקסט אחרון שווה נאל
 
            // יצירת שרשרת חוליות של מספרים שלמים. נקסט אחרון שווה נאל
 
            Node<int> chain10 = new Node<int>(5, new Node<int>(4, new Node<int>(3, new Node<int>(2, new Node<int>(1))))); // יצירת שרשרת חוליות של מספרים שלמים. נקסט אחרון שווה נאל
 
 
 
            bool isSorted1 = IsSortedAscending(chain7); // הפעלת הפונקציה שבודקת אם סדר האיברים עולה ברשימה מקושרת
 
            Console.WriteLine("Is Chain Sorted Ascending? " + isSorted1);
 
            bool isSorted2 = IsSortedAscending(chain8); // הפעלת הפונקציה שבודקת אם סדר האיברים עולה ברשימה מקושרת
 
            Console.WriteLine("Is Chain Sorted Ascending? " + isSorted2);
 
 
 
            bool isSorted3 = IsSortedDescending(chain9); // הפעלת הפונקציה שבודקת אם סדר האיברים יורד ברשימה מקושרת
 
            Console.WriteLine("Is Chain Sorted Descending? " + isSorted3);
 
            bool isSorted4 = IsSortedDescending(chain10); // הפעלת הפונקציה שבודקת אם סדר האיברים יורד ברשימה מקושרת
 
            Console.WriteLine("Is Chain Sorted Descending? " + isSorted4);
 
 
 
            Node<int> chain11 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            double average = Average(chain11); // הפעלת פונקציה שמחשבת את הממוצע ברשימה מקושרת ושמירתו במשתנה
 
            Console.WriteLine("The Average: " + average); // הדפסת הממוצע 
 
 
 
            Node<int> chain12 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            int number = 6;
 
            chain12 = AddNodeStart(chain12, number); // עפעלת פונקציה שמוסיפה איבר בתחילת שרשרת מקושרת
 
            Console.Write("New Chain: "); PrintChain(chain12); // הדפסת השרשרת החדשה
 
 
 
            Node<int> chain13 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            int number1 = 0;
 
            AddNodeEnd(chain13, number1); // הפעלת פונקציה שמוסיפה איבר בסוף שרשרת מקושרת
 
            Console.Write("New Chain: "); PrintChain(chain13); // הדפסת השרשרת החדשה
 
 
 
            Node<int> chain14 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            int value = 10;
 
            int index1 = 5;
 
            chain14 = AddNodeAtIndex(chain14, index1, value); // הפעלת פונקציה שמוסיפה איבר בשרשרת מקושרת לפי אינדקס 
 
            Console.Write("New Chain: "); PrintChain(chain14); // הדפסת השרשרת החדשה
 
 
 
            Node<int> chain15 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5, new Node<int>(6))))));
 
            Node<int> chain16 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
 
 
            FindAndPrintMiddle(chain15); // הדפסת האיבר/ים האמצעי/ים
 
            FindAndPrintMiddle(chain16); // הדפסת האיבר/ים האמצעי/ים
 
 
 
            Node<int> chain17 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            Node<int> chain18 = new Node<int>(2, new Node<int>(2, new Node<int>(10, new Node<int>(4, new Node<int>(5)))));
 
 
 
            bool isBalanced1 = IsBalanced(chain17); // הפעלת פונקציה שבודקת אם ברשימה מקושרת מספר האיברים הגדולים מהממוצע שווה למספר האיברים הקטנים מהממוצע
 
            Console.WriteLine("Is the list balanced? " + isBalanced1);
 
 
 
            bool isBalanced2 = IsBalanced(chain18); // הפעלת פונקציה שבודקת אם ברשימה מקושרת מספר האיברים הגדולים מהממוצע שווה למספר האיברים הקטנים מהממוצע 
 
            Console.WriteLine("Is the list balanced? " + isBalanced2);
 
 
 
            Node<int> chain19 =
 
                new Node<int>(2,
 
                new Node<int>(2,
 
                new Node<int>(2,
 
                new Node<int>(2,
 
                new Node<int>(3,
 
                new Node<int>(2,
 
                new Node<int>(4)))))));
 
 
 
            int numToFind = 2;
 
            int sequenceCount = sequences(chain19, numToFind);
 
            Console.WriteLine($"Number of sequences for {numToFind}: {sequenceCount}");
 
 
 
            Node<int> chain20 = new Node<int>(2, new Node<int>(0, new Node<int>(3, new Node<int>(4, new Node<int>(5, new Node<int>(6))))));
 
            int minIndex = FindMinValueIndex(chain20); // הפעלת פונקציה שמוצאת את האינדקס של הערך הנמוך ביותר בשרשרת
 
            Console.WriteLine("The index of the minimum value is: " + minIndex); // הדפסת הערך
 
 
 
            Node<int> chain21 = new Node<int>(0, new Node<int>(1, new Node<int>(3, new Node<int>(4, new Node<int>(5, new Node<int>(6))))));
 
            int maxIndex = FindMaxValueIndex(chain21); // הפעלת פונקציה שמוצאת את האינדקס של הערך הנמוך ביותר בשרשרת
 
            Console.WriteLine("The index of the maximum value is: " + maxIndex); // הדפסת הערך
 
 
 
            Node<int> chain22 = new Node<int>(1, new Node<int>(2, new Node<int>(1, new Node<int>(4, new Node<int>(5)))));
 
            List<int> minIndexes = FindMinValueIndexes(chain22); // הפעלת פונקציה שמוצאת את האינדקס/ים של הערך/ים הנמוך/ים ביותר בשרשרת
 
            Console.WriteLine("The indexes of the minimum value is: " + string.Join(", ", minIndexes)); // הדפסת הערך
 
 
 
            Node<int> chain23 = new Node<int>(5, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            List<int> maxIndexes = FindMaxValueIndexes(chain23); // הפעלת פונקציה שמוצאת את האינדקס/ים של הערך/ים הנמוך/ים ביותר בשרשרת
 
            Console.WriteLine("The indexes of the maximum value is: " + string.Join(", ", maxIndexes)); // הדפסת הערך
 
 
 
            Node<int> chain24 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            List<int> secondMaxIndexes = FindSecondMaxValueIndex(chain24); // הפעלת הפונקציה
 
            Console.WriteLine("The index of the second maximum value is: " + string.Join(", ", secondMaxIndexes)); // הדפסת הערכים
 
 
 
            Node<int> chain25 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            List<int> secondMinIndexes = FindSecondMinValueIndex(chain25); // הפעלת הפונקציה
 
            Console.WriteLine("The index of the second minimum value is: " + string.Join(", ", secondMinIndexes)); // הדפסת הערכים
 
 
 
            Node<int> chain26 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(2, new Node<int>(1)))));
 
            Node<int> chain27 = new Node<int>(1, new Node<int>(2, new Node<int>(3, new Node<int>(4, new Node<int>(5)))));
 
            
 
            bool Palindrome1 = IsPalindrome(chain26); // הפעלת פונקציה שבודקת אם הרשימה היא פלינדרום
 
            Console.WriteLine("Is The Chain a Palindrome? " + Palindrome1);
 
            bool Palindrome2 = IsPalindrome(chain27); // הפעלת פונקציה שבודקת אם הרשימה היא פלינדרום
 
            Console.WriteLine("Is The Chain a Palindrome? " + Palindrome2);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
        }
 
 
 
        // Node<int> current = chain; 
 
        // משתנה שמצביע על האיבר הנוכני ברשימה. בתחילת הלולאה הוא מצביע על ראש הרשימה.
 
 
 
 
 
        static void PrintChain(Node<int> chain) // פונקציה להדפסת כל האיברים ברשימה מקושרת 
 
        {
 
            Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית 
 
 
 
            while (current != null) // לולאה שעוברת על כל האיברים ברשימה עד לסופה
 
            {
 
                Console.Write(current.GetValue() + " ---> "); //הדפסת האיבר הנוכחי ברשימה
 
                current = current.GetNext(); // עבור לאיבר הבא ברשימה
 
            }
 
 
 
            Console.WriteLine("Null!"); // לאחר סיום הפונקציה והדפסת כל האיברים, אין עוד איברים ולכן איבר הבא נאל
 
        }
 
 
 
        static void PrintChainReverse(Node<int> chain) // פונקציה להדפסת כל האיברים בסדר הפוך ברשימה מקושרת
 
        {
 
            if (chain == null) // אם השרשרת ריקה
 
            {
 
                Console.WriteLine("The chain is null. Nothing to print."); // הודעה מתאימה
 
                return; // יציאה מהפונקציה
 
            }
 
 
 
            List<int> values = new List<int>(); // רשימה זמנית לאחסון הערכים
 
            Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית
 
 
 
            // איסוף כל הערכים בשרשרת
 
            while (current != null) // כל עוד השרשרת לא ריקה
 
            {
 
                values.Add(current.GetValue()); // מוסיף את הערך לרשימה של ווליוס
 
                current = current.GetNext(); // עבור לאיבר הבא
 
            }
 
 
 
            // הדפסת הערכים מהסוף להתחלה
 
            for (int i = values.Count - 1; i >= 0; i--)
 
            {
 
                Console.Write(values[i] + " ---> ");
 
            }
 
 
 
            Console.WriteLine("Null!"); // הגענו לאיבר האחרון
 
        }
 
 
 
        public static int SizeOfChain(Node<int> chain) // פונקציה שמחזירה את כמות האיברים ברשימה מקושרת 
 
        {
 
            if (chain == null) // אם השרשרת ריקה
 
            {
 
                return 0; // אין איברים
 
            }
 
 
 
            int size = 0; // אתחול הגודל
 
            Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית
 
 
 
            while (current != null) // לולאה שרצה על כל איברי השרשרת
 
            {
 
                size++; // עלה את סכום האיברים
 
                current = current.GetNext(); // עבור לאיבר הבא ברשימה
 
            }
 
 
 
            return size; // החזר את כמות האיברים
 
        }
 
 
 
        public static bool IsNodeExists(Node<int> chain, int value) // פונקציה שבודקת אם איבר קיים לפי ערך ווליו (שמתקבל בפרמטר) ברשימה מקושרת  
 
        {
 
            // משתנה עזר לשימירת הרשימה/השרשרת המקורית
 
            Node<int> current = chain;
 
 
 
            // לולאה שרצה על כל האיברים ברשימה
 
            while (current != null)
 
            {
 
                // אם הערך של האיבר הנוכחי שווה לערך שחיפשנו
 
                if (current.GetValue() == value)
 
                {
 
                    return true; // מצאנו את הערך
 
                }
 
 
 
                // עוברים לאיבר הבא
 
                current = current.GetNext();
 
            }
 
 
 
            // אם יצאנו מהלולאה בלי למצוא את הערך, האיבר לא קיים
 
            return false;
 
        }
 
 
 
        public static Node<int> RemoveFirst(Node<int> chain) // פונקציה שמסירה את האיבר הראשון ברשימה מקושרת 
 
        {
 
            if (chain == null) // אם השרשרת ריקה
 
            {
 
                return null; // מקרה קיצון, אין איברים להסרה
 
            }
 
 
 
            if (chain.GetNext() == null) // אם בשרשרת איבר יחיד
 
            {
 
                return null; // מקרה קיצון, אם בשרשרת יש רק איבר אחד ונסיר אותו לא תתקיים שרשרת
 
            }
 
 
 
            return chain.GetNext(); // הסרת האיבר הראשון והחזרת הרשימה החדשה
 
        }
 
 
 
        public static Node<int> RemoveLast(Node<int> chain) // פונקציה שמסירה את האיבר האחרון ברשימה מקושרת 
 
        {
 
            if (chain == null) // אם השרשרת ריקה
 
            {
 
                return null; // מקרה קיצון, אין איבר להסרה
 
            }
 
 
 
            if (chain.GetNext() == null) // אם בשרשרת איבר יחיד
 
            {
 
                return null; // מקרה קיצון, אם בשרשרת יש רק איבר אחד ונסיר אותו לא תתקיים שרשרת
 
            }
 
 
 
            Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית
 
 
 
            while (current.GetNext().GetNext() != null) // לולאה שרצה עד לאיבר האחרון
 
            {
 
                current = current.GetNext(); // עבור לאיבר הבא 
 
            }
 
 
 
            current.SetNext(null); // הסרת האיבר האחרון
 
            return chain; // החזרת הרשימה החדשה
 
        }
 
 
 
        public static Node<int> RemoveByValue(Node<int> chain, int value) // פונקציה שמסירה את האיבר האחרון ברשימה מקושרת 
 
        {
 
            if (chain == null) // אם השרשרת ריקה
 
            {
 
                return null; // מקרה קיצון, אין איבר להסרה
 
            }
 
 
 
            if (chain.GetNext() == null) // אם בשרשרת איבר יחיד
 
            {
 
                return null; // מקרה קיצון, אם בשרשרת יש רק איבר אחד ונסיר אותו לא תתקיים שרשרת
 
            }
 
 
 
            Node<int> NewNode = new Node<int>(0); // יצירת שרשרת חדשה לאחסון השרשרת המקורית
 
            NewNode.SetNext(chain); // קישור לראש הרשימה
 
            Node<int> prev = NewNode; // משתנה לאחסון האיבר הקודם
 
            Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית
 
            bool flag = false; // משתנה בוליאני שאומר האם מצאנו את האיבר להסרה
 
 
 
            while (current != null) // לולאה שעוברת על כל הרשימה
 
            {
 
                if (current.GetValue() == value) // אם מצאנו את האיבר להסרה
 
                {
 
                    prev.SetNext(current.GetNext()); // קישור האיבר הקודם לאיבר הבא של האיבר הנוכחי
 
                    flag = true; // עדכון המשתנה שמעיד שמצאנו את האיבר
 
                }
 
 
 
                else // אם לא מצאנו את האיבר הנוכחי
 
                {
 
                    prev = current; // עדכון האיבר הקודם לאיבר הנוכחי
 
                }
 
 
 
                current = current.GetNext(); // עבור לאיבר הבא
 
            }
 
 
 
            if (!flag) // אם לא מצאנו את האיבר להסרה
 
            {
 
                Console.WriteLine($"Value {value} does not exist!"); // הערך לא קיים בשרשרת
 
                return null; // מקרה קיצון, צא מהפונקציה
 
            }
 
 
 
            return NewNode.GetNext(); // החזר את השרשרת החדשה
 
        }
 
 
 
        public static Node<int> RemoveByIndex(Node<int> chain, int index) // פונקציה שמסירה את איבר לפי אינדקס שמתקבל בפרמטר ברשימה מקושרת 
 
        {
 
            if (chain == null || index < 0) // אם הרשימה ריקה או שהאינדקס שלילי
 
            {
 
                return null; // מקרה קיצון, אין איבר להעיף
 
            }
 
 
 
            if (chain.GetNext() == null) // אם בשרשרת איבר יחיד
 
            {
 
                return null; // מקרה קיצון, אם בשרשרת יש רק איבר אחד ונסיר אותו לא תתקיים שרשרת
 
            }
 
 
 
            Node<int> prev = null; // מצביע על הצומת הקודם
 
            Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית
 
            int currentIndex = 0; // מכיל את האינדקס הנוכחי שאנחנו נמצאים בו ברשימה
 
 
 
            while (current != null) // לולאה שרצה על כל האיברים
 
            {
 
                if (currentIndex == index) // אם מצאנו את האינדקס
 
                {
 
                    if (prev == null)  // אם האיבר להסרה הוא האיבר הראשון
 
                    {
 
                        chain = current.GetNext(); // עדכון הראש של הרשימה לאיבר הבא
 
                    }
 
 
 
                    else // אם האיבר להסרה הוא לא האיבר הראשון
 
                    {
 
                        prev.SetNext(current.GetNext()); // קישור האיבר הקודם לאיבר הבא של האיבר הנוכחי
 
                    }
 
 
 
                }
 
 
 
                prev = current; // האיבר הקודם עובר להיות האיבר הנוכחי
 
                current = current.GetNext(); // עבור לאיבר הבא
 
                currentIndex++; // עברנו האינדקס הנוכחי
 
            }
 
 
 
            if (currentIndex <= index) // אם הגענו לסוף הרשימה מבלי למצוא את האינדקס
 
            {
 
                Console.WriteLine($"Index {index} does not exist!"); // האינדקס לא קיים
 
                return null; // מקרה קיצון, צא מהפונקציה
 
            }
 
 
 
            return chain; // החזרת הרשימה החדשה
 
        }
 
 
 
        public static bool IsSortedAscending(Node<int> chain) // פונקציה שבודקת אם רשימה מקושרת ממוינת בסדר עולה
 
        {
 
            if (chain == null || chain.GetNext() == null) // בדוק אם השרשרת ריקה או שקיים רק איבר אחד
 
            {
 
                return false; // אין סדר עולה
 
            }
 
 
 
            Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית
 
            while (current.GetNext() != null) // לולאה שעוברת על כל האיברים
 
            {
 
                if (current.GetValue() >= current.GetNext().GetValue()) // אם הערך הנוכחי גדול מהערך הבא
 
                {
 
                    return false; // הרשימה לא מסודרת
 
                }
 
 
 
                current = current.GetNext(); // עוברים לאיבר הבא
 
            }
 
 
 
            return true; // אם עברנו את כל הבדיקות, הרשימה מסודרת בסדר עולה
 
        }
 
 
 
        public static bool IsSortedDescending(Node<int> chain) // פונקציה שבודקת אם רשימה מקושרת ממוינת בסדר יורד
 
        {
 
            if (chain == null || chain.GetNext() == null) // בדוק אם השרשרת ריקה או שקיים רק איבר אחד
 
            {
 
                return false; // אין סדר עולה
 
            }
 
 
 
            Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית
 
            while (current.GetNext() != null) // לולאה שעוברת על כל האיברים ברשימה עד הסוף
 
            {
 
                if (current.GetValue() <= current.GetNext().GetValue()) // אם הערך הנוכחי קטן או שווה לערך הבא
 
                {
 
                    return false; // הרשימה לא בסדר יורד
 
                }
 
 
 
                current = current.GetNext(); // עבור לאיבר הבא ברשימה
 
            }
 
 
 
            return true; // אם עברנו את כל הבדיקות, הרשימה מסודרת בסדר יורד
 
        }
 
 
 
        public static double Average(Node<int> chain) // פונקציה שמדפיסה את ממוצע ערך האיברים ברשימה מקושרת  
 
        {
 
            if (chain == null) // אם השרשרת ריקה
 
            {
 
                return 0; // ממוצע אפס
 
            }
 
 
 
            int sum = 0; // משתנה לשמירת סכום כל הערכים ברשימה
 
            int count = 0; // משתנה לספירת מספר האיברים ברשימה
 
            Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית 
 
 
 
            while (current != null) // לולאה שעוברת על כל האיברים ברשימה עד שהיא מגיעה לסוף
 
            {
 
                sum += current.GetValue(); // מוסיף את הערך של האיבר הנוכחי לסכום
 
                count++; // מגדיל את ספירת האיברים
 
                current = current.GetNext(); // מעביר את המצביע לאיבר הבא ברשימה
 
            }
 
 
 
            return (double)sum / count; // החזר את הממוצע
 
        }
 
 
 
        public static Node<int> AddNodeStart(Node<int> chain, int data) // פונקציה שמוסיפה איבר בתחילת רשימה מקושרת   
 
        {
 
            // יצירת איבר חדש
 
            Node<int> newNode = new Node<int>(data);
 
 
 
            // הגדר את האיבר הבא לשרשרת המקורית 
 
            newNode.SetNext(chain);
 
 
 
            // החזר את הרשימה החדשה לאחר הוספת האיבר 
 
            return newNode;
 
        }
 
 
 
        public static void AddNodeEnd(Node<int> chain, int value) // פונקציה שמוסיפה איבר בסוף רשימה מקושרת  
 
        {
 
            // יצירת איבר חדש עם הערך שקיבלנו מהפרמטר
 
            Node<int> newNode = new Node<int>(value);
 
 
 
            // בדוק אם הרשימה ריקה. אם כן, אין איבר להוספה
 
            if (chain == null) return;
 
 
 
            else
 
            {
 
                Node<int> current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית 
 
 
 
                while (current.GetNext() != null) // לולאה שעוברת על כל האיברים ברשימה
 
                {
 
                    current = current.GetNext(); // עבור לאיבר הבא ברשימה
 
                }
 
 
 
                current.SetNext(newNode); // חיבור האיבר החדש לסוף הרשימה
 
            }
 
        }
 
 
 
        public static Node<int> AddNodeAtIndex(Node<int> chain, int index, int value) // פונקציה שמוסיפה איבר לפי אינדקס (שמתקבל בפרמטר) ברשימה מקושרת  
 
        {
 
            // יצירת איבר חדש עם הערך שקיבלנו מהפרמטר
 
            Node<int> newNode = new Node<int>(value);
 
 
 
            // בדוק אם הרשימה ריקה או אם האינדקס אינו תקין אם כן צא מהפונקציה
 
            if (chain == null || index < 0)
 
            {
 
                Console.WriteLine("Chain Is Empty Or Index Is");
 
                return null;
 
            }
 
 
 
            // אם האינדקס הוא 0, הוסף את האיבר החדש בתחילת הרשימה
 
            if (index == 0)
 
            {
 
                // הגדר את האיבר הבא לשרשרת המקורית 
 
                newNode.SetNext(chain);
 
 
 
                // החזר את הרשימה החדשה לאחר הוספת האיבר 
 
                return newNode;
 
            }
 
 
 
            // מציאת האיבר לפני המקום שבו רוצים להוסיף
 
            Node<int> current = chain;  // משתנה עזר לשימירת הרשימה/השרשרת המקורית 
 
            int currentIndex = 0; // משתנה לאחסון האינדקס הנוכחי
 
 
 
            while (current != null && currentIndex < index - 1) // לולאה לחיפוש האיבר המבוקש לפי האינדקס בפרמטר
 
            {
 
                current = current.GetNext(); // עבור לאיבר הבא
 
                currentIndex++; // עדכון האינדקס הנוכחי
 
            }
 
 
 
            // אם הגענו לסוף הרשימה, האינדקס לא קיים
 
            if (current == null)
 
            {
 
                Console.WriteLine("Nonexistent Index!"); // הדפסת הודעה מתאימה
 
                return null; // מקרה קיצון, יציאה מהפונקציה
 
            }
 
 
 
            // חיבור האיבר החדש לרשימה
 
            newNode.SetNext(current.GetNext()); // קישור האיבר החדש לאיבר הבא
 
            current.SetNext(newNode); // קישור האיבר הקודם לאיבר החדש
 
            return chain; // החזרת הראשימה החדשה
 
        }
 
 
 
        public static void FindAndPrintMiddle(Node<int> chain) // פונקציה שמוצאת את האיברים האמצעיים ברשימה מקושרת ומדפיסה אותם
 
        {
 
            if (chain == null) // אם השרשרת ריקה
 
            {
 
                Console.WriteLine("The List Is Empty."); // הודעה מתאימה
 
                return; // יציאה מהפונקציה
 
            }
 
 
 
            Node<int> slow = chain; // משתנה עזר ראשון שמצביע לאיבר הראשון ברשימה
 
            Node<int> fast = chain; // משתנה עזר שני שמצביע לאיבר הראשון ברשימה
 
            Node<int> prevSlow = null; // משתנה לאחסון האיבר הקודם של סלואו
 
 
 
            while (fast != null && fast.GetNext() != null) // לולאה שרצה על כל האיברים
 
            {
 
                prevSlow = slow; // עדכון האיבר הקודם להיות האיבר הנוכחי
 
                slow = slow.GetNext(); // האיבר הנוכחי הראשון עובר לאיבר הבא
 
                fast = fast.GetNext().GetNext(); // האיבר הנוכחי השני עובר שני איברים קדימה
 
            }
 
 
 
            if (fast == null) // מספר זוגי של איברים
 
            {
 
                Console.WriteLine($"The Middle Nodes: {prevSlow.GetValue()} and {slow.GetValue()}");
 
            }
 
 
 
            else // מספר אי זוגי של איברים
 
            {
 
                Console.WriteLine($"The Middle Node: {slow.GetValue()}");
 
            }
 
        }
 
 
 
        public static int GetValueByIndex(Node<int> chain, int index) // פונקציה  שעוברת על כל האיברים בשרשרת ומחזירה את הערך של האיבר כאשר היא מגיעה לאינדקס המבוקש
 
        {
 
            int currentIndex = 0; // מייצג את האינדקס הנוכחי בשרשרת
 
            Node<int> currentNode = chain; // משתנה עזר לשמירת האיבר הנוכחי
 
 
 
            // לולאה שרצה על האיברים כל עוד לא הגענו לסוף השרשרת
 
            while (currentNode != null)
 
            {
 
                // בודק אם הגענו לאינדקס המבוקש
 
                if (currentIndex == index)
 
                {
 
                    return currentNode.GetValue(); // מחזיר את הערך אם הגענו לאינדקס המבוקש
 
                }
 
 
 
                // מתקדם לאיבר הבא ומגדיל את האינדקס הנוכחי באחד
 
                currentNode = currentNode.GetNext();
 
                currentIndex++;
 
            }
 
 
 
            return -1; // מחזיר -1 אם לא נמצא האיבר באינדקס המבוקש
 
        }
 
 
 
        public static int GetIndexByValue(Node<int> chain, int value) // פונקציה לקבלת אינדקס בעזרת ערך מסוים ברשימה מקושרת
 
        {
 
            int currentIndex = 0; // משתנה לאחסון האינדקס הנוכחי
 
            Node<int> currentNode = chain; // מצביע לאיבר הנוכחי ברשימה
 
 
 
            while (currentNode != null) // לולאה שעוברת על כל האיברים ברשימה
 
            {
 
                if (currentNode.GetValue() == value) // בדיקה אם הערך של הנוד הנוכחי תואם לערך המבוקש
 
                {
 
                    return currentIndex; // מחזיר את האינדקס אם הערך נמצא
 
                }
 
 
 
                currentNode = currentNode.GetNext(); // מעבר לאיבר הבא הרשימה 
 
                currentIndex++; // הגדלת האינקס
 
            }
 
 
 
            return -1; // החזר -1 אם הערך לא נמצא
 
        }
 
 
 
        public static bool IsBalanced(Node<int> chain) // פונקציה שבודקת אם רשימה מקושרת היא גם "רשימה מאוזנת". רשימה מאוזנת היא רשימה שמספר האיברים הגדולים מהממוצע שווה למספר האיברים הקטנים מהממוצע.
 
        {
 
            // אם הרשימה ריקה, היא נחשבת מאוזנת
 
            if (chain == null) return true;
 
 
 
            int sum = 0; // משתנה לשמירת סכום הערכים
 
            int count = 0; // משתנה לספירת האיברים
 
 
 
            Node<int> current = chain;  // משתנה עזר לשימירת הרשימה/השרשרת המקורית 
 
 
 
            while (current != null) // לולאה שרצה על כל האיברים
 
            {
 
                sum += current.GetValue(); // הוספת הערך לסכום
 
                count++; // העלאת מונה האיברים
 
                current = current.GetNext(); // מעבר לאיבר הבא
 
            }
 
 
 
            // חישוב הממוצע
 
            double average = (double)sum / count;
 
 
 
            int greaterCount = 0; // משתנה לספירת איברים הגדולים מהממוצע
 
            int lesserCount = 0; // משתנה לספירת איברים הקטנים מהממוצע
 
 
 
            current = chain; // משתנה עזר לשימירת הרשימה/השרשרת המקורית 
 
 
 
            // ספירת האיברים הגדולים והקטנים מהממוצע
 
 
 
            while (current != null) // לולאה שעוברת על כל האיברים
 
            {
 
                if (current.GetValue() > average) // אם הערך גדול מהממוצע
 
                {
 
                    greaterCount++; // ספירת איבר גדול מהממוצע
 
                }
 
 
 
                else if (current.GetValue() < average) // אם הערך קטן מהממוצע
 
                {
 
                    lesserCount++; // ספירת איבר קטן מהממוצע
 
                }
 
                current = current.GetNext(); // מעבר לאיבר הבא ברשימה
 
            }
 
 
 
            return greaterCount == lesserCount; // החזרת התשובה האם הרשימה היא מאוזנת
 
        }
 
 
 
        public static int sequences(Node<int> chain, int num) // פונקציה שבודקת את מספר הרצפים שיש ברשימה מקושרת עבור מספר מסוים
 
        {
 
            int sequences = 0; // סוכם הרצפים
 
            Node<int> pos = chain; // משתנה עזר למיקום נוכחי ברשימה
 
            bool inSequence = false; // בדיקה אם הרצף ממשיך
 
            int count = 0; // מונה למופעים רצופים
 
 
 
            // לולאה שרצה כל עוד לא הגענו לסוף הרשימה
 
            while (pos != null)
 
            {
 
                // בודק אם הערך של הצומת הנוכחי שווה למספר שאנחנו מחפשים
 
                if (pos.GetValue() == num)
 
                {
 
                    count++; // מוסיף למונה
 
                    inSequence = true; // הרצף קיים
 
                }
 
 
 
                else
 
                {
 
                    if (inSequence && count >= 2) // אם סיימנו רצף עם 2 מופעים או יותר
 
                    {
 
                        sequences++; // מוסיפים לספירה
 
                    }
 
 
 
                    inSequence = false; // הרצף הפסיק
 
                    count = 0; // מאפס את המונה
 
                }
 
 
 
                // עובר לאיבר הבא ברשימה
 
                pos = pos.GetNext();
 
            }
 
 
 
            // בודק במקרה שהרצף נגמר בסוף הרשימה
 
            if (inSequence && count >= 2)
 
            {
 
                sequences++;
 
            }
 
 
 
            // מחזיר את מספר הרצפים של המספר המבוקש
 
            return sequences;
 
        }
 
 
 
        public static int FindMinValueIndex(Node<int> chain) // פונצקיה שמקבלת שרשרת ומחזירה את האינדקס של האינדקס של הערך הנמוך ביותר בשרשרת מקושרת
 
        {
 
            if (chain == null) // אם השרשרת ריקה
 
            {
 
                Console.WriteLine("The List Is Empty."); // הודעה מתאימה
 
                return -1; // יציאה מהפונקציה
 
            }
 
 
 
            Node<int> pos = chain; // משתנה עזר לשמירת השרשרת המקורית
 
            int minValue = pos.GetValue(); // אתחול הערך המינימלי לערך החוליה הראשונה
 
            int minIndex = 0; // אינדקס המינימום מתחיל מאפס
 
            int currentIndex = 0; // מונה אינדקס נוכחי
 
 
 
            // לולאה שעוברת על כל החוליות ברשימה
 
            while (pos != null)
 
            {
 
                if (pos.GetValue() < minValue) // עם הערך הנוכחי קטן מהערך המינימלי הקודם
 
                {
 
                    minValue = pos.GetValue(); // עדכון הערך המינימלי
 
                    minIndex = currentIndex; // עדכון האינדקס למיקום הנמוך ביותר
 
                }
 
 
 
                pos = pos.GetNext(); // מעבר לחוליה הבאה
 
                currentIndex++; // עדכון האינדקס הנוכחי
 
            }
 
 
 
            return minIndex; // החזרת האינדקס של הערך הנמוך ביותר
 
        }
 
 
 
        public static int FindMaxValueIndex(Node<int> chain) // פונקציה שמקבלת שרשרת ומחזירה את האינדקס של הערך הגבוה ביותר בשרשרת המקושרת
 
        {
 
            if (chain == null) // אם השרשרת ריקה
 
            {
 
                Console.WriteLine("The List Is Empty."); // הודעה מתאימה
 
                return -1; // החזרת -1 במקרה של שרשרת ריקה
 
            }
 
 
 
            Node<int> pos = chain; // משתנה עזר לשמירת השרשרת המקורית
 
            int maxValue = pos.GetValue(); // אתחול הערך המקסימלי לערך של החוליה הראשונה
 
            int maxIndex = 0; // אינדקס המקסימום מתחיל מאפס
 
            int currentIndex = 0; // מונה אינדקס נוכחי
 
 
 
            // לולאה שעוברת על כל החוליות ברשימה
 
            while (pos != null)
 
            {
 
                if (pos.GetValue() > maxValue) // אם הערך הנוכחי גדול מהערך המקסימלי הקודם
 
                {
 
                    maxValue = pos.GetValue(); // עדכון הערך המקסימלי
 
                    maxIndex = currentIndex; // עדכון האינדקס למיקום הגבוה ביותר
 
                }
 
 
 
                pos = pos.GetNext(); // מעבר לחוליה הבאה
 
                currentIndex++; // עדכון האינדקס הנוכחי
 
            }
 
 
 
            return maxIndex; // החזרת האינדקס של הערך הגבוה ביותר
 
        }
 
 
 
        public static List<int> FindMinValueIndexes(Node<int> chain) // פונקציה שמקבלת שרשרת ומחזירה את האינדקס/ים עם הערך/ים הכי נמוך/ים
 
        {
 
            if (chain == null) // אם הרשימה ריקה
 
            {
 
                Console.WriteLine("The List Is Empty."); // הודעה מתאימה
 
                return null; // מקרה קיצון, יציאה מהפונקציה
 
            }
 
 
 
            Node<int> pos = chain; // משתנה עזר שמחזיק את השרשרת המקורית
 
            int minValue = pos.GetValue(); // אתחול ערך מינימלי עם הערך של האיבר הראשון
 
            List<int> minIndexes = new List<int>(); // רשימה להחזיק את האינדקסים של הערך/ים המינימלי/ם
 
            int currentIndex = 0; // מונה אינדקסים נוכחי
 
 
 
            // לולאה שעוברת על כל הצמתים ברשימה
 
            while (pos != null)
 
            {
 
                if (pos.GetValue() < minValue) // אם הערך הנוכחי קטן מהערך המינימלי הקודם
 
                {
 
                    minValue = pos.GetValue(); // עדכון הערך המינימלי
 
                    minIndexes.Clear(); // ניקוי אינדקסים קודמים
 
                    minIndexes.Add(currentIndex); // הוספת האינדקס המינימלי החדש
 
                }
 
 
 
                else if (pos.GetValue() == minValue) // אם הערך הנוכחי שווה לערך המינימלי הנוכחי
 
                {
 
                    minIndexes.Add(currentIndex); // הוספת אינדקס זה לרשימת האינדקסים המינימליים
 
                }
 
 
 
                pos = pos.GetNext(); // // מעבר לאיבר הבא
 
                currentIndex++; // עדכון האינדקס הנוכחי
 
            }
 
 
 
            return minIndexes; // החזרת האינדקסים של הערכים המינימלים
 
        }
 
 
 
        public static List<int> FindMaxValueIndexes(Node<int> chain) // פונקציה שמקבלת שרשרת ומחזירה את האינדקסים עם הערך/ים הכי גבוה/ים בשרשרת מקושרת
 
        {
 
            if (chain == null) // אם הרשימה ריקה
 
            {
 
                Console.WriteLine("The List Is Empty."); // הודעה מתאימה
 
                return null; // מקרה קיצון, יציאה מהפונקציה
 
            }
 
 
 
            Node<int> pos = chain; // משתנה עזר לשמירת השרשרת המקורית
 
            int maxValue = pos.GetValue(); // אתחול ערך מקסימלי עם הערך של האיבר הראשון
 
            List<int> maxIndexes = new List<int>(); // רשימה להחזיק את האינדקסים של הערך/ים המקסימלי/ם
 
            int currentIndex = 0; // מונה אינדקסים נוכחי
 
 
 
            // לולאה שעוברת על כל הצמתים ברשימה
 
            while (pos != null)
 
            {
 
                if (pos.GetValue() > maxValue) // אם הערך הנוכחי גדול מהערך המקסימלי הקודם
 
                {
 
                    maxValue = pos.GetValue(); // עדכון הערך המקסימלי
 
                    maxIndexes.Clear(); // ניקוי אינדקסים קודמים
 
                    maxIndexes.Add(currentIndex); // הוספת האינדקס המקסימלי החדש
 
                }
 
                else if (pos.GetValue() == maxValue) // אם הערך הנוכחי שווה לערך המקסימלי הנוכחי
 
                {
 
                    maxIndexes.Add(currentIndex); // הוספת אינדקס זה לרשימת האינדקסים המקסימליים
 
                }
 
 
 
                pos = pos.GetNext(); // מעבר לאיבר הבא
 
                currentIndex++; // עדכון האינדקס הנוכחי
 
            }
 
 
 
            return maxIndexes; // החזרת האינדקסים של הערכים המקסימליים
 
        }
 
 
 
        public static List<int> FindSecondMaxValueIndex(Node<int> chain) // פונקציה שמקבלת שרשרת 
 
        {
 
            if (chain == null) return new List<int>(); // אם הרשימה ריקה, מחזירים רשימה ריקה
 
 
 
            int max = int.MinValue;
 
            int secondMax = int.MinValue;
 
            List<int> secondMaxIndexes = new List<int>();
 
            int index = 0;
 
 
 
            // סיבוב על כל האלמנטים בשרשרת
 
            for (Node<int> current = chain; current != null; current = current.GetNext())
 
            {
 
                // מעדכנים את הערכים המקסימליים
 
                if (current.GetValue() > max)
 
                {
 
                    secondMax = max; // הערך הקודם הופך לערך השני הכי גבוה
 
                    max = current.GetValue(); // מעדכנים את הערך המקסימלי
 
                }
 
 
 
                else if (current.GetValue() > secondMax && current.GetValue() < max)
 
                {
 
                    secondMax = current.GetValue(); // מעדכנים את הערך השני הכי גבוה
 
                }
 
 
 
                index++;
 
            }
 
 
 
            // מחפשים את כל האינדקסים של הערך השני הכי גבוה
 
            index = 0; // מאפסים את האינדקס
 
 
 
            for (Node<int> current = chain; current != null; current = current.GetNext())
 
            {
 
                if (current.GetValue() == secondMax)
 
                {
 
                    secondMaxIndexes.Add(index); // מוסיפים את האינדקס לרשימה
 
                }
 
 
 
                index++;
 
            }
 
 
 
            return secondMaxIndexes; // מחזירים את הרשימה של אינדקסים
 
        }
 
 
 
        public static List<int> FindSecondMinValueIndex(Node<int> chain) // פונקציה שמקבלת שרשרת
 
        {
 
            if (chain == null) return new List<int>(); // אם הרשימה ריקה, מחזירים רשימה ריקה
 
 
 
            int min = int.MaxValue;
 
            int secondMin = int.MaxValue;
 
            List<int> secondMinIndexes = new List<int>();
 
            int index = 0;
 
 
 
            // סיבוב על כל האלמנטים בשרשרת
 
            for (Node<int> current = chain; current != null; current = current.GetNext())
 
            {
 
                // מעדכנים את הערכים המינימליים
 
                if (current.GetValue() < min)
 
                {
 
                    secondMin = min; // הערך הקודם הופך לערך השני הכי נמוך
 
                    min = current.GetValue(); // מעדכנים את הערך המינימלי
 
                }
 
                else if (current.GetValue() < secondMin && current.GetValue() > min)
 
                {
 
                    secondMin = current.GetValue(); // מעדכנים את הערך השני הכי נמוך
 
                }
 
 
 
                index++;
 
            }
 
 
 
            // מחפשים את כל האינדקסים של הערך השני הכי נמוך
 
            index = 0; // מאפסים את האינדקס
 
 
 
            for (Node<int> current = chain; current != null; current = current.GetNext())
 
            {
 
                if (current.GetValue() == secondMin)
 
                {
 
                    secondMinIndexes.Add(index); // מוסיפים את האינדקס לרשימה
 
                }
 
 
 
                index++;
 
            }
 
 
 
            return secondMinIndexes; // מחזירים את הרשימה של אינדקסים
 
        }
 
 
 
        public static bool IsPalindrome(Node<int> chain) // פונקציה שבודקת אם רשימה מקושרת היא פלינדרום
 
        {
 
            // אם הרשימה ריקה או כוללת איבר אחד, היא נחשבת פלינדרום
 
            if (chain == null || chain.GetNext() == null) return true;
 
 
 
            // שלב 1: העתקת הערכים לרשימה כדי שניתן יהיה לקרוא אחורה
 
            List<int> values = new List<int>();
 
            Node<int> current = chain; // משתנה עזר לשמירת השרשרת המקורית
 
 
 
            while (current != null) // לולאה שעוברת על כל האיברים ומוסיפה אותם לרשימה
 
            {
 
                values.Add(current.GetValue());
 
                current = current.GetNext();
 
            }
 
 
 
            // שלב 2: בדיקת סימטריה
 
            int left = 0; // התחלה של הרשימה
 
            int right = values.Count - 1; // סוף של הרשימה
 
 
 
            while (left < right) // לולאה שממשיכה כל עוד יש איברים משני הצדדים
 
            {
 
                if (values[left] != values[right]) // אם הערכים אינם שווים
 
                {
 
                    return false; // השרשרת אינה פלינדרום
 
                }
 
                left++;
 
                right--;
 
            }
 
 
 
            return true; // אם כל הערכים היו שווים, הרשימה היא פלינדרום
 
        }
 
 
 
    }
 
}
const Button = styled.button`
  background: red;
  border-radius: 3px;
  border: 2px solid #BF4F74;
  color: #BF4F74;
  margin: 0 1em;
  padding: 0.25em 1em;
`
class livre{
    private String titre;
    private String auteur;
    private int nbp;
    private float prix;
  
    livre(String titre,String auteur,int nbp,float prix){
        this.titre=titre;
        this.auteur=auteur;
        this.nbp=nbp;
        this.prix=prix;
    }
    String getTitre(){
        return this.titre;
    }
    String getAuteur(){
        return this.auteur;
    }
    int getNbp(){
        return this.nbp;
    }
    float getPrix(){
        return this.prix;
    }
    void setTitre(String titre){
        this.titre=titre;
    }
    void setAuteur(String auteur){
        this.auteur=auteur;
    }
    void setNbp(int nbp){
        this.nbp=nbp;
    }
    void setPrix(float prix){
        this.prix=prix;
    }
    public String toString() {
        return "Livre{" +
                "titre='" + titre + '\'' +
                ", auteur='" + auteur + '\'' +
                ", nombrePages=" + nbp +
                ", prix=" + prix +
                '}';
    }
    public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }

    if (obj == null || getClass() != obj.getClass()) {
        return false;
    }

    livre autre = (livre) obj;

    return this.titre.equals(autre.getTitre())
        && this.auteur.equals(autre.getAuteur());
      
      
}}
class etagere{
    private livre [] tab;
    private int nblivre;
    etagere(int n){
        this.tab=new livre[n];
        this.nblivre=0;
    }
    int getNbmax(){
        return tab.length;
    }
    int getNblivre(){
        return this.nblivre;
    }
    
   boolean ajouter(livre l){
       if(nblivre<tab.length){
           tab[nblivre]=l;
           nblivre++;
           return true;
       }
       return false;
   }
   livre getLivre(int p){
       if(p>0 && p<=nblivre){
           return tab[p-1];
       }
        return null;
       }
    int cher(String ti,String au){
        int nb=0;
        for(int i=0;i<nblivre;i++){
            if(tab[i].getTitre().equals(ti) && tab[i].getAuteur().equals(au)){
                return i+1;
            }
        }
        return 0;
    }
 int [] cherch(String ti,String au){
     int x=0,x1=0;
      for(int i=0;i<nblivre;i++){
            if(tab[i].getTitre().equals(ti) && tab[i].getAuteur().equals(au)){
                x++;
            }}
            int []t=new int[x];
             for(int i=0;i<nblivre;i++){
            if(tab[i].getTitre().equals(ti) && tab[i].getAuteur().equals(au)){
                t[x1]=i+1;
                x1++;}}
        return t;
 }
        
 
 

void affiche() {
        System.out.println("Livres sur l'etagere :");
        for (int i = 0; i < nblivre; i++) {
            System.out.println((i + 1) + ". " + tab[i]);
        }
    }

}
public class Main{
    public static void main(String [] args){
        livre l1=new livre("koukou","ahmed",250,3500);
        livre l2=new livre("boubou","iyed",630,7800);
        livre l3=new livre("kouk","wael",852,6988);
        livre l4=new livre("boubou","iyed",630,7800);
        System.out.println(l1.toString());
        System.out.println(l2.toString());
        etagere e1=new etagere(5);
        e1.ajouter(l1);
        e1.ajouter(l2);
        e1.ajouter(l3);
        e1.ajouter(l4);
        e1.affiche(); 
        int[] position = e1.cherch("boubou", "iyed");
        if (position.length > 0) {
            System.out.println("Positions des livres trouves");
           for (int i = 0; i < position.length; i++) {
        System.out.println(position[i]);
    }
} else {
    System.out.println("Aucun livre trouvé avec ce titre et cet auteur.");
        
        } }}
        
        
        
        
        
        
        
        
        
        
        
        
        
        
package oddevenprime;

import java.util.Scanner;
public class OddEvenPrime {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
       Scanner input = new Scanner(System.in);
        System.out.print("Enter starting number: ");
        int start = input.nextInt();
        System.out.print("Enter ending number: ");
        int end = input.nextInt();

        for (int num = start; num <= end; num++) {
            if (num % 2 == 0) {
                System.out.println(num + " is even");
            } else {
                System.out.println(num + " is odd");
            }

            boolean isPrime = true;
            for (int i = 2; i <= Math.sqrt(num); i++) {
                if (num % i == 0) {
                    isPrime = false;
                    break;
                }
            }

            if (isPrime && num > 1) {
                System.out.println(num + " is prime");
            }
        }
    }
}
package fibonacciseries;
import java.util.Scanner;
public class FibonacciSeries {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
              Scanner input = new Scanner(System.in);
        System.out.print("Enter the size of the series: ");
        int size = input.nextInt();

        int first = 0, second = 1, next;

        System.out.print(first + " " + second + " ");

        for (int i = 3; i <= size; i++) {
            next = first + second;
            System.out.print(next + " ");
            first = second;
            second = next;
        }
    }
}
package passedfailedgrades;
import java.util.Scanner;
public class PassedFailedGrades {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int passedCount = 0, failedCount = 0;

        for (int i = 1; i <= 10; i++) {
            System.out.print("Enter grade " + i + ": ");
            int grade = input.nextInt();

            if (grade >= 75) {
                passedCount++;
            } else {
                failedCount++;
            }
        }

        System.out.println("Passed: " + passedCount);
        System.out.println("Failed: " + failedCount);
    }
}
package positivenegativecount;
import java.util.Scanner;
public class PositiveNegativeCount {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
                Scanner input = new Scanner(System.in);
        int positiveCount = 0, negativeCount = 0;

        for (int i = 1; i <= 5; i++) {
            System.out.print("Enter number " + i + ": ");
            int num = input.nextInt();

            if (num > 0) {
                positiveCount++;
            } else if (num < 0) {
                negativeCount++;
            }
        }

        System.out.println("Positive: " + positiveCount);
        System.out.println("Negative: " + negativeCount);
    }
}
        Scanner input = new Scanner(System.in);
        int positiveCount = 0, negativeCount = 0;

        for (int i = 1; i <= 5; i++) {
            System.out.print("Enter number " + i + ": ");
            int num = input.nextInt();

            if (num > 0) {
                positiveCount++;
            } else if (num < 0) {
                negativeCount++;
            }
        }

        System.out.println("Positive: " + positiveCount);
        System.out.println("Negative: " + negativeCount);
    }
}
package sumofsquares;

import java.util.Scanner;
public class SumOfSquares {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.print("Enter a number: ");
        int n = input.nextInt();

        int sum = 0;
        for (int i = 1; i <= n; i++) {
            sum += i * i;
        }

        System.out.println("Sum of squares: " + sum);
    }
}
package rangecounter;

import java.util.Scanner;
public class RangeCounter {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
               Scanner input = new Scanner(System.in);
        int count1 = 0, count2 = 0, count3 = 0, count4 = 0;

        for (int i = 1; i <= 20; i++) {
            System.out.print("Enter number " + i + ": ");
            int num = input.nextInt();

            if (num >= 1 && num <= 50) {
                count1++;
            } else if (num >= 51 && num <= 100) {
                count2++;
            } else if (num >= 101 && num <= 150) {
                count3++;
            } else if (num >= 151 && num <= 200) {
                count4++;
            }
        }

        System.out.println("Number of values in range 1-50: " + count1);
        System.out.println("Number of values in range 51-100: " + count2);
        System.out.println("Number of values in range 101-150: " + count3);
        System.out.println("Number of values in range 151-200: " + count4);
    }
}

package sumsandaverage;
import java.util.Scanner;

public class SumsAndAverage {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
             Scanner input = new Scanner(System.in);
        System.out.print("Enter a number: ");
        int n = input.nextInt();

        int sum = 0;
        for (int i = 1; i <= n; i++) {
            System.out.print(i + " ");
            sum += i;
        }

        double average = (double) sum / n;

        System.out.println("\nSum: " + sum);
        System.out.println("Average: " + average);
    }
}
package displaynumbers;

import java.util.Scanner;
public class DisplayNumbers {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
         Scanner input = new Scanner(System.in);
        System.out.print("Enter a number: ");
        int n = input.nextInt();

        // Using a for loop
        for (int i = 1; i <= n; i++) {
            System.out.print(i + " ");
        }

        // Using a while loop
        int i = 1;
        while (i <= n) {
            System.out.print(i + " ");
            i++;
        }

        // Using a do-while loop
        i = 1;
        do {
            System.out.print(i + " ");
            i++;
        } while (i <= n);

        System.out.println();
    }
}
package circlearea;

/**
 *
 * @author Almer
 */
public class CircleArea {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        double pi = Math.PI;
        for (int r = 1; r <= 5; r++) {
            double area = pi * r * r;
            System.out.println("Radius: " + r + ", Area: " + area);
        }
    }
}
package countstoten;

/**
 *
 * @author Almer
 */
public class CountsToTen {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
               for (int i = 1; i <= 10; i++) {
            System.out.println(i);
        }
    }
}
package employeessalary;
import java.util.Scanner;
public class EmployeesSalary {

    
    public static void main(String[] args) {
             Scanner input = new Scanner(System.in);

        System.out.print("Enter the employee category (c/p/r): ");
        char category = input.next().charAt(0);

        System.out.print("Enter number of days worked: ");
        int daysWorked = input.nextInt();

        double dailyRate;
        String categoryName;

        switch (category) {
            case 'c':
                dailyRate = 350;
                categoryName = "Contractual";
                break;
            case 'p':
                dailyRate = 400;
                categoryName = "Probationary";
                break;
            case 'r':
                dailyRate = 450;
                categoryName = "Regular";
                break;
            default:
                dailyRate = 0;
                categoryName = "Invalid Input";
        }

        double basicPay = dailyRate * daysWorked;

        System.out.println("Category: " + categoryName);
        System.out.println("Daily Rate: " + dailyRate);
        System.out.println("Basic Pay: " + basicPay);
    }
}
package studentgrade;

import java.util.Scanner;
public class StudentGrade {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
            Scanner input = new Scanner(System.in);

        System.out.print("Enter Prelim Grade: ");
        double prelim = input.nextDouble();

        System.out.print("Enter Midterm Grade: ");
        double midterm = input.nextDouble();

        System.out.print("Enter Final Grade: ");
        double finalGrade = input.nextDouble();

        double subjectGrade = (prelim + midterm + (finalGrade * 2)) / 4;

        String gradeEquivalent;
        if (subjectGrade >= 96) {
            gradeEquivalent = "1.00";
        } else if (subjectGrade >= 94) {
            gradeEquivalent = "1.25";
        } else if (subjectGrade >= 92) {
            gradeEquivalent = "1.50";
        } else if (subjectGrade >= 89) {
            gradeEquivalent = "1.75";
        } else if (subjectGrade >= 87) {
            gradeEquivalent = "2.00";
        } else if (subjectGrade >= 84) {
            gradeEquivalent = "2.25";
        } else if (subjectGrade >= 80) {
            gradeEquivalent = "2.50";
        } else if (subjectGrade >= 78) {
            gradeEquivalent = "2.75";
        } else if (subjectGrade >= 75) {
            gradeEquivalent = "3.00";
        } else {
            gradeEquivalent = "5.00";
        }

        System.out.println("Subject Grade: " + subjectGrade);
        System.out.println("Grade Equivalent: " + gradeEquivalent);
    }
}
package gendergreeting;
import java.util.Scanner;
public class GenderGreeting {

    public static void main(String[] args) {
                Scanner input = new Scanner(System.in);

        System.out.print("Enter your gender (m/f): ");
        char gender = input.next().charAt(0);

        if (gender == 'm' || gender == 'M') {
            System.out.println("Hello Sir");
        } else if (gender == 'f' || gender == 'F') {
            System.out.println("Hello Madam");
        } else {
            System.out.println("Invalid input");
        }
    }
}
package yearendbonus;

import java.util.Scanner;
public class YearEndBonus {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
         Scanner input = new Scanner(System.in);

        System.out.print("Enter the employee's name: ");
        String name = input.nextLine();

        System.out.print("Enter the employee's monthly salary: ");
        double salary = input.nextDouble();

        double bonus;
        if (salary < 2000) {
            bonus = salary * 0.5;
        } else {
            bonus = 1500;
        }

        System.out.println(name + "'s bonus is: " + bonus);
    }
}
package employeesalary;
import java.util.Scanner;
public class EmployeeSalary {

   
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        System.out.print("Enter the number of hours worked: ");
        int hoursWorked = input.nextInt();

        double salary = 0;
        if (hoursWorked <= 40) {
            salary = hoursWorked * 50;
        } else {
            salary = 40 * 50 + (hoursWorked - 40) * 30;
        }

        System.out.println("The salary is: " + salary);
    }
}
  
package gradeincrease;

import java.util.Scanner;
public class GradeIncrease {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        System.out.print("Enter the original grade: ");
        double originalGrade = input.nextDouble();

        double newGrade = originalGrade;
        if (originalGrade < 90) {
            newGrade += 5;
        }

        System.out.println("The new grade is: " + newGrade);
    }
}
Increase the Modal Height

.uiModal flowruntime-flow {
    max-height: 100% !important;
}
 Save
Set the Modal Width

.uiModal--medium .modal-container {
    max-width: 400px !important;
}
 Save
Hide the Close Button

button.slds-modal__close.closeIcon {
    display: none;
}
 Save
Increase the Text Area Fields' Height

textarea {
    min-height: 300px !important;
}
 Save
Change the Color of Text Area Fields

textarea {
    color: green !important;
    font-weight: 800;
    min-height: 200px !important;
}
 Save
Change the Navigation Bar's Color

.uiModal flowruntime-navigation-bar {
    background-color: lightblue !important;
    border-width: 0 !important;
}
 Save
Add a Background Image

.uiModal flowruntime-flow {
    background-image: url("https://salesforcetime.com/wp-content/uploads/2021/04/sfba3.jpg") !important;
    background-repeat: no-repeat !important;
    background-position: center;
    background-size: cover;
}

.slds-modal__header {
    margin-bottom: 0 !important;
}
 Save
Remove the Borders of the Flow

article.flowRuntimeForFlexipage {
 border: none;
}
 Save
Change the Height of a Data Table

flowruntime-datatable .restrict-scroll {
    max-height: 200px !important;
}
// Previous Way
function getListData(data) {
  const items = [];
  if (!data) return [];
  for (const [index, item] of Object.entries(data)) {
    const name = item.name;
    const category = item.category;
    const web = item.website;

    const obj = {
      name,
      category,
      web,
    };

    items.push(obj);
  }
  return items;
}





// Cleaner Solution - new way

  function getListData(data) {
    if (!data) return [];
    return Object.entries(data).map(([index, item]) => ({
      name: item.name,
      category: item.category,
      web: item.website,
    }));
  }


const getData = getListData(dummyData)
#include<iostream>
#include<vector>
using namespace std;
int LinearSearch(vector<int> &vec, int target){
    int i = 0;
    for(int val : vec){
        if(val == target)
           return i;
        i++;
    }
    return -1;
}
int main(){
    vector<int> vec = {1, 2, 5, 8, 5, 7, 8};
    int target = 7;
    cout << LinearSearch(vec, target) << endl;
    return 0;
}
import mongoose from "mongoose";

const userSchema = new mongoose.Schema(
  {},
  { timestamps: true }
);

export const User = mongoose.model("User", userSchema);
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema(
  {
    name: { type: String, required: true },
    email: { type: String, required: true, unique: true },
    password: { type: String, required: true },
    age: { type: Number, min: 18 },
  },
  { timestamps: true } 
);

const User = mongoose.model('User', userSchema);

module.exports = User;
package prisontest;

/**
 *
 * @author Almer
 */
public class Prisontest {
    
        public static void main(String[] args){
        cell cellA1 = new cell("A1", false, 1234);
        prisoner bubba = new prisoner("Bubba", 2.08, 4, cellA1);
        
        bubba.display();
        cellA1.setIsOpen(1111);
        cellA1.setIsOpen(1234);
        cellA1.setIsOpen(1234);
    }
}
package prisontest;

/**
 *
 * @author Almer
 */
public class prisoner {
    
    private String name;
    private double height;
    private int sentence;
    private cell cell;
    
    //Constructor
    public prisoner(String name, double height, int sentence, cell cell){
 	this.name = name;
 	this.height = height;
 	this.sentence = sentence;
        this.cell = cell;
    }
    
    //Methods
    public void think(){
        System.out.println("I'll have my revenge.");
    }
    public void display(){
        System.out.println("Name: " +getName());
        System.out.println("Height: " +getHeight());
        System.out.println("Sentence: " +getSentence());
        System.out.println("Cell: " +getCell().getName());
    }

    public String getName() {
        return name;
    }
    public double getHeight() {
        return height;
    }
    public int getSentence() {
        return sentence;
    }
    public cell getCell() {
        return cell;
    }
    //Setters
    public void setName(String name) {
        this.name = name;
    }
    public void setHeight(double height) {
        this.height = height;
    }
    public void setSentence(int sentence) {
        this.sentence = sentence;
    }
    public void setCell(cell cell) {
        this.cell = cell;
    }
}

package prisontest;


public class cell {
    private String name;
    private boolean isOpen;
    private int securityCode;
    
    public cell(String name, boolean isOpen, int securityCode){
        this.name = name;
        this.isOpen = isOpen;
        this.securityCode = securityCode;
    }
    
    public String getName(){
        return name;
    }
    public boolean getIsOpen(){
        return isOpen;
    }
    
    public void setIsOpen(int code){
        if(code != securityCode){
            System.out.println("Incorrect code");
        }
        else{
            if(isOpen == true){
                isOpen = false;
                System.out.println("Cell " +name +" Closed");
            }
            else{
                isOpen = true;
                System.out.println("Cell " +name +" Open");
            }
        }
    }
}

#include <iostream>
#include <fstream>
#include <string>
#include <memory>

struct Node {
    std::string line;
    int number;
    std::shared_ptr<Node> next;
    
    Node(std::string l = "", int n = 0) : line(l), number(n), next(nullptr) {}
};

void read(std::shared_ptr<Node>& root) {
    std::ifstream reader("read.txt");  // cin
    if (reader.is_open() && !reader.eof()) {
        root = std::make_shared<Node>();
        reader >> root->line >> root->number;  
        auto tmp = root;
        
        while(!reader.eof()) {
            tmp->next = std::make_shared<Node>();
            tmp = tmp->next;
            reader >> tmp->line >> tmp->number;
        }
    }
}

void type(std::shared_ptr<Node> root) {
    auto tmp = root;
    while (tmp) {
        std::cout << tmp->line << " " << tmp->number << std::endl;
        tmp = tmp->next;
    }
}

void remove(std::shared_ptr<Node>& root, int const number) {
    
    // for first root
    if (root->number == number) {
        root = root->next;
        return;
    }

    auto tmp = root;
    while (tmp->next && tmp->next->number != number) {
        tmp = tmp->next;
    }

    if (tmp->next) {
        tmp->next = tmp->next->next;
    } else {
        std::cout << "we didn' find this element" << std::endl;
    }
}

void insert(std::shared_ptr<Node>& root, int pos, const std::string& str, int val) {
    if (pos == 0) {
        std::shared_ptr<Node> new_root = std::make_shared<Node>(str, val);
        new_root->next = root;
        root = new_root;
        return;
    }

    auto tmp = root;
    for (int i = 1; tmp && i < pos; ++i) {
        tmp = tmp->next;
    }

    if (tmp) {
        std::shared_ptr<Node> new_node = std::make_shared<Node>(str, val);
        new_node->next = tmp->next;
        tmp->next = new_node;
    } 
}

int main() {
    std::shared_ptr<Node> root;
    
    read(root);
    
    std::cout << "list:" << std::endl;
    type(root);
    
    insert(root, 0, "New first line", 10);
    std::cout << "\nuse insert to put new element to the first root:" << std::endl;
    type(root);

    insert(root, 2, "newline", 20);
    std::cout << "\njust use void insert:" << std::endl;
    type(root);
    
    remove(root, 10);
    std::cout << "\n delete root with value = 10:" << std::endl;
    type(root);


    return 0;
}
1. Purga la instalación de Docker:
sudo apk del docker

2. Instalar o reinstalar Docker:
sudo apk add docker

3. Solucionar problemas:
Para desmascarar los servicios de Docker:

sudo rc-update add docker default
sudo service docker start

4. Iniciar Docker:

sudo service docker start

5. Probar la instalación de Docker:
sudo docker run hello-world

6. Reiniciar Docker:

sudo service docker restart

7. Parar Docker:
sudo service docker stop

7.1 ver el estado de docker:
sudo service docker status

8. Comprobar el estado de Docker:
sudo service docker status

9. Ver imágenes de Docker:
docker images

10. Agregar usuario al grupo "docker":
Esto te permite ejecutar comandos de Docker sin sudo:
sudo addgroup $USER docker && newgrp docker

Otros Comandos Útiles
Listar contextos de Docker:
docker context ls 

Usar el contexto por defecto:
docker context use default 

Establecer el host de Docker:
export DOCKER_HOST="tcp://0.0.0.0:2375"

Detener todos los recursos pendientes (imágenes, contenedores, volúmenes y redes):
docker system prune

detener un contenedor de docker
docker stop <container_ID>
  
luego de detenerlo ejecuta este para eliminarlo
docker rm <container_ID>

Eliminar contenedores detenidos y todas las imágenes no utilizadas:
docker system prune -a

Eliminar imágenes por nombre (asegúrate de tener permisos adecuados):
sudo docker rmi <image_name>

sudo docker rmi -f <image_name:latest>
  
  Enumerar imágenes pendientes es decir que esten siendo usadas por otro contenedor:
docker images -f dangling=true

Eliminar imágenes pendientes:
docker rmi $(docker images -f "dangling=true" -q)
# I am working on scRNAseq data derived from human bladder cancer 'Urothelial carcinoma'
# Urothelial carcinoma has 2 subtypes - muscle invasive (MIBC), non-muscle invasive (NMIBC)
# NMIBC has high likelihood of recurrence 50-70% and progression to MIBC (cite 1), where MIBC has a concerning 50-70% mortality rate! (cite 2)
# Hence progression is a useful point of target, and I will look at urothelial heterogeneity within non-malignant NMIBC papilloma
# to see what could possibly be contributing to the process, as well as what makes it non-malignant?

# Data comes from 2 individuals. (M 67yrs, M 58yrs)
# sample BC1 = low grade Ta non-malignant NMIBC cells from (M, 67yrs)
# sample BC6 = low grade Ta non-malignant NMIBC cells from (M, 58yrs)
# differences between the two cell sets should be due to person differences (let's see if it's true!)

# Firstly, I will access the Genomics shared libraries 
.libPaths("libs/R_4.3.3")

# load relevant libraries
library(tidyverse)
library(Seurat)
library(clustree)
library(ggplot2)
library(ggrepel)
library(fgsea)

# Questions to ask ####
# REFERENCES????
# 2 - filters cells with more than number of features defined by 'feat_max_filt' defined in line 130
# find out the feat_max threshold and then put in numerical values 
# end of section 2 data QC - does 2 data sets refer to pre QC and post QC or the 2 features (nfeature, MT%)

# 1 Load, preview and explore data ####
counts <- Read10X("data5/02_assessment_options/assessment02_BC1-BC6")

# check dimensions of data (i.e number of genes - rows, cells - columns)
dim(counts)
# number of rows = 38606, columns = 16155

# quick preview of data. Structure, type, first few values
str(counts)

# setting IDs and conditions (here = cancer T stages) for counts
# reminder that all data originates from one person (80 yrs, M)
# sample BC4 = high grade T2 malignant MIBC cells 
# sample BCN = paracancerous normal urothelial cells (hence T0 since not defined by T stages)
ids <- c("BC1", "BC6")
con <- c("Ta1", "Ta6")

# create a table 'cell_counts' based on column names from 'counts'
# create metadata df, and annotate my data with labels
cell_counts <- table(substring(colnames(counts),18))

# construct two vectors 'sample', 'conditions' from 'ids', 'con' based on 'cell_counts'
# set up sample and condition labels for the backgrounds
samples <- c()
for (s in 1:length(ids)) { 
  samples <- c(samples, (rep(paste(ids)[s], cell_counts[s])))
} 
conditions <- c()
for (c in 1:length(con)) { 
  conditions <- c(conditions, (rep(paste(con)[c], cell_counts[c])))
} 

# now I will create a metadata df
metadata <- data.frame(Sample=samples, Conditions=conditions, row.names=colnames(counts))

# then check metadata df cell numbers match expected 
metadata |> group_by(Sample) |> summarise(Cells=n())
metadata |> group_by(Conditions) |> summarise(Cells=n())

# create seurat object 'so' from data
# an R package used for scRNAseq analysis that stores + organise scRNAseq data, metadata, results 
# rows = genes, columns = cells
# 'meta.data' specifies a metadata df which has additional info of each cell (ie cell types)
so <- CreateSeuratObject(counts=counts, project="Genomics_W5assessment", meta.data=metadata)

# assign cell identities based on 'conditions' column from metadata
# this allows further analysis to consider cells belonging to different conditions
# i.e DEA, clustering etc can be done based on 'conditions'
Idents(so) <- so@meta.data$Conditions

# remove unused variables to tidy up memory
rm(c, s, cell_counts, con, conditions, ids, samples, counts, metadata)

# ################################### #

# 2 Data QC check ####
# removing low quality data from dataset 

# Main areas to lookout in scRNAseq - contamination of data
# high Mt% indicates dying cells, often correlated with low number of features
# high number of features suggests 2 cells are present in sample instead of single cell

# calc %MT gene expression  
# adds a new metadata column 'percent.mt' of %MT for each cell
so <- PercentageFeatureSet(so, pattern="^MT-", col.name="percent.mt")

# Visualize the distribution of mitochondrial gene percentages 
VlnPlot(so, features = "percent.mt")

# violin plot to visualize and compare distribution of 2 selected features - number of features, MT%
# across different cell groups (i.e sample or condition)
# assists QC by easing detection of any outliers in my data (low quality/stressed/dying cells)
VlnPlot(so, features=c("nFeature_RNA","percent.mt"), 
        ncol=2, pt.size=0, group.by="Sample", raster=FALSE)

# distribution pattern is different for BC1 BC6 in nFeature_RNA
# BC1 data is too evenly distributed, no median possible to be observed
# In contrast BC6 has nice violin shaped distribution making it relatively easier to decide cut off points to remove low quality data
# so I decide data cut off threshold based on BC6 

# save plot
ggsave("plots5/1_violinplot_preQC.png")

# Summarize key stats based on distribution above, related to %MT and number of features 
# Create a summary table 
summary_metadata <- so@meta.data |> 
  group_by(Sample) |> 
  summarize(
    mt_med = quantile(percent.mt, 0.5),
    mt_q95 = quantile(percent.mt, 0.95),
    mt_q75_plus_IQR = quantile(percent.mt, 0.75) + (1.5 * IQR(percent.mt)),
    feat_med = median(nFeature_RNA),
    feat_q95 = quantile(nFeature_RNA, 0.95),
    feat_q75_plus_IQR = quantile(nFeature_RNA, 0.75) + (1.5 * IQR(nFeature_RNA)),
    count = n()
  )

# print the table
summary_metadata

# scatter plot number of features VS %MT for each cell 
# assists my QC by identifying cells with high MT%, low features (indicative of dying cells/ empty droplets)
# also can identify cell clusters - useful for downstream analysis 
ggplot(so@meta.data, aes(nFeature_RNA, percent.mt, colour=Sample)) +
  geom_point(alpha=0.2) + 
  facet_grid(.~Sample) + 
  theme_bw()

ggsave("plots5/2_nfeatures_vs_%MT_preQC.png")

# removing low feature/high MT% cells using UQ + (1.5*IQR) rule
# find the upper threshold limit for MT% in both samples, then take the lowest value
mt_filt <- min(summary_metadata$mt_q75_plus_IQR)

# find upper threshold limit for feature number in both, then take the lowest value
feat_max_filt <- min(summary_metadata$feat_q75_plus_IQR)

# print proposed thresholds
mt_filt # 6.370424
feat_max_filt # 5279.75
# These are proposed threshold, but I need to take closer look at data first to decide cut off points  

# Taking a closer look at low quality data first - I will use 2 graphs, one for each feature
# this is in preparation to filter data after visualization 

# 1 - zoomed-in version scatter plot focusing on cells < 10% MT content (clear up feature 1)
# I can exclude cells that are potentially stressed/ dying more clearly since zoomed in view
ggplot(subset(so@meta.data, subset = percent.mt < 10), aes(nFeature_RNA, percent.mt, colour=Sample)) + 
  geom_point(alpha=0.2) + 
  facet_grid(.~Sample) + 
  theme_bw() + 
  xlim(0,8000) + # set limits to x axis to zoom in when viewing graph to decide cut off point

ggsave("plots5/3_%MT_zoomedlowqual_QC.png")

# 2 - density plot for number of features detected per cell (clear up feature 2) 
# across different samples in the seurat object 'so' I created earlier
# from plot I can identify potential problems like under-sampling or a variability in number of genes detected
ggplot(so@meta.data, aes(x=nFeature_RNA, colour=Sample)) + 
  geom_density() + 
  facet_grid(.~Sample) + 
  theme_bw() + 
  xlim(0,3500) # set limits for x axis to zoom in when viewing graph to decide cut off point, the 'dip' in graph 
# graph 'dip' is approx at 1800 on x axis

ggsave("plots5/4_nfeature_zoomedlowqual_QC.png")

# Now I can begin data filtering process! - filter based on 3 conditions
# 1 - cells < 1800 features (genes) detected
# 2 - cells with more than number of features defined by 'feat_max_filt' defined in line 130 - an upper limit
# 3 - % MT gene expression. Threshold 6.370424 prev defined by 'mt_filt'. Again, filtering out cells with high MT content as indicative of low quality cells (i.e dying)
so <- subset(so, subset = nFeature_RNA >= 1800 & nFeature_RNA <= feat_max_filt & percent.mt <= mt_filt)

# after filtering I have new data set - post QC
# so generate new summary data for filtered data set 
so@meta.data |> group_by(Sample) |> summarize(mt_med = quantile(percent.mt, 0.5),
                                              mt_q95 = quantile(percent.mt, 0.95),
                                              mt_q75_plus_IQR = quantile(percent.mt, 0.75) + (1.5 * IQR(percent.mt)),
                                              feat_med = median(nFeature_RNA),
                                              feat_q95 = quantile(nFeature_RNA, 0.95),
                                              feat_q75_plus_IQR = quantile(nFeature_RNA, 0.75) + (1.5 * IQR(nFeature_RNA)),
                                              count = n())

# now visualize new summary data post QC - violin plot like previous
# violin plot to visualize and compare distribution of 2 selected features - number of features, MT%
# across different cell groups (i.e sample or condition)
VlnPlot(so, features=c("nFeature_RNA", "percent.mt"), 
        ncol=2, pt.size=0, group.by="Sample", raster=FALSE)

# Recap - I have chosen thresholds based on BC6 as it had better initial distribution to decide data cut off points
# filtered data only shows cells of good quality facilitating my downstream analysis

ggsave("plots5/5_violinplot_postQC.png")

# some points to consider about the QC process is that : 
# same filters are applied to both data sets BC1 BC6, which would surely have differences (i.e starting distributions, sequencing depth across data sets)
# a threshold that works well for one data set may i.e discard good quality cells in another
# but can only try our best when deciding cut-off point - i.e zooming into graph. It is better than including bad quality data!

# create save point
save.image("savepointA_QC-complete.RData")

# ############################################## #

# 3 Data Integration ####

# merge data sets after filtering each data sets individually. Need to ensure filtering doesn't bias data
# potential problem - imbalanced data set (i.e one was aggressively filtered = has far fewer cells than other, could cause bias downstream)
# can use stats to account for these differences (i.e normalization, batch correction, merging strategies)
# here I use normalization 

# Merging data is crucial for comparison 
# different cell types from one person can be more similar than same cell type from 2 people 
# this means same cell type from different donors would be separated during analysis/ clustering - not useful, hence integration needed

# split objects by conditions defined in section 1 (Ta1, Ta6)
con.list <- SplitObject(so, split.by = "Conditions")

# normalize and identify variable features for each data set independently
# also ensure the modified object is returned so con.list is updated
# top 3000 most variable genes selected for downstream analysis
con.list <- lapply(X = con.list, FUN = function(x) {
  x <- NormalizeData(x, normalization.method = "LogNormalize")
  x <- FindVariableFeatures(x, selection.method = "vst", nfeatures = 3000)
  return(x)  
})

# Scale the data and perform PCA for each condition
con.list <- lapply(X = con.list, FUN = function(x) {
  x <- ScaleData(x)
  x <- RunPCA(x)
  return(x)
})

# (extra from workshop)####
# after normalization and variable feature selection, can proceed with other analyses such as scaling, PCA, clustering, or differential expression

# after normalization and variable feature selection - standard thing to do is integrate the 2 conditions based on shared variable features
# I prev selected top 3000 most variable genes to look at (nfeature)
# when shared variable features close to 3000 = likely lose biological difference
# but some similarities/ shared variables (to certain extent) needed to merge 2 data sets = ~600-2400, closer halfway the better

# check overlap between most variable features in 2 conditions (Ta1,Ta6)
length(intersect(VariableFeatures(con.list$Ta1), VariableFeatures(con.list$Ta6)))

# select features repeatedly variable across data sets for integration
intfeats <- SelectIntegrationFeatures(object.list = con.list, nfeatures = 3000)

# integration - finally! Now combine data sets using anchors 
int.anchors <- FindIntegrationAnchors(object.list = con.list, anchor.features = intfeats)
so_donorint <- IntegrateData(anchorset = int.anchors)

# scaling data to ensure genes with higher variance don't dominate analysis following integration, each feature contributes equally
# set default assay to 'integrated' so downstream analysis uses integrated data (corrected values)
# instead of data before integration/ raw counts etc
DefaultAssay(so_donorint) <- "integrated"
so_donorint <- ScaleData(so_donorint, features = rownames(so_donorint))

# clear up objects no longer needed after integration 
# splitted conditions, anchors used to integrate datasets, features selected for integration, original 'so' object before processing
rm(con.list, int.anchors, intfeats, so)

# create save point 
save.image("savepointB_QC-integration-complete.RData")

# #################################### #

# 4 Find clusters of cell types ####

# Data quality is sorted following QC (section 1) and integration (section 3)
# data is now a single analysis object!

# can now look at biology - try identify communities of cells alike 
# genes can work in pathways so not equally informative
# use PCA to reduce dimension and identify patterns of shared variance then derive (potential) communities 
# also work out how many clusters are (potentially!) informative 

# run PCA on integrated data set 
# recap PCA reduces dimensions in data, only capture max variance in data so easy to visualize
# in context of scRNAseq, I'm using PCA to get main sources of variation in gene expression
so_donorint <- RunPCA(so_donorint)

# top 5 PCs shown, biggest contributor in each direction are : 
# COSMIC to see if these genes contain mutations that is implicated in cancer? 
# PC1 positive = HLA-DRB6 - antigen processing + presenting, immune response
# PC1 negative = ADIRF - positive regulation of fat cell differentiation 
# PC2 positive = TXNIP - tumour suppressor gene (uniprot)
# PC2 negative = MT-CO1 - 
# PC3 positive = DHRS2 
# PC3 negative = CD3D
# PC4 positive = SGK1 
# PC4 negative = DHRS2 
# PC5 positive = MT-CO3
# PC5 negative = HSPA1A

# pick the most informative PC
# elbow plot to show me percentage variance explained by each PC
ElbowPlot(so_donorint)

# As number of PC increases, the variance explained by each subsequent PC decrease more gradually
# The "elbow" is the point where the curve flattens out - stop considering additional PC as they contribute little to explaining data's variance.

# after running PCA to assess how much variance in each PC
# calc % variance explained by each PC and cumulative % variance across all PCs 
# helps me determine number of PCs to keep for downstream analysis
pct <- so_donorint[["pca"]]@stdev / sum(so_donorint[["pca"]]@stdev) * 100
cumu <- cumsum(pct)

# identify point/PC where cumulative variance > 90%, % variance explained < 5% (does not contribute much to variance)
co1 <- which(cumu > 90 & pct < 5)[1]
co1 # 43

# identify point/PC where difference in % variance explained (contribution to variance) between 2 consecutive PCs is > 0.1%
# I can find the point of significant drop in contribution of variance explained by each PC
co2 <- sort(which((pct[1:length(pct) - 1] - pct[2:length(pct)]) > 0.1), decreasing = T)[1]
co2 # 12

# select minimum value between the 2 measures (co1, co2)
# provides criteria to decide when to stop including additional PCs
# co1 - point where a PC has cumulative variance > 90%, variance explained < 5%
# co2 - point where there's significant drop in variance explained between 2 consecutive PCs
pcs <- min(co1, co2)
pcs # 12

# create data frame containing 3 variables
# pct - % variance contributed by each PC
# cumu - cumulative % variance contributed by PCs 
# rank - ranking of each PC showing its order in analysis
cumu_df <- data.frame(pct = pct, cumu = cumu, rank = 1:length(pct))

# Elbow plot to visualize relation between cumulative variance explained, % variance contribution by each PC
ggplot(cumu_df, aes(cumu, pct, label = rank, color = rank > pcs)) + 
  geom_text() +
  theme_bw()

# clean up - remove objects unnecessary for downstream analysis 
rm(pct, cumu, cumu_df, co1, co2)

# PCA-based scatter plot to visualize 4 selected features/genes - check if PCA successful
# cells expressing these markers are shaded from dark blue (most expression) to pale pink (least/none)
FeaturePlot(so_donorint, reduction = "pca", dims = c(1, 2), 
            features = c("HLA-DRB6", "ADIRF", "TXNIP", "MT-CO1"), cols = c("#fcd5ce", "#4886af"), 
            pt.size = 2.5, alpha = 0.7, order = TRUE,)

ggsave("plots5/6_featureplot.png")

# data is spread across first 2 main PCs only
# gene 'MT-CO1' shown to have greatest expression across PC1 PC2, closely followed by gene 'ADIRF'
# gene 'HLA-DRB6' have least expression across PC1 PC2 
# add comment on - Are the genes are typically markers of different cell types present in tumors 

# Neighbor analysis 
# to find relationships between cells (calc neighborhoods) based on first PC (pcs)
DefaultAssay(so_donorint) <- "integrated"
so_donorint <- FindNeighbors(so_donorint, dims = 1:pcs)

# problems with neighbour analysis
# Neighbour analysis finds potential communities but does not give reference of how many communities should be present
# community detection starts with all cells in 1 community - followed by successive subdivisions
# using cluster tree = can visualize how communities derived + subdivided 

# so, perform clustering analysis across multiple resolution values
# then visualize resulting clusters by cluster tree plot 
so_donorint_orgs <- FindClusters(so_donorint, resolution = seq(0, 0.3, 0.05))
clustree(so_donorint_orgs, show_axis = TRUE) + theme(legend.position = "none") + ylab("Resolution")

ggsave("plots5/7_clustertree_lineage.png")

# so above cluster tree plot shows successive community divisions as resolution increases
# an issue is - most numerous type often results in most subgroups. Purely due to its high abundance and not biologically different
# I will therefore start my analysis at low resolution to monitor closely the main community lineages

# clear up unnecessary objects for downstream analysis 
rm(so_donorint_orgs)

# set initial resolution to 0.05 for clustering cells 
# based on cluster tree plot I should see 3 communities 
res <- 0.05

# now assign cells to a cluster and run UMAP - reduce dimensions so I can visualize
# UMAP allows me to visualize clusters - based on first PCA 
# 2D representation of cells to visualize similarities/differences based on high dimensional features (i.e gene expression) - based on first PCA
so_donorint <- FindClusters(so_donorint, resolution = res)
so_donorint <- RunUMAP(so_donorint, dims=1:pcs, return.model = TRUE, verbose = FALSE)

# UMAP plot - Visualization of my clustered data using UMAP plot 
DimPlot(so_donorint, reduction = "umap", label = TRUE, label.size = 6)

# based on cluster tree plot I should see 3 communities 
# however population 1 (green) is shown to be in 2 separate groups suggesting further subdivision
# I will test with higher resolution later in this analysis to see subdivisions for different cell types 

# save plot first
ggsave("plots5/8_UMAP_res0.05.png")

# split UMAP plot - based on 'conditions' + add labels 
# shows how clusters are distributed across conditions Ta1 Ta6
DimPlot(so_donorint, reduction = "umap", split.by = "Conditions", label = TRUE, label.size = 6)

ggsave("plots5/9_splitUMAP_res0.05.png")

# since Ta1 Ta6 are identical - same grade, same non-malignant NMIBC tumour pattern should be the same
# any differences technically should be due to person differences
# distribution is roughly the same, but xxxxxxxxxxxxxx

# % distribution of each cell cluster across different conditions 
round(prop.table(table(Idents(so_donorint), so_donorint$Conditions))*100,3)

# add comments of graph pls - how organization of cell populations are in relation to exp conditions 
# which clusters are more abundant in certain conditions
# are any clusters enriched n one condition over another
# how evenly or unevenly distributed are the clusters across the different conditions 


# ################################## # 

# 5 Annotate clusters ####

# set default assay to 'RNA' and normalize gene expression data in 'RNA'
DefaultAssay(so_donorint) <- "RNA"
so_donorint_dp_norm <- NormalizeData(so_donorint, verbose = TRUE)

# now define list of genes for biological markers - likely communities
# can find genes that are related to cancer and see if its present via dotplot 
features <- c("TP53", "PTEN",                       # tumour suppressing - but if mutated = MIBC characteristic markers
              "FGFR3",                              # low grade NIBC tumour development markers
              "UPK2", "KRT13", "EPCAM", "KRT18",    # urothelial markers
              "COL1A1", "CALD1",                    # muscle markers
              "PECAM1",                             # endothelial
              "CD2", "CD3D", "CD3E",                # T cells
              "C1QC", "CD14", "CSF1R")              # macrophages/myeloid

# DotPlot to visualize expression of list of genes across different clusters of cells
# look at intensity/ proportion of cells expressing each marker in each community
# list of genes were defined previously
DotPlot(so_donorint_dp_norm, features = features, dot.scale=8) + 
  theme(axis.text.x = element_text(size = 11)) + 
  RotatedAxis ()

ggsave("plots5/Dotplot.png")
# again comment on the plot 
# what are the intensity/ proportion of cells expresker in each community

# FeaturePlot to visualize expression of 6 specific genes across UMAP-reduced data set
# check how specific the markers are 
FeaturePlot(so_donorint_dp_norm, reduction = "umap", 
            pt.size = 2, alpha = 0.7, order = TRUE, 
            features = c("UPK2", "EPCAM", "TP53", "PECAM1", "CD2", "C1QC", "PTEN"))

# again comment on plot
# cells more similar = placed closer together 
# colour of cells corresponds to expression level of specified genes. Higher expression = warmer colours (red/yellow). lower = blue/purple etc
# by specify multiple features = generate separate plot for each gene where colour intensity refelct expression of that gene across all cells 

# can use plot to - identify cell types - which clusters of cells express markers I've specified
# ie. UPK2 might be strongly expressed in one cluster (urothelial cells), while PECAM1 might be more expressed in endothelial cells
# put into your own context!
# can use plot to - assess whether gene-co-expression/ distinct expression across different cell clusters
# what communities contain what ?

# switch back to integrated assay for comparisons (not for plotting)
DefaultAssay(so_donorint) <- "integrated"

# run DEA to identify differentially expressed genes between the 2 sets of cells 
uro.markers <- FindMarkers(so_donorint, ident.1 = 0, ident.2 = 1)

# check data frame 
head(uro.markers)

# avoid errors caused by small p-values downstream by setting p-value limits
# all adjusted p-value > or = to (1e-300)
uro.markers["p_val_adj"] <- lapply(uro.markers["p_val_adj"], pmax, 1e-300)

# preparation for volcano plot
# categorize genes (in uro.markers) based on their DEA results
# create new column 'DEA' to classify each gene as up, down, no based on log fold-change and adjusted p-value
uro.markers$DEA <- "NO"
uro.markers$DEA[uro.markers$avg_log2FC > 1 & uro.markers$p_val_adj < 0.05] <- "UP"
uro.markers$DEA[uro.markers$avg_log2FC < -1 & uro.markers$p_val_adj < 0.05] <- "DOWN"
uro.markers$genes <- rownames(uro.markers)

# Volcano plot to visualize DEA results for comparison between the conditions (T1, T3)
ggplot(uro.markers, aes(x=avg_log2FC, y=-log10(p_val_adj))) + 
  geom_point(aes(colour = DEA), show.legend = FALSE) + 
  scale_colour_manual(values = c("blue", "gray", "red")) +
  geom_hline(yintercept = -log10(0.05), linetype = "dotted") + 
  geom_vline(xintercept = c(-1,1), linetype = "dotted") + 
  theme_bw() + 
  theme(panel.border = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(), axis.line = element_line(colour = "black")) +
  geom_text_repel(data=subset(uro.markers, (abs(avg_log2FC) > 4 & p_val_adj < 0.05)), aes(x=avg_log2FC, y=-log10(p_val_adj), label=genes), max.overlaps = 1000, size=4.5)

# comment on volcano plot 

# Cell cycle analysis - cell cycle scoring 
# to assign cell cycle phase (G1, S, G2M) based on expression of predefined sets of genes 
so_donorint.cc <- CellCycleScoring(so_donorint, s.features = cc.genes$s.genes,
                                   g2m.features = cc.genes$g2m.genes, set.ident = TRUE)

# check output to see newly assigned cell cycle phase for each cell
head(so_donorint.cc)

# visualize data in UMAP, split by cell cycle phase 
DimPlot(so_donorint.cc, reduction="umap", split.by="Phase", label=TRUE, label.size=10)

# comment on the plots 

# Validate the above interpretations with GSEA
# add a new column 'pi' to the 'uro.markers' data frame 
# pi is indicative of fold change and significance of each gene 
uro.markers <- mutate(uro.markers, pi = (avg_log2FC * (-1 * log10(p_val_adj))))

# set data frame to include only 2 column genes, pi
prerank <- uro.markers[c("genes", "pi")]
prerank <- setNames(prerank$pi, prerank$genes)

# check structure
str(prerank)

# prepare for GSEA - load gene set from GMT file
genesets = gmtPathways("data/h.all.v2024.1.Hs.symbols.gmt")
# need to copy from workshop 5 data file

# check output
str(genesets)

# run GSEA on 'prerank'. Results stored in fgseaRes
# stats method to determine whether a set of genes is statistically enriched in a ranked gene list (from DEA)
fgseaRes <- fgsea(pathways = genesets, stats = prerank, minSize=15, maxSize=500)

# check output
head(fgseaRes)

# extract top 10 significant pathways from GSEA results based on smallest p-value
top10_fgseaRes <- head(fgseaRes[order(pval), ], 10)
top10_fgseaRes

# visualize enrichment of gene set in ranked gene list 'prerank'
plotEnrichment(genesets[["HALLMARK_G2M_CHECKPOINT"]], prerank) + labs(title="G2M checkpoint", subtitle="Gene set enrichment analysis", x="Ranked Genes", y="Enrichment Score")

# comment on the plot 
# plot should help me understand where in the ranked gene list the genes associated with the G2/M checkpoint pathway are concentrated 
# possibly relate to any biological insights related to cell cycle

# Now I've identified cell communities with marker genes, differential expression, cell cycle analysis, GSEA
# add names to UMAP - some communities can do further subdivision (highlighted)
# zoom in by changing resolution to see lineages


# add RES ####  

# so prev xxx on UMAP shows community (X) in X colour is separately into 2 populations, indicative by its different positions
# this suggests further subdivision of community (X) could be seen at higher resolution
# Since I am looking at heterogeneity I want to identify different cell types present

# set resolution at 0.03 which is higher than previously used 0.05 for clustering cells 
res <- 0.1

# now assign cells to a cluster and run UMAP - reduce dimensions so I can visualize
# UMAP allows visualizing clusters 
# 2D representation of cells to visualize similarities/differences based on high dimensional features (i.e gene expression) - based on first PCA
so_donorint <- FindClusters(so_donorint, resolution = res)
so_donorint <- RunUMAP(so_donorint, dims=1:pcs, return.model = TRUE, verbose = FALSE)

# UMAP plot - Visualization of my clustered data using UMAP plot 
DimPlot(so_donorint, reduction = "umap", label = TRUE, label.size = 6)

# comment on interpret the relationships between different clusters visually. 
# It is useful for quickly assessing how well the clusters are separated and how distinct they are in the UMAP space.

# split UMAP plot - based on 'conditions' + add labels 
# shows me how clusters are distributed across different experimental conditions 
DimPlot(so_donorint, reduction = "umap", split.by = "Conditions", label = TRUE, label.size = 6)

# comment on split UMAP plot pls - the distributions and stuff


# % distribution of each cell cluster across different conditions 
# allows me to understand how cell populations are organized in relation to experimental conditions 
round(prop.table(table(Idents(so_donorint), so_donorint$Conditions))*100,3)

# add comments of graph pls - how organization of cell populations are in relation to exp conditions 
# which clusters are more abundant in certain conditions
# are any clusters enriched n one condition over another
# how evenly or unevenly distributed are the clusters across the different conditions 

# rename each cluster to make them biologically relevant
cluster_names <- c("urothelial_G1", "urothelial_G2M", "immune", "fibroblasts", "endothelial")
names(cluster_names) <- levels(so_donorint)
so_donorint <- RenameIdents(so_donorint, cluster_names)

# generate UMAP for 'so_donorint' to visualize
DimPlot(so_donorint, reduction = "umap", label = TRUE, label.size = 6) + NoLegend()

# comment on plot 

# save point 
save.image("savepointC_QC-integration-annotation-complete.RData") 

# 6 Are Ta1, Ta6 cells different? ####
# In both my data sets, cells are of same grade and cancer T stage
# since I am looking at heterogeneity, all cells will be assessed as a whole
# differences should originate from person differences

# ensure assay is integrated 
DefaultAssay(so_donorint) <- "integrated"

# combine cluster number and condition info into new variable 'celltype.condition'
# then set it as identity class of the cells 
# consider - how cell clusters behave under different conditions
so_donorint$celltype.condition <- paste(so_donorint$seurat_clusters, so_donorint$Conditions, sep="_")
Idents(so_donorint) <- "celltype.condition"

# run DEA for 2 sets of cells Ta1, Ta6 - compare expression profiles 
uroG1_T1vsT3 <- FindMarkers(so_donorint, ident.1 = "0_T3", ident.2 = "0_T1", test.use = "bimod")

# check output 
head(uroG1_T1vsT3)

# prepare data needed for volcano plot, as previous 
uroG1_T1vsT3["p_val_adj"] <- lapply(uroG1_T1vsT3["p_val_adj"], pmax, 1e-300)
uroG1_T1vsT3$DEA <- "NO"
uroG1_T1vsT3$DEA[uroG1_T1vsT3$avg_log2FC > 1 & uroG1_T1vsT3$p_val_adj < 0.05] <- "UP"
uroG1_T1vsT3$DEA[uroG1_T1vsT3$avg_log2FC < -1 & uroG1_T1vsT3$p_val_adj < 0.05] <- "DOWN"
uroG1_T1vsT3$genes <- rownames(uroG1_T1vsT3)

# Volcano plot to visualize DEA results to compare between Ta1, Ta6
ggplot(uroG1_T1vsT3, aes(x=avg_log2FC, y=-log10(p_val_adj))) + 
  geom_point(aes(colour = DEA), show.legend = FALSE) + 
  scale_colour_manual(values = c("blue", "gray", "red")) +
  geom_hline(yintercept = -log10(0.05), linetype = "dotted") + 
  geom_vline(xintercept = c(-1,1), linetype = "dotted") + 
  theme_bw() + 
  theme(panel.border = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(), axis.line = element_line(colour = "black")) +
  geom_text_repel(data=subset(uroG1_T1vsT3, (abs(avg_log2FC) > 8 & p_val_adj < 0.05)), aes(x=avg_log2FC, y=-log10(p_val_adj), label=genes), max.overlaps = 1000, size=4.5)

# comment on volcano plot and what it shows and why
# technically patterns should be the same as both same cell type, grade etc
# only differences should only be due to person differences 

# create pi values
# add new column to data frame 'uroG1_T1vsT3' where each gene is assigned a pi score (calc below)
# pi score allows me to rank genes - based on measure of log2fold change + stats significance, can then use to identify top genes for further analysis 
uroG1_T1vsT3 <- mutate(uroG1_T1vsT3, pi = (avg_log2FC * (-1 * log10(p_val_adj))))

# check data set - look at the top hit genes !!
head(uroG1_T1vsT3)

# select top 20 genes (for Ta6) based on pi score in descending order - fr highest pi scores
# these genes are most significant and differentially expressed when comparing between Ta1, Ta6 for G1 urothelial cluster
uroG1_T1vsT3 %>% arrange(desc(pi)) %>% slice(1:20) 

# select top 20 genes (for Ta1) based on pi score in ascending order - fr low pi score
# these genes are either of smaller fold changes or less stats significant p-values 
uroG1_T1vsT3 %>% arrange(pi) %>% slice(1:20) 

# prep for GSEA 
# extract 'genes', 'pi' from data frame and convert 'prerank' to numeric vector 
prerank <- uroG1_T1vsT3[c("genes", "pi")]
prerank <- setNames(prerank$pi, prerank$genes)
str(prerank)

# run GSEA and store results in fgseaRes
genesets = gmtPathways("data/c2.cp.v2024.1.Hs.symbols.gmt")
fgseaRes <- fgsea(pathways = genesets, stats = prerank, minSize=15, maxSize=300, eps=0)

# filter results from GSEA stored in fgseaRes
# checking top hits for either side of volcano plot 
fgseaRes %>% arrange(padj) %>% filter(NES<0) %>% slice(1:20)
fgseaRes %>% arrange(padj) %>% filter(NES>0) %>% slice(1:20)

# final save point!
save.image("savepointD_QC-integration-annotation-biocomp-complete.RData") 

# Extra analysis (1,2,3,4) ####

# ######################################################### # 


# Single-cell gene regulatory network inference 
# how TF regulate gene expression within different cell types or states
# provides insight to mechanisms driving cellular heterogeneity 

# GENIE3 - infers gene regulatory networks from single cell exp data 
library(GENIE3)
grn <- GENIE3(expression_data)

# SCENIC - identifies regulons (set of genes co-reg by common TF) + assess activity
library(SCENIC)
scenic_result <- runSCENIC(expression_data)



# ######################################################### # 

# Trajectory (pseudotime) analysis 
# follow progression of cells through differentiation, study transitions between different cell states 

# monocle - construct single cell trajectory + orders cells based on gene expression profiles 
library(monocle3)
cds <- as.cell_data_set(so)
cds <- preprocess_cds(cds, num_dim = 50)
cds <- reduce_dimension(cds)
plot_cells(cds, color_cells_by = "pseudotime")

# slingshot - orders cells along a trajectory + visualizes developmental/ differentiation pathways
library(Slingshot)
slingshot_data <- slingshot(so, clusterLabels = "seurat_clusters", reducedDim = "UMAP")
plot(slingshot_data, type = "line")


######################################################## # 

# Cell-cell interaction analysis using Cellchat 
# study communication between cells based on expression profiles 
# I use this to identify interactions between different cell type to understand cell behaviour in disease (cancer)
# identify the most abundant interaction as it may be crucial for determining tumour as 'non-malignant'
# can possibly induce similar interactions in malignant communities if identical cell types are also present

# Install Bioconductor 
install.packages("BiocManager")
BiocManager::install()

# Install CellChat package
devtools::install_github("sqjin/CellChat")

# Load the required libraries
library(CellChat)
library(Seurat)

# prepare single cell data 
# Load Seurat object containing single-cell RNA-seq data
so_donorint <- readRDS("path_to_your_seurat_object.rds")

# Ensure Seurat object has cell type information, stored in the "ident" column
so_donorint$celltype <- Idents(so_donorint)  

# preprocess data for CellChat - extract gene data, identify cell types
# Extract the expression matrix from the Seurat object
expression_data <- as.matrix(so_donorint@assays$RNA@counts)

# Identify cell types/conditions (you should have this in your Seurat object metadata)
cell_types <- so_donorint$celltype

# create CellChat object after processing data - stores necessary info for interaction analysis
cellchat <- createCellChat(object = expression_data, meta = so_donorint@meta.data, group.by = "celltype")

# Preprocess data for the interaction analysis
cellchat <- subsetData(cellchat)  # Subset the data (e.g., remove lowly expressed genes)

# run cell-cell interaction analysis 
# using pre-defined ligand-receptor interactions to compute potential cell-cell communication activities
cellchat <- computeCommunProb(cellchat)

# Identify significant interactions and pathways
cellchat <- computeCommunProbPathway(cellchat)

# Identify important ligand-receptor pairs
cellchat <- computeNetSimilarity(cellchat)

# Compute the signaling pathways' activity
cellchat <- aggregateNet(cellchat)

# now visualize cell-cell interaction networks (results)
# Plot network of cell-cell interactions/ communication
netVisual_aggregate(cellchat, signaling = "Ligand-Receptor", layout = "fr")

# visualize interactions for a specific ligand-receptor pair 
netVisual_bubble(cellchat, sources = "T_cells", targets = "Tumor_cells", signaling = "TNF")

# visualize cell communication pathways
pathwayPlot(cellchat, signaling = "TNF")
# add comments - how much activity in the given cell types or conditions 

# heatmap of communication strength - visualize strength of communication between different cell types
netVisual_heatmap(cellchat)

# comment on heatmap
# cell-cell interaction analysis is complete. Now decide which interactions are significant

# Differential cell-cell interaction to identify conditions that have significantly changed between conditions (Ta1 vs Ta6)
# in my research context would be same cells between 2 individuals. However results/ patterns are expected to be same as same cell community, just different individual
# so there should not be significant changes - if correct 

# Further analysis - Perform differential analysis between two conditions (e.g., "Condition1" and "Condition2")
cellchat <- identifyOverExpressedGenes(cellchat)
cellchat <- computeDifferentialNet(cellchat, group.by = "Condition")

# Further analysis - Compare interaction strength across different cell types between conditions 
netVisual_compare(cellchat, group.by = "Condition")

# Export cell communication network results as a data frame
interaction_results <- extractNet(cellchat)
write.csv(interaction_results, "cell_cell_interaction_happy_results.csv")

############################################################ # 


# Copy number variation (CNV) analysis 
# identify genomic regions where gene copy number differs from normal diploid state 

# Install necessary R packages
install.packages("BiocManager")
BiocManager::install(c("DNAcopy", "GenomicRanges", "DESeq2", "infercnv"))

# Load the libraries
library(DNAcopy)
library(GenomicRanges)
library(DESeq2)
library(infercnv)

# preparing data from seurat 
library(Seurat)

# Load Seurat object with RNA-seq data
so <- readRDS("path_to_your_seurat_object.rds")

# Extract gene expression matrix
expression_matrix <- as.matrix(so@assays$RNA@counts)

# check output
head(expression_matrix)

# prepare data input for CNV analysis by inferCNV. Need: 
# Expression data: A gene expression matrix (cells as columns and genes as rows).
# Cell annotations: A vector indicating cell type or condition
# Reference cells: Cells that are used as a reference for determining CNVs

# Assume you have cell type annotations in the Seurat object metadata
cell_types <- so$celltype  # This assumes cell type is in the metadata

# Prepare the CNV input (matrix of gene expression counts)
expression_data <- as.data.frame(t(expression_matrix))  # Transpose so that cells are rows

# Create a cell annotation file (indicating which cells are reference cells)
# Example: Create a vector where "1" indicates normal cells, "2" indicates tumor cells
cell_annotations <- ifelse(cell_types == "normal", 1, 2)
names(cell_annotations) <- colnames(expression_data)

# run CNV analysis on prepared data
infercnv_obj <- CreateInfercnvObject(
  raw_counts_matrix = expression_data,  # Input gene expression data matrix
  annotations_file = cell_annotations,   # Cell type annotations
  delim = "\t",                          # Delimiter if annotations file is a text file
  gene_order_file = "path_to_gene_order_file", # File containing the gene order (for human genome, hg38 gene order)
  ref_group_names = c("normal")          # Define the reference group (normal cells)
)

# Now run CNV analysis with default settings
infercnv_obj <- infercnv::run(infercnv_obj, 
                              cutoff = 1,        # Cutoff for filtering genes
                              num_threads = 4,   # Number of threads
                              window_length = 101,  # Window length for CNV smoothing
                              plot_steps = TRUE)  # Optionally plot the intermediate steps

# visualize CNV results after inferCNV - Plot the CNV results
infercnv::plot_cnv(infercnv_obj, 
                   output_filename = "cnv_results.png", 
                   color_by = "celltype")   # Optional color by cell type

# comment on the plot

# Perform differential CNV analysis across conditions Ta1, Ta6
# however here I am using it to hopefully prove same pattern across the 2 conditions
# due to same cells, just originate from different people 
# well but this is generally used to identify significant copy number changes between conditions 

dds <- DESeqDataSetFromMatrix(countData = cn_data, 
                              colData = data.frame(condition = c("normal", "tumor")), 
                              design = ~ condition)

# Run DESeq2 to find differential CNVs
dds <- DESeq(dds)
res <- results(dds)

# View differential CNV results
head(res)

# Export CNV results as CSV
write.csv(segments$output, "cnv_segments_results.csv")

# Save differential CNV results
write.csv(res, "differential_cnv_results.csv")

############################################################ # 









 Get-Process | Where-Object {$_.ProcessName -like '*ollama*'} | Stop-Process
import React, { useEffect, useState } from "react";
import { useNavigate, useSearchParams } from "react-router-dom";
import {
  DataGridPremium,
  GridColDef,
  GridFilterModel,
  GridLogicOperator,
  GridRowSelectionModel,
  GridToolbarContainer,
  GridToolbarExport,
  GridToolbarFilterButton,
  GridToolbarQuickFilter,
} from "@mui/x-data-grid-premium";
import Box from "@mui/material/Box";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import { DemoContainer } from "@mui/x-date-pickers/internals/demo";
import { DateRangePicker } from "@mui/x-date-pickers-pro/DateRangePicker";
import { SingleInputDateRangeField } from "@mui/x-date-pickers-pro/SingleInputDateRangeField";
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
import CalendarMonthIcon from "@mui/icons-material/CalendarMonth";
import IconButton from "@mui/material/IconButton";
import Tooltip from "@mui/material/Tooltip";
import FileDownloadOffIcon from "@mui/icons-material/FileDownloadOff";
import dayjs, { Dayjs } from "dayjs";
import Flag from "../../components/locationMakerWraper/Flag";
import DropdownMenuSea from "../../components/dropdown/DropdownMenuSea";
import initialRows from "./data/rowData";
import statusSettings from "./data/statusData";

const renderHeader = (params) => {
  return (
    <div>
      <span
        style={{
          fontWeight: 600,
        }}
      >
        {params.colDef.headerName}
      </span>
    </div>
  );
};

const initialColumns: Array<GridColDef> = [
  {
    field: "vessel",
    headerName: "Vessel",
    width: 200,
    renderHeader: renderHeader,
    cellClassName: "font-weight-medium",
    renderCell: (params) => {
      return (
        <div>
          <span
            style={{
              backgroundColor: "#f9fafb",
              padding: "6px 12px",
              borderRadius: 4,
              border: "1px solid #c4c9cb",
            }}
          >
            {params.value}
          </span>
        </div>
      );
    },
  },
  {
    field: "openDate",
    headerName: "Open Date",
    width: 100,
    type: "date",
    renderHeader: renderHeader,
    valueGetter: (value) => value && new Date(value),
    valueFormatter: (params) => {
      if (!params) return "";
      return dayjs(params).format("DD MMM YYYY");
    },
    filterable: false,
  },
  {
    field: "openUntil",
    headerName: "Open Until",
    width: 100,
    type: "date",
    renderHeader: renderHeader,
    valueGetter: (value) => value && new Date(value),
    valueFormatter: (params) => {
      if (!params) return "";
      return dayjs(params).format("DD MMM YYYY");
    },
    filterable: false,
  },
  {
    field: "status",
    headerName: "Status",
    width: 100,
    renderHeader: renderHeader,
    renderCell: (params) => {
      const status = statusSettings.find((s) => s.name === params.value);
      if (!status) return null;
      return (
        <div>
          <span
            style={{
              backgroundColor: status?.color || "transparent",
              color: status?.textColor || "inherit",
              padding: "2px 10px",
              borderRadius: 4,
              border: `1px solid ${status?.borderColor || "#e3e3e7"}`,
            }}
          >
            {params.value}
          </span>
        </div>
      );
    },
    filterable: false,
  },
  {
    field: "dwt",
    headerName: "DWT (t)",
    width: 100,
    type: "number",
    renderHeader: renderHeader,
    align: "left",
    headerAlign: "left",
  },
  {
    field: "buildYear",
    headerName: "Build year",
    width: 100,
    type: "number",
    renderHeader: renderHeader,
    align: "left",
    headerAlign: "left",
  },
  {
    field: "regionPort",
    headerName: "Region & Port",
    width: 200,
    renderHeader: renderHeader,
    renderCell: (params) => {
      const country = params.value.split(" / ")[1];
      const flag = params.value.split(" / ")[0];
      return <Flag country={country} flag={flag.toLowerCase()} />;
    },
  },
  {
    field: "subType",
    headerName: "Vessel Sub Type",
    width: 150,
    renderHeader: renderHeader,
  },
  {
    field: "lastCargos",
    headerName: "Last 3 Cargos",
    width: 150,
    renderHeader: renderHeader,
    renderCell: (params) => {
      const cargo = params.value.replace(/,/g, " /");
      return <div>{cargo}</div>;
    },
  },
  {
    field: "dirtyClean",
    headerName: "Dirty / Clean",
    width: 100,
    type: "singleSelect",
    valueOptions: ["Dirty", "Clean"],
    renderHeader: renderHeader,
  },
  {
    field: "operator",
    headerName: "Operator",
    width: 200,
    renderHeader: renderHeader,
    renderCell: (params) => {
      const country = params.value.split(" / ")[1];
      const flag = params.value.split(" / ")[0];
      return <Flag country={country} flag={flag.toLowerCase()} />;
    },
  },
];

const CustomToolbar = ({
  rows,
  // rowSelectionModel,
  statusValue,
  setStatusValue,
  dateRange,
  setDateRange,
}: {
  rows: any[];
  // rowSelectionModel: any[];
  statusValue: string;
  setStatusValue: (value: string) => void;
  dateRange: [Dayjs | null, Dayjs | null];
  setDateRange: (value: [Dayjs | null, Dayjs | null]) => void;
}) => {
  const dateFormat = "YYYY-MM-DD";
  return (
    <GridToolbarContainer>
      <div style={{ width: "100%", padding: "8px" }}>
        <div
          style={{
            display: "flex",
            alignItems: "center",
            justifyContent: "space-between",
          }}
        >
          <h2>Position List</h2>
          <div>
            <GridToolbarQuickFilter debounce={300} />
            {/*{rows.length < 1000 ||*/}
            {/*(rowSelectionModel.length < 1000 &&*/}
            {/*  rowSelectionModel.length > 0) ? (*/}
            {/*  <GridToolbarExport*/}
            {/*    printOptions={{ hideToolbar: true, hideFooter: true }}*/}
            {/*    csvOptions={{ fileName: `SEA (${dayjs().format(dateFormat)})` }}*/}
            {/*    excelOptions={{*/}
            {/*      fileName: `SEA (${dayjs().format(dateFormat)})`,*/}
            {/*    }}*/}
            {/*  />*/}
            {/*) : (*/}
            {/*  <Tooltip title="You may only export 1000 positions at a time.">*/}
            {/*    <IconButton>*/}
            {/*      <FileDownloadOffIcon />*/}
            {/*    </IconButton>*/}
            {/*  </Tooltip>*/}
            {/*)}*/}
          </div>
        </div>
        <div style={{ padding: "20px 0" }}>LIST VIEW / MAP VIEW</div>
        <div
          style={{
            display: "flex",
            alignItems: "center",
            justifyContent: "space-between",
          }}
        >
          <div style={{ display: "flex" }}>
            <GridToolbarFilterButton />
            <DropdownMenuSea
              label="Status"
              options={statusSettings}
              onChange={setStatusValue}
              value={statusValue}
            />
            <LocalizationProvider dateAdapter={AdapterDayjs}>
              <DateRangePicker
                sx={{ background: "#f0f0f0" }}
                slotProps={{
                  field: { clearable: true },
                  popper: { disablePortal: true, placement: "bottom" },
                  textField: () => ({
                    InputProps: {
                      startAdornment: <CalendarMonthIcon />,
                    },
                  }),
                }}
                format="DD MMM YYYY"
                value={dateRange}
                onChange={setDateRange}
              />
            </LocalizationProvider>
          </div>
          <div>
            Last updated {dayjs(new Date()).format("DD MMM YYYY [at] HH:mm")} •{" "}
            {rows.length} results
          </div>
        </div>
      </div>
    </GridToolbarContainer>
  );
};

const SeaTable = () => {
  const navigate = useNavigate();
  const [searchParams] = useSearchParams();
  const [filterModel, setFilterModel] = useState<GridFilterModel>({
    items: [],
    logicOperator: GridLogicOperator.And,
  });
  const [rows, setRows] = useState(initialRows);
  const [columns, setColumns] = useState(initialColumns);
  const [dateRange, setDateRange] = useState<[Dayjs | null, Dayjs | null]>([
    null,
    null,
  ]);
  const [rowSelectionModel, setRowSelectionModel] =
    useState<GridRowSelectionModel>([]);
  const [statusValue, setStatusValue] = useState("");

  useEffect(() => {
    console.log("alp1");
    loadUrlFilters();
  }, []);

  useEffect(() => {
    console.log("alp2");
    if (
      filterModel.items.length > 0 ||
      (dateRange[0] && dateRange[1]) ||
      statusValue !== ""
    ) {
      addUrlFilters(filterModel);
    } else {
      navigate({
        pathname: location.pathname,
        search: "",
      });
      return;
    }
  }, [filterModel, dateRange, statusValue]);

  useEffect(() => {
    console.log("alp3");
    applyFilters();
  }, [dateRange, statusValue]);

  const loadUrlFilters = () => {
    const items = [];
    let fieldId = 0;
    let logicOperator = GridLogicOperator.And;

    searchParams.forEach((value, key) => {
      switch (key) {
        case "logicOperator":
          logicOperator =
            value === "or" ? GridLogicOperator.Or : GridLogicOperator.And;
          break;
        case "startDate":
        case "endDate": {
          setDateRange([
            dayjs(searchParams.get("startDate")),
            dayjs(searchParams.get("endDate")),
          ]);
          break;
        }
        case "statusValue": {
          setStatusValue(searchParams.get("statusValue"));
          break;
        }
        default: {
          const [field, operator] = key.split("_");
          if (field && operator) {
            items.push({
              field,
              operator,
              value: operator === "isAnyOf" ? value.split(",") : value,
              id: fieldId++,
            });
          }
          break;
        }
      }
    });

    // If no filters, reset to show all rows
    if (items.length === 0) {
      setFilterModel({ items: [], logicOperator: GridLogicOperator.And });
      return;
    }

    setFilterModel({ items, logicOperator });
  };

  const addUrlFilters = (filterModel: GridFilterModel) => {
    const searchParams = new URLSearchParams();
    if (filterModel.items.length > 0) {
      filterModel.items.forEach((filter) => {
        const { field, operator, value } = filter;
        if (field && operator) {
          searchParams.set(`${field}_${operator}`, value ?? "");
        }
      });
      if (filterModel.logicOperator === GridLogicOperator.Or) {
        searchParams.set("logicOperator", "or");
      }
    }
    if (dateRange[0] && dateRange[1]) {
      searchParams.set("startDate", dateRange[0].format("YYYY-MM-DD"));
      searchParams.set("endDate", dateRange[1].format("YYYY-MM-DD"));
    }
    if (statusValue) {
      searchParams.set("statusValue", statusValue);
    }

    navigate({
      pathname: location.pathname,
      search: searchParams.toString(),
    });
  };

  const applyFilters = () => {
    let filteredRows = [...initialRows];
    if (statusValue !== "") {
      filteredRows = filteredRows.filter((row) => row.status === statusValue);
    }
    if (dateRange[0] && dateRange[1]) {
      filteredRows = filterRowsByDateRange(filteredRows, dateRange);
    }
    setRows(filteredRows);
  };

  const filterRowsByDateRange = (
    rows,
    [start, end]: [Dayjs | null, Dayjs | null],
  ) => {
    if (!start || !end) return rows;

    const startDate = start.startOf("day").toDate();
    const endDate = end.endOf("day").toDate();

    return rows.filter((row) => {
      const openDate = row.openDate ? new Date(row.openDate) : null;
      const openUntil = row.openUntil ? new Date(row.openUntil) : null;
      const isOpenDateWithinRange = openDate && openDate <= endDate;
      const isOpenUntilWithinRange = openUntil && openUntil >= startDate;

      if (!openUntil) return isOpenDateWithinRange;
      if (!openDate) return isOpenUntilWithinRange;

      return isOpenDateWithinRange && isOpenUntilWithinRange;
    });
  };

  return (
    <Box
      height="800px"
      sx={{
        padding: "36px",
        "& .font-weight-medium": {
          fontWeight: "500",
        },
      }}
    >
      <DataGridPremium
        rows={rows}
        columns={columns}
        checkboxSelection
        onRowSelectionModelChange={(newRowSelectionModel) => {
          setRowSelectionModel(newRowSelectionModel);
        }}
        rowSelectionModel={rowSelectionModel}
        slots={{
          toolbar: () => (
            <CustomToolbar
              rows={rows}
              // rowSelectionModel={rowSelectionModel}
              setStatusValue={setStatusValue}
              statusValue={statusValue}
              dateRange={dateRange}
              setDateRange={setDateRange}
            />
          ),
        }}
        filterModel={filterModel}
        onFilterModelChange={(newFilterModel) => setFilterModel(newFilterModel)}
        ignoreDiacritics
        hideFooterRowCount
      />
    </Box>
  );
};

export default SeaTable;
#include<iostream>
#include <climits>
using namespace std;
int sum(int arr[], int size){
    int sum = 0;
    for(int i = 0; i < size; i++){
        sum += arr[i];
    }
    return sum;
}
int product(int arr[], int size){
    int product = 1;
    for(int i = 0; i < size; i++){
        product *= arr[i];
    }
    return product;
}
void swap(int &a, int &b){
    a = a + b;
    b = a - b;
    a = a - b;
}
void uniqueElement(int arr[], int size){
    for(int i = 0; i < size; i++){
        bool isUnique = true;
        for(int j = 0; j < size; j++){
            if(i != j && arr[i] == arr[j]){
                isUnique = false;
                break;
            }
        }
        if(isUnique) cout << arr[i] << " ";
    }
    cout << endl;
} 
void reverseMinAndMax(int arr[], int size){
    int largest = INT_MIN, smallest = INT_MAX, largest_index = -1, smallest_index = -1;
    for(int i = 0; i < size; i++){
        if(arr[i] > largest){
            largest = arr[i];
            largest_index = i;
        }
        if(arr[i] < smallest){
            smallest = arr[i];
            smallest_index = i;
        }
    }
    swap(arr[largest_index], arr[smallest_index]);
    for(int i = 0; i < size; i++){
        cout << arr[i] << " ";
    }
    cout << endl;
}
void intersection(int arr1[], int size1, int arr2[], int size2){
    for(int i = 0; i < size1; i++){
        bool repeated = false;
        for(int j = 0; j < size1; j++){
            if(i != j && arr1[i] == arr1[j]){
               repeated = true;
               break;
            }
        }
        if(repeated) arr1[i] = INT_MAX;
        for(int j = 0; j < size2; j++){
            if(arr1[i] == arr2[j]){
               cout << arr1[i] << " ";
               break;
            }
        }

    }
    cout << endl;
}
int main(){
    int arr1[] = {1, 2, 4, 6, 4, 6, 2, 5, 9};
    int size1 = sizeof(arr1) / sizeof(int);
    int arr2[] = {2, 4, 3, 5, 8, 6, 3};
    int size2 = sizeof(arr2) / sizeof(int);
    cout << "Sum of elements : " << sum(arr1, size1) << endl;
    cout << "Product of elements : " << product(arr1, size1) << endl;
    cout << "The elements of the first array after the maximum element and minimum element are reversed : ";
    reverseMinAndMax(arr1, size1);
    cout << "The unique elements in the first array : ";
    uniqueElement(arr1, size1);
    cout << "The intersecting elements between the first and second array : ";
    intersection(arr1, size1, arr2, size2);
    return 0;
}
document.addEventListener("DOMContentLoaded", function () {
  gsap.registerPlugin(ScrollTrigger);

  const cards = document.querySelectorAll(".stacking-cards .card");
  const cardWidth = cards[0].offsetWidth;
  const gap = 20;
  const totalOffset = (cardWidth + gap) * (cards.length - 1);

  const scrollTrigger = ScrollTrigger.create({
    trigger: ".stacking-cards",
    pin: true,
    start: "top top",
    end: "+=" + totalOffset + "px",
    scrub: true,
    markers: true,
    onUpdate: (self) => {
      const progress = self.progress; // Global progress [0 - 1]

      cards.forEach((card, index) => {
        const cardStart = index / cards.length; // Start point for this card
        const cardEnd = (index + 1) / cards.length; // End point for this card
        const cardProgress = (progress - cardStart) / (cardEnd - cardStart); // Normalize progress for this card

        if (progress >= cardStart && progress < cardEnd) {
          // Active card during its scroll range
          gsap.to(card, {
            x: -(index * (cardWidth + gap)), // Move to active position
            duration: 0.3,
            ease: "power1.out",
          });
          card.classList.add("active");
          card.classList.remove("stacked");
          card.classList.remove("vertical-text");
        } else if (progress >= cardEnd) {
          // Cards before the active one
          gsap.set(card, {
            x: -(index * (cardWidth + gap)), // Stack position
          });
          card.classList.add("stacked");
          card.classList.remove("active");
        } else {
          // Cards after the active one
          gsap.set(card, {
            x: 0, // Keep in starting position until their turn
          });
          card.classList.remove("active", "stacked", "vertical-text");
        }
      });
    },
    onLeave: () => {
      // At the end of the scroll, remove the 'stacked' class from all cards
      cards.forEach((card) => {
        card.classList.remove("stacked");
      });
    },
  });
});
star

Mon Dec 09 2024 09:06:04 GMT+0000 (Coordinated Universal Time) https://lmarena.ai/

@admino

star

Mon Dec 09 2024 09:02:26 GMT+0000 (Coordinated Universal Time)

@iliavial

star

Mon Dec 09 2024 09:00:09 GMT+0000 (Coordinated Universal Time)

@iliavial

star

Mon Dec 09 2024 08:59:33 GMT+0000 (Coordinated Universal Time)

@iliavial

star

Mon Dec 09 2024 08:58:52 GMT+0000 (Coordinated Universal Time)

@iliavial

star

Mon Dec 09 2024 06:33:35 GMT+0000 (Coordinated Universal Time) https://www.addustechnologies.com/blog/triangular-arbitrage-bot-trading-opportunities

@Seraphina

star

Sun Dec 08 2024 18:45:42 GMT+0000 (Coordinated Universal Time) https://www.thiscodeworks.com/6755e6d45d41c300140a429c

@idans8

star

Sun Dec 08 2024 16:22:34 GMT+0000 (Coordinated Universal Time) https://styled-components.com/

@Abd_ElRahaman #tsx

star

Sun Dec 08 2024 14:58:14 GMT+0000 (Coordinated Universal Time)

@saharmess #mysql

star

Sun Dec 08 2024 11:13:01 GMT+0000 (Coordinated Universal Time)

@John_Almer

star

Sun Dec 08 2024 11:10:57 GMT+0000 (Coordinated Universal Time)

@John_Almer

star

Sun Dec 08 2024 10:33:11 GMT+0000 (Coordinated Universal Time)

@John_Almer

star

Sun Dec 08 2024 10:32:36 GMT+0000 (Coordinated Universal Time)

@John_Almer

star

Sat Dec 07 2024 21:20:19 GMT+0000 (Coordinated Universal Time) https://salesforcetime.com/2023/11/15/how-to-control-the-css-of-screen-flows/

@dannygelf #flow #salesforce #ui

star

Sat Dec 07 2024 19:46:13 GMT+0000 (Coordinated Universal Time)

@davidmchale

star

Sat Dec 07 2024 11:45:20 GMT+0000 (Coordinated Universal Time)

@khadizasultana #loop #c++ #vector

star

Sat Dec 07 2024 11:27:32 GMT+0000 (Coordinated Universal Time)

@hitsabhishek

star

Sat Dec 07 2024 11:01:50 GMT+0000 (Coordinated Universal Time)

@hitsabhishek

star

Sat Dec 07 2024 10:31:58 GMT+0000 (Coordinated Universal Time) https://developer.chrome.com/docs/extensions/reference/api/types#ChromeSetting

@Misotek25 #ts

star

Sat Dec 07 2024 10:16:46 GMT+0000 (Coordinated Universal Time) https://www.onlinegdb.com/online_c_compiler

@Narendra

star

Sat Dec 07 2024 10:15:42 GMT+0000 (Coordinated Universal Time) https://www.onlinegdb.com/online_c_compiler

@Narendra

star

Sat Dec 07 2024 08:58:43 GMT+0000 (Coordinated Universal Time) https://www.onlinegdb.com/online_c_compiler

@Narendra

star

Sat Dec 07 2024 07:00:07 GMT+0000 (Coordinated Universal Time) https://angelx-speedo.com/fast-liquidation-sell-usdt-to-inr-with-angelx-speedo/

@diagorass #angelxspeedo #sell #usdt #inr

star

Sat Dec 07 2024 06:53:28 GMT+0000 (Coordinated Universal Time) https://blockchainjunction.online

@diagorass #blockchain #blockchainjunction #web3 #india

star

Sat Dec 07 2024 06:49:54 GMT+0000 (Coordinated Universal Time) https://angelx-super.com/how-it-works/

@diagorass ##angelxsuper ##usdt #inr

star

Sat Dec 07 2024 02:39:57 GMT+0000 (Coordinated Universal Time)

@John_Almer

star

Fri Dec 06 2024 20:50:23 GMT+0000 (Coordinated Universal Time)

@okkpurple

star

Fri Dec 06 2024 18:01:21 GMT+0000 (Coordinated Universal Time)

@jrg_300i #undefined

star

Fri Dec 06 2024 17:58:02 GMT+0000 (Coordinated Universal Time)

@eho135

star

Fri Dec 06 2024 17:04:19 GMT+0000 (Coordinated Universal Time)

@RobertoSilvaZ #server #ollama #windows #llama

star

Fri Dec 06 2024 12:51:43 GMT+0000 (Coordinated Universal Time)

@Jacko

star

Fri Dec 06 2024 12:13:48 GMT+0000 (Coordinated Universal Time)

@khadizasultana #loop #array #c++

star

Fri Dec 06 2024 11:28:44 GMT+0000 (Coordinated Universal Time) https://appticz.com/cash-app-clone

@davidscott

star

Fri Dec 06 2024 10:02:09 GMT+0000 (Coordinated Universal Time) https://betprocoders.com/satta-matka-game-development

@betprocoders #sattamatkagame development #sattamatkaappdevelopment

star

Fri Dec 06 2024 09:07:10 GMT+0000 (Coordinated Universal Time)

@shri

star

Fri Dec 06 2024 08:02:53 GMT+0000 (Coordinated Universal Time) https://www.mageplaza.com/devdocs/custom-shipping-address-template-magento-2.html

@zaki

Save snippets that work with our extensions

Available in the Chrome Web Store Get Firefox Add-on Get VS Code extension