From ff885ef3bebaeb82a5b0bbc48a3ff3c828858e32 Mon Sep 17 00:00:00 2001 From: Rinat Shagisultanov Date: Wed, 6 Apr 2022 08:55:33 -0600 Subject: [PATCH] Initial commit Update README.md Update README.md Update README.md Update README.md Create git-tips.md Update git-tips.md Update README.md Update 0-start.yml Update STEP Create check-file.sh Create create-workflow-pr.sh Create initialize-repository.sh Update 0-start.yml Update 0-start.yml Create index.html added docs files Update and rename 1-tbd.yml to 1-resolve-duplicate-issues.yml Update 1-resolve-duplicate-issues.yml Update 1-resolve-duplicate-issues.yml Update 1-resolve-duplicate-issues.yml Update 1-resolve-duplicate-issues.yml Update 1-resolve-duplicate-issues.yml Update 1-resolve-duplicate-issues.yml Update 1-resolve-duplicate-issues.yml Update 1-resolve-duplicate-issues.yml Update STEP Update 1-resolve-duplicate-issues.yml Update 1-resolve-duplicate-issues.yml Update 1-resolve-duplicate-issues.yml Update 1-resolve-duplicate-issues.yml Update 1-resolve-duplicate-issues.yml Update 1-resolve-duplicate-issues.yml Update 1-resolve-duplicate-issues.yml Update 1-resolve-duplicate-issues.yml Update 1-resolve-duplicate-issues.yml Update 1-resolve-duplicate-issues.yml Update 1-resolve-duplicate-issues.yml Update STEP Update 1-resolve-duplicate-issues.yml Update STEP Update to 2 in STEP and README.md Update README.md Update _sidebar.md Update _sidebar.md Update and rename 2-tbd.yml to 2-find-commit-in-history.yml Update 2-find-commit-in-history.yml Update 2-find-commit-in-history.yml Update 2-find-commit-in-history.yml Update 2-find-commit-in-history.yml Update 2-find-commit-in-history.yml Update 2-find-commit-in-history.yml Update 2-find-commit-in-history.yml Update 2-find-commit-in-history.yml Update to 3 in STEP and README.md Update 1-resolve-duplicate-issues.yml add sidebar to documentation add sidebar to documentation Update 2-find-commit-in-history.yml Update README.md Update and rename 3-tbd.yml to 3-fix-broken-sidebar.yml Delete 4-tbd.yml Delete 5-merge-your-pull-request.yml Fixing sidebar Fixing #2 Update 3-fix-broken-sidebar.yml Fixing sidebar Fixing #2 Fixing sidebar Fixing #2 Update 3-fix-broken-sidebar.yml Update to 4 in STEP and README.md Update README.md Update STEP Update to 4 in STEP and README.md Update 0-start.yml Update _sidebar.md Update README.md Update STEP git commit --amend# --- .github/script/STEP | 1 + .github/script/check-file.sh | 42 ++ .github/script/create-workflow-pr.sh | 20 + .github/script/initialize-repository.sh | 45 ++ .github/script/update-step.sh | 42 ++ .github/workflows/0-start.yml | 72 ++++ .../workflows/1-resolve-duplicate-issues.yml | 76 ++++ .../workflows/2-find-commit-in-history.yml | 78 ++++ .github/workflows/3-fix-broken-sidebar.yml | 78 ++++ .gitignore | 37 ++ LICENSE | 395 ++++++++++++++++++ README.md | 211 ++++++++++ docs/.nojekyll | 0 docs/README.md | 0 docs/_sidebar.md | 5 + docs/doc-references.md | 3 + docs/git-tips.md | 195 +++++++++ docs/index.html | 20 + docs/learning-resources.md | 3 + docs/past-work.md | 3 + 20 files changed, 1326 insertions(+) create mode 100644 .github/script/STEP create mode 100644 .github/script/check-file.sh create mode 100644 .github/script/create-workflow-pr.sh create mode 100644 .github/script/initialize-repository.sh create mode 100755 .github/script/update-step.sh create mode 100644 .github/workflows/0-start.yml create mode 100644 .github/workflows/1-resolve-duplicate-issues.yml create mode 100644 .github/workflows/2-find-commit-in-history.yml create mode 100644 .github/workflows/3-fix-broken-sidebar.yml create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 docs/.nojekyll create mode 100644 docs/README.md create mode 100644 docs/_sidebar.md create mode 100644 docs/doc-references.md create mode 100644 docs/git-tips.md create mode 100644 docs/index.html create mode 100644 docs/learning-resources.md create mode 100644 docs/past-work.md diff --git a/.github/script/STEP b/.github/script/STEP new file mode 100644 index 0000000..573541a --- /dev/null +++ b/.github/script/STEP @@ -0,0 +1 @@ +0 diff --git a/.github/script/check-file.sh b/.github/script/check-file.sh new file mode 100644 index 0000000..85236a5 --- /dev/null +++ b/.github/script/check-file.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# Make sure this file is executable +# chmod a+x .github/script/check-file.sh + +# Make sure to escape your backslashes => \\ <= in YAML +# So that its still a single \ in bash + +# Check if pattern match found in file +grep_pattern() { + echo + echo "Check that $1 includes $2" + if grep --extended-regexp "$2" -- $1 + then + echo "Found $2 in $1" + else + echo "Missing $2 in $1" + echo "----------------" + echo "$(cat $1)" + exit 204 # We're sending a weird code so it looks different from other "failures" + fi +} + +# Run grep check for each term in list +search_list() { + for pattern in "$@" + do + grep_pattern $FILE $pattern + done +} + +# Handle single search term +if [ -n "${SEARCH+set}" ] && [ -n "${FILE+set}" ]; then + grep_pattern $FILE $SEARCH + +# Handle multiple search terms, space delimited +elif [ -n "${SEARCH_LIST+set}" ] && [ -n "${FILE+set}" ]; then + search_list $SEARCH_LIST + +# Missing FILE or search term(s) +else + echo "FILE and (SEARCH | SEARCH_LIST) required" +fi diff --git a/.github/script/create-workflow-pr.sh b/.github/script/create-workflow-pr.sh new file mode 100644 index 0000000..c720214 --- /dev/null +++ b/.github/script/create-workflow-pr.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# Make sure this file is executable +# chmod a+x .github/script/create-workflow-pr.sh + +git config user.name github-actions +git config user.email github-actions@github.com + +# If --pull-first is set, pull latest from main +# before creating pull request +if [ "$1" = "--pull-first" ] +then + echo "Merging main into $PR_BRANCH" + git checkout $PR_BRANCH + git pull origin main --no-rebase -X theirs --no-edit + git push origin $PR_BRANCH +fi + +echo "Create pull request for $PR_BRANCH into main" +gh pr create --base main --head $PR_BRANCH --title "$PR_TITLE" --body "" +b diff --git a/.github/script/initialize-repository.sh b/.github/script/initialize-repository.sh new file mode 100644 index 0000000..846b4df --- /dev/null +++ b/.github/script/initialize-repository.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# Make sure this file is executable +# chmod a+x .github/script/initialize-repository.sh + +# USAGE: This should only be run once upon initial creation of the +# learner's repository from the template repository. +# Does a dry run by default, --dry-run=false to run live. + +# PURPOSE: This script establishes an initial related history for +# all branches. It merges main into all other branches in this repository +# while auto-resolving conflicts in favor of main. + +# BACKGROUND: This operation is required because when a repository is +# created from a template repository with 'Include all branches', each +# of the branches starts with only one initial commit and no related history. +# +# That state makes it impossible to create pull requests from the +# step-specific branches into main as the learner progresses +# through the course. + +# Setup committer identity +git config user.name github-actions +git config user.email github-actions@github.com + +# Fetch all remote branches +git pull --all + +# Create list of all remote branches +branches=$(git branch -r | grep -v main | sed -r 's/origin\///g' | paste -s -d ' ' -) + +# Merge main into each branch +echo -e "Merge main into each branch\n---" +for branch in $branches +do + # Dry run by default + if [[ $1 = '--dry-run=false' ]] + then + git checkout "$branch" + git pull origin main --no-rebase -X theirs --allow-unrelated-histories --no-edit + git push origin "$branch" + echo "---" + else + echo "plan: merge main into $branch" + fi +done diff --git a/.github/script/update-step.sh b/.github/script/update-step.sh new file mode 100755 index 0000000..db99b88 --- /dev/null +++ b/.github/script/update-step.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# Make sure this file is executable +# chmod a+x .github/script/update-step.sh + +echo "Check that we are on FROM_STEP" +if [ "$(cat .github/script/STEP)" != $FROM_STEP ] +then + echo "Current step is not $FROM_STEP" + exit 0 +fi + +echo "Make sure we are on the main branch" +git checkout main + +echo "Remove 'open' from any
tags" +sed -r 's/
/
/g' README.md > tmp +mv tmp README.md + +echo "Add 'open' to step TO_STEP" +sed -r "s/
/
/g" README.md > tmp +mv tmp README.md + +echo "Update the STEP file to TO_STEP" +echo "$TO_STEP" > .github/script/STEP + +echo "Commit the files, and push to main" +git config user.name github-actions +git config user.email github-actions@github.com +git add README.md +git add .github/script/STEP +git commit --message="Update to $TO_STEP in STEP and README.md" +git push + +echo "If BRANCH_NAME, update that branch as well" +if git show-ref --quiet refs/heads/$BRANCH_NAME +then + git checkout $BRANCH_NAME + git cherry-pick main + git push +else + echo "Branch $BRANCH_NAME does not exist" +fi diff --git a/.github/workflows/0-start.yml b/.github/workflows/0-start.yml new file mode 100644 index 0000000..ed435cb --- /dev/null +++ b/.github/workflows/0-start.yml @@ -0,0 +1,72 @@ +name: Step 0, Start + +# This step triggers after the learner creates a new repository from the template +# This step sets STEP to 1 +# This step closes
and opens
+ +# When creating a repository from a template, there is variability in the +# order and timing of events that fire and when workflow triggers are registered. +# Given that, these triggers are purposely broad to ensure this workflow is always triggered. +# The conditions within the on_start job are to ensure it is only fully executed once. +# Reference https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows +on: + create: + workflow_dispatch: + +permissions: + # Need `contents: read` to checkout the repository + # Need `contents: write` to update the step metadata + contents: write + +jobs: + get_current_step: + name: Check current step number + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - id: get_step + run: echo "::set-output name=current_step::$(cat ./.github/script/STEP)" + outputs: + current_step: ${{ steps.get_step.outputs.current_step }} + + on_start: + name: On start + needs: get_current_step + + # We will only run this action when: + # 1. This repository isn't the template repository + # 2. The STEP is currently '0' (see update-step.sh) + # 3. This is the first workflow run on the repository + # Reference https://docs.github.com/en/actions/learn-github-actions/contexts + # Reference https://docs.github.com/en/actions/learn-github-actions/expressions + if: ${{ github.repository_owner != 'InfomagnusOrg' + && needs.get_current_step.outputs.current_step == 0 + && github.run_number == 1 }} + + # We'll run Ubuntu for performance instead of Mac or Windows + runs-on: ubuntu-latest + + steps: + # We'll need to check out the repository so that we can edit the README + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 # Let's get all the branches + + # Update README to close
+ # and open
+ # and set STEP to '1' + - name: Update to step 1 + run: ./.github/script/update-step.sh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + FROM_STEP: 0 + TO_STEP: 1 + + # This is required to establish a related history for branches + # after being created from the template repository + - name: Initialize repository + run: ./.github/script/initialize-repository.sh --dry-run=false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/1-resolve-duplicate-issues.yml b/.github/workflows/1-resolve-duplicate-issues.yml new file mode 100644 index 0000000..359d925 --- /dev/null +++ b/.github/workflows/1-resolve-duplicate-issues.yml @@ -0,0 +1,76 @@ +name: Step 1, Resolve duplicate issues + +# This step triggers after 0-start.yml +# This step sets STEP to 2 +# This step closes
and opens
+ +# This will run every time we update or close the issue +# Reference https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows + +on: + workflow_dispatch: + issue_comment: + types: [created, edited] + +permissions: + # Need `contents: read` to checkout the repository + # Need `contents: write` to update the step metadata + contents: write + +jobs: + + get_current_step: + name: Check current step number + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - id: get_step + run: echo "::set-output name=current_step::$(cat ./.github/script/STEP)" + outputs: + current_step: ${{ steps.get_step.outputs.current_step }} + + on_duplicate_issue_closed: + name: Check if duplicate issue is marked as duplicate + needs: get_current_step + + # We will only run this action when: + # 1. This repository isn't the template repository + # 2. The STEP is currently 1 (see update-step.sh) + # Reference https://docs.github.com/en/actions/learn-github-actions/contexts + # Reference https://docs.github.com/en/actions/learn-github-actions/expressions + if: ${{ github.repository_owner != 'TBD-organization' }} + && needs.get_current_step.outputs.current_step == 1 }} + + # We'll run Ubuntu for performance instead of Mac or Windows + runs-on: ubuntu-latest + + steps: + # We'll need to check out the repository so that we can edit the README + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 # Let's get all the branches + + - name: Dump GitHub comment context + id: github_comment_step + run: echo '${{ toJSON(github.event.comment) }}' + + - name: Dump GitHub issue context + id: github_issue_step + run: echo '${{ toJSON(github.event.issue) }}' + + - name: Check if commented issue is closed and marked as duplicate + if: ${{ contains(github.event.comment.body, 'Duplicate of') && (github.event.issue.state == 'closed')}} + run: echo 'Duplicate issue closed' + + # Update README to close
+ # and open
+ # and set STEP to '2' + - name: Update to step 2 + run: ./.github/script/update-step.sh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + FROM_STEP: 1 + TO_STEP: 2 + BRANCH_NAME: main diff --git a/.github/workflows/2-find-commit-in-history.yml b/.github/workflows/2-find-commit-in-history.yml new file mode 100644 index 0000000..e58e989 --- /dev/null +++ b/.github/workflows/2-find-commit-in-history.yml @@ -0,0 +1,78 @@ +name: Step 2, Find a commit in history + +# This step triggers after TBD-step-2-event-desc +# This step sets STEP to 3 +# This step closes
and opens
+ +# This will run every time we TBD-step-2-event-desc +# Reference https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows +on: + workflow_dispatch: + issue_comment: + types: [created, edited] + +permissions: + # Need `contents: read` to checkout the repository + # Need `contents: write` to update the step metadata + contents: write + +env: + FIND_COMMIT_ID: f3dcc803ace969b145b318bfbf6a9f3071b322f7 + +jobs: + + get_current_step: + name: Check current step number + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - id: get_step + run: echo "::set-output name=current_step::$(cat ./.github/script/STEP)" + outputs: + current_step: ${{ steps.get_step.outputs.current_step }} + + on_fix_the_sidebar_issue_comment: + name: Check if the issue comment is referencing the correct commit ID + needs: get_current_step + + # We will only run this action when: + # 1. This repository isn't the template repository + # 2. The STEP is currently 2 (see update-step.sh) + # Reference https://docs.github.com/en/actions/learn-github-actions/contexts + # Reference https://docs.github.com/en/actions/learn-github-actions/expressions + if: ${{ github.repository_owner != 'TBD-organization' }} + && needs.get_current_step.outputs.current_step == 2 }} + + # We'll run Ubuntu for performance instead of Mac or Windows + runs-on: ubuntu-latest + + steps: + # We'll need to check out the repository so that we can edit the README + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 # Let's get all the branches + + - name: Dump GitHub comment context + id: github_comment_step + run: echo '${{ toJSON(github.event.comment) }}' + + - name: Dump GitHub issue context + id: github_issue_step + run: echo '${{ toJSON(github.event.issue) }}' + + - name: Check if the isuees comments is referencing the required commit ID + if: contains(github.event.comment.body, env.FIND_COMMIT_ID) + run: echo 'Found the reference to required commit in the comment' + + # Update README to close
+ # and open
+ # and set STEP to '3' + - name: Update to step 3 + run: ./.github/script/update-step.sh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + FROM_STEP: 2 + TO_STEP: 3 + BRANCH_NAME: main diff --git a/.github/workflows/3-fix-broken-sidebar.yml b/.github/workflows/3-fix-broken-sidebar.yml new file mode 100644 index 0000000..b82c06f --- /dev/null +++ b/.github/workflows/3-fix-broken-sidebar.yml @@ -0,0 +1,78 @@ +name: Step 3, Fix a broken sidebar + +# This step triggers after TBD-step-3-event-desc +# This step sets STEP to 4 +# This step closes
and opens
+ +# This will run every time we TBD-step-3-event-desc +# Reference https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows +on: + workflow_dispatch: + push: + branches: [main] + +permissions: + # Need `contents: read` to checkout the repository + # Need `contents: write` to update the step metadata + contents: write + +env: + FIND_FIXING_MESSAGE: Fixing + +jobs: + + get_current_step: + name: Check current step number + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - id: get_step + run: echo "::set-output name=current_step::$(cat ./.github/script/STEP)" + outputs: + current_step: ${{ steps.get_step.outputs.current_step }} + + on_fix_the_sidebar_issue_comment: + name: Check if the issue comment is referencing the correct commit ID + needs: get_current_step + + # We will only run this action when: + # 1. This repository isn't the template repository + # 2. The STEP is currently 2 (see update-step.sh) + # Reference https://docs.github.com/en/actions/learn-github-actions/contexts + # Reference https://docs.github.com/en/actions/learn-github-actions/expressions + if: ${{ github.repository_owner != 'TBD-organization' }} + && needs.get_current_step.outputs.current_step == 3 }} + + # We'll run Ubuntu for performance instead of Mac or Windows + runs-on: ubuntu-latest + + steps: + # We'll need to check out the repository so that we can edit the README + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 # Let's get all the branches + + - name: Dump GitHub comment context + id: github_comment_step + run: echo '${{ toJSON(github.event) }}' + + - name: Dump GitHub issue context + id: github_issue_step + run: echo '${{ toJSON(github.event) }}' + + - name: Check if the isuees comments is referencing the required commit ID + if: contains(github.event.head_commit.message, env.FIND_FIXING_MESSAGE) + run: echo 'Found _fixing_ message with autolinked issue in the push' + + # Update README to close
+ # and open
+ # and set STEP to '4' + - name: Update to step 4 + run: ./.github/script/update-step.sh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + FROM_STEP: 3 + TO_STEP: 4 + BRANCH_NAME: main diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..773bfd6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# Compiled source # +################### +*.com +*.class +*.dll +*.exe +*.o +*.so + +# Packages # +############ +# it's better to unpack these files and commit the raw source +# git has its own built in compression methods +*.7z +*.dmg +*.gz +*.iso +*.jar +*.rar +*.tar +*.zip + +# Logs and databases # +###################### +*.log +*.sql +*.sqlite + +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4ea99c2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,395 @@ +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6aaf3f8 --- /dev/null +++ b/README.md @@ -0,0 +1,211 @@ + + + + +# Connect the Dots in a GitHub Repository + +_This course will teach you skills for finding relevant conversations, commits, and projects in a repository._ + + + +
+:golf: Start + +**To start this course: [Use this template](https://github.com/InfomagnusOrg/github-connecting-dots/generate)** + +> We recommend creating a public repository, as private repositories will [use Actions minutes](https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions).
+> After you make your own repository, wait about 20 seconds and refresh. I will go to the next step. + +Have you ever worked in a repository with a lot of history? Perhaps you've had to track down related issues and pull requests in the past, or you've had to find who committed a particular change. If you've ever found yourself in any of these situations, you'll know how important it is to navigate your workspace. + +- **Who is this for**: Developers, GitHub users, users new to Git, students, managers, teams. +- **What you'll learn**: + - Find relevant issues and pull requests + - Search history to find context + - Make connections within GitHub to help others find things +- **What you'll build**: Reposity with existing commits, duplicated isssus and content defect to be fixed. +- **Prerequisites**: Before you take this course, you may want to go through the [Introduction to GitHub](https://lab.github.com/githubtraining/introduction-to-github) course on Learning Lab. +- **How long**: This course is three steps long and takes less than 15 min to complete. +- **Projects Used**: [docsify](https://docsify.js.org/#/), a magical documentation site generator + +
+ + +Welcome to this Learning Lab course about finding your way through the history of GitHub repositories. For example, you could be working in repositories with a lot of history, many collaborators, or many files. + +Before you take this course, you may want to go through the [Introduction to GitHub]({{ host }}/{{ course.Owner.login }}/introduction-to-github) course on Learning Lab. + +In this course, you'll learn how to do lots of things, like: + +- Find relevant issues and pull requests +- Search history to find context +- Make connections within GitHub to help others find things + +### Cross-linking issues and pull requests + +GitHub has special capabilities to help reference other information on GitHub. For example, when you reference another issue or pull request by number, that number will be hyperlinked. At the same time, a cross-reference is created in the linked issue or pull request. This two-way reference helps people track the relationship of information across GitHub. + +![a screenshot of an issue linking to a PR, and a PR with a cross-reference to the issue](https://user-images.githubusercontent.com/16547949/67594663-d9710900-f732-11e9-8df8-d3173d952bd5.png) + +
+:zap: Step 1: Resolve Duplicate Issues + +### Welcome to "Connect the dots in a GitHub repository"! :wave: + +Below, you will see a reference to another issue. The other issue references _this_ issue. The other issue appears to be a duplicate, so it would be a good idea to close it. + +### Creating references + +When you link to another issue, a reference within GitHub is automatically created. In fact, you don't even need to include the full link. If you were to type `#5` within a comment, that would turn into a link to issue or pull request number 5. + +When you want to create a crosslink, try typing the title of an issue or pull request directly after you type the `#` symbol. GitHub will suggest issues or pull requests that will link to the right place. To learn even more, check out the [Autolinked References and URLs](https://help.github.com/en/articles/autolinked-references-and-urls) article. + +### :keyboard: Activity: Find and close the cross-linked issue + +1. Navigate to the other issue referenced from this issue +2. Close that issue + +
+ + + +
+:dart: Step 2: Find a commit in history + +### You did Resolve Duplicate Issues! :tada: + +An important part of version control is the ability to look into the past. By using `git blame`, and finding the story behind a commit, we're able to do more than _blame_ people for code. We're able to see the story around why a commit was made - what is the associated pull request? Who approved the pull request? What tests were run on that commit before it was merged? + +The obvious reason to find things in history is to know about history. With issues and pull requests, we see a more complete story about history - not just the bare minimum. + +### What's `git blame`? + +`git blame` is a Git functionality that shows what revision and author last modified each line of a file. Information like who made a commit, when, and even why can be found this way. If you aren't sure who introduced certain changes to a file, you can use `git blame` to find out. While `git blame` sounds rather accusatory, this can be used to understand the context around decisions. + +### What's a SHA? + +A SHA is a reference to a specific object. In this case, it's a reference to a commit. On GitHub, you can look at a specific commit to see the changes introduced, by whom, and if they were a part of a pull request. + +### :keyboard: Activity: Find commit in history + +1. Navigate to the Code tab of this repository + - _Tip: start this process in a new tab, since you will need it later_ +2. Click `docs` to navigate into the `/docs` directory +3. Click `_sidebar.md` to view the file +4. On the top right side of the file, click **Blame** to see the details of the most recent revision +5. Click the commit message, `add sidebar to documentation` to see the commit details +6. Copy some part of the SHA (at least the first 6 characters of the 40 character hexadecimal string listed after `commit`) +7. Comment (at least the first 6 characters of) the SHA in **this issue** + +
+ + + +
+:wrench: Step 3: Fix a broken sidebar + +### Nice work finishing Find a commit in history :sparkles: + +Thanks for finding that commit! We now know that the sidebar was indeed added, and it was done in that commit. Let's see if we can dig a little deeper to find out if any planning or conversation occurred around this change. + +# Context + +As we've already seen, conversations in issues and pull requests can reference other work. + +But the amount of context goes much further than crosslinks - Remember, Git is version control! For example, the commit that you found in the last step is connected with much more information: + +- Who made the commit +- What other changes were included +- When the commit was made +- Which pull request the commit was a part of + +The pull request is important because it goes beyond knowing when a commit happened - you can know _why_ a commit happened. Finding history is not about _blaming_ anyone, but about seeing the bigger picture. Why were decisions made? Who was involved? What were the build outputs and test results for each commit? Who requested changes, and who approved them? + +### A story about finding experts + +Imagine you find an internal white-paper on a really exciting topic. You're looking for experts to help you research this topic for an upcoming project. When you find this article, you're ecstatic! But, there's no author referenced in the plain text. + +You can see that it's written in markdown, and it's versioned in GitHub. It's already a part of the `main` branch, but you want to know who was involved in creating this. You use `git blame` to see the author(s), and you can find the pull request associated with that branch. Now, you can see who all of the authors were, who the reviewers were, and if there are any other issues or conversations related to this topic. + +Just like that, you've found the people at your company who can help move your project forward. :tada: + +### Finding a pull request from a commit + +When you're looking at a commit on GitHub, you can see a lot of information. From this view, you can also find a link to the pull request in which the commit was created. We'll use this in the next step. + +![screenshot of a view of a commit on GitHub, highlighting the link to the pull request](https://user-images.githubusercontent.com/16547949/67341250-3edbb480-f4fd-11e9-805a-6bce5a8ba2d1.png) + +### :keyboard: Activity: Fix a broken sidebar + +1. In the main branch [Edit the `docs/_sidebar.md` file](/edit/docs/_sidebar.md) +2. Correct the spelling of the reference `(doc-references__.md)` on line 4 by changing it into `(doc-references.md)` +3. Commit the changes on the `fix-sidebar` branch +4. In the [Pull requests tab](/pulls), create a pull request by comparing 'main' branch to 'fix-sidebar' bramch +5. Using the **Assignees** section on the right side, assign yourself to the pull request +6. In the PR comment add 'Closing #2' and autolink issue #2 +6. Merge this pull request +7. Delete the branch 'fix-sidebar' + +
+ + + +
+:checkered_flag: Finish + +### Congratulations friend, you've completed this course! :tada: + +In this course, you've learned a lot about finding and sharing information. Within a GitHub repository, you can find history about what changes were made, and more importantly, _why_ changes were made. + +### What's next? + +- We'd love to hear what you thought of this course [in our community forum](https://github.community/c/education/github-learning-lab/34). +- [Take another GitHub Learn course](https://github.com/githublearn). +- [Read the GitHub Getting Started docs](https://docs.github.com/en/get-started). +- To find projects to contribute to, check out [GitHub Explore](https://github.com/explore). + +
+ + + +--- + +Get help: [Post in our community forum](https://github.community/c/education/github-learning-lab/34) • [Review the GitHub status page](https://www.githubstatus.com/) + +© 2022 GitHub • [Code of Conduct](https://www.contributor-covenant.org/version/2/1/code_of_conduct/code_of_conduct.md) • [CC-BY-4.0 License](https://creativecommons.org/licenses/by/4.0/legalcode) diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/_sidebar.md b/docs/_sidebar.md new file mode 100644 index 0000000..258c20e --- /dev/null +++ b/docs/_sidebar.md @@ -0,0 +1,5 @@ +# Resources + +- [Learning resources](learning-resources.md) +- [Documentation references](doc-references__.md) +- [Past work](past-work.md) diff --git a/docs/doc-references.md b/docs/doc-references.md new file mode 100644 index 0000000..08da081 --- /dev/null +++ b/docs/doc-references.md @@ -0,0 +1,3 @@ +# Documentation References + +_List handy documentation references, like https://docsify.js.org._ \ No newline at end of file diff --git a/docs/git-tips.md b/docs/git-tips.md new file mode 100644 index 0000000..21ca1c8 --- /dev/null +++ b/docs/git-tips.md @@ -0,0 +1,195 @@ +# GIT tics + +# Fetch a file from another branch to the current one +git checkout branch_name -- filename + +# Unstage all changes but leave files in the working directory untouched +git reset HEAD + +# Unstage a file +git reset HEAD + +# Go back to last commit and remove all changes from working directory +git reset HEAD --hard + +# Delete untracked files +git clean -f + +# Compare two branches +git diff develop..master + +# Compare two commits +git diff .. + +## Unstage file +```bash +git reset filename +``` + +## Unstage deleted file +```bash +git checkout HEAD filename +``` + +## Undo commit +```bash +git reset --soft HEAD\^ +``` + +## Checkout remote branch +```bash +git fetch origin +git checkout develop +``` + +## Go back to previous branch +```bash +git checkout - +``` + +## Create empty master branch +```bash +git branch -D master +git checkout --orphan master +``` +## Tag the release +```bash +# optional: tag important things, such as releases +git tag 1.0.0-RC1 +``` + +## Delete local tag +```bash +git tag -d v0.2.0 +``` + +## Delete remote tag +```bash +git push origin :refs/tags/v0.2.0 +``` + +## Amend last commit +If you want to change the message of the latest commit do +```bash +git commit --amend -m "New commit message" +``` + +## Revert specific file to previous version +If you want to revert a specific file to its previous version do +```bash +git checkout -- filename +``` + +## Undo all changes in branch +If you want to reset all non-committed changes do +```bash +git reset --hard +``` + +## Restore a file deleted in a previous commit +If you want to restore a file deleted in a previous commit do +```bash +git rev-list -n 1 HEAD -- +git checkout ^ -- +``` + +## Remove a file from a commit that has not been pushed +If you want to remove a specific file from a commit that has not been pushed do +```bash +git reset HEAD filename +``` +You can do it without the --, but if the filename looks like a branch or tag (or other revision identifier), it may get confused, so using -- is best. + +## Checkout specific version of file +You can also check out a particular version of a file +```bash +git checkout v1.2.3 -- filename # tag v1.2.3 +git checkout stable -- filename # stable branch +git checkout origin/master -- filename # upstream master +git checkout HEAD -- filename # the version from the most recent commit +git checkout HEAD^ -- filename # the version before the most recent commit +``` + +## Remove a commit that has not been pushed +```bash +git reset --hard HEAD^ +``` +to reset to the previous commit before the current head; that way you don't have to be copying around commit IDs. + +## Revert a commit +Identify the hash of the commit, using `git log`, then use `git revert ` to create a new commit that removes these changes. In a way, `git revert` is the converse of `git cherry-pick` -- the latter applies the patch to a branch that's missing it, the former removes it from a branch that has it. + +## Create a patch +```bash +git commit ... +git checkout +git format-patch --stdout > fix_empty_poster.patch +git apply --stat fix_empty_poster.patch +git apply --check fix_empty_poster.patch +git am --signoff < fix_empty_poster.patch +``` +or +```bash +git diff > fix_empty_poster.patch +git apply fix_empty_poster.patch +``` + +## Sync a fork +Add remote repository `upstream`. +```bash +git remote add upstream https://github.com/trntv/yii2-starter-kit.git +``` +Fetch latest commit from it +```bash +git fetch upstream +``` +Merge these commits to your repository +```bash +git checkout master +git merge upstream/master +``` +**IMPORTANT: there might be a conflicts between `upstream` and your code. You should resolve merging conflicts on your own** + +## Prune remote branches +```bash +git fetch --prune && git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -d +``` + +## Submodules +If you want to use someone else's repo as a Git Submodule on GitHub do +```bash +git submodule add git://github.com/username/repo.git destination/folder +git submodule init +git submodule update +``` +from the root of your project. + +## Stash +```bash +git stash save +git stash save --include-untracked (-u) +git stash pop (git stash apply && git stash drop) +git stash apply (to re-use same stash later) +git stash list +git stash show +git stash apply +git stash branch testchanges +``` +## Renaming branches +If you want to rename a branch while pointed to any branch, do : +``` +git branch -m +``` +If you want to rename the current branch, you can do: +``` +git branch -m +``` + +## git-extras +```bash +git setup (from git-extras) +git ignore .DS_Store +git summary +git effort --above 10 +git undo +``` diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..eb8361d --- /dev/null +++ b/docs/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + + +
+ + + + diff --git a/docs/learning-resources.md b/docs/learning-resources.md new file mode 100644 index 0000000..fb64666 --- /dev/null +++ b/docs/learning-resources.md @@ -0,0 +1,3 @@ +# Learning resources + +_List your favorite learning resources here._ \ No newline at end of file diff --git a/docs/past-work.md b/docs/past-work.md new file mode 100644 index 0000000..138f3ad --- /dev/null +++ b/docs/past-work.md @@ -0,0 +1,3 @@ +# Past work + +_Include references to your own completed Learning Labs or other work_. \ No newline at end of file