Setting up Machines with Conda Scripts

GitHub

  • What is GitHub?

Github is a place where people can record and share their code.

  • Why do we use GitHub? Why not Google Drive or messages? It implements Git and provides a good way to refer back to code history.

  • What's the difference between Git and GitHub?

Git is a way to store code while GitHub is the website for users to share their code.

  • Name as many Git commands as you can:

git clone, git pull

Two Main Machines

  • Which is better, MacOS or Windows?

Windows has better compatibility.

  • Give some differences between MacOS and Windows in terms of the development we use in APCSP: They use diffferent commands to set up.

  • If you are on Windows, you want to skip the MacOS Setup instructions.

Our Tools:

  • What is the first tool you remember installing?

    VSCode

  • Why was installations so hard the first time?

    We were unfamiliar with coding.

  • Without looking back at previous notes, name three tools you remember installing. This can be kernels, extensions, any installation for APCSP, and also write why it is needed.

  • VS Code, this provides the platform to code

  • Jupyter Notebook provides an easy way to include snippets of code on blog
  • Github to record versions of code
  • JavaScript kernel to code in JavaScript
  • Install Python3 to code in Python

Actual Installations:

Tool setup is a week 0 thing. You should already have the knowledge to set up your machine. There is also a high chance you had to remove your environments and set up your machine again due to errors. If, for some reason, these don't apply to you, go here to set up your machine, here to check everything working with Bash, and here for Docker setup, which are the main tools on our machine needed to develop in APCSP.

MacOS Conda Scripts

After installing Homebrew, VSCode, and Python2, you'll need to run these Homebrew commands:

brew list # list packages
brew update # update package list
brew upgrade # upgrade packages
brew install git  # install latest git
brew install python # install python3 for development
python --version # version of python3 installed
brew install java # openjdk install

Windows Conda Scripts

To get set up, run these commands:

wsl --install
wsl --list
wsl --install -d Ubuntu-20.04
# restart machine
wsl
cd ~
mkdir vscode
ls
cd ~/vscode  # changes the directory to path for vscode files
git clone https://github.com/nighthawkcoders/APCSP.git # clone repo
cd APCSP  # changes the directory to path for APCSP repos assets
code .  # opens APCSP in VSCode
cd ..    # changes the directory to the previous/parent directory
git config --global user.email mygmail@gmail.com  # tell git your email
git config --global user.name mygithub   # tell git your github id
shay@MSI:/mnt/c/Users/ShayM$ git config --global user.email your@email.here
shay@MSI:/mnt/c/Users/ShayM$ git config --global user.name yourusernamehere
# restart machine
PS C:\Users\UserName> wsl  # Windows prompt to WSL command
cd /tmp
wget https://repo.anaconda.com/archive/Anaconda3-2022.05-Linux-x86_64.sh
chmod +x Anaconda3-2022.05-Linux-x86_64.sh
# Answer yes to all the prompts
./Anaconda3-2022.05-Linux-x86_64.sh
# run apt package commands now
sudo apt list # list packages
sudo apt update # update package list
sudo apt upgrade # upgrade packages
sudo apt install python2 # install python2 for package dependencies
sudo apt install python3 python3-pip # install python3 and pip3 for development
python --version  # version of python3 should be shown
sudo apt install default-jdk default-jre  # java install
java --version  # java runtime version
javac --version # java compiler version
sudo apt install unzip  # unzip utility

Setting Up Kernels

Now that you have everything installed on MacOS/Windows, we need to get kernels installed so that we can develop inside Fastpages notebooks. To do that, run these commands on both MacOS and Windows:

(base) id:~$ conda --version 
(base) id:~$ conda install jupyter # install jupyter
(base) id:~$ jupyter kernelspec list # list installed kernels
Available kernels:
  python3    /home/shay/.local/share/jupyter/kernels/python3

(base) id:~$ # start in home directory
(base) id:~$ pip install bash_kernel # download bash kernel
Collecting bash_kernel
  Downloading bash_kernel-0.7.2-py2.py3-none-any.whl (15 kB)
Requirement already satisfied: pexpect>=4.0 in ./anaconda3/lib/python3.9/site-packages (from bash_kernel) (4.8.0)
Requirement already satisfied: ptyprocess>=0.5 in ./anaconda3/lib/python3.9/site-packages (from pexpect>=4.0->bash_kernel) (0.7.0)
Installing collected packages: bash-kernel
Successfully installed bash-kernel-0.7.2
(base) id:~$ python -m bash_kernel.install # install kernel
Installing IPython kernel spec
(base) id:~$ jupyter kernelspec list # list kernels
Available kernels:
  bash       /home/shay/.local/share/jupyter/kernels/bash
  python3    /home/shay/.local/share/jupyter/kernels/python3

(base) id:~$ conda install nodejs # node is framework for JavaScript kernel
(base) id:~$ npm -version  # node package manager comes with nodejs
(base) id:~$ npm install -g ijavascript  # get the kernel
(base) id:~$ ijsinstall # install javascript kernel
(base) id:~$ jupyter kernelspec list # list kernels
Available kernels:
  bash          /home/shay/.local/share/jupyter/kernels/bash
  javascript    /home/shay/.local/share/jupyter/kernels/javascript
  python3       /home/shay/.local/share/jupyter/kernels/python3

By now, you should already know how to clone Git repositories into your VSCode directory. Once you do that, you're all set for developing with GitHub Pages and Fastpages!

Before We Set Up Pages, A Guide to Git

As we've discussed, Git is different from GitHub. Because GitHub is merely the place where we store Git repos, we use Git's commands to help us get, open, and configure these repositories. Here are some of the Git commands you should be using a lot (In the comments, tell what each Git command does):

git clone {repos-name-here.git} # what does it do? Clone a repo
git checkout [branch] # what does it do? Switch between branches
git fork {repos-name-here.git} # what does it do? Create a fork
git commit -m {"commit-msg"} # what does it do? Commit with a message
git pull # what does it do? Pull the updated changes from the repo
git push # what does it do? Push changes to GitHub

# After this line, name other commands that you can use and what they do. This should be easy, as you've already answered the qeue
git fetch # retrieve from repo

Setting Up GitHub Pages

Some of you may have come to know that GitHub Pages is starting to become outdated. So why do we still use it? The answer is that we are in a class, and following a curriculum with something like GitHub Pages is much easier than creating portfolio content from scratch, which becomes quite unecessary. Therefore, we can use GitHub Pages to create this content instead. On the topic of unecessary vs necessary coding, we don't need to make GitHub Pages from scratch as opposed to using a template that our very own Mr. Mortensen created for us. To do that, we can go to the Leuck Reunion repository and use the template to make our own GitHub Pages. Then, in Ubuntu, we can git clone our repository and open it in VSCode. After we have it open, the last thing we want to do is set up local hosting for this website, so that we can preview it and make changes in real time. To do that, head here to install Jekyll for Ubuntu, here to install Ruby next, and here to finalize the process by installing Bundler.

Setting Up FastPages

In Setting Up Github Pages, we talked about how it is easier to use a template to create portfolio content. It is also easier to use a template when creating the portfolio itself. To do that, we can use Fastpages, which is what we have been using to show our blogs, code, and projects. However, Fastpages has been deprecated for some time now, so the instructions in Week 0 won't be effective. So, we need to fork the APCSP Fastpages. To do that, follow this video to get started developing with Fastpages.

Hacks

  • Show how you incorporate three tools that we have installed into your project. 0.1 points for each feature. (0.3). This can include code, but definitely blog about it.

  • Python was used to code the backend for the project. I used Python to create the API endpoint on the backend, and also to connect to the SQLite database.

  • JavaScript was used to code the frontend. I used JavaScript to send a fetch request to the backend so that data could be fetched and displayed on the website.

  • To code for frontend and backend, I used VS Code as my code editor. I also used Git to push and pull code onto the GitHub repositories.

  • frontend hack goes here


Below is a portion of my frontend code that demonstrates fetching with JavaScript. This code sends a fetch request to the backend website's API endpoint. The backend returns data from the database, and using JavaScript, I created a table that outputs the data onto the frontend website.

fetch("https://seal.nighthawkcodingsociety.com/api/users/classreview")
          .then(response => {
            response.json().then(data => {
                console.log(data);

                for (const row of data) {
                    if (classInput.toUpperCase() == row.className.toUpperCase()) {
                      const tr = document.createElement("tr");
                      
                      const className = document.createElement("td");
                      className.innerHTML = row.className;  
          
                      const daysBtwTest= document.createElement("td");
                      daysBtwTest.innerHTML = row.daysBtwTest; 
          
                      const difficulty= document.createElement("td");
                      difficulty.innerHTML = row.difficulty; 

                      const hoursOfHw= document.createElement("td");
                      hoursOfHw.innerHTML = row.hoursOfHw; 

                      const memorizationLevel = document.createElement("td");
                      memorizationLevel.innerHTML = row.memorizationLevel; 

                      const comments = document.createElement("td");
                      comments.innerHTML = row.comments; 
                      
                      tr.appendChild(className);
                      tr.appendChild(daysBtwTest);
                      tr.appendChild(difficulty);
                      tr.appendChild(hoursOfHw);
                      tr.appendChild(memorizationLevel);
                      tr.appendChild(comments);
          
                      document.getElementById("reviews").appendChild(tr);
                    }


                    }
                   
                
            })
            }
        )
  • backend hack goes here

To create the API endpoint on the backend, I used api.add_resource() to create a link to the endpoint. I also created classes for Create, Read, Update, and Delete options that take in input from a GET/POST request and returns the data in JSON.

The code below shows a class that I created to Create a class review (the topic of my project is to read, submit, edit, and delete class reviews).

class _CreateClassReview(Resource):
        def post(self):
            ''' Read data for json body '''
            body = request.get_json()
            

            username = body.get('username')
            className = body.get('className')
            difficulty = body.get('difficulty')
            hoursOfHw = body.get('hoursOfHw')
            daysBtwTest = body.get('daysBtwTest')
            memorizationLevel = body.get('memorizationLevel')
            comments = body.get('comments')
            
            if int(difficulty) < 0:
                return {'message': f'Invalid number'}, 210
            if int(hoursOfHw) < 0:
                return {'message': f'Invalid number'}, 210
            if int(daysBtwTest) < 0:
                return {'message': f'Invalid number'}, 210
            if int(memorizationLevel) < 0:
                return {'message': f'Invalid number'}, 210
            
            id = findId(username)
            
            #create a review object based on user's input
            review = ClassReview(id=id, className=className, difficulty=difficulty, hoursOfHw=hoursOfHw, daysBtwTest=daysBtwTest, memorizationLevel=memorizationLevel, comments=comments)

           
            
            #I HAVE TO CHANGE THIS VARIABLE NAME LOL
            reviews = review.create()
            if reviews:
                return jsonify(reviews.read())
            # failure returns error
            return {'message': f'Processed {username}, either a format error or duplicate'}, 210

To connect the Python code to the SQLite database, I created a ClassReview class that takes in attributes of a class review, such as the name of the class, its difficulty ranking, number of days between tests, and extra comments. This is what the code for the class looks like:

class ClassReview(db.Model):
    __tablename__ = 'classReview'
    # Define the Classes schema
    id = db.Column(db.Integer, primary_key=True)
    # Define a relationship in classes Schema to userID who originates the classes, many-to-one (many classes to one user)
    userID = db.Column(db.Integer, db.ForeignKey('users.id'))

    #columns (class review inputs)
    className = db.Column(db.String(255), unique=False, nullable=False)
    difficulty = db.Column(db.String(255), unique=False, nullable=False)
    hoursOfHw = db.Column(db.String(255), unique=False, nullable=False)
    daysBtwTest = db.Column(db.String(255), unique=False, nullable=False)
    memorizationLevel = db.Column(db.String(255), unique=False, nullable=False)
    comments = db.Column(db.String(255), unique=False, nullable=False)

    # Constructor of a Notes object, initializes of instance variables within object
    def __init__(self, id, className, difficulty, hoursOfHw, daysBtwTest, memorizationLevel, comments):
        self.userID = id
        self.className = className
        self.difficulty = difficulty
        self.hoursOfHw = hoursOfHw
        self.daysBtwTest = daysBtwTest
        self.memorizationLevel = memorizationLevel
        self.comments = comments
        


    # Returns a string representation of the Notes object, similar to java toString()
    # returns string
    def __repr__(self):
        return "ClassReview(" + str(self.userID) + "," + self.className+ "," + self.difficulty + "," + self.hoursOfHw + "," + self.daysBtwTest + "," + self.memorizationLevel  + "," + self.comments + ")"

    # CRUD create, adds a new record to the Notes table
    # returns the object added or None in case of an error
    def create(self):
        try:
            # creates a Notes object from Notes(db.Model) class, passes initializers
            db.session.add(self)  # add prepares to persist person object to Notes table
            db.session.commit()  # SqlAlchemy "unit of work pattern" requires a manual commit
            return self
        except IntegrityError:
            db.session.remove()
            return None

    # CRUD read, returns dictionary representation of Notes object
    # returns dictionary
    def read(self):
        
        return {
            "userID": self.userID,
            "className": self.className,
            "difficulty": self.difficulty,
            "hoursOfHw": self.hoursOfHw,
            "daysBtwTest": self.daysBtwTest,
            "memorizationLevel": self.memorizationLevel,
            "comments": self.comments,
        }

    def update(self, className, difficulty, hoursOfHw, daysBtwTest, memorizationLevel, comments):
        #only updates values greater than 0
        if int(difficulty) >= 0 :
            self.difficulty = difficulty
        if int(hoursOfHw) >= 0 :
            self.hoursOfHw = hoursOfHw
        if int(daysBtwTest) >= 0 :
            self.daysBtwTest = daysBtwTest
        if int(memorizationLevel) >= 0 :
            self.memorizationLevel = memorizationLevel
        self.className = className
        self.comments = comments
        db.session.commit()
        return self 

    def delete(self):
        #print(ClassReview.query.filter_by(userID=id, className=className).first())
        db.session.delete(self)
        db.session.commit()
        return None