From 9f427f3bbeb7d5c2183e0fb759e3d3c23957081d Mon Sep 17 00:00:00 2001 From: Jordan Mesches <69156199+Jordan-Mesches@users.noreply.github.com> Date: Thu, 9 Nov 2023 13:57:30 -0800 Subject: [PATCH] Initial commit --- .devcontainer/Dockerfile | 7 + .devcontainer/devcontainer.json | 52 + .dockerignore | 5 + .github/ISSUE_TEMPLATE/feature_request.md | 20 + .github/dependabot.yml | 14 + .github/dependency-review-config.yml | 13 + .github/release.yml | 18 + .gitignore | 7 + CODE_OF_CONDUCT.md | 94 + Dockerfile | 11 + README.md | 15 + docs/.tetris.game/LICENSE | 19 + docs/.tetris.game/README.txt | 26 + docs/.tetris.game/app.js | 559 +++ docs/.tetris.game/app.test.js | 16 + docs/.tetris.game/index.html | 26 + docs/.tetris.game/stats.js | 9 + docs/.tetris.game/style.css | 191 + docs/.tetris.game/texture.jpg | Bin 0 -> 44996 bytes .../app-destination-repository-selection.png | Bin 0 -> 170413 bytes docs/assets/img/app-home-display.png | Bin 0 -> 198145 bytes .../app-installation-success-notification.png | Bin 0 -> 32768 bytes docs/assets/img/app-owner-selection.png | Bin 0 -> 59120 bytes docs/assets/img/build-warning.png | Bin 0 -> 213171 bytes docs/assets/img/change-port-visibility.png | Bin 0 -> 86886 bytes docs/assets/img/codeql-analysis-setup.png | Bin 0 -> 168512 bytes .../img/codeql-protection-rules-setup.png | Bin 0 -> 179760 bytes docs/assets/img/completely-passing-checks.png | Bin 0 -> 163647 bytes docs/assets/img/create-a-new-codespaces.png | Bin 0 -> 123535 bytes docs/assets/img/create-a-new-repository.png | Bin 0 -> 287000 bytes docs/assets/img/create-project.png | Bin 0 -> 337304 bytes .../create-pull-request-from-codespace.png | Bin 0 -> 51499 bytes .../img/dependency-review-milestone.png | Bin 0 -> 177136 bytes .../img/dependency-review-outcome-01.png | Bin 0 -> 96146 bytes docs/assets/img/deployments-list.png | Bin 0 -> 303748 bytes .../img/deployments-view-on-repo-home.png | Bin 0 -> 721419 bytes docs/assets/img/develop-and-validate-work.png | Bin 0 -> 176007 bytes docs/assets/img/e2e-github.png | Bin 0 -> 205449 bytes ...ul-integration-tetris-game-integration.png | Bin 0 -> 320908 bytes docs/assets/img/favicon.ico | Bin 0 -> 6518 bytes ...thub-icon-in-sidebar-menu-of-codespace.png | Bin 0 -> 62625 bytes docs/assets/img/initiate-and-track-goals.png | Bin 0 -> 172165 bytes docs/assets/img/issue-closed-done.png | Bin 0 -> 37853 bytes docs/assets/img/merge-pull-request.png | Bin 0 -> 194332 bytes .../img/milestone-continuous-deployment.png | Bin 0 -> 180988 bytes ...package-and-release-delivery-artifacts.png | Bin 0 -> 180142 bytes docs/assets/img/milestone-versioning.png | Bin 0 -> 178142 bytes docs/assets/img/milestones-all.png | Bin 0 -> 200081 bytes docs/assets/img/milestones-start.png | Bin 0 -> 170814 bytes docs/assets/img/milestones.png | Bin 0 -> 466010 bytes docs/assets/img/missing-tetris-game.jpeg | Bin 0 -> 203664 bytes docs/assets/img/packages.png | Bin 0 -> 353506 bytes docs/assets/img/passing-test.png | Bin 0 -> 63848 bytes .../img/pull-request-form-in-codespace.png | Bin 0 -> 135980 bytes docs/assets/img/pull-request-view.png | Bin 0 -> 392219 bytes docs/assets/img/release-discussions.png | Bin 0 -> 251092 bytes docs/assets/img/repository-settings-tab.png | Bin 0 -> 86565 bytes docs/assets/img/restart-codespace.png | Bin 0 -> 45789 bytes ...resume-existing-codespace-at-repo-home.png | Bin 0 -> 94183 bytes docs/assets/img/select-new-project.png | Bin 0 -> 529269 bytes docs/assets/img/successful-deployment-job.png | Bin 0 -> 248615 bytes docs/assets/img/tetris-game.png | Bin 0 -> 981256 bytes docs/assets/javascripts/extra.js | 26 + docs/assets/javascripts/katex.js | 10 + docs/assets/javascripts/tables.js | 6 + docs/assets/stylesheets/extra.css | 58 + docs/exercises/01.collaborate/01.md | 72 + docs/exercises/01.collaborate/02.md | 450 ++ docs/exercises/01.collaborate/index.md | 14 + .../02.secure.the.software.supply.chain/01.md | 100 + .../02.secure.the.software.supply.chain/02.md | 92 + .../index.md | 14 + docs/exercises/03.automate.release/01.md | 90 + docs/exercises/03.automate.release/02.md | 137 + docs/exercises/03.automate.release/index.md | 12 + docs/exercises/index.md | 47 + docs/exercises/recap/index.md | 13 + docs/index.md | 31 + docs/prerequisites.md | 186 + jest.config.js | 198 + mkdocs.yml | 169 + package-lock.json | 4235 +++++++++++++++++ package.json | 36 + playwright.config.js | 78 + reference.implementations/dependabot.yml | 14 + .../dependency-review-config.yml | 28 + reference.implementations/release.yml | 18 + .../tests/tetris.spec.js | 26 + .../workflows/1.1.continuous.integration.yml | 56 + .../workflows/1.2.continuous.integration.yml | 67 + .../workflows/1.3.continuous.integration.yml | 55 + .../workflows/2.1.continuous.delivery.yml | 60 + .../workflows/2.2.continuous.delivery.yml | 105 + ...2.3.optional.container.image.packaging.yml | 28 + .../workflows/3.continuous.deployment.yml | 77 + requirements.ci.txt | 4 + requirements.txt | 8 + 97 files changed, 7722 insertions(+) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json create mode 100644 .dockerignore create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/dependabot.yml create mode 100644 .github/dependency-review-config.yml create mode 100644 .github/release.yml create mode 100644 .gitignore create mode 100644 CODE_OF_CONDUCT.md create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 docs/.tetris.game/LICENSE create mode 100644 docs/.tetris.game/README.txt create mode 100644 docs/.tetris.game/app.js create mode 100755 docs/.tetris.game/app.test.js create mode 100644 docs/.tetris.game/index.html create mode 100644 docs/.tetris.game/stats.js create mode 100644 docs/.tetris.game/style.css create mode 100644 docs/.tetris.game/texture.jpg create mode 100644 docs/assets/img/app-destination-repository-selection.png create mode 100644 docs/assets/img/app-home-display.png create mode 100644 docs/assets/img/app-installation-success-notification.png create mode 100644 docs/assets/img/app-owner-selection.png create mode 100644 docs/assets/img/build-warning.png create mode 100644 docs/assets/img/change-port-visibility.png create mode 100644 docs/assets/img/codeql-analysis-setup.png create mode 100644 docs/assets/img/codeql-protection-rules-setup.png create mode 100644 docs/assets/img/completely-passing-checks.png create mode 100644 docs/assets/img/create-a-new-codespaces.png create mode 100644 docs/assets/img/create-a-new-repository.png create mode 100644 docs/assets/img/create-project.png create mode 100644 docs/assets/img/create-pull-request-from-codespace.png create mode 100644 docs/assets/img/dependency-review-milestone.png create mode 100644 docs/assets/img/dependency-review-outcome-01.png create mode 100644 docs/assets/img/deployments-list.png create mode 100644 docs/assets/img/deployments-view-on-repo-home.png create mode 100644 docs/assets/img/develop-and-validate-work.png create mode 100644 docs/assets/img/e2e-github.png create mode 100644 docs/assets/img/example-successful-integration-tetris-game-integration.png create mode 100644 docs/assets/img/favicon.ico create mode 100644 docs/assets/img/github-icon-in-sidebar-menu-of-codespace.png create mode 100644 docs/assets/img/initiate-and-track-goals.png create mode 100644 docs/assets/img/issue-closed-done.png create mode 100644 docs/assets/img/merge-pull-request.png create mode 100644 docs/assets/img/milestone-continuous-deployment.png create mode 100644 docs/assets/img/milestone-package-and-release-delivery-artifacts.png create mode 100644 docs/assets/img/milestone-versioning.png create mode 100644 docs/assets/img/milestones-all.png create mode 100644 docs/assets/img/milestones-start.png create mode 100644 docs/assets/img/milestones.png create mode 100644 docs/assets/img/missing-tetris-game.jpeg create mode 100644 docs/assets/img/packages.png create mode 100644 docs/assets/img/passing-test.png create mode 100644 docs/assets/img/pull-request-form-in-codespace.png create mode 100644 docs/assets/img/pull-request-view.png create mode 100644 docs/assets/img/release-discussions.png create mode 100644 docs/assets/img/repository-settings-tab.png create mode 100644 docs/assets/img/restart-codespace.png create mode 100644 docs/assets/img/resume-existing-codespace-at-repo-home.png create mode 100644 docs/assets/img/select-new-project.png create mode 100644 docs/assets/img/successful-deployment-job.png create mode 100644 docs/assets/img/tetris-game.png create mode 100644 docs/assets/javascripts/extra.js create mode 100644 docs/assets/javascripts/katex.js create mode 100644 docs/assets/javascripts/tables.js create mode 100644 docs/assets/stylesheets/extra.css create mode 100644 docs/exercises/01.collaborate/01.md create mode 100644 docs/exercises/01.collaborate/02.md create mode 100644 docs/exercises/01.collaborate/index.md create mode 100644 docs/exercises/02.secure.the.software.supply.chain/01.md create mode 100644 docs/exercises/02.secure.the.software.supply.chain/02.md create mode 100644 docs/exercises/02.secure.the.software.supply.chain/index.md create mode 100644 docs/exercises/03.automate.release/01.md create mode 100644 docs/exercises/03.automate.release/02.md create mode 100644 docs/exercises/03.automate.release/index.md create mode 100644 docs/exercises/index.md create mode 100644 docs/exercises/recap/index.md create mode 100644 docs/index.md create mode 100644 docs/prerequisites.md create mode 100644 jest.config.js create mode 100644 mkdocs.yml create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 playwright.config.js create mode 100644 reference.implementations/dependabot.yml create mode 100644 reference.implementations/dependency-review-config.yml create mode 100644 reference.implementations/release.yml create mode 100644 reference.implementations/tests/tetris.spec.js create mode 100644 reference.implementations/workflows/1.1.continuous.integration.yml create mode 100644 reference.implementations/workflows/1.2.continuous.integration.yml create mode 100644 reference.implementations/workflows/1.3.continuous.integration.yml create mode 100644 reference.implementations/workflows/2.1.continuous.delivery.yml create mode 100644 reference.implementations/workflows/2.2.continuous.delivery.yml create mode 100644 reference.implementations/workflows/2.3.optional.container.image.packaging.yml create mode 100644 reference.implementations/workflows/3.continuous.deployment.yml create mode 100644 requirements.ci.txt create mode 100644 requirements.txt diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..e6d16ca --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,7 @@ +FROM --platform=linux/amd64 mcr.microsoft.com/vscode/devcontainers/python:3 + +WORKDIR /workspace + +COPY requirements*.txt . + +RUN python -m pip install --no-cache-dir --upgrade --requirement requirements.ci.txt \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..348f93e --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,52 @@ +{ + "hostRequirements": { + "cpus": 4, + "memory": "16gb", + "storage": "32gb" + }, + "build": { + "dockerfile": "./Dockerfile", + "context": ".." + }, + "postAttachCommand": "python -m mkdocs serve --clean --dev-addr 127.0.0.1:8080", + "forwardPorts": [ + 8080 + ], + "containerEnv": { + "TETRIS_APP_HOST": "127.0.0.1", + "TETRIS_APP_PORT": "8080", + "TETRIS_APP_PATH": "github-devsecops-fundamentals" + }, + "customizations": { + "vscode": { + "extensions": [ + "GitHub.vscode-pull-request-github", + "ms-azuretools.vscode-docker", + "github.vscode-github-actions", + "ms-python.python", + "esbenp.prettier-vscode", + "ms-python.flake8", + "ms-python.black-formatter", + "ms-python.mypy-type-checker", + "ms-python.pylint", + "ms-python.vscode-pylance", + "ms-vsliveshare.vsliveshare", + "ms-playwright.playwright", + "GitHub.copilot-chat", + "GitHub.copilot", + "pomdtr.excalidraw-editor" + ] + } + }, + "features": { + "ghcr.io/devcontainers/features/git:1": { + "ppa": true, + "version": "latest" + } + }, + "portsAttributes": { + "8080": { + "label": "Site" + } + } +} \ No newline at end of file diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..66cc66b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +* +!docs/* +!mkdocs.yml +!requirements*.txt +!.devcontainer/* diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..bbcbbe7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..78ab862 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,14 @@ +version: 2 +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "daily" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/dependency-review-config.yml b/.github/dependency-review-config.yml new file mode 100644 index 0000000..d053e5f --- /dev/null +++ b/.github/dependency-review-config.yml @@ -0,0 +1,13 @@ +fail-on-severity: moderate + +comment-summary-in-pr: always + +allow-licenses: + - MIT + - GPL-3.0 + - BSD-3-Clause + +fail-on-scopes: + - development + - runtime + - unknown diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000..8dc79cd --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,18 @@ +changelog: + exclude: + labels: + - ignore-for-release + authors: + - octocat + categories: + - title: Breaking Changes 🛠 + labels: + - Semver-Major + - breaking-change + - title: Exciting New Features 🎉 + labels: + - Semver-Minor + - enhancement + - title: Other Changes + labels: + - "*" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0a9020b --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +site +node_modules/ +/test-results/ +/playwright-report/ +/playwright/.cache/ +.vscode/settings.json diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..b06c827 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,94 @@ + +# Code of Conduct + +The GitHub Universe 2023 Discussion Forum is intended to be a place for questions, feedback and chat related to sessions at the virtual GitHub Universe 2023 event. This is a civilized place for connecting with other attendees, and Hubbers from across the world taking part in the event. By participating in this community, you are agreeing to the same [Terms of Service](https://help.github.com/articles/github-terms-of-service) that apply to GitHub.com, as well as the GitHub Universe 2023 Discussion Forum specific Code of Conduct. + +With this Code of Conduct, we hope to help you understand how best to collaborate in Discussions, what you can expect from moderators, and what type of actions or content may result in temporary or permanent suspension from this project. We will investigate any abuse reports and may moderate public content within the discussion that we determine to be in violation of either the GitHub Terms of Service or this Code of Conduct. + +GitHub users worldwide bring wildly different perspectives, ideas, and experiences, and range from people who created their first "Hello World" project last week to the most well-known software developers in the world. We are committed to making GitHub Universe a welcoming environment for all the different voices and perspectives here, while maintaining a space where people are free to express themselves. + + +### Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in the GitHub Universe Discussions a harassment-free experience for everyone, regardless of age, body size, ability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + + +### Standards + +Treat the GitHub Universe Discussions with respect. The following are not hard and fast rules, merely aids to the human judgment of our Community. Use these guidelines to keep this a clean, well-lighted place for civilized public discourse. + + +#### _Best Practices for Building a Strong Community_ + + + +* Be respectful and considerate. + * Be welcoming and open-minded. Other GitHub members may not have the same experience level or background as you, but that doesn't mean they don't have good ideas to contribute. We encourage you to be welcoming to new members and those just getting started. + * Respect each other. Nothing sabotages healthy conversation like rudeness. Be civil and professional, and don’t post anything that a reasonable person would consider offensive, abusive, or hate speech. Don’t harass or grief anyone. Treat each other with dignity and consideration in all interactions. \ +You may wish to respond to something by disagreeing with it. That’s fine. But remember to criticize ideas, not people. Avoid name-calling, ad hominem attacks, responding to a post’s tone instead of its actual content, and knee-jerk contradiction. Instead, provide reasoned counter-arguments that improve the conversation. + * Communicate with empathy. Disagreements or differences of opinion are a fact of life. Being part of a community means interacting with people from a variety of backgrounds and perspectives, many of which may not be your own. If you disagree with someone, try to understand and share their feelings before you address them. This will promote a respectful and friendly atmosphere where people feel comfortable asking questions, participating in discussions, and making contributions. +* Contribute in a positive and constructive way. + * Improve the discussion. Help us make this a great place for discussion by always working to improve the discussion in some way, however small. If you are not sure your post adds to the conversation, think over what you want to say and try again later. \ +The topics discussed here matter to us, and we want you to act as if they matter to you, too. Be respectful of the topics and the people discussing them, even if you disagree with some of what is being said. + * Be clear and stay on topic. Communicating with strangers on the Internet can be awkward. It's hard to convey or read tone, and sarcasm is frequently misunderstood. Try to use clear language, and think about how it will be received by the other person. \ +This applies to sharing links, as well. Any links shared in the discussions should be shared with the intent of providing relevant and appropriate information. Links should not be posted to simply drive traffic or attention to a site. Links should always be accompanied by a full explanation of the content and purpose of the link. Posting links, especially unsolicited ones, without relevant and valuable context can come across as advertising or serving even more malicious purposes. + * Share mindfully. Don't share sensitive information. This includes your own email address. We don't allow the sharing of such information in this discussion forum, as it can create security and privacy risks for the poster, as well as other users. + * Keep it tidy. Make the effort to put things in the right place, so that we can spend more time discussing and less time cleaning up. So: + * Don’t cross-post the same thing in multiple topics. + * Don’t post no-content replies. + * Don’t divert a topic by changing it midstream. + * Rather than posting “+1” or “Agreed”, use the Reaction emoji button. +* Be trustworthy. + * Always be honest. Don’t knowingly share incorrect information or intentionally mislead other GitHub members. If you don’t know the answer to someone’s question but still want to help, you can try helping them research or find resources instead. GitHub staff will also be active in the discussions, so if you’re unsure of an answer, it’s likely a moderator will be able to help. + +#### _What is not Allowed_ + +* Threats of violence. You may not threaten violence towards others or use the site to organize, promote, or incite acts of real-world violence or terrorism. Think carefully about the words you use, the images you post, and even the software you write, and how they may be interpreted by others. Even if you mean something as a joke, it might not be received that way. If you think that someone else might interpret the content you post as a threat, or as promoting violence or terrorism, stop. Don't post it. In extraordinary cases, we may report threats of violence to law enforcement if we think there may be a genuine risk of physical harm or a threat to public safety. +* Hate speech and discrimination. While it is not forbidden to broach topics such as age, body size, ability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation, we do not tolerate speech that attacks a person or group of people on the basis of who they are. Just realize that talking about these or other sensitive topics can make others feel unwelcome, or perhaps even unsafe, if approached in an aggressive or insulting manner. We expect our community members to be respectful when discussing sensitive topics. +* Bullying and harassment. We do not tolerate bullying or harassment. This means any habitual badgering or intimidation targeted at a specific person or group of people. In general, if your actions are unwanted and you continue to engage in them, there's a good chance you are headed into bullying or harassment territory. +* Impersonation. You may not impersonate another person by copying their avatar, posting content under their email address, intentionally using a deceptively similar username or otherwise posing as someone else. Impersonation is a form of harassment. +* Doxxing and invasion of privacy. Don't post other people's personal information, such as phone numbers, private email addresses, physical addresses, credit card numbers, Social Security/National Identity numbers, or passwords. Depending on the context, such as in the case of intimidation or harassment, we may consider other information, such as photos or videos that were taken or distributed without the subject's consent, to be an invasion of privacy, especially when such material presents a safety risk to the subject. +* Prurient/Sexually explicit content. Basically, don't post pornography. This does not mean that all nudity or sexual content is prohibited. We recognize that sexuality is a part of life and non-pornographic sexual content may be a part of your project, or may be presented for educational or artistic purposes. If you have any questions or concerns about something you want to post, [feel free to reach out and ask](https://support.github.com/contact) beforehand. +* Spam. Respect the GitHub Universe Discussions. Don’t post advertisements, link to spammy websites, or otherwise vandalize the community. This community is meant for GitHub Universe participants to talk about the sessions, to provide feedback, as questions, learn, and share ideas with one another - not for advertising or other spam-like content. Content that we deem spammy will be removed. +* Copyrighted or illegal content. Only post your own stuff. You are responsible for what you post. If you post something you didn’t create yourself, you must have the right to post it. You may not post illegal content, including content illegal under copyright and trademark laws, links to illegal content, or methods for circumventing the law. +* Active malware or exploits. Being part of this community includes not taking advantage of other members of the community. We do not allow anyone to use our platform for exploit delivery (e.g. Using the community as a means to deliver malicious executables) or as attack infrastructure (e.g. Organizing denial of service attacks or managing command and control servers). Note, however, that we do not prohibit the posting of source code which could be used to develop malware or exploits, as the publication and distribution of such source code has educational value and provides a net benefit to the security community. +* Anyone under the age of 13. If you're a child under the age of 13, you may not have an account on GitHub. GitHub does not knowingly collect information from or direct any of our content specifically to children under 13. If we learn or have reason to suspect that you are a user who is under the age of 13, we will unfortunately have to close both your GitHub.com account. We don't want to discourage you from learning to code, but those are the rules. Please see our [Terms of Service](https://help.github.com/articles/github-terms-of-service) for information about account termination. +* Other conduct which could reasonably be considered inappropriate in a professional setting. The GitHub Universe Discussions is a professional space and should be treated as such. + +### Enforcement + + +#### _What GitHub Universe Discussions members Can Do_ + +* If you see a problem, report it. Moderators have special authority; they are responsible for this community. But so are you. With your help, moderators can be community facilitators, not just janitors or police. \ +When you see bad behavior, don’t reply. It encourages the bad behavior by acknowledging it, consumes your energy, and wastes everyone’s time. Just report it by copying a direct link to the reply in question and emailing it to events@github.com + +#### Our Responsibilities + + +There are a variety of actions that we may take in response to inappropriate behavior or content. It usually depends on the exact circumstances of a particular case. We recognize that sometimes people may say or do inappropriate things for any number of reasons. Perhaps they did not realize how their words would be perceived. Or maybe they just let their emotions get the best of them. Of course, sometimes, there are folks who just want to spam or cause trouble. + +Each case requires a different approach, and we try to tailor our response to meet the needs of the situation. We'll review each situation on a case-by-case basis. In each case, we will have a diverse team investigate the content and surrounding facts and respond as appropriate, using this Code of Conduct to guide our decision. + +Actions we may take in response to a flag or abuse report include, but are not limited to: + + + +* Content Removal +* Content Blocking +* GitHub Account Suspension +* GitHub Account Termination + +### Contacting GitHub Staff + + +If, for any reason, you want to contact GitHub Staff, the Community Managers, Administrators, or Moderators of this forum privately, you can send an email to events@github.com. + +Let's work together to keep the discussion a place where people feel safe to participate by being respectful of them and their time. + + +### Legal Notices + +Yes, legalese is boring, but we must protect ourselves – and by extension, you and your data – against unfriendly folks. We have a [Terms of Service](https://help.github.com/articles/github-terms-of-service/) and [Privacy Statement](https://help.github.com/articles/github-privacy-statement/) describing your (and our) behavior and rights related to content, privacy, and laws. To use this service, you must agree to abide by our [Terms of Service](https://help.github.com/articles/github-terms-of-service/) and the [Privacy Statement](https://help.github.com/articles/github-privacy-statement/). + +This Code of Conduct does not modify our [Terms of Service](https://help.github.com/articles/github-terms-of-service/) and is not intended to be a complete list. GitHub retains full discretion under the [Terms of Service](https://help.github.com/articles/github-terms-of-service/) to remove any content or terminate any accounts for activity that is "unlawful, offensive, threatening, libelous, defamatory, pornographic, obscene or otherwise objectionable or violates any party's intellectual property or these Terms of Service." This Code of Conduct describes when we will exercise that discretion. diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c6f75f6 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM python:3.12.0-alpine + +WORKDIR /app + +COPY . . + +RUN pip install -r requirements.txt + +EXPOSE 8080 + +CMD ["mkdocs", "serve", "--dev-addr=127.0.0.1:8080"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..d61f0a1 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ + + +
+ Prerequisites • + Resources • + Learning Objectives +
+ ++Goto :eyes: workshop site +
diff --git a/docs/.tetris.game/LICENSE b/docs/.tetris.game/LICENSE new file mode 100644 index 0000000..b831a05 --- /dev/null +++ b/docs/.tetris.game/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jake Gordon and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/docs/.tetris.game/README.txt b/docs/.tetris.game/README.txt new file mode 100644 index 0000000..7a8bdd6 --- /dev/null +++ b/docs/.tetris.game/README.txt @@ -0,0 +1,26 @@ +Javascript Tetris +================= + +An HTML5 Tetris Game + + * [play the game](http://codeincomplete.com/projects/tetris/) + * read a [blog article](http://codeincomplete.com/posts/2011/10/10/javascript_tetris/) + * view the [source](https://github.com/jakesgordon/javascript-tetris) + +>> _*SUPPORTED BROWSERS*: Chrome, Firefox, Safari, Opera and IE9+_ + +FUTURE +====== + + * menu + * animation and fx + * levels + * high scores + * touch support + * music and sound fx + + +License +======= + +[MIT](http://en.wikipedia.org/wiki/MIT_License) license. diff --git a/docs/.tetris.game/app.js b/docs/.tetris.game/app.js new file mode 100644 index 0000000..eba1481 --- /dev/null +++ b/docs/.tetris.game/app.js @@ -0,0 +1,559 @@ +//------------------------------------------------------------------------- +// base helper methods +//------------------------------------------------------------------------- + +function get(id) { + return document.getElementById(id); +} +function hide(id) { + get(id).style.visibility = "hidden"; +} +function show(id) { + get(id).style.visibility = null; +} +function html(id, html) { + get(id).innerHTML = html; +} + +function timestamp() { + return new Date().getTime(); +} +function random(min, max) { + return min + Math.random() * (max - min); +} +function randomChoice(choices) { + return choices[Math.round(random(0, choices.length - 1))]; +} + +if (!window.requestAnimationFrame) { + // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ + window.requestAnimationFrame = + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function (callback, element) { + window.setTimeout(callback, 1000 / 60); + }; +} + +//------------------------------------------------------------------------- +// game constants +//------------------------------------------------------------------------- + +var KEY = { ESC: 27, SPACE: 32, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40 }, + DIR = { UP: 0, RIGHT: 1, DOWN: 2, LEFT: 3, MIN: 0, MAX: 3 }, + stats = new Stats(), + canvas = get("canvas"), + ctx = canvas.getContext("2d"), + ucanvas = get("upcoming"), + uctx = ucanvas.getContext("2d"), + speed = { start: 0.6, decrement: 0.005, min: 0.1 }, // how long before piece drops by 1 row (seconds) + nx = 10, // width of tetris court (in blocks) + ny = 20, // height of tetris court (in blocks) + nu = 5; // width/height of upcoming preview (in blocks) + +//------------------------------------------------------------------------- +// game variables (initialized during reset) +//------------------------------------------------------------------------- + +var dx, + dy, // pixel size of a single tetris block + blocks, // 2 dimensional array (nx*ny) representing tetris court - either empty block or occupied by a 'piece' + actions, // queue of user actions (inputs) + playing, // true|false - game is in progress + dt, // time since starting this game + current, // the current piece + next, // the next piece + score, // the current score + vscore, // the currently displayed score (it catches up to score in small chunks - like a spinning slot machine) + rows, // number of completed rows in the current game + step; // how long before current piece drops by 1 row + +//------------------------------------------------------------------------- +// tetris pieces +// +// blocks: each element represents a rotation of the piece (0, 90, 180, 270) +// each element is a 16 bit integer where the 16 bits represent +// a 4x4 set of blocks, e.g. j.blocks[0] = 0x44C0 +// +// 0100 = 0x4 << 3 = 0x4000 +// 0100 = 0x4 << 2 = 0x0400 +// 1100 = 0xC << 1 = 0x00C0 +// 0000 = 0x0 << 0 = 0x0000 +// ------ +// 0x44C0 +// +//------------------------------------------------------------------------- + +var i = { + size: 4, + blocks: [0x0f00, 0x2222, 0x00f0, 0x4444], + color: "cyan", +}; +var j = { + size: 3, + blocks: [0x44c0, 0x8e00, 0x6440, 0x0e20], + color: "blue", +}; +var l = { + size: 3, + blocks: [0x4460, 0x0e80, 0xc440, 0x2e00], + color: "orange", +}; +var o = { + size: 2, + blocks: [0xcc00, 0xcc00, 0xcc00, 0xcc00], + color: "yellow", +}; +var s = { + size: 3, + blocks: [0x06c0, 0x8c40, 0x6c00, 0x4620], + color: "green", +}; +var t = { + size: 3, + blocks: [0x0e40, 0x4c40, 0x4e00, 0x4640], + color: "purple", +}; +var z = { + size: 3, + blocks: [0x0c60, 0x4c80, 0xc600, 0x2640], + color: "red", +}; + +//------------------------------------------------ +// do the bit manipulation and iterate through each +// occupied block (x,y) for a given piece +//------------------------------------------------ +function eachblock(type, x, y, dir, fn) { + var bit, + result, + row = 0, + col = 0, + blocks = type.blocks[dir]; + for (bit = 0x8000; bit > 0; bit = bit >> 1) { + if (blocks & bit) { + fn(x + col, y + row); + } + if (++col === 4) { + col = 0; + ++row; + } + } +} + +//----------------------------------------------------- +// check if a piece can fit into a position in the grid +//----------------------------------------------------- +function occupied(type, x, y, dir) { + var result = false; + eachblock(type, x, y, dir, function (x, y) { + if (x < 0 || x >= nx || y < 0 || y >= ny || getBlock(x, y)) result = true; + }); + return result; +} + +function unoccupied(type, x, y, dir) { + return !occupied(type, x, y, dir); +} + +//----------------------------------------- +// start with 4 instances of each piece and +// pick randomly until the 'bag is empty' +//----------------------------------------- +var pieces = []; +function randomPiece() { + if (pieces.length == 0) + pieces = [ + i, + i, + i, + i, + j, + j, + j, + j, + l, + l, + l, + l, + o, + o, + o, + o, + s, + s, + s, + s, + t, + t, + t, + t, + z, + z, + z, + z, + ]; + var type = pieces.splice(random(0, pieces.length - 1), 1)[0]; + return { + type: type, + dir: DIR.UP, + x: Math.round(random(0, nx - type.size)), + y: 0, + }; +} + +//------------------------------------------------------------------------- +// GAME LOOP +//------------------------------------------------------------------------- + +function run() { + showStats(); // initialize FPS counter + addEvents(); // attach keydown and resize events + + var last = (now = timestamp()); + function frame() { + now = timestamp(); + update(Math.min(1, (now - last) / 1000.0)); // using requestAnimationFrame have to be able to handle large delta's caused when it 'hibernates' in a background or non-visible tab + draw(); + stats.update(); + last = now; + requestAnimationFrame(frame, canvas); + } + + resize(); // setup all our sizing information + reset(); // reset the per-game variables + frame(); // start the first frame +} + +function showStats() { + stats.domElement.id = "stats"; + get("menu").appendChild(stats.domElement); +} + +function addEvents() { + document.addEventListener("keydown", keydown, false); + window.addEventListener("resize", resize, false); +} + +function resize(event) { + canvas.width = canvas.clientWidth; // set canvas logical size equal to its physical size + canvas.height = canvas.clientHeight; // (ditto) + ucanvas.width = ucanvas.clientWidth; + ucanvas.height = ucanvas.clientHeight; + dx = canvas.width / nx; // pixel size of a single tetris block + dy = canvas.height / ny; // (ditto) + invalidate(); + invalidateNext(); +} + +function keydown(ev) { + var handled = false; + if (playing) { + switch (ev.keyCode) { + case KEY.LEFT: + actions.push(DIR.LEFT); + handled = true; + break; + case KEY.RIGHT: + actions.push(DIR.RIGHT); + handled = true; + break; + case KEY.UP: + actions.push(DIR.UP); + handled = true; + break; + case KEY.DOWN: + actions.push(DIR.DOWN); + handled = true; + break; + case KEY.ESC: + lose(); + handled = true; + break; + } + } else if (ev.keyCode == KEY.SPACE) { + play(); + handled = true; + } + if (handled) ev.preventDefault(); // prevent arrow keys from scrolling the page (supported in IE9+ and all other browsers) +} + +//------------------------------------------------------------------------- +// GAME LOGIC +//------------------------------------------------------------------------- + +function play() { + hide("start"); + reset(); + playing = true; +} +function lose() { + show("start"); + setVisualScore(); + playing = false; +} + +function setVisualScore(n) { + vscore = n || score; + invalidateScore(); +} +function setScore(n) { + score = n; + setVisualScore(n); +} +function addScore(n) { + score = score + n; +} +function clearScore() { + setScore(0); +} +function clearRows() { + setRows(0); +} +function setRows(n) { + rows = n; + step = Math.max(speed.min, speed.start - speed.decrement * rows); + invalidateRows(); +} +function addRows(n) { + setRows(rows + n); +} +function getBlock(x, y) { + return blocks && blocks[x] ? blocks[x][y] : null; +} +function setBlock(x, y, type) { + blocks[x] = blocks[x] || []; + blocks[x][y] = type; + invalidate(); +} +function clearBlocks() { + blocks = []; + invalidate(); +} +function clearActions() { + actions = []; +} +function setCurrentPiece(piece) { + current = piece || randomPiece(); + invalidate(); +} +function setNextPiece(piece) { + next = piece || randomPiece(); + invalidateNext(); +} + +function reset() { + dt = 0; + clearActions(); + clearBlocks(); + clearRows(); + clearScore(); + setCurrentPiece(next); + setNextPiece(); +} + +function update(idt) { + if (playing) { + if (vscore < score) setVisualScore(vscore + 1); + handle(actions.shift()); + dt = dt + idt; + if (dt > step) { + dt = dt - step; + drop(); + } + } +} + +function handle(action) { + switch (action) { + case DIR.LEFT: + move(DIR.LEFT); + break; + case DIR.RIGHT: + move(DIR.RIGHT); + break; + case DIR.UP: + rotate(); + break; + case DIR.DOWN: + drop(); + break; + } +} + +function move(dir) { + var x = current.x, + y = current.y; + switch (dir) { + case DIR.RIGHT: + x = x + 1; + break; + case DIR.LEFT: + x = x - 1; + break; + case DIR.DOWN: + y = y + 1; + break; + } + if (unoccupied(current.type, x, y, current.dir)) { + current.x = x; + current.y = y; + invalidate(); + return true; + } else { + return false; + } +} + +function rotate() { + var newdir = current.dir == DIR.MAX ? DIR.MIN : current.dir + 1; + if (unoccupied(current.type, current.x, current.y, newdir)) { + current.dir = newdir; + invalidate(); + } +} + +function drop() { + if (!move(DIR.DOWN)) { + addScore(10); + dropPiece(); + removeLines(); + setCurrentPiece(next); + setNextPiece(randomPiece()); + clearActions(); + if (occupied(current.type, current.x, current.y, current.dir)) { + lose(); + } + } +} + +function dropPiece() { + eachblock(current.type, current.x, current.y, current.dir, function (x, y) { + setBlock(x, y, current.type); + }); +} + +function removeLines() { + var x, + y, + complete, + n = 0; + for (y = ny; y > 0; --y) { + complete = true; + for (x = 0; x < nx; ++x) { + if (!getBlock(x, y)) complete = false; + } + if (complete) { + removeLine(y); + y = y + 1; // recheck same line + n++; + } + } + if (n > 0) { + addRows(n); + addScore(100 * Math.pow(2, n - 1)); // 1: 100, 2: 200, 3: 400, 4: 800 + } +} + +function removeLine(n) { + var x, y; + for (y = n; y >= 0; --y) { + for (x = 0; x < nx; ++x) setBlock(x, y, y == 0 ? null : getBlock(x, y - 1)); + } +} + +//------------------------------------------------------------------------- +// RENDERING +//------------------------------------------------------------------------- + +var invalid = {}; + +function invalidate() { + invalid.court = true; +} +function invalidateNext() { + invalid.next = true; +} +function invalidateScore() { + invalid.score = true; +} +function invalidateRows() { + invalid.rows = true; +} + +function draw() { + ctx.save(); + ctx.lineWidth = 1; + ctx.translate(0.5, 0.5); // for crisp 1px black lines + drawCourt(); + drawNext(); + drawScore(); + drawRows(); + ctx.restore(); +} + +function drawCourt() { + if (invalid.court) { + ctx.clearRect(0, 0, canvas.width, canvas.height); + if (playing) + drawPiece(ctx, current.type, current.x, current.y, current.dir); + var x, y, block; + for (y = 0; y < ny; y++) { + for (x = 0; x < nx; x++) { + if ((block = getBlock(x, y))) drawBlock(ctx, x, y, block.color); + } + } + ctx.strokeRect(0, 0, nx * dx - 1, ny * dy - 1); // court boundary + invalid.court = false; + } +} + +function drawNext() { + if (invalid.next) { + var padding = (nu - next.type.size) / 2; // half-arsed attempt at centering next piece display + uctx.save(); + uctx.translate(0.5, 0.5); + uctx.clearRect(0, 0, nu * dx, nu * dy); + drawPiece(uctx, next.type, padding, padding, next.dir); + uctx.strokeStyle = "black"; + uctx.strokeRect(0, 0, nu * dx - 1, nu * dy - 1); + uctx.restore(); + invalid.next = false; + } +} + +function drawScore() { + if (invalid.score) { + html("score", ("00000" + Math.floor(vscore)).slice(-5)); + invalid.score = false; + } +} + +function drawRows() { + if (invalid.rows) { + html("rows", rows); + invalid.rows = false; + } +} + +function drawPiece(ctx, type, x, y, dir) { + eachblock(type, x, y, dir, function (x, y) { + drawBlock(ctx, x, y, type.color); + }); +} + +function drawBlock(ctx, x, y, color) { + ctx.fillStyle = color; + ctx.fillRect(x * dx, y * dy, dx, dy); + ctx.strokeRect(x * dx, y * dy, dx, dy); +} + +//------------------------------------------------------------------------- +// FINALLY, lets run the game +//------------------------------------------------------------------------- + +run(); + +module.exports = { setScore, addScore }; diff --git a/docs/.tetris.game/app.test.js b/docs/.tetris.game/app.test.js new file mode 100755 index 0000000..89ccb05 --- /dev/null +++ b/docs/.tetris.game/app.test.js @@ -0,0 +1,16 @@ +const { setScore, addScore } = require("./app.js"); + +describe("setScore", () => { + it("should set the score to the given value", () => { + setScore(5); + expect(score).toBe(5); + }); +}); + +describe("addScore", () => { + it("should add the given value to the current score", () => { + setScore(5); + addScore(3); + expect(score).toBe(8); + }); +}); diff --git a/docs/.tetris.game/index.html b/docs/.tetris.game/index.html new file mode 100644 index 0000000..f09137b --- /dev/null +++ b/docs/.tetris.game/index.html @@ -0,0 +1,26 @@ + + + +g#~izNQH5LUrT1q6?T$m!3=*z8Q~{I2x>>AD!#<1|WsIJZu2Y
zY!#%Awkxwo6wIR;P@&VV!C3AcZU!Q+N2Qopkh$?c7
zUjJ*BsIbSBY4^>%dILBU+~PXs;X&y}tG%yJY6^6$NL!R+*uDDN$8E4aS`6Fwq~6~F
zb11vO;@Ybqd-j&XiG^Ake#(RmH`rD{b~50X^IMY8FQ}>(!y6B~@HYL651TU08Go{W
zMlav8q>Q|a-J(mNLV2?i@*pMRK zA=>%PoeFjz7gFBCrQ`5u+DUSj8ziaCW$biiwP;bqy6VwR2^7
zH+cT4aPl_n6mKld41CU_-kU4x&uvYzcuc66tkd=RlT(
=9UQv!o+t;jVOD4hL76^!i11D6(k4V+H^~f%8HjFT#86t=w~*oEccxbd$@j
zOH@1fm*s}{MvQ)ZqCm*#cZY5AB{UECz_(5*Kk&truJzAzdwos2HR}q4*AdYdl3|^b
zE;M$Jos>^0dt_D_{QNe$$a3tK+vo$L8Q)BPrDDQPdJtLN%Lsf=j@zR%G;MXK)Z0~B
zGTjA7?4;o#E=KjHSkzo-aj&<~dWJ2&q9Y
zb<@}H#C3eWWr1-G2|zOrcUM3B;vHMG;7EG%5OL|r|7RX$N#0P&ckV~SLZ^h_5~7Qd
z=*QMC0}@Z^@3UuwFS;afbbZQ+8?w}iXDzW7MJSxbngfr*ZfuERK^NbF2Z$H$U!ZG(U?A!Lc>RO_p?x87|;M-s`UcWolsr@LkRfu9~bVt-4LU=2fa5_L|>c
z@^UoEhJN{Tt;IjcR~AtG%ptO=;4AOw{Zst8wIOHH+K9`yMju-XJPZp=)^6VAs^N7f
zt7kj6{zgtD|J4k&$$$&Sgqwcu6hZ5Nq)e{Ns{)z8{d&6xO?P<(-O3s2;p^5bC6-q6
zi3mpIWD-+V@ctGv&;
gWqq)&}9p>G6(e5C;I&8`KO3-}99;y;-fJ$|@`
z8w&RbpEr#`-S*NI*R55Zc}yJovn;Zr-