From 9bb85593f63ea0c69bfaa0870c1f5ab026efccce Mon Sep 17 00:00:00 2001 From: Derrick Chambers Date: Sat, 20 Jan 2024 14:38:40 -0700 Subject: [PATCH] restructure to multiple courses --- .github/workflows/deploy.yml | 2 +- README.md | 3 +- _extensions/mcanouil/iconify/LICENSE | 21 ++ _extensions/mcanouil/iconify/_extension.yml | 7 + .../mcanouil/iconify/iconify-icon.min.js | 13 + _extensions/mcanouil/iconify/iconify.lua | 138 ++++++++ _quarto.yml | 266 ++++++++------- index.qmd | 70 ++-- .../going_forward.qmd | 0 {images => osc_intro/images}/code_review.png | Bin .../images}/conspiracy_board.png | Bin {images => osc_intro/images}/conveyor.png | Bin .../images}/cyber_punk_streets.png | Bin .../images}/decorative_cloth.png | Bin .../images}/factory_robots.png | Bin {images => osc_intro/images}/future_city.png | Bin {images => osc_intro/images}/hallway.png | Bin {images => osc_intro/images}/my_type.png | Bin {images => osc_intro/images}/scafold.png | Bin .../images}/sharing_papers.png | Bin {images => osc_intro/images}/smelly_code.svg | 0 {images => osc_intro/images}/style_guy.png | Bin {images => osc_intro/images}/therapy.png | Bin .../images}/workbench_explosion.png | Bin osc_intro/intro.qmd | 55 ++++ .../modules}/_template/exercises.qmd | 0 .../modules}/_template/overview.qmd | 0 .../modules}/_template/slides.qmd | 0 .../collaborative_development/exercises.qmd | 0 .../collaborative_development/overview.qmd | 0 .../collaborative_development/slides.qmd | 8 +- .../modules}/documentation/exercises.qmd | 0 .../modules}/documentation/overview.qmd | 0 .../modules}/documentation/slides.qmd | 10 +- .../modules}/functional_python/exercises.qmd | 0 .../functional_python/images/tangled_cat.png | Bin .../modules}/functional_python/overview.qmd | 0 .../modules}/functional_python/slides.qmd | 10 +- .../modules}/git/exercises.qmd | 0 .../modules}/git/images/bat_smack.avif | Bin .../modules}/git/images/hes-dead-jim.jpg | Bin .../images/stick_figures_speach_bubble.svg | 0 .../modules}/git/images/thought_tools.png | Bin .../modules}/git/images/yes.png | Bin .../modules}/git/overview.qmd | 0 {modules => osc_intro/modules}/git/slides.qmd | 10 +- .../object_oriented_python/exercises.qmd | 0 .../images/class_map.png | Bin .../images/misfit_wf_eq.png | Bin .../object_oriented_python/images/real_oo.png | Bin .../images/simple_oo.png | Bin .../object_oriented_python/overview.qmd | 0 .../object_oriented_python/slides.qmd | 10 +- .../modules}/structure/exercises.qmd | 0 .../images/science_repo_spectrum.svg | 0 .../modules}/structure/images/spectrum.png | Bin .../modules}/structure/overview.qmd | 0 .../modules}/structure/slides.qmd | 10 +- .../modules}/style/exercises.qmd | 0 .../modules}/style/images/babel.png | Bin .../modules}/style/images/code_smell.png | Bin .../images/pillar_of_programming_purpose.png | Bin .../images/programming_purpose_pillars.svg | 0 .../modules}/style/images/smelly_code.svg | 0 .../modules}/style/images/tim.png | Bin .../modules}/style/overview.qmd | 0 .../modules}/style/slides.qmd | 10 +- .../modules}/testing/examples/test_norm1.py | 0 .../modules}/testing/exercises.qmd | 0 .../modules}/testing/images/sentinel.jpg | Bin .../modules}/testing/images/test_pyramid.png | Bin .../modules}/testing/images/test_pyramid.svg | 0 .../modules}/testing/images/test_run.png | Bin .../modules}/testing/overview.qmd | 0 .../modules}/testing/slides.qmd | 10 +- setup.qmd => osc_intro/setup.qmd | 10 +- python_intro/images/blocks.png | Bin 0 -> 444682 bytes python_intro/images/data_structures_hub.png | Bin 0 -> 13829 bytes python_intro/intro.qmd | 15 + python_intro/modules/datatypes/excercises.qmd | 5 + python_intro/modules/datatypes/overview.qmd | 10 + python_intro/modules/datatypes/slides.qmd | 305 ++++++++++++++++++ slides.css | 7 + 83 files changed, 794 insertions(+), 211 deletions(-) create mode 100644 _extensions/mcanouil/iconify/LICENSE create mode 100644 _extensions/mcanouil/iconify/_extension.yml create mode 100644 _extensions/mcanouil/iconify/iconify-icon.min.js create mode 100644 _extensions/mcanouil/iconify/iconify.lua rename going_forward.qmd => osc_intro/going_forward.qmd (100%) rename {images => osc_intro/images}/code_review.png (100%) rename {images => osc_intro/images}/conspiracy_board.png (100%) rename {images => osc_intro/images}/conveyor.png (100%) rename {images => osc_intro/images}/cyber_punk_streets.png (100%) rename {images => osc_intro/images}/decorative_cloth.png (100%) rename {images => osc_intro/images}/factory_robots.png (100%) rename {images => osc_intro/images}/future_city.png (100%) rename {images => osc_intro/images}/hallway.png (100%) rename {images => osc_intro/images}/my_type.png (100%) rename {images => osc_intro/images}/scafold.png (100%) rename {images => osc_intro/images}/sharing_papers.png (100%) rename {images => osc_intro/images}/smelly_code.svg (100%) rename {images => osc_intro/images}/style_guy.png (100%) rename {images => osc_intro/images}/therapy.png (100%) rename {images => osc_intro/images}/workbench_explosion.png (100%) create mode 100644 osc_intro/intro.qmd rename {modules => osc_intro/modules}/_template/exercises.qmd (100%) rename {modules => osc_intro/modules}/_template/overview.qmd (100%) rename {modules => osc_intro/modules}/_template/slides.qmd (100%) rename {modules => osc_intro/modules}/collaborative_development/exercises.qmd (100%) rename {modules => osc_intro/modules}/collaborative_development/overview.qmd (100%) rename {modules => osc_intro/modules}/collaborative_development/slides.qmd (86%) rename {modules => osc_intro/modules}/documentation/exercises.qmd (100%) rename {modules => osc_intro/modules}/documentation/overview.qmd (100%) rename {modules => osc_intro/modules}/documentation/slides.qmd (97%) rename {modules => osc_intro/modules}/functional_python/exercises.qmd (100%) rename {modules => osc_intro/modules}/functional_python/images/tangled_cat.png (100%) rename {modules => osc_intro/modules}/functional_python/overview.qmd (100%) rename {modules => osc_intro/modules}/functional_python/slides.qmd (98%) rename {modules => osc_intro/modules}/git/exercises.qmd (100%) rename {modules => osc_intro/modules}/git/images/bat_smack.avif (100%) rename {modules => osc_intro/modules}/git/images/hes-dead-jim.jpg (100%) rename {modules => osc_intro/modules}/git/images/stick_figures_speach_bubble.svg (100%) rename {modules => osc_intro/modules}/git/images/thought_tools.png (100%) rename {modules => osc_intro/modules}/git/images/yes.png (100%) rename {modules => osc_intro/modules}/git/overview.qmd (100%) rename {modules => osc_intro/modules}/git/slides.qmd (99%) rename {modules => osc_intro/modules}/object_oriented_python/exercises.qmd (100%) rename {modules => osc_intro/modules}/object_oriented_python/images/class_map.png (100%) rename {modules => osc_intro/modules}/object_oriented_python/images/misfit_wf_eq.png (100%) rename {modules => osc_intro/modules}/object_oriented_python/images/real_oo.png (100%) rename {modules => osc_intro/modules}/object_oriented_python/images/simple_oo.png (100%) rename {modules => osc_intro/modules}/object_oriented_python/overview.qmd (100%) rename {modules => osc_intro/modules}/object_oriented_python/slides.qmd (98%) rename {modules => osc_intro/modules}/structure/exercises.qmd (100%) rename {modules => osc_intro/modules}/structure/images/science_repo_spectrum.svg (100%) rename {modules => osc_intro/modules}/structure/images/spectrum.png (100%) rename {modules => osc_intro/modules}/structure/overview.qmd (100%) rename {modules => osc_intro/modules}/structure/slides.qmd (95%) rename {modules => osc_intro/modules}/style/exercises.qmd (100%) rename {modules => osc_intro/modules}/style/images/babel.png (100%) rename {modules => osc_intro/modules}/style/images/code_smell.png (100%) rename {modules => osc_intro/modules}/style/images/pillar_of_programming_purpose.png (100%) rename {modules => osc_intro/modules}/style/images/programming_purpose_pillars.svg (100%) rename {modules => osc_intro/modules}/style/images/smelly_code.svg (100%) rename {modules => osc_intro/modules}/style/images/tim.png (100%) rename {modules => osc_intro/modules}/style/overview.qmd (100%) rename {modules => osc_intro/modules}/style/slides.qmd (98%) rename {modules => osc_intro/modules}/testing/examples/test_norm1.py (100%) rename {modules => osc_intro/modules}/testing/exercises.qmd (100%) rename {modules => osc_intro/modules}/testing/images/sentinel.jpg (100%) rename {modules => osc_intro/modules}/testing/images/test_pyramid.png (100%) rename {modules => osc_intro/modules}/testing/images/test_pyramid.svg (100%) rename {modules => osc_intro/modules}/testing/images/test_run.png (100%) rename {modules => osc_intro/modules}/testing/overview.qmd (100%) rename {modules => osc_intro/modules}/testing/slides.qmd (98%) rename setup.qmd => osc_intro/setup.qmd (82%) create mode 100644 python_intro/images/blocks.png create mode 100644 python_intro/images/data_structures_hub.png create mode 100644 python_intro/intro.qmd create mode 100644 python_intro/modules/datatypes/excercises.qmd create mode 100644 python_intro/modules/datatypes/overview.qmd create mode 100644 python_intro/modules/datatypes/slides.qmd diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 2b24355..91fb32b 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -34,7 +34,7 @@ jobs: - name: Install quarto uses: quarto-dev/quarto-actions/setup@v2 with: - version: "1.2.313" + version: "1.2.475" # Note cant bump passed 1.2 until quarto_cli #3973 is fixed. - name: print quarto version run: | diff --git a/README.md b/README.md index 01720f6..01aadb8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # OpenSourceCourse -This is the website for OpenSourceCourse, a short course designed to help engineers and scientists contribute to -the open-source scientific python ecosystem. +This is the website for OpenSourceCourse, a collection of educational material designed to help engineers and scientists contribute to the open-source scientific python ecosystem. The course website is found [here](https://opensourcecourse.dev/). diff --git a/_extensions/mcanouil/iconify/LICENSE b/_extensions/mcanouil/iconify/LICENSE new file mode 100644 index 0000000..8965781 --- /dev/null +++ b/_extensions/mcanouil/iconify/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Mickaël Canouil + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/_extensions/mcanouil/iconify/_extension.yml b/_extensions/mcanouil/iconify/_extension.yml new file mode 100644 index 0000000..77dde62 --- /dev/null +++ b/_extensions/mcanouil/iconify/_extension.yml @@ -0,0 +1,7 @@ +title: Iconify support +author: Mickaël Canouil +version: 1.0.8 +quarto-required: ">=1.2.280" +contributes: + shortcodes: + - iconify.lua diff --git a/_extensions/mcanouil/iconify/iconify-icon.min.js b/_extensions/mcanouil/iconify/iconify-icon.min.js new file mode 100644 index 0000000..0647165 --- /dev/null +++ b/_extensions/mcanouil/iconify/iconify-icon.min.js @@ -0,0 +1,13 @@ +/** +* (c) Iconify +* +* For the full copyright and license information, please view the license.txt +* files at https://github.com/iconify/iconify +* +* Licensed under MIT. +* Source: https://github.com/iconify/code/tree/gh-pages/iconify-icon +* +* @license MIT +* @version 1.0.8 +*/ +!function(){"use strict";const t=Object.freeze({left:0,top:0,width:16,height:16}),e=Object.freeze({rotate:0,vFlip:!1,hFlip:!1}),n=Object.freeze({...t,...e}),o=Object.freeze({...n,body:"",hidden:!1}),i=Object.freeze({width:null,height:null}),r=Object.freeze({...i,...e});const s=/[\s,]+/;const c={...r,preserveAspectRatio:""};function a(t){const e={...c},n=(e,n)=>t.getAttribute(e)||n;var o;return e.width=n("width",null),e.height=n("height",null),e.rotate=function(t,e=0){const n=t.replace(/^-?[0-9.]*/,"");function o(t){for(;t<0;)t+=4;return t%4}if(""===n){const e=parseInt(t);return isNaN(e)?0:o(e)}if(n!==t){let e=0;switch(n){case"%":e=25;break;case"deg":e=90}if(e){let i=parseFloat(t.slice(0,t.length-n.length));return isNaN(i)?0:(i/=e,i%1==0?o(i):0)}}return e}(n("rotate","")),o=e,n("flip","").split(s).forEach((t=>{switch(t.trim()){case"horizontal":o.hFlip=!0;break;case"vertical":o.vFlip=!0}})),e.preserveAspectRatio=n("preserveAspectRatio",n("preserveaspectratio","")),e}const u=/^[a-z0-9]+(-[a-z0-9]+)*$/,l=(t,e,n,o="")=>{const i=t.split(":");if("@"===t.slice(0,1)){if(i.length<2||i.length>3)return null;o=i.shift().slice(1)}if(i.length>3||!i.length)return null;if(i.length>1){const t=i.pop(),n=i.pop(),r={provider:i.length>0?i[0]:o,prefix:n,name:t};return e&&!f(r)?null:r}const r=i[0],s=r.split("-");if(s.length>1){const t={provider:o,prefix:s.shift(),name:s.join("-")};return e&&!f(t)?null:t}if(n&&""===o){const t={provider:o,prefix:"",name:r};return e&&!f(t,n)?null:t}return null},f=(t,e)=>!!t&&!(""!==t.provider&&!t.provider.match(u)||!(e&&""===t.prefix||t.prefix.match(u))||!t.name.match(u));function d(t,n){const i=function(t,e){const n={};!t.hFlip!=!e.hFlip&&(n.hFlip=!0),!t.vFlip!=!e.vFlip&&(n.vFlip=!0);const o=((t.rotate||0)+(e.rotate||0))%4;return o&&(n.rotate=o),n}(t,n);for(const r in o)r in e?r in t&&!(r in i)&&(i[r]=e[r]):r in n?i[r]=n[r]:r in t&&(i[r]=t[r]);return i}function h(t,e,n){const o=t.icons,i=t.aliases||Object.create(null);let r={};function s(t){r=d(o[t]||i[t],r)}return s(e),n.forEach(s),d(t,r)}function p(t,e){const n=[];if("object"!=typeof t||"object"!=typeof t.icons)return n;t.not_found instanceof Array&&t.not_found.forEach((t=>{e(t,null),n.push(t)}));const o=function(t,e){const n=t.icons,o=t.aliases||Object.create(null),i=Object.create(null);return(e||Object.keys(n).concat(Object.keys(o))).forEach((function t(e){if(n[e])return i[e]=[];if(!(e in i)){i[e]=null;const n=o[e]&&o[e].parent,r=n&&t(n);r&&(i[e]=[n].concat(r))}return i[e]})),i}(t);for(const i in o){const r=o[i];r&&(e(i,h(t,i,r)),n.push(i))}return n}const g={provider:"",aliases:{},not_found:{},...t};function m(t,e){for(const n in e)if(n in t&&typeof t[n]!=typeof e[n])return!1;return!0}function b(t){if("object"!=typeof t||null===t)return null;const e=t;if("string"!=typeof e.prefix||!t.icons||"object"!=typeof t.icons)return null;if(!m(t,g))return null;const n=e.icons;for(const t in n){const e=n[t];if(!t.match(u)||"string"!=typeof e.body||!m(e,o))return null}const i=e.aliases||Object.create(null);for(const t in i){const e=i[t],r=e.parent;if(!t.match(u)||"string"!=typeof r||!n[r]&&!i[r]||!m(e,o))return null}return e}const y=Object.create(null);function v(t,e){const n=y[t]||(y[t]=Object.create(null));return n[e]||(n[e]=function(t,e){return{provider:t,prefix:e,icons:Object.create(null),missing:new Set}}(t,e))}function x(t,e){return b(e)?p(e,((e,n)=>{n?t.icons[e]=n:t.missing.add(e)})):[]}function w(t,e){let n=[];return("string"==typeof t?[t]:Object.keys(y)).forEach((t=>{("string"==typeof t&&"string"==typeof e?[e]:Object.keys(y[t]||{})).forEach((e=>{const o=v(t,e);n=n.concat(Object.keys(o.icons).map((n=>(""!==t?"@"+t+":":"")+e+":"+n)))}))})),n}let k=!1;function j(t){return"boolean"==typeof t&&(k=t),k}function A(t){const e="string"==typeof t?l(t,!0,k):t;if(e){const t=v(e.provider,e.prefix),n=e.name;return t.icons[n]||(t.missing.has(n)?null:void 0)}}function _(t,e){const n=l(t,!0,k);if(!n)return!1;return function(t,e,n){try{if("string"==typeof n.body)return t.icons[e]={...n},!0}catch(t){}return!1}(v(n.provider,n.prefix),n.name,e)}function C(t,e){if("object"!=typeof t)return!1;if("string"!=typeof e&&(e=t.provider||""),k&&!e&&!t.prefix){let e=!1;return b(t)&&(t.prefix="",p(t,((t,n)=>{n&&_(t,n)&&(e=!0)}))),e}const n=t.prefix;if(!f({provider:e,prefix:n,name:"a"}))return!1;return!!x(v(e,n),t)}function O(t){return!!A(t)}function S(t){const e=A(t);return e?{...n,...e}:null}function I(t,e){t.forEach((t=>{const n=t.loaderCallbacks;n&&(t.loaderCallbacks=n.filter((t=>t.id!==e)))}))}let E=0;const M=Object.create(null);function T(t,e){M[t]=e}function F(t){return M[t]||M[""]}var P={resources:[],index:0,timeout:2e3,rotate:750,random:!1,dataAfterTimeout:!1};function N(t,e,n,o){const i=t.resources.length,r=t.random?Math.floor(Math.random()*i):t.index;let s;if(t.random){let e=t.resources.slice(0);for(s=[];e.length>1;){const t=Math.floor(Math.random()*e.length);s.push(e[t]),e=e.slice(0,t).concat(e.slice(t+1))}s=s.concat(e)}else s=t.resources.slice(r).concat(t.resources.slice(0,r));const c=Date.now();let a,u="pending",l=0,f=null,d=[],h=[];function p(){f&&(clearTimeout(f),f=null)}function g(){"pending"===u&&(u="aborted"),p(),d.forEach((t=>{"pending"===t.status&&(t.status="aborted")})),d=[]}function m(t,e){e&&(h=[]),"function"==typeof t&&h.push(t)}function b(){u="failed",h.forEach((t=>{t(void 0,a)}))}function y(){d.forEach((t=>{"pending"===t.status&&(t.status="aborted")})),d=[]}function v(){if("pending"!==u)return;p();const o=s.shift();if(void 0===o)return d.length?void(f=setTimeout((()=>{p(),"pending"===u&&(y(),b())}),t.timeout)):void b();const i={status:"pending",resource:o,callback:(e,n)=>{!function(e,n,o){const i="success"!==n;switch(d=d.filter((t=>t!==e)),u){case"pending":break;case"failed":if(i||!t.dataAfterTimeout)return;break;default:return}if("abort"===n)return a=o,void b();if(i)return a=o,void(d.length||(s.length?v():b()));if(p(),y(),!t.random){const n=t.resources.indexOf(e.resource);-1!==n&&n!==t.index&&(t.index=n)}u="completed",h.forEach((t=>{t(o)}))}(i,e,n)}};d.push(i),l++,f=setTimeout(v,t.rotate),n(o,e,i.callback)}return"function"==typeof o&&h.push(o),setTimeout(v),function(){return{startTime:c,payload:e,status:u,queriesSent:l,queriesPending:d.length,subscribe:m,abort:g}}}function L(t){const e={...P,...t};let n=[];function o(){n=n.filter((t=>"pending"===t().status))}return{query:function(t,i,r){const s=N(e,t,i,((t,e)=>{o(),r&&r(t,e)}));return n.push(s),s},find:function(t){return n.find((e=>t(e)))||null},setIndex:t=>{e.index=t},getIndex:()=>e.index,cleanup:o}}function R(t){let e;if("string"==typeof t.resources)e=[t.resources];else if(e=t.resources,!(e instanceof Array&&e.length))return null;return{resources:e,path:t.path||"/",maxURL:t.maxURL||500,rotate:t.rotate||750,timeout:t.timeout||5e3,random:!0===t.random,index:t.index||0,dataAfterTimeout:!1!==t.dataAfterTimeout}}const z=Object.create(null),Q=["https://api.simplesvg.com","https://api.unisvg.com"],q=[];for(;Q.length>0;)1===Q.length||Math.random()>.5?q.push(Q.shift()):q.push(Q.pop());function D(t,e){const n=R(e);return null!==n&&(z[t]=n,!0)}function U(t){return z[t]}function J(){return Object.keys(z)}function H(){}z[""]=R({resources:["https://api.iconify.design"].concat(q)});const $=Object.create(null);function B(t,e,n){let o,i;if("string"==typeof t){const e=F(t);if(!e)return n(void 0,424),H;i=e.send;const r=function(t){if(!$[t]){const e=U(t);if(!e)return;const n={config:e,redundancy:L(e)};$[t]=n}return $[t]}(t);r&&(o=r.redundancy)}else{const e=R(t);if(e){o=L(e);const n=F(t.resources?t.resources[0]:"");n&&(i=n.send)}}return o&&i?o.query(e,i,n)().abort:(n(void 0,424),H)}const G="iconify2",V="iconify",K=V+"-count",W=V+"-version",X=36e5,Y=168;function Z(t,e){try{return t.getItem(e)}catch(t){}}function tt(t,e,n){try{return t.setItem(e,n),!0}catch(t){}}function et(t,e){try{t.removeItem(e)}catch(t){}}function nt(t,e){return tt(t,K,e.toString())}function ot(t){return parseInt(Z(t,K))||0}const it={local:!0,session:!0},rt={local:new Set,session:new Set};let st=!1;let ct="undefined"==typeof window?{}:window;function at(t){const e=t+"Storage";try{if(ct&&ct[e]&&"number"==typeof ct[e].length)return ct[e]}catch(t){}it[t]=!1}function ut(t,e){const n=at(t);if(!n)return;const o=Z(n,W);if(o!==G){if(o){const t=ot(n);for(let e=0;e{const o=V+t.toString(),r=Z(n,o);if("string"==typeof r){try{const n=JSON.parse(r);if("object"==typeof n&&"number"==typeof n.cached&&n.cached>i&&"string"==typeof n.provider&&"object"==typeof n.data&&"string"==typeof n.data.prefix&&e(n,t))return!0}catch(t){}et(n,o)}};let s=ot(n);for(let e=s-1;e>=0;e--)r(e)||(e===s-1?(s--,nt(n,s)):rt[t].add(e))}function lt(){if(!st){st=!0;for(const t in it)ut(t,(t=>{const e=t.data,n=v(t.provider,e.prefix);if(!x(n,e).length)return!1;const o=e.lastModified||-1;return n.lastModifiedCached=n.lastModifiedCached?Math.min(n.lastModifiedCached,o):o,!0}))}}function ft(t,e){function n(n){let o;if(!it[n]||!(o=at(n)))return;const i=rt[n];let r;if(i.size)i.delete(r=Array.from(i).shift());else if(r=ot(o),!nt(o,r+1))return;const s={cached:Math.floor(Date.now()/X),provider:t.provider,data:e};return tt(o,V+r.toString(),JSON.stringify(s))}st||lt(),e.lastModified&&!function(t,e){const n=t.lastModifiedCached;if(n&&n>=e)return n===e;if(t.lastModifiedCached=e,n)for(const n in it)ut(n,(n=>{const o=n.data;return n.provider!==t.provider||o.prefix!==t.prefix||o.lastModified===e}));return!0}(t,e.lastModified)||Object.keys(e.icons).length&&(e.not_found&&delete(e=Object.assign({},e)).not_found,n("local")||n("session"))}function dt(){}function ht(t){t.iconsLoaderFlag||(t.iconsLoaderFlag=!0,setTimeout((()=>{t.iconsLoaderFlag=!1,function(t){t.pendingCallbacksFlag||(t.pendingCallbacksFlag=!0,setTimeout((()=>{t.pendingCallbacksFlag=!1;const e=t.loaderCallbacks?t.loaderCallbacks.slice(0):[];if(!e.length)return;let n=!1;const o=t.provider,i=t.prefix;e.forEach((e=>{const r=e.icons,s=r.pending.length;r.pending=r.pending.filter((e=>{if(e.prefix!==i)return!0;const s=e.name;if(t.icons[s])r.loaded.push({provider:o,prefix:i,name:s});else{if(!t.missing.has(s))return n=!0,!0;r.missing.push({provider:o,prefix:i,name:s})}return!1})),r.pending.length!==s&&(n||I([t],e.id),e.callback(r.loaded.slice(0),r.missing.slice(0),r.pending.slice(0),e.abort))}))})))}(t)})))}const pt=(t,e)=>{const n=function(t,e=!0,n=!1){const o=[];return t.forEach((t=>{const i="string"==typeof t?l(t,e,n):t;i&&o.push(i)})),o}(t,!0,j()),o=function(t){const e={loaded:[],missing:[],pending:[]},n=Object.create(null);t.sort(((t,e)=>t.provider!==e.provider?t.provider.localeCompare(e.provider):t.prefix!==e.prefix?t.prefix.localeCompare(e.prefix):t.name.localeCompare(e.name)));let o={provider:"",prefix:"",name:""};return t.forEach((t=>{if(o.name===t.name&&o.prefix===t.prefix&&o.provider===t.provider)return;o=t;const i=t.provider,r=t.prefix,s=t.name,c=n[i]||(n[i]=Object.create(null)),a=c[r]||(c[r]=v(i,r));let u;u=s in a.icons?e.loaded:""===r||a.missing.has(s)?e.missing:e.pending;const l={provider:i,prefix:r,name:s};u.push(l)})),e}(n);if(!o.pending.length){let t=!0;return e&&setTimeout((()=>{t&&e(o.loaded,o.missing,o.pending,dt)})),()=>{t=!1}}const i=Object.create(null),r=[];let s,c;return o.pending.forEach((t=>{const{provider:e,prefix:n}=t;if(n===c&&e===s)return;s=e,c=n,r.push(v(e,n));const o=i[e]||(i[e]=Object.create(null));o[n]||(o[n]=[])})),o.pending.forEach((t=>{const{provider:e,prefix:n,name:o}=t,r=v(e,n),s=r.pendingIcons||(r.pendingIcons=new Set);s.has(o)||(s.add(o),i[e][n].push(o))})),r.forEach((t=>{const{provider:e,prefix:n}=t;i[e][n].length&&function(t,e){t.iconsToLoad?t.iconsToLoad=t.iconsToLoad.concat(e).sort():t.iconsToLoad=e,t.iconsQueueFlag||(t.iconsQueueFlag=!0,setTimeout((()=>{t.iconsQueueFlag=!1;const{provider:e,prefix:n}=t,o=t.iconsToLoad;let i;delete t.iconsToLoad,o&&(i=F(e))&&i.prepare(e,n,o).forEach((n=>{B(e,n,(e=>{if("object"!=typeof e)n.icons.forEach((e=>{t.missing.add(e)}));else try{const n=x(t,e);if(!n.length)return;const o=t.pendingIcons;o&&n.forEach((t=>{o.delete(t)})),ft(t,e)}catch(t){console.error(t)}ht(t)}))}))})))}(t,i[e][n])})),e?function(t,e,n){const o=E++,i=I.bind(null,n,o);if(!e.pending.length)return i;const r={id:o,icons:e,callback:t,abort:i};return n.forEach((t=>{(t.loaderCallbacks||(t.loaderCallbacks=[])).push(r)})),i}(e,o,r):dt},gt=t=>new Promise(((e,o)=>{const i="string"==typeof t?l(t,!0):t;i?pt([i||t],(r=>{if(r.length&&i){const t=A(i);if(t)return void e({...n,...t})}o(t)})):o(t)}));function mt(t,e){const n="string"==typeof t?l(t,!0,!0):null;if(!n){const e=function(t){try{const e="string"==typeof t?JSON.parse(t):t;if("string"==typeof e.body)return{...e}}catch(t){}}(t);return{value:t,data:e}}const o=A(n);if(void 0!==o||!n.prefix)return{value:t,name:n,data:o};const i=pt([n],(()=>e(t,n,A(n))));return{value:t,name:n,loading:i}}function bt(t){return t.hasAttribute("inline")}let yt=!1;try{yt=0===navigator.vendor.indexOf("Apple")}catch(t){}const vt=/(-?[0-9.]*[0-9]+[0-9.]*)/g,xt=/^-?[0-9.]*[0-9]+[0-9.]*$/g;function wt(t,e,n){if(1===e)return t;if(n=n||100,"number"==typeof t)return Math.ceil(t*e*n)/n;if("string"!=typeof t)return t;const o=t.split(vt);if(null===o||!o.length)return t;const i=[];let r=o.shift(),s=xt.test(r);for(;;){if(s){const t=parseFloat(r);isNaN(t)?i.push(r):i.push(Math.ceil(t*e*n)/n)}else i.push(r);if(r=o.shift(),void 0===r)return i.join("");s=!s}}const kt=t=>"unset"===t||"undefined"===t||"none"===t;function jt(t,e){const o={...n,...t},i={...r,...e},s={left:o.left,top:o.top,width:o.width,height:o.height};let c=o.body;[o,i].forEach((t=>{const e=[],n=t.hFlip,o=t.vFlip;let i,r=t.rotate;switch(n?o?r+=2:(e.push("translate("+(s.width+s.left).toString()+" "+(0-s.top).toString()+")"),e.push("scale(-1 1)"),s.top=s.left=0):o&&(e.push("translate("+(0-s.left).toString()+" "+(s.height+s.top).toString()+")"),e.push("scale(1 -1)"),s.top=s.left=0),r<0&&(r-=4*Math.floor(r/4)),r%=4,r){case 1:i=s.height/2+s.top,e.unshift("rotate(90 "+i.toString()+" "+i.toString()+")");break;case 2:e.unshift("rotate(180 "+(s.width/2+s.left).toString()+" "+(s.height/2+s.top).toString()+")");break;case 3:i=s.width/2+s.left,e.unshift("rotate(-90 "+i.toString()+" "+i.toString()+")")}r%2==1&&(s.left!==s.top&&(i=s.left,s.left=s.top,s.top=i),s.width!==s.height&&(i=s.width,s.width=s.height,s.height=i)),e.length&&(c=''+c+"")}));const a=i.width,u=i.height,l=s.width,f=s.height;let d,h;null===a?(h=null===u?"1em":"auto"===u?f:u,d=wt(h,l/f)):(d="auto"===a?l:a,h=null===u?wt(d,f/l):"auto"===u?f:u);const p={},g=(t,e)=>{kt(e)||(p[t]=e.toString())};return g("width",d),g("height",h),p.viewBox=s.left.toString()+" "+s.top.toString()+" "+l.toString()+" "+f.toString(),{attributes:p,body:c}}let At=(()=>{let t;try{if(t=fetch,"function"==typeof t)return t}catch(t){}})();function _t(t){At=t}function Ct(){return At}const Ot={prepare:(t,e,n)=>{const o=[],i=function(t,e){const n=U(t);if(!n)return 0;let o;if(n.maxURL){let t=0;n.resources.forEach((e=>{const n=e;t=Math.max(t,n.length)}));const i=e+".json?icons=";o=n.maxURL-t-n.path.length-i.length}else o=0;return o}(t,e),r="icons";let s={type:r,provider:t,prefix:e,icons:[]},c=0;return n.forEach(((n,a)=>{c+=n.length+1,c>=i&&a>0&&(o.push(s),s={type:r,provider:t,prefix:e,icons:[]},c=n.length),s.icons.push(n)})),o.push(s),o},send:(t,e,n)=>{if(!At)return void n("abort",424);let o=function(t){if("string"==typeof t){const e=U(t);if(e)return e.path}return"/"}(e.provider);switch(e.type){case"icons":{const t=e.prefix,n=e.icons.join(",");o+=t+".json?"+new URLSearchParams({icons:n}).toString();break}case"custom":{const t=e.uri;o+="/"===t.slice(0,1)?t.slice(1):t;break}default:return void n("abort",400)}let i=503;At(t+o).then((t=>{const e=t.status;if(200===e)return i=501,t.json();setTimeout((()=>{n(function(t){return 404===t}(e)?"abort":"next",e)}))})).then((t=>{"object"==typeof t&&null!==t?setTimeout((()=>{n("success",t)})):setTimeout((()=>{404===t?n("abort",t):n("next",i)}))})).catch((()=>{n("next",i)}))}};function St(t,e){switch(t){case"local":case"session":it[t]=e;break;case"all":for(const t in it)it[t]=e}}const It="data-style";let Et="";function Mt(t){Et=t}function Tt(t,e){let n=Array.from(t.childNodes).find((t=>t.hasAttribute&&t.hasAttribute(It)));n||(n=document.createElement("style"),n.setAttribute(It,It),t.appendChild(n)),n.textContent=":host{display:inline-block;vertical-align:"+(e?"-0.125em":"0")+"}span,svg{display:block}"+Et}function Ft(t,e){let n=-1===t.indexOf("xlink:")?"":' xmlns:xlink="http://www.w3.org/1999/xlink"';for(const t in e)n+=" "+t+'="'+e[t]+'"';return'"+t+""}const Pt={"background-color":"currentColor"},Nt={"background-color":"transparent"},Lt={image:"var(--svg)",repeat:"no-repeat",size:"100% 100%"},Rt={"-webkit-mask":Pt,mask:Pt,background:Nt};for(const t in Rt){const e=Rt[t];for(const n in Lt)e[t+"-"+n]=Lt[n]}function zt(t){return t?t+(t.match(/^[-0-9.]+$/)?"px":""):"inherit"}let Qt;function qt(t){return void 0===Qt&&function(){try{Qt=window.trustedTypes.createPolicy("iconify",{createHTML:t=>t})}catch(t){Qt=null}}(),Qt?Qt.createHTML(t):t}function Dt(t,e){const o=e.icon.data,i=e.customisations,r=jt(o,i);i.preserveAspectRatio&&(r.attributes.preserveAspectRatio=i.preserveAspectRatio);const s=e.renderedMode;let c;if("svg"===s)c=function(t){const e=document.createElement("span"),n=t.attributes;let o="";n.width||(o="width: inherit;"),n.height||(o+="height: inherit;"),o&&(n.style=o);const i=Ft(t.body,n);return e.innerHTML=qt(i),e.firstChild}(r);else c=function(t,e,n){const o=document.createElement("span");let i=t.body;-1!==i.indexOf("/g,"%3E").replace(/\s+/g," ")}(u)+'")'),c=o.style,a={"--svg":s,width:zt(r.width),height:zt(r.height),...n?Pt:Nt};var u;for(const t in a)c.setProperty(t,a[t]);return o}(r,{...n,...o},"mask"===s);const a=Array.from(t.childNodes).find((t=>{const e=t.tagName&&t.tagName.toUpperCase();return"SPAN"===e||"SVG"===e}));a?"SPAN"===c.tagName&&a.tagName===c.tagName?a.setAttribute("style",c.getAttribute("style")):t.replaceChild(c,a):t.appendChild(c)}function Ut(t,e,n){return{rendered:!1,inline:e,icon:t,lastRender:n&&(n.rendered?n:n.lastRender)}}!function(t="iconify-icon"){let e,n;try{e=window.customElements,n=window.HTMLElement}catch(t){return}if(!e||!n)return;const o=e.get(t);if(o)return o;const i=["icon","mode","inline","width","height","rotate","flip"],r=class extends n{_shadowRoot;_state;_checkQueued=!1;constructor(){super();const t=this._shadowRoot=this.attachShadow({mode:"open"}),e=bt(this);Tt(t,e),this._state=Ut({value:""},e),this._queueCheck()}static get observedAttributes(){return i.slice(0)}attributeChangedCallback(t){if("inline"===t){const t=bt(this),e=this._state;t!==e.inline&&(e.inline=t,Tt(this._shadowRoot,t))}else this._queueCheck()}get icon(){const t=this.getAttribute("icon");if(t&&"{"===t.slice(0,1))try{return JSON.parse(t)}catch(t){}return t}set icon(t){"object"==typeof t&&(t=JSON.stringify(t)),this.setAttribute("icon",t)}get inline(){return bt(this)}set inline(t){t?this.setAttribute("inline","true"):this.removeAttribute("inline")}restartAnimation(){const t=this._state;if(t.rendered){const e=this._shadowRoot;if("svg"===t.renderedMode)try{return void e.lastChild.setCurrentTime(0)}catch(t){}Dt(e,t)}}get status(){const t=this._state;return t.rendered?"rendered":null===t.icon.data?"failed":"loading"}_queueCheck(){this._checkQueued||(this._checkQueued=!0,setTimeout((()=>{this._check()})))}_check(){if(!this._checkQueued)return;this._checkQueued=!1;const t=this._state,e=this.getAttribute("icon");if(e!==t.icon.value)return void this._iconChanged(e);if(!t.rendered)return;const n=this.getAttribute("mode"),o=a(this);(t.attrMode!==n||function(t,e){for(const n in c)if(t[n]!==e[n])return!0;return!1}(t.customisations,o))&&this._renderIcon(t.icon,o,n)}_iconChanged(t){const e=mt(t,((t,e,n)=>{const o=this._state;if(o.rendered||this.getAttribute("icon")!==t)return;const i={value:t,name:e,data:n};i.data?this._gotIconData(i):o.icon=i}));e.data?this._gotIconData(e):this._state=Ut(e,this._state.inline,this._state)}_gotIconData(t){this._checkQueued=!1,this._renderIcon(t,a(this),this.getAttribute("mode"))}_renderIcon(t,e,n){const o=function(t,e){switch(e){case"svg":case"bg":case"mask":return e}return"style"===e||!yt&&-1!==t.indexOf("{t in r.prototype||Object.defineProperty(r.prototype,t,{get:function(){return this.getAttribute(t)},set:function(e){null!==e?this.setAttribute(t,e):this.removeAttribute(t)}})}));const s=function(){let t;T("",Ot),j(!0);try{t=window}catch(t){}if(t){if(lt(),void 0!==t.IconifyPreload){const e=t.IconifyPreload,n="Invalid IconifyPreload syntax.";"object"==typeof e&&null!==e&&(e instanceof Array?e:[e]).forEach((t=>{try{("object"!=typeof t||null===t||t instanceof Array||"object"!=typeof t.icons||"string"!=typeof t.prefix||!C(t))&&console.error(n)}catch(t){console.error(n)}}))}if(void 0!==t.IconifyProviders){const e=t.IconifyProviders;if("object"==typeof e&&null!==e)for(const t in e){const n="IconifyProviders["+t+"] is invalid.";try{const o=e[t];if("object"!=typeof o||!o||void 0===o.resources)continue;D(t,o)||console.error(n)}catch(t){console.error(n)}}}}return{enableCache:t=>St(t,!0),disableCache:t=>St(t,!1),iconExists:O,getIcon:S,listIcons:w,addIcon:_,addCollection:C,calculateSize:wt,buildIcon:jt,loadIcons:pt,loadIcon:gt,addAPIProvider:D,appendCustomStyle:Mt,_api:{getAPIConfig:U,setAPIModule:T,sendAPIQuery:B,setFetch:_t,getFetch:Ct,listAPIProviders:J}}}();for(const t in s)r[t]=r.prototype[t]=s[t];e.define(t,r)}()}(); diff --git a/_extensions/mcanouil/iconify/iconify.lua b/_extensions/mcanouil/iconify/iconify.lua new file mode 100644 index 0000000..488b331 --- /dev/null +++ b/_extensions/mcanouil/iconify/iconify.lua @@ -0,0 +1,138 @@ +--[[ +# MIT License +# +# Copyright (c) Mickaël Canouil +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +]] + +local function ensure_html_deps() + quarto.doc.add_html_dependency({ + name = 'iconify', + version = '1.0.8', + scripts = {"iconify-icon.min.js"} + }) +end + +local function is_empty(s) + return s == nil or s == '' +end + +local function is_valid_size(size) + if is_empty(size) then + return '' + end + local size_table = { + ["tiny"] = "0.5em", + ["scriptsize"] = "0.7em", + ["footnotesize"] = "0.8em", + ["small"] = "0.9em", + ["normalsize"] = "1em", + ["large"] = "1.2em", + ["Large"] = "1.5em", + ["LARGE"] = "1.75em", + ["huge"] = "2em", + ["Huge"] = "2.5em", + ["1x"] = "1em", + ["2x"] = "2em", + ["3x"] = "3em", + ["4x"] = "4em", + ["5x"] = "5em", + ["6x"] = "6em", + ["7x"] = "7em", + ["8x"] = "8em", + ["9x"] = "9em", + ["10x"] = "10em", + ["2xs"] = "0.625em", + ["xs"] = "0.75em", + ["sm"] = "0.875em", + ["lg"] = "1.25em", + ["xl"] = "1.5em", + ["2xl"] = "2em" + } + for key, value in pairs(size_table) do + if key == size then + return 'font-size: ' .. value .. ';' + end + end + return 'font-size: ' .. size .. ';' +end + +return { + ["iconify"] = function(args, kwargs) + -- detect html (excluding epub which won't handle fa) + if quarto.doc.is_format("html:js") then + ensure_html_deps() + local set = "fluent-emoji" + local icon = pandoc.utils.stringify(args[1]) + if #args > 1 then + set = icon + icon = pandoc.utils.stringify(args[2]) + end + + local attributes = ' icon="' .. set .. ':' .. icon .. '"' + local label = '"Icon ' .. icon .. ' from ' .. set .. ' Iconify.design set."' + + local size = is_valid_size(pandoc.utils.stringify(kwargs["size"])) + if not is_empty(size) then + attributes = attributes .. ' style="' .. size .. '"' + end + + local aria_label = pandoc.utils.stringify(kwargs["label"]) + if is_empty(aria_label) then + aria_label = ' aria-label="' .. label .. '"' + else + attributes = attributes .. aria_label + end + local title = pandoc.utils.stringify(kwargs["title"]) + if is_empty(title) then + title = ' title="' .. label .. '"' + else + attributes = attributes .. title + end + -- local style = pandoc.utils.stringify(kwargs["style"]) + -- if not is_empty(style) then + -- local attributes = attributes .. ' style="' .. style .. '"' + -- end + local width = pandoc.utils.stringify(kwargs["width"]) + if not is_empty(width) and is_empty(size) then + attributes = attributes .. ' width="' .. width .. '"' + end + local height = pandoc.utils.stringify(kwargs["height"]) + if not is_empty(height) and is_empty(size) then + attributes = attributes .. ' height="' .. height .. '"' + end + local flip = pandoc.utils.stringify(kwargs["flip"]) + if not is_empty(flip) then + attributes = attributes .. ' flip="' .. flip.. '"' + end + local rotate = pandoc.utils.stringify(kwargs["rotate"]) + if not is_empty(rotate) then + attributes = attributes .. ' rotate="' .. rotate .. '"' + end + + return pandoc.RawInline( + 'html', + '' + ) + else + return pandoc.Null() + end + end +} diff --git a/_quarto.yml b/_quarto.yml index f7388e5..737a1e8 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -2,139 +2,181 @@ project: type: website output-dir: _site +format: + html: + toc: true + theme: + light: [cosmo, theme.scss] + dark: darkly + code-copy: true + code-overflow: wrap + css: styles.css + website: title: "OSC" image: "images/logo.png" favicon: "images/osc_favi.png" - # google-analytics: "G-FV9Z7SDZ0M" - # open-graph: true twitter-card: true site-url: https://github.com/opensourcecourse repo-url: https://github.com/opensourcecourse/website repo-actions: [edit] page-navigation: true - sidebar: - style: "floating" - collapse-level: 2 - title: "Open Source Course" - subtitle: 'OSC' - logo: "images/oss_gateway.png" - search: true - contents: - - index.qmd - - setup.qmd - - - section: "Modules" - contents: - - - section: "Git" - href: modules/git/overview.qmd - contents: - - text: 'overview' - href: modules/git/overview.qmd - - text: 'slides' - href: modules/git/slides.qmd - - text: "exercises" - href: modules/git/exercises.qmd - - - section: "Style" - href: modules/style/overview.qmd - contents: - - text: 'overview' - href: modules/style/overview.qmd - - text: 'slides' - href: modules/style/slides.qmd - - text: "exercises" - href: modules/style/exercises.qmd - - - section: "Object Oriented Python" - href: modules/object_oriented_python/overview.qmd - contents: - - text: 'overview' - href: modules/object_oriented_python/overview.qmd - - text: 'slides' - href: modules/object_oriented_python/slides.qmd - - text: "exercises" - href: modules/object_oriented_python/exercises.qmd - - - section: "Functional Python" - href: modules/functional_python/overview.qmd - contents: - - text: 'overview' - href: modules/functional_python/overview.qmd - - text: 'slides' - href: modules/functional_python/slides.qmd - - text: "exercises" - href: modules/functional_python/exercises.qmd - - - section: "Testing" - href: modules/testing/overview.qmd - contents: - - text: 'overview' - href: modules/testing/overview.qmd - - text: 'slides' - href: modules/testing/slides.qmd - - text: "exercises" - href: modules/testing/exercises.qmd - - - section: "Documentation" - href: modules/documentation/overview.qmd - contents: - - text: 'overview' - href: modules/documentation/overview.qmd - - text: 'slides' - href: modules/documentation/slides.qmd - - text: "exercises" - href: modules/documentation/exercises.qmd - - - section: "Collaborative Development" - href: modules/collaborative_development/overview.qmd - contents: - - text: 'overview' - href: modules/collaborative_development/overview.qmd - - text: 'slides' - href: modules/collaborative_development/slides.qmd - - text: "exercises" - href: modules/collaborative_development/exercises.qmd - - - section: "Project Structure" - href: modules/structure/overview.qmd - contents: - - text: 'overview' - href: modules/structure/overview.qmd - - text: 'slides' - href: modules/structure/slides.qmd - - text: "exercises" - href: modules/structure/exercises.qmd - - - going_forward.qmd - - acknowledgements.qmd - navbar: background: light logo: images/oss_gateway.png logo-alt: "OSC logo." title: false + search: true collapse-below: lg + left: - - text: "Overview" + - text: "About" href: index.qmd + - text: "Open Source Development" + href: osc_intro/intro.qmd + + - text: "Python Intro" + href: python_intro/intro.qmd + right: - - icon: github + + - text: "{{< iconify devicon jupyter size=xl >}}" + href: https://opensourcecourse.github.io/hub + + - text: "{{< iconify devicon github size=xl >}}" href: https://github.com/opensourcecourse/website aria-label: OpenSourceCourse GitHub - -# bibliography: references.bib -format: - html: - toc: true - theme: - light: [cosmo, theme.scss] - code-copy: true - code-overflow: wrap - css: styles.css - # include-after-body: js.html + sidebar: + + - id: about + style: "floating" + collapse-level: 1 + title: "Welcome" + subtitle: 'About' + logo: "images/oss_gateway.png" + + contents: + - index.qmd + - acknowledgements.qmd + + + - id: osc + style: "floating" + collapse-level: 2 + title: "Open Source Course" + subtitle: 'OSC' + logo: "images/oss_gateway.png" + + contents: + - osc_intro/intro.qmd + - setup.qmd + + - section: "Modules" + contents: + + - section: "Git" + href: osc_intro/modules/git/overview.qmd + contents: + - text: 'overview' + href: osc_intro/modules/git/overview.qmd + - text: 'slides' + href: osc_intro/modules/git/slides.qmd + - text: "exercises" + href: osc_intro/modules/git/exercises.qmd + + - section: "Style" + href: osc_intro/modules/style/overview.qmd + contents: + - text: 'overview' + href: osc_intro/modules/style/overview.qmd + - text: 'slides' + href: osc_intro/modules/style/slides.qmd + - text: "exercises" + href: osc_intro/modules/style/exercises.qmd + + - section: "Object Oriented Python" + href: osc_intro/modules/object_oriented_python/overview.qmd + contents: + - text: 'overview' + href: osc_intro/modules/object_oriented_python/overview.qmd + - text: 'slides' + href: osc_intro/modules/object_oriented_python/slides.qmd + - text: "exercises" + href: osc_intro/modules/object_oriented_python/exercises.qmd + + - section: "Functional Python" + href: osc_intro/modules/functional_python/overview.qmd + contents: + - text: 'overview' + href: osc_intro/modules/functional_python/overview.qmd + - text: 'slides' + href: osc_intro/modules/functional_python/slides.qmd + - text: "exercises" + href: osc_intro/modules/functional_python/exercises.qmd + + - section: "Testing" + href: osc_intro/modules/testing/overview.qmd + contents: + - text: 'overview' + href: osc_intro/modules/testing/overview.qmd + - text: 'slides' + href: osc_intro/modules/testing/slides.qmd + - text: "exercises" + href: osc_intro/modules/testing/exercises.qmd + + - section: "Documentation" + href: osc_intro/modules/documentation/overview.qmd + contents: + - text: 'overview' + href: osc_intro/modules/documentation/overview.qmd + - text: 'slides' + href: osc_intro/modules/documentation/slides.qmd + - text: "exercises" + href: osc_intro/modules/documentation/exercises.qmd + + - section: "Collaborative Development" + href: osc_intro/modules/collaborative_development/overview.qmd + contents: + - text: 'overview' + href: osc_intro/modules/collaborative_development/overview.qmd + - text: 'slides' + href: osc_intro/modules/collaborative_development/slides.qmd + - text: "exercises" + href: osc_intro/modules/collaborative_development/exercises.qmd + + - section: "Project Structure" + href: osc_intro/modules/structure/overview.qmd + contents: + - text: 'overview' + href: osc_intro/modules/structure/overview.qmd + - text: 'slides' + href: osc_intro/modules/structure/slides.qmd + - text: "exercises" + href: osc_intro/modules/structure/exercises.qmd + + - osc_intro/going_forward.qmd + + - id: py_intro + style: "floating" + collapse-level: 2 + title: "Python Intro" + subtitle: 'OSC' + logo: "python_intro/images/blocks.png" + + contents: + - python_intro/intro.qmd + - section: "Modules" + contents: + - section: "Data Types" + href: python_intro/modules/datatypes/overview.qmd + contents: + - text: 'overview' + href: python_intro/modules/datatypes/overview.qmd + - text: 'slides' + href: python_intro/modules/datatypes/slides.qmd + - text: "exercises" + href: python_intro/modules/datatypes/exercises.qmd diff --git a/index.qmd b/index.qmd index 1bccc9d..9b73378 100644 --- a/index.qmd +++ b/index.qmd @@ -3,66 +3,41 @@ title: OpenSourceCourse pagetitle: "OSC" css: index.css editor: source +listing: + id: source_content + type: grid + contents: + - "osc_intro/intro.qmd" + - "python_intro/intro.qmd" --- Welcome to OpenSourceCourse (OSC)! -OSC is designed to help engineering/science students learn to effectively contribute to the -open-source scientific python ecosystem. +OSC is a collection of education material to help engineering/science students improve their software development skills. Each course is designed to be taught in-person. -You an find a video introduction [here](https://www.youtube.com/watch?v=b4ru68A31Uk) +Current courses are: -# Learning Objectives - -After successfully completing this course you will: - -1. Have a working understanding of the git version control system -2. Develop a sense of "Pythonic" code and the importance of coding style -3. Know when to use various object-oriented and functional Python features -4. Understand basic software testing philosophies and how to use the pytest framework -5. Know how to effectively document various types of python code -6. Be familiar with collaborative development practices - -# Prerequisites - -This course is designed for students with some Python experience. Specifically you should: - -1. Be well-versed with writing python functions -2. Be familiar with common data structures like lists, dicts, tuples, etc. -3. Understand iteration and indexing -4. Understand Python's control flow (if/then, for, while, etc.) -5. Know how to install python packages and manage python environments -6. Be semi-comfortable using a terminal (command line) - - -:::{.callout-warning} -Although the content is meant to be approachable, this is not a beginning python/computing course. +::: {#source_content} ::: -# Course Structure -Apart from this website, the [student discussion board](https://github.com/orgs/opensourcecourse/teams/students) -contains information about the course schedule, exercises, and office hours. It is also the right place to -ask a question about a topic or exercise. +# Course Structure -The [OpenSourceCourse github organization](https://github.com/opensourcecourse) is home to all the course content. -The course is organized into modules (on the left menu bar). Each module contains three components: +The [OpenSourceCourse github organization](https://github.com/opensourcecourse) is home to all course content. +Each course is organized into modules (on the left menu bar). Each module contains three components: ### Overview The overview gives a short introduction to the topic and motivation. -Before each module is presented in class, you should review the overview, including the links in the reading sections -(but feel free to skip additional resources). This doesn't mean you need to understand everything in the reading, -but do come to class with well-formed questions. +Before each module is presented in class, you should review the overview, including the links in the reading sections (but feel free to skip additional resources). This doesn't mean you need to understand everything in the reading, but do come to class with well-formed questions. ### Slides -The slides contain the material that will be presented in class. You can look them over but this is not required. -Notice that must slides progress from left to right using keyboard arrow keys or mouse clicks on the navigation icon, but some slides have horizontal, or grid, navigation features. +The slides contain the material that will be presented in class. You can look them over before class but this is not required. Notice that most slides progress from left to right using keyboard arrow keys or mouse clicks on the navigation icon, but some slides have horizontal, or grid, navigation features. ### Exercises -The exercises are to be done after a module is presented in class. They are essential to help you internalize +The exercises are to be done after a module is presented in class. They will help you internalize the concepts and develop the applicable skills. Although they are not difficult or time-consuming, please do treat them seriously. Each exercise should take between 30 minutes to 3 hours. @@ -71,20 +46,17 @@ You will find links to start each exercise and due dates on the ### Project -The last part of this course is to make a non-trivial contribution to an open-source project. You can -add a feature to an existing library, or release a small package of your own. More details are found -in the [collaborative development exercise](https://github.com/opensourcecourse/collaborative-development-assignment). +Each course has a final project to integrate and demonstrate the skills learned in the course. + # Enlisting -You should start by creating a github account, if you don't already have one. Then, you sign up for the course by -joining the [student team](https://github.com/orgs/opensourcecourse/teams/students) of the OSC organization. Next, -follow the [setup guide](setup.qmd). +You should start by creating a github account, if you don't already have one. Then, you sign up for a course by +joining the [student team](https://github.com/orgs/opensourcecourse/teams/students) of the OSC organization. Next, follow the [setup guide](setup.qmd). # Getting Help -Office hours for the instructors will be posted in the -[student discussion board](https://github.com/orgs/opensourcecourse/teams/students/discussions?pinned=1). +Office hours for the instructors of each course will be posted in the corresponding discussion board. # Collaboration @@ -94,5 +66,3 @@ The slides have a "source" hyperlink at the bottom which you can click for a sim You can also find all the template directories for the assignments on the [github org](https://github.com/opensourcecourse). Feel free to open PRs there as well. - -Now, let's learn together! diff --git a/going_forward.qmd b/osc_intro/going_forward.qmd similarity index 100% rename from going_forward.qmd rename to osc_intro/going_forward.qmd diff --git a/images/code_review.png b/osc_intro/images/code_review.png similarity index 100% rename from images/code_review.png rename to osc_intro/images/code_review.png diff --git a/images/conspiracy_board.png b/osc_intro/images/conspiracy_board.png similarity index 100% rename from images/conspiracy_board.png rename to osc_intro/images/conspiracy_board.png diff --git a/images/conveyor.png b/osc_intro/images/conveyor.png similarity index 100% rename from images/conveyor.png rename to osc_intro/images/conveyor.png diff --git a/images/cyber_punk_streets.png b/osc_intro/images/cyber_punk_streets.png similarity index 100% rename from images/cyber_punk_streets.png rename to osc_intro/images/cyber_punk_streets.png diff --git a/images/decorative_cloth.png b/osc_intro/images/decorative_cloth.png similarity index 100% rename from images/decorative_cloth.png rename to osc_intro/images/decorative_cloth.png diff --git a/images/factory_robots.png b/osc_intro/images/factory_robots.png similarity index 100% rename from images/factory_robots.png rename to osc_intro/images/factory_robots.png diff --git a/images/future_city.png b/osc_intro/images/future_city.png similarity index 100% rename from images/future_city.png rename to osc_intro/images/future_city.png diff --git a/images/hallway.png b/osc_intro/images/hallway.png similarity index 100% rename from images/hallway.png rename to osc_intro/images/hallway.png diff --git a/images/my_type.png b/osc_intro/images/my_type.png similarity index 100% rename from images/my_type.png rename to osc_intro/images/my_type.png diff --git a/images/scafold.png b/osc_intro/images/scafold.png similarity index 100% rename from images/scafold.png rename to osc_intro/images/scafold.png diff --git a/images/sharing_papers.png b/osc_intro/images/sharing_papers.png similarity index 100% rename from images/sharing_papers.png rename to osc_intro/images/sharing_papers.png diff --git a/images/smelly_code.svg b/osc_intro/images/smelly_code.svg similarity index 100% rename from images/smelly_code.svg rename to osc_intro/images/smelly_code.svg diff --git a/images/style_guy.png b/osc_intro/images/style_guy.png similarity index 100% rename from images/style_guy.png rename to osc_intro/images/style_guy.png diff --git a/images/therapy.png b/osc_intro/images/therapy.png similarity index 100% rename from images/therapy.png rename to osc_intro/images/therapy.png diff --git a/images/workbench_explosion.png b/osc_intro/images/workbench_explosion.png similarity index 100% rename from images/workbench_explosion.png rename to osc_intro/images/workbench_explosion.png diff --git a/osc_intro/intro.qmd b/osc_intro/intro.qmd new file mode 100644 index 0000000..eb98a81 --- /dev/null +++ b/osc_intro/intro.qmd @@ -0,0 +1,55 @@ +--- +title: Intro to Open-Source Development +pagetitle: "OSC" +css: ../index.css +editor: source +image: ../images/oss_gateway.png +--- + +This course covers Git, style guides, advanced python features, testing, documentation, and collaborative coding using GitHub. + +It is designed to help engineering/science students learn to effectively contribute to the +open-source scientific python ecosystem. + +You can find a video introduction [here](https://www.youtube.com/watch?v=b4ru68A31Uk) + +# Course Learning Outcomes +After successfully completing the course you will be able to: + +1. Use the Git version control system to manage software projects. +2. Apply style guides to codebases. +3. Design object-oriented and functional python implementations for solving computing problems. +4. Use the pytest framework to verify correctness of programs. +5. Design documentation which effectively advertises and explains a project. +6. Evaluate pull request and bug report quality and provide feedback for making improvements. +7. Create and submit code contributions which follow best practices and project guidelines. + +# Prerequisites + +This course is designed for students with some Python experience. Specifically you should: + +1. Be well-versed with writing python functions +2. Be familiar with common data structures like lists, dicts, tuples, etc. +3. Understand iteration and indexing +4. Understand Python's control flow (if/then, for, while, etc.) +5. Know how to install python packages and manage python environments +6. Be semi-comfortable using a terminal (command line) + +:::{.callout-warning} +Although the content is meant to be approachable, this is not a beginning python/computing course. + +If you don't feel comfortable with these topics, the [Python Intro course material](../python_intro/intro.qmd) may be a better place to start. +::: + +See the [OSC overview page](../index.qmd) for general information on course structure. + + +## Project + +The last part of this course is to make a non-trivial contribution to an open-source project. You can +add a feature to an existing library, or release a small package of your own. More details are found +in the [collaborative development exercise](https://github.com/opensourcecourse/collaborative-development-assignment). + +## Setup + +Follow the [setup guide](setup.qmd) to get setup for this course. \ No newline at end of file diff --git a/modules/_template/exercises.qmd b/osc_intro/modules/_template/exercises.qmd similarity index 100% rename from modules/_template/exercises.qmd rename to osc_intro/modules/_template/exercises.qmd diff --git a/modules/_template/overview.qmd b/osc_intro/modules/_template/overview.qmd similarity index 100% rename from modules/_template/overview.qmd rename to osc_intro/modules/_template/overview.qmd diff --git a/modules/_template/slides.qmd b/osc_intro/modules/_template/slides.qmd similarity index 100% rename from modules/_template/slides.qmd rename to osc_intro/modules/_template/slides.qmd diff --git a/modules/collaborative_development/exercises.qmd b/osc_intro/modules/collaborative_development/exercises.qmd similarity index 100% rename from modules/collaborative_development/exercises.qmd rename to osc_intro/modules/collaborative_development/exercises.qmd diff --git a/modules/collaborative_development/overview.qmd b/osc_intro/modules/collaborative_development/overview.qmd similarity index 100% rename from modules/collaborative_development/overview.qmd rename to osc_intro/modules/collaborative_development/overview.qmd diff --git a/modules/collaborative_development/slides.qmd b/osc_intro/modules/collaborative_development/slides.qmd similarity index 86% rename from modules/collaborative_development/slides.qmd rename to osc_intro/modules/collaborative_development/slides.qmd index e100bd1..d759ac8 100644 --- a/modules/collaborative_development/slides.qmd +++ b/osc_intro/modules/collaborative_development/slides.qmd @@ -5,7 +5,7 @@ format: revealjs: slide-number: true preview-links: auto - theme: [../../custom_slides.scss] + theme: [../../../custom_slides.scss] css: "../../slides.css" view-distance: 100 mobile-view-distance: 100 @@ -17,9 +17,9 @@ format: theme: default footer: \ - overview /\ - source /\ - exercises + overview /\ + source /\ + exercises --- diff --git a/modules/documentation/exercises.qmd b/osc_intro/modules/documentation/exercises.qmd similarity index 100% rename from modules/documentation/exercises.qmd rename to osc_intro/modules/documentation/exercises.qmd diff --git a/modules/documentation/overview.qmd b/osc_intro/modules/documentation/overview.qmd similarity index 100% rename from modules/documentation/overview.qmd rename to osc_intro/modules/documentation/overview.qmd diff --git a/modules/documentation/slides.qmd b/osc_intro/modules/documentation/slides.qmd similarity index 97% rename from modules/documentation/slides.qmd rename to osc_intro/modules/documentation/slides.qmd index 388d17d..b787a06 100644 --- a/modules/documentation/slides.qmd +++ b/osc_intro/modules/documentation/slides.qmd @@ -5,8 +5,8 @@ format: revealjs: slide-number: true preview-links: auto - theme: [../../custom_slides.scss] - css: ../../slides.css + theme: [../../../custom_slides.scss] + css: ../../../slides.css view-distance: 100 mobile-view-distance: 100 navigation-mode: vertical @@ -14,9 +14,9 @@ format: controls-tutorial: true footer: \ - overview /\ - source /\ - exercises + overview /\ + source /\ + exercises --- diff --git a/modules/functional_python/exercises.qmd b/osc_intro/modules/functional_python/exercises.qmd similarity index 100% rename from modules/functional_python/exercises.qmd rename to osc_intro/modules/functional_python/exercises.qmd diff --git a/modules/functional_python/images/tangled_cat.png b/osc_intro/modules/functional_python/images/tangled_cat.png similarity index 100% rename from modules/functional_python/images/tangled_cat.png rename to osc_intro/modules/functional_python/images/tangled_cat.png diff --git a/modules/functional_python/overview.qmd b/osc_intro/modules/functional_python/overview.qmd similarity index 100% rename from modules/functional_python/overview.qmd rename to osc_intro/modules/functional_python/overview.qmd diff --git a/modules/functional_python/slides.qmd b/osc_intro/modules/functional_python/slides.qmd similarity index 98% rename from modules/functional_python/slides.qmd rename to osc_intro/modules/functional_python/slides.qmd index c2fce06..870576c 100644 --- a/modules/functional_python/slides.qmd +++ b/osc_intro/modules/functional_python/slides.qmd @@ -5,16 +5,16 @@ format: revealjs: slide-number: true preview-links: auto - theme: [../../custom_slides.scss] - css: ../../slides.css + theme: [../../../custom_slides.scss] + css: ../../../slides.css navigation-mode: vertical controls-layout: bottom-right controls-tutorial: true footer: \ - overview /\ - source /\ - exercises + overview /\ + source /\ + exercises --- # Programming Paradigms diff --git a/modules/git/exercises.qmd b/osc_intro/modules/git/exercises.qmd similarity index 100% rename from modules/git/exercises.qmd rename to osc_intro/modules/git/exercises.qmd diff --git a/modules/git/images/bat_smack.avif b/osc_intro/modules/git/images/bat_smack.avif similarity index 100% rename from modules/git/images/bat_smack.avif rename to osc_intro/modules/git/images/bat_smack.avif diff --git a/modules/git/images/hes-dead-jim.jpg b/osc_intro/modules/git/images/hes-dead-jim.jpg similarity index 100% rename from modules/git/images/hes-dead-jim.jpg rename to osc_intro/modules/git/images/hes-dead-jim.jpg diff --git a/modules/git/images/stick_figures_speach_bubble.svg b/osc_intro/modules/git/images/stick_figures_speach_bubble.svg similarity index 100% rename from modules/git/images/stick_figures_speach_bubble.svg rename to osc_intro/modules/git/images/stick_figures_speach_bubble.svg diff --git a/modules/git/images/thought_tools.png b/osc_intro/modules/git/images/thought_tools.png similarity index 100% rename from modules/git/images/thought_tools.png rename to osc_intro/modules/git/images/thought_tools.png diff --git a/modules/git/images/yes.png b/osc_intro/modules/git/images/yes.png similarity index 100% rename from modules/git/images/yes.png rename to osc_intro/modules/git/images/yes.png diff --git a/modules/git/overview.qmd b/osc_intro/modules/git/overview.qmd similarity index 100% rename from modules/git/overview.qmd rename to osc_intro/modules/git/overview.qmd diff --git a/modules/git/slides.qmd b/osc_intro/modules/git/slides.qmd similarity index 99% rename from modules/git/slides.qmd rename to osc_intro/modules/git/slides.qmd index a5f42a7..29b5890 100644 --- a/modules/git/slides.qmd +++ b/osc_intro/modules/git/slides.qmd @@ -7,8 +7,8 @@ format: revealjs: slide-number: true preview-links: auto - theme: [../../custom_slides.scss] - css: "../../slides.css" + theme: [../../../custom_slides.scss] + css: "../../../slides.css" view-distance: 100 mobile-view-distance: 100 navigation-mode: vertical @@ -19,9 +19,9 @@ format: theme: default footer: \ - overview /\ - source /\ - exercises + overview /\ + source /\ + exercises --- diff --git a/modules/object_oriented_python/exercises.qmd b/osc_intro/modules/object_oriented_python/exercises.qmd similarity index 100% rename from modules/object_oriented_python/exercises.qmd rename to osc_intro/modules/object_oriented_python/exercises.qmd diff --git a/modules/object_oriented_python/images/class_map.png b/osc_intro/modules/object_oriented_python/images/class_map.png similarity index 100% rename from modules/object_oriented_python/images/class_map.png rename to osc_intro/modules/object_oriented_python/images/class_map.png diff --git a/modules/object_oriented_python/images/misfit_wf_eq.png b/osc_intro/modules/object_oriented_python/images/misfit_wf_eq.png similarity index 100% rename from modules/object_oriented_python/images/misfit_wf_eq.png rename to osc_intro/modules/object_oriented_python/images/misfit_wf_eq.png diff --git a/modules/object_oriented_python/images/real_oo.png b/osc_intro/modules/object_oriented_python/images/real_oo.png similarity index 100% rename from modules/object_oriented_python/images/real_oo.png rename to osc_intro/modules/object_oriented_python/images/real_oo.png diff --git a/modules/object_oriented_python/images/simple_oo.png b/osc_intro/modules/object_oriented_python/images/simple_oo.png similarity index 100% rename from modules/object_oriented_python/images/simple_oo.png rename to osc_intro/modules/object_oriented_python/images/simple_oo.png diff --git a/modules/object_oriented_python/overview.qmd b/osc_intro/modules/object_oriented_python/overview.qmd similarity index 100% rename from modules/object_oriented_python/overview.qmd rename to osc_intro/modules/object_oriented_python/overview.qmd diff --git a/modules/object_oriented_python/slides.qmd b/osc_intro/modules/object_oriented_python/slides.qmd similarity index 98% rename from modules/object_oriented_python/slides.qmd rename to osc_intro/modules/object_oriented_python/slides.qmd index 42d7bc2..1985f52 100644 --- a/modules/object_oriented_python/slides.qmd +++ b/osc_intro/modules/object_oriented_python/slides.qmd @@ -5,8 +5,8 @@ format: revealjs: slide-number: true preview-links: auto - theme: [../../custom_slides.scss] - css: "../../slides.css" + theme: [../../../custom_slides.scss] + css: "../../../slides.css" view-distance: 100 mobile-view-distance: 100 navigation-mode: vertical @@ -16,9 +16,9 @@ format: mermaid: theme: default footer: \ - overview /\ - source /\ - exercises + overview /\ + source /\ + exercises --- # Intro diff --git a/modules/structure/exercises.qmd b/osc_intro/modules/structure/exercises.qmd similarity index 100% rename from modules/structure/exercises.qmd rename to osc_intro/modules/structure/exercises.qmd diff --git a/modules/structure/images/science_repo_spectrum.svg b/osc_intro/modules/structure/images/science_repo_spectrum.svg similarity index 100% rename from modules/structure/images/science_repo_spectrum.svg rename to osc_intro/modules/structure/images/science_repo_spectrum.svg diff --git a/modules/structure/images/spectrum.png b/osc_intro/modules/structure/images/spectrum.png similarity index 100% rename from modules/structure/images/spectrum.png rename to osc_intro/modules/structure/images/spectrum.png diff --git a/modules/structure/overview.qmd b/osc_intro/modules/structure/overview.qmd similarity index 100% rename from modules/structure/overview.qmd rename to osc_intro/modules/structure/overview.qmd diff --git a/modules/structure/slides.qmd b/osc_intro/modules/structure/slides.qmd similarity index 95% rename from modules/structure/slides.qmd rename to osc_intro/modules/structure/slides.qmd index 5e975c0..a3f527e 100644 --- a/modules/structure/slides.qmd +++ b/osc_intro/modules/structure/slides.qmd @@ -7,8 +7,8 @@ format: revealjs: slide-number: true preview-links: auto - theme: [../../custom_slides.scss] - css: "../../slides.css" + theme: [../../../custom_slides.scss] + css: "../../../slides.css" view-distance: 100 mobile-view-distance: 100 navigation-mode: vertical @@ -19,9 +19,9 @@ format: theme: default footer: \ - overview /\ - source /\ - exercises + overview /\ + source /\ + exercises --- # Outline diff --git a/modules/style/exercises.qmd b/osc_intro/modules/style/exercises.qmd similarity index 100% rename from modules/style/exercises.qmd rename to osc_intro/modules/style/exercises.qmd diff --git a/modules/style/images/babel.png b/osc_intro/modules/style/images/babel.png similarity index 100% rename from modules/style/images/babel.png rename to osc_intro/modules/style/images/babel.png diff --git a/modules/style/images/code_smell.png b/osc_intro/modules/style/images/code_smell.png similarity index 100% rename from modules/style/images/code_smell.png rename to osc_intro/modules/style/images/code_smell.png diff --git a/modules/style/images/pillar_of_programming_purpose.png b/osc_intro/modules/style/images/pillar_of_programming_purpose.png similarity index 100% rename from modules/style/images/pillar_of_programming_purpose.png rename to osc_intro/modules/style/images/pillar_of_programming_purpose.png diff --git a/modules/style/images/programming_purpose_pillars.svg b/osc_intro/modules/style/images/programming_purpose_pillars.svg similarity index 100% rename from modules/style/images/programming_purpose_pillars.svg rename to osc_intro/modules/style/images/programming_purpose_pillars.svg diff --git a/modules/style/images/smelly_code.svg b/osc_intro/modules/style/images/smelly_code.svg similarity index 100% rename from modules/style/images/smelly_code.svg rename to osc_intro/modules/style/images/smelly_code.svg diff --git a/modules/style/images/tim.png b/osc_intro/modules/style/images/tim.png similarity index 100% rename from modules/style/images/tim.png rename to osc_intro/modules/style/images/tim.png diff --git a/modules/style/overview.qmd b/osc_intro/modules/style/overview.qmd similarity index 100% rename from modules/style/overview.qmd rename to osc_intro/modules/style/overview.qmd diff --git a/modules/style/slides.qmd b/osc_intro/modules/style/slides.qmd similarity index 98% rename from modules/style/slides.qmd rename to osc_intro/modules/style/slides.qmd index c63da41..09cd593 100644 --- a/modules/style/slides.qmd +++ b/osc_intro/modules/style/slides.qmd @@ -7,16 +7,16 @@ format: revealjs: slide-number: true preview-links: auto - theme: [../../custom_slides.scss] - css: ../../slides.css + theme: [../../../custom_slides.scss] + css: ../../../slides.css navigation-mode: vertical controls-layout: bottom-right controls-tutorial: true footer: \ - overview /\ - source /\ - exercises + overview /\ + source /\ + exercises --- # Overview diff --git a/modules/testing/examples/test_norm1.py b/osc_intro/modules/testing/examples/test_norm1.py similarity index 100% rename from modules/testing/examples/test_norm1.py rename to osc_intro/modules/testing/examples/test_norm1.py diff --git a/modules/testing/exercises.qmd b/osc_intro/modules/testing/exercises.qmd similarity index 100% rename from modules/testing/exercises.qmd rename to osc_intro/modules/testing/exercises.qmd diff --git a/modules/testing/images/sentinel.jpg b/osc_intro/modules/testing/images/sentinel.jpg similarity index 100% rename from modules/testing/images/sentinel.jpg rename to osc_intro/modules/testing/images/sentinel.jpg diff --git a/modules/testing/images/test_pyramid.png b/osc_intro/modules/testing/images/test_pyramid.png similarity index 100% rename from modules/testing/images/test_pyramid.png rename to osc_intro/modules/testing/images/test_pyramid.png diff --git a/modules/testing/images/test_pyramid.svg b/osc_intro/modules/testing/images/test_pyramid.svg similarity index 100% rename from modules/testing/images/test_pyramid.svg rename to osc_intro/modules/testing/images/test_pyramid.svg diff --git a/modules/testing/images/test_run.png b/osc_intro/modules/testing/images/test_run.png similarity index 100% rename from modules/testing/images/test_run.png rename to osc_intro/modules/testing/images/test_run.png diff --git a/modules/testing/overview.qmd b/osc_intro/modules/testing/overview.qmd similarity index 100% rename from modules/testing/overview.qmd rename to osc_intro/modules/testing/overview.qmd diff --git a/modules/testing/slides.qmd b/osc_intro/modules/testing/slides.qmd similarity index 98% rename from modules/testing/slides.qmd rename to osc_intro/modules/testing/slides.qmd index 165aa02..ef8a6bf 100644 --- a/modules/testing/slides.qmd +++ b/osc_intro/modules/testing/slides.qmd @@ -5,8 +5,8 @@ format: revealjs: slide-number: true preview-links: auto - theme: [../../custom_slides.scss] - css: ../../slides.css + theme: [../../../custom_slides.scss] + css: ../../../slides.css view-distance: 100 mobile-view-distance: 100 navigation-mode: vertical @@ -14,9 +14,9 @@ format: controls-tutorial: true footer: \ - overview /\ - source /\ - exercises + overview /\ + source /\ + exercises --- diff --git a/setup.qmd b/osc_intro/setup.qmd similarity index 82% rename from setup.qmd rename to osc_intro/setup.qmd index cf47ab4..1da4787 100644 --- a/setup.qmd +++ b/osc_intro/setup.qmd @@ -6,14 +6,12 @@ In order to use class time effectively, please do the following before the cours # Create a Github Account -Go to [Github's website](https://github.com/) and click sign up on the top right. Of course, -if you already have a github account you can skip this step. +Go to [Github's website](https://github.com/) and click sign up on the top right. Of course, if you already have a github account you can skip this step. # Setup Git -Here we will make sure your git installation is working and configured properly to push to github. If you know git is -already installed on your machine and you have recently pushed content to a github repo you can skip this section. +Here we will make sure your git installation is working and configured properly to push to github. If you know git is already installed on your machine and you have recently pushed content to a github repo you can skip this section. 1. Make sure you have [git installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git). 2. [Create a personal repo](https://docs.github.com/en/get-started/quickstart/create-a-repo) called "git_test" @@ -77,9 +75,7 @@ to use https or 2) Setup [ssh keys](https://docs.github.com/en/authentication/co # Setup Python Environment -There are several ways to setup python but we recommend using [conda](https://conda.io/projects/conda/en/latest/user-guide/install/index.html). You -may also want to [create a virtual environment](https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#creating-an-environment-with-commands) -for the course. +There are several ways to setup python but we recommend using [conda](https://conda.io/projects/conda/en/latest/user-guide/install/index.html). You may also want to [create a virtual environment](https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#creating-an-environment-with-commands) for the course. All the packages you will need for the assignments can be installed with the following command: diff --git a/python_intro/images/blocks.png b/python_intro/images/blocks.png new file mode 100644 index 0000000000000000000000000000000000000000..56fa9496abb0200a8755b931601085999569eb1a GIT binary patch literal 444682 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