├── .github └── workflows │ └── mdbook.yaml ├── README.md ├── code ├── .gitignore ├── application │ ├── .gitignore │ ├── client │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── public │ │ │ ├── favicon.ico │ │ │ ├── index.html │ │ │ ├── logo192.png │ │ │ ├── logo512.png │ │ │ ├── manifest.json │ │ │ └── robots.txt │ │ └── src │ │ │ ├── App.css │ │ │ ├── App.js │ │ │ ├── App.test.js │ │ │ ├── OverView.js │ │ │ ├── UnitView.js │ │ │ ├── index.css │ │ │ ├── index.js │ │ │ ├── logo.svg │ │ │ ├── reportWebVitals.js │ │ │ └── setupTests.js │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── uk │ │ │ │ └── ac │ │ │ │ └── bristol │ │ │ │ └── cs │ │ │ │ └── application │ │ │ │ ├── Application.java │ │ │ │ ├── ApplicationWebConfig.java │ │ │ │ ├── NoSuchElementException.java │ │ │ │ ├── Templates.java │ │ │ │ ├── controller │ │ │ │ ├── CountryController.java │ │ │ │ ├── CountyController.java │ │ │ │ ├── ErrorHandler.java │ │ │ │ ├── RegionController.java │ │ │ │ ├── StatisticsController.java │ │ │ │ └── WardController.java │ │ │ │ ├── model │ │ │ │ ├── Country.java │ │ │ │ ├── County.java │ │ │ │ ├── ModelClass.java │ │ │ │ ├── Region.java │ │ │ │ ├── Statistic.java │ │ │ │ └── Ward.java │ │ │ │ └── repository │ │ │ │ ├── CountryRepository.java │ │ │ │ ├── CountyRepository.java │ │ │ │ ├── RegionRepository.java │ │ │ │ └── WardRepository.java │ │ └── resources │ │ │ ├── application.properties │ │ │ └── templates │ │ │ └── 404.html │ │ └── test │ │ └── java │ │ └── uk │ │ └── ac │ │ └── bristol │ │ └── cs │ │ └── application │ │ └── ApplicationTests.java ├── censusexplorer │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── uk │ │ │ └── ac │ │ │ └── bristol │ │ │ └── cs │ │ │ └── censusexplorer │ │ │ ├── Application.java │ │ │ ├── Templates.java │ │ │ ├── controller │ │ │ ├── CountryController.java │ │ │ ├── CountyController.java │ │ │ ├── MainController.java │ │ │ └── RegionController.java │ │ │ ├── model │ │ │ ├── Country.java │ │ │ ├── County.java │ │ │ └── Region.java │ │ │ └── repository │ │ │ ├── CountryRepository.java │ │ │ ├── CountyRepository.java │ │ │ └── RegionRepository.java │ │ └── resources │ │ ├── application.properties │ │ ├── static │ │ ├── reset.css │ │ └── styles.css │ │ └── templates │ │ ├── country_list.html │ │ ├── country_show.html │ │ ├── county_show.html │ │ ├── index.html │ │ ├── layout.html │ │ ├── region_list.html │ │ └── region_show.html ├── databases │ ├── sample-data.sql │ ├── sampledata.tar │ └── secure-setup.sql ├── debugging │ ├── stackcalc.c │ └── stackcalc.txt ├── javascript │ ├── JavaScript.js │ ├── Objects.js │ ├── Trees.js │ ├── bristol-app │ │ ├── app.html │ │ ├── script.js │ │ └── style.css │ ├── callback.js │ ├── callbackhell.js │ ├── class.js │ ├── dom-test-1 │ │ ├── DOM-Test.js │ │ ├── PM5544.png │ │ └── dom-example.html │ ├── dom-test-2 │ │ ├── dom-smile.html │ │ ├── rotate.js │ │ └── style.css │ ├── foreach.js │ ├── hoisting.js │ ├── index.js │ ├── inheritance.js │ ├── json.js │ ├── oliterals.js │ ├── promise.js │ ├── scope.js │ └── wordcount.js ├── jdbc │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── org │ │ └── example │ │ └── Example.java ├── orm │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── org │ │ │ └── example │ │ │ ├── Candidate.java │ │ │ ├── Example.java │ │ │ ├── Party.java │ │ │ └── Ward.java │ │ └── resources │ │ └── hibernate.cfg.xml ├── server01 │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── softwaretools │ │ │ │ └── server01 │ │ │ │ ├── Controller.java │ │ │ │ └── Server01Application.java │ │ └── resources │ │ │ ├── application.properties │ │ │ └── web │ │ │ └── page.html │ │ └── test │ │ └── java │ │ └── softwaretools │ │ └── server01 │ │ └── Server01ApplicationTests.java └── server02 │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── softwaretools │ │ │ └── server02 │ │ │ ├── Controller.java │ │ │ ├── Server02Application.java │ │ │ ├── Templates.java │ │ │ └── model │ │ │ ├── Database.java │ │ │ ├── Pair.java │ │ │ ├── Student.java │ │ │ ├── Unit.java │ │ │ └── internal │ │ │ └── DatabaseImpl.java │ └── resources │ │ ├── application.properties │ │ ├── templates │ │ ├── unit.html │ │ └── units.html │ │ └── web │ │ └── index.html │ └── test │ └── java │ └── softwaretools │ └── server02 │ └── Server02ApplicationTests.java ├── docs ├── README.md ├── _config.yml ├── _layouts │ └── default.html ├── assets │ ├── css │ │ └── style.scss │ └── images │ │ └── OST.jpg ├── exercises │ ├── part1 │ │ ├── .nojekyll │ │ ├── 404.html │ │ ├── FontAwesome │ │ │ ├── css │ │ │ │ └── font-awesome.css │ │ │ └── fonts │ │ │ │ ├── FontAwesome.ttf │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ ├── fontawesome-webfont.svg │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ ├── fontawesome-webfont.woff │ │ │ │ └── fontawesome-webfont.woff2 │ │ ├── ayu-highlight.css │ │ ├── book.js │ │ ├── build1 │ │ │ ├── exercise.html │ │ │ └── index.html │ │ ├── build2 │ │ │ ├── c.html │ │ │ ├── index.html │ │ │ ├── java.html │ │ │ ├── python.html │ │ │ └── spring.html │ │ ├── clipboard.min.js │ │ ├── css │ │ │ ├── chrome.css │ │ │ ├── general.css │ │ │ ├── print.css │ │ │ └── variables.css │ │ ├── db1 │ │ │ ├── er-diagram.html │ │ │ ├── er2.html │ │ │ ├── setup.html │ │ │ └── sql-introduction.html │ │ ├── db2 │ │ │ ├── census.html │ │ │ ├── elections.html │ │ │ ├── explore-database.html │ │ │ ├── normalforms.html │ │ │ └── sql-beginners.html │ │ ├── db3 │ │ │ ├── exercises.html │ │ │ └── sql-intermediate.html │ │ ├── db4 │ │ │ ├── hibernate.html │ │ │ ├── jdbc.html │ │ │ ├── sql-java.html │ │ │ └── sqlite.html │ │ ├── elasticlunr.min.js │ │ ├── favicon.png │ │ ├── favicon.svg │ │ ├── fonts │ │ │ ├── OPEN-SANS-LICENSE.txt │ │ │ ├── SOURCE-CODE-PRO-LICENSE.txt │ │ │ ├── fonts.css │ │ │ ├── open-sans-v17-all-charsets-300.woff2 │ │ │ ├── open-sans-v17-all-charsets-300italic.woff2 │ │ │ ├── open-sans-v17-all-charsets-600.woff2 │ │ │ ├── open-sans-v17-all-charsets-600italic.woff2 │ │ │ ├── open-sans-v17-all-charsets-700.woff2 │ │ │ ├── open-sans-v17-all-charsets-700italic.woff2 │ │ │ ├── open-sans-v17-all-charsets-800.woff2 │ │ │ ├── open-sans-v17-all-charsets-800italic.woff2 │ │ │ ├── open-sans-v17-all-charsets-italic.woff2 │ │ │ ├── open-sans-v17-all-charsets-regular.woff2 │ │ │ └── source-code-pro-v11-all-charsets-500.woff2 │ │ ├── git │ │ │ ├── git.html │ │ │ ├── git1.html │ │ │ ├── git2.html │ │ │ ├── git3.html │ │ │ └── index.html │ │ ├── highlight.css │ │ ├── highlight.js │ │ ├── index.html │ │ ├── mark.min.js │ │ ├── overview.html │ │ ├── posix1 │ │ │ ├── admin.html │ │ │ ├── git1.html │ │ │ ├── index.html │ │ │ ├── install.html │ │ │ ├── shell.html │ │ │ └── ssh.html │ │ ├── posix2 │ │ │ ├── git2.html │ │ │ ├── index.html │ │ │ ├── permissions.html │ │ │ ├── pipes.html │ │ │ ├── regex.html │ │ │ └── shell.html │ │ ├── posix3 │ │ │ ├── git3.html │ │ │ ├── index.html │ │ │ ├── permissions.html │ │ │ ├── script.html │ │ │ └── stat.html │ │ ├── posix4 │ │ │ ├── c_io.html │ │ │ ├── concurrent.html │ │ │ ├── cpipe.html │ │ │ ├── final.html │ │ │ ├── index.html │ │ │ ├── posix_io.html │ │ │ └── stat.html │ │ ├── print.html │ │ ├── resources │ │ │ ├── Vagrantfile │ │ │ ├── after-merge.png │ │ │ ├── after-rebase.png │ │ │ ├── before-rebase.png │ │ │ ├── census.png │ │ │ ├── elections.png │ │ │ ├── pipe1.png │ │ │ ├── pipe2.png │ │ │ ├── pipe3.png │ │ │ ├── pr-after-rebase.png │ │ │ ├── pr-before-rebase.png │ │ │ └── uni-diagram.png │ │ ├── searcher.js │ │ ├── searchindex.js │ │ ├── searchindex.json │ │ └── tomorrow-night.css │ └── part2 │ │ ├── .nojekyll │ │ ├── 404.html │ │ ├── FontAwesome │ │ ├── css │ │ │ └── font-awesome.css │ │ └── fonts │ │ │ ├── FontAwesome.ttf │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ └── fontawesome-webfont.woff2 │ │ ├── app1 │ │ ├── ex.html │ │ ├── extent.html │ │ ├── index.html │ │ ├── lifecycle.html │ │ ├── setup.html │ │ └── walkthrough.html │ │ ├── app2 │ │ └── index.html │ │ ├── ayu-highlight.css │ │ ├── book.js │ │ ├── clipboard.min.js │ │ ├── cloud │ │ ├── cloud1.html │ │ └── cloud2.html │ │ ├── css │ │ ├── chrome.css │ │ ├── framework.html │ │ ├── general.css │ │ ├── index.html │ │ ├── print.css │ │ ├── rhythm1.png │ │ ├── rhythm2.png │ │ ├── text.html │ │ └── variables.css │ │ ├── cssgrid │ │ ├── curriculum.html │ │ ├── curriculum.png │ │ ├── index.html │ │ ├── intro.html │ │ ├── trees-medium.png │ │ ├── trees-wide.png │ │ └── trees.html │ │ ├── elasticlunr.min.js │ │ ├── encryption │ │ ├── index.html │ │ ├── openssl.html │ │ └── pgp.html │ │ ├── favicon.png │ │ ├── favicon.svg │ │ ├── fonts │ │ ├── OPEN-SANS-LICENSE.txt │ │ ├── SOURCE-CODE-PRO-LICENSE.txt │ │ ├── fonts.css │ │ ├── open-sans-v17-all-charsets-300.woff2 │ │ ├── open-sans-v17-all-charsets-300italic.woff2 │ │ ├── open-sans-v17-all-charsets-600.woff2 │ │ ├── open-sans-v17-all-charsets-600italic.woff2 │ │ ├── open-sans-v17-all-charsets-700.woff2 │ │ ├── open-sans-v17-all-charsets-700italic.woff2 │ │ ├── open-sans-v17-all-charsets-800.woff2 │ │ ├── open-sans-v17-all-charsets-800italic.woff2 │ │ ├── open-sans-v17-all-charsets-italic.woff2 │ │ ├── open-sans-v17-all-charsets-regular.woff2 │ │ └── source-code-pro-v11-all-charsets-500.woff2 │ │ ├── highlight.css │ │ ├── highlight.js │ │ ├── html5 │ │ ├── basic.html │ │ ├── index.html │ │ └── templates.html │ │ ├── http │ │ ├── explore.html │ │ ├── index.html │ │ ├── research.html │ │ ├── server.html │ │ └── setup.html │ │ ├── index.html │ │ ├── js │ │ ├── MyCoolApp.html │ │ ├── dynamic1.html │ │ ├── dynamic2.html │ │ ├── exercises.html │ │ ├── haha.json │ │ ├── haha2.json │ │ ├── index.html │ │ ├── single.html │ │ └── static.html │ │ ├── mark.min.js │ │ ├── overview.html │ │ ├── print.html │ │ ├── react │ │ ├── character.html │ │ ├── hello.html │ │ ├── index.html │ │ └── installing.html │ │ ├── resources │ │ ├── baseline.png │ │ ├── cattax.tar.gz │ │ ├── curriculum.html │ │ ├── examplepage.html │ │ ├── http-response │ │ ├── movie-search.tar.gz │ │ ├── page1.html │ │ ├── page2.html │ │ ├── reset.css │ │ ├── scrape.py │ │ ├── sometext.html │ │ └── trees.tar.gz │ │ ├── scrape │ │ ├── crawl.html │ │ ├── index.html │ │ └── soup.html │ │ ├── searcher.js │ │ ├── searchindex.js │ │ ├── searchindex.json │ │ └── tomorrow-night.css ├── lectures.md ├── organisation.md ├── repository.md ├── slides │ ├── 01-intro.md │ ├── 02-git.pdf │ ├── 03-shell.pdf │ ├── 04-debugging.pdf │ ├── 05-sql.pdf │ ├── 06-web.md │ ├── 07-css.md │ ├── 08-JavaScript.pdf │ ├── 08-JavaScript.pptx │ ├── 09-webscraping.md │ └── 10-encryption.pdf └── syllabus.md └── exercises ├── part1 ├── .gitignore ├── book.toml ├── build.bat ├── preprocessor.py ├── src │ ├── SUMMARY.md │ ├── build1 │ │ ├── exercise.md │ │ └── index.md │ ├── build2 │ │ ├── c.md │ │ ├── index.md │ │ ├── java.md │ │ ├── python.md │ │ └── spring.md │ ├── db1 │ │ ├── er-diagram.md │ │ ├── er2.md │ │ ├── setup.md │ │ └── sql-introduction.md │ ├── db2 │ │ ├── census.md │ │ ├── elections.md │ │ ├── explore-database.md │ │ └── normalforms.md │ ├── db3 │ │ ├── exercises.md │ │ └── sql-intermediate.md │ ├── db4 │ │ ├── hibernate.md │ │ ├── jdbc.md │ │ ├── sql-java.md │ │ └── sqlite.md │ ├── git │ │ ├── git.md │ │ └── index.md │ ├── overview.md │ ├── posix1 │ │ ├── admin.md │ │ ├── index.md │ │ ├── install.md │ │ └── ssh.md │ ├── posix2 │ │ ├── index.md │ │ ├── pipes.md │ │ ├── regex.md │ │ └── shell.md │ ├── posix3 │ │ ├── index.md │ │ ├── permissions.md │ │ └── script.md │ ├── posix4 │ │ ├── c_io.md │ │ ├── concurrent.md │ │ ├── cpipe.md │ │ ├── final.md │ │ ├── index.md │ │ ├── posix_io.md │ │ └── stat.md │ └── resources │ │ ├── Vagrantfile │ │ ├── after-merge.png │ │ ├── after-rebase.png │ │ ├── before-rebase.png │ │ ├── census.png │ │ ├── elections.png │ │ ├── pipe1.png │ │ ├── pipe2.png │ │ ├── pipe3.png │ │ ├── pr-after-rebase.png │ │ ├── pr-before-rebase.png │ │ └── uni-diagram.png └── theme │ └── css │ └── general.css └── part2 ├── .gitignore ├── book.toml ├── build.bat ├── preprocessor.py ├── src ├── SUMMARY.md ├── app1 │ ├── ex.md │ ├── extent.md │ ├── index.md │ ├── lifecycle.md │ ├── setup.md │ └── walkthrough.md ├── app2 │ └── index.md ├── cloud │ └── cloud1.md ├── css │ ├── framework.md │ ├── index.md │ ├── rhythm1.png │ ├── rhythm2.png │ └── text.md ├── cssgrid │ ├── curriculum.md │ ├── curriculum.png │ ├── index.md │ ├── intro.md │ ├── trees-medium.png │ ├── trees-wide.png │ └── trees.md ├── encryption │ ├── index.md │ ├── openssl.md │ └── pgp.md ├── html5 │ ├── basic.md │ ├── index.md │ └── templates.md ├── http │ ├── explore.md │ ├── index.md │ ├── research.md │ ├── server.md │ └── setup.md ├── js │ ├── MyCoolApp.md │ ├── dynamic1.md │ ├── dynamic2.md │ ├── exercises.md │ ├── index.md │ ├── single.md │ └── static.md ├── overview.md ├── resources │ ├── baseline.png │ ├── cattax.tar.gz │ ├── curriculum.html │ ├── examplepage.html │ ├── http-response │ ├── movie-search.tar.gz │ ├── page1.html │ ├── page2.html │ ├── reset.css │ ├── scrape.py │ ├── sometext.html │ └── trees.tar.gz └── scrape │ ├── crawl.md │ ├── index.md │ └── soup.md └── theme └── css └── general.css /.github/workflows/mdbook.yaml: -------------------------------------------------------------------------------- 1 | name: Build and deploy mdbook 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@master 14 | - name: Get mdbook 15 | uses: peaceiris/actions-mdbook@v1 16 | with: 17 | mdbook-version: 'latest' 18 | - name: Build the books and deploy 19 | run: | 20 | for f in exercises/*; do 21 | cd $f 22 | mdbook build 23 | mkdir -p ../../docs/$f 24 | cp -r book/* ../../docs/$f 25 | cd ../.. 26 | done 27 | - name: Commit 28 | uses: stefanzweifel/git-auto-commit-action@v4 29 | with: 30 | commit_message: "Build and deploy mdbook" 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # COMSM0085 Software Tools 2 | 3 | This is the repository for the MSc unit COMSM0085 Overview of Software Tools. 4 | 5 | If you are looking for the unit website, it is at https://cs-uob.github.io/COMSM0085. 6 | 7 | To clone this repository to your computer, type `git clone https://github.com/cs-uob/COMSM0085` in a terminal. 8 | This repository is public, so you do not need an account to do this. 9 | -------------------------------------------------------------------------------- /code/.gitignore: -------------------------------------------------------------------------------- 1 | target/ -------------------------------------------------------------------------------- /code/application/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | nbactions.xml 3 | src/main/resources/public 4 | src/main/resources/static -------------------------------------------------------------------------------- /code/application/client/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /code/application/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.15.1", 7 | "@testing-library/react": "^11.2.7", 8 | "@testing-library/user-event": "^12.8.3", 9 | "bootstrap": "^5.1.3", 10 | "react": "^17.0.2", 11 | "react-bootstrap": "^2.0.2", 12 | "react-dom": "^17.0.2", 13 | "react-scripts": "4.0.3", 14 | "web-vitals": "^1.1.2" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test", 20 | "eject": "react-scripts eject" 21 | }, 22 | "eslintConfig": { 23 | "extends": [ 24 | "react-app", 25 | "react-app/jest" 26 | ] 27 | }, 28 | "browserslist": { 29 | "production": [ 30 | ">0.2%", 31 | "not dead", 32 | "not op_mini all" 33 | ], 34 | "development": [ 35 | "last 1 chrome version", 36 | "last 1 firefox version", 37 | "last 1 safari version" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /code/application/client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/code/application/client/public/favicon.ico -------------------------------------------------------------------------------- /code/application/client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | React census sample application 12 | 13 | 14 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /code/application/client/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/code/application/client/public/logo192.png -------------------------------------------------------------------------------- /code/application/client/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/code/application/client/public/logo512.png -------------------------------------------------------------------------------- /code/application/client/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /code/application/client/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /code/application/client/src/App.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/code/application/client/src/App.css -------------------------------------------------------------------------------- /code/application/client/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /code/application/client/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /code/application/client/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /code/application/client/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /code/application/client/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /code/application/client/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /code/application/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.6.0 9 | 10 | 11 | uk.ac.bristol.cs 12 | application 13 | 0.0.1-SNAPSHOT 14 | application 15 | Demo project for Spring Boot 16 | 17 | 11 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-data-jpa 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-thymeleaf 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-web 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-devtools 36 | runtime 37 | true 38 | 39 | 40 | org.mariadb.jdbc 41 | mariadb-java-client 42 | runtime 43 | 44 | 45 | com.fasterxml.jackson.datatype 46 | jackson-datatype-hibernate5 47 | 2.13.0 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-starter-test 52 | test 53 | 54 | 55 | 56 | 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-maven-plugin 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/Application.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/ApplicationWebConfig.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application; 2 | 3 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.http.converter.HttpMessageConverter; 6 | import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; 7 | import com.fasterxml.jackson.databind.ObjectMapper; 8 | import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module; 9 | 10 | import java.util.List; 11 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 12 | 13 | @Configuration 14 | public class ApplicationWebConfig implements WebMvcConfigurer { 15 | 16 | /** 17 | * The purpose of this method is to make Jackson (that converts entities 18 | * to JSON) aware of Hibernate eager/lazy loading so you get neither a 19 | * N+1 problem nor a lazy loading exception. 20 | */ 21 | @Override 22 | public void extendMessageConverters(List> converters) { 23 | for (HttpMessageConverter converter : converters) { 24 | if (converter instanceof MappingJackson2HttpMessageConverter) { 25 | ObjectMapper mapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper(); 26 | mapper.registerModule(new Hibernate5Module()); 27 | } 28 | } 29 | } 30 | 31 | @Override 32 | public void addCorsMappings(CorsRegistry reg) { 33 | reg.addMapping("/api/**"); 34 | } 35 | } -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/NoSuchElementException.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.web.bind.annotation.ResponseStatus; 5 | 6 | @ResponseStatus(HttpStatus.NOT_FOUND) 7 | public class NoSuchElementException extends RuntimeException { 8 | 9 | private final Class cls; 10 | private final String id; 11 | 12 | public NoSuchElementException(Class cls, String id) { 13 | super("Could not find an instance of " + cls.getName() + " for id " + id); 14 | this.cls = cls; 15 | this.id = id; 16 | } 17 | 18 | public Class getCls() { return cls; } 19 | public String getId() { return id; } 20 | } -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/Templates.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application; 2 | 3 | import org.springframework.stereotype.Component; 4 | import org.thymeleaf.TemplateEngine; 5 | import org.thymeleaf.context.Context; 6 | import org.thymeleaf.spring5.SpringTemplateEngine; 7 | import org.thymeleaf.templatemode.TemplateMode; 8 | import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; 9 | 10 | @Component("templates") 11 | public class Templates { 12 | private final TemplateEngine engine; 13 | 14 | public Templates() { 15 | ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver(); 16 | resolver.setTemplateMode(TemplateMode.HTML); 17 | resolver.setPrefix("templates/"); 18 | engine = new SpringTemplateEngine(); 19 | engine.setTemplateResolver(resolver); 20 | } 21 | 22 | public String render(String template, Context c) { 23 | return this.engine.process(template, c); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/controller/CountryController.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application.controller; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.web.bind.annotation.RestController; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | 9 | import uk.ac.bristol.cs.application.model.Country; 10 | import uk.ac.bristol.cs.application.model.ModelClass; 11 | import uk.ac.bristol.cs.application.repository.CountryRepository; 12 | 13 | @RestController 14 | public class CountryController { 15 | 16 | private final CountryRepository repository; 17 | 18 | CountryController(CountryRepository repository) { 19 | this.repository = repository; 20 | } 21 | 22 | @GetMapping("/api/countries") 23 | List getAllCountries() { 24 | return repository.findAll(); 25 | } 26 | 27 | @GetMapping(path = "/api/country/{id}", produces = "application/json") 28 | String getCountryById(@PathVariable String id) { 29 | Country c = repository.getWithChildren(id); 30 | return ModelClass.renderJSON(c, Country.class, id); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/controller/CountyController.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application.controller; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.web.bind.annotation.RestController; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | 9 | import uk.ac.bristol.cs.application.model.County; 10 | import uk.ac.bristol.cs.application.model.ModelClass; 11 | import uk.ac.bristol.cs.application.repository.CountyRepository; 12 | 13 | @RestController 14 | public class CountyController { 15 | 16 | private final CountyRepository repository; 17 | 18 | CountyController(CountyRepository repository) { 19 | this.repository = repository; 20 | } 21 | 22 | @GetMapping("/api/counties") 23 | List getAllCounties() { 24 | return repository.findAll(); 25 | } 26 | 27 | @GetMapping(path = "/api/county/{id}", produces = "application/json") 28 | String getCountyById(@PathVariable String id) { 29 | County c = repository.getWithChildren(id); 30 | return ModelClass.renderJSON(c, County.class, id); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/controller/ErrorHandler.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.http.HttpHeaders; 5 | import org.springframework.http.ResponseEntity; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | import org.thymeleaf.context.Context; 9 | 10 | import uk.ac.bristol.cs.application.NoSuchElementException; 11 | import uk.ac.bristol.cs.application.Templates; 12 | 13 | @ControllerAdvice 14 | public class ErrorHandler { 15 | 16 | @Autowired 17 | Templates templates; 18 | 19 | @ExceptionHandler(NoSuchElementException.class) 20 | public ResponseEntity handle404(NoSuchElementException e) { 21 | Context c = new Context(); 22 | c.setVariable("cls", e.getCls()); 23 | c.setVariable("id", e.getId()); 24 | return ResponseEntity 25 | .status(404) 26 | .header(HttpHeaders.CONTENT_TYPE, "text/html") 27 | .body(templates.render("404.html", c)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/controller/RegionController.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application.controller; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.web.bind.annotation.RestController; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import uk.ac.bristol.cs.application.model.ModelClass; 9 | 10 | import uk.ac.bristol.cs.application.model.Region; 11 | import uk.ac.bristol.cs.application.repository.RegionRepository; 12 | 13 | @RestController 14 | public class RegionController { 15 | 16 | private final RegionRepository repository; 17 | 18 | RegionController(RegionRepository repository) { 19 | this.repository = repository; 20 | } 21 | 22 | @GetMapping("/api/regions") 23 | List getAllRegions() { 24 | return repository.findAll(); 25 | } 26 | 27 | @GetMapping(path="/api/region/{id}", produces="application/json") 28 | String getRegionById(@PathVariable String id) { 29 | Region r = repository.findByIdFull(id); 30 | return ModelClass.renderJSON(r, Region.class, id); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/controller/WardController.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application.controller; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.web.bind.annotation.RestController; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import uk.ac.bristol.cs.application.NoSuchElementException; 9 | 10 | import uk.ac.bristol.cs.application.model.Ward; 11 | import uk.ac.bristol.cs.application.repository.WardRepository; 12 | 13 | @RestController 14 | public class WardController { 15 | 16 | private final WardRepository repository; 17 | 18 | WardController(WardRepository repository) { 19 | this.repository = repository; 20 | } 21 | 22 | @GetMapping("/api/wards") 23 | List getAllWards() { 24 | return repository.findAll(); 25 | } 26 | 27 | @GetMapping("/api/wards/full") 28 | List getAllWardsFull() { 29 | return repository.fetchAllFull(); 30 | } 31 | 32 | @GetMapping("/api/ward/{id}") 33 | Ward getWardById(@PathVariable String id) { 34 | return repository.findById(id) 35 | .orElseThrow(() -> new NoSuchElementException(Ward.class, id)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/model/Country.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonView; 4 | import java.io.Serializable; 5 | import java.util.List; 6 | import java.util.Objects; 7 | import javax.persistence.Entity; 8 | import javax.persistence.FetchType; 9 | import javax.persistence.Id; 10 | import javax.persistence.OneToMany; 11 | 12 | @Entity 13 | public class Country extends ModelClass implements Serializable { 14 | private @Id String code; 15 | private String name; 16 | 17 | @OneToMany(fetch = FetchType.LAZY, mappedBy = "parent") 18 | @JsonView(Country.class) 19 | private List regions; 20 | 21 | public String getName() { return name; } 22 | public String getCode() { return code; } 23 | public List getRegions() { return regions; } 24 | 25 | public void setName(String name) { this.name = name; } 26 | public void setCode(String code) { this.code = code; } 27 | public void setRegions(List regions) { this.regions = regions; } 28 | 29 | @Override 30 | public int hashCode() { 31 | int hash = 3; 32 | hash = 83 * hash + Objects.hashCode(this.code); 33 | hash = 83 * hash + Objects.hashCode(this.name); 34 | return hash; 35 | } 36 | 37 | @Override 38 | public boolean equals(Object obj) { 39 | if (this == obj) { 40 | return true; 41 | } 42 | if (obj == null) { 43 | return false; 44 | } 45 | if (getClass() != obj.getClass()) { 46 | return false; 47 | } 48 | final Country other = (Country) obj; 49 | return Objects.equals(this.name, other.name); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/model/County.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonView; 4 | import java.io.Serializable; 5 | import java.util.List; 6 | import java.util.Objects; 7 | import javax.persistence.Entity; 8 | import javax.persistence.FetchType; 9 | import javax.persistence.Id; 10 | import javax.persistence.JoinColumn; 11 | import javax.persistence.ManyToOne; 12 | import javax.persistence.OneToMany; 13 | 14 | @Entity 15 | public class County extends ModelClass implements Serializable { 16 | private @Id String code; 17 | private String name; 18 | @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name="parent") 19 | @JsonView(County.class) 20 | private Region parent; 21 | @OneToMany(fetch = FetchType.LAZY, mappedBy = "parent") 22 | @JsonView(County.class) 23 | private List wards; 24 | 25 | public String getName() { return name; } 26 | public String getCode() { return code; } 27 | public Region getParent() { return parent; } 28 | public String getParentCode() { return parent.getCode(); } 29 | public List getWards() { return wards; } 30 | 31 | public void setName(String name) { this.name = name; } 32 | public void setCode(String code) { this.code = code; } 33 | public void setParent(Region parent) { this.parent = parent; } 34 | public void setWards(List wards) { this.wards = wards; } 35 | 36 | @Override 37 | public int hashCode() { 38 | int hash = 3; 39 | hash = 61 * hash + Objects.hashCode(this.code); 40 | hash = 61 * hash + Objects.hashCode(this.name); 41 | return hash; 42 | } 43 | 44 | @Override 45 | public boolean equals(Object obj) { 46 | if (this == obj) { 47 | return true; 48 | } 49 | if (obj == null) { 50 | return false; 51 | } 52 | if (getClass() != obj.getClass()) { 53 | return false; 54 | } 55 | final County other = (County) obj; 56 | return Objects.equals(this.name, other.name); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/model/ModelClass.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application.model; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import uk.ac.bristol.cs.application.NoSuchElementException; 6 | 7 | /** 8 | * This class is an abstract base class of our model classes so that 9 | * we can get extents on views correct. 10 | */ 11 | public abstract class ModelClass { 12 | public static String renderJSON(T element, Class cls, String id) { 13 | if (element == null) { 14 | throw new NoSuchElementException(cls, id); 15 | } 16 | try { 17 | return new ObjectMapper() 18 | .writerWithView(cls) 19 | .writeValueAsString(element); 20 | } catch (JsonProcessingException e) { 21 | throw new RuntimeException(e); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/model/Region.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonView; 4 | import java.io.Serializable; 5 | import java.util.List; 6 | import java.util.Objects; 7 | import javax.persistence.Entity; 8 | import javax.persistence.FetchType; 9 | import javax.persistence.Id; 10 | import javax.persistence.JoinColumn; 11 | import javax.persistence.ManyToOne; 12 | import javax.persistence.OneToMany; 13 | 14 | @Entity 15 | public class Region extends ModelClass implements Serializable { 16 | private @Id String code; 17 | private String name; 18 | @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name="parent") 19 | @JsonView(Region.class) 20 | private Country parent; 21 | 22 | @OneToMany(fetch = FetchType.LAZY, mappedBy = "parent") 23 | @JsonView(Region.class) 24 | private List counties; 25 | 26 | public String getName() { return name; } 27 | public String getCode() { return code; } 28 | public Country getParent() { return parent; } 29 | public String getParentCode() { return parent.getCode(); } 30 | public List getCounties() { return counties; } 31 | 32 | public void setName(String name) { this.name = name; } 33 | public void setCode(String code) { this.code = code; } 34 | public void setParent(Country parent) { this.parent = parent; } 35 | public void setCounties(List counties) { this.counties = counties; } 36 | 37 | @Override 38 | public int hashCode() { 39 | int hash = 7; 40 | hash = 53 * hash + Objects.hashCode(this.code); 41 | hash = 53 * hash + Objects.hashCode(this.name); 42 | return hash; 43 | } 44 | 45 | @Override 46 | public boolean equals(Object obj) { 47 | if (this == obj) { 48 | return true; 49 | } 50 | if (obj == null) { 51 | return false; 52 | } 53 | if (getClass() != obj.getClass()) { 54 | return false; 55 | } 56 | final Region other = (Region) obj; 57 | return Objects.equals(this.code, other.code); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/model/Statistic.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application.model; 2 | 3 | public class Statistic { 4 | private String code; 5 | private int occId; 6 | private String occName; 7 | private int men; 8 | private int women; 9 | 10 | public String getCode() { 11 | return code; 12 | } 13 | 14 | public void setCode(String code) { 15 | this.code = code; 16 | } 17 | 18 | public int getOccId() { 19 | return occId; 20 | } 21 | 22 | public void setOccId(int occId) { 23 | this.occId = occId; 24 | } 25 | 26 | public String getOccName() { 27 | return occName; 28 | } 29 | 30 | public void setOccName(String occName) { 31 | this.occName = occName; 32 | } 33 | 34 | public int getMen() { 35 | return men; 36 | } 37 | 38 | public void setMen(int men) { 39 | this.men = men; 40 | } 41 | 42 | public int getWomen() { 43 | return women; 44 | } 45 | 46 | public void setWomen(int women) { 47 | this.women = women; 48 | } 49 | 50 | public int getTotal() { 51 | return women + men; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/model/Ward.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonView; 4 | import javax.persistence.Entity; 5 | import javax.persistence.Id; 6 | import javax.persistence.ManyToOne; 7 | import javax.persistence.JoinColumn; 8 | import javax.persistence.FetchType; 9 | 10 | import java.io.Serializable; 11 | import java.util.Objects; 12 | 13 | @Entity 14 | public class Ward extends ModelClass implements Serializable { 15 | @Id private String code; 16 | private String name; 17 | 18 | @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name="parent") 19 | @JsonView(Ward.class) 20 | private County parent; 21 | 22 | public String getName() { return name; } 23 | public String getCode() { return code; } 24 | public County getParent() { return parent; } 25 | public String getParentCode() { 26 | if (parent == null) { 27 | return null; 28 | } else { 29 | return parent.getCode(); 30 | } 31 | } 32 | 33 | public void setName(String name) { this.name = name; } 34 | public void setCode(String code) { this.code = code; } 35 | public void setParent(County parent) { this.parent = parent; } 36 | 37 | @Override 38 | public int hashCode() { 39 | int hash = 3; 40 | hash = 37 * hash + Objects.hashCode(this.code); 41 | hash = 37 * hash + Objects.hashCode(this.name); 42 | return hash; 43 | } 44 | 45 | @Override 46 | public boolean equals(Object obj) { 47 | if (this == obj) { 48 | return true; 49 | } 50 | if (obj == null) { 51 | return false; 52 | } 53 | if (getClass() != obj.getClass()) { 54 | return false; 55 | } 56 | final Ward other = (Ward) obj; 57 | return Objects.equals(this.code, other.code); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/repository/CountryRepository.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.data.jpa.repository.Query; 5 | 6 | import uk.ac.bristol.cs.application.model.Country; 7 | 8 | public interface CountryRepository extends JpaRepository { 9 | 10 | @Query("SELECT c FROM Country c LEFT JOIN FETCH c.regions WHERE c.code = ?1") 11 | Country getWithChildren(String id); 12 | } -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/repository/CountyRepository.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application.repository; 2 | 3 | import java.util.List; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.Query; 6 | 7 | import uk.ac.bristol.cs.application.model.County; 8 | 9 | public interface CountyRepository extends JpaRepository { 10 | @Query("FROM County c JOIN FETCH c.parent JOIN FETCH c.parent.parent") 11 | List fetchAllFull(); 12 | 13 | @Query("SELECT c FROM County c JOIN FETCH c.parent LEFT JOIN FETCH c.wards WHERE c.code = ?1") 14 | County getWithChildren(String id); 15 | } -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/repository/RegionRepository.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application.repository; 2 | 3 | import java.util.List; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.Query; 6 | 7 | import uk.ac.bristol.cs.application.model.Region; 8 | 9 | public interface RegionRepository extends JpaRepository { 10 | 11 | @Query("SELECT r FROM Region r JOIN FETCH r.parent LEFT JOIN FETCH r.counties WHERE r.id = ?1") 12 | Region findByIdFull(String id); 13 | 14 | @Query("FROM Region r JOIN FETCH r.parent") 15 | List fetchAllFull(); 16 | } -------------------------------------------------------------------------------- /code/application/src/main/java/uk/ac/bristol/cs/application/repository/WardRepository.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application.repository; 2 | 3 | import java.util.List; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.Query; 6 | 7 | import uk.ac.bristol.cs.application.model.Ward; 8 | 9 | public interface WardRepository extends JpaRepository { 10 | 11 | // JOIN ALL THE THINGS 12 | @Query("FROM Ward w JOIN FETCH w.parent JOIN FETCH w.parent.parent JOIN FETCH w.parent.parent.parent") 13 | List fetchAllFull(); 14 | } -------------------------------------------------------------------------------- /code/application/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8000 2 | 3 | spring.datasource.url=jdbc:mariadb://localhost:3306/census 4 | spring.datasource.username=vagrant 5 | spring.datasource.password= 6 | spring.datasource.driver-class-name=org.mariadb.jdbc.Driver 7 | 8 | spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect 9 | spring.jpa.show-sql=true 10 | spring.jpa.open-in-view=false 11 | 12 | spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl -------------------------------------------------------------------------------- /code/application/src/main/resources/templates/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 404 error 5 | 6 | 7 | 8 |

404 Error

9 |

The following element could not be found:

10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
Class:
ID:
20 | 21 | 22 | -------------------------------------------------------------------------------- /code/application/src/test/java/uk/ac/bristol/cs/application/ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.application; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /code/censusexplorer/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 4.0.0 6 | 7 | 8 | org.springframework.boot 9 | spring-boot-starter-parent 10 | 2.4.5 11 | 12 | 13 | 14 | uk.ac.bristol.cs 15 | census-explorer 16 | 0.1 17 | 18 | census-explorer 19 | 20 | 21 | UTF-8 22 | 1.8 23 | 1.8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-web 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-data-jpa 35 | 36 | 37 | org.mariadb.jdbc 38 | mariadb-java-client 39 | 40 | 41 | net.java.dev.jna 42 | jna 43 | 5.6.0 44 | 45 | 46 | net.java.dev.jna 47 | jna-platform 48 | 5.6.0 49 | 50 | 51 | org.hibernate 52 | hibernate-core 53 | 5.4.27.Final 54 | 55 | 56 | org.thymeleaf 57 | thymeleaf 58 | 59 | 60 | 61 | 62 | 63 | 64 | org.springframework.boot 65 | spring-boot-maven-plugin 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/java/uk/ac/bristol/cs/censusexplorer/Application.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.censusexplorer; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | public static void main(String[] args) { 9 | SpringApplication.run(Application.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/java/uk/ac/bristol/cs/censusexplorer/Templates.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.censusexplorer; 2 | 3 | import org.springframework.stereotype.Component; 4 | import org.thymeleaf.TemplateEngine; 5 | import org.thymeleaf.templatemode.TemplateMode; 6 | import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; 7 | 8 | @Component("templates") 9 | public class Templates { 10 | private final TemplateEngine engine; 11 | 12 | public Templates() { 13 | ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver(); 14 | resolver.setTemplateMode(TemplateMode.HTML); 15 | resolver.setPrefix("templates/"); 16 | engine = new TemplateEngine(); 17 | engine.setTemplateResolver(resolver); 18 | } 19 | 20 | public TemplateEngine engine() { 21 | return this.engine; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/java/uk/ac/bristol/cs/censusexplorer/controller/CountryController.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.censusexplorer.controller; 2 | 3 | import java.util.List; 4 | import org.springframework.web.bind.annotation.RestController; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import org.thymeleaf.context.Context; 9 | import uk.ac.bristol.cs.censusexplorer.Templates; 10 | 11 | import uk.ac.bristol.cs.censusexplorer.repository.CountryRepository; 12 | import uk.ac.bristol.cs.censusexplorer.model.Country; 13 | 14 | @RestController 15 | public class CountryController { 16 | 17 | @Autowired 18 | public CountryRepository repository; 19 | 20 | @Autowired 21 | public Templates templates; 22 | 23 | @GetMapping("/country/count") 24 | public String countCountries() { 25 | long count = repository.count(); 26 | return "There are " + count + " countries in the database."; 27 | } 28 | 29 | @GetMapping("/country/all") 30 | public String displayCountries() { 31 | List countries = repository.findAll(); 32 | Context c = new Context(); 33 | c.setVariable("countries", countries); 34 | return templates.engine().process("country_list.html", c); 35 | } 36 | 37 | @GetMapping("/country/show/{id}") 38 | public String showCountry(@PathVariable String id) { 39 | Country c = repository.getOne(id); 40 | Context cx = new Context(); 41 | cx.setVariable("country", c); 42 | return templates.engine().process("country_show.html", cx); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/java/uk/ac/bristol/cs/censusexplorer/controller/CountyController.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.censusexplorer.controller; 2 | 3 | import java.util.List; 4 | import org.springframework.web.bind.annotation.RestController; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import org.thymeleaf.context.Context; 9 | import uk.ac.bristol.cs.censusexplorer.Templates; 10 | 11 | import uk.ac.bristol.cs.censusexplorer.repository.CountyRepository; 12 | import uk.ac.bristol.cs.censusexplorer.model.County; 13 | 14 | @RestController 15 | public class CountyController { 16 | 17 | @Autowired 18 | public CountyRepository repository; 19 | 20 | @Autowired 21 | public Templates templates; 22 | 23 | @GetMapping("/county/count") 24 | public String countCounties() { 25 | long count = repository.count(); 26 | return "There are " + count + " counties in the database."; 27 | } 28 | 29 | @GetMapping("/county/show/{id}") 30 | public String showCounty(@PathVariable String id) { 31 | County c = repository.getOne(id); 32 | Context cx = new Context(); 33 | cx.setVariable("county", c); 34 | return templates.engine().process("county_show.html", cx); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/java/uk/ac/bristol/cs/censusexplorer/controller/MainController.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.censusexplorer.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.web.bind.annotation.RestController; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.thymeleaf.context.Context; 7 | import uk.ac.bristol.cs.censusexplorer.Templates; 8 | 9 | @RestController 10 | public class MainController { 11 | 12 | @Autowired 13 | private Templates templates; 14 | 15 | @GetMapping("/") 16 | public String mainPage() { 17 | Context c = new Context(); 18 | return templates.engine().process("index.html", c); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/java/uk/ac/bristol/cs/censusexplorer/controller/RegionController.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.censusexplorer.controller; 2 | 3 | import java.util.List; 4 | import org.springframework.web.bind.annotation.RestController; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import org.thymeleaf.context.Context; 9 | import uk.ac.bristol.cs.censusexplorer.Templates; 10 | 11 | import uk.ac.bristol.cs.censusexplorer.repository.RegionRepository; 12 | import uk.ac.bristol.cs.censusexplorer.model.Region; 13 | 14 | @RestController 15 | public class RegionController { 16 | 17 | @Autowired 18 | public RegionRepository repository; 19 | 20 | @Autowired 21 | public Templates templates; 22 | 23 | @GetMapping("/region/count") 24 | public String countRegions() { 25 | long count = repository.count(); 26 | return "There are " + count + " regions in the database."; 27 | } 28 | 29 | @GetMapping("/region/all") 30 | public String displayCountries() { 31 | List regions = repository.findAll(); 32 | Context c = new Context(); 33 | c.setVariable("regions", regions); 34 | return templates.engine().process("region_list.html", c); 35 | } 36 | 37 | @GetMapping("/region/show/{id}") 38 | public String showRegion(@PathVariable String id) { 39 | Region c = repository.getOne(id); 40 | Context cx = new Context(); 41 | cx.setVariable("region", c); 42 | return templates.engine().process("region_show.html", cx); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/java/uk/ac/bristol/cs/censusexplorer/model/Country.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.censusexplorer.model; 2 | 3 | import java.util.List; 4 | import javax.persistence.Entity; 5 | import javax.persistence.Table; 6 | import javax.persistence.Id; 7 | import javax.persistence.OneToMany; 8 | 9 | @Entity 10 | @Table(name="Country") 11 | public class Country { 12 | @Id private String code; 13 | private String name; 14 | @OneToMany(mappedBy = "parent") private List regions; 15 | 16 | public String getCode() { 17 | return code; 18 | } 19 | 20 | public void setCode(String code) { 21 | this.code = code; 22 | } 23 | 24 | public String getName() { 25 | return name; 26 | } 27 | 28 | public void setName(String name) { 29 | this.name = name; 30 | } 31 | 32 | public List getRegions() { 33 | return regions; 34 | } 35 | 36 | public void setRegions(List regions) { 37 | this.regions = regions; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/java/uk/ac/bristol/cs/censusexplorer/model/County.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.censusexplorer.model; 2 | 3 | import java.util.List; 4 | import javax.persistence.Entity; 5 | import javax.persistence.Table; 6 | import javax.persistence.Id; 7 | import javax.persistence.JoinColumn; 8 | import javax.persistence.ManyToOne; 9 | import javax.persistence.OneToMany; 10 | 11 | @Entity 12 | @Table(name="County") 13 | public class County { 14 | @Id private String code; 15 | private String name; 16 | @ManyToOne @JoinColumn(name = "parent") private Region parent; 17 | @ManyToOne @JoinColumn(name = "country") private Country country; 18 | 19 | public String getCode() { 20 | return code; 21 | } 22 | 23 | public void setCode(String code) { 24 | this.code = code; 25 | } 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | 31 | public void setName(String name) { 32 | this.name = name; 33 | } 34 | 35 | public Region getParent() { 36 | return parent; 37 | } 38 | 39 | public void setParent(Region parent) { 40 | this.parent = parent; 41 | } 42 | 43 | public Country getCountry() { 44 | return country; 45 | } 46 | 47 | public void setCountry(Country country) { 48 | this.country = country; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/java/uk/ac/bristol/cs/censusexplorer/model/Region.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.censusexplorer.model; 2 | 3 | import java.util.List; 4 | import javax.persistence.Entity; 5 | import javax.persistence.Table; 6 | import javax.persistence.Id; 7 | import javax.persistence.JoinColumn; 8 | import javax.persistence.ManyToOne; 9 | import javax.persistence.OneToMany; 10 | 11 | @Entity 12 | @Table(name="Region") 13 | public class Region { 14 | @Id private String code; 15 | private String name; 16 | @ManyToOne @JoinColumn(name = "parent") private Country parent; 17 | @OneToMany(mappedBy = "parent") private List counties; 18 | 19 | public String getCode() { 20 | return code; 21 | } 22 | 23 | public void setCode(String code) { 24 | this.code = code; 25 | } 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | 31 | public void setName(String name) { 32 | this.name = name; 33 | } 34 | 35 | public Country getParent() { 36 | return parent; 37 | } 38 | 39 | public void setParent(Country parent) { 40 | this.parent = parent; 41 | } 42 | 43 | public List getCounties() { 44 | return counties; 45 | } 46 | 47 | public void setCounties(List counties) { 48 | this.counties = counties; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/java/uk/ac/bristol/cs/censusexplorer/repository/CountryRepository.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.censusexplorer.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.stereotype.Repository; 5 | 6 | import uk.ac.bristol.cs.censusexplorer.model.Country; 7 | 8 | @Repository 9 | public interface CountryRepository extends JpaRepository{ 10 | 11 | } 12 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/java/uk/ac/bristol/cs/censusexplorer/repository/CountyRepository.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.censusexplorer.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.stereotype.Repository; 5 | 6 | import uk.ac.bristol.cs.censusexplorer.model.County; 7 | 8 | @Repository 9 | public interface CountyRepository extends JpaRepository{ 10 | 11 | } 12 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/java/uk/ac/bristol/cs/censusexplorer/repository/RegionRepository.java: -------------------------------------------------------------------------------- 1 | package uk.ac.bristol.cs.censusexplorer.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.stereotype.Repository; 5 | 6 | import uk.ac.bristol.cs.censusexplorer.model.Region; 7 | 8 | @Repository 9 | public interface RegionRepository extends JpaRepository{ 10 | 11 | } 12 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.jpa.show-sql=true 2 | spring.jpa.properties.hibernate.format_sql=true 3 | spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl 4 | spring.datasource.url=jdbc:mariadb://localhost:3306/census?user=vagrant -------------------------------------------------------------------------------- /code/censusexplorer/src/main/resources/static/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 8 | a, abbr, acronym, address, big, cite, code, 9 | del, dfn, em, img, ins, kbd, q, s, samp, 10 | small, strike, strong, sub, sup, tt, var, 11 | b, u, i, center, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, embed, 16 | figure, figcaption, footer, header, hgroup, 17 | menu, nav, output, ruby, section, summary, 18 | time, mark, audio, video { 19 | margin: 0; 20 | padding: 0; 21 | border: 0; 22 | font-size: 100%; 23 | font: inherit; 24 | vertical-align: baseline; 25 | } 26 | /* HTML5 display-role reset for older browsers */ 27 | article, aside, details, figcaption, figure, 28 | footer, header, hgroup, menu, nav, section { 29 | display: block; 30 | } 31 | body { 32 | line-height: 1; 33 | } 34 | ol, ul { 35 | list-style: none; 36 | } 37 | blockquote, q { 38 | quotes: none; 39 | } 40 | blockquote:before, blockquote:after, 41 | q:before, q:after { 42 | content: ''; 43 | content: none; 44 | } 45 | table { 46 | border-collapse: collapse; 47 | border-spacing: 0; 48 | } 49 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/resources/static/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: grid; 3 | grid-template-columns: 15rem auto; 4 | grid-template-rows: 5em auto; 5 | font-family: sans-serif; 6 | } 7 | 8 | nav { 9 | background-color: #006055; /* contrast ratio 7.48 */ 10 | color: white; 11 | grid-column-start: 1; 12 | grid-column-end: 2; 13 | grid-row-start: 1; 14 | grid-row-end: 3; 15 | 16 | height: 100vh; 17 | overflow: hidden; 18 | box-sizing: border-box; 19 | 20 | padding: 5px; 21 | } 22 | 23 | nav hr { 24 | border: 0; 25 | border-top: 1px solid white; 26 | } 27 | 28 | nav h1, nav h2 { 29 | text-align: center; 30 | color: white; 31 | } 32 | 33 | nav a { 34 | color: white; 35 | } 36 | 37 | header { 38 | grid-column-start: 2; 39 | grid-column-end: 3; 40 | grid-row-start: 1; 41 | grid-row-end: 2; 42 | display: flex; 43 | align-items: center; 44 | 45 | padding: 10px; 46 | 47 | border-bottom: 1px solid #006055; 48 | } 49 | 50 | main { 51 | grid-column-start: 2; 52 | grid-column-end: 3; 53 | grid-row-start: 2; 54 | grid-row-end: 3; 55 | 56 | padding: 10px; 57 | } 58 | 59 | h1 { 60 | font-weight: bold; 61 | font-size: 144%; 62 | color: #006055; 63 | } 64 | 65 | h2 { 66 | font-weight: bold; 67 | font-size: 120%; 68 | color: #006055; 69 | } 70 | 71 | main h1, main h2 { 72 | margin-top: 4ex; 73 | margin-bottom: 1ex; 74 | } 75 | 76 | main h2:first-child { 77 | margin-top: 0; 78 | } 79 | 80 | p { 81 | margin-top: 1ex; 82 | } 83 | 84 | p.separator { 85 | padding-top: 12px; 86 | } 87 | 88 | ul li { 89 | list-style-type: square; 90 | list-style-position: inside; 91 | padding-bottom: 0.5ex; 92 | } 93 | 94 | em { 95 | font-weight: bold; 96 | } 97 | 98 | em.blocklabel { 99 | float: left; 100 | min-width: 6em; 101 | } 102 | 103 | main a { 104 | color: #006055; 105 | } 106 | 107 | a.nodecorate { 108 | text-decoration: none; 109 | } 110 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/resources/templates/country_list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |

List of Countries

8 |
9 |
10 |
    11 |
  • ()
  • 12 |
13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/resources/templates/country_show.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |

8 |
9 |
10 |

Country details:

11 |

Name:

12 |

ID:

13 |

Regions in this country:

14 |
    15 |
  • 16 | 17 | () 18 |
  • 19 |
20 |

21 |

Back to countries list

22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/resources/templates/county_show.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |

8 |
9 |
10 |

County details:

11 |

Name:

12 |

ID:

13 |

Part of: ()

14 |

Wards in this county:

15 |

TO DO

16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |

Census Explorer

8 |
9 |
10 |

11 | Choose an item in the left menu. 12 |

13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/resources/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 18 |
19 | header 20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/resources/templates/region_list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |

List of Regions

8 |
9 |
10 |
    11 |
  • ()
  • 12 |
13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /code/censusexplorer/src/main/resources/templates/region_show.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |

8 |
9 |
10 |

Region details:

11 |

Name:

12 |

ID:

13 |

Part of: ()

14 |

Counties in this region:

15 |
    16 |
  • 17 | 18 | () 19 |
  • 20 |
21 |

22 |

Back to regions list

23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /code/databases/sample-data.sql: -------------------------------------------------------------------------------- 1 | -- to be run as root 2 | 3 | -- create the default user 'vagrant' so 'mysql' on its own works 4 | CREATE USER 'vagrant'@'localhost'; 5 | -- database for people to play around with 6 | CREATE DATABASE data; 7 | GRANT ALL ON data.* to 'vagrant'@'localhost'; 8 | -- sample data, these are read-only by default to prevent accidents 9 | CREATE DATABASE census; 10 | GRANT SELECT ON census.* to 'vagrant'@'localhost'; 11 | CREATE DATABASE elections; 12 | GRANT SELECT ON elections.* to 'vagrant'@'localhost'; 13 | 14 | FLUSH PRIVILEGES; 15 | 16 | -- load the data 17 | USE census; 18 | source /vagrant/sampledata/census/setup.sql; 19 | source /vagrant/sampledata/census/import.sql; 20 | USE elections; 21 | source /vagrant/sampledata/elections/setup.sql; 22 | source /vagrant/sampledata/elections/import.sql; 23 | 24 | -------------------------------------------------------------------------------- /code/databases/secure-setup.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Does the equivalent of mysql_secure_installation, but doesn't prompt 3 | the user each time. This lets us run the script as part of vagrant setup. 4 | */ 5 | 6 | UPDATE mysql.user SET Password=PASSWORD('BA/458cR-5p.') WHERE User='root'; 7 | DELETE FROM mysql.user WHERE User=''; 8 | DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1'); 9 | DROP DATABASE IF EXISTS test; 10 | DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%'; 11 | FLUSH PRIVILEGES; 12 | -------------------------------------------------------------------------------- /code/debugging/stackcalc.txt: -------------------------------------------------------------------------------- 1 | Stack Calculator Documentation 2 | 3 | This program implements a simple RPN/stack calculator. You can use the digits 0-9 and the 4 | four operators "+-*/". You can use spaces between numbers and operators, and you must use 5 | spaces to separate numbers e.g. "12" is the number 12 but "1 2" is the number 1 followed 6 | by the number 2. The strings "1 2+" and "1 2 +" and any variation on these that adds more 7 | spaces have exactly the same effect. 8 | 9 | The program reads tokens (numbers or operators) from left to right and 10 | - for every number read, pushes it onto the stack 11 | - for every operator read, pops two values off the stack, operates on them and pushes 12 | the result back on the stack. 13 | An expression is valid if, at the end of evaluating, there is exactly one value on the 14 | stack and there was never an operator encountered while there were fewer than two values 15 | on the stack. 16 | 17 | Terminate the program by closing standard input (e.g. Control+D on a fresh line on the 18 | terminal.) 19 | 20 | Compile with "-lreadline". You might need to "sudo apt-get install libreadline-dev" first. 21 | 22 | For example, 23 | 24 | "1 2 +" -> 3.0000 (all output and calcuations are done on doubles). 25 | "1 2 + 4 *" -> 12.0000 (this is (1+2)*4, note how RPN never needs brackets). 26 | "1" -> 1.0000 (a number on its own just evaluates to itself). 27 | "01" -> 1.0000 (leading zeroes are ignored). 28 | 29 | Errors 30 | 31 | If the stack limit of 10 is exceeded, you get "Error, stack full". 32 | 33 | "1 2 3 4 5 6 7 8 9 0 1" -> Error 34 | 35 | If you put an operator when there are fewer than two values on the stack, you get the 36 | message "Error, operator on empty stack." 37 | 38 | "+ 1" -> Error 39 | "1 + 1" -> Error 40 | "1 1 +" -> 2.0000 (not an error) 41 | "1 +" -> Error 42 | "1 2 + 3 -" -> 0.0000 (not an error) 43 | "1 2 + - 3" -> Error (the minus appears when there is only one value on the stack) 44 | 45 | Any character other than the ones specified above is an error. Note that we don't 46 | need to handle newlines, because readline() strips them for us, and we stop on 47 | reaching the end of the string. 48 | 49 | If there is no value or more than one value on the stack at the end of the line, 50 | you get "Error, expected exactly one value but got #." where # is the number of 51 | values on the stack at the end. 52 | 53 | "" -> Error 54 | "1 2" -> Error 55 | "1" -> 1.0000 (not an error, although not particularly insightful either) 56 | "1 2 + 3" -> Error 57 | 58 | Division by zero produces an inf or -inf double value, inf/inf or 0/0 produces NaN. 59 | These are not errors as far as the program is concerned. 60 | -------------------------------------------------------------------------------- /code/javascript/Trees.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | /* Loads the first argument as a file, removes all punctuation, 4 | and computes the frequency of each word. */ 5 | let ws = null; 6 | fs.readFile(process.argv[2], 'utf8', function (err, data) { 7 | if (err) { 8 | return console.log("error: " + err); 9 | } 10 | const punct = /[!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]/g; 11 | ws = data.replace(punct, '').trim().split(/\s+/); 12 | }); 13 | 14 | count(ws); 15 | 16 | function count(words) { 17 | 18 | function insert(w, t) { 19 | if (t === null) { t = { word : w, count : 1, left : null, right : null }; } 20 | else if (w === t.word) { t.count += 1; } 21 | else if (w < t.word) { t.left = insert(w, t.left); } 22 | else { t.right = insert(w, t.right); } 23 | return t; 24 | } 25 | 26 | function flatten(t) { 27 | if (t === null) { return []; } 28 | else { 29 | return [...flatten(t.left), {"word" : t.word, "count" : t.count}, ...flatten(t.right)]; 30 | } 31 | } 32 | 33 | let root = null; 34 | words.forEach(w => { root = insert(w, root); }); 35 | const results = flatten(root); 36 | console.log(results); 37 | } -------------------------------------------------------------------------------- /code/javascript/bristol-app/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | The City of Bristol 6 | 7 | 8 | 9 | 10 | 11 |

The City of Bristol

12 | 15 |
16 |
Please select one of the wards on the left to view more data about it.
17 |
18 |
created by G. A. Kavvos
19 | 20 | -------------------------------------------------------------------------------- /code/javascript/bristol-app/script.js: -------------------------------------------------------------------------------- 1 | window.onload = function () { 2 | let wards = fetch('https://opendata.bristol.gov.uk/api/v2/catalog/datasets/wards/records?limit=50&select=name,ward_id') 3 | .then(response => response.json()) 4 | .then(populateWards) 5 | .catch(err => console.log(err)); 6 | } 7 | 8 | function populateWards(wards) { 9 | let buttons = new DocumentFragment(); 10 | 11 | wards.records.forEach(w => { 12 | const [id, name] = [w.record.fields.ward_id, w.record.fields.name]; 13 | const b = document.createElement("button"); 14 | b.textContent = name; 15 | b.onclick = displayData(id, name); 16 | buttons.appendChild(b); 17 | }); 18 | 19 | let nav = document.getElementById("nav"); 20 | nav.textContent = ''; 21 | nav.append(buttons); 22 | } 23 | 24 | function displayData(id, name) { 25 | 26 | function buildPopulation(records) { 27 | 28 | // Make heading 29 | let heading = document.createElement('h2'); 30 | heading.textContent = 'Population'; 31 | 32 | // Make table 33 | let table = document.createElement('table'); 34 | table.setAttribute('id','populationTable'); 35 | 36 | // Make table header 37 | let header = document.createElement('tr'); 38 | header.innerHTML = 'YearPopulation'; 39 | table.appendChild(header); 40 | 41 | // Populate table 42 | records.sort((x1, x2) => x1.record.fields.mid_year < x2.record.fields.mid_year ? -1 : 1) 43 | .forEach(r => { 44 | let year = document.createElement('td'); 45 | year.textContent = r.record.fields.mid_year; 46 | let population = document.createElement('td'); 47 | population.textContent = r.record.fields.population_estimate; 48 | 49 | let row = document.createElement('tr'); 50 | row.append(year, population); 51 | table.appendChild(row); 52 | }); 53 | 54 | let population = new DocumentFragment(); 55 | population.append(heading, table); 56 | 57 | return population; 58 | } 59 | 60 | return function () { 61 | let wards = fetch(`https://opendata.bristol.gov.uk/api/v2/catalog/datasets/population-estimates-time-series-ward/records?limit=20&select=mid_year,population_estimate&refine=ward_2016_code:${id}`) 62 | .then(response => response.json()) 63 | .then(data => { 64 | let heading = document.createElement('h1'); 65 | heading.textContent = name; 66 | 67 | let population = buildPopulation(data.records); 68 | 69 | let dataPane = document.getElementById("dataPane"); 70 | dataPane.textContent = ''; 71 | dataPane.append(heading, population); 72 | }) 73 | .catch(err => console.log(err)); 74 | } 75 | } -------------------------------------------------------------------------------- /code/javascript/bristol-app/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 12pt; 3 | font-family: 'Libre Baskerville', serif; 4 | } 5 | 6 | body { 7 | display: grid; 8 | grid-template-columns: 200px 1fr; 9 | } 10 | 11 | nav { 12 | text-align: center; 13 | } 14 | 15 | nav > button { 16 | padding-top: 1em; 17 | padding-bottom: 1em; 18 | margin: 1em 1em 1em 1em; 19 | box-shadow: 5px 5px; 20 | } 21 | 22 | main { 23 | margin: 1em 0em 0em 1em; 24 | } 25 | 26 | .initial { 27 | margin-left: 2rem; 28 | margin-top: 2rem; 29 | margin-right: auto; 30 | } 31 | 32 | #populationTable { 33 | border: 1px solid black; 34 | margin-left: 4rem; 35 | margin-right: auto; 36 | } 37 | 38 | #populationTable th, #populationTable td { 39 | text-align: center; 40 | padding: 0.5rem 0.5rem 0.5rem 0.5rem; 41 | } 42 | 43 | header { 44 | color: white; 45 | background-color: slateblue; 46 | grid-column: span 2; 47 | } 48 | 49 | header > h1 { 50 | margin-left: 50px; 51 | margin-right: auto; 52 | } 53 | 54 | footer { 55 | margin-top: 2em; 56 | padding: 1em 0em 1em 0em; 57 | text-align: center; 58 | background-color: slateblue; 59 | color: white; 60 | grid-column: span 2; 61 | } -------------------------------------------------------------------------------- /code/javascript/callback.js: -------------------------------------------------------------------------------- 1 | setTimeout(function(){ 2 | 3 | console.log("I will come after 5 seconds"); 4 | },5000) 5 | function goFirst(callback){ 6 | console.log("Hello World \n"); 7 | callback(); 8 | } 9 | function goSecond(){ 10 | console.log("goFirst is calling me when it wants"); 11 | } 12 | goFirst(goSecond); 13 | 14 | -------------------------------------------------------------------------------- /code/javascript/callbackhell.js: -------------------------------------------------------------------------------- 1 | setTimeout(function(){ 2 | console.log("I will come after 5 seconds"); 3 | setTimeout(function(){ 4 | console.log("I will also come after 5 seconds second "); 5 | setTimeout(function(){ 6 | console.log("I will also come after 5 seconds third"); 7 | },5000) 8 | },5000) 9 | },5000) -------------------------------------------------------------------------------- /code/javascript/class.js: -------------------------------------------------------------------------------- 1 | class Students { 2 | name; 3 | constructor(name){ 4 | this.name = name; 5 | 6 | } 7 | myname(){ 8 | console.log(this.name); 9 | } 10 | } 11 | const joe = new Students("Joe Gardiner"); 12 | joe.myname(); 13 | 14 | -------------------------------------------------------------------------------- /code/javascript/dom-test-1/DOM-Test.js: -------------------------------------------------------------------------------- 1 | const t = document.querySelector('img'); 2 | t.remove(); 3 | document.body.appendChild(t); 4 | document.body.insertBefore(t, document.body.firstChild); 5 | 6 | let x = document.createElement('p'); 7 | x.setAttribute('id', 'wrong'); 8 | x.textContent = "This largely stopped when things became digital."; 9 | document.body.appendChild(x); 10 | 11 | let y = document.getElementById('wrong'); 12 | y.textContent = "Nowadays these are digitally generated."; -------------------------------------------------------------------------------- /code/javascript/dom-test-1/PM5544.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/code/javascript/dom-test-1/PM5544.png -------------------------------------------------------------------------------- /code/javascript/dom-test-1/dom-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simple DOM example 6 | 7 | 8 |
9 | The Philips PM5544 test card 10 |

Back in the day TV engineers used test cards to calibrate TV equipment.

11 |
12 | 13 | -------------------------------------------------------------------------------- /code/javascript/dom-test-2/dom-smile.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Simple DOM example 2 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /code/javascript/dom-test-2/rotate.js: -------------------------------------------------------------------------------- 1 | // Adapted from https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals 2 | 3 | window.onload = function () { 4 | const smile = document.querySelector('div'); 5 | let rotateCount = 0; 6 | let startTime = null; 7 | 8 | function draw(timestamp) { 9 | if (!startTime) { 10 | startTime = timestamp; 11 | } 12 | 13 | rotateCount = (timestamp - startTime) / 3; 14 | rotateCount %= 360; 15 | 16 | smile.style.transform = `rotate(${rotateCount}deg)`; 17 | 18 | requestAnimationFrame(draw); 19 | } 20 | 21 | draw(); 22 | } -------------------------------------------------------------------------------- /code/javascript/dom-test-2/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | color: white; 3 | height: 100%; 4 | } 5 | 6 | body { 7 | height: inherit; 8 | background-color: navy; 9 | margin: 0; 10 | display: flex; 11 | justify-content: center; 12 | align-items: center; 13 | } 14 | 15 | div { 16 | display: inline-block; 17 | font-size: 10rem; 18 | } -------------------------------------------------------------------------------- /code/javascript/foreach.js: -------------------------------------------------------------------------------- 1 | const numbers = [1, 2, 3, 4, 5]; 2 | numbers.forEach((number, index, array) => { 3 | console.log('Index: ' + index + ' Value: ' + number); 4 | }); 5 | -------------------------------------------------------------------------------- /code/javascript/hoisting.js: -------------------------------------------------------------------------------- 1 | console.log(calledbeforedeclared()); 2 | 3 | function calledbeforedeclared(){ 4 | var x = 10; 5 | console.log(x); 6 | } 7 | 8 | -------------------------------------------------------------------------------- /code/javascript/index.js: -------------------------------------------------------------------------------- 1 | const string = '{"name":"John","age":30,"city":"New York"}'; 2 | const myJSON = JSON.parse(string); 3 | console.log(myJSON); -------------------------------------------------------------------------------- /code/javascript/inheritance.js: -------------------------------------------------------------------------------- 1 | const myDate = new Date(); 2 | let object = myDate; 3 | 4 | do { 5 | object = Object.getPrototypeOf(object); 6 | console.log(object); 7 | } while (object); 8 | 9 | -------------------------------------------------------------------------------- /code/javascript/json.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | "name": "CyberJoe", 3 | "hobby": "hacking", 4 | "language" : ["JavaScript", "HTML", "CSS"] 5 | } 6 | // accessing JSON object 7 | console.log(data.name); 8 | console.log(data.hobby); 9 | console.log(data.language[0]); -------------------------------------------------------------------------------- /code/javascript/oliterals.js: -------------------------------------------------------------------------------- 1 | function Students(name){ 2 | this.name = name; 3 | } 4 | 5 | var joe = new Students("Joe Gardiner"); 6 | console.log(joe.name); 7 | Students.prototype.city="Bristol"; 8 | console.log(joe.city); 9 | var marvin = new Students("Marvin Kopo"); 10 | console.log(marvin.name); 11 | console.log(marvin.city); 12 | -------------------------------------------------------------------------------- /code/javascript/promise.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | const link = "https://api.github.com/users/parthadc9"; 4 | 5 | const response = fetch(link); 6 | 7 | response.then(function(data){ 8 | console.log(data); 9 | }) 10 | 11 | -------------------------------------------------------------------------------- /code/javascript/scope.js: -------------------------------------------------------------------------------- 1 | function first(){ 2 | second(); 3 | function second(){ 4 | console.log(a); 5 | } 6 | } 7 | var a = 10; 8 | first(); -------------------------------------------------------------------------------- /code/javascript/wordcount.js: -------------------------------------------------------------------------------- 1 | .const fs = require('fs'); 2 | 3 | /* Loads the first argument as a file, removes all punctuation, 4 | and computes the frequency of each word. */ 5 | let ws = null; 6 | fs.readFile(process.argv[2], 'utf8', function (err, data) { 7 | if (err) { 8 | return console.log("error: " + err); 9 | } 10 | const punct = /[!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]/g; 11 | ws = data.replace(punct, '').trim().split(/\s+/); 12 | count(ws); 13 | }); 14 | 15 | 16 | 17 | function count(words) { 18 | 19 | function insert(w, t) { 20 | if (t === null) { t = { word : w, count : 1, left : null, right : null }; } 21 | else if (w === t.word) { t.count += 1; } 22 | else if (w < t.word) { t.left = insert(w, t.left); } 23 | else { t.right = insert(w, t.right); } 24 | return t; 25 | } 26 | 27 | function flatten(t) { 28 | if (t === null) { return []; } 29 | else { 30 | return [...flatten(t.left), {"word" : t.word, "count" : t.count}, ...flatten(t.right)]; 31 | } 32 | } 33 | 34 | let root = null; 35 | words.forEach(w => { root = insert(w, root); }); 36 | const results = flatten(root); 37 | console.log(results); 38 | } -------------------------------------------------------------------------------- /code/jdbc/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 4.0.0 6 | 7 | org.example 8 | jdbc-example 9 | 0.1 10 | 11 | jdbc-example 12 | 13 | 14 | UTF-8 15 | 1.8 16 | 1.8 17 | 18 | 19 | 20 | 21 | org.mariadb.jdbc 22 | mariadb-java-client 23 | 2.7.1 24 | 25 | 26 | net.java.dev.jna 27 | jna 28 | 5.6.0 29 | 30 | 31 | net.java.dev.jna 32 | jna-platform 33 | 5.6.0 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | org.codehaus.mojo 42 | exec-maven-plugin 43 | 3.0.0 44 | 45 | org.example.Example 46 | 47 | 48 | 49 | org.apache.maven.plugins 50 | maven-assembly-plugin 51 | 3.1.1 52 | 53 | 54 | jar-with-dependencies 55 | 56 | 57 | 58 | 59 | make-assembly 60 | package 61 | 62 | single 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /code/jdbc/src/main/java/org/example/Example.java: -------------------------------------------------------------------------------- 1 | package org.example; 2 | 3 | import java.sql.Connection; 4 | import java.sql.DriverManager; 5 | import java.sql.SQLException; 6 | import java.sql.PreparedStatement; 7 | import java.sql.ResultSet; 8 | 9 | public class Example { 10 | 11 | public static String CS = "jdbc:mariadb://localhost:3306/elections?user=vagrant&localSocket=/var/run/mysqld/mysqld.sock"; 12 | 13 | private void readData(Connection c) { 14 | String SQL = "SELECT id, name FROM Party"; 15 | try (PreparedStatement s = c.prepareStatement(SQL)) { 16 | ResultSet r = s.executeQuery(); 17 | while (r.next()) { 18 | int id = r.getInt("id"); 19 | String name = r.getString("name"); 20 | System.out.println("Party #" + id + " is: " + name); 21 | } 22 | } catch (SQLException e) { 23 | throw new RuntimeException(e); 24 | } 25 | } 26 | 27 | public static void main(String[] args) { 28 | Example example = new Example(); 29 | try (Connection c = DriverManager.getConnection(CS)) { 30 | example.readData(c); 31 | } catch (SQLException e) { 32 | throw new RuntimeException(e); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /code/orm/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | jar 5 | 6 | org.example 7 | orm-example 8 | 0.1 9 | 10 | 11 | UTF-8 12 | 1.8 13 | 1.8 14 | 15 | 16 | 17 | 18 | org.hibernate 19 | hibernate-core 20 | 5.4.27.Final 21 | 22 | 23 | org.mariadb.jdbc 24 | mariadb-java-client 25 | 2.7.1 26 | 27 | 28 | net.java.dev.jna 29 | jna 30 | 5.6.0 31 | 32 | 33 | net.java.dev.jna 34 | jna-platform 35 | 5.6.0 36 | 37 | 38 | 39 | 40 | 41 | 42 | org.codehaus.mojo 43 | exec-maven-plugin 44 | 3.0.0 45 | 46 | org.example.Example 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /code/orm/src/main/java/org/example/Candidate.java: -------------------------------------------------------------------------------- 1 | package org.example; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.Id; 5 | import javax.persistence.ManyToOne; 6 | import javax.persistence.JoinColumn; 7 | 8 | @Entity 9 | public class Candidate { 10 | @Id private int id; 11 | private String name; 12 | 13 | @ManyToOne 14 | @JoinColumn(name = "party") 15 | private Party party; 16 | 17 | @ManyToOne 18 | @JoinColumn(name = "ward") 19 | private Ward ward; 20 | 21 | private int votes; 22 | 23 | public Candidate() {} 24 | 25 | public int getId() { return id; } 26 | public String getName() { return name; } 27 | public Party getParty() { return party; } 28 | public Ward getWard() { return ward; } 29 | public int getVotes() { return votes; } 30 | 31 | public void setId(int id) { this.id = id; } 32 | public void setName(String name) { this.name = name; } 33 | public void setParty(Party party) { this.party = party; } 34 | public void setWard(Ward ward) { this.ward = ward; } 35 | public void setVotes(int votes) { this.votes = votes; } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /code/orm/src/main/java/org/example/Example.java: -------------------------------------------------------------------------------- 1 | package org.example; 2 | 3 | import java.util.List; 4 | 5 | import org.hibernate.SessionFactory; 6 | import org.hibernate.Session; 7 | import org.hibernate.cfg.Configuration; 8 | 9 | import javax.persistence.TypedQuery; 10 | import javax.persistence.criteria.CriteriaBuilder; 11 | 12 | public class Example implements AutoCloseable { 13 | 14 | SessionFactory sessionFactory; 15 | 16 | public Example() { 17 | sessionFactory = new Configuration().configure().buildSessionFactory(); 18 | } 19 | 20 | public void close() { 21 | sessionFactory.close(); 22 | } 23 | 24 | public void run() { 25 | // This try-with-resources block creates a session. 26 | try (Session session = sessionFactory.openSession()) { 27 | 28 | // Load an entity by ID. 29 | Party p1 = session.get(Party.class, 1); 30 | System.out.println(" The party with id=1 is: " + p1.getName()); 31 | 32 | // Load all entities of a class. 33 | // The string is HQL = Hibernate Query Language, based on SQL. 34 | TypedQuery query = session.createQuery("FROM Ward", Ward.class); 35 | List wards = query.getResultList(); 36 | System.out.println(" Wards:"); 37 | for (Ward ward : wards) { 38 | System.out.println(" " + ward.getName()); 39 | } 40 | 41 | // This example shows how joins are automatically added by 42 | // Hibernate when necessary. It also shows how to do prepared 43 | // queries in HQL. 44 | TypedQuery q = session.createQuery("FROM Candidate c WHERE c.party.name = :name", Candidate.class); 45 | q.setParameter("name", "Labour"); 46 | List candidates = q.getResultList(); 47 | System.out.println(" Labour Candidates:"); 48 | for (Candidate c : candidates) { 49 | System.out.println(" " + c.getName() + " (" + c.getWard().getName() + ")"); 50 | } 51 | 52 | } 53 | } 54 | 55 | public static void main(String[] args) { 56 | try (Example example = new Example()) { 57 | example.run(); 58 | } 59 | System.out.println("Done."); 60 | System.exit(0); 61 | } 62 | 63 | } 64 | 65 | -------------------------------------------------------------------------------- /code/orm/src/main/java/org/example/Party.java: -------------------------------------------------------------------------------- 1 | package org.example; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.Id; 5 | 6 | @Entity 7 | public class Party { 8 | @Id private int id; 9 | private String name; 10 | 11 | public Party() {} 12 | 13 | public int getId() { return id; } 14 | public String getName() { return name; } 15 | 16 | public void setId(int id) { this.id = id; } 17 | public void setName(String name) { this.name = name; } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /code/orm/src/main/java/org/example/Ward.java: -------------------------------------------------------------------------------- 1 | package org.example; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.Id; 5 | 6 | @Entity 7 | public class Ward { 8 | @Id private int id; 9 | private String name; 10 | private int electorate; 11 | 12 | public Ward() {} 13 | 14 | public int getId() { return id; } 15 | public String getName() { return name; } 16 | public int getElectorate() { return electorate; } 17 | 18 | public void setId(int id) { this.id = id; } 19 | public void setName(String name) { this.name = name; } 20 | public void setElectorate(int electorate) { this.electorate = electorate; } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /code/orm/src/main/resources/hibernate.cfg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | org.hibernate.dialect.MySQLDialect 9 | jdbc:mariadb://localhost/elections?localSocket=/var/run/mysqld/mysqld.sock 10 | vagrant 11 | 12 | 13 | thread 14 | 15 | 16 | true 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /code/server01/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.5.5 9 | 10 | 11 | softwaretools 12 | server01 13 | 0.0.1-SNAPSHOT 14 | server01 15 | Software Tools Exercises 16 | 17 | 11 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-web 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-thymeleaf 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-test 33 | test 34 | 35 | 36 | 37 | 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-maven-plugin 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /code/server01/src/main/java/softwaretools/server01/Controller.java: -------------------------------------------------------------------------------- 1 | package softwaretools.server01; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.core.io.Resource; 5 | import org.springframework.core.io.ResourceLoader; 6 | import org.springframework.web.bind.annotation.RestController; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.http.ResponseEntity; 9 | import org.springframework.http.HttpHeaders; 10 | 11 | @RestController 12 | public class Controller { 13 | 14 | @Autowired 15 | ResourceLoader loader; 16 | 17 | @GetMapping("/") 18 | public ResponseEntity mainPage() { 19 | HttpHeaders headers = new HttpHeaders(); 20 | headers.set(HttpHeaders.CONTENT_TYPE, "text/plain"); 21 | 22 | return new ResponseEntity("Hello from Spring", headers, 200); 23 | } 24 | 25 | @GetMapping("/html") 26 | public ResponseEntity htmlPage() { 27 | Resource htmlfile = loader.getResource("classpath:web/page.html"); 28 | return ResponseEntity 29 | .status(200) 30 | .header(HttpHeaders.CONTENT_TYPE, "text/html") 31 | .body(htmlfile); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /code/server01/src/main/java/softwaretools/server01/Server01Application.java: -------------------------------------------------------------------------------- 1 | package softwaretools.server01; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Server01Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Server01Application.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /code/server01/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8000 2 | -------------------------------------------------------------------------------- /code/server01/src/main/resources/web/page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Example HTML page 6 | 7 | 8 |

Sample HTML5 page

9 |

Hello from HTML!

10 | 11 | 12 | -------------------------------------------------------------------------------- /code/server01/src/test/java/softwaretools/server01/Server01ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package softwaretools.server01; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class Server01ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /code/server02/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.5.5 9 | 10 | 11 | softwaretools 12 | server02 13 | 0.0.1-SNAPSHOT 14 | server02 15 | Software Tools Exercises 16 | 17 | 11 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-web 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-thymeleaf 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-test 33 | test 34 | 35 | 36 | 37 | 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-maven-plugin 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /code/server02/src/main/java/softwaretools/server02/Controller.java: -------------------------------------------------------------------------------- 1 | package softwaretools.server02; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.core.io.Resource; 5 | import org.springframework.core.io.ResourceLoader; 6 | import org.springframework.web.bind.annotation.RestController; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.http.ResponseEntity; 9 | import org.springframework.http.HttpHeaders; 10 | import org.springframework.web.bind.annotation.PathVariable; 11 | import org.thymeleaf.context.Context; 12 | import softwaretools.server02.model.Database; 13 | import softwaretools.server02.model.Unit; 14 | import softwaretools.server02.model.internal.DatabaseImpl; 15 | import java.util.List; 16 | 17 | @RestController 18 | public class Controller { 19 | 20 | @Autowired 21 | ResourceLoader loader; 22 | 23 | @Autowired 24 | Templates templates; 25 | 26 | @GetMapping("/") 27 | public ResponseEntity mainPage() { 28 | Resource htmlfile = loader.getResource("classpath:web/index.html"); 29 | return ResponseEntity 30 | .status(200) 31 | .header(HttpHeaders.CONTENT_TYPE, "text/html") 32 | .body(htmlfile); 33 | } 34 | 35 | @GetMapping("/units") 36 | public String unitsPage() { 37 | Database d = new DatabaseImpl(); 38 | List units = d.getUnits(); 39 | Context cx = new Context(); 40 | cx.setVariable("units", units); 41 | return templates.render("units.html", cx); 42 | } 43 | 44 | @GetMapping("/unit/{code}") 45 | public ResponseEntity 46 | unitDetailPage(@PathVariable String code) { 47 | Database d = new DatabaseImpl(); 48 | Unit u = null; 49 | for (Unit uu : d.getUnits()) { 50 | if (uu.getCode().equals(code)) { 51 | u = uu; 52 | break; 53 | } 54 | } 55 | 56 | if (u == null) { 57 | return ResponseEntity 58 | .status(404) 59 | .header(HttpHeaders.CONTENT_TYPE, "text/plain") 60 | .body("No unit with code " + code); 61 | } 62 | 63 | Context cx = new Context(); 64 | cx.setVariable("unit", u); 65 | return ResponseEntity 66 | .status(200) 67 | .header(HttpHeaders.CONTENT_TYPE, "text/html") 68 | .body(templates.render("unit.html", cx)); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /code/server02/src/main/java/softwaretools/server02/Server02Application.java: -------------------------------------------------------------------------------- 1 | package softwaretools.server02; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Server02Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Server02Application.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /code/server02/src/main/java/softwaretools/server02/Templates.java: -------------------------------------------------------------------------------- 1 | package softwaretools.server02; 2 | 3 | import org.springframework.stereotype.Component; 4 | import org.thymeleaf.TemplateEngine; 5 | import org.thymeleaf.context.Context; 6 | import org.thymeleaf.spring5.SpringTemplateEngine; 7 | import org.thymeleaf.templatemode.TemplateMode; 8 | import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; 9 | 10 | @Component("templates") 11 | public class Templates { 12 | private final TemplateEngine engine; 13 | 14 | public Templates() { 15 | ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver(); 16 | resolver.setTemplateMode(TemplateMode.HTML); 17 | resolver.setPrefix("templates/"); 18 | engine = new SpringTemplateEngine(); 19 | engine.setTemplateResolver(resolver); 20 | } 21 | 22 | public String render(String template, Context c) { 23 | return this.engine.process(template, c); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/server02/src/main/java/softwaretools/server02/model/Database.java: -------------------------------------------------------------------------------- 1 | package softwaretools.server02.model; 2 | 3 | import java.util.List; 4 | 5 | public interface Database { 6 | List getStudents(); 7 | List getUnits(); 8 | } 9 | -------------------------------------------------------------------------------- /code/server02/src/main/java/softwaretools/server02/model/Pair.java: -------------------------------------------------------------------------------- 1 | package softwaretools.server02.model; 2 | 3 | public class Pair { 4 | A a; 5 | B b; 6 | 7 | public Pair(A a, B b) { 8 | this.a = a; 9 | this.b = b; 10 | } 11 | 12 | public A getFirst() { 13 | return this.a; 14 | } 15 | 16 | public B getSecond() { 17 | return this.b; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /code/server02/src/main/java/softwaretools/server02/model/Student.java: -------------------------------------------------------------------------------- 1 | package softwaretools.server02.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Objects; 8 | 9 | public class Student { 10 | private int id; 11 | private String name; 12 | private final Map grades; 13 | 14 | public Student(int id, String name) { 15 | this.id = id; 16 | this.name = name; 17 | this.grades = new HashMap<>(); 18 | } 19 | 20 | public void addGrade(Unit unit, Integer grade) { 21 | this.grades.put(unit, grade); 22 | } 23 | 24 | public List> getGrades() { 25 | List> list = new ArrayList<>(); 26 | for (Map.Entry entry : grades.entrySet()) { 27 | list.add(new Pair<>(entry.getKey(), entry.getValue())); 28 | } 29 | return list; 30 | } 31 | 32 | public int getId() { 33 | return id; 34 | } 35 | 36 | public void setId(int id) { 37 | this.id = id; 38 | } 39 | 40 | public String getName() { 41 | return name; 42 | } 43 | 44 | public void setName(String name) { 45 | this.name = name; 46 | } 47 | 48 | @Override 49 | public int hashCode() { 50 | int hash = 7; 51 | hash = 53 * hash + this.id; 52 | hash = 53 * hash + Objects.hashCode(this.name); 53 | return hash; 54 | } 55 | 56 | @Override 57 | public boolean equals(Object obj) { 58 | if (this == obj) { 59 | return true; 60 | } 61 | if (obj == null) { 62 | return false; 63 | } 64 | if (getClass() != obj.getClass()) { 65 | return false; 66 | } 67 | final Student other = (Student) obj; 68 | if (this.id != other.id) { 69 | return false; 70 | } 71 | if (!Objects.equals(this.name, other.name)) { 72 | return false; 73 | } 74 | return true; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /code/server02/src/main/java/softwaretools/server02/model/Unit.java: -------------------------------------------------------------------------------- 1 | package softwaretools.server02.model; 2 | 3 | import java.util.Objects; 4 | 5 | public class Unit { 6 | private String code; 7 | private String title; 8 | 9 | public Unit(String code, String title) { 10 | this.code = code; 11 | this.title = title; 12 | } 13 | 14 | public String getCode() { 15 | return code; 16 | } 17 | 18 | public void setCode(String code) { 19 | this.code = code; 20 | } 21 | 22 | public String getTitle() { 23 | return title; 24 | } 25 | 26 | public void setTitle(String title) { 27 | this.title = title; 28 | } 29 | 30 | @Override 31 | public boolean equals(Object obj) { 32 | if (this == obj) { 33 | return true; 34 | } 35 | if (obj == null) { 36 | return false; 37 | } 38 | if (getClass() != obj.getClass()) { 39 | return false; 40 | } 41 | final Unit other = (Unit) obj; 42 | if (!Objects.equals(this.code, other.code)) { 43 | return false; 44 | } 45 | if (!Objects.equals(this.title, other.title)) { 46 | return false; 47 | } 48 | return true; 49 | } 50 | 51 | @Override 52 | public int hashCode() { 53 | int hash = 5; 54 | hash = 59 * hash + Objects.hashCode(this.code); 55 | hash = 59 * hash + Objects.hashCode(this.title); 56 | return hash; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /code/server02/src/main/java/softwaretools/server02/model/internal/DatabaseImpl.java: -------------------------------------------------------------------------------- 1 | package softwaretools.server02.model.internal; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import softwaretools.server02.model.Database; 6 | import softwaretools.server02.model.Student; 7 | import softwaretools.server02.model.Unit; 8 | 9 | public class DatabaseImpl implements Database { 10 | /* 11 | This pattern will not win any contests for good OOP style, but it 12 | works for making a singleton for this example. 13 | */ 14 | private static final List students; 15 | private static final List units; 16 | static { 17 | students = new ArrayList<>(); 18 | Student s = new Student(2021001, "Steven"); 19 | Student c = new Student(2021002, "Connie"); 20 | students.add(s); 21 | students.add(c); 22 | 23 | units = new ArrayList<>(); 24 | Unit mathsA = new Unit("COMS10014", "Mathematics A"); 25 | Unit mathsB = new Unit("COMS10013", "Mathematics B"); 26 | Unit awesome = new Unit("COMS10012", "Software Tools"); 27 | Unit impFunc = new Unit("COMS10016", "Imperative and Functional Programming"); 28 | Unit compArch = new Unit("COMS10015", "Computer Architecture"); 29 | Unit oopAlg = new Unit("COMS10017", "Object-Oriented Programming and Algorithms 1"); 30 | units.add(mathsA); 31 | units.add(mathsB); 32 | units.add(awesome); 33 | units.add(impFunc); 34 | units.add(compArch); 35 | units.add(oopAlg); 36 | 37 | s.addGrade(mathsA, 55); 38 | s.addGrade(mathsB, 58); 39 | s.addGrade(awesome, 60); 40 | s.addGrade(impFunc, 45); 41 | s.addGrade(compArch, 52); 42 | s.addGrade(oopAlg, 58); 43 | 44 | c.addGrade(mathsA, 75); 45 | c.addGrade(mathsB, 83); 46 | c.addGrade(awesome, 90); 47 | c.addGrade(impFunc, 72); 48 | c.addGrade(compArch, 70); 49 | c.addGrade(oopAlg, 85); 50 | } 51 | 52 | @Override 53 | public List getStudents() { 54 | return students; 55 | } 56 | 57 | @Override 58 | public List getUnits() { 59 | return units; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /code/server02/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8000 2 | -------------------------------------------------------------------------------- /code/server02/src/main/resources/templates/unit.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Unit details 6 | 7 | 8 |

Unit details

9 |

Unit name:

10 |

Unit code:

11 | 12 | 13 | -------------------------------------------------------------------------------- /code/server02/src/main/resources/templates/units.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | List of Units 6 | 7 | 8 |

List of units

9 |
    10 |
  • 11 | 12 | 13 |
  • 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /code/server02/src/main/resources/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | University Database 6 | 7 | 8 |

University Database

9 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /code/server02/src/test/java/softwaretools/server02/Server02ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package softwaretools.server02; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class Server02ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # COMSM0085 Software Tools 2 | 3 | ![OST banner](/assets/images/OST.jpg) 4 | 5 | Welcome to the website for COMSM0085 Overview of Software Tools, Teaching Block 2, 2024. 6 | 7 | Please see the following pages for more details: 8 | 9 | - [Unit organisation](organisation.md) 10 | - [Syllabus](syllabus.md) 11 | - [About this repository](repository.md) 12 | 13 | The unit materials are available at the following locations: 14 | 15 | - [Lecture slides](lectures.md) 16 | - [Part 1, weeks 13-17](exercises/part1/) 17 | - [Part 2, weeks 19-23](exercises/part2/) 18 | 19 | 20 |
21 |

22 | "RETRO COMPUTER AND MICROSOFT WINDOWS 3.1" by ▓▒░ TORLEY ░▒▓ is licensed with CC BY-SA 2.0.' 23 |

24 |
25 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | title: COMSM0085 2 | description: Website for Overview of Software Tools 3 | code: COMSM0085 4 | name: Overview of Software Tools -------------------------------------------------------------------------------- /docs/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {% seo %} 9 | 10 | 11 | 12 | 13 |
14 |

{{ site.code }}

15 |

{{ site.name }}

16 |
17 | 18 |
19 | {{ content }} 20 |
21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/assets/css/style.scss: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | @import "{{ site.theme }}"; 5 | 6 | header { 7 | background: #002f5f; 8 | color: #ffffff; 9 | width: 100%; 10 | padding-left: 1ex; 11 | } 12 | 13 | footer { 14 | width: 100%; 15 | margin: 5rem; 16 | text-align: center; 17 | } -------------------------------------------------------------------------------- /docs/assets/images/OST.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/assets/images/OST.jpg -------------------------------------------------------------------------------- /docs/exercises/part1/.nojekyll: -------------------------------------------------------------------------------- 1 | This file makes sure that Github Pages doesn't process mdBook's output. 2 | -------------------------------------------------------------------------------- /docs/exercises/part1/FontAwesome/fonts/FontAwesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/FontAwesome/fonts/FontAwesome.ttf -------------------------------------------------------------------------------- /docs/exercises/part1/FontAwesome/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/FontAwesome/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /docs/exercises/part1/FontAwesome/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/FontAwesome/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /docs/exercises/part1/FontAwesome/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/FontAwesome/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /docs/exercises/part1/FontAwesome/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/FontAwesome/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /docs/exercises/part1/ayu-highlight.css: -------------------------------------------------------------------------------- 1 | /* 2 | Based off of the Ayu theme 3 | Original by Dempfi (https://github.com/dempfi/ayu) 4 | */ 5 | 6 | .hljs { 7 | display: block; 8 | overflow-x: auto; 9 | background: #191f26; 10 | color: #e6e1cf; 11 | } 12 | 13 | .hljs-comment, 14 | .hljs-quote { 15 | color: #5c6773; 16 | font-style: italic; 17 | } 18 | 19 | .hljs-variable, 20 | .hljs-template-variable, 21 | .hljs-attribute, 22 | .hljs-attr, 23 | .hljs-regexp, 24 | .hljs-link, 25 | .hljs-selector-id, 26 | .hljs-selector-class { 27 | color: #ff7733; 28 | } 29 | 30 | .hljs-number, 31 | .hljs-meta, 32 | .hljs-builtin-name, 33 | .hljs-literal, 34 | .hljs-type, 35 | .hljs-params { 36 | color: #ffee99; 37 | } 38 | 39 | .hljs-string, 40 | .hljs-bullet { 41 | color: #b8cc52; 42 | } 43 | 44 | .hljs-title, 45 | .hljs-built_in, 46 | .hljs-section { 47 | color: #ffb454; 48 | } 49 | 50 | .hljs-keyword, 51 | .hljs-selector-tag, 52 | .hljs-symbol { 53 | color: #ff7733; 54 | } 55 | 56 | .hljs-name { 57 | color: #36a3d9; 58 | } 59 | 60 | .hljs-tag { 61 | color: #00568d; 62 | } 63 | 64 | .hljs-emphasis { 65 | font-style: italic; 66 | } 67 | 68 | .hljs-strong { 69 | font-weight: bold; 70 | } 71 | 72 | .hljs-addition { 73 | color: #91b362; 74 | } 75 | 76 | .hljs-deletion { 77 | color: #d96c75; 78 | } 79 | -------------------------------------------------------------------------------- /docs/exercises/part1/css/print.css: -------------------------------------------------------------------------------- 1 | 2 | #sidebar, 3 | #menu-bar, 4 | .nav-chapters, 5 | .mobile-nav-chapters { 6 | display: none; 7 | } 8 | 9 | #page-wrapper.page-wrapper { 10 | transform: none !important; 11 | margin-inline-start: 0px; 12 | overflow-y: initial; 13 | } 14 | 15 | #content { 16 | max-width: none; 17 | margin: 0; 18 | padding: 0; 19 | } 20 | 21 | .page { 22 | overflow-y: initial; 23 | } 24 | 25 | code { 26 | direction: ltr !important; 27 | } 28 | 29 | pre > .buttons { 30 | z-index: 2; 31 | } 32 | 33 | a, a:visited, a:active, a:hover { 34 | color: #4183c4; 35 | text-decoration: none; 36 | } 37 | 38 | h1, h2, h3, h4, h5, h6 { 39 | page-break-inside: avoid; 40 | page-break-after: avoid; 41 | } 42 | 43 | pre, code { 44 | page-break-inside: avoid; 45 | white-space: pre-wrap; 46 | } 47 | 48 | .fa { 49 | display: none !important; 50 | } 51 | -------------------------------------------------------------------------------- /docs/exercises/part1/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/favicon.png -------------------------------------------------------------------------------- /docs/exercises/part1/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/exercises/part1/fonts/open-sans-v17-all-charsets-300.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/fonts/open-sans-v17-all-charsets-300.woff2 -------------------------------------------------------------------------------- /docs/exercises/part1/fonts/open-sans-v17-all-charsets-300italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/fonts/open-sans-v17-all-charsets-300italic.woff2 -------------------------------------------------------------------------------- /docs/exercises/part1/fonts/open-sans-v17-all-charsets-600.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/fonts/open-sans-v17-all-charsets-600.woff2 -------------------------------------------------------------------------------- /docs/exercises/part1/fonts/open-sans-v17-all-charsets-600italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/fonts/open-sans-v17-all-charsets-600italic.woff2 -------------------------------------------------------------------------------- /docs/exercises/part1/fonts/open-sans-v17-all-charsets-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/fonts/open-sans-v17-all-charsets-700.woff2 -------------------------------------------------------------------------------- /docs/exercises/part1/fonts/open-sans-v17-all-charsets-700italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/fonts/open-sans-v17-all-charsets-700italic.woff2 -------------------------------------------------------------------------------- /docs/exercises/part1/fonts/open-sans-v17-all-charsets-800.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/fonts/open-sans-v17-all-charsets-800.woff2 -------------------------------------------------------------------------------- /docs/exercises/part1/fonts/open-sans-v17-all-charsets-800italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/fonts/open-sans-v17-all-charsets-800italic.woff2 -------------------------------------------------------------------------------- /docs/exercises/part1/fonts/open-sans-v17-all-charsets-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/fonts/open-sans-v17-all-charsets-italic.woff2 -------------------------------------------------------------------------------- /docs/exercises/part1/fonts/open-sans-v17-all-charsets-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/fonts/open-sans-v17-all-charsets-regular.woff2 -------------------------------------------------------------------------------- /docs/exercises/part1/fonts/source-code-pro-v11-all-charsets-500.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/fonts/source-code-pro-v11-all-charsets-500.woff2 -------------------------------------------------------------------------------- /docs/exercises/part1/highlight.css: -------------------------------------------------------------------------------- 1 | /* 2 | * An increased contrast highlighting scheme loosely based on the 3 | * "Base16 Atelier Dune Light" theme by Bram de Haan 4 | * (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) 5 | * Original Base16 color scheme by Chris Kempson 6 | * (https://github.com/chriskempson/base16) 7 | */ 8 | 9 | /* Comment */ 10 | .hljs-comment, 11 | .hljs-quote { 12 | color: #575757; 13 | } 14 | 15 | /* Red */ 16 | .hljs-variable, 17 | .hljs-template-variable, 18 | .hljs-attribute, 19 | .hljs-tag, 20 | .hljs-name, 21 | .hljs-regexp, 22 | .hljs-link, 23 | .hljs-name, 24 | .hljs-selector-id, 25 | .hljs-selector-class { 26 | color: #d70025; 27 | } 28 | 29 | /* Orange */ 30 | .hljs-number, 31 | .hljs-meta, 32 | .hljs-built_in, 33 | .hljs-builtin-name, 34 | .hljs-literal, 35 | .hljs-type, 36 | .hljs-params { 37 | color: #b21e00; 38 | } 39 | 40 | /* Green */ 41 | .hljs-string, 42 | .hljs-symbol, 43 | .hljs-bullet { 44 | color: #008200; 45 | } 46 | 47 | /* Blue */ 48 | .hljs-title, 49 | .hljs-section { 50 | color: #0030f2; 51 | } 52 | 53 | /* Purple */ 54 | .hljs-keyword, 55 | .hljs-selector-tag { 56 | color: #9d00ec; 57 | } 58 | 59 | .hljs { 60 | display: block; 61 | overflow-x: auto; 62 | background: #f6f7f6; 63 | color: #000; 64 | } 65 | 66 | .hljs-emphasis { 67 | font-style: italic; 68 | } 69 | 70 | .hljs-strong { 71 | font-weight: bold; 72 | } 73 | 74 | .hljs-addition { 75 | color: #22863a; 76 | background-color: #f0fff4; 77 | } 78 | 79 | .hljs-deletion { 80 | color: #b31d28; 81 | background-color: #ffeef0; 82 | } 83 | -------------------------------------------------------------------------------- /docs/exercises/part1/resources/Vagrantfile: -------------------------------------------------------------------------------- 1 | Vagrant.configure("2") do |config| 2 | config.vm.box = "generic/debian12" 3 | config.vm.synced_folder ".", "/vagrant" 4 | 5 | config.vm.provision "shell", inline: <<-SHELL 6 | echo "Post-provision installs go here" 7 | SHELL 8 | end 9 | -------------------------------------------------------------------------------- /docs/exercises/part1/resources/after-merge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/resources/after-merge.png -------------------------------------------------------------------------------- /docs/exercises/part1/resources/after-rebase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/resources/after-rebase.png -------------------------------------------------------------------------------- /docs/exercises/part1/resources/before-rebase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/resources/before-rebase.png -------------------------------------------------------------------------------- /docs/exercises/part1/resources/census.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/resources/census.png -------------------------------------------------------------------------------- /docs/exercises/part1/resources/elections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/resources/elections.png -------------------------------------------------------------------------------- /docs/exercises/part1/resources/pipe1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/resources/pipe1.png -------------------------------------------------------------------------------- /docs/exercises/part1/resources/pipe2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/resources/pipe2.png -------------------------------------------------------------------------------- /docs/exercises/part1/resources/pipe3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/resources/pipe3.png -------------------------------------------------------------------------------- /docs/exercises/part1/resources/pr-after-rebase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/resources/pr-after-rebase.png -------------------------------------------------------------------------------- /docs/exercises/part1/resources/pr-before-rebase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/resources/pr-before-rebase.png -------------------------------------------------------------------------------- /docs/exercises/part1/resources/uni-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part1/resources/uni-diagram.png -------------------------------------------------------------------------------- /docs/exercises/part1/tomorrow-night.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Night Theme */ 2 | /* https://github.com/jmblog/color-themes-for-highlightjs */ 3 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 4 | /* https://github.com/jmblog/color-themes-for-highlightjs */ 5 | 6 | /* Tomorrow Comment */ 7 | .hljs-comment { 8 | color: #969896; 9 | } 10 | 11 | /* Tomorrow Red */ 12 | .hljs-variable, 13 | .hljs-attribute, 14 | .hljs-tag, 15 | .hljs-regexp, 16 | .ruby .hljs-constant, 17 | .xml .hljs-tag .hljs-title, 18 | .xml .hljs-pi, 19 | .xml .hljs-doctype, 20 | .html .hljs-doctype, 21 | .css .hljs-id, 22 | .css .hljs-class, 23 | .css .hljs-pseudo { 24 | color: #cc6666; 25 | } 26 | 27 | /* Tomorrow Orange */ 28 | .hljs-number, 29 | .hljs-preprocessor, 30 | .hljs-pragma, 31 | .hljs-built_in, 32 | .hljs-literal, 33 | .hljs-params, 34 | .hljs-constant { 35 | color: #de935f; 36 | } 37 | 38 | /* Tomorrow Yellow */ 39 | .ruby .hljs-class .hljs-title, 40 | .css .hljs-rule .hljs-attribute { 41 | color: #f0c674; 42 | } 43 | 44 | /* Tomorrow Green */ 45 | .hljs-string, 46 | .hljs-value, 47 | .hljs-inheritance, 48 | .hljs-header, 49 | .hljs-name, 50 | .ruby .hljs-symbol, 51 | .xml .hljs-cdata { 52 | color: #b5bd68; 53 | } 54 | 55 | /* Tomorrow Aqua */ 56 | .hljs-title, 57 | .css .hljs-hexcolor { 58 | color: #8abeb7; 59 | } 60 | 61 | /* Tomorrow Blue */ 62 | .hljs-function, 63 | .python .hljs-decorator, 64 | .python .hljs-title, 65 | .ruby .hljs-function .hljs-title, 66 | .ruby .hljs-title .hljs-keyword, 67 | .perl .hljs-sub, 68 | .javascript .hljs-title, 69 | .coffeescript .hljs-title { 70 | color: #81a2be; 71 | } 72 | 73 | /* Tomorrow Purple */ 74 | .hljs-keyword, 75 | .javascript .hljs-function { 76 | color: #b294bb; 77 | } 78 | 79 | .hljs { 80 | display: block; 81 | overflow-x: auto; 82 | background: #1d1f21; 83 | color: #c5c8c6; 84 | } 85 | 86 | .coffeescript .javascript, 87 | .javascript .xml, 88 | .tex .hljs-formula, 89 | .xml .javascript, 90 | .xml .vbscript, 91 | .xml .css, 92 | .xml .hljs-cdata { 93 | opacity: 0.5; 94 | } 95 | 96 | .hljs-addition { 97 | color: #718c00; 98 | } 99 | 100 | .hljs-deletion { 101 | color: #c82829; 102 | } 103 | -------------------------------------------------------------------------------- /docs/exercises/part2/.nojekyll: -------------------------------------------------------------------------------- 1 | This file makes sure that Github Pages doesn't process mdBook's output. 2 | -------------------------------------------------------------------------------- /docs/exercises/part2/FontAwesome/fonts/FontAwesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/FontAwesome/fonts/FontAwesome.ttf -------------------------------------------------------------------------------- /docs/exercises/part2/FontAwesome/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/FontAwesome/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /docs/exercises/part2/FontAwesome/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/FontAwesome/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /docs/exercises/part2/FontAwesome/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/FontAwesome/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /docs/exercises/part2/FontAwesome/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/FontAwesome/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /docs/exercises/part2/ayu-highlight.css: -------------------------------------------------------------------------------- 1 | /* 2 | Based off of the Ayu theme 3 | Original by Dempfi (https://github.com/dempfi/ayu) 4 | */ 5 | 6 | .hljs { 7 | display: block; 8 | overflow-x: auto; 9 | background: #191f26; 10 | color: #e6e1cf; 11 | } 12 | 13 | .hljs-comment, 14 | .hljs-quote { 15 | color: #5c6773; 16 | font-style: italic; 17 | } 18 | 19 | .hljs-variable, 20 | .hljs-template-variable, 21 | .hljs-attribute, 22 | .hljs-attr, 23 | .hljs-regexp, 24 | .hljs-link, 25 | .hljs-selector-id, 26 | .hljs-selector-class { 27 | color: #ff7733; 28 | } 29 | 30 | .hljs-number, 31 | .hljs-meta, 32 | .hljs-builtin-name, 33 | .hljs-literal, 34 | .hljs-type, 35 | .hljs-params { 36 | color: #ffee99; 37 | } 38 | 39 | .hljs-string, 40 | .hljs-bullet { 41 | color: #b8cc52; 42 | } 43 | 44 | .hljs-title, 45 | .hljs-built_in, 46 | .hljs-section { 47 | color: #ffb454; 48 | } 49 | 50 | .hljs-keyword, 51 | .hljs-selector-tag, 52 | .hljs-symbol { 53 | color: #ff7733; 54 | } 55 | 56 | .hljs-name { 57 | color: #36a3d9; 58 | } 59 | 60 | .hljs-tag { 61 | color: #00568d; 62 | } 63 | 64 | .hljs-emphasis { 65 | font-style: italic; 66 | } 67 | 68 | .hljs-strong { 69 | font-weight: bold; 70 | } 71 | 72 | .hljs-addition { 73 | color: #91b362; 74 | } 75 | 76 | .hljs-deletion { 77 | color: #d96c75; 78 | } 79 | -------------------------------------------------------------------------------- /docs/exercises/part2/css/print.css: -------------------------------------------------------------------------------- 1 | 2 | #sidebar, 3 | #menu-bar, 4 | .nav-chapters, 5 | .mobile-nav-chapters { 6 | display: none; 7 | } 8 | 9 | #page-wrapper.page-wrapper { 10 | transform: none !important; 11 | margin-inline-start: 0px; 12 | overflow-y: initial; 13 | } 14 | 15 | #content { 16 | max-width: none; 17 | margin: 0; 18 | padding: 0; 19 | } 20 | 21 | .page { 22 | overflow-y: initial; 23 | } 24 | 25 | code { 26 | direction: ltr !important; 27 | } 28 | 29 | pre > .buttons { 30 | z-index: 2; 31 | } 32 | 33 | a, a:visited, a:active, a:hover { 34 | color: #4183c4; 35 | text-decoration: none; 36 | } 37 | 38 | h1, h2, h3, h4, h5, h6 { 39 | page-break-inside: avoid; 40 | page-break-after: avoid; 41 | } 42 | 43 | pre, code { 44 | page-break-inside: avoid; 45 | white-space: pre-wrap; 46 | } 47 | 48 | .fa { 49 | display: none !important; 50 | } 51 | -------------------------------------------------------------------------------- /docs/exercises/part2/css/rhythm1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/css/rhythm1.png -------------------------------------------------------------------------------- /docs/exercises/part2/css/rhythm2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/css/rhythm2.png -------------------------------------------------------------------------------- /docs/exercises/part2/cssgrid/curriculum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/cssgrid/curriculum.png -------------------------------------------------------------------------------- /docs/exercises/part2/cssgrid/trees-medium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/cssgrid/trees-medium.png -------------------------------------------------------------------------------- /docs/exercises/part2/cssgrid/trees-wide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/cssgrid/trees-wide.png -------------------------------------------------------------------------------- /docs/exercises/part2/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/favicon.png -------------------------------------------------------------------------------- /docs/exercises/part2/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/exercises/part2/fonts/open-sans-v17-all-charsets-300.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/fonts/open-sans-v17-all-charsets-300.woff2 -------------------------------------------------------------------------------- /docs/exercises/part2/fonts/open-sans-v17-all-charsets-300italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/fonts/open-sans-v17-all-charsets-300italic.woff2 -------------------------------------------------------------------------------- /docs/exercises/part2/fonts/open-sans-v17-all-charsets-600.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/fonts/open-sans-v17-all-charsets-600.woff2 -------------------------------------------------------------------------------- /docs/exercises/part2/fonts/open-sans-v17-all-charsets-600italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/fonts/open-sans-v17-all-charsets-600italic.woff2 -------------------------------------------------------------------------------- /docs/exercises/part2/fonts/open-sans-v17-all-charsets-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/fonts/open-sans-v17-all-charsets-700.woff2 -------------------------------------------------------------------------------- /docs/exercises/part2/fonts/open-sans-v17-all-charsets-700italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/fonts/open-sans-v17-all-charsets-700italic.woff2 -------------------------------------------------------------------------------- /docs/exercises/part2/fonts/open-sans-v17-all-charsets-800.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/fonts/open-sans-v17-all-charsets-800.woff2 -------------------------------------------------------------------------------- /docs/exercises/part2/fonts/open-sans-v17-all-charsets-800italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/fonts/open-sans-v17-all-charsets-800italic.woff2 -------------------------------------------------------------------------------- /docs/exercises/part2/fonts/open-sans-v17-all-charsets-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/fonts/open-sans-v17-all-charsets-italic.woff2 -------------------------------------------------------------------------------- /docs/exercises/part2/fonts/open-sans-v17-all-charsets-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/fonts/open-sans-v17-all-charsets-regular.woff2 -------------------------------------------------------------------------------- /docs/exercises/part2/fonts/source-code-pro-v11-all-charsets-500.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/fonts/source-code-pro-v11-all-charsets-500.woff2 -------------------------------------------------------------------------------- /docs/exercises/part2/highlight.css: -------------------------------------------------------------------------------- 1 | /* 2 | * An increased contrast highlighting scheme loosely based on the 3 | * "Base16 Atelier Dune Light" theme by Bram de Haan 4 | * (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) 5 | * Original Base16 color scheme by Chris Kempson 6 | * (https://github.com/chriskempson/base16) 7 | */ 8 | 9 | /* Comment */ 10 | .hljs-comment, 11 | .hljs-quote { 12 | color: #575757; 13 | } 14 | 15 | /* Red */ 16 | .hljs-variable, 17 | .hljs-template-variable, 18 | .hljs-attribute, 19 | .hljs-tag, 20 | .hljs-name, 21 | .hljs-regexp, 22 | .hljs-link, 23 | .hljs-name, 24 | .hljs-selector-id, 25 | .hljs-selector-class { 26 | color: #d70025; 27 | } 28 | 29 | /* Orange */ 30 | .hljs-number, 31 | .hljs-meta, 32 | .hljs-built_in, 33 | .hljs-builtin-name, 34 | .hljs-literal, 35 | .hljs-type, 36 | .hljs-params { 37 | color: #b21e00; 38 | } 39 | 40 | /* Green */ 41 | .hljs-string, 42 | .hljs-symbol, 43 | .hljs-bullet { 44 | color: #008200; 45 | } 46 | 47 | /* Blue */ 48 | .hljs-title, 49 | .hljs-section { 50 | color: #0030f2; 51 | } 52 | 53 | /* Purple */ 54 | .hljs-keyword, 55 | .hljs-selector-tag { 56 | color: #9d00ec; 57 | } 58 | 59 | .hljs { 60 | display: block; 61 | overflow-x: auto; 62 | background: #f6f7f6; 63 | color: #000; 64 | } 65 | 66 | .hljs-emphasis { 67 | font-style: italic; 68 | } 69 | 70 | .hljs-strong { 71 | font-weight: bold; 72 | } 73 | 74 | .hljs-addition { 75 | color: #22863a; 76 | background-color: #f0fff4; 77 | } 78 | 79 | .hljs-deletion { 80 | color: #b31d28; 81 | background-color: #ffeef0; 82 | } 83 | -------------------------------------------------------------------------------- /docs/exercises/part2/resources/baseline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/resources/baseline.png -------------------------------------------------------------------------------- /docs/exercises/part2/resources/cattax.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/resources/cattax.tar.gz -------------------------------------------------------------------------------- /docs/exercises/part2/resources/examplepage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | COMS10012 Software Tools 6 | 7 | 8 |

COMS10012 Software Tools

9 |

10 | This unit teaches you the basics of web development. 11 |

12 |

Content

13 |

14 | Content is a combination of video lectures and reading assignments from the Mozilla Developer Network. 15 |

16 |

17 | You can find the unit page on github. 18 |

19 |

Learning Outcomes

20 |

21 | After completing this unit, you will be able to use the following: 22 |

23 |
    24 |
  • HTML5
  • 25 |
  • CSS
  • 26 |
  • JavaScript
  • 27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /docs/exercises/part2/resources/http-response: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Content-type: text/plain 3 | Content-length: 16 4 | Connection: close 5 | 6 | Hello over HTTP! 7 | 8 | -------------------------------------------------------------------------------- /docs/exercises/part2/resources/movie-search.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/resources/movie-search.tar.gz -------------------------------------------------------------------------------- /docs/exercises/part2/resources/page1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CSS example 6 | 7 | 8 | 9 |
10 |

CSS conference booking page

11 |
12 |
13 |

CSS conference

14 |

CSS conference is a place where you can learn all about modern web design with CSS. You will learn all about responsive design, frameworks, tips and tricks and practical examples from the designers of real websites.

15 | 16 |
17 |

Registration Form

18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 |
28 |
29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /docs/exercises/part2/resources/page2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CSS example 6 | 7 | 8 | 9 |
10 |

CSS conference booking page

11 |
12 |
13 |

CSS conference

14 |

CSS conference is a place where you can learn all about modern web design with CSS. You will learn all about responsive design, frameworks, tips and tricks and practical examples from the designers of real websites.

15 | 16 |

Registration Form

17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |
27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /docs/exercises/part2/resources/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 8 | a, abbr, acronym, address, big, cite, code, 9 | del, dfn, em, img, ins, kbd, q, s, samp, 10 | small, strike, strong, sub, sup, tt, var, 11 | b, u, i, center, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, embed, 16 | figure, figcaption, footer, header, hgroup, 17 | menu, nav, output, ruby, section, summary, 18 | time, mark, audio, video { 19 | margin: 0; 20 | padding: 0; 21 | border: 0; 22 | font-size: 100%; 23 | font: inherit; 24 | vertical-align: baseline; 25 | } 26 | /* HTML5 display-role reset for older browsers */ 27 | article, aside, details, figcaption, figure, 28 | footer, header, hgroup, menu, nav, section { 29 | display: block; 30 | } 31 | body { 32 | line-height: 1; 33 | } 34 | ol, ul { 35 | list-style: none; 36 | } 37 | blockquote, q { 38 | quotes: none; 39 | } 40 | blockquote:before, blockquote:after, 41 | q:before, q:after { 42 | content: ''; 43 | content: none; 44 | } 45 | table { 46 | border-collapse: collapse; 47 | border-spacing: 0; 48 | } -------------------------------------------------------------------------------- /docs/exercises/part2/resources/scrape.py: -------------------------------------------------------------------------------- 1 | from bs4 import BeautifulSoup 2 | import os 3 | 4 | 5 | for file in os.listdir('cattax'): 6 | if file[-4:] == 'html': 7 | soup = BeautifulSoup(open('cattax/'+file,'r'), features='html.parser') 8 | print(soup.title.text + " : " + soup.h1.text) 9 | 10 | -------------------------------------------------------------------------------- /docs/exercises/part2/resources/trees.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/exercises/part2/resources/trees.tar.gz -------------------------------------------------------------------------------- /docs/exercises/part2/tomorrow-night.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Night Theme */ 2 | /* https://github.com/jmblog/color-themes-for-highlightjs */ 3 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 4 | /* https://github.com/jmblog/color-themes-for-highlightjs */ 5 | 6 | /* Tomorrow Comment */ 7 | .hljs-comment { 8 | color: #969896; 9 | } 10 | 11 | /* Tomorrow Red */ 12 | .hljs-variable, 13 | .hljs-attribute, 14 | .hljs-tag, 15 | .hljs-regexp, 16 | .ruby .hljs-constant, 17 | .xml .hljs-tag .hljs-title, 18 | .xml .hljs-pi, 19 | .xml .hljs-doctype, 20 | .html .hljs-doctype, 21 | .css .hljs-id, 22 | .css .hljs-class, 23 | .css .hljs-pseudo { 24 | color: #cc6666; 25 | } 26 | 27 | /* Tomorrow Orange */ 28 | .hljs-number, 29 | .hljs-preprocessor, 30 | .hljs-pragma, 31 | .hljs-built_in, 32 | .hljs-literal, 33 | .hljs-params, 34 | .hljs-constant { 35 | color: #de935f; 36 | } 37 | 38 | /* Tomorrow Yellow */ 39 | .ruby .hljs-class .hljs-title, 40 | .css .hljs-rule .hljs-attribute { 41 | color: #f0c674; 42 | } 43 | 44 | /* Tomorrow Green */ 45 | .hljs-string, 46 | .hljs-value, 47 | .hljs-inheritance, 48 | .hljs-header, 49 | .hljs-name, 50 | .ruby .hljs-symbol, 51 | .xml .hljs-cdata { 52 | color: #b5bd68; 53 | } 54 | 55 | /* Tomorrow Aqua */ 56 | .hljs-title, 57 | .css .hljs-hexcolor { 58 | color: #8abeb7; 59 | } 60 | 61 | /* Tomorrow Blue */ 62 | .hljs-function, 63 | .python .hljs-decorator, 64 | .python .hljs-title, 65 | .ruby .hljs-function .hljs-title, 66 | .ruby .hljs-title .hljs-keyword, 67 | .perl .hljs-sub, 68 | .javascript .hljs-title, 69 | .coffeescript .hljs-title { 70 | color: #81a2be; 71 | } 72 | 73 | /* Tomorrow Purple */ 74 | .hljs-keyword, 75 | .javascript .hljs-function { 76 | color: #b294bb; 77 | } 78 | 79 | .hljs { 80 | display: block; 81 | overflow-x: auto; 82 | background: #1d1f21; 83 | color: #c5c8c6; 84 | } 85 | 86 | .coffeescript .javascript, 87 | .javascript .xml, 88 | .tex .hljs-formula, 89 | .xml .javascript, 90 | .xml .vbscript, 91 | .xml .css, 92 | .xml .hljs-cdata { 93 | opacity: 0.5; 94 | } 95 | 96 | .hljs-addition { 97 | color: #718c00; 98 | } 99 | 100 | .hljs-deletion { 101 | color: #c82829; 102 | } 103 | -------------------------------------------------------------------------------- /docs/lectures.md: -------------------------------------------------------------------------------- 1 | # Lecture Materials 2 | 3 | 4 | + [01: POSIX Systems](slides/01-intro.md) 5 | + [02: Git](slides/02-git.pdf) 6 | + [03: Shellscripting and Buildtools](slides/03-shell.pdf) 7 | + [04: Debugging](slides/04-debugging.pdf) 8 | + [05: Databases](slides/05-sql.pdf) 9 | + [06: HTTP & HTML](slides/06-web.md) 10 | + [07: CSS](slides/07-css.md) 11 | + [08: JavaScript](slides/08-JavaScript.pdf) [(PPTX with videos)](slides/08-JavaScript.pptx) 12 | + [09: Web scraping](slides/09-webscraping.md) 13 | + [10: Encryption](slides/10-encryption.pdf) 14 | -------------------------------------------------------------------------------- /docs/slides/02-git.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/slides/02-git.pdf -------------------------------------------------------------------------------- /docs/slides/03-shell.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/slides/03-shell.pdf -------------------------------------------------------------------------------- /docs/slides/04-debugging.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/slides/04-debugging.pdf -------------------------------------------------------------------------------- /docs/slides/05-sql.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/slides/05-sql.pdf -------------------------------------------------------------------------------- /docs/slides/08-JavaScript.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/slides/08-JavaScript.pdf -------------------------------------------------------------------------------- /docs/slides/08-JavaScript.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/slides/08-JavaScript.pptx -------------------------------------------------------------------------------- /docs/slides/10-encryption.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/docs/slides/10-encryption.pdf -------------------------------------------------------------------------------- /exercises/part1/.gitignore: -------------------------------------------------------------------------------- 1 | book/ -------------------------------------------------------------------------------- /exercises/part1/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["David"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "Exercises" 7 | 8 | [preprocessor.python] 9 | command = "python preprocessor.py" -------------------------------------------------------------------------------- /exercises/part1/build.bat: -------------------------------------------------------------------------------- 1 | mdbook build 2 | xcopy /S /Y book ..\..\docs\exercises\part1 -------------------------------------------------------------------------------- /exercises/part1/preprocessor.py: -------------------------------------------------------------------------------- 1 | # Preprocessor to handle ||| custom blocks. 2 | 3 | import sys 4 | import json 5 | import re 6 | 7 | # this is for when mdbook first pokes the preprocessor to see if it works 8 | if len(sys.argv) > 1: 9 | if sys.argv[1] == 'supports': 10 | # sys.argv[2] is the renderer name 11 | sys.exit(0) 12 | 13 | def begin_block(acc, type): 14 | acc += ["", f'
', f'
', '
', ""] 15 | 16 | def end_block(acc): 17 | acc += ["", "
", "
", ""] 18 | 19 | def process(item): 20 | """ 21 | The item has a ['content'] field with the page text. 22 | Process this. 23 | """ 24 | content = item['content'] 25 | lines = content.split('\n') 26 | out = [] 27 | block = False 28 | for line in lines: 29 | if block is False: 30 | if (m := re.match("\|\|\|([a-z]+)", line)) is not None: 31 | begin_block(out, m.group(1)) 32 | block = True 33 | else: 34 | out.append(line) 35 | else: 36 | if re.match("\|\|\|", line) is not None: 37 | end_block(out) 38 | block = False 39 | else: 40 | out.append(line) 41 | item['content'] = "\n".join(out) 42 | 43 | context, book = json.load(sys.stdin) 44 | 45 | #log = open("preprocessor.log", "a") 46 | 47 | sections = book['sections'] 48 | for section in sections: 49 | #log.write("SECTION\n") 50 | #for k in section: 51 | # log.write(f" {k}\n") 52 | 53 | if 'Chapter' in section: 54 | process(section['Chapter']) 55 | for subitem in section['Chapter']['sub_items']: 56 | process(subitem['Chapter']) 57 | 58 | #log.close() 59 | 60 | #with open("log", "w") as log: 61 | # json.dump(book, log) 62 | json.dump(book, sys.stdout) 63 | -------------------------------------------------------------------------------- /exercises/part1/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Exercises 2 | 3 | [Overview](./overview.md) 4 | 5 | # Week 1: POSIX Systems 6 | - [System Administration](./posix1/index.md) 7 | - [Secure shell](./posix1/ssh.md) 8 | - [Installing Vagrant and Debian](./posix1/install.md) 9 | - [Debian system administration](./posix1/admin.md) 10 | - [The POSIX Shell](./posix2/index.md) 11 | - [Shell expansion](./posix2/shell.md) 12 | - [Pipes](./posix2/pipes.md) 13 | - [Regular expressions](./posix2/regex.md) 14 | 15 | # Week 2: Version Control 16 | - [Git](./git/index.md) 17 | - [Git](./git/git.md) 18 | 19 | # Week 3: Shell Scripting & Build Tools 20 | - [Shell Scripting](./posix3/index.md) 21 | - [File permissions](./posix3/permissions.md) 22 | - [Shell scripting](./posix3/script.md) 23 | - [Build Tools](./build2/index.md) 24 | - [C](./build2/c.md) 25 | - [Python](./build2/python.md) 26 | - [Java](./build2/java.md) 27 | - [Spring](./build2/spring.md) 28 | 29 | # Week 4: Debugging 30 | - [Debugging](./build1/index.md) 31 | - [Exercise](./build1/exercise.md) 32 | - [Bonus POSIX (unassessed)](./posix4/index.md) 33 | - [inodes and system calls](./posix4/stat.md) 34 | - [Concurrent programming in POSIX](./posix4/concurrent.md) 35 | - [Pipes in C](./posix4/cpipe.md) 36 | - [Input/Output in C](./posix4/c_io.md) 37 | - [Input/Output in POSIX](./posix4/posix_io.md) 38 | - [The final challenge](./posix4/final.md) 39 | 40 | # Week 5: Databases 41 | - [SQL introduction](./db1/sql-introduction.md) 42 | - [Set up the database](./db1/setup.md) 43 | - [ER diagram](./db1/er-diagram.md) 44 | - [More modelling](./db1/er2.md) 45 | - [Explore the database](./db2/explore-database.md) 46 | - [Bristol elections](./db2/elections.md) 47 | - [The UK census](./db2/census.md) 48 | - [Normal forms](./db2/normalforms.md) 49 | - [Intermediate SQL](./db3/sql-intermediate.md) 50 | - [Exercises](./db3/exercises.md) 51 | - [SQL and Java](./db4/sql-java.md) 52 | - [JDBC](./db4/jdbc.md) 53 | - [Hibernate](./db4/hibernate.md) 54 | - [SQLite](./db4/sqlite.md) 55 | -------------------------------------------------------------------------------- /exercises/part1/src/build1/exercise.md: -------------------------------------------------------------------------------- 1 | # Debugging exercise 2 | 3 | Clone the repository `git@github.com:cs-uob/COMSM0085` if you have not done so already and open the folder `code/debugging`. 4 | 5 | There is a program `stackcalc.c` that attempts to implement the specification in `stackcalc.txt` for a Reverse Polish Notation calculator, but it does not work correctly. For example, `1 2 +` should produce `3.0000` but produces `Error, operator on empty stack`. (Read the notes in the text file about how to compile the program with the required library.) 6 | 7 | Your exercise is to debug and fix the program, making as few changes to the general structure as possible (so don't just rewrite the whole thing from scratch). 8 | -------------------------------------------------------------------------------- /exercises/part1/src/build1/index.md: -------------------------------------------------------------------------------- 1 | # Build Tools 1 2 | 3 | ## Videos 4 | 5 | | Video | Length | Slides | 6 | |-------|-------:|--------| 7 | | [Debugging](https://web.microsoftstream.com/video/10926ab8-e10e-43b4-b486-495ce9f775c2)| 34 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EX0-s0boltxDq0oNPgudC40BsWc1PnK6pEWXJuRabPQnHA?e=ccd8Gh) | 8 | 9 | ## Exercise 10 | 11 | - [Debugging exercise](./exercise.md) 12 | -------------------------------------------------------------------------------- /exercises/part1/src/build2/index.md: -------------------------------------------------------------------------------- 1 | # Build Tools 2 2 | 3 | ## Videos 4 | 5 | | Video | Length | Slides | 6 | |-------|-------:|--------| 7 | | [Build Tools 1](https://web.microsoftstream.com/video/48cac422-9b33-4630-8c85-517f1f7cd619) | 17 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EfuDdA92T65GqK6H_89K9IYBaFKiwvRwj7F-unUeP2iB1Q?e=TlIwVN) | 8 | | [Build Tools 2](https://web.microsoftstream.com/video/0edff26c-c5ee-4ac6-9ea8-42238d98a4f1) | 12 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EYzpCf0Y0pBNvGLdeJ3bHHcBZBE7HULs1h8lCNA_NIw1XQ?e=lK2prk) | 9 | 10 | ## Exercises 11 | 12 | - [C](c.html) 13 | - [Python](python.html) 14 | - [Java](java.html) 15 | - [Spring](spring.html) 16 | -------------------------------------------------------------------------------- /exercises/part1/src/db1/er2.md: -------------------------------------------------------------------------------- 1 | # More modelling 2 | 3 | Using what you have learnt so far about relational modelling, think about and discuss in groups how you would model a university database to store student's academic progress, such as units enrolled on and completed, marks obtained etc. based on your understanding of how the University of Bristol works. For example, a unit can have different assessments with different weights. You will of course also need a `Students` table, and you can make the model more involved if you like by including that different students are on different degree programmes, and that sometimes students have to resit units. 4 | 5 | You should end up with a more detailed version of the model briefly shown at the top of the previous page - if you have the time you can make both an ER diagram and a create/drop script. 6 | 7 | This is also a good point to mention another fact of how marks and credit points work: exam boards. At the end of each academic year around May, your unit directors all report their marks for each student to an exam board, which sits and decides on final marks and awarding credit. For example, an exam board can moderate the marks for a unit. This is why you do not get your exam marks until a long time after the exam has happened, even if it's a multiple choice exam that can be marked automatically: the marks still have to go through an exam board. (There is another, smaller exam board around the start of Teaching Block 2 so you don't have to wait until summer for your January exam marks to be released.) 8 | If you want to model this in your schema, the idea here is that a student has two marks associated with each unit: the "actual mark" (the input to the exam board) and the "agreed mark" (the one that comes out of the board and goes on your transcript). Of course, for most students most of the time, the two are the same. Your schema will need to store "agreed marks" explicitly, but there are ways of doing the model that does not store the "actual mark" directly. Think about how you could recompute it from other information in the database - we will of course learn how to do this in SQL in a later activity. 9 | 10 | The key idea in relational modelling is not to store information more than once if you can avoid it. If you have stored in several places that Fred is taking Introduction to Programming, and then Fred switches his units, you don't want to end up with a situation where this change is only reflected in some parts of the database. -------------------------------------------------------------------------------- /exercises/part1/src/db1/sql-introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction to SQL 2 | 3 | This is the first of three activities to teach you about relational databases and the SQL programming language. 4 | 5 | ## Videos 6 | 7 | The videos for this activity are: 8 | 9 | | Video | Length | Slides | 10 | |-------|-------:|--------| 11 | | [Introduction to databases](https://web.microsoftstream.com/video/b3d41a41-17ec-4194-bec1-9666cc234e40) | 16 minutes | [PDF](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EX_d8Ny3NAtPuVuybL02Mf8BmK-iwH_AAZKU8aa03RWNow?e=qvMIo6) | 12 | | [Entity Relationship Diagrams](https://web.microsoftstream.com/video/2b6639e2-35e4-42bf-9e50-fc5228c4e321) | 11 minutes | [PDF](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EaEjGii_A6dFlwr9H99i6bgBKenNumCIYqUmZmmOJ1DBFw?e=0yBFi3) | 13 | | [Intro to SQL](https://web.microsoftstream.com/video/8f2881d9-82f7-4364-a227-e555b776cda0) | 29 minutes | [PDF](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EaUps_sEdCNAneB4qz3VcS0Bw-yqRF7knK6ODUGu00GtNA?e=d1Neil) | 14 | | [Normal Forms](https://web.microsoftstream.com/video/6a9b6876-9e38-4e92-afed-7aaa872714cf?list=studio) | 14 minutes | [PDF](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EQzXXyCAs-NCicgguerjs2AB6uzpeLsteXg2I07g0MjLZg?e=SzrlgF) | 15 | 16 | ## Exercises 17 | 18 | - [Set up the database](./setup.md) 19 | - [ER diagrams](./er-diagram.md) 20 | - [More modelling](./er2.md) 21 | - [Explore the database](../db2/explore-database.md) 22 | - [Bristol elections](../db2/elections.md) 23 | - [The UK census](../db2/census.md) 24 | - [Normal forms](../db2/normalforms.md) 25 | -------------------------------------------------------------------------------- /exercises/part1/src/db2/elections.md: -------------------------------------------------------------------------------- 1 | # Bristol elections 2 | 3 | In 2014, Bristol held council elections for 24 of its wards. Each ward elected one councillor to represent the ward on the city council. The results are in the `elections` database, with the following schema as you have hopefully just discovered: 4 | 5 | ![elections ER diagram](../resources/elections.png) 6 | 7 | From an ER diagram you can derive a _JOIN strategy_, a way of representing all the useful information in a database. For individual queries, you may only need a subset of this information so you can leave off unnecessary parts of the full JOIN strategy. In this case, the following would work: 8 | 9 | ``` 10 | SELECT Candidate.name AS name, Party.name AS party, Ward.name AS ward, Candidate.votes, Ward.electorate 11 | FROM Candidate 12 | INNER JOIN Party ON Candidate.party = Party.id 13 | INNER JOIN Ward ON Candidate.ward = Ward.id 14 | ``` 15 | 16 | ## Exercises 17 | 18 | Find SQL statements to answer the following questions. Your answer to each question should be a single query, and you should not hard-code any ids. For example, if a question is about the Labour party, you should use the string `'Labour'` in your query somewhere, not look up the party id and hard-code that in your query. 19 | 20 | Although you can answer all the exercises in this section by taking the join strategy and adding clauses where necessary, there is sometimes a quicker way. But if you don't know where to start, consider how you would extract the result you want from the joined table. The WHERE clause determines which rows appear in the result and the SELECT clause picks the columns that appear in the result. 21 | 22 | 1. List the names of all parties that stood in the election, ordered alphabetically by name. 23 | 2. List the names of all parties that stood in the Bedminster ward. 24 | 3. How many votes did Labour get in the Stockwood ward? 25 | 4. List the names, parties and number of votes obtained for all candidates in the Southville ward. Order the candidates by number of votes obtained descending (winner comes first). 26 | 5. List the name, party and number of votes obtained for the winner only in the Knowle ward. *(Hint: apart from changing the ward name, you only need one small modification to the statement from the last question. You may assume no ties.)* 27 | -------------------------------------------------------------------------------- /exercises/part1/src/db3/sql-intermediate.md: -------------------------------------------------------------------------------- 1 | # Intermediate SQL 2 | 3 | This is the third of four activities to teach you about relational databases and SQL. 4 | 5 | ## Videos 6 | 7 | The videos for this activity are: 8 | 9 | | Video | Length | Slides | 10 | |-------|-------:|--------| 11 | |[Intermediate SQL](https://web.microsoftstream.com/video/455af5a1-bcca-4378-a0e1-6b52891b20a4) | 22 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EWv9-8AjCwpBpO0V9einLsEBSugn1YIDSV_18mknho_Vvw?e=L0TOLh) | 12 | 13 | ## Exercises 14 | 15 | The exercises for this activity are all on one page: 16 | 17 | - [Intermediate SQL](./exercises.md) 18 | -------------------------------------------------------------------------------- /exercises/part1/src/db4/sql-java.md: -------------------------------------------------------------------------------- 1 | # SQL and Java 2 | 3 | In this activity you will learn how to connect to an SQL database from a Java program using the JDBC interface and the Hibernate ORM. 4 | 5 | ## Videos 6 | 7 | The videos for this activity are: 8 | 9 | | Video | Length | Slides | 10 | |-------|-------:|--------| 11 | | [JDBC](https://web.microsoftstream.com/video/9c046863-65f4-44a2-91bb-0bf1023c78b4) | 25 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EZqSbPzVyMBOjLk7wVVV4ecBcg_JSPIYMPT2AkTC0npttw?e=E2qtCw) | 12 | 13 | ## Exercises 14 | 15 | The exercises for this activity are: 16 | 17 | - [JDBC](./jdbc.md) 18 | - [Hibernate](./hibernate.md) 19 | - [SQLite](./sqlite.md) 20 | -------------------------------------------------------------------------------- /exercises/part1/src/git/index.md: -------------------------------------------------------------------------------- 1 | # Activity: Git 2 | 3 | ## Videos 4 | 5 | | Video | Length | Slides | 6 | |-------|-------:|--------| 7 | | [Git, part 1](https://web.microsoftstream.com/video/1fb28095-555d-40e5-8b3b-5fb18b178892) | 34 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/ETueHYft1rVKjld7jesRNBwBL-iNbDoDElJRwZ1BymcXnQ?e=obfTVF) | 8 | | [Git, part 2](https://web.microsoftstream.com/video/ea90c1c9-89cd-4cbf-9af1-14675bebdaea) | 27 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EZjMmRvbrndMkCf0wNwv93MBLorPR9KHzlMZ0iEJa1vBJg?e=08BmRQ) | 9 | | [Git, part 3](https://web.microsoftstream.com/video/ecb70e8b-a390-44fa-8bc1-5af08d79a065) | 19 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/Ed3pRweWtgBPlylvSqRa9eMBzieIVzJ_SYjJY-Hw10V_3Q?e=WGEyNg) | 10 | 11 | ## Exercises 12 | 13 | - [Git](./git.md) 14 | 15 | ## Reading 16 | 17 | Optional (but recommended). 18 | 19 | - [`man 7 giteveryday`](https://www.man7.org/linux/man-pages/man7/giteveryday.7.html) 20 | -------------------------------------------------------------------------------- /exercises/part1/src/overview.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | This page contains the exercises for Part 1 (the first 5 weeks) of COMSM0085 Software Tools. 4 | Weeks usually contain two workbooks, and each workbook has associated videos to 5 | watch before the lab (on the main page for each workbook) as well as a set of 6 | practical exercises which you'll tackle before and during the lab. 7 | 8 | Part 1 focuses on tools for setting up systems and writing code. We'll start 9 | with system administration tasks (like connecting to machines via ssh and 10 | updating software) and then move on to making good use of Unix tools, 11 | progressing to shell scripting and how to automate or simplify tasks you might 12 | encounter as a developer. Then we'll look at tools you can use to support 13 | programming in several different languages, including version control and 14 | debuggers. Finally, we'll cover how you can store structured information 15 | effectively in a relational database, and write queries to interact with that 16 | database. 17 | -------------------------------------------------------------------------------- /exercises/part1/src/posix1/index.md: -------------------------------------------------------------------------------- 1 | # System Administration 2 | 3 | ## Videos 4 | 5 | Before this activity, you should watch the following videos - most of them are quite short. The videos are hosted on Microsoft Stream, and you will need to authenticate via university log-in to watch them. 6 | 7 | | Video | Length | Slides | 8 | |-------|-------:|--------| 9 | | [SSH](https://web.microsoftstream.com/video/d2736b4b-80de-4740-9084-2ab458a9dbab) | 10 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/ERXOIS-oCUxMmOguGB0ctO8BSWKpCskLDBmWM3c6wrk90A?e=IobhBb) | 10 | | [Vagrant](https://web.microsoftstream.com/video/373abf95-52ce-45d2-82d0-28250d300184) | 12 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EW4-UCx2St1Gl8AGPwTuq4EBhNt7-KfnKhbewow6w3WuJQ?e=bJeh4g) | 11 | | [Package managers](https://web.microsoftstream.com/video/9091bdf6-2242-4b43-b09e-9641f9401135) | 6 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EUPLvl82HzRGi-nyhSdiBicBb7EBnouRVnT6RAKKyzhqKQ?e=Ow5cmt) | 12 | 13 | _NB: The videos were recorded last year. Almost everything still applies, but you might see us talking about 'Alpine' or 'apk' -- the Linux VM we used to use, and its package manager. Look at the updated slides to see how Alpine-specific commands translate to Debian._ 14 | 15 | ## Exercises 16 | 17 | - [Secure shell](./ssh.md) 18 | - [Installing vagrant and Debian](./install.md) 19 | - [Debian system administration](./admin.md) 20 | -------------------------------------------------------------------------------- /exercises/part1/src/posix2/index.md: -------------------------------------------------------------------------------- 1 | # The POSIX Shell 2 | 3 | ## Videos 4 | 5 | | Video | Length | Slides | 6 | |-------|-------:|--------| 7 | | [The shell](https://web.microsoftstream.com/video/a55ff501-9e8d-4bb3-a00e-b680596b2de3) | 30 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EbOfjsNY9SJAkEXbMb9WorcBAQMW0QuKthcQHRBDvru8eg?e=HWh7D1) | 8 | | [Pipes 1](https://web.microsoftstream.com/video/7b2657a6-a2d4-4c34-a642-da993d468851) | 20 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EdOsJY_EYlRIveTotkGszNoBWeGx5efiVPJPhhbiQfydTQ?e=RHGVol) | 9 | | [Pipes 2](https://web.microsoftstream.com/video/d04fb18c-533b-4ffe-b8a1-f4d46e9b73d1) | 30 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EfGZcNx_ttNCsx8vpo2uZqIBERTzvUzap84BdzMfxLRuQw?e=Ty9yjZ) | 10 | 11 | 12 | ## Exercises 13 | 14 | - [Shell expansion](./shell.md) 15 | - [Pipes](./pipes.md) 16 | - [Regular expressions](./regex.md) 17 | -------------------------------------------------------------------------------- /exercises/part1/src/posix2/regex.md: -------------------------------------------------------------------------------- 1 | # Regular expressions 2 | 3 | For this exercise you'll want to refer often to a manual for `grep`. 4 | You can access one on the commandline by invoking `man grep`. 5 | You've already tackled some problems involving regular expressions in a previous 6 | exercise. Here are some more advanced questions that will require you to 7 | understand more about `grep`, its options, and how regular expression syntax 8 | works. 9 | 10 | 11 | 1. Study the documentation for the `-w` option. Contrive a file such that `grep 12 | PATTERN FILE` returns two different lines but `grep -w PATTERN FILE` returns 13 | only one line. 14 | 2. You'll have seen beforehand that you can count the results of a search with 15 | `grep PATTERN FILE | wc -l`. However, `grep` also has a `-c` option which 16 | counts matches. Can you find the situation where the `wc -l` approach and the 17 | `-c` approach produce different results? Can you explain why? 18 | 3. Some words have different spelling between British English and American 19 | English. For example, 'encyclopaedia' is valid in British English but not 20 | American. Can you write a regular expression that would match both of these 21 | words, but nothing else? How about matching both 'color' (American) and 'colour' 22 | (British)? 23 | 4. UK postcodes follow a general schema of two letters followed by one number, 24 | followed by an optional space, then another number, followed by two more letters. Can you write 25 | a regular expression that would match such sequences? 26 | 5. In practice, the above is a simplified version of the system, and a better UK 27 | postcode validator regex is known to be 28 | `^(([A-Z]{1,2}[0-9][A-Z0-9]?|ASCN|STHL|TDCU|BBND|[BFS]IQQ|PCRN|TKCA) 29 | ?[0-9][A-Z]{2}|BFPO ?[0-9]{1,4}|(KY[0-9]|MSR|VG|AI)[ -]?[0-9]{4}|[A-Z]{2} 30 | ?[0-9]{2}|GE ?CX|GIR ?0A{2}|SAN ?TA1)$`. Try breaking apart this monster to 31 | understand what is being tested, and find an example that would match the schema 32 | described for the fourth question but fail to match this expression. 33 | -------------------------------------------------------------------------------- /exercises/part1/src/posix3/index.md: -------------------------------------------------------------------------------- 1 | # Shell Scripting 2 | 3 | ## Videos 4 | 5 | | Video | Length | Slides | 6 | |-------|-------:|--------| 7 | | [Permissions](https://web.microsoftstream.com/video/71b186df-c373-4b98-ba34-035679cb1ec6) | 20 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EUQ3xxCL4xlHtQ1M6uaLdW4Bc2sxbrCrLNQcinAUgCjmOg?e=ciQDX2) | 8 | | [shell scripting 1](https://web.microsoftstream.com/video/bbe017bf-c1b6-44a0-96cf-ef79a9b17f0e) | 17 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/Ebuz7SukPjRLhMYQd3NJRkkBhgkFxVutnYmcv622ePSxkg?e=8hhLWP) | 9 | | [shell scripting 2](https://web.microsoftstream.com/video/0a2a65bc-1655-4089-984f-53c9400dc2d3) | 21 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EVMTcoOLqmVNiflYUpHfRhMB1XzttL_7gHYOux1qznX4ZA?e=mXRBtE) | 10 | 11 | ## Exercises 12 | - [File permissions](./permissions.md) 13 | - [Shell scripting](./script.md) 14 | -------------------------------------------------------------------------------- /exercises/part1/src/posix4/index.md: -------------------------------------------------------------------------------- 1 | # Bonus POSIX Activity 2 | 3 | *This activity is optional, and non-examinable. We recommend that you watch the videos anyway.* 4 | 5 | ## Videos 6 | 7 | | Video | Length | Slides | 8 | |-------|-------:|--------| 9 | | [inodes](https://web.microsoftstream.com/video/8f01c778-9ead-4e15-b5ad-21305dc96eba) | 18 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EUke3KQirYBEtq809FUGEjMBKbE9VWpbn2q7t9T6KrnGAA?e=kX4ZY6) | 10 | | [The TTY](https://web.microsoftstream.com/video/bc1a7bdd-1f40-47e6-b86b-ec9eef84fe39) | 22 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EaUyN9P0dr5NoHkdvYGPRzkB2mR3hYuHqoJ4W1OqT1830w?e=YdPV0f) | 11 | 12 | ## Exercises 13 | 14 | - [inodes and system calls](./stat.md) 15 | - [Concurrent programming in POSIX](./concurrent.md) 16 | - [Pipes in C](./cpipe.md) 17 | - [Input/Output in C](./c_io.md) 18 | - [Input/Output in POSIX](./posix_io.md) 19 | - [The final challenge](./final.md) 20 | -------------------------------------------------------------------------------- /exercises/part1/src/resources/Vagrantfile: -------------------------------------------------------------------------------- 1 | Vagrant.configure("2") do |config| 2 | config.vm.box = "generic/debian12" 3 | config.vm.synced_folder ".", "/vagrant" 4 | 5 | config.vm.provision "shell", inline: <<-SHELL 6 | echo "Post-provision installs go here" 7 | SHELL 8 | end 9 | -------------------------------------------------------------------------------- /exercises/part1/src/resources/after-merge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/exercises/part1/src/resources/after-merge.png -------------------------------------------------------------------------------- /exercises/part1/src/resources/after-rebase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/exercises/part1/src/resources/after-rebase.png -------------------------------------------------------------------------------- /exercises/part1/src/resources/before-rebase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/exercises/part1/src/resources/before-rebase.png -------------------------------------------------------------------------------- /exercises/part1/src/resources/census.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/exercises/part1/src/resources/census.png -------------------------------------------------------------------------------- /exercises/part1/src/resources/elections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/exercises/part1/src/resources/elections.png -------------------------------------------------------------------------------- /exercises/part1/src/resources/pipe1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/exercises/part1/src/resources/pipe1.png -------------------------------------------------------------------------------- /exercises/part1/src/resources/pipe2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/exercises/part1/src/resources/pipe2.png -------------------------------------------------------------------------------- /exercises/part1/src/resources/pipe3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/exercises/part1/src/resources/pipe3.png -------------------------------------------------------------------------------- /exercises/part1/src/resources/pr-after-rebase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/exercises/part1/src/resources/pr-after-rebase.png -------------------------------------------------------------------------------- /exercises/part1/src/resources/pr-before-rebase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/exercises/part1/src/resources/pr-before-rebase.png -------------------------------------------------------------------------------- /exercises/part1/src/resources/uni-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/exercises/part1/src/resources/uni-diagram.png -------------------------------------------------------------------------------- /exercises/part2/.gitignore: -------------------------------------------------------------------------------- 1 | book/ -------------------------------------------------------------------------------- /exercises/part2/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["David"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "Exercises" 7 | 8 | [preprocessor.python] 9 | command = "python preprocessor.py" -------------------------------------------------------------------------------- /exercises/part2/build.bat: -------------------------------------------------------------------------------- 1 | mdbook build 2 | xcopy /S /Y book ..\..\docs\exercises\part2\ -------------------------------------------------------------------------------- /exercises/part2/preprocessor.py: -------------------------------------------------------------------------------- 1 | # Preprocessor to handle ||| custom blocks. 2 | 3 | import sys 4 | import json 5 | import re 6 | 7 | # this is for when mdbook first pokes the preprocessor to see if it works 8 | if len(sys.argv) > 1: 9 | if sys.argv[1] == 'supports': 10 | # sys.argv[2] is the renderer name 11 | sys.exit(0) 12 | 13 | def begin_block(acc, type): 14 | acc += ["", f'
', f'
', '
', ""] 15 | 16 | def end_block(acc): 17 | acc += ["", "
", "
", ""] 18 | 19 | def process(item): 20 | """ 21 | The item has a ['content'] field with the page text. 22 | Process this. 23 | """ 24 | content = item['content'] 25 | lines = content.split('\n') 26 | out = [] 27 | block = False 28 | for line in lines: 29 | if block is False: 30 | if (m := re.match("\|\|\|([a-z]+)", line)) is not None: 31 | begin_block(out, m.group(1)) 32 | block = True 33 | else: 34 | out.append(line) 35 | else: 36 | if re.match("\|\|\|", line) is not None: 37 | end_block(out) 38 | block = False 39 | else: 40 | out.append(line) 41 | item['content'] = "\n".join(out) 42 | 43 | context, book = json.load(sys.stdin) 44 | 45 | #log = open("preprocessor.log", "a") 46 | 47 | sections = book['sections'] 48 | for section in sections: 49 | #log.write("SECTION\n") 50 | #for k in section: 51 | # log.write(f" {k}\n") 52 | 53 | if 'Chapter' in section: 54 | process(section['Chapter']) 55 | for subitem in section['Chapter']['sub_items']: 56 | process(subitem['Chapter']) 57 | 58 | #log.close() 59 | 60 | #with open("log", "w") as log: 61 | # json.dump(book, log) 62 | json.dump(book, sys.stdout) 63 | -------------------------------------------------------------------------------- /exercises/part2/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Exercises 2 | 3 | [Overview](./overview.md) 4 | 5 | # Week 6: The Web 6 | - [HTTP](./http/index.md) 7 | - [Setup](./http/setup.md) 8 | - [Exploring HTTP](./http/explore.md) 9 | - [Online research](./http/research.md) 10 | - [A server in Java](./http/server.md) 11 | - [HTML5](./html5/index.md) 12 | - [Basic HTML5](./html5/basic.md) 13 | - [Templates](./html5/templates.md) 14 | 15 | # Week 7: CSS 16 | - [CSS](./css/index.md) 17 | - [Styling Text](./css/text.md) 18 | - [Frameworks](./css/framework.md) 19 | - [CSS grids](./cssgrid/index.md) 20 | - [Introduction](./cssgrid/intro.md) 21 | - [Curriculum exercise](./cssgrid/curriculum.md) 22 | - [Trees exercise (responsive layout)](./cssgrid/trees.md) 23 | 24 | # Week 8: Javascript 25 | - [JavaScript](./js/index.md) 26 | - [My Cool App](./js/MyCoolApp.md) 27 | 28 | # Week 9: Web Scraping 29 | - [Web scraping](./scrape/index.md) 30 | - [Crawling](./scrape/crawl.md) 31 | - [BeautifulSoup](./scrape/soup.md) 32 | 33 | # Week 10: Practical Encryption 34 | - [Practical Encryption](./encryption/index.md) 35 | - [OpenSSL](./encryption/openssl.md) 36 | - [PGP](./encryption/pgp.md) 37 | -------------------------------------------------------------------------------- /exercises/part2/src/app1/index.md: -------------------------------------------------------------------------------- 1 | # A complete application, part 1 2 | 3 | In this workshop we will set up and inspect a complete application including database, Java back-end/API and React front-end. 4 | 5 | Just one short video to introduce the topic: 6 | 7 | | Video | Length | Slides | 8 | |-------|-------:|--------| 9 | | [Application](https://web.microsoftstream.com/video/52fa34a2-02f8-4988-9fa1-21a317acbde3) | 9 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EU-n9IGv5SxGu5tR7HrTsz8B4-e8ERD6i7ct2mPeoLZbQQ?e=zUVT6e) | 10 | 11 | Please try the steps on the "setting things up" page before you come to the workshop - ideally you will then be able to start the walkthrough in the workshop itself immediately, but if you get stuck in the set-up, you will be able to ask for help at the very start. 12 | -------------------------------------------------------------------------------- /exercises/part2/src/cloud/cloud1.md: -------------------------------------------------------------------------------- 1 | # The Cloud 2 | 3 | For this session, there are no videos. Instead, you should read the following 4 | web resources, the content of which is examinable: 5 | 6 | - [What is Cloud Computing?](https://cloud.google.com/learn/what-is-cloud-computing) 7 | - [What is Cloud Economics?](https://www.cloudzero.com/blog/cloud-economics) 8 | - [As A Service](https://www.ibm.com/topics/iaas-paas-saas) 9 | 10 | 11 | There are no exercises for the cloud material. Instead, use this time to 12 | complete the React exercises, recap exercises from earlier in this part of the 13 | unit, and ask questions about this or other material from across the unit. If 14 | there are exercises that you could not solve or want to ask questions about, now 15 | would be a good time to revisit them and ask for help. 16 | 17 | 18 | _(The original intention was to include a non-examinable practical component 19 | here using AWS services, but there was trouble getting this set up for the class 20 | in time. While not the same as a guided exercise, some of you may want to look 21 | at AWS' own onboarding material 22 | [here](https://aws.amazon.com/getting-started/).)_ 23 | 24 | -------------------------------------------------------------------------------- /exercises/part2/src/css/index.md: -------------------------------------------------------------------------------- 1 | # CSS 2 | 3 | CSS, or Cascading Style Sheets, allows you to set what your page looks like, separately from creating the content. 4 | 5 | _Not to be confused with [CSS Bristol](https://cssbristol.co.uk/)._ 6 | 7 | ## Videos 8 | 9 | | Video | Length | Slides | 10 | |-------|-------:|--------| 11 | | [CSS part 1](https://web.microsoftstream.com/video/966c07b6-6f2f-4676-b348-e942101be174) | 14 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EXPRGR7nfbdLgB8krc9jTFcBHEH__HvV-vqXfbmYemGfnA?e=lwKNBI) | 12 | | [CSS part 2](https://web.microsoftstream.com/video/b38974b4-2675-4143-82c8-a8ff2c6a3288) | 10 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EaPEjEpM1JtNkDwYQyQ8tCUBFT6Q78VI4QKMSANf6jhfyg?e=VIS7eB) | 13 | 14 | ## MDN 15 | 16 | For this workshop, please read the following pages: 17 | 18 | - [CSS first steps](https://developer.mozilla.org/en-US/docs/Learn/CSS/First_steps) including the 5 subpages linked under "Guides" - they are all meant for beginners so you should be able to get through them quickly. 19 | - [CSS selectors](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors) 20 | - [The box model](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/The_box_model) 21 | - [Values and units](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units) 22 | 23 | ## Exercises 24 | 25 | - [Styling Text](./text.md) 26 | - [Frameworks](./framework.md) 27 | -------------------------------------------------------------------------------- /exercises/part2/src/css/rhythm1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/exercises/part2/src/css/rhythm1.png -------------------------------------------------------------------------------- /exercises/part2/src/css/rhythm2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/exercises/part2/src/css/rhythm2.png -------------------------------------------------------------------------------- /exercises/part2/src/cssgrid/curriculum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/exercises/part2/src/cssgrid/curriculum.png -------------------------------------------------------------------------------- /exercises/part2/src/cssgrid/index.md: -------------------------------------------------------------------------------- 1 | # CSS grids 2 | 3 | ## Videos 4 | 5 | | Video | Length | Slides | 6 | |-------|-------:|--------| 7 | | [Design](https://web.microsoftstream.com/video/ef9e9dcf-f9b8-4bcf-8ac6-f8608514cc22) | 13 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EUlNRBt92L9MmCs7UUPFCnsBfrW30OIZiFGjrzvBEdPAGQ?e=FmmJEW) | 8 | | [CSS grids](https://web.microsoftstream.com/video/93c2a47c-5fd4-432d-9f93-71e7181fd104) | 7 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/EbxgG7O3lb1MoSgwQuUMDZ8B8WBnR0ZyiBD0Q1hQk9P9eg?e=ks2kqT) | 9 | | [Responsive Layout](https://web.microsoftstream.com/video/d2099c95-eef3-474e-9ae8-4f5a84521d18) | 3 minutes | [slides](https://uob-my.sharepoint.com/:b:/g/personal/me17847_bristol_ac_uk/Ebvt4NOYIGtHvJDTNsbXK4kBzon6XArErDCWxs74DzyNgA?e=jJRS8E) | 10 | 11 | ## MDN 12 | 13 | Please read the following pages, and play with the interactive examples: 14 | 15 | - [Normal flow](https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Normal_Flow) 16 | - [CSS grids](https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Grids) 17 | - [Media queries](https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Media_queries) 18 | 19 | ## Exercises 20 | 21 | - [Introduction](./intro.md) 22 | - [Curriculum exercise](./curriculum.md) 23 | - [Trees (responsive layout)](./trees.md) 24 | -------------------------------------------------------------------------------- /exercises/part2/src/cssgrid/intro.md: -------------------------------------------------------------------------------- 1 | # CSS grids introduction 2 | 3 | To create a CSS grid, you place a container element (usually a `
`) and style it `display: grid`. All its direct children will now be laid out in a grid, and you can configure the general layout on the parent element: 4 | 5 | - `grid-template-columns` defines the number and widths of the columns. 6 | - `gap` (which should have been called `grid-gap`, but is not) defines the gap between different grid cells. 7 | - For a gap around the outside of the grid, give the container a margin (or padding). 8 | 9 | On the child elements, you can set the placement rules for each one and the browser will build the grid accordingly: 10 | 11 | - By default, each child takes up the next free 1x1 space. 12 | - `grid-row` and `grid-column` modify this: 13 | - `span N` makes a child element N cells wide/tall. 14 | - `M / N` positions the child absolutely from dividing line M to dividing line N (you can overlap or stack elements on top of each other this way if you want to). 15 | 16 | There are many more things that you can do with grids, and your best resources if you need to look this up are: 17 | 18 | - [Grids on MDN](https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Grids) 19 | - [CSS-tricks complete guide to grids](https://css-tricks.com/snippets/css/complete-guide-grid/) 20 | -------------------------------------------------------------------------------- /exercises/part2/src/cssgrid/trees-medium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/exercises/part2/src/cssgrid/trees-medium.png -------------------------------------------------------------------------------- /exercises/part2/src/cssgrid/trees-wide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cs-uob/COMSM0085/0131572bd20fbc2ac105b1c6317db76558961ca0/exercises/part2/src/cssgrid/trees-wide.png -------------------------------------------------------------------------------- /exercises/part2/src/encryption/index.md: -------------------------------------------------------------------------------- 1 | # Practical Encryption 2 | 3 | ## Videos 4 | 5 | | Video | Length | Slides | 6 | |-------|-------:|--------| 7 | 8 | 9 | ## Exercises 10 | 11 | - [OpenSSL](./openssl.md) 12 | - [PGP](./pgp.md) 13 | -------------------------------------------------------------------------------- /exercises/part2/src/html5/basic.md: -------------------------------------------------------------------------------- 1 | # Basic HTML5 2 | 3 | For your first exercise, create a page called `index.html` and add the HTML5 template code to it. 4 | 5 | ```html 6 | 7 | 8 | 9 | 10 | A web page 11 | 12 | 13 |

An example web-page

14 |

A paragraph of text here, perhaps with a link

15 | 16 | 17 | ``` 18 | 19 | The name `index.html` is a convention: most web servers, if you give an URL that looks like a "folder" e.g. `example.com/pages` (or `example.com/pages/` with slash on the end) will serve the file `index.html` from within that folder, if there is one. 20 | 21 | ## Create a page 22 | 23 | Create content in your page to make it look like the following, then open it in your browser. All body text, but not the bullet list, is contained in paragraph tags. 24 | 25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
http://localhost:8000
33 |
34 | 36 |
37 | 38 | ## Validate your page 39 | 40 | There are various libraries and services that check if your page is valid HTML5. 41 | 42 | At [validator.w3.org](https://validator.w3.org/) you can enter an URL, upload a file, or paste the contents of a file and validate it. Check that the page you have just written is valid HTML5. 43 | 44 | Your browser's developer tools can also check the page you are viewing. For Chrome/Edge, to to the _Console_ tab and, if the button at the top does not read _No Issues_ but shows a number with a blue (or even yellow or red) icon, then click it to open the _Issues_ tab and see what the browser is complaining about. 45 | 46 | You can check the sample solution [here](../resources/examplepage.html) but you might have a different, equally valid solution. 47 | -------------------------------------------------------------------------------- /exercises/part2/src/html5/index.md: -------------------------------------------------------------------------------- 1 | # HTML5 2 | 3 | HTML5, officially introduced in 2014, is the modern markup language for writing websites. 4 | 5 | It gets rid of a lot of historical annoyances and inconsistencies from previous versions of HTML and XML and contains a lot of new standard tags and attributes for features that individual sites had built with JavaScript or Adobe Flash in the past. For example, HTML5 has a `