diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..f173110 --- /dev/null +++ b/.nojekyll @@ -0,0 +1 @@ +This file makes sure that Github Pages doesn't process mdBook's output. diff --git a/404.html b/404.html new file mode 100644 index 0000000..d67bad5 --- /dev/null +++ b/404.html @@ -0,0 +1,190 @@ + + + + + + Page not found - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Document not found (404)

+

This URL is invalid, sorry. Please use the navigation bar or search to continue.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..1a76e56 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +docs.techstartucalgary.com diff --git a/CONTRIBUTING.html b/CONTRIBUTING.html new file mode 100644 index 0000000..93a3cf6 --- /dev/null +++ b/CONTRIBUTING.html @@ -0,0 +1,231 @@ + + + + + + Contributing - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Contributing

+

Please submit bug reports, +feature requests, +or general feedback to our +Bug Tracker on GitHub.

+

Code contributions

+

The easiest way to contribute to this project +is by clicking on the button in the top right corner of any page. +This will open the corresponding page on GitHub, +where you can add or modify content +and then commit the change.

+

For more elaborate changes please:

+
    +
  1. Fork the project from: https://github.com/techstartucalgary/docs.
  2. +
  3. Follow the tutorial of mdBook, +the tool we use to build and generate this documentation.
  4. +
  5. Before you make a PR, please run markdownlint on the files you changed. I recommend using the VS Code extensions for ease of use.
  6. +
  7. Make a PR!
  8. +
+ +
    +
  1. All of the code that you submit to our code repository +will be licensed under the +Creative Commons CC0 1.0 Universal +and The Unlicense.
  2. +
  3. By submitting code to our code repository you also certify +that you agree to the following +Developer Certificate of Origin.
  4. +
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/CREDITS.html b/CREDITS.html new file mode 100644 index 0000000..b25c964 --- /dev/null +++ b/CREDITS.html @@ -0,0 +1,207 @@ + + + + + + Credits - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Credits

+

Special thanks to Kevin Amado1 for writing these docs.

+
1 +

VP Development 2022. Feel free to connect with me on LinkedIn or GitHub, or read my personal website.

+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/FontAwesome/css/font-awesome.css b/FontAwesome/css/font-awesome.css new file mode 100644 index 0000000..540440c --- /dev/null +++ b/FontAwesome/css/font-awesome.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} diff --git a/FontAwesome/fonts/FontAwesome.ttf b/FontAwesome/fonts/FontAwesome.ttf new file mode 100644 index 0000000..35acda2 Binary files /dev/null and b/FontAwesome/fonts/FontAwesome.ttf differ diff --git a/FontAwesome/fonts/fontawesome-webfont.eot b/FontAwesome/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000..e9f60ca Binary files /dev/null and b/FontAwesome/fonts/fontawesome-webfont.eot differ diff --git a/FontAwesome/fonts/fontawesome-webfont.svg b/FontAwesome/fonts/fontawesome-webfont.svg new file mode 100644 index 0000000..855c845 --- /dev/null +++ b/FontAwesome/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FontAwesome/fonts/fontawesome-webfont.ttf b/FontAwesome/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000..35acda2 Binary files /dev/null and b/FontAwesome/fonts/fontawesome-webfont.ttf differ diff --git a/FontAwesome/fonts/fontawesome-webfont.woff b/FontAwesome/fonts/fontawesome-webfont.woff new file mode 100644 index 0000000..400014a Binary files /dev/null and b/FontAwesome/fonts/fontawesome-webfont.woff differ diff --git a/FontAwesome/fonts/fontawesome-webfont.woff2 b/FontAwesome/fonts/fontawesome-webfont.woff2 new file mode 100644 index 0000000..4d13fc6 Binary files /dev/null and b/FontAwesome/fonts/fontawesome-webfont.woff2 differ diff --git a/LICENSE.html b/LICENSE.html new file mode 100644 index 0000000..9748e27 --- /dev/null +++ b/LICENSE.html @@ -0,0 +1,353 @@ + + + + + + License - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

License

+

This project is released under either +the Creative Commons CC0 1.0 Universal license +and/or under the The Unlicense license, +at your discretion, +whose verbatim copies can be found below.

+
The Unlicense
+-------------
+
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+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 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.
+
+For more information, please refer to <https://unlicense.org>
+
+
Creative Commons Legal Code
+---------------------------
+
+CC0 1.0 Universal
+
+    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+    HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+  i. the right to reproduce, adapt, distribute, perform, display,
+     communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+     likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+     subject to the limitations in paragraph 4(a), below;
+  v. rights protecting the extraction, dissemination, use and reuse of data
+     in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+     European Parliament and of the Council of 11 March 1996 on the legal
+     protection of databases, and under any national implementation
+     thereof, including any amended or successor version of such
+     directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+     world based on applicable law or treaty, and any national
+     implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+    surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+    warranties of any kind concerning the Work, express, implied,
+    statutory or otherwise, including without limitation warranties of
+    title, merchantability, fitness for a particular purpose, non
+    infringement, or the absence of latent or other defects, accuracy, or
+    the present or absence of errors, whether or not discoverable, all to
+    the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+    that may apply to the Work or any use thereof, including without
+    limitation any person's Copyright and Related Rights in the Work.
+    Further, Affirmer disclaims responsibility for obtaining any necessary
+    consents, permissions or other rights required for any use of the
+    Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+    party to this document and has no duty or obligation with respect to
+    this CC0 or use of the Work.
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/archive/2022-2023/demos/used-by.png b/archive/2022-2023/demos/used-by.png new file mode 100644 index 0000000..43ee814 Binary files /dev/null and b/archive/2022-2023/demos/used-by.png differ diff --git a/ayu-highlight.css b/ayu-highlight.css new file mode 100644 index 0000000..32c9432 --- /dev/null +++ b/ayu-highlight.css @@ -0,0 +1,78 @@ +/* +Based off of the Ayu theme +Original by Dempfi (https://github.com/dempfi/ayu) +*/ + +.hljs { + display: block; + overflow-x: auto; + background: #191f26; + color: #e6e1cf; +} + +.hljs-comment, +.hljs-quote { + color: #5c6773; + font-style: italic; +} + +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-attr, +.hljs-regexp, +.hljs-link, +.hljs-selector-id, +.hljs-selector-class { + color: #ff7733; +} + +.hljs-number, +.hljs-meta, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #ffee99; +} + +.hljs-string, +.hljs-bullet { + color: #b8cc52; +} + +.hljs-title, +.hljs-built_in, +.hljs-section { + color: #ffb454; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-symbol { + color: #ff7733; +} + +.hljs-name { + color: #36a3d9; +} + +.hljs-tag { + color: #00568d; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-addition { + color: #91b362; +} + +.hljs-deletion { + color: #d96c75; +} diff --git a/book.js b/book.js new file mode 100644 index 0000000..e303ebb --- /dev/null +++ b/book.js @@ -0,0 +1,688 @@ +"use strict"; + +// Fix back button cache problem +window.onunload = function () { }; + +// Global variable, shared between modules +function playground_text(playground, hidden = true) { + let code_block = playground.querySelector("code"); + + if (window.ace && code_block.classList.contains("editable")) { + let editor = window.ace.edit(code_block); + return editor.getValue(); + } else if (hidden) { + return code_block.textContent; + } else { + return code_block.innerText; + } +} + +(function codeSnippets() { + function fetch_with_timeout(url, options, timeout = 6000) { + return Promise.race([ + fetch(url, options), + new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout)) + ]); + } + + var playgrounds = Array.from(document.querySelectorAll(".playground")); + if (playgrounds.length > 0) { + fetch_with_timeout("https://play.rust-lang.org/meta/crates", { + headers: { + 'Content-Type': "application/json", + }, + method: 'POST', + mode: 'cors', + }) + .then(response => response.json()) + .then(response => { + // get list of crates available in the rust playground + let playground_crates = response.crates.map(item => item["id"]); + playgrounds.forEach(block => handle_crate_list_update(block, playground_crates)); + }); + } + + function handle_crate_list_update(playground_block, playground_crates) { + // update the play buttons after receiving the response + update_play_button(playground_block, playground_crates); + + // and install on change listener to dynamically update ACE editors + if (window.ace) { + let code_block = playground_block.querySelector("code"); + if (code_block.classList.contains("editable")) { + let editor = window.ace.edit(code_block); + editor.addEventListener("change", function (e) { + update_play_button(playground_block, playground_crates); + }); + // add Ctrl-Enter command to execute rust code + editor.commands.addCommand({ + name: "run", + bindKey: { + win: "Ctrl-Enter", + mac: "Ctrl-Enter" + }, + exec: _editor => run_rust_code(playground_block) + }); + } + } + } + + // updates the visibility of play button based on `no_run` class and + // used crates vs ones available on http://play.rust-lang.org + function update_play_button(pre_block, playground_crates) { + var play_button = pre_block.querySelector(".play-button"); + + // skip if code is `no_run` + if (pre_block.querySelector('code').classList.contains("no_run")) { + play_button.classList.add("hidden"); + return; + } + + // get list of `extern crate`'s from snippet + var txt = playground_text(pre_block); + var re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g; + var snippet_crates = []; + var item; + while (item = re.exec(txt)) { + snippet_crates.push(item[1]); + } + + // check if all used crates are available on play.rust-lang.org + var all_available = snippet_crates.every(function (elem) { + return playground_crates.indexOf(elem) > -1; + }); + + if (all_available) { + play_button.classList.remove("hidden"); + } else { + play_button.classList.add("hidden"); + } + } + + function run_rust_code(code_block) { + var result_block = code_block.querySelector(".result"); + if (!result_block) { + result_block = document.createElement('code'); + result_block.className = 'result hljs language-bash'; + + code_block.append(result_block); + } + + let text = playground_text(code_block); + let classes = code_block.querySelector('code').classList; + let edition = "2015"; + if(classes.contains("edition2018")) { + edition = "2018"; + } else if(classes.contains("edition2021")) { + edition = "2021"; + } + var params = { + version: "stable", + optimize: "0", + code: text, + edition: edition + }; + + if (text.indexOf("#![feature") !== -1) { + params.version = "nightly"; + } + + result_block.innerText = "Running..."; + + fetch_with_timeout("https://play.rust-lang.org/evaluate.json", { + headers: { + 'Content-Type': "application/json", + }, + method: 'POST', + mode: 'cors', + body: JSON.stringify(params) + }) + .then(response => response.json()) + .then(response => { + if (response.result.trim() === '') { + result_block.innerText = "No output"; + result_block.classList.add("result-no-output"); + } else { + result_block.innerText = response.result; + result_block.classList.remove("result-no-output"); + } + }) + .catch(error => result_block.innerText = "Playground Communication: " + error.message); + } + + // Syntax highlighting Configuration + hljs.configure({ + tabReplace: ' ', // 4 spaces + languages: [], // Languages used for auto-detection + }); + + let code_nodes = Array + .from(document.querySelectorAll('code')) + // Don't highlight `inline code` blocks in headers. + .filter(function (node) {return !node.parentElement.classList.contains("header"); }); + + if (window.ace) { + // language-rust class needs to be removed for editable + // blocks or highlightjs will capture events + code_nodes + .filter(function (node) {return node.classList.contains("editable"); }) + .forEach(function (block) { block.classList.remove('language-rust'); }); + + code_nodes + .filter(function (node) {return !node.classList.contains("editable"); }) + .forEach(function (block) { hljs.highlightBlock(block); }); + } else { + code_nodes.forEach(function (block) { hljs.highlightBlock(block); }); + } + + // Adding the hljs class gives code blocks the color css + // even if highlighting doesn't apply + code_nodes.forEach(function (block) { block.classList.add('hljs'); }); + + Array.from(document.querySelectorAll("code.language-rust")).forEach(function (block) { + + var lines = Array.from(block.querySelectorAll('.boring')); + // If no lines were hidden, return + if (!lines.length) { return; } + block.classList.add("hide-boring"); + + var buttons = document.createElement('div'); + buttons.className = 'buttons'; + buttons.innerHTML = ""; + + // add expand button + var pre_block = block.parentNode; + pre_block.insertBefore(buttons, pre_block.firstChild); + + pre_block.querySelector('.buttons').addEventListener('click', function (e) { + if (e.target.classList.contains('fa-eye')) { + e.target.classList.remove('fa-eye'); + e.target.classList.add('fa-eye-slash'); + e.target.title = 'Hide lines'; + e.target.setAttribute('aria-label', e.target.title); + + block.classList.remove('hide-boring'); + } else if (e.target.classList.contains('fa-eye-slash')) { + e.target.classList.remove('fa-eye-slash'); + e.target.classList.add('fa-eye'); + e.target.title = 'Show hidden lines'; + e.target.setAttribute('aria-label', e.target.title); + + block.classList.add('hide-boring'); + } + }); + }); + + if (window.playground_copyable) { + Array.from(document.querySelectorAll('pre code')).forEach(function (block) { + var pre_block = block.parentNode; + if (!pre_block.classList.contains('playground')) { + var buttons = pre_block.querySelector(".buttons"); + if (!buttons) { + buttons = document.createElement('div'); + buttons.className = 'buttons'; + pre_block.insertBefore(buttons, pre_block.firstChild); + } + + var clipButton = document.createElement('button'); + clipButton.className = 'fa fa-copy clip-button'; + clipButton.title = 'Copy to clipboard'; + clipButton.setAttribute('aria-label', clipButton.title); + clipButton.innerHTML = ''; + + buttons.insertBefore(clipButton, buttons.firstChild); + } + }); + } + + // Process playground code blocks + Array.from(document.querySelectorAll(".playground")).forEach(function (pre_block) { + // Add play button + var buttons = pre_block.querySelector(".buttons"); + if (!buttons) { + buttons = document.createElement('div'); + buttons.className = 'buttons'; + pre_block.insertBefore(buttons, pre_block.firstChild); + } + + var runCodeButton = document.createElement('button'); + runCodeButton.className = 'fa fa-play play-button'; + runCodeButton.hidden = true; + runCodeButton.title = 'Run this code'; + runCodeButton.setAttribute('aria-label', runCodeButton.title); + + buttons.insertBefore(runCodeButton, buttons.firstChild); + runCodeButton.addEventListener('click', function (e) { + run_rust_code(pre_block); + }); + + if (window.playground_copyable) { + var copyCodeClipboardButton = document.createElement('button'); + copyCodeClipboardButton.className = 'fa fa-copy clip-button'; + copyCodeClipboardButton.innerHTML = ''; + copyCodeClipboardButton.title = 'Copy to clipboard'; + copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title); + + buttons.insertBefore(copyCodeClipboardButton, buttons.firstChild); + } + + let code_block = pre_block.querySelector("code"); + if (window.ace && code_block.classList.contains("editable")) { + var undoChangesButton = document.createElement('button'); + undoChangesButton.className = 'fa fa-history reset-button'; + undoChangesButton.title = 'Undo changes'; + undoChangesButton.setAttribute('aria-label', undoChangesButton.title); + + buttons.insertBefore(undoChangesButton, buttons.firstChild); + + undoChangesButton.addEventListener('click', function () { + let editor = window.ace.edit(code_block); + editor.setValue(editor.originalCode); + editor.clearSelection(); + }); + } + }); +})(); + +(function themes() { + var html = document.querySelector('html'); + var themeToggleButton = document.getElementById('theme-toggle'); + var themePopup = document.getElementById('theme-list'); + var themeColorMetaTag = document.querySelector('meta[name="theme-color"]'); + var stylesheets = { + ayuHighlight: document.querySelector("[href$='ayu-highlight.css']"), + tomorrowNight: document.querySelector("[href$='tomorrow-night.css']"), + highlight: document.querySelector("[href$='highlight.css']"), + }; + + function showThemes() { + themePopup.style.display = 'block'; + themeToggleButton.setAttribute('aria-expanded', true); + themePopup.querySelector("button#" + get_theme()).focus(); + } + + function updateThemeSelected() { + themePopup.querySelectorAll('.theme-selected').forEach(function (el) { + el.classList.remove('theme-selected'); + }); + themePopup.querySelector("button#" + get_theme()).classList.add('theme-selected'); + } + + function hideThemes() { + themePopup.style.display = 'none'; + themeToggleButton.setAttribute('aria-expanded', false); + themeToggleButton.focus(); + } + + function get_theme() { + var theme; + try { theme = localStorage.getItem('mdbook-theme'); } catch (e) { } + if (theme === null || theme === undefined) { + return default_theme; + } else { + return theme; + } + } + + function set_theme(theme, store = true) { + let ace_theme; + + if (theme == 'coal' || theme == 'navy') { + stylesheets.ayuHighlight.disabled = true; + stylesheets.tomorrowNight.disabled = false; + stylesheets.highlight.disabled = true; + + ace_theme = "ace/theme/tomorrow_night"; + } else if (theme == 'ayu') { + stylesheets.ayuHighlight.disabled = false; + stylesheets.tomorrowNight.disabled = true; + stylesheets.highlight.disabled = true; + ace_theme = "ace/theme/tomorrow_night"; + } else { + stylesheets.ayuHighlight.disabled = true; + stylesheets.tomorrowNight.disabled = true; + stylesheets.highlight.disabled = false; + ace_theme = "ace/theme/dawn"; + } + + setTimeout(function () { + themeColorMetaTag.content = getComputedStyle(document.body).backgroundColor; + }, 1); + + if (window.ace && window.editors) { + window.editors.forEach(function (editor) { + editor.setTheme(ace_theme); + }); + } + + var previousTheme = get_theme(); + + if (store) { + try { localStorage.setItem('mdbook-theme', theme); } catch (e) { } + } + + html.classList.remove(previousTheme); + html.classList.add(theme); + updateThemeSelected(); + } + + // Set theme + var theme = get_theme(); + + set_theme(theme, false); + + themeToggleButton.addEventListener('click', function () { + if (themePopup.style.display === 'block') { + hideThemes(); + } else { + showThemes(); + } + }); + + themePopup.addEventListener('click', function (e) { + var theme; + if (e.target.className === "theme") { + theme = e.target.id; + } else if (e.target.parentElement.className === "theme") { + theme = e.target.parentElement.id; + } else { + return; + } + set_theme(theme); + }); + + themePopup.addEventListener('focusout', function(e) { + // e.relatedTarget is null in Safari and Firefox on macOS (see workaround below) + if (!!e.relatedTarget && !themeToggleButton.contains(e.relatedTarget) && !themePopup.contains(e.relatedTarget)) { + hideThemes(); + } + }); + + // Should not be needed, but it works around an issue on macOS & iOS: https://github.com/rust-lang/mdBook/issues/628 + document.addEventListener('click', function(e) { + if (themePopup.style.display === 'block' && !themeToggleButton.contains(e.target) && !themePopup.contains(e.target)) { + hideThemes(); + } + }); + + document.addEventListener('keydown', function (e) { + if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; } + if (!themePopup.contains(e.target)) { return; } + + switch (e.key) { + case 'Escape': + e.preventDefault(); + hideThemes(); + break; + case 'ArrowUp': + e.preventDefault(); + var li = document.activeElement.parentElement; + if (li && li.previousElementSibling) { + li.previousElementSibling.querySelector('button').focus(); + } + break; + case 'ArrowDown': + e.preventDefault(); + var li = document.activeElement.parentElement; + if (li && li.nextElementSibling) { + li.nextElementSibling.querySelector('button').focus(); + } + break; + case 'Home': + e.preventDefault(); + themePopup.querySelector('li:first-child button').focus(); + break; + case 'End': + e.preventDefault(); + themePopup.querySelector('li:last-child button').focus(); + break; + } + }); +})(); + +(function sidebar() { + var html = document.querySelector("html"); + var sidebar = document.getElementById("sidebar"); + var sidebarLinks = document.querySelectorAll('#sidebar a'); + var sidebarToggleButton = document.getElementById("sidebar-toggle"); + var sidebarResizeHandle = document.getElementById("sidebar-resize-handle"); + var firstContact = null; + + function showSidebar() { + html.classList.remove('sidebar-hidden') + html.classList.add('sidebar-visible'); + Array.from(sidebarLinks).forEach(function (link) { + link.setAttribute('tabIndex', 0); + }); + sidebarToggleButton.setAttribute('aria-expanded', true); + sidebar.setAttribute('aria-hidden', false); + try { localStorage.setItem('mdbook-sidebar', 'visible'); } catch (e) { } + } + + + var sidebarAnchorToggles = document.querySelectorAll('#sidebar a.toggle'); + + function toggleSection(ev) { + ev.currentTarget.parentElement.classList.toggle('expanded'); + } + + Array.from(sidebarAnchorToggles).forEach(function (el) { + el.addEventListener('click', toggleSection); + }); + + function hideSidebar() { + html.classList.remove('sidebar-visible') + html.classList.add('sidebar-hidden'); + Array.from(sidebarLinks).forEach(function (link) { + link.setAttribute('tabIndex', -1); + }); + sidebarToggleButton.setAttribute('aria-expanded', false); + sidebar.setAttribute('aria-hidden', true); + try { localStorage.setItem('mdbook-sidebar', 'hidden'); } catch (e) { } + } + + // Toggle sidebar + sidebarToggleButton.addEventListener('click', function sidebarToggle() { + if (html.classList.contains("sidebar-hidden")) { + var current_width = parseInt( + document.documentElement.style.getPropertyValue('--sidebar-width'), 10); + if (current_width < 150) { + document.documentElement.style.setProperty('--sidebar-width', '150px'); + } + showSidebar(); + } else if (html.classList.contains("sidebar-visible")) { + hideSidebar(); + } else { + if (getComputedStyle(sidebar)['transform'] === 'none') { + hideSidebar(); + } else { + showSidebar(); + } + } + }); + + sidebarResizeHandle.addEventListener('mousedown', initResize, false); + + function initResize(e) { + window.addEventListener('mousemove', resize, false); + window.addEventListener('mouseup', stopResize, false); + html.classList.add('sidebar-resizing'); + } + function resize(e) { + var pos = (e.clientX - sidebar.offsetLeft); + if (pos < 20) { + hideSidebar(); + } else { + if (html.classList.contains("sidebar-hidden")) { + showSidebar(); + } + pos = Math.min(pos, window.innerWidth - 100); + document.documentElement.style.setProperty('--sidebar-width', pos + 'px'); + } + } + //on mouseup remove windows functions mousemove & mouseup + function stopResize(e) { + html.classList.remove('sidebar-resizing'); + window.removeEventListener('mousemove', resize, false); + window.removeEventListener('mouseup', stopResize, false); + } + + document.addEventListener('touchstart', function (e) { + firstContact = { + x: e.touches[0].clientX, + time: Date.now() + }; + }, { passive: true }); + + document.addEventListener('touchmove', function (e) { + if (!firstContact) + return; + + var curX = e.touches[0].clientX; + var xDiff = curX - firstContact.x, + tDiff = Date.now() - firstContact.time; + + if (tDiff < 250 && Math.abs(xDiff) >= 150) { + if (xDiff >= 0 && firstContact.x < Math.min(document.body.clientWidth * 0.25, 300)) + showSidebar(); + else if (xDiff < 0 && curX < 300) + hideSidebar(); + + firstContact = null; + } + }, { passive: true }); + + // Scroll sidebar to current active section + var activeSection = document.getElementById("sidebar").querySelector(".active"); + if (activeSection) { + // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView + activeSection.scrollIntoView({ block: 'center' }); + } +})(); + +(function chapterNavigation() { + document.addEventListener('keydown', function (e) { + if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; } + if (window.search && window.search.hasFocus()) { return; } + + switch (e.key) { + case 'ArrowRight': + e.preventDefault(); + var nextButton = document.querySelector('.nav-chapters.next'); + if (nextButton) { + window.location.href = nextButton.href; + } + break; + case 'ArrowLeft': + e.preventDefault(); + var previousButton = document.querySelector('.nav-chapters.previous'); + if (previousButton) { + window.location.href = previousButton.href; + } + break; + } + }); +})(); + +(function clipboard() { + var clipButtons = document.querySelectorAll('.clip-button'); + + function hideTooltip(elem) { + elem.firstChild.innerText = ""; + elem.className = 'fa fa-copy clip-button'; + } + + function showTooltip(elem, msg) { + elem.firstChild.innerText = msg; + elem.className = 'fa fa-copy tooltipped'; + } + + var clipboardSnippets = new ClipboardJS('.clip-button', { + text: function (trigger) { + hideTooltip(trigger); + let playground = trigger.closest("pre"); + return playground_text(playground, false); + } + }); + + Array.from(clipButtons).forEach(function (clipButton) { + clipButton.addEventListener('mouseout', function (e) { + hideTooltip(e.currentTarget); + }); + }); + + clipboardSnippets.on('success', function (e) { + e.clearSelection(); + showTooltip(e.trigger, "Copied!"); + }); + + clipboardSnippets.on('error', function (e) { + showTooltip(e.trigger, "Clipboard error!"); + }); +})(); + +(function scrollToTop () { + var menuTitle = document.querySelector('.menu-title'); + + menuTitle.addEventListener('click', function () { + document.scrollingElement.scrollTo({ top: 0, behavior: 'smooth' }); + }); +})(); + +(function controllMenu() { + var menu = document.getElementById('menu-bar'); + + (function controllPosition() { + var scrollTop = document.scrollingElement.scrollTop; + var prevScrollTop = scrollTop; + var minMenuY = -menu.clientHeight - 50; + // When the script loads, the page can be at any scroll (e.g. if you reforesh it). + menu.style.top = scrollTop + 'px'; + // Same as parseInt(menu.style.top.slice(0, -2), but faster + var topCache = menu.style.top.slice(0, -2); + menu.classList.remove('sticky'); + var stickyCache = false; // Same as menu.classList.contains('sticky'), but faster + document.addEventListener('scroll', function () { + scrollTop = Math.max(document.scrollingElement.scrollTop, 0); + // `null` means that it doesn't need to be updated + var nextSticky = null; + var nextTop = null; + var scrollDown = scrollTop > prevScrollTop; + var menuPosAbsoluteY = topCache - scrollTop; + if (scrollDown) { + nextSticky = false; + if (menuPosAbsoluteY > 0) { + nextTop = prevScrollTop; + } + } else { + if (menuPosAbsoluteY > 0) { + nextSticky = true; + } else if (menuPosAbsoluteY < minMenuY) { + nextTop = prevScrollTop + minMenuY; + } + } + if (nextSticky === true && stickyCache === false) { + menu.classList.add('sticky'); + stickyCache = true; + } else if (nextSticky === false && stickyCache === true) { + menu.classList.remove('sticky'); + stickyCache = false; + } + if (nextTop !== null) { + menu.style.top = nextTop + 'px'; + topCache = nextTop; + } + prevScrollTop = scrollTop; + }, { passive: true }); + })(); + (function controllBorder() { + menu.classList.remove('bordered'); + document.addEventListener('scroll', function () { + if (menu.offsetTop === 0) { + menu.classList.remove('bordered'); + } else { + menu.classList.add('bordered'); + } + }, { passive: true }); + })(); +})(); diff --git a/clipboard.min.js b/clipboard.min.js new file mode 100644 index 0000000..02c549e --- /dev/null +++ b/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.4 + * https://zenorocha.github.io/clipboard.js + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return function(n){var o={};function r(t){if(o[t])return o[t].exports;var e=o[t]={i:t,l:!1,exports:{}};return n[t].call(e.exports,e,e.exports,r),e.l=!0,e.exports}return r.m=n,r.c=o,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=0)}([function(t,e,n){"use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=function(){function o(t,e){for(var n=0;n .hljs { + color: var(--links); +} + +/* + body-container is necessary because mobile browsers don't seem to like + overflow-x on the body tag when there is a tag. +*/ +#body-container { + /* + This is used when the sidebar pushes the body content off the side of + the screen on small screens. Without it, dragging on mobile Safari + will want to reposition the viewport in a weird way. + */ + overflow-x: hidden; +} + +/* Menu Bar */ + +#menu-bar, +#menu-bar-hover-placeholder { + z-index: 101; + margin: auto calc(0px - var(--page-padding)); +} +#menu-bar { + position: relative; + display: flex; + flex-wrap: wrap; + background-color: var(--bg); + border-bottom-color: var(--bg); + border-bottom-width: 1px; + border-bottom-style: solid; +} +#menu-bar.sticky, +.js #menu-bar-hover-placeholder:hover + #menu-bar, +.js #menu-bar:hover, +.js.sidebar-visible #menu-bar { + position: -webkit-sticky; + position: sticky; + top: 0 !important; +} +#menu-bar-hover-placeholder { + position: sticky; + position: -webkit-sticky; + top: 0; + height: var(--menu-bar-height); +} +#menu-bar.bordered { + border-bottom-color: var(--table-border-color); +} +#menu-bar i, #menu-bar .icon-button { + position: relative; + padding: 0 8px; + z-index: 10; + line-height: var(--menu-bar-height); + cursor: pointer; + transition: color 0.5s; +} +@media only screen and (max-width: 420px) { + #menu-bar i, #menu-bar .icon-button { + padding: 0 5px; + } +} + +.icon-button { + border: none; + background: none; + padding: 0; + color: inherit; +} +.icon-button i { + margin: 0; +} + +.right-buttons { + margin: 0 15px; +} +.right-buttons a { + text-decoration: none; +} + +.left-buttons { + display: flex; + margin: 0 5px; +} +.no-js .left-buttons { + display: none; +} + +.menu-title { + display: inline-block; + font-weight: 200; + font-size: 2.4rem; + line-height: var(--menu-bar-height); + text-align: center; + margin: 0; + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.js .menu-title { + cursor: pointer; +} + +.menu-bar, +.menu-bar:visited, +.nav-chapters, +.nav-chapters:visited, +.mobile-nav-chapters, +.mobile-nav-chapters:visited, +.menu-bar .icon-button, +.menu-bar a i { + color: var(--icons); +} + +.menu-bar i:hover, +.menu-bar .icon-button:hover, +.nav-chapters:hover, +.mobile-nav-chapters i:hover { + color: var(--icons-hover); +} + +/* Nav Icons */ + +.nav-chapters { + font-size: 2.5em; + text-align: center; + text-decoration: none; + + position: fixed; + top: 0; + bottom: 0; + margin: 0; + max-width: 150px; + min-width: 90px; + + display: flex; + justify-content: center; + align-content: center; + flex-direction: column; + + transition: color 0.5s, background-color 0.5s; +} + +.nav-chapters:hover { + text-decoration: none; + background-color: var(--theme-hover); + transition: background-color 0.15s, color 0.15s; +} + +.nav-wrapper { + margin-top: 50px; + display: none; +} + +.mobile-nav-chapters { + font-size: 2.5em; + text-align: center; + text-decoration: none; + width: 90px; + border-radius: 5px; + background-color: var(--sidebar-bg); +} + +.previous { + float: left; +} + +.next { + float: right; + right: var(--page-padding); +} + +@media only screen and (max-width: 1080px) { + .nav-wide-wrapper { display: none; } + .nav-wrapper { display: block; } +} + +@media only screen and (max-width: 1380px) { + .sidebar-visible .nav-wide-wrapper { display: none; } + .sidebar-visible .nav-wrapper { display: block; } +} + +/* Inline code */ + +:not(pre) > .hljs { + display: inline; + padding: 0.1em 0.3em; + border-radius: 3px; +} + +:not(pre):not(a) > .hljs { + color: var(--inline-code-color); + overflow-x: initial; +} + +a:hover > .hljs { + text-decoration: underline; +} + +pre { + position: relative; +} +pre > .buttons { + position: absolute; + z-index: 100; + right: 0px; + top: 2px; + margin: 0px; + padding: 2px 0px; + + color: var(--sidebar-fg); + cursor: pointer; + visibility: hidden; + opacity: 0; + transition: visibility 0.1s linear, opacity 0.1s linear; +} +pre:hover > .buttons { + visibility: visible; + opacity: 1 +} +pre > .buttons :hover { + color: var(--sidebar-active); + border-color: var(--icons-hover); + background-color: var(--theme-hover); +} +pre > .buttons i { + margin-left: 8px; +} +pre > .buttons button { + cursor: inherit; + margin: 0px 5px; + padding: 3px 5px; + font-size: 14px; + + border-style: solid; + border-width: 1px; + border-radius: 4px; + border-color: var(--icons); + background-color: var(--theme-popup-bg); + transition: 100ms; + transition-property: color,border-color,background-color; + color: var(--icons); +} +@media (pointer: coarse) { + pre > .buttons button { + /* On mobile, make it easier to tap buttons. */ + padding: 0.3rem 1rem; + } +} +pre > code { + padding: 1rem; +} + +/* FIXME: ACE editors overlap their buttons because ACE does absolute + positioning within the code block which breaks padding. The only solution I + can think of is to move the padding to the outer pre tag (or insert a div + wrapper), but that would require fixing a whole bunch of CSS rules. +*/ +.hljs.ace_editor { + padding: 0rem 0rem; +} + +pre > .result { + margin-top: 10px; +} + +/* Search */ + +#searchresults a { + text-decoration: none; +} + +mark { + border-radius: 2px; + padding: 0 3px 1px 3px; + margin: 0 -3px -1px -3px; + background-color: var(--search-mark-bg); + transition: background-color 300ms linear; + cursor: pointer; +} + +mark.fade-out { + background-color: rgba(0,0,0,0) !important; + cursor: auto; +} + +.searchbar-outer { + margin-left: auto; + margin-right: auto; + max-width: var(--content-max-width); +} + +#searchbar { + width: 100%; + margin: 5px auto 0px auto; + padding: 10px 16px; + transition: box-shadow 300ms ease-in-out; + border: 1px solid var(--searchbar-border-color); + border-radius: 3px; + background-color: var(--searchbar-bg); + color: var(--searchbar-fg); +} +#searchbar:focus, +#searchbar.active { + box-shadow: 0 0 3px var(--searchbar-shadow-color); +} + +.searchresults-header { + font-weight: bold; + font-size: 1em; + padding: 18px 0 0 5px; + color: var(--searchresults-header-fg); +} + +.searchresults-outer { + margin-left: auto; + margin-right: auto; + max-width: var(--content-max-width); + border-bottom: 1px dashed var(--searchresults-border-color); +} + +ul#searchresults { + list-style: none; + padding-left: 20px; +} +ul#searchresults li { + margin: 10px 0px; + padding: 2px; + border-radius: 2px; +} +ul#searchresults li.focus { + background-color: var(--searchresults-li-bg); +} +ul#searchresults span.teaser { + display: block; + clear: both; + margin: 5px 0 0 20px; + font-size: 0.8em; +} +ul#searchresults span.teaser em { + font-weight: bold; + font-style: normal; +} + +/* Sidebar */ + +.sidebar { + position: fixed; + left: 0; + top: 0; + bottom: 0; + width: var(--sidebar-width); + font-size: 0.875em; + box-sizing: border-box; + -webkit-overflow-scrolling: touch; + overscroll-behavior-y: contain; + background-color: var(--sidebar-bg); + color: var(--sidebar-fg); +} +.sidebar-resizing { + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} +.js:not(.sidebar-resizing) .sidebar { + transition: transform 0.3s; /* Animation: slide away */ +} +.sidebar code { + line-height: 2em; +} +.sidebar .sidebar-scrollbox { + overflow-y: auto; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + padding: 10px 10px; +} +.sidebar .sidebar-resize-handle { + position: absolute; + cursor: col-resize; + width: 0; + right: 0; + top: 0; + bottom: 0; +} +.js .sidebar .sidebar-resize-handle { + cursor: col-resize; + width: 5px; +} +.sidebar-hidden .sidebar { + transform: translateX(calc(0px - var(--sidebar-width))); +} +.sidebar::-webkit-scrollbar { + background: var(--sidebar-bg); +} +.sidebar::-webkit-scrollbar-thumb { + background: var(--scrollbar); +} + +.sidebar-visible .page-wrapper { + transform: translateX(var(--sidebar-width)); +} +@media only screen and (min-width: 620px) { + .sidebar-visible .page-wrapper { + transform: none; + margin-left: var(--sidebar-width); + } +} + +.chapter { + list-style: none outside none; + padding-left: 0; + line-height: 2.2em; +} + +.chapter ol { + width: 100%; +} + +.chapter li { + display: flex; + color: var(--sidebar-non-existant); +} +.chapter li a { + display: block; + padding: 0; + text-decoration: none; + color: var(--sidebar-fg); +} + +.chapter li a:hover { + color: var(--sidebar-active); +} + +.chapter li a.active { + color: var(--sidebar-active); +} + +.chapter li > a.toggle { + cursor: pointer; + display: block; + margin-left: auto; + padding: 0 10px; + user-select: none; + opacity: 0.68; +} + +.chapter li > a.toggle div { + transition: transform 0.5s; +} + +/* collapse the section */ +.chapter li:not(.expanded) + li > ol { + display: none; +} + +.chapter li.chapter-item { + line-height: 1.5em; + margin-top: 0.6em; +} + +.chapter li.expanded > a.toggle div { + transform: rotate(90deg); +} + +.spacer { + width: 100%; + height: 3px; + margin: 5px 0px; +} +.chapter .spacer { + background-color: var(--sidebar-spacer); +} + +@media (-moz-touch-enabled: 1), (pointer: coarse) { + .chapter li a { padding: 5px 0; } + .spacer { margin: 10px 0; } +} + +.section { + list-style: none outside none; + padding-left: 20px; + line-height: 1.9em; +} + +/* Theme Menu Popup */ + +.theme-popup { + position: absolute; + left: 10px; + top: var(--menu-bar-height); + z-index: 1000; + border-radius: 4px; + font-size: 0.7em; + color: var(--fg); + background: var(--theme-popup-bg); + border: 1px solid var(--theme-popup-border); + margin: 0; + padding: 0; + list-style: none; + display: none; + /* Don't let the children's background extend past the rounded corners. */ + overflow: hidden; +} +.theme-popup .default { + color: var(--icons); +} +.theme-popup .theme { + width: 100%; + border: 0; + margin: 0; + padding: 2px 20px; + line-height: 25px; + white-space: nowrap; + text-align: left; + cursor: pointer; + color: inherit; + background: inherit; + font-size: inherit; +} +.theme-popup .theme:hover { + background-color: var(--theme-hover); +} + +.theme-selected::before { + display: inline-block; + content: "✓"; + margin-left: -14px; + width: 14px; +} diff --git a/css/general.css b/css/general.css new file mode 100644 index 0000000..344b53e --- /dev/null +++ b/css/general.css @@ -0,0 +1,203 @@ +/* Base styles and content styles */ + +@import 'variables.css'; + +:root { + /* Browser default font-size is 16px, this way 1 rem = 10px */ + font-size: 62.5%; +} + +html { + font-family: "Open Sans", sans-serif; + color: var(--fg); + background-color: var(--bg); + text-size-adjust: none; + -webkit-text-size-adjust: none; +} + +body { + margin: 0; + font-size: 1.6rem; + overflow-x: hidden; +} + +code { + font-family: var(--mono-font) !important; + font-size: var(--code-font-size); +} + +/* make long words/inline code not x overflow */ +main { + overflow-wrap: break-word; +} + +/* make wide tables scroll if they overflow */ +.table-wrapper { + overflow-x: auto; +} + +/* Don't change font size in headers. */ +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + font-size: unset; +} + +.left { float: left; } +.right { float: right; } +.boring { opacity: 0.6; } +.hide-boring .boring { display: none; } +.hidden { display: none !important; } + +h2, h3 { margin-top: 2.5em; } +h4, h5 { margin-top: 2em; } + +.header + .header h3, +.header + .header h4, +.header + .header h5 { + margin-top: 1em; +} + +h1:target::before, +h2:target::before, +h3:target::before, +h4:target::before, +h5:target::before, +h6:target::before { + display: inline-block; + content: "»"; + margin-left: -30px; + width: 30px; +} + +/* This is broken on Safari as of version 14, but is fixed + in Safari Technology Preview 117 which I think will be Safari 14.2. + https://bugs.webkit.org/show_bug.cgi?id=218076 +*/ +:target { + scroll-margin-top: calc(var(--menu-bar-height) + 0.5em); +} + +.page { + outline: 0; + padding: 0 var(--page-padding); + margin-top: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */ +} +.page-wrapper { + box-sizing: border-box; +} +.js:not(.sidebar-resizing) .page-wrapper { + transition: margin-left 0.3s ease, transform 0.3s ease; /* Animation: slide away */ +} + +.content { + overflow-y: auto; + padding: 0 5px 50px 5px; +} +.content main { + margin-left: auto; + margin-right: auto; + max-width: var(--content-max-width); +} +.content p { line-height: 1.45em; } +.content ol { line-height: 1.45em; } +.content ul { line-height: 1.45em; } +.content a { text-decoration: none; } +.content a:hover { text-decoration: underline; } +.content img, .content video { max-width: 100%; } +.content .header:link, +.content .header:visited { + color: var(--fg); +} +.content .header:link, +.content .header:visited:hover { + text-decoration: none; +} + +table { + margin: 0 auto; + border-collapse: collapse; +} +table td { + padding: 3px 20px; + border: 1px var(--table-border-color) solid; +} +table thead { + background: var(--table-header-bg); +} +table thead td { + font-weight: 700; + border: none; +} +table thead th { + padding: 3px 20px; +} +table thead tr { + border: 1px var(--table-header-bg) solid; +} +/* Alternate background colors for rows */ +table tbody tr:nth-child(2n) { + background: var(--table-alternate-bg); +} + + +blockquote { + margin: 20px 0; + padding: 0 20px; + color: var(--fg); + background-color: var(--quote-bg); + border-top: .1em solid var(--quote-border); + border-bottom: .1em solid var(--quote-border); +} + +kbd { + background-color: var(--table-border-color); + border-radius: 4px; + border: solid 1px var(--theme-popup-border); + box-shadow: inset 0 -1px 0 var(--theme-hover); + display: inline-block; + font-size: var(--code-font-size); + font-family: var(--mono-font); + line-height: 10px; + padding: 4px 5px; + vertical-align: middle; +} + +:not(.footnote-definition) + .footnote-definition, +.footnote-definition + :not(.footnote-definition) { + margin-top: 2em; +} +.footnote-definition { + font-size: 0.9em; + margin: 0.5em 0; +} +.footnote-definition p { + display: inline; +} + +.tooltiptext { + position: absolute; + visibility: hidden; + color: #fff; + background-color: #333; + transform: translateX(-50%); /* Center by moving tooltip 50% of its width left */ + left: -8px; /* Half of the width of the icon */ + top: -35px; + font-size: 0.8em; + text-align: center; + border-radius: 6px; + padding: 5px 8px; + margin: 5px; + z-index: 1000; +} +.tooltipped .tooltiptext { + visibility: visible; +} + +.chapter li.part-title { + color: var(--sidebar-fg); + margin: 5px 0px; + font-weight: bold; +} + +.result-no-output { + font-style: italic; +} diff --git a/css/print.css b/css/print.css new file mode 100644 index 0000000..5e690f7 --- /dev/null +++ b/css/print.css @@ -0,0 +1,54 @@ + +#sidebar, +#menu-bar, +.nav-chapters, +.mobile-nav-chapters { + display: none; +} + +#page-wrapper.page-wrapper { + transform: none; + margin-left: 0px; + overflow-y: initial; +} + +#content { + max-width: none; + margin: 0; + padding: 0; +} + +.page { + overflow-y: initial; +} + +code { + background-color: #666666; + border-radius: 5px; + + /* Force background to be printed in Chrome */ + -webkit-print-color-adjust: exact; +} + +pre > .buttons { + z-index: 2; +} + +a, a:visited, a:active, a:hover { + color: #4183c4; + text-decoration: none; +} + +h1, h2, h3, h4, h5, h6 { + page-break-inside: avoid; + page-break-after: avoid; +} + +pre, code { + page-break-inside: avoid; + white-space: pre-wrap; +} + +.fa { + display: none !important; +} diff --git a/css/variables.css b/css/variables.css new file mode 100644 index 0000000..21bf8e5 --- /dev/null +++ b/css/variables.css @@ -0,0 +1,255 @@ + +/* Globals */ + +:root { + --sidebar-width: 300px; + --page-padding: 15px; + --content-max-width: 750px; + --menu-bar-height: 50px; + --mono-font: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace; + --code-font-size: 0.875em /* please adjust the ace font size accordingly in editor.js */ +} + +/* Themes */ + +.ayu { + --bg: hsl(210, 25%, 8%); + --fg: #c5c5c5; + + --sidebar-bg: #14191f; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #5c6773; + --sidebar-active: #ffb454; + --sidebar-spacer: #2d334f; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #b7b9cc; + + --links: #0096cf; + + --inline-code-color: #ffb454; + + --theme-popup-bg: #14191f; + --theme-popup-border: #5c6773; + --theme-hover: #191f26; + + --quote-bg: hsl(226, 15%, 17%); + --quote-border: hsl(226, 15%, 22%); + + --table-border-color: hsl(210, 25%, 13%); + --table-header-bg: hsl(210, 25%, 28%); + --table-alternate-bg: hsl(210, 25%, 11%); + + --searchbar-border-color: #848484; + --searchbar-bg: #424242; + --searchbar-fg: #fff; + --searchbar-shadow-color: #d4c89f; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #252932; + --search-mark-bg: #e3b171; +} + +.coal { + --bg: hsl(200, 7%, 8%); + --fg: #98a3ad; + + --sidebar-bg: #292c2f; + --sidebar-fg: #a1adb8; + --sidebar-non-existant: #505254; + --sidebar-active: #3473ad; + --sidebar-spacer: #393939; + + --scrollbar: var(--sidebar-fg); + + --icons: #43484d; + --icons-hover: #b3c0cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #141617; + --theme-popup-border: #43484d; + --theme-hover: #1f2124; + + --quote-bg: hsl(234, 21%, 18%); + --quote-border: hsl(234, 21%, 23%); + + --table-border-color: hsl(200, 7%, 13%); + --table-header-bg: hsl(200, 7%, 28%); + --table-alternate-bg: hsl(200, 7%, 11%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #b7b7b7; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #98a3ad; + --searchresults-li-bg: #2b2b2f; + --search-mark-bg: #355c7d; +} + +.light { + --bg: hsl(0, 0%, 100%); + --fg: hsl(0, 0%, 0%); + + --sidebar-bg: #fafafa; + --sidebar-fg: hsl(0, 0%, 0%); + --sidebar-non-existant: #aaaaaa; + --sidebar-active: #1f1fff; + --sidebar-spacer: #f4f4f4; + + --scrollbar: #8F8F8F; + + --icons: #747474; + --icons-hover: #000000; + + --links: #20609f; + + --inline-code-color: #301900; + + --theme-popup-bg: #fafafa; + --theme-popup-border: #cccccc; + --theme-hover: #e6e6e6; + + --quote-bg: hsl(197, 37%, 96%); + --quote-border: hsl(197, 37%, 91%); + + --table-border-color: hsl(0, 0%, 95%); + --table-header-bg: hsl(0, 0%, 80%); + --table-alternate-bg: hsl(0, 0%, 97%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #fafafa; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #e4f2fe; + --search-mark-bg: #a2cff5; +} + +.navy { + --bg: hsl(226, 23%, 11%); + --fg: #bcbdd0; + + --sidebar-bg: #282d3f; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #505274; + --sidebar-active: #2b79a2; + --sidebar-spacer: #2d334f; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #b7b9cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #161923; + --theme-popup-border: #737480; + --theme-hover: #282e40; + + --quote-bg: hsl(226, 15%, 17%); + --quote-border: hsl(226, 15%, 22%); + + --table-border-color: hsl(226, 23%, 16%); + --table-header-bg: hsl(226, 23%, 31%); + --table-alternate-bg: hsl(226, 23%, 14%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #aeaec6; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #5f5f71; + --searchresults-border-color: #5c5c68; + --searchresults-li-bg: #242430; + --search-mark-bg: #a2cff5; +} + +.rust { + --bg: hsl(60, 9%, 87%); + --fg: #262625; + + --sidebar-bg: #3b2e2a; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #505254; + --sidebar-active: #e69f67; + --sidebar-spacer: #45373a; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #262625; + + --links: #2b79a2; + + --inline-code-color: #6e6b5e; + + --theme-popup-bg: #e1e1db; + --theme-popup-border: #b38f6b; + --theme-hover: #99908a; + + --quote-bg: hsl(60, 5%, 75%); + --quote-border: hsl(60, 5%, 70%); + + --table-border-color: hsl(60, 9%, 82%); + --table-header-bg: #b3a497; + --table-alternate-bg: hsl(60, 9%, 84%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #fafafa; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #dec2a2; + --search-mark-bg: #e69f67; +} + +@media (prefers-color-scheme: dark) { + .light.no-js { + --bg: hsl(200, 7%, 8%); + --fg: #98a3ad; + + --sidebar-bg: #292c2f; + --sidebar-fg: #a1adb8; + --sidebar-non-existant: #505254; + --sidebar-active: #3473ad; + --sidebar-spacer: #393939; + + --scrollbar: var(--sidebar-fg); + + --icons: #43484d; + --icons-hover: #b3c0cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #141617; + --theme-popup-border: #43484d; + --theme-hover: #1f2124; + + --quote-bg: hsl(234, 21%, 18%); + --quote-border: hsl(234, 21%, 23%); + + --table-border-color: hsl(200, 7%, 13%); + --table-header-bg: hsl(200, 7%, 28%); + --table-alternate-bg: hsl(200, 7%, 11%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #b7b7b7; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #98a3ad; + --searchresults-li-bg: #2b2b2f; + --search-mark-bg: #355c7d; + } +} diff --git a/elasticlunr.min.js b/elasticlunr.min.js new file mode 100644 index 0000000..94b20dd --- /dev/null +++ b/elasticlunr.min.js @@ -0,0 +1,10 @@ +/** + * elasticlunr - http://weixsong.github.io + * Lightweight full-text search engine in Javascript for browser search and offline search. - 0.9.5 + * + * Copyright (C) 2017 Oliver Nightingale + * Copyright (C) 2017 Wei Song + * MIT Licensed + * @license + */ +!function(){function e(e){if(null===e||"object"!=typeof e)return e;var t=e.constructor();for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.9.5",lunr=t,t.utils={},t.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),t.utils.toString=function(e){return void 0===e||null===e?"":e.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var e=Array.prototype.slice.call(arguments),t=e.pop(),n=e;if("function"!=typeof t)throw new TypeError("last argument must be a function");n.forEach(function(e){this.hasHandler(e)||(this.events[e]=[]),this.events[e].push(t)},this)},t.EventEmitter.prototype.removeListener=function(e,t){if(this.hasHandler(e)){var n=this.events[e].indexOf(t);-1!==n&&(this.events[e].splice(n,1),0==this.events[e].length&&delete this.events[e])}},t.EventEmitter.prototype.emit=function(e){if(this.hasHandler(e)){var t=Array.prototype.slice.call(arguments,1);this.events[e].forEach(function(e){e.apply(void 0,t)},this)}},t.EventEmitter.prototype.hasHandler=function(e){return e in this.events},t.tokenizer=function(e){if(!arguments.length||null===e||void 0===e)return[];if(Array.isArray(e)){var n=e.filter(function(e){return null===e||void 0===e?!1:!0});n=n.map(function(e){return t.utils.toString(e).toLowerCase()});var i=[];return n.forEach(function(e){var n=e.split(t.tokenizer.seperator);i=i.concat(n)},this),i}return e.toString().trim().toLowerCase().split(t.tokenizer.seperator)},t.tokenizer.defaultSeperator=/[\s\-]+/,t.tokenizer.seperator=t.tokenizer.defaultSeperator,t.tokenizer.setSeperator=function(e){null!==e&&void 0!==e&&"object"==typeof e&&(t.tokenizer.seperator=e)},t.tokenizer.resetSeperator=function(){t.tokenizer.seperator=t.tokenizer.defaultSeperator},t.tokenizer.getSeperator=function(){return t.tokenizer.seperator},t.Pipeline=function(){this._queue=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in t.Pipeline.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[n]=e},t.Pipeline.getRegisteredFunction=function(e){return e in t.Pipeline.registeredFunctions!=!0?null:t.Pipeline.registeredFunctions[e]},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.getRegisteredFunction(e);if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._queue.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i+1,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i,0,n)},t.Pipeline.prototype.remove=function(e){var t=this._queue.indexOf(e);-1!==t&&this._queue.splice(t,1)},t.Pipeline.prototype.run=function(e){for(var t=[],n=e.length,i=this._queue.length,o=0;n>o;o++){for(var r=e[o],s=0;i>s&&(r=this._queue[s](r,o,e),void 0!==r&&null!==r);s++);void 0!==r&&null!==r&&t.push(r)}return t},t.Pipeline.prototype.reset=function(){this._queue=[]},t.Pipeline.prototype.get=function(){return this._queue},t.Pipeline.prototype.toJSON=function(){return this._queue.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.DocumentStore,this.index={},this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var e=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,e)},t.Index.prototype.off=function(e,t){return this.eventEmitter.removeListener(e,t)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;n._fields=e.fields,n._ref=e.ref,n.documentStore=t.DocumentStore.load(e.documentStore),n.pipeline=t.Pipeline.load(e.pipeline),n.index={};for(var i in e.index)n.index[i]=t.InvertedIndex.load(e.index[i]);return n},t.Index.prototype.addField=function(e){return this._fields.push(e),this.index[e]=new t.InvertedIndex,this},t.Index.prototype.setRef=function(e){return this._ref=e,this},t.Index.prototype.saveDocument=function(e){return this.documentStore=new t.DocumentStore(e),this},t.Index.prototype.addDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.addDoc(i,e),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));this.documentStore.addFieldLength(i,n,o.length);var r={};o.forEach(function(e){e in r?r[e]+=1:r[e]=1},this);for(var s in r){var u=r[s];u=Math.sqrt(u),this.index[n].addToken(s,{ref:i,tf:u})}},this),n&&this.eventEmitter.emit("add",e,this)}},t.Index.prototype.removeDocByRef=function(e){if(e&&this.documentStore.isDocStored()!==!1&&this.documentStore.hasDoc(e)){var t=this.documentStore.getDoc(e);this.removeDoc(t,!1)}},t.Index.prototype.removeDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.hasDoc(i)&&(this.documentStore.removeDoc(i),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));o.forEach(function(e){this.index[n].removeToken(e,i)},this)},this),n&&this.eventEmitter.emit("remove",e,this))}},t.Index.prototype.updateDoc=function(e,t){var t=void 0===t?!0:t;this.removeDocByRef(e[this._ref],!1),this.addDoc(e,!1),t&&this.eventEmitter.emit("update",e,this)},t.Index.prototype.idf=function(e,t){var n="@"+t+"/"+e;if(Object.prototype.hasOwnProperty.call(this._idfCache,n))return this._idfCache[n];var i=this.index[t].getDocFreq(e),o=1+Math.log(this.documentStore.length/(i+1));return this._idfCache[n]=o,o},t.Index.prototype.getFields=function(){return this._fields.slice()},t.Index.prototype.search=function(e,n){if(!e)return[];e="string"==typeof e?{any:e}:JSON.parse(JSON.stringify(e));var i=null;null!=n&&(i=JSON.stringify(n));for(var o=new t.Configuration(i,this.getFields()).get(),r={},s=Object.keys(e),u=0;u0&&t.push(e);for(var i in n)"docs"!==i&&"df"!==i&&this.expandToken(e+i,t,n[i]);return t},t.InvertedIndex.prototype.toJSON=function(){return{root:this.root}},t.Configuration=function(e,n){var e=e||"";if(void 0==n||null==n)throw new Error("fields should not be null");this.config={};var i;try{i=JSON.parse(e),this.buildUserConfig(i,n)}catch(o){t.utils.warn("user configuration parse failed, will use default configuration"),this.buildDefaultConfig(n)}},t.Configuration.prototype.buildDefaultConfig=function(e){this.reset(),e.forEach(function(e){this.config[e]={boost:1,bool:"OR",expand:!1}},this)},t.Configuration.prototype.buildUserConfig=function(e,n){var i="OR",o=!1;if(this.reset(),"bool"in e&&(i=e.bool||i),"expand"in e&&(o=e.expand||o),"fields"in e)for(var r in e.fields)if(n.indexOf(r)>-1){var s=e.fields[r],u=o;void 0!=s.expand&&(u=s.expand),this.config[r]={boost:s.boost||0===s.boost?s.boost:1,bool:s.bool||i,expand:u}}else t.utils.warn("field name in user configuration not found in index instance fields");else this.addAllFields2UserConfig(i,o,n)},t.Configuration.prototype.addAllFields2UserConfig=function(e,t,n){n.forEach(function(n){this.config[n]={boost:1,bool:e,expand:t}},this)},t.Configuration.prototype.get=function(){return this.config},t.Configuration.prototype.reset=function(){this.config={}},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(e){var t=new this;return t.elements=e,t.length=e.length,t},lunr.SortedSet.prototype.add=function(){var e,t;for(e=0;e1;){if(r===e)return o;e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o]}return r===e?o:-1},lunr.SortedSet.prototype.locationFor=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;)e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o];return r>e?o:e>r?o+1:void 0},lunr.SortedSet.prototype.intersect=function(e){for(var t=new lunr.SortedSet,n=0,i=0,o=this.length,r=e.length,s=this.elements,u=e.elements;;){if(n>o-1||i>r-1)break;s[n]!==u[i]?s[n]u[i]&&i++:(t.add(s[n]),n++,i++)}return t},lunr.SortedSet.prototype.clone=function(){var e=new lunr.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},lunr.SortedSet.prototype.union=function(e){var t,n,i;this.length>=e.length?(t=this,n=e):(t=e,n=this),i=t.clone();for(var o=0,r=n.toArray();o + + + + diff --git a/fonts/OPEN-SANS-LICENSE.txt b/fonts/OPEN-SANS-LICENSE.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/fonts/OPEN-SANS-LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/fonts/SOURCE-CODE-PRO-LICENSE.txt b/fonts/SOURCE-CODE-PRO-LICENSE.txt new file mode 100644 index 0000000..366206f --- /dev/null +++ b/fonts/SOURCE-CODE-PRO-LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/fonts/fonts.css b/fonts/fonts.css new file mode 100644 index 0000000..858efa5 --- /dev/null +++ b/fonts/fonts.css @@ -0,0 +1,100 @@ +/* Open Sans is licensed under the Apache License, Version 2.0. See http://www.apache.org/licenses/LICENSE-2.0 */ +/* Source Code Pro is under the Open Font License. See https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL */ + +/* open-sans-300 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300; + src: local('Open Sans Light'), local('OpenSans-Light'), + url('open-sans-v17-all-charsets-300.woff2') format('woff2'); +} + +/* open-sans-300italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 300; + src: local('Open Sans Light Italic'), local('OpenSans-LightItalic'), + url('open-sans-v17-all-charsets-300italic.woff2') format('woff2'); +} + +/* open-sans-regular - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans Regular'), local('OpenSans-Regular'), + url('open-sans-v17-all-charsets-regular.woff2') format('woff2'); +} + +/* open-sans-italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 400; + src: local('Open Sans Italic'), local('OpenSans-Italic'), + url('open-sans-v17-all-charsets-italic.woff2') format('woff2'); +} + +/* open-sans-600 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 600; + src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), + url('open-sans-v17-all-charsets-600.woff2') format('woff2'); +} + +/* open-sans-600italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 600; + src: local('Open Sans SemiBold Italic'), local('OpenSans-SemiBoldItalic'), + url('open-sans-v17-all-charsets-600italic.woff2') format('woff2'); +} + +/* open-sans-700 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), + url('open-sans-v17-all-charsets-700.woff2') format('woff2'); +} + +/* open-sans-700italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 700; + src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), + url('open-sans-v17-all-charsets-700italic.woff2') format('woff2'); +} + +/* open-sans-800 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 800; + src: local('Open Sans ExtraBold'), local('OpenSans-ExtraBold'), + url('open-sans-v17-all-charsets-800.woff2') format('woff2'); +} + +/* open-sans-800italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 800; + src: local('Open Sans ExtraBold Italic'), local('OpenSans-ExtraBoldItalic'), + url('open-sans-v17-all-charsets-800italic.woff2') format('woff2'); +} + +/* source-code-pro-500 - latin_vietnamese_latin-ext_greek_cyrillic-ext_cyrillic */ +@font-face { + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 500; + src: url('source-code-pro-v11-all-charsets-500.woff2') format('woff2'); +} diff --git a/fonts/open-sans-v17-all-charsets-300.woff2 b/fonts/open-sans-v17-all-charsets-300.woff2 new file mode 100644 index 0000000..9f51be3 Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-300.woff2 differ diff --git a/fonts/open-sans-v17-all-charsets-300italic.woff2 b/fonts/open-sans-v17-all-charsets-300italic.woff2 new file mode 100644 index 0000000..2f54544 Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-300italic.woff2 differ diff --git a/fonts/open-sans-v17-all-charsets-600.woff2 b/fonts/open-sans-v17-all-charsets-600.woff2 new file mode 100644 index 0000000..f503d55 Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-600.woff2 differ diff --git a/fonts/open-sans-v17-all-charsets-600italic.woff2 b/fonts/open-sans-v17-all-charsets-600italic.woff2 new file mode 100644 index 0000000..c99aabe Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-600italic.woff2 differ diff --git a/fonts/open-sans-v17-all-charsets-700.woff2 b/fonts/open-sans-v17-all-charsets-700.woff2 new file mode 100644 index 0000000..421a1ab Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-700.woff2 differ diff --git a/fonts/open-sans-v17-all-charsets-700italic.woff2 b/fonts/open-sans-v17-all-charsets-700italic.woff2 new file mode 100644 index 0000000..12ce3d2 Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-700italic.woff2 differ diff --git a/fonts/open-sans-v17-all-charsets-800.woff2 b/fonts/open-sans-v17-all-charsets-800.woff2 new file mode 100644 index 0000000..c94a223 Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-800.woff2 differ diff --git a/fonts/open-sans-v17-all-charsets-800italic.woff2 b/fonts/open-sans-v17-all-charsets-800italic.woff2 new file mode 100644 index 0000000..eed7d3c Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-800italic.woff2 differ diff --git a/fonts/open-sans-v17-all-charsets-italic.woff2 b/fonts/open-sans-v17-all-charsets-italic.woff2 new file mode 100644 index 0000000..398b68a Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-italic.woff2 differ diff --git a/fonts/open-sans-v17-all-charsets-regular.woff2 b/fonts/open-sans-v17-all-charsets-regular.woff2 new file mode 100644 index 0000000..8383e94 Binary files /dev/null and b/fonts/open-sans-v17-all-charsets-regular.woff2 differ diff --git a/fonts/source-code-pro-v11-all-charsets-500.woff2 b/fonts/source-code-pro-v11-all-charsets-500.woff2 new file mode 100644 index 0000000..7222456 Binary files /dev/null and b/fonts/source-code-pro-v11-all-charsets-500.woff2 differ diff --git a/guides/API_Guide/images/image1.png b/guides/API_Guide/images/image1.png new file mode 100644 index 0000000..76be96f Binary files /dev/null and b/guides/API_Guide/images/image1.png differ diff --git a/guides/API_Guide/images/image2.png b/guides/API_Guide/images/image2.png new file mode 100644 index 0000000..b2ba6f9 Binary files /dev/null and b/guides/API_Guide/images/image2.png differ diff --git a/guides/API_Guide/images/image3.png b/guides/API_Guide/images/image3.png new file mode 100644 index 0000000..381060e Binary files /dev/null and b/guides/API_Guide/images/image3.png differ diff --git a/guides/API_Guide/index.html b/guides/API_Guide/index.html new file mode 100644 index 0000000..8979b8b --- /dev/null +++ b/guides/API_Guide/index.html @@ -0,0 +1,264 @@ + + + + + + APIs - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+
+
+
+

Tech Start's API Guide

+

alt_text

+

APIs are a ubiquitous component of software engineering. APIs allow different components of a software system to interact with each other in a logical way.

+

Learning about APIs is critical to your growth as a software developer. This guide contains links and advice to get you started!

+

Introduction

+

What is an API?

+

alt_text

+

API stands for Application Programming Interface, and in simple words, allows two applications to talk to each other and send information between the two.

+

Further reading on the basics of APIs: https://www.plektonlabs.com/api-101-what-are-they-and-how-do-they-work/?gclid=Cj0KCQiAhf2MBhDNARIsAKXU5GRbLqWDWBPN0Zh4ZX6KwjevURl9KmQo0EVBzLn5mcePxaI_l1oWQSQaAkGDEALw_wcB

+

Analogy of an API

+

Imagine you are sitting in a restaurant with a menu and you are trying to decide what to order. You are one of the applications and in order to get food, the kitchen will act like the other application. It is the system that will “make” you food. The waiter in this scenario will be the API, and he/she delivers the food from one application(the kitchen) to another(you). The waiter is the messenger that takes your request or order and tells the kitchen – the system – what to do. Then the waiter delivers the response back to you; in this case, it is the food.

+

How API’s Work

+
    +
  1. A client application initiates an API call to retrieve information—also known as a request. This request is processed from an application to the web server via the API’s Uniform Resource Identifier (URI) and includes a request verb(see Types of API calls), headers, and sometimes, a request body.
  2. +
  3. After receiving a valid request, the API makes a call to the external program or web server.
  4. +
  5. The server sends a response to the API with the requested information.
  6. +
  7. The API transfers the data to the initial application that requested the information.
  8. +
+

Why would you need an API?

+

Many companies have APIs built to allow others to build interesting applications using their company data. APIs also allows a project to be dynamic - it will update the frontend information automatically when the back end is updated. This saves the hassle of going through tons of HTML code updating data one by one.

+

Types of APIs

+

GraphQL vs Rest

+

Reading In favor of GraphQl:

+

https://www.howtographql.com/basics/1-graphql-is-the-better-rest/

+

Reading In favor of Rest:

+

https://www.rubrik.com/blog/technology/19/11/graphql-vs-rest-apis

+

Rest APIs

+

About

+

https://www.ibm.com/cloud/learn/rest-apis

+

A REST API is an API that conforms to the design principles of the REST, or representational state transfer architectural style. For this reason, REST APIs are sometimes referred to RESTful APIs.

+

What is a RESTful API? https://www.youtube.com/watch?v=y0U-ZxgLu98

+

Types of API calls

+

alt_text

+

Creating your own API

+

Interactive Resource on APIs

+

https://apiary.io/how-to-build-api#phase-design

+

Tons of help on creating API with different languages https://rapidapi.com/blog/20-tutorials-on-how-to-create-your-own-api-sorted-by-programming-language/

+

Explanations of API’s and more in depth language-specific resources

+

https://www.moesif.com/blog/api-guide/getting-started-with-apis/

+

Using Postman

+

What is Postman?

+

Postman is a platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs faster.

+

Getting Started with Postman: https://www.guru99.com/postman-tutorial.html#1

+

Good Postman Series starting with setting up: https://www.youtube.com/watch?v=juldrxDrSH0&ab_channel=AutomationStepbyStep

+

Further Resources on APIs

+

Collection of Free, premade API’s

+

Most premade API’s will have documentation of how to use/maintain them

+

https://github.com/public-apis/public-apis

+

https://any-api.com/

+

Example of using a premade API

+

https://rapidapi.com/blog/how-to-use-an-api/

+

GraphQL

+

Further Help

+

GraphQL Tutorial: https://www.youtube.com/watch?v=ed8SzALpx1Q&ab_channel=freeCodeCamp.org

+

What is GraphQL (A really good article): https://www.redhat.com/en/topics/api/what-is-graphql

+

Why use GraphQL: https://www.apollographql.com/docs/intro/benefits/

+

Getting started with GraphQL: https://www.apollographql.com/docs/intro/benefits/

+

GraphQL is split into two main parts, A Schema (Basically a model for the response), and a resolver (a collection of functions that generate response for a GraphQL query. In simple terms, a resolver acts as a GraphQL query handler)

+

An article that explains what a Query, Mutation & Subscription are: https://medium.com/software-insight/graphql-queries-mutations-and-subscriptions-286522b263d9

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/guides/Django_Guide/images/django-initial-page.png b/guides/Django_Guide/images/django-initial-page.png new file mode 100644 index 0000000..ac2c9bd Binary files /dev/null and b/guides/Django_Guide/images/django-initial-page.png differ diff --git a/guides/Django_Guide/images/image1.png b/guides/Django_Guide/images/image1.png new file mode 100644 index 0000000..c2dc3dd Binary files /dev/null and b/guides/Django_Guide/images/image1.png differ diff --git a/guides/Django_Guide/images/image10.png b/guides/Django_Guide/images/image10.png new file mode 100644 index 0000000..7e1259b Binary files /dev/null and b/guides/Django_Guide/images/image10.png differ diff --git a/guides/Django_Guide/images/image11.png b/guides/Django_Guide/images/image11.png new file mode 100644 index 0000000..06dbb24 Binary files /dev/null and b/guides/Django_Guide/images/image11.png differ diff --git a/guides/Django_Guide/images/image12.png b/guides/Django_Guide/images/image12.png new file mode 100644 index 0000000..49db837 Binary files /dev/null and b/guides/Django_Guide/images/image12.png differ diff --git a/guides/Django_Guide/images/image13.png b/guides/Django_Guide/images/image13.png new file mode 100644 index 0000000..9161cbb Binary files /dev/null and b/guides/Django_Guide/images/image13.png differ diff --git a/guides/Django_Guide/images/image14.png b/guides/Django_Guide/images/image14.png new file mode 100644 index 0000000..2c27cf4 Binary files /dev/null and b/guides/Django_Guide/images/image14.png differ diff --git a/guides/Django_Guide/images/image15.png b/guides/Django_Guide/images/image15.png new file mode 100644 index 0000000..12e2a36 Binary files /dev/null and b/guides/Django_Guide/images/image15.png differ diff --git a/guides/Django_Guide/images/image16.png b/guides/Django_Guide/images/image16.png new file mode 100644 index 0000000..160f9db Binary files /dev/null and b/guides/Django_Guide/images/image16.png differ diff --git a/guides/Django_Guide/images/image17.png b/guides/Django_Guide/images/image17.png new file mode 100644 index 0000000..568218d Binary files /dev/null and b/guides/Django_Guide/images/image17.png differ diff --git a/guides/Django_Guide/images/image18.png b/guides/Django_Guide/images/image18.png new file mode 100644 index 0000000..ad52aa4 Binary files /dev/null and b/guides/Django_Guide/images/image18.png differ diff --git a/guides/Django_Guide/images/image19.png b/guides/Django_Guide/images/image19.png new file mode 100644 index 0000000..edca256 Binary files /dev/null and b/guides/Django_Guide/images/image19.png differ diff --git a/guides/Django_Guide/images/image2.png b/guides/Django_Guide/images/image2.png new file mode 100644 index 0000000..a8b2956 Binary files /dev/null and b/guides/Django_Guide/images/image2.png differ diff --git a/guides/Django_Guide/images/image20.png b/guides/Django_Guide/images/image20.png new file mode 100644 index 0000000..1944723 Binary files /dev/null and b/guides/Django_Guide/images/image20.png differ diff --git a/guides/Django_Guide/images/image21.png b/guides/Django_Guide/images/image21.png new file mode 100644 index 0000000..c98ca33 Binary files /dev/null and b/guides/Django_Guide/images/image21.png differ diff --git a/guides/Django_Guide/images/image22.png b/guides/Django_Guide/images/image22.png new file mode 100644 index 0000000..c3587b1 Binary files /dev/null and b/guides/Django_Guide/images/image22.png differ diff --git a/guides/Django_Guide/images/image23.png b/guides/Django_Guide/images/image23.png new file mode 100644 index 0000000..cd9a988 Binary files /dev/null and b/guides/Django_Guide/images/image23.png differ diff --git a/guides/Django_Guide/images/image24.png b/guides/Django_Guide/images/image24.png new file mode 100644 index 0000000..1eed90b Binary files /dev/null and b/guides/Django_Guide/images/image24.png differ diff --git a/guides/Django_Guide/images/image25.png b/guides/Django_Guide/images/image25.png new file mode 100644 index 0000000..38bb54c Binary files /dev/null and b/guides/Django_Guide/images/image25.png differ diff --git a/guides/Django_Guide/images/image26.png b/guides/Django_Guide/images/image26.png new file mode 100644 index 0000000..8fa6fbc Binary files /dev/null and b/guides/Django_Guide/images/image26.png differ diff --git a/guides/Django_Guide/images/image3.png b/guides/Django_Guide/images/image3.png new file mode 100644 index 0000000..00bbd2d Binary files /dev/null and b/guides/Django_Guide/images/image3.png differ diff --git a/guides/Django_Guide/images/image4.png b/guides/Django_Guide/images/image4.png new file mode 100644 index 0000000..f1f1d0e Binary files /dev/null and b/guides/Django_Guide/images/image4.png differ diff --git a/guides/Django_Guide/images/image5.png b/guides/Django_Guide/images/image5.png new file mode 100644 index 0000000..34d45f4 Binary files /dev/null and b/guides/Django_Guide/images/image5.png differ diff --git a/guides/Django_Guide/images/image6.png b/guides/Django_Guide/images/image6.png new file mode 100644 index 0000000..df82768 Binary files /dev/null and b/guides/Django_Guide/images/image6.png differ diff --git a/guides/Django_Guide/images/image7.png b/guides/Django_Guide/images/image7.png new file mode 100644 index 0000000..21c6f71 Binary files /dev/null and b/guides/Django_Guide/images/image7.png differ diff --git a/guides/Django_Guide/images/image8.png b/guides/Django_Guide/images/image8.png new file mode 100644 index 0000000..1068a4c Binary files /dev/null and b/guides/Django_Guide/images/image8.png differ diff --git a/guides/Django_Guide/images/image9.png b/guides/Django_Guide/images/image9.png new file mode 100644 index 0000000..6539748 Binary files /dev/null and b/guides/Django_Guide/images/image9.png differ diff --git a/guides/Django_Guide/index.html b/guides/Django_Guide/index.html new file mode 100644 index 0000000..4c9839b --- /dev/null +++ b/guides/Django_Guide/index.html @@ -0,0 +1,910 @@ + + + + + + Django - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Tech Start's Django Guide

+

Django is a free and open source python framework that lets you build awesome backends for websites, apps, and more. You can use it to host databases and build secure APIs for them without writing a line of SQL. You can also use it to create multi-page applications with dynamically served content. It makes it easy to get started building complex functionalities by automating a lot of the boilerplate code that you'd normally have to write.

+

We recommend that you have a basic knowledge of python before using django! This will help you debug any errors that you get.

+

alt_text

+

(Img src: https://medium.com/crowdbotics/when-to-use-django-and-when-not-to-9f62f55f693b)

+

Table of Contents

+ +

Requirements

+

First you will need to install Homebrew, Python, Pip, and Pyenv. If you have not done so already, please follow the instructions in the Installfest section.

+

Setup

+

To create a Django project first wee need to create a directory for the project. To do so, run the following command:

+
mkdir <project-name>
+
+

Then, we need to navigate to the directory we just created. To do so, run the following command:

+
cd <project-name>
+
+

Now, we need to create a virtual environment for our project. To do so, run the following command:

+
pyenv virtualenv .venv
+
+

Then, we need to activate the virtual environment. You need to do this every time you want to run your project. To do so, run the following command:

+
source .venv/bin/activate
+
+

If you want to deactivate your virtual environment when you're done working on your project, run the following command:

+
deactivate
+
+

Now, we need to install Django. To do so, run the following command:

+
pip install django
+
+

To check if Django is installed, run the following command:

+
python3 -m django --version 
+
+

Next, let's create a project.

+
django-admin startproject <project-name> . # the dot is important! it will create the project in the current directory
+
+
Good to know: Projects vs. apps
+What's the difference between a django project and a django app? An app is a Web application that does something – e.g., a Weblog system, a database of public records or a small poll app. A project is a collection of configuration and apps for a particular website. A project can contain multiple apps. An app can be in multiple projects.
+
+
python3 manage.py startapp <your-app-name>
+
+

This creates an app within your project. You can create as many apps as you want within a project.

+

Next step: include your app in the INSTALLED_APPS fields in settings.py (just the name)

+
INSTALLED_APPS = [
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+
+    ...
+    'your-app-name',
+]
+
+

Installing Dotenv

+

Dotenv is a zero-dependency module that loads environment variables from a .env file into process.env. Storing configuration in the environment separate from code is based on The Twelve-Factor App methodology. To install dotenv, run the following command:

+
pip install python-dotenv
+
+

Then freeze the requirements. To do so, run the following command:

+
pip freeze > requirements.txt
+
+

This will create a file called requirements.txt that will contain all the packages that are installed in your virtual environment. This file will be useful for when you need to install the same packages in another virtual environment. After adding a new package to your virtual environment, you will need to freeze the requirements again.

+

Next, go to your project and create a .env file. To do so, run the following command:

+
touch .env
+
+

Then go to your settings.py file and add the following code:

+
from django.core.management.utils import get_random_secret_key
+from dotenv import load_dotenv
+
+...
+
+load_dotenv()
+
+# SECURITY WARNING: keep the secret key used in production secret!
+# Copy the secret key from the .env file
+SECRET_KEY = os.getenv("DJANGO_SECRET_KEY", get_random_secret_key())
+
+

Your .env file should look like this:

+
DJANGO_SECRET_KEY=your-secret-key
+
+

Installing Postgres and psycopg2

+

PostgreSQL is a powerful, open source object-relational database system with over 30 years of active development that has earned it a strong reputation for reliability, feature robustness, and performance. To install Postgres, run the following command:

+
brew install postgresql
+
+

To check if Postgres is installed, run the following command:

+
postgres --version
+
+

psycopg2 is a PostgreSQL database adapter for the Python programming language. To install psycopg2, run the following command:

+
pip install psycopg2
+
+

Then freeze the requirements. To do so, run the following command:

+
pip freeze > requirements.txt
+
+

Then go to your settings.py file and add the following code:

+
INSTALLED_APPS = [
+    ...
+    'psycopg2',
+]
+
+

Creating a Postgres database

+

To create a Postgres database, run the following command:

+
createdb <database-name>
+
+

Remember your credentials for the database. You will need them later.

+

It is also recommended to install pgAdmin, a free and open-source administration and development platform for PostgreSQL and its related database management systems. To install pgAdmin, run the following command:

+
brew install --cask pgadmin4
+
+

Connecting Django to Postgres

+

Add the following code to your .env file:

+
DATABASE_NAME=<database-name>
+DATABASE_USER=<database-user>
+DATABASE_PASSWORD=<database-password>
+
+

Now go to your settings.py file and add the following code:

+
import os
+
+...
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.postgresql',
+        'NAME': os.getenv('DATABASE_NAME'),
+        'USER': os.getenv('DATABASE_USER'),
+        'PASSWORD': os.getenv('DATABASE_PASSWORD'),
+        'HOST': "127.0.0.1",
+        'PORT': "5432",
+    }
+}
+
+

Writing Models

+

Models allow you to define the content of your database. If you don't need content in your database, you won't need models.

+

You can follow along with this section here:

+

https://docs.djangoproject.com/en/3.1/intro/tutorial02/

+

More about models: https://docs.djangoproject.com/en/3.1/topics/db/models/

+

You will define all your models in models.py, located within the folder for your app.

+
from django.db import models
+
+# Create your models here.
+class Album(models.Model):
+    name = models.CharField(max_length=200)
+    artist = models.CharField(max_length=100)
+    year_released = models.DateField()
+    def __str__(self):
+        return str(self.name)
+
+class Song(models.Model):
+    song_name = models.CharField(max_length=100)
+    album = models.ForeignKey(Album, on_delete=models.CASCADE)
+    num_streams = models.IntegerField()
+    def __str__(self):
+        return str(self.song_name)
+
+

Each model should correspond to the structure of a table of a relational model of a database. If you don't know what this means, ask someone who has taken CPSC 471 (or an equivalent databases course)

+

Django can convert these into real SQL tables!

+
    +
  • Good to know: Primary Keys: In the above example we didn't specify any ids for our models (normally, with databases, you want an id to be your primary key). Django automatically creates an ID field to be the primary key for each model and takes care of auto-incrementing, unless you specifically override it. I don't recommend overriding, it's not worth the effort (and its doubly complicated and not worth it to have a primary key composed of several fields)
  • +
  • Good to know: str: the str function is Python's default function for string representation. In this case, it's good practice to override this for your models. This will help you understand your data if you login via the admin view (I'll show how to do this later)
  • +
  • Good to know: Foreign Keys: See the Song model class for how you can reference a foreign key belonging to another model (in this case it refers to Album). You don't need to refer to a foreign model's keys directly, all you need to do is specify which table you are referencing. Also note: if you are referring to a table, it needs to be defined above the point in the code where you are referring to it.
  • +
+

There are more options that can be explored about how you can define your models, but this should be a good base for you to do your own research :)

+

Now we're ready to convert these into a real database! By default, Django will make a migration file that has your database.

+
Converting models into your database
+
+https://docs.djangoproject.com/en/3.1/intro/tutorial02/
+
+>> python3 manage.py makemigrations appName
+Creates migrations for the changes you made in appName
+
+>> python3 manage.py migrate
+Migrates the changes you made into your database
+
+
+

Run your app

+

Whenever you are ready to run your server, just call this command!

+
python3 manage.py runserver 
+
+

You should see something like this:

+

django-initial-page

+

By default, this will run the Django server on localhost:8000. View the django documentation to see how you can run it on a different port. You can now access it from your web browser by visiting http://localhost:8000 !

+

You can also create a superuser (admin) to view the inner contents of your database. To do this, you first need to create them from the command line using the following command:

+
python3 manage.py createsuperuser --username yourNameHere --email yours@email.ca
+
+

This will create a super user with your provided info (it will prompt you to enter a password as well).

+

The following command creates a token for the superuser that you can use for authentication in requests. If you are not using Django Rest Framework, this is not applicable to you.

+
python3 manage.py drf_create_token yourSuperUserName
+
+

Note: if you're trying to run these for your deployed app on heroku, you need to prepend heroku run before those commands! See the Heroku section for a description on how you can deploy it.

+

You can see the admin page of your website to view the inner content of your database. This is automatically created by Django. Visit http://localhost:8000/admin and enter your passcode.

+

If you want your models to show up in the admin page, you will need to specify them in admin.py like this:

+
from django.contrib import admin
+from .models import Album, Song
+# Register your models here.
+
+admin.site.register(Album)
+admin.site.register(Song)
+
+

Once you log in to the admin site, you should see something like this. From here, you can add & remove database entries. +alt_text

+

URLs

+

URLs allow you to define the paths that exist in your system, and what happens when you call them.

+

URLs documentation: https://docs.djangoproject.com/en/3.1/ref/urls/

+

How URLs are processed in Django: https://docs.djangoproject.com/en/3.1/topics/http/urls/#how-django-processes-a-request

+

Read more: https://docs.djangoproject.com/en/3.1/intro/tutorial03/

+

If you're constructing a big application, it's standard practice in django to include different _apps _for each part of your system, and link them to the main project.

+

alt_text

+

However, since we're only making small-scale side-projects, it's fine to ignore this best-practice and include everything in a single app. Just understand that in a large industrial scale project you wouldn't necessarily want to do this.

+

// urls.py in a project:

+
from django.contrib import admin
+from django.urls import path, include
+
+urlpatterns = [
+    path('admin/', admin.site.urls),
+    path('myApp/', include('myApp.urls'))
+]
+
+

// example urls.py in myApp folder:

+
from django.urls import path
+from . import views
+
+urlpatterns = [
+    path('hello_world', views.ping, name='Hello World!'),
+    path('hello-x/<str:hello_to>', views.hellox, name='Hello to x'),
+    path('hello-x/<print_me>/print', views.printx, name='Print this!'),
+    path('goodbye', views.goodbye, name='goodbye'),
+]
+
+

Now you can visit a path using http://localhost:8000/myApp/hello-world, for example.

+

Views

+

**Views **allow you to define what happens when you access a certain url in your system (using your browser, an API tool like Postman, or something else altogether). In your views, you could define interactions with the model (your database) or entirely different interactions altogether. You can use the definition of the view to call external processes.

+

If you want to make more complicated views and understand the Request and Response items, read this:

+

https://docs.djangoproject.com/en/3.1/ref/request-response/

+

To understand views more in-depth, read the documentation: https://docs.djangoproject.com/en/3.1/topics/http/views/

+

Here are some simple examples of what you can do with a view. Note that these are just examples and don't represent best practice at all.

+
from django.http import HttpResponse, response
+# views.py
+def ping(request):
+    myRes = "Hello World!"
+    return HttpResponse(myRes)
+
+def hellox(request, hello_to):
+    myRes = {"My Reply": "Hello " + hello_to}
+    return response.JsonResponse(myRes)
+
+def printx(request, print_me):
+    print("Hello to " + print_me)
+    return response.HttpResponseNotFound("I printed it!")
+
+def goodbye(request):
+    if not (request.method == 'GET'):
+        return response.HttpResponseBadRequest()
+    queryParams = request.GET
+    msg = queryParams.get('msg', "Gamers")
+    return response.JsonResponse({"Reply": "Goodbye " + msg})
+
+

Now, we want to adhere to DRY (Don't repeat yourself) when creating views. Therefore, it is almost always best to define your views as Class-Based views (CBVs) which handle more of the boiler plate code for you and help ensure your views follow standards.

+

Please read more about class-based views here: https://docs.djangoproject.com/en/3.1/topics/class-based-views/

+

Both the above docs and the docs for views also show how you can interact with your database items through a view. But, if you're building an API, I highly recommend using the tools in the following section: Django REST Framework.

+

Once you have defined your views and given them a corresponding url, you can test them out.

+
python3 manage.py runserver 
+
+

Run your server, and using either a web browser, or preferably an API testing tool like Postman (https://www.postman.com/) access the proper urls (ex. http://localhost:8000/myApp/hello_world) to see if they have the expected behavior.

+

Django REST Framework

+

Django REST Framework is an add-on to Django that makes it simple to develop REST-compliant APIs. There is great documentation here: https://www.django-rest-framework.org/ <--- FOLLOW INSTALL INSTRUCTIONS

+

What is a RESTful framework? Learn more here: https://restfulapi.net/

+

Django REST Framework provides you with tools to make class-based views to easily implement database CRUD (Create Read Update Destroy) operations, as well as define more complex operations.

+

Before we define any endpoints with Django REST Framework, let's make some serializers.

+

alt_text

+

Serializers

+

Django REST Framework uses serializers as a way to perform **translation **of your models from your python code and your database into data formats like JSON and XML that an API might use. Read more about them here:

+

https://www.django-rest-framework.org/api-guide/serializers/

+

We should define some basic serializers so that we can make API endpoints that interact with the content of our database models.

+
    +
  1. Create a new file called serializers.py inside the app you want to use serializers with.
  2. +
  3. Create your serializers. Give them a relevant name (though the exact syntax is not important)
  4. +
  5. List the fields that you want your serializer to translate. If you don't want it to translate a particular field, then don't include it.
  6. +
+

Here's an example, using the Song and Album models we defined earlier. Here's what's at the top of serializers.py:

+
from rest_framework import serializers
+from .models import *
+
+class SongSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = Song
+        fields = ("id", "song_name", "num_streams")
+
+class AlbumSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = Album
+        fields = ("name", "year_released", "artist", "id")
+
+

Make sure your fields match exactly the names that you used in your models.

+

You may be curious why I also included an id, when we didn't define one in our models- this is because Django auto generated an id for us in this models because we didn't specify a primary key. This id field always has the name id. It is often useful for our API, so we'll include it.

+

We can also create multiple serializers for the same models, if we wanted different behavior. For example, what if we wanted to include the album id of the song?

+
class SongSerializerWithAlbumId(serializers.ModelSerializer):
+    class Meta: 
+        model = Song
+        fields = ("id", "song_name", "num_streams", "album")
+
+

This would include the album's PK (in this case, it's id, but if the PK was different, it'd be something else).

+

What if we wanted to include the full album info when an api request was made to see the song? Here's another example serializer that we could make:

+
class SongSerializerFullAlbum(serializers.ModelSerializer):
+    myFullAlbumDesc = AlbumSerializer("album", read_only=True)
+    class Meta:
+        model = Song
+        fields = ("id", "song_name", "num_streams", "myFullAlbumDesc")
+
+

It's using our album serializer from earlier to serialize a field, which must (read only is an optional parameter that makes it so that it's only included in reading requests, not create/update/destroy.)

+

This was just an introduction to serializers. If you want to use more complex behaviors, you'll have to do the research on your own.

+

Django REST Framework: Class based Views

+
Pre-requisite to this section: understand URLS and views in vanilla Django, and read the serializers section
+
+

More reading: https://www.django-rest-framework.org/tutorial/3-class-based-views/

+

Video overview of similar topic: https://www.youtube.com/watch?v=akvFA5VMXJU

+

You can use Django's Class Based Views to quickly create views that can do CRUD (Create, Read, Update, Destroy) operations on your database.

+

In views.py:

+
from rest_framework.views import APIView
+from rest_framework import generics
+from rest_framework import status
+from .models import *
+from .serializers import *
+
+

Some class based views that we'll define. Right now these are just the generic create, read, update, destroy views. By defining these views with the classes, Django REST Framework takes care of the default behavior for us. It's that easy!

+
class SaveSong(generics.CreateAPIView):
+    queryset = Song.objects.all()
+    serializer_class = SongSerializerWithAlbumId
+
+class GetSongs(generics.ListAPIView):
+    queryset = Song.objects.all()
+    serializer_class = SongSerializer
+
+class DeleteSong(generics.DestroyAPIView):
+    queryset = Song.objects.all()
+    serializer_class = SongSerializer
+
+class UpdateSong(generics.RetrieveUpdateAPIView):
+    queryset = Song.objects.all()
+    serializer_class = SongSerializerWithAlbumId
+
+

Notice that we need to make the create and update serializers include the album ID- if we didn't then you couldn't create song objects since their album id must be _not null._This same principal applies to any model that has a foreign key which isn't allowed to be null.

+

Before we can use the views we created, we need to hook them up to a URL, just like you would for any other view. Do keep in mind that we need to call the as-view function on them, though. Here is an example of the URLs for the previous views. This pattern is how we normally define CRUD endpoint urls for any entity in a database

+
    path('song', views.GetSongs.as_view(), name='songs'),
+    # Create a song
+    path('song/create', views.SaveSong.as_view(), name='Save Song'),
+    #Updates a specified license with information
+    path('song/<int:pk>', views.UpdateSong.as_view(), name='Update Song'),
+    # Deletes a song specified by pk
+    path('song/<int:pk>/delete', views.DeleteSong.as_view(), name='Delete Song'),
+
+

If you are using a pk that is not an int (you manually defined a pk instead of using the default id generated), you'll have to specify that accordingly.

+

What if we want more complex behavior beyond the default predefined classes? We can modify them to add more conditions to what is returned.

+

In this example, we added an optional way to filter songs by album, using a query_param called album. You'll need to read documentation and tutorials if you want to know more about the custom behavior you can define within your Django REST Framework views.

+
class GetSongInAlbum(generics.ListAPIView):
+    serializer_class = SongSerializer
+    def get_queryset(self):
+        queryset = Song.objects.all()
+        alb = self.request.query_params.get('album', None)
+        queryset = queryset.filter(album=alb)
+        return queryset
+
+

If you have a view that isn't necessarily linked to CRUD actions, or has more complex usage and needs more custom defined behavior, you can use APIView.

+

Test out your Django REST API

+

Compile and run your app with

+
python3 manage.py runserver 
+
+

Use your bugfixing wizardry to fix any errors that might show up. Now you should be ready to give those predefined endpoints you made for a spin!

+

Here's some examples that I did using Postman for API testing. If you used Django REST Framework, it should also come with a built-in API testing tool that you can use in your browser.

+

Here's a simple GET request. This is a database read operation, and it's pretty simple. Your browser is making GET requests to every URL you visit while you surf the web.

+ + + + + + + + + +
Request + +alt_text +
Response + +alt_text +
+

Here's a POST request (it's post because we're _creating _or Posting new data) to our create route. We should include the key-value pairs for the song we want to create in the **_Body _**of our request.

+ + + + + + + + + +
Request + +alt_text +
Response + +alt_text +
+

To update, let's follow the URL pattern we defined with the pk of the song we want to update. We can use PUT or PATCH. The info you're sending should be in the _Body _of the request, just like it was for our POST request.

+ + + + + + + + + +
Request + +alt_text +
Response + +alt_text +
+

Let's do the same thing for our deleteSong view, but let's delete Taylor's song this time (pk: 2). I'm sure it was no good anyways.

+ + + + + + + + + +
Request + +alt_text +
Response + +alt_text +alt_text +
+

Let's use our GET view to see what's inside the DB now:

+

alt_text

+

alt_text

+

**unimportant note: in my zeal to delete taylor's song I had a mishap and accidentally deleted song 3, which I have readded here using a post request. but it's id is now 5 :[

+

Finally, let's try out that "song with album" route. We'll add it to our urls.py:

+
    # Probably not the best naming convention
+    path('songInAlbum', views.GetSongInAlbum.as_view(), name='Get song in album'),
+
+

alt_text

+

Here's what our request will look like. ^^^^^^^^

+

Here's the response:

+

alt_text

+
Good to know: Query Parameters
+Notice how our query params don't have to be specified in urls.py - they are dynamically generated from the URL that we try access (everything that comes after a ? in a url is a query parameter, with keys and values separated by '='. If you had multiple query parameters they would be separated by '&'. Next time you're browsing the web, notice how query parameters are used across the different websites you visit!
+It's easy to access query params within Django - see the getSongInAlbum view definition for an example.
+
+

Authtokens, users, logins with Django REST Framework

+

Up to now, we've covered the fundamentals of how to create a database, populate it, and create simple endpoints for creating, updating, and destroying. But what happens when we want our system to be used by real users? How do we store their information and their interactions with our system? There are a few important issues that we'll need to address:

+
    +
  • How do we make sure that users' personal information like their passcodes are being stored in a secure way that protects them from being stolen?
  • +
  • How do we build a system that users can sign up for and log in to? How do we store info about their session?
  • +
  • How do we make certain endpoints in our system behave differently depending on the user who is accessing them?
  • +
+

The answer to these questions can be complicated. In order to save your time and energy, we're going to utilize the resources that Django and Django REST Framework provide for us as much as possible instead of developing our own solutions. Not only is this easier, but it's also much more secure- would you trust a system written from scratch by a novice undergrad student with your password and financial information?

+

How do we store user's personal info?

+

The answer to this question is usually to use Django's built-in User model. You can read the docs on User models here:

+

https://docs.djangoproject.com/en/3.1/ref/contrib/auth/

+

The User model contains common fields that will be used by users, and in your serializers you can define which fields are relevant to your use case.

+

By default, Django builds the User models for you. You can see them after you runserver and check inside the /admin route.

+

We can also utilize the User model to build new endpoints in our API, just like we could with any other model. Here's an example:

+

Models.py

+
from django.contrib.auth.models import User
+
+

+
class UserLikesSong(models.Model):
+    user = models.ForeignKey(User, on_delete=models.CASCADE)
+    song = models.ForeignKey(Song, on_delete=models.CASCADE)
+
+

Serializers.py

+
class UserLikesSongSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = UserLikesSong
+        fields = ("id", "user", "song")
+        #Id of the rel, Id of the user, ID of the song
+
+

You can now make endpoints with this just like you would with any other model/serializer. This specific example could be used to track what songs the User likes, like in Spotify.

+

If you wanted to make a custom User model, you could read more about it here https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html and do more research, as there are many methods you could use. For basic university usage though, it's 99% of the time going to be faster and easier to roll with the User model they give you out of the box.

+

If you want to give different categories of users different permissions, see the_ permissions _section (TODO: this won't be done for a while. In the meantime, these links may help: https://www.django-rest-framework.org/api-guide/permissions/ ← Technical overview

+

https://www.django-rest-framework.org/tutorial/4-authentication-and-permissions/ ← Basic usage example)

+

Signup, Login, Sessions: How do we do them?

+

I highly recommend using Django REST Framework's Authtokens to handle information about user sessions. You can read about authtokens, as well as the other options available, here: https://www.django-rest-framework.org/api-guide/authentication/#tokenauthentication

+

To add Authtoken's, make sure the following items appear in settings.py:

+
###### You will need to add the REST Framework part.
+###### INSTALLED_APPS should already exist.
+
+REST_FRAMEWORK = {
+    'DEFAULT_AUTHENTICATION_CLASSES': [
+        'rest_framework.authentication.TokenAuthentication',  
+    ],
+}
+
+INSTALLED_APPS = [ # There will be more here
+  'rest_framework',
+  'rest_framework.authtoken',
+]
+
+
+
+

Note: I couldn't get these to work, at least not with authtoken. Leaving them here in case some enterprising individual finds them useful, or message us on Discord if you figure this out :)

+

To get REST Framework's default login and logout views (prebuilt), type this in your project's root urls.py file:

+
 urlpatterns = [
+    ...
+    path('api-auth/', include('rest_framework.urls'))
+]
+
+

Your path doesn't have to be api-auth, it can be whatever you want.

+

To use REST Framework's login view, include this in urls.py:

+
    path('whateverPathYouWantToLogin', obtain_auth_token, name='API Token Login'),
+
+

Include this at top of your urls.py:

+
from rest_framework.authtoken.views import obtain_auth_token
+
+

When you access this path and provide a real username and password in the request body, then you should receive an authtoken. This authtoken is associated with your account. Store this authtoken in a safe place. Now, you can use it in the "authorization" section of your next HTTP requests, and all requests you make from the client will be associated with the account you just logged in from.

+

Creating views for signing up is more difficult.

+ + + + + + + + + + + + + +
In serializers.py: +

+from django.contrib.auth.models import User +

+class RegisterSerializer(serializers.ModelSerializer): +

+ class Meta: +

+ model = User +

+ fields = ('id','username','password')#Change fields if u want +

+ extra_kwargs = { +

+ 'password':{'write_only': True}, +

+ } +

+ def create(self, validated_data): +

+ user = User.objects.create_user(validated_data['username'], password = validated_data['password']) +

+ return user +

+This serializer will make sure that the password that the user makes is valid, and that it's write-only for security purposes. Choose which fields us +

In views.py: +

+from django.contrib.auth import get_user_model # If used custom user model +

+from rest_framework import permissions #We'll discuss more about perms later +

+… +

+class RegisterUserView(generics.CreateAPIView): +

+ model = get_user_model() #Will get the right one if you use custom +

+ permission_classes = [ +

+ permissions.AllowAny # Or anon users can't register +

+ ] +

+ serializer_class = RegisterSerializer #What we defined above +

In urls.py: +

+ path('register', views.CreateUserView.as_view(), name='Register user'), +

+(you may want to put your register / login views together in a different Django App (so they are in a distinct section of your API) +

Test Request in Postman: +

+alt_text +

+Response from request: +

+alt_text +

+

Now let's quickly do a login from this user we just created!

+

I did a login request to the login view I made earlier, but here's what I got:

+

alt_text

+

Whenever you see an error like "no such table", that should be a clue that you need to rerun migrations. The app expected there to be a SQL table, but there was none made yet! Running migrations will ensure there is. Recall the commands for migrations are:

+
+
+

python3 manage.py makemigrations yourAppName

+
+
+
+
+

python3 manage.py migrate

+
+
+

In this case, just the second command will be sufficient

+

Request:

+

alt_text

+

Response:

+

alt_text

+

Yay! It worked! Now we can include this token in our request headers to associate all future requests made with the user we logged in.

+

In future requests, you should put the token as a value in your request headers, using the key: token.

+

alt_text

+


+Depending on the front-end you build, you should use a different way to store the authtoken that you get from logging in. Usually storing in local memory is okay. Do your own research for how to store authtokens with whatever system you are using.

+

If you want to improve security further, you can use JWT (JSON webtoken) instead, following the instructions here: https://simpleisbetterthancomplex.com/tutorial/2018/12/19/how-to-use-jwt-authentication-with-django-rest-framework.html

+

How do we make endpoints behave differently depending on which user is accessing them?

+

If a user makes a request while they are authenticated (using authtoken, or some other alternative method), then the system will automatically know what user is associated with the user who made the request.

+

You can access the user within a class-based view through

+
 self.request.user
+
+

You can use this within your views in a variety of ways: to filter, to make more complex queries, and to check if the user should have access.

+

For example, let's make a UserLikesSong endpoint that is limited to the songs that the currently logged in user has liked.

+
class GetUserLikesSongs(generics.ListAPIView):
+    def get_queryset(self):
+        queryset = UserLikesSong.objects.all()
+        queryset = queryset.filter(user=self.request.user)
+	# Leftside of filter: from queryset. Rightside: how we're filtering
+        return queryset
+    serializer_class = UserLikesSongSerializer
+
+

We'll cover this in much more detail in the Permissions section.

+

Permissions

+
NOTE: Everything past here is incomplete - you will need to supplement it with your own research, like I did to make this guide!
+
+

To use generic permissions with Django, all you need to do is:

+
    +
  • In your views.py:
  • +
+
from rest_framework.permissions import IsAdminUser, IsAuthenticated, IsAuthenticatedOrReadOnly
+
+

Now, on any class-based view you want to guard with permissions, you can add the following line:

+
class deleteLicenseType(generics.DestroyAPIView):
+    permission_classes = [IsAdminUser]
+    queryset = License_Type.objects.all()
+    serializer_class = License_TypeSerializer
+
+

(this is from a different project)

+

You can apply multiple permissions to the same view like this:

+
    permission_classes = [IsAdminUser|IsAuthenticatedOrReadOnly]
+
+

Sessions & Cookies

+

Sessions/cookies are very easy to make use of with Django. You can use cookies to store information in a user's browser that you'll be able to access in all subsequent requests that a user makes. One example of a good use of sessions/cookies is to store a user's shopping cart content.

+

Some great videos for learning about sessions & cookies:

+

https://www.youtube.com/watch?v=C75IW38hKI8

+

https://www.youtube.com/watch?v=RjykNmVdcgI

+

alt_text

+

Deploy to Heroku

+

alt_text

+

To get your projects online, you can deploy them to Heroku. Heroku is just one of several possible hosting services for Django- but it's base tier is free, easy to use, and simple to deploy to, so that's what I recommend you use. The biggest downside of using Heroku is that its free tier will automatically shut down your app after a period of downtime, meaning it'll take a long time to respond the next time you try to access it.

+

A guide on getting started:

+

https://devcenter.heroku.com/articles/django-app-configuration

+

Some useful commands:

+
+
+

pip install gunicorn

+
+
+

To deploy to Heroku, you will need to make a file called Procfile (no file ending), and add the following gunicorn text to it:

+
web: gunicorn yourAppName.wsgi
+
+

This gunicorn file should be at the same level as your manage.py file. When you deploy to Heroku, you should be deploying from this level of the project hierarchy to avoid issues.

+

Your remote heroku environment needs to understand what requirements it will need to have to start up. You can do this by providing it with a requirements.txt file which will also be at the same level as your manage.py file.

+

To get the right requirements in a .txt file, type

+
+
+

pip freeze > requirements.txt

+
+
+

These commands will help initialize your heroku repository:

+
+
+

heroku create

+
+
+
+
+

heroku run python3 manage.py migrate

+
+
+
+
+

heroku run python3 manage.py createsuperuser

+
+
+

Important: Your database itself will not transfer to Heroku. You will need to recreate all entities, config, and users.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/guides/Git_Guide/images/branchDiagram.png b/guides/Git_Guide/images/branchDiagram.png new file mode 100644 index 0000000..77f55b7 Binary files /dev/null and b/guides/Git_Guide/images/branchDiagram.png differ diff --git a/guides/Git_Guide/images/image1.png b/guides/Git_Guide/images/image1.png new file mode 100644 index 0000000..c9af8a3 Binary files /dev/null and b/guides/Git_Guide/images/image1.png differ diff --git a/guides/Git_Guide/images/image2.png b/guides/Git_Guide/images/image2.png new file mode 100644 index 0000000..aebf63e Binary files /dev/null and b/guides/Git_Guide/images/image2.png differ diff --git a/guides/Git_Guide/images/image3.png b/guides/Git_Guide/images/image3.png new file mode 100644 index 0000000..513f896 Binary files /dev/null and b/guides/Git_Guide/images/image3.png differ diff --git a/guides/Git_Guide/images/image4.png b/guides/Git_Guide/images/image4.png new file mode 100644 index 0000000..b603657 Binary files /dev/null and b/guides/Git_Guide/images/image4.png differ diff --git a/guides/Git_Guide/images/image5.png b/guides/Git_Guide/images/image5.png new file mode 100644 index 0000000..7addde0 Binary files /dev/null and b/guides/Git_Guide/images/image5.png differ diff --git a/guides/Git_Guide/index.html b/guides/Git_Guide/index.html new file mode 100644 index 0000000..5353cc0 --- /dev/null +++ b/guides/Git_Guide/index.html @@ -0,0 +1,715 @@ + + + + + + Git - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Tech Start's Git Guide

+

alt_text

+

Contents

+ +

Note

+

Unless otherwise stated, all git commands are one line terminal commands

+

We are also assuming that you have set up a project at /path/to/project and had cd'ed to /path/to/project

+

Getting Started - Setting up a Repository

+

GitHub: Create a Repository

+

A Git Repository is virtual storage of your code, allowing you to save versions of your code, as well as share and allow others to edit the code.

+

Initializing a new repository: git init

+
    +
  • This step is typically used by the project manager, or the owner of the project
  • +
+

Cloning an existing repository: git clone [GitHub git link]

+

E.g. git clone https://github.com/techstartucalgary/tsu-website.git

+
    +
  • This step is typically used by the project members, or anyones who wants to add onto the projects after it has already been created
  • +
  • The GitHub git link can be located on the GitHub repository website under the <> Code dropdown
  • +
+

Git Analogy

+

Imagine that we have two people working on the same paper remotely, Person A and Person B. Person B is the laziest of the two, so Person A starts the paper.

+

Person A choses to create a word document on their local machine. This can be seen as Initializing a new repository.

+

After working on the paper for a bit, they realize that Person B also needs to contribute, so they send the paper by email to Person B. This step is equivalent to forking a repository.

+

Person B decides that they would prefer to work on the paper by hand, and so they takes the email that Person A sent, and prints it to work on, cloning the repository

+

GUI vs Command Line?

+

There are a number of great GUI (graphical user interface) tools that simplify the process of +using Git, like GitHub Desktop, GitKraken, and the built-in Source Control tab in VSCode. +There's nothing wrong with using these tools, but we like to encourage our members to use the +command line in order to get a better understanding of what exactly you're doing. It's also universal, +so whatever you learn here can be used in any organization that uses Git!

+

Staging Files & Creating Commits

+

Git works using units of change called commits. These commits are essentially snapshots of your project. To share any changes, additions, and deletions that you make with other people and upload it to the internet, you will need to package them into a commit first.

+

You can think of the staging area of git (the green box that says "staged changes" in the below diagram) like a box. You can add and remove changes from the box on a per-file basis.

+

Committing is like sealing that box and sticking a label on it. The contents of that box are your changes. But, if there are changes in the untracked or unstaged areas, they will not be included in the commit, because they are outside of the box.

+

The following diagram shows how the staging process works, and what commands you can use to move changes (again, per-file basis) between areas. Use the git status command to see a summary of where every change in your project is on this diagram! We recommend using git status frequently.

+

image

+

Common Commands

+

Here are some common commands for using Git to store and prepare the code to be pushed to the remote repository. +They are shown in the general order that you want to use them in.

+

Below is the legend for some common, optional parameters which are shown

+
    +
  • (-text) = optional parameters for command, which are called as is (git command -text)
  • +
  • <helloWorld> = optional parameters for command, which are called with your version of the name (git command helloWorld)
  • +
  • For example: For git add [path], you should replace [path] with path/to/your/file, so the final command is git add path/to/your/file
  • +
+

git status

+

Shows the status of all changes (all staged or unstaged changes, not committed changes). It shows where every change is on the diagram above, and even lists some helpful commands.

+

It will also say what branch you are on, and if you are ahead or behind the remote version of your branch in terms of commits (more on this in later sections).

+

Additionally, if you have a merge conflict, it will show which files caused it.

+

git add [path/to/file]

+
+

git add app/pages/HomePage.tsx

+
+

Selects the specified files, moves it to the “staging area” to be included in the next commit.

+

This command will also allow adding a deleted file to be staged, which after being committed and pushed will remove the file from the git branch.

+

This command will ignore all files in the “.gitignore” file.

+
    +
  • [path/to/file] File path expression. Any files which match the expression are acted upon by git add +
      +
    • You can use git add -p to add parts of a changed file if needed.
    • +
    • Pro tip: You can use git add -A to add all changed files! Read about why you shouldn't always do this.
    • +
    +
  • +
+

git commit -m "[commitMessage]"

+
+

git commit -m "Updated homepage text"

+
+

Creates a new commit that includes all changes that you added to the staging area.

+

You always need to include a commit message (-m) for your commit . It is helpful to be as descriptive as possible!

+

If you don't use the -m flag and provide a commit message in quotations, Git will make you write a commit message using a text editor. However, this can be very confusing since your default Git text editor is often configured to be VIM (stuck in VIM? type :qa to exit). For this reason, we recommend always specifying the commit message using -m.

+

After you commit, these changes are no longer in the staging area - they are in your commit!

+
    +
  • +

    (-m) means you will be specifying a commit message in quotations

    +
  • +
  • +

    "[commitMessage]" the message that will be attached to the commit. Only usable if -m is used, otherwise a text editor will appear for the commit message.

    +
  • +
  • +

    Tip: always wrap your message in double quotes ("). This lets you use abbrevations in your message (... -m "Reverted Ben's Changes")

    +
  • +
+

git restore [path/to/file]

+
+

git restore app/pages/HomePage.tsx

+
+

Discards local changes in a file, thereby restoring its last committed state.

+

Think of it like a super-undo, allowing you to quickly get rid of accidental or unnecessary changes, restoring your files to how they used to be before you changed them.

+

It won't work if your file is already staged - you'll have to unstage it with git restore --staged [path/to/file] first.

+

git restore --staged [path/to/file]

+
+

git restore --staged app/pages/HomePage.tsx

+
+

Removes the file from the Staging Area, but preserve all modifications you made to it. +You can use it if you accidentally added a file to the staging area whose changes shouldn't be included as part of the next commit you are planning to make. +If the file was originally untracked, it becomes untracked again. If it was originally a file with unstaged changes, the changes become unstaged again.

+

Naming commits

+

When you create a commit, you always want to include a descriptive name for the commit that describes exactly what it accomplishes. You wouldn’t label a moving box with kitchen items as simply “stuff”. +Remember that other people will see these commit names, so make it easy for them to understand!

+

For a video tutorial on staging files, watch this

+

If you want to learn about additional flags and commands you can use in the process of staging files and adding commits, see the section Advanced Staging & Commits

+

Branches

+

Branches represent an independent copy of the code that has branched off the main code at a certain time. +They allow new features to be worked on, while ensuring that a working version of the code is not tampered with. +This allows large changes to be made to the code base, with little fear of breaking your projects.

+

git branch

+

Lists all branches in the current repository

+

git branch [branchName]

+
+

git branch ben/updateFont

+
+

Creates a branch called branchName in the current repository.

+

The created branch's commit history will match the branch you were on when you called git branch.

+

We recommend naming branches according to what you want your branch to do, prefixed by your name. +For example, if I was updating the font on a website, I might call my branch ben/updateFont. +Since branch names include whitespace, we recommend using camelCase to name them, but check with your PM +how they want to handle this.

+

git branch -d [branchName]

+
+

git branch -d ben/updateFont

+
+

Deletes the branch called branchName

+

Note: you cannot delete the branch you are one! git checkout to another branch first.

+

(You can use -D instead of -d to force delete the specified branch, even is it has unmerged changes. +It's typically better to use -d, unless you are 100% sure you will never need the branch you are deleting again)

+

git checkout [branchName]

+

Navigates your current directory to the specified branch, allows you to select which line of development you are working on.

+

You can only switch branches if you have no unstaged/staged changes in your current branch. If you can't switch branches because of this, see What happens if you can't checkout? for more instructions.

+

Pro tip: You can use git checkout -b [branchName] to create a branch and switch to it immediately.

+

How to use branches

+

Some rules (more like guidelines):

+
    +
  • Every single time you start modifying the code you should create a new branch to use
  • +
  • Branches should generally only be for one feature
  • +
  • Always branch off main
  • +
+

Before you make your branch, you should make sure you are creating your branch based on the most recent code. Do git checkout main to switch to the primary branch of your repository. You should also do git pull to make sure the primary branch is up to date with the version present on your remote repository (more on this in the next section).

+

Now that you are on the primary branch, use git branch [branchName] to create a new branch based on the current one. Make sure you name it according to what you aim to accomplish there (see the description of the command above).

+

Now that you have created your branch, you'll want to switch to it. Use git checkout [branchName] to switch to your branch. You can do work here and follow the instructions in the staging files and creating commits section to save your changes into commits.

+

Eventually, you'll be done using the branch (perhaps you will follow the instructions in the next few sections to push it to your remote repository and use it in a pull request. or perhaps you need to work somewhere else). Either way, you can switch to a different branch with git checkout [branchName]

+

If you have completed a pull request for your branch to merge it into a different branch of your project, you no longer need to keep the local copy of your branch. We recommend you use git branch -d to delete any branches you will no longer need to use. This makes sure your local repository remains nice and tidy.

+

Here's a quick summary of the commands:

+
git checkout main
+git pull
+git branch ben/updateFont
+git checkout ben/updateFont
+... doing stuff ...
+git checkout main
+git branch -d ben/updateFont
+
+

Git Branch Diagram

+

What happens if you can't checkout?

+

Git will not let you checkout to switch branches if you have staged or unstaged changes.

+

You will have a few choices on what to do:

+
    +
  • Restore files to how they originally were (either by manually undoing, or ideally making use of git restore, described in the previous section). Do this if any of your changes are unnecessary or accidental.
  • +
  • Create a commit, following instructions from the previous section. Only create a commit if you actually want to save the changes you made. +
      +
    • We recommend you avoid making commits on any branches that you share with other people, especially your primary branch (main)! All Tech Start repositories actually prohibit commits to main to prevent this.
    • +
    +
  • +
  • Utilize git stash to move changes from one branch to another without needing to commit them. Do this if your changes are intentional, but you wanted them on a different branch than the one you are currently on. This is described in more detail here.
  • +
+

You can combine these approaches to deal with your changes as necessary.

+

Remote Repositories

+

When you work with Git, you will typically have a local repository (the copy of your project that exists on your personal device) and a remote repository (the copy of your project that exists on the internet, usually on a service like GitHub, GitLab or BitBucket)

+

An absolutely core part of using Git is managing the interactions between your local repository and the associated remote repository. The two key commands you will need to learn are git push (which you can use to push commits from your local repository to the remote repository) +and git pull (which you can use to pull commits from the remote repository and insert them into your own local repository).

+

A common mistake that newcomers to Git will make is assuming that the local repository is the same as the remote repository - when they're actually 2 separate concepts. Your commits won't appear on the remote repository until you manually push them there. If someone else pushes new changes to the remote repository, you won't see their changes on your local repository until you manually pull those changes to your device.

+

Most version control related work happens in a local repository(staging, committing, viewing status, etc.). +Remote repositories come into play when you start working with others on the same project. +You can think of it as a cloud file server that you use to collaborate with others.

+

Remotes

+
+ + + +
LocalRemote
Are located on the computers of the team membersAre on the internet or a local network
Contains branches, commits, tagsContains branches, commits, tags
All “coding work” happens only in the local repository, and needs to be made and committed locally.After the work has been committed locally, it can be “uploaded” to the remote repository in order to share with others.
+
+

Note: You can name a local branch the same name as the remote branch, but they are NOT the same

+

Note: You can also have multiple remote repositories (default is origin), though you probably won't need this, +since each local repository stores what it's remote is.

+

git fetch is what you do when you want to see what everybody else has been working on. It doesn’t force you to actually merge the changes into your repository. This makes fetching a safe way to review commits before integrating them with your local repository.

+

You might be wondering how to set a remote, and the good news is that if you cloned your repository from GitHub, +it's been set for you, so no need to worry! +If you need to change the remote for some reason, you can do git remote set-url origin <url>

+

Intro to Remote Repositories

+

git pull [remoteName] [branchName]

+

git pull origin ben/updateFont

+

Pulls all changes/commits from the specified remote branch, and inserts them into your current branch.

+

Pro tip: Use git pull without any other options to update the branch you're on. You'll most likely only use this to update main.

+

More technical description: fetches from the remote branch (git fetch), and merges your current branch with commits from the remote (git merge)

+
    +
  • [remoteName] [branchName] pulls from a specific branch, which you specify
  • +
+

git pull origin main

+

Fetches commits from the master branch of the origin remote (into the local origin/master branch), and then it merges origin/master into the branch you currently have selected

+

git push

+

Updates the remote branch with your staged, local commits

+

Always pull before pushing to a branch to avoid unwanted merge conflicts and errors..

+

Merge Conflicts

+

Conflicts generally arise when two people have changed the same lines in a file, or if one developer deleted a file while another developer was modifying it. In these cases, Git doesn't know which change is correct. Git will mark the file as being conflicted and halt the merging process. It is then the developers' responsibility to resolve the conflict.

+

Although they look scary, resolving merge conflicts is a completely normal part of working collaboratively.

+

The general steps for resolving merge conflicts can be seen as:

+
    +
  1. Figure out the conflicts and change them accordingly
  2. +
  3. Re-commit the changes
  4. +
  5. Attempt to merge with the selected branches
  6. +
  7. Read error messages (if any) and repeat if necessary
  8. +
+

Some useful commands for attempting to fix merge conflicts

+
+ + + + +
CommandDescription
git statusHelp identify conflicted files
git log --mergeProduces a log with a list of commits that conflict between the merging branches
git diffFinds the differences between the states of a repository, which helps in preventing conflicts
git reset --mixedUndo changes to the working directory and staging area
+
+

Example of Merge Conflicts shown in Command Line

+

alt_text

+

In this case, there are two instances of the file “merge.text” that were modified by different branches/people. Git is unable to determine which lines to keep, as both were changed manually.

+

Resolving Merge Conflicts

+
    +
  1. Identify Conflicted Files
  2. +
+

Git will notify you if there are any merge conflicts after running git status. You can identify these conflicts by looking at your project files. Conflicted files will have markers like <<<<<<< HEAD, =======, and >>>>>>> [branch name] where the conflicting changes are.

+
    +
  1. Open the Conflicted File
  2. +
+

Use a text editor or an integrated development environment (IDE) like VS Code to open the conflicted file. Inside, you will see the conflicting sections clearly marked by symbols.

+
    +
  1. Resolve Conflicts
  2. +
+

Review the conflicting sections and decide which changes to keep. You can choose to keep your changes, the incoming changes from the other branch, or a combination of both. Make your edits, then remove the conflict markers (<<<, ===, >>>).

+
 <<<<<<< HEAD
+// Your changes
+=======
+// Incoming changes
+>>>>>>> [branch name]
+
+
    +
  1. Save the File
  2. +
+

Once you've resolved the conflict, save the file.

+
    +
  1. Add the Resolved File
  2. +
+

Use git add command to stage the resolved file.

+
    +
  1. Continue the Merge
  2. +
+

After resolving all conflicts, use git commit to finalize the merge.

+

git commit -m "Resolved merge conflicts"

+
    +
  1. Push Your Changes
  2. +
+

git push your changes to the remote repository.

+
+

Merge conflicts can be complicated to resolve, so make sure you communicate with the person who created +the branch you have a conflict with to ensure you don't lose their work.

+

Remember that Incoming changes are from the other branch, while Current changes are from your branch.

+

It also doesn't hurt to use a tool that's purpose-built to resolve merge conflicts. +VS Code has one built in, but there are a number of free options available online.

+

Using GitHub

+

GitHub is a company that provides a service of hosting Git repositories online. There are many other alternative companies that provide a similar service, like BitBucket, GitLab, and Azure DevOps, but GitHub is the most popular one and the one our project teams use.

+

The instructions for the rest of this section will focus on GitHub's features. However, almost every feature described here has equivalents in the other git hosts, so if you know how to use one you generally know how to use them all.

+

Pull requests

+

Video intro to pull requests

+

A pull request is a way of merging code from one branch of your remote repository into another.

+

alt_text

+

You are requesting that the base branch pulls the commits from the compare branch. +In the above example, you are requesting that the main branch pulls the commits from the addLaunchEvent. +In other words, you are taking the changes from compare and putting them into base.

+

You will use pull requests extensively as part of your Git workflow.

+

We encourage teams to use small, frequent, single-feature PRs. Ideally each PR should be associated with only one branch, and each branch to only one PR. Each PR should have a name that describes exactly what the PR accomplishes. By doing smaller PRs, you will make sure everyone frequently updates their codebase so you don't end up with massive merge conflicts. By limiting your PR to a single feature, you also make it super easy to roll back that feature and reverse all commits in the PR by reverting the PR itself.

+

Advantages of pull requests:

+
    +
  • They enable your team to do pull request reviews (see more below)
  • +
  • Your team can set up custom tests / deployments using CI/CD methods to ensure that your code runs as expected before you merge it
  • +
  • It enables you to double check what code you are adding
  • +
  • If you ever need to undo a pull request, it's very easy. Most git hosts have an easy way of reverting a pull request- usually it will create a new branch and PR itself, from which you can solve any merge conflicts and quickly roll back the code added from a previous PR.
  • +
  • If you stick to coding 1 feature per pull request, it makes it very easy to understand the history of your repository
  • +
+

Sometimes, when you create a pull request, it will say there is a merge conflict. If this happens, don't force the PR to merge! Instead, you'll want to resolve the merge conflict.

+

Steps:

+
    +
  1. On your local machine, checkout to the "compare" branch - git checkout addLaunchEvent
  2. +
  3. Once you are on the compare branch, do a git pull from the base branch of your PR - git pull origin main
  4. +
  5. This will pull changes from the base into your compare branch. Git will notify you that this caused a merged conflict. This is okay!
  6. +
  7. Resolve the merge conflict according to the instructions in the Merge Conflicts section. You'll need to add and commit the files where you solved the merge conflict.
  8. +
  9. Confirm you have resolved every merge conflict. Try running/building your app again to make sure everything works as expected.
  10. +
  11. Push the commit(s) that solved the merge conflict to your remote compare branch git push origin addLaunchEvent
  12. +
  13. The pull request should now update saying there is no merge conflict! You can merge it now, as long as your team approves of it.
  14. +
+

Additional readings on pull requests:

+

GitHub Docs

+

https://product.hubspot.com/blog/git-and-github-tutorial-for-beginners

+

https://yangsu.github.io/pull-request-tutorial/

+

Pull Request Reviews

+

One of the main advantages of pull requests is that they enable you to do a pull request review, ensuring that code that gets pulled into your primary branches has been reviewed by your team to make sure it won't introduce code smells or bugs.

+

PRs provide the opportunity to review another developer's code and make sure that it meets the guidelines or practices that your organization or team has. For example, if you have a developer who is more familiar with the architecture of the software system, they can provide valuable input towards making sure that your changes fit within the long term architectural vision of the system. +Alternatively, you can have a newer team member who is not yet familiar with the overall code structure and they can add comments to specific parts of the code in a PR to ask for further clarification for why a certain change was made.

+

Aside from learning, PRs generally serve as a major communication channel for developers in industry, because they provide the opportunity for automated testing and improvements before your code changes are moved to the next deployment stages. One example of automated testing is using linter which is a static code analysis tool used to flag errors in your code such as bugs, stylistics errors, and suspicious constructs, like for example declaring a variable twice.

+

Whenever someone wants to merge a pull request, you should require them to get their PR reviewed first. To review a pull request, look at all the changes they made.

+

Best Practices for PR Contributors:

+
    +
  • Review your own PR before adding reviewers. +
      +
    • You may find some work-in-progress or experimental code. There could also be a typo, unintended indentation, or extra line breaks.
    • +
    +
  • +
  • Link your PR to your issue.
  • +
  • Include a brief description of your changes.
  • +
  • Push small incremental commits to your PR. +
      +
    • You can also mark your PR as a DRAFT PR in GitHub. This pre-commit review can be good practice to check with reviewers if you are going in the right direction before making any more code changes.
    • +
    +
  • +
  • Add additional comments to your PR to guide reviewers through the review. +
      +
    • Highlight areas reviewers should focus on.
    • +
    • Clarify changes with comments and additional references.
    • +
    • Favor adding code comments over PR comments as the code comments will out survive the PR comments.
    • +
    +
  • +
+

Best Practices for Reviewers

+
    +
  • Be fast, not furious +
      +
    • Responsiveness and turnaround time are very important to keep PRs healthy and not go stale due to other changes which may have been merged during the time that the PR is open and may even introduce new merge conflicts.
    • +
    • Either as a reviewer or as an author, you should keep the conversation actively going until the issue is resolved.
    • +
    • As a rule of thumb, if the PR is small or trivial, you should review it within one business day.
    • +
    • Plus, context switching is very expensive in industry. Many developers, like myself, have the memory of a goldfish when it comes to remembering the code we wrote a day ago. So, as a courtesy, you can let the developer who opened the PR know if you are planning on looking at their PR at a later time. If there are PRs open, it is also good practice to review them before you create a new one yourself.
    • +
    +
  • +
  • If there are outstanding comments or the PR is in draft mode, do not approve the PR. +
      +
    • Instead, stay involved and follow the discussions and new changes to see how the PR pans out.
    • +
    +
  • +
  • Do NOT rubber stamp reviews. +
      +
    • If you do not understand a change, you can ask for clarification or justification in the comments.
    • +
    • You do not have to approve a PR if you are not actually approving the change. You can let the author know that you have completed your review but are not weighing in on the approval.
    • +
    • Our TechStart website team's default PR policy requires approvals from 2 different reviewers, but an approval that is rubber stamped can be more harmful than abstaining if it promotes bad practices and bugs to be user-facing.
    • +
    +
  • +
  • Provide constructive comments +
      +
    • Code reviews are an important step in ensuring we build high-quality software products. As a reviewer, it's your job to carefully read and think about the code you are reviewing, and provide constructive feedback or ask questions about the code if things are unclear.
    • +
    • If the code isn't formatted correctly, too confusing, contains mistakes, or follows poor conventions, leave a comment to tell them what they did wrong and how they might be able to fix it (but phrase everything constructively! you don't want to seem rude or aggressive).
    • +
    • If you disagree with something, give a reason and an example of a better solution. Let the author know exactly what you think is better.
    • +
    +
  • +
+

GitHub and other Git hosts support adding inline comments, so you can comment on specific areas of the code when necessary. The best place to do this is the "Files Changed" tab of a pull request.

+

It is up to them to address every issue that is brought up, and push the changes back to their branch. They should let you know when they've completed everything, and you can check to make sure you're happy with their changes.

+ +

Let's assume you have some commits on branch yourLocalBranch, and you want to merge them into a branch on your team's GitHub (which uses the default remote alias, origin) called branchYouWantToMergeTo.

+

Part 1 - Set up your branch:

+
    +
  1. Ensure you are on the main branch of your repository. It is usually called main. If you are not on the main branch, switch to it with git checkout main
  2. +
  3. Pull the most recent version of your main branch from GitHub. You can do this with git pull origin main. This will make sure your new branch contains all the most recent changes
  4. +
  5. Create a new branch for yourself. The name of the branch should describe what the code inside will do, and you should prefix it with your name or nickname. For example, git branch joel/changeButtonColor
  6. +
  7. Check out your new branch before you make any changes. Example: git checkout joel/changeButtonColor. Refer to Branches if you make any mistakes.
  8. +
+

Part 2 - Make your commits:

+
    +
  1. Follow the instructions in the Staging Files and Adding Commits section to create a commit containing your desired changes. Use git status frequently to make sure you are doing everything correctly.
  2. +
+

Part 3 - Push your commits to origin:

+
    +
  1. Push your branch to origin. Ex. git push origin joel/changeButtonColor
  2. +
  3. Set up a pull request on GitHub, with the base as main (or the branch you want to merge to) and the compare branch as your branch, (ex joel/changeButtonColor)
  4. +
  5. (Only if your pull request indicates you have a merge conflict): DO NOT merge the branch. Instead, do git pull origin main (or the branch you want to merge to) on your local machine. This will bring up the merge conflict.
  6. +
  7. Follow the instructions in Merge Conflicts to fix any merge conflicts that you get from pulling that branch. Once you have fixed all merge conflicts, remember to double check that your code runs, then git add and git commit your fixes!
  8. +
  9. Push your changes to your remote repository! Do git push origin yourLocalBranch
  10. +
  11. Now that your changes are present on your remote repository, you should create a pull request on GitHub. The base (target branch) should be branchYouWantToMergeTo, and the source should be yourLocalBranch.
  12. +
  13. Check to make sure the pull request says "No merge conflicts". If it does detect merge conflicts, that means you didn't do steps 4-7 correctly, so redo them!
  14. +
  15. Request a reviewer for your pull request. They will read your code and offer suggestions on how to improve it.
  16. +
  17. Resolve the comments of your reviewer. Once they are resolved and your reviewer confirms you can proceed, you can merge the pull request on GitHub. Congratulations! Your code is now merged into your project.
  18. +
+

Clean up:

+
    +
  1. Delete your branch on the remote repository
  2. +
  3. Delete your branch on your local system (checkout to main. Then delete with git branch -d yourBranchName)
  4. +
+

Big Picture Git/GitHub Workflow

+

Now that you understand the complete process on an individual level, let's take a step back to understand how your team will be using git.

+

Here is the Git workflow we recommend:

+

This is what is used at Microsoft. It works well and it's good practice to teach it.

+
    +
  1. When a team member wants to make changes or additions to the code, they should create a new branch for themselves. The branch name should describe what it does, ex. fixButtonGlitch
  2. +
  3. They git push their code to a branch on your origin repo that shares the same name
  4. +
  5. When they're ready, they create a Pull Request on GitHub. The PR's source should be their branch, and the destination should be main.
  6. +
  7. They should describe their Pull Request in the description and provide screenshots if applicable
  8. +
  9. They merge their own PR, once the following 3 conditions are met: +
      +
    1. There are no merge conflicts with the base branch
    2. +
    3. If your project has Continuous Integration (which it should), the PR build succeeds
    4. +
    5. At least 2 people have reviewed the code in the PR (more on code reviews later) and all comments from code reviews have been resolved
    6. +
    +
  10. +
  11. Upon merging the PR, they delete their branch.
  12. +
+

FAQ

+ +

Advanced Section

+

Here are some advanced Git commands you can use to boost your Git game to the next level. They are not essential to using Git, but you may find them helpful. If you're still learning the beginner commands, we recommend focusing on them until you're comfortable with them before worrying about these advanced commands.

+

Advanced Staging and Commits

+

Here are some additional commands and flags for existing commands that you can use while you are staging files and adding commits.

+

If you want descriptions of the basic staging and commits, please see staging files & creating commits in the beginner part of the guide.

+

git status (-s) (-v)

+

(-s) displays information in a shortened and fast format

+

(-v) displays information in more detail, with additions such as the textual changes of uncommitted files

+

git add [fileName or folderName] (-u)

+

You can use the -u flag on git add for the following effects:

+

(-u) adds new/modified files and IGNORES deleted files to the staging area

+

git commit (-a) (-am) "[Commit message here]"

+

You can use the -a and -am flags on git commit for the following effects:

+

(-a) commits all files in the staging area

+

(-am) commits all files in the staging area and allows the addition of the commit message in the command

+

"[Commit message here]" the message that will be attached to the commit. Only usable if -m or -am is used; otherwise, a text editor will appear for the commit message.

+

Git Stash

+

Tutorial

+

🚧 Under Construction 🚧

+ +

Git Clean

+

Tutorial

+

🚧 Under Construction 🚧

+ +

Undoing Commits & Changes

+

Below is the general sequence of commands to check, and undo previous commits. Notice that we must use the commit comments as the easiest factor in differentiating between commits. It is important to use a descriptive comment for each commit.

+

git log

+

Displays old commits with the ID hash and commit comment on the current branch.

+

git checkout [id hash]

+

Will make your working directory match the exact state of the id’ed commit.

+

Nothing you do here will be saved to the current state of the project (to go back do git checkout main).

+

git clean (-f) (-n)

+

git clean -n shows which UNTRACKED files will be removed, should you do git clean -f.

+

Good practice is to always -n before you -f. Learn more

+

(-n) runs a dry run (previews what files would be removed).

+

(-f) to force untracked file detection (removes the files).

+

git revert

+

Undoes a single commit.

+

git reset [id hash]

+

Goes back to the specified commit by removing all subsequent commits.

+

Git Rebase and Git Merge

+

git merge [branchName]

+

Merges the specified branch into the branch that your local directory is currently on. +In a typical workflow, you will not need to use this command ever. +Instead, git pull and pull requests will handle all merging for you.

+

🚧 Under Construction 🚧

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/guides/React_Guide/images/image1.png b/guides/React_Guide/images/image1.png new file mode 100644 index 0000000..650f810 Binary files /dev/null and b/guides/React_Guide/images/image1.png differ diff --git a/guides/React_Guide/images/image2.png b/guides/React_Guide/images/image2.png new file mode 100644 index 0000000..a6883c2 Binary files /dev/null and b/guides/React_Guide/images/image2.png differ diff --git a/guides/React_Guide/index.html b/guides/React_Guide/index.html new file mode 100644 index 0000000..de0829f --- /dev/null +++ b/guides/React_Guide/index.html @@ -0,0 +1,787 @@ + + + + + + React - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+
+
+
+

Tech Start's React Guide

+

+

alt_text

+

React Main Concepts

+ +

JavaScript For React

+ +

More React

+ +

React Ecosystem

+ +

React Main Concepts

+

React Video

+

Check out this video as a crash course to React:

+

https://www.youtube.com/watch ?v=Ke90Tje7VS0

+

If you find this video confusing, or prefer a different one as a React intro, please let us know :)

+

If you prefer reading to watching videos, this guide is helpful:

+

Components

+

React is built around the concept of components. Components are reusable, self-contained units that encapsulate the UI and behavior of a part of the application. React applications are typically composed of many components.

+
function MyComponent() {
+  return <div>Hello, World!</div>;
+}
+
+

JSX

+

JSX (JavaScript XML) is a syntax extension for JavaScript that allows you to write HTML-like code within your JavaScript. It's used in React to define the structure of components.

+
const element = <h1>Hello, world!</h1>;
+
+

Rendering

+

React renders components into the DOM (Document Object Model). You can use the ReactDOM library to render a component into a specific HTML element.

+
ReactDOM.render(<MyComponent />, document.getElementById('root'));
+
+

Props

+

Props (short for properties) allow you to pass data from a parent component to a child component. This enables you to create dynamic and reusable components.

+
function Greeting(props) {
+  return <div>Hello, {props.name}</div>;
+}
+
+

State

+

State is a way to store and manage data that can change over time. It is used to make components dynamic and interactive.

+
class Counter extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = { count: 0 };
+  }
+}
+
+

Lifecycle Methods

+

React components have a lifecycle, and you can use lifecycle methods to perform actions at various stages of a component's existence. For example, componentDidMount is called after a component is rendered.

+
componentDidMount() {
+  // Perform initialization after rendering.
+}
+
+

Handling Events

+

You can define event handlers in React components to respond to user interactions, such as clicks or input changes.

+
function Button() {
+  function handleClick() {
+    console.log('Button clicked');
+  }
+
+  return <button onClick={handleClick}>Click me</button>;
+}
+
+

Conditional Rendering

+

You can use conditional statements and expressions to conditionally render different parts of a component based on certain conditions.

+
function Greeting(props) {
+  if (props.isLoggedIn) {
+    return <div>Welcome, User!</div>;
+  } else {
+    return <div>Please log in.</div>;
+  }
+}
+
+

Lists and Keys

+

React provides a way to render lists of elements efficiently and assigns unique keys to each item in the list for optimization.

+
const numbers = [1, 2, 3, 4, 5];
+const listItems = numbers.map((number) => <li key={number}>{number}</li>);
+
+

React utilizes several JavaScript features and concepts like arrow functions, classes, callbacks, promises, and async/await to create dynamic and interactive user interfaces. Let's explore each of these in detail and discuss how they are related and integrated in React:

+

Javascript For React:

+

Arrow functions, classes, callbacks, promises, and async/await are fundamental JavaScript concepts that are commonly used in React. Let's explore each of these topics and how they are related and integrated in React:

+

Arrow Functions:

+

Arrow functions are a concise way to write functions in JavaScript. They are commonly used in React for defining components and functions, as they have a more compact syntax compared to traditional function expressions. Arrow functions capture the this value of the enclosing context automatically, making them suitable for working within React components and event handlers.

+

Example of an arrow function defining a React component:

+
const MyComponent = () => {
+  return <div>Hello, World!</div>;
+};
+
+

Classes:

+

Classes in JavaScript are used to define and create objects with methods and properties. In React, components are often defined as classes, especially when they need to manage component state and lifecycle methods. React class components extend the React.Component class and can have methods like render, componentDidMount, and more for handling component behavior.

+

Example of a React class component:

+
class MyComponent extends React.Component {
+  render() {
+    return <div>Hello, World!</div>;
+  }
+}
+
+

**Note on functional versus class-based components**

+

When React was first created, class-based components were the standard. But functional components were introduced later, and they eclipse class-based components in every way.

+

Our advice: Ironically, you should probably never use class-based components!

+

Stick to functional components. They are more modern and more versatile.

+

Lots of tutorial content online still uses class-based components. If you stumble upon a tutorial or explanation that uses a class-based component, and you're new to React, please search for a functional-component alternative instead!

+

Callbacks:

+

Callbacks are functions that are passed as arguments to other functions and are executed at a later time or in response to an event. React uses callbacks extensively, especially in event handling. For example, you can pass callback functions to event handlers to respond to user interactions.

+

Example of a callback function for handling a button click:

+
function handleClick() {
+  console.log('Button clicked');
+}
+
+<button onClick={handleClick}>Click me</button>
+
+

Promises:

+

Promises are a way to handle asynchronous operations in JavaScript. They represent a value that might be available now, or in the future, or never. Promises have three states: pending, fulfilled, and rejected.

+
    +
  • +

    Creating Promises: +You can create a promise using the Promise constructor. It takes a function with two arguments: resolve and reject. You typically perform an asynchronous operation in this function and call resolve when the operation is successful or reject when it fails.

    +
    const myPromise = new Promise((resolve, reject) => {
    +  // Asynchronous operation
    +  if (operationSucceeded) {
    +    resolve(result);
    +  } else {
    +    reject(error);
    +  }
    +});
    +
    +
  • +
  • +

    Chaining Promises: +Promises can be chained together using .then() and .catch() to handle the resolved value or errors. This chaining allows you to compose complex asynchronous operations.

    +
    myPromise
    +  .then((result) => {
    +    // Handle success
    +  })
    +  .catch((error) => {
    +    // Handle error
    +  });
    +
    +
  • +
+

async/await:

+

async and await are modern JavaScript features for working with asynchronous code. They make asynchronous code more readable and maintainable.

+
    +
  • +

    async Function: +An async function is a function that always returns a promise. It allows you to use the await keyword inside the function to pause execution until the promise is resolved.

    +
    async function fetchData() {
    +  const data = await fetch('https://api.example.com/data');
    +  return data.json();
    +}
    +
    +
  • +
  • +

    await Keyword: +The await keyword can only be used inside an async function. It pauses the execution of the function until the promise is resolved, and it returns the resolved value.

    +
    const result = await myPromise;
    +// The code here will not execute until myPromise is resolved.
    +
    +
  • +
+

Promises and Aysnc/Await Integration in React:

+

React applications often involve asynchronous operations, such as fetching data from APIs or making network requests. Promises, async/await, and React's lifecycle methods can be integrated for managing asynchronous tasks effectively:

+
    +
  • +

    Fetching Data: +You can use async/await to fetch data in React components. Typically, you do this inside componentDidMount() or within functional components using the useEffect hook.

    +
    async componentDidMount() {
    +  try {
    +    const response = await fetch('https://api.example.com/data');
    +    const data = await response.json();
    +    this.setState({ data });
    +  } catch (error) {
    +    console.error('Error fetching data:', error);
    +  }
    +}
    +
    +
  • +
  • +

    Updating Component State: +Once the data is fetched, you can update the component state to trigger a re-render with the new data.

    +
  • +
  • +

    Handling Errors: +Use try/catch to handle errors gracefully. You can also integrate error boundaries in React to catch errors in the component tree.

    +
  • +
  • +

    Using Promises: +React works well with Promises, and you can use .then() and .catch() to manage asynchronous operations. However, async/await is often preferred for its more readable and synchronous-like syntax.

    +
  • +
+

Integrating Promises and async/await in React allows you to manage asynchronous operations in a clean and structured way, providing a better user experience by preventing UI blocking during data retrieval.

+

More React:

+

Events in React

+

Event Handling

+

In React, events are used to capture and respond to user interactions, such as clicks, input changes, and mouse movements. Event handling in React is similar to handling events in traditional HTML, but there are some differences due to React's synthetic event system.

+

In React, you define event handlers as functions and attach them to JSX elements using event attributes. Here's an example of how you might handle a click event in React:

+
function Button() {
+  function handleClick() {
+    console.log('Button clicked');
+  }
+
+  return <button onClick={handleClick}>Click me</button>;
+}
+
+

The onClick attribute specifies the event handler function, handleClick, which will be executed when the button is clicked. React's synthetic event system provides a consistent API for handling events across different browsers.

+

Event Object

+

In React, event handlers are passed an event object as an argument. This object contains information about the event, such as the type of event, target element, and any event-specific data. You can access event properties and methods within your event handler functions.

+
function handleChange(event) {
+  console.log('Input value:', event.target.value);
+}
+
+

Higher Order Components (HOCs) in React

+

What Are HOCs?

+

Higher Order Components are a design pattern in React that allows you to reuse component logic by wrapping one or more components with a higher-order component. HOCs are not a part of the React API; they are a pattern that leverages the composability of components.

+

How HOCs Work

+

HOCs are functions that take a component and return a new enhanced component. They can add props, modify behavior, or encapsulate certain functionality. For example, you might create an HOC that provides authentication, access control, or data fetching capabilities to a component.

+

Here's a simplified example of a higher order component that provides a "loading" indicator to a component:

+
function withLoadingIndicator(WrappedComponent) {
+  return function WithLoadingIndicator(props) {
+    if (props.isLoading) {
+      return <div>Loading...</div>;
+    }
+    return <WrappedComponent {...props} />;
+  };
+}
+
+

Using HOCs

+

You can use an HOC by wrapping your component with it. For instance, suppose you have a component called MyComponent, and you want to add a loading indicator using the withLoadingIndicator HOC:

+
const MyComponentWithLoading = withLoadingIndicator(MyComponent);
+
+

Now, MyComponentWithLoading is a new component that includes the loading indicator logic from the HOC. You can render it as you would with any other component.

+
<MyComponentWithLoading isLoading={true} />
+
+

Benefits of HOCs

+

HOCs enable you to separate concerns and promote reusability. They help you avoid code duplication by encapsulating common functionality in a separate function. This makes your code more maintainable and flexible, allowing you to compose and extend component behavior as needed.

+

Relationship Between Events and HOCs

+

Events and HOCs can work together in a React application. For instance, you might create an HOC that handles common event-related logic, such as tracking user interactions, and then wrap components that need that behavior. This can help centralize event handling logic and make it reusable across multiple components. Additionally, you can pass event handling functions as props when composing components with HOCs, allowing for flexible customization of event behavior.

+

In summary, events in React are essential for capturing and responding to user interactions, while Higher Order Components are a design pattern that promotes reusability and composability of component logic. You can use HOCs to encapsulate and extend event-related logic, making it easier to manage event handling across your React application.

+

Props vs. State

+

Props and state are two fundamental concepts in React, and they play distinct roles in how components work.

+

Props

+

Props (short for properties) are a mechanism for passing data from a parent component to a child component. Props are read-only, meaning that the child component cannot modify the props it receives. They are used to customize or configure child components based on data from their parent.

+

Example of using props:

+
function Greeting(props) {
+  return <div>Hello, {props.name}</div>;
+}
+
+

State

+

State is a way to store and manage data that can change over time within a component. State is used to make components dynamic and interactive. Unlike props, state is mutable, and components can change their internal state using the setState method. State is often used for data that the component needs to keep track of, such as user input or UI state.

+

Example of using state:

+
class Counter extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = { count: 0 };
+  }
+
+  render() {
+    return (
+      <div>
+        <p>Count: {this.state.count}</p>
+        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
+          Increment
+        </button>
+      </div>
+    );
+  }
+}
+
+

How They Relate and Are Integrated

+

Props and state are often used together to create dynamic and interactive React applications. Here's how they relate and are integrated:

+
    +
  1. +

    Passing Data: Props are used to pass data from a parent component to its child components. This data can be initial data that a child component uses to render itself.

    +
  2. +
  3. +

    Updating Data: State is used to manage data that can change within a component. Components can have state and use it to keep track of user interactions, input, or changes in data.

    +
  4. +
  5. +

    Reactivity: When a parent component passes props to a child component, any changes to those props in the parent will re-render the child. This allows for dynamic updates.

    +
  6. +
  7. +

    State Management: State is local to the component that owns it, and changes in state trigger re-renders of that component, updating the UI as needed.

    +
  8. +
  9. +

    Lifting State: Sometimes, you might need to manage state at a higher level in the component tree and pass it down as props to child components. This is called "lifting state up."

    +
  10. +
+

In summary, props are for passing data from parent to child, while state is for managing data that can change within a component. Together, they enable you to build interactive and data-driven React applications. Hooks, especially the useState hook, make it easier to manage local state in functional components, further enhancing the capabilities of React functional components.

+

Hooks in Functional Components

+

React introduced Hooks in version 16.8 as a way to add state and side-effects to functional components, which were previously limited to stateless rendering.

+

In React, "stateless rendering" refers to the practice of creating functional components (also known as stateless functional components) that are purely responsible for rendering UI based on the input data provided through props. These components do not manage or maintain any internal state.

+

Out with the old in with the new KING, hooks allow you to reuse stateful logic and side-effects across components, making functional components more powerful and flexible.

+

Some of the most commonly used hooks include:

+

1. useState

+

This one might sound familiar from above, useState hook allows functional components to manage local state. It takes an initial state value and returns an array with the current state and a function to update it.

+
import React, { useState } from 'react';
+
+function Counter() {
+  const [count, setCount] = useState(0);
+
+  return (
+    <div>
+      <p>Count: {count}</p>
+      <button onClick={() => setCount(count + 1)}>Increment</button>
+    </div>
+  );
+}
+
+

2. useEffect

+

The useEffect hook enables you to perform side-effects in functional components. It takes a function that will be executed after every render, and you can specify dependencies to control when the effect should run.

+
import React, { useEffect, useState } from 'react';
+
+function Example() {
+  const [data, setData] = useState([]);
+
+  useEffect(() => {
+    // Fetch data from an API and update the state
+    fetchData().then((result) => setData(result));
+  }, []); // Empty dependency array runs the effect only once
+}
+
+

3. Other Built-in Hooks

+

React provides several other built-in hooks, such as useContext and useReducer, which allow you to manage context, state transitions, and references in functional components, respectively.

+
    +
  • useContext: Allows you to access the context API within functional components. It's useful for sharing data across the component tree without prop drilling.
  • +
+
import React, { useContext } from 'react';
+
+const ThemeContext = React.createContext('light');
+
+function ThemedButton() {
+  const theme = useContext(ThemeContext);
+  return <button className={theme}>Themed Button</button>;
+}
+
+
    +
  • useReducer: This hook is used for more complex state management and state transitions. It's similar to setState but offers more control over how state updates occur.
  • +
+
import React, { useReducer } from 'react';
+
+const initialState = { count: 0 };
+
+function counterReducer(state, action) {
+  switch (action.type) {
+    case 'increment':
+      return { count: state.count + 1 };
+    case 'decrement':
+      return { count: state.count - 1 };
+    default:
+      return state;
+  }
+}
+
+function Counter() {
+  const [state, dispatch] = useReducer(counterReducer, initialState);
+
+  return (
+    <div>
+      <p>Count: {state.count}</p>
+      <button onClick={() => dispatch({ type: 'increment' })}> Increment</button>
+      <button onClick={() => dispatch({ type: 'decrement' })}> Decrement</button>
+    </div>
+  );
+}
+
+

4. Custom Hooks

+

You can create your own custom hooks to encapsulate and share component logic across different components. Custom hooks promote code reuse and maintainability.

+
// Custom hook for handling form input state
+import { useState } from 'react';
+
+function useFormInput(initialValue) {
+  const [value, setValue] = useState(initialValue);
+
+  const handleChange = (e) => {
+    setValue(e.target.value);
+  };
+
+  return {
+    value,
+    onChange: handleChange,
+  };
+}
+
+

In summary, hooks in React are a way to manage state and side-effects in functional components. They integrate seamlessly with functional components, making it easier to write and maintain complex logic and enabling better code reuse. React's built-in hooks and the ability to create custom hooks provide a powerful toolset for building dynamic and interactive applications.

+

Great Resources(videos): https://www.youtube.com/watch?v=Jl4q2cccwf0&ab_channel=TheNetNinja

+
    +
  1. useState: https://www.youtube.com/watch?v=4qVNaohzDWU&ab_channel=LogRocket
  2. +
  3. useEffect:https://www.youtube.com/watch?v=gv9ugDJ1ynU&ab_channel=TheNetNinja
  4. +
  5. useRef: https://www.youtube.com/watch?v=yCS2m01bQ6w&ab_channel=Codevolution
  6. +
  7. useCallback: https://www.youtube.com/watch?v=-Ls48dd-vJE&ab_channel=BenAwad
  8. +
+

React Ecosystem

+

Calling APIs

+

Calling APIs is a key part of any React App. It's what enables your app to communicate with the outside world - including, presumably, your backend.

+

Here's a helpful tutorial on the best practices for calling APIs in React:

+

https://www.youtube.com/watch?v=bYFYF2GnMy8

+

There's also a part 2:

+

https://www.youtube.com/watch?v=1tfd6ANaNRY

+

The best ways to fetch data are using the popular package Axos (https://www.npmjs.com/package/axios) or the vanilla JS _fetch _function (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)

+

Once you have parsed the data, you'll probably want to store it in your state somehow (using useState or a redux store).

+

It is also good practice to encapsulate your entire API call into a custom hook, and name the hook according to what it does (ex. useFetchPokemonStats). This is also much easier to do if you use a state-management system like Redux, which is described below.

+

The methods described above let you call an API immediately upon rendering a certain component. But what happens if you want to manually trigger an API call (ex. after a certain action or event)?

+

Your API call should still use useEffect, and should look mostly like the calls you learned about in Part 1. The 1 difference is you need to guard the useEffect wisely in its dependency array.

+

As you recall, the dependency array of a useEffect contains everything that the useEffect depends upon - if any of its dependencies change, it will have a _side effect _of rerunning the useEffect.

+

So, you can define a specific variable which only changes when you want your API call to run. You can put that variable in the dependency array of the useEffect. When the action or event that you want to trigger the API call occurs, you should change the trigger variable. This change will trigger the useEffect to run. The trigger variable should never change except when you want the useEffect to run.

+

I personally like making my trigger variable an object which also contains any subvariables that my API call needs. So for example, if I was coding a call to a search API that included a text query and target price, my trigger object would contain those.

+

Here is an example of a very basic React application that calls an API to perform a search with a custom hook and a useEffect guarded by a trigger object as described above: https://github.com/Tech-Start-UCalgary/react-api-examples/tree/main/js-no-redux

+

useSWR

+

alt_text

+

useSWR is a useful React hook for data fetching published by Vercel (creators of Next.js).

+

SWR stands for stale-while-revalidate. It allows for smart data fetching and encapsulates a lot of advanced fetching logic (like how often should you refetch? should you have a cache?) in a single line of code.

+

You should read more about useSWR here:

+

https://swr.vercel.app/

+

You can watch a video tutorial here:

+

https://www.youtube.com/watch?v=f7yjEdXgGiM

+

React Router

+

React Router is a popular library used for routing in React applications. Routing is the process of determining which UI components should be displayed based on the current URL or path. React Router helps you create single-page applications with multiple views and navigate between them without requiring full page reloads.

+

Here's an elaboration on React Router and its integration with React:

+

React Router Features:

+
    +
  1. +

    Declarative Routing: React Router uses a declarative approach, where you define the routes and their corresponding components in a clear and organized manner. You specify what component should be rendered when a particular URL is matched.

    +
  2. +
  3. +

    Nested Routing: React Router supports nested routes, allowing you to create complex and hierarchical UI structures. This is especially useful for building multi-level menus or complex application layouts.

    +
  4. +
  5. +

    Route Parameters: You can define route parameters in your routes, allowing you to extract dynamic data from the URL. For example, a route like /users/:id can capture the id as a parameter.

    +
  6. +
  7. +

    Programmatic Navigation: React Router provides a set of functions for programmatic navigation. You can change the route, push to the browser's history, or replace the current route using these functions. This is useful for actions like form submissions or after successful authentication.

    +
  8. +
  9. +

    Route Guards: React Router allows you to implement route guards for protecting routes based on user authentication or other conditions. This ensures that users can only access certain routes if they meet specific criteria.

    +
  10. +
+

Integration with React:

+

React Router is typically integrated into a React application as a separate library. Here's how it's commonly done:

+
    +
  1. +

    Installation: You start by installing React Router as a package in your React project. You can use either react-router-dom (for web applications) or react-router-native (for mobile applications).

    +
    npm install react-router-dom
    +
    +
  2. +
  3. +

    Router Component: You wrap your entire application (or a part of it) with a <BrowserRouter> or <HashRouter> component provided by React Router. This component manages the application's navigation state and listens to changes in the URL.

    +
    import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
    +
    +function App() {
    +  return (
    +    <Router>
    +      {/* Define your routes here */}
    +    </Router>
    +  );
    +}
    +
    +
  4. +
  5. +

    Route Configuration: Inside the <Router>, you define your routes using the <Route> component. Each <Route> component specifies a path and the component to render when the path matches.

    +
    <Route path="/home" component={Home} />
    +<Route path="/about" component={About} />
    +
    +
  6. +
  7. +

    Route Navigation: To navigate between routes, you use the <Link> component to create links or the history object to programmatically navigate.

    +
    <Link to="/home">Home</Link>
    +// OR
    +history.push('/home');
    +
    +
  8. +
  9. +

    Route Parameters: You can use route parameters to capture dynamic values from the URL. These parameters are accessible as props in the routed components.

    +
    <Route path="/user/:id" component={UserProfile} />
    +
    +
  10. +
  11. +

    Nested Routes: You can nest routes by defining routes within the components rendered by other routes. This allows for hierarchical routing structures.

    +
    <Route path="/dashboard" component={Dashboard}>
    +  <Route path="/dashboard/profile" component={Profile} />
    +</Route>
    +
    +
  12. +
+

By integrating React Router into your React application, you can create well-organized, client-side routing that provides a seamless and efficient user experience for navigating different parts of your application.

+

React with Redux

+

Redux is a widely used state container for javascript apps. As soon as your app reaches any level of data complexity, it makes a ton of sense to start using Redux to manage your state.

+

A fair warning: Redux will seem complicated at the beginning. That's completely expected! Push through that initial discomfort and you'll get used to it in no time :)

+

Here is a great introductory video to React-Redux:

+

https://www.youtube.com/watch?v=CVpUuw9XSjY

+

I highly recommend using **createSlice to setup your Redux Store. **It is a simple way to encapsulate creating actions and slicers in a simple, easy-to-read, easy-to-understand way. Here is a short video that does a great job explaining how to use createSlice:

+

https://www.youtube.com/watch?v=e0MEtFaQTZk

+

To access your Redux state and update your Redux state in React, I highly recommend using the twin hooks **useSelector **and useDispatch respectively. They are simple, easy, and elegant.

+

https://www.youtube.com/watch?v=3zoIigieur0

+

Lastly, Next.JS

+

Next.js is a framework built on top of React, designed to simplify and enhance the development of web applications. It provides several features and benefits while seamlessly integrating with React. Let's explore these aspects interactively:

+

Q1: What is Next.js?

+

Next.js is a framework for building web applications that are built on top of the React library. It simplifies many aspects of React development and adds capabilities for server-side rendering, routing, and more.

+

Q2: How does Next.js relate to React?

+

Next.js is an extension of React. It leverages React's component-based structure and allows you to build React applications while providing additional tools and features for server-side rendering, routing, and other optimizations.

+

Q3: What are some key features of Next.js?

+

Next.js offers several key features:

+
    +
  • +

    Server-Side Rendering (SSR): Next.js enables server-side rendering, which improves performance and SEO by rendering pages on the server before sending them to the client.

    +
  • +
  • +

    Routing: It includes a built-in routing system, so you can easily define and navigate between pages.

    +
  • +
  • +

    File-Based Routing: Routes are created based on the file structure, making it intuitive and easy to organize your application.

    +
  • +
  • +

    Automatic Code Splitting: It automatically splits your JavaScript code into smaller, more manageable chunks, optimizing loading times.

    +
  • +
  • +

    Static Site Generation (SSG): Next.js allows you to generate static HTML files at build time for even better performance and SEO.

    +
  • +
+

Q4: How do you create a new Next.js app?

+

To create a new Next.js app, you can use the following commands:

+
npx create-next-app my-nextjs-app
+cd my-nextjs-app
+npm run dev
+
+

This will set up a new Next.js application and start the development server.

+

Q5: Can you explain the pages and routing in Next.js?

+

In Next.js, you create pages by simply adding files to the pages directory. Each file becomes a route. For example, if you create pages/about.js, you will have a route at /about.

+

Q6: How does Next.js handle data fetching?

+

Next.js allows you to fetch data during server-side rendering using the getServerSideProps function. This data can be injected into your React components as props.

+
export async function getServerSideProps() {
+  // Fetch data from an API or database
+  const data = await fetchData();
+
+  return {
+    props: { data },
+  };
+}
+
+

Q7: What's the advantage of server-side rendering in Next.js?

+

Server-side rendering in Next.js improves the initial loading speed of your application and helps with search engine optimization (SEO). It also ensures that users see content more quickly.

+

Q8: How can I build a static website with Next.js?

+

Next.js provides static site generation (SSG) via the getStaticProps function. You can generate static HTML files for your pages at build time.

+
export async function getStaticProps() {
+  // Fetch data from an API or database
+  const data = await fetchData();
+
+  return {
+    props: { data },
+  };
+}
+
+

Q9: Are there any limitations or trade-offs with Next.js?

+

While Next.js offers many advantages, it may introduce complexity to smaller projects. It requires server-side rendering, which might not be necessary for all applications.

+

Q10: Can I deploy Next.js applications to various hosting platforms?

+

Yes, you can deploy Next.js applications to a wide range of hosting platforms, including Vercel, Netlify, and AWS. These platforms often provide built-in support for Next.js, making deployment straightforward.

+

Next.js is a powerful tool that enhances React applications by providing features like server-side rendering, routing, and automatic code splitting. It simplifies the development process and improves performance. If you have more specific questions or need further information about Next.js, feel free to ask!

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/guides/React_Native_Guide/index.html b/guides/React_Native_Guide/index.html new file mode 100644 index 0000000..fe18687 --- /dev/null +++ b/guides/React_Native_Guide/index.html @@ -0,0 +1,1335 @@ + + + + + + React Native - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+
+
+
+

Tech Start's React Native Guide

+

Please get acquainted with our React Guide before you read this page, this is just a recommendation though. Transitioning from a good background in React to React Native is a relatively smooth process, as many concepts carry over. However, there are specific topics and components you should learn to effectively work with React Native. Here's an outline of the topics you need to cover:

+
    +
  1. +

    Video Resources (If you don't Like Reading)

    +
  2. +
  3. +

    React Native Basics Main Concepts

    + +
  4. +
  5. +

    Navigation

    +
  6. +
  7. +

    Platform-Specific Code

    +
  8. +
  9. +

    Accessing Device Features

    +
  10. +
  11. +

    Native Modules and Bridges

    +
  12. +
  13. +

    State Management

    +
  14. +
  15. +

    Async Storage

    +
  16. +
  17. +

    Network Requests

    +
  18. +
  19. +

    Advanced Topics;

    + +
  20. +
  21. +

    Third-Party Integration

    +
  22. +
  23. +

    Security

    +
  24. +
  25. +

    conclusion

    +
  26. +
+

Video Resources:

+

These tutorials should be sufficient to get started but this guide gives many more subtle topics that are not covered in these videos. Choose your weapon wisely.

+
    +
  • https://www.youtube.com/playlist?list=PL4cUxeGkcC9ixPU-QkScoRBVxtPPzVjrQ
  • +
  • https://www.youtube.com/watch?v=0-S5a0eXPoc
  • +
+

React Native Basics:

+

Components in React Native

+

Components in React Native are similar to those in React, but with some variations and additional elements. Here's a more detailed breakdown:

+

1. Core Components:

+

React Native provides a set of core components that are similar to HTML elements. These include:

+
    +
  • View: The fundamental component for creating UI layouts.
  • +
  • Text: Used for displaying text.
  • +
  • Image: For displaying images.
  • +
  • ScrollView: For scrollable content.
  • +
  • TextInput: For text input fields.
  • +
  • And many more.
  • +
+

2. Custom Components:

+

You can create your custom components just like in React. These components can be stateless functional components or class components. To create a custom component, use the View, Text, Image, and other core components to compose your UI.

+

Styling in React Native

+

Styling in React Native is different from traditional web development. You have various options for styling your components:

+

a. Inline Styles:

+

React Native supports inline styles using JavaScript objects. You can apply styles directly to components, like this:

+
<View style={{ flex: 1, backgroundColor: 'lightblue' }}>
+  <Text style={{ fontSize: 20, color: 'black' }}>Hello, React Native!</Text>
+</View>
+
+

b. Stylesheets:

+

Using stylesheets, you can create reusable style definitions:

+
const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+    backgroundColor: 'lightblue',
+  },
+  text: {
+    fontSize: 20,
+    color: 'black',
+  },
+});
+
+<View style={styles.container}>
+  <Text style={styles.text}>Hello, React Native!</Text>
+</View>
+
+

c. Flexbox Layout:

+

React Native relies heavily on flexbox for layout design. It's similar to CSS flexbox but with a few differences. You can use properties like flex, alignItems, and justifyContent to control layout.

+
<View style={{ flex: 1, flexDirection: 'column', justifyContent: 'center', alignItems: 'center' }}>
+  <Text>Hello, React Native!</Text>
+</View>
+
+

Layout in React Native

+

Understanding layout is vital in React Native to create responsive and visually appealing designs.

+
    +
  1. +

    Flexbox Layout: Flexbox is the primary layout system in React Native. It allows you to design flexible and adaptive layouts. Key properties include:

    +
      +
    • flex: Determines how space is distributed among children.
    • +
    • alignItems: Aligns items along the cross-axis (vertical alignment).
    • +
    • justifyContent: Aligns items along the main axis (horizontal alignment).
    • +
    • flexDirection: Sets the direction of the main axis.
    • +
    +
  2. +
  3. +

    Positioning: You can control the position of elements using properties like position, top, left, right, and bottom.

    +
  4. +
  5. +

    Dimensions: Set dimensions using width and height. You can use percentages, fixed values, or dynamic values like flex.

    +
  6. +
  7. +

    Responsive Design: React Native allows you to create responsive designs using Dimensions and the onLayout event.

    +
  8. +
  9. +

    Orientation Handling: Handle changes in device orientation by adjusting your layout accordingly. Use the Dimensions API to detect changes.

    +
  10. +
  11. +

    Stylesheet Composition: Compose styles using stylesheets and conditionally apply styles based on screen dimensions or other criteria.

    +
  12. +
  13. +

    Best Practices:

    +
      +
    • +

      Separation of Concerns: Keep styles, logic, and presentation separate for better maintainability and code clarity.

      +
    • +
    • +

      Optimizing Styles: Optimize styles to reduce unnecessary re-renders and improve app performance.

      +
    • +
    +
  14. +
+

By mastering these concepts related to components, styling, and layout in React Native, you can create rich and visually appealing mobile app user interfaces. Flexbox, in particular, is a powerful tool for creating flexible layouts, and understanding the nuances of styling is crucial for developing a professional-looking app.

+ +

Navigation is a crucial aspect of building mobile applications with React Native. It involves creating the structure and flow of your app, allowing users to move between different screens or views. The most common library for implementing navigation in React Native is React Navigation. Here's a more detailed overview of navigation in React Native:

+

1. Installing React Navigation:

+
    +
  • To get started with React Navigation, you need to install it in your project using npm or yarn: +
    npm install @react-navigation/native @react-navigation/stack
    +
    +
  • +
+

2. Stack Navigator:

+
    +
  • The Stack Navigator is one of the most commonly used navigators in React Navigation. It allows you to create a stack of screens where each screen is placed on top of the previous one. You can navigate between screens by pushing and popping them from the stack.
  • +
  • To set up a Stack Navigator, you need to import it and define your screens. +
    import { createStackNavigator } from '@react-navigation/stack';
    +
    +const Stack = createStackNavigator();
    +
    +
  • +
+

3. Defining Screens:

+
    +
  • Each screen in your app is defined as a React component. For example, you might have a HomeScreen and a ProfileScreen. +
    function HomeScreen() {
    +  // Your screen's content
    +}
    +
    +function ProfileScreen() {
    +  // Your screen's content
    +}
    +
    +
  • +
+

4. Navigating Between Screens:

+
    +
  • You can navigate between screens using navigation functions provided by React Navigation. For example, to navigate from the HomeScreen to the ProfileScreen: +
    import { NavigationContainer } from '@react-navigation/native';
    +import { createStackNavigator } from '@react-navigation/stack';
    +
    +const Stack = createStackNavigator();
    +
    +function App() {
    +    return (
    +        <NavigationContainer>
    +        <Stack.Navigator>
    +            <Stack.Screen name="Home" component={HomeScreen} />
    +            <Stack.Screen name="Profile" component={ProfileScreen} />
    +        </Stack.Navigator>
    +        </NavigationContainer>
    +    );
    +}
    +
    +In your HomeScreen component, you can use navigation.navigate('Profile') to navigate to the ProfileScreen.
  • +
+

5. Passing Data Between Screens:

+
    +
  • You can pass data from one screen to another using parameters. For example, you can send a user's ID to the ProfileScreen: +
    // In HomeScreen
    +navigation.navigate('Profile', { userId: 123 });
    +
    +// In ProfileScreen
    +const userId = route.params.userId;
    +
    +
  • +
+

6. Drawer Navigation and Tab Navigation:

+
    +
  • React Navigation also supports Drawer and Tab navigations. The Drawer Navigator creates a sidebar menu for navigation, while the Tab Navigator allows you to switch between different tabs within an app.
  • +
+

7. Nested Navigation:

+

React Navigation allows you to nest navigators within each other, creating complex navigation structures. This can be useful when you have a tab navigator and want to use a stack navigator within one of the tabs, or if you want to combine different types of navigators for more intricate navigation patterns.

+

Here's an example of nesting a Stack Navigator within a Tab Navigator:

+
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import { createStackNavigator } from '@react-navigation/stack';
+
+const Tab = createBottomTabNavigator();
+const Stack = createStackNavigator();
+
+// Define a tab navigator with a stack navigator in one of the tabs
+function TabNavigator() {
+  return (
+    <Tab.Navigator>
+      <Tab.Screen name="Tab1" component={Tab1Component} />
+      <Tab.Screen name="Tab2" component={Tab2Component} />
+      <Tab.Screen name="Tab3" component={StackScreen} />
+    </Tab.Navigator>
+  );
+}
+
+// Define a stack navigator to use within a tab
+function StackScreen() {
+  return (
+    <Stack.Navigator>
+      <Stack.Screen name="StackScreen1" component={StackScreen1Component} />
+      <Stack.Screen name="StackScreen2" component={StackScreen2Component} />
+    </Stack.Navigator>
+  );
+}
+
+

8. Navigation Lifecycle:

+

React Navigation provides navigation lifecycle events that allow you to perform actions when a screen comes into view or goes out of view. Common lifecycle events include:

+
    +
  • focus: Triggered when a screen comes into focus.
  • +
  • blur: Triggered when a screen loses focus.
  • +
  • didFocus: Triggered after the screen has come into focus.
  • +
+

You can add listeners to these events to perform actions or fetch data when a screen is in focus.

+
import { useFocusEffect } from '@react-navigation/native';
+
+function MyScreen({ navigation }) {
+  // Add a focus event listener
+  useFocusEffect(
+    React.useCallback(() => {
+      // Perform actions when the screen comes into focus
+      console.log('Screen is in focus');
+      // You can also fetch data or make API calls here
+    }, [])
+  );
+
+  // ... rest of the screen component
+}
+
+

9. Screen Options:

+

You can customize the appearance and behavior of each screen's navigation using the options property in your screen component. This allows you to set options like the screen title, header style, and more.

+
function MyScreen({ route, navigation }) {
+  // Define screen-specific options
+  React.useLayoutEffect(() => {
+    navigation.setOptions({
+      title: 'Custom Title',
+      headerStyle: {
+        backgroundColor: 'blue',
+      },
+      headerTintColor: 'white',
+    });
+  }, [navigation]);
+
+  // ... rest of the screen component
+}
+
+

10. Navigation Methods:

+

React Navigation provides a set of methods that allow you to navigate between screens programmatically. Common methods include:

+
    +
  • navigate: Navigate to a new screen in the same stack.
  • +
  • push: Push a new screen onto the stack.
  • +
  • pop: Pop the current screen from the stack.
  • +
  • goBack: Navigate back to the previous screen.
  • +
+

These methods are accessible through the navigation prop in your screen components.

+
function MyScreen({ navigation }) {
+  return (
+    <View>
+      <Button title="Go to Screen2" onPress={() => navigation.navigate('Screen2')} />
+      <Button title="Push Screen3" onPress={() => navigation.push('Screen3')} />
+      <Button title="Go Back" onPress={() => navigation.goBack()} />
+    </View>
+  );
+}
+
+

These features offer extensive flexibility in designing complex navigation structures and allow you to respond to navigation events and customize screen-specific options. Understanding these concepts is crucial for building intuitive and feature-rich navigation in your React Native applications.

+

Platform-Specific Code:

+

Platform-specific code in React Native involves writing code that is specific to either iOS or Android platforms. This is sometimes necessary when you want to implement platform-specific features, handle platform-specific behaviors, or optimize your app for a particular platform. Here's a more detailed overview of this topic:

+

1. Platform-Specific Components and Styling:

+
    +
  • +

    React Native allows you to conditionally render components or apply styles based on the platform. For example, you can use the Platform.OS property to determine the platform:

    +
    import { View, Text } from 'react-native';
    +import { Platform } from 'react-native';
    +
    +const MyComponent = () => (
    +  <View>
    +    <Text>Common Text</Text>
    +    {Platform.OS === 'ios' && <Text>iOS only Text</Text>}
    +    {Platform.OS === 'android' && <Text>Android only Text</Text>}
    +  </View>
    +);
    +
    +
  • +
  • +

    Similarly, you can conditionally apply styles:

    +
    import { StyleSheet } from 'react-native';
    +
    +const styles = StyleSheet.create({
    +  commonStyle: {
    +    // Common styles
    +  },
    +  iosStyle: {
    +    // iOS-specific styles
    +  },
    +  androidStyle: {
    +    // Android-specific styles
    +  },
    +});
    +
    +const MyComponent = () => (
    +  <View>
    +    <Text style={[styles.commonStyle, Platform.OS === 'ios' ? styles.iosStyle : styles.androidStyle]}>
    +      Platform-specific styling
    +    </Text>
    +  </View>
    +);
    +
    +
  • +
+

2. Platform-Specific Modules:

+
    +
  • +

    In some cases, you might need to use platform-specific modules or APIs. React Native provides a way to do this using the .ios.js and .android.js file extensions. For example, you can have separate implementations for iOS and Android as follows:

    +
      +
    • MyModule.ios.js for iOS-specific code.
    • +
    • MyModule.android.js for Android-specific code.
    • +
    +
  • +
  • +

    React Native will automatically pick the right file based on the platform. This is useful when dealing with platform-specific features or APIs.

    +
  • +
+

3. Conditional Logic:

+
    +
  • +

    You can use conditional logic to handle platform-specific behaviors. For instance, you might need to request permissions differently on iOS and Android or use platform-specific libraries.

    +
    import { PermissionsAndroid, Platform } from 'react-native';
    +
    +async function requestLocationPermission() {
    +  if (Platform.OS === 'android') {
    +    // Android-specific logic for requesting permissions
    +    try {
    +      const granted = await PermissionsAndroid.request(
    +        PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
    +      );
    +      if (granted === PermissionsAndroid.RESULTS.GRANTED) {
    +        console.log('Location permission granted.');
    +      } else {
    +        console.log('Location permission denied.');
    +      }
    +    } catch (err) {
    +      console.warn(err);
    +    }
    +  } else if (Platform.OS === 'ios') {
    +    // iOS-specific logic for requesting permissions
    +    // ...
    +  }
    +}
    +
    +
  • +
+

4. Platform-Specific Libraries:

+
    +
  • +

    There are times when you need to use platform-specific libraries or modules. React Native allows you to conditionally include these libraries based on the platform. You can use conditional require statements to achieve this:

    +
    let platformSpecificLibrary;
    +if (Platform.OS === 'ios') {
    +  platformSpecificLibrary = require('ios-specific-library');
    +} else {
    +  platformSpecificLibrary = require('android-specific-library');
    +}
    +
    +
  • +
+

5. Native Modules:

+
    +
  • For highly platform-specific tasks, you might need to write native code (Objective-C/Swift for iOS or Java/Kotlin for Android) and create native modules. These native modules can be called from your React Native code, allowing you to perform platform-specific tasks.
  • +
+

Understanding how to handle platform-specific code is important for ensuring your React Native app functions correctly and efficiently on both iOS and Android devices. By using these techniques, you can create a seamless and native-like experience for users on each platform.

+

Accessing Device Features:

+

Accessing device features in React Native involves interacting with native device functionality, such as the camera, geolocation, sensors, and more. Here, I'll provide more detail on this topic and examples of how to access specific device features:

+
    +
  1. +

    Camera:

    +
      +
    • To access the camera in React Native, you can use the react-native-camera library. This library allows you to capture photos and record videos. You can also customize the camera settings, switch between front and back cameras, and apply real-time image processing.
    • +
    • Example: +
      import { RNCamera } from 'react-native-camera';
      +
      +// In your component
      +<RNCamera
      +  type={RNCamera.Constants.Type.back}
      +  flashMode={RNCamera.Constants.FlashMode.auto}
      +/>
      +
      +
    • +
    +
  2. +
  3. +

    Geolocation:

    +
      +
    • To access the device's location, you can use the built-in Geolocation module in React Native. It provides methods for retrieving the user's current location and monitoring changes in real-time.
    • +
    • Example: +
      import Geolocation from '@react-native-community/geolocation';
      +
      +// Get the current location
      +Geolocation.getCurrentPosition((position) => {
      +  console.log(position.coords.latitude, position.coords.longitude);
      +});
      +
      +
    • +
    +
  4. +
  5. +

    Sensors:

    +
      +
    • React Native provides access to various device sensors, including the accelerometer, gyroscope, and magnetometer, through the react-native-sensors library. You can use this library to collect data from these sensors.
    • +
    • Example: +
      import { Accelerometer } from 'react-native-sensors';
      +
      +const accelerometerObservable = new Accelerometer();
      +
      +const subscription = accelerometerObservable.subscribe((data) => {
      +  console.log('Acceleration X:', data.x);
      +  console.log('Acceleration Y:', data.y);
      +  console.log('Acceleration Z:', data.z);
      +});
      +
      +
    • +
    +
  6. +
  7. +

    Contacts:

    +
      +
    • Accessing device contacts can be achieved using the react-native-contacts library. This allows you to read and write contacts to the user's address book.
    • +
    • Example: +
      import Contacts from 'react-native-contacts';
      +
      +// Fetch all contacts
      +Contacts.getAll()
      +  .then((contacts) => {
      +    console.log(contacts);
      +  })
      +  .catch((error) => {
      +    console.error(error);
      +  });
      +
      +
    • +
    +
  8. +
  9. +

    Device Information:

    +
      +
    • React Native provides device information through the react-native-device-info library. You can retrieve details like the device's manufacturer, model, unique identifier, and more.
    • +
    • Example: +
      import DeviceInfo from 'react-native-device-info';
      +
      +// Get device information
      +console.log('Device Model:', DeviceInfo.getModel());
      +console.log('Device ID:', DeviceInfo.getUniqueId());
      +
      +
    • +
    +
  10. +
  11. +

    Bluetooth and NFC:

    +
      +
    • To work with Bluetooth and NFC, you can use libraries like react-native-ble-manager and react-native-nfc-manager. These libraries enable communication with nearby devices and NFC tags.
    • +
    • Examples can get quite involved, as working with Bluetooth and NFC often requires handling various events and connections. You can refer to the library documentation for detailed examples.
    • +
    +
  12. +
+

When accessing device features in React Native, it's essential to follow the documentation and best practices for the specific libraries and modules you're using. Additionally, consider handling permissions appropriately, especially for features like camera, geolocation, and contacts, which may require user consent.

+

Native Modules and Bridges:

+

Native modules and bridges in React Native are a way to access native code (Java or Objective-C) from JavaScript and vice versa. They are essential for tasks that require platform-specific functionality or performance optimization. Let's dive into more detail and provide examples of how to create and use native modules and bridges in React Native.

+

Native Modules

+

Native modules allow you to expose native code to JavaScript in a structured manner. Here's how to create a simple native module:

+
    +
  1. +

    Create a Native Module for iOS (Objective-C):

    +

    Let's say you want to create a native module that shows a native iOS alert.

    +
    // AlertModule.h
    +#import <React/RCTBridgeModule.h>
    +
    +@interface AlertModule : NSObject <RCTBridgeModule>
    +@end
    +
    +
    // AlertModule.m
    +#import "AlertModule.h"
    +#import <React/RCTLog.h>
    +
    +@implementation AlertModule
    +
    +RCT_EXPORT_MODULE();
    +
    +RCT_EXPORT_METHOD(showAlert:(NSString *)title message:(NSString *)message)
    +{
    +    UIAlertController *alert = [UIAlertController
    +        alertControllerWithTitle:title
    +        message:message
    +        preferredStyle:UIAlertControllerStyleAlert];
    +
    +    UIAlertAction *ok = [UIAlertAction
    +        actionWithTitle:@"OK"
    +        style:UIAlertActionStyleDefault
    +        handler:nil];
    +
    +    [alert addAction:ok];
    +    
    +    UIViewController *rootViewController = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
    +    [rootViewController presentViewController:alert animated:YES completion:nil];
    +}
    +
    +@end
    +
    +
  2. +
  3. +

    Create a Native Module for Android (Java):

    +

    To do the same thing in Android, create a native module to show an alert dialog.

    +
    // AlertModule.java
    +import com.facebook.react.bridge.ReactApplicationContext;
    +import com.facebook.react.bridge.ReactContextBaseJavaModule;
    +import com.facebook.react.bridge.ReactMethod;
    +
    +public class AlertModule extends ReactContextBaseJavaModule {
    +    public AlertModule(ReactApplicationContext reactContext) {
    +        super(reactContext);
    +    }
    +
    +    @Override
    +    public String getName() {
    +        return "AlertModule";
    +    }
    +
    +    @ReactMethod
    +    public void showAlert(String title, String message) {
    +        AlertDialog.Builder builder = new AlertDialog.Builder(getCurrentActivity());
    +        builder.setTitle(title);
    +        builder.setMessage(message);
    +        builder.setPositiveButton("OK", null);
    +        builder.show();
    +    }
    +}
    +
    +
  4. +
  5. +

    Using Native Modules in JavaScript:

    +

    In your JavaScript code, you can now use the native module you created:

    +
    import { NativeModules } from 'react-native';
    +
    +// For iOS
    +NativeModules.AlertModule.showAlert('Hello', 'This is an alert!');
    +
    +// For Android
    +NativeModules.AlertModule.showAlert('Hello', 'This is an alert!');
    +
    +
  6. +
+

Native Bridges

+

Bridges in React Native are responsible for connecting JavaScript and native code. React Native's native modules use bridges to enable communication between the two sides. In the examples above, the React Native framework handles the bridge for you.

+

Behind the scenes, React Native's bridge system serializes and deserializes data and manages the communication between JavaScript and native modules. It abstracts away many of the complexities, making it easier for developers to work with native modules in a JavaScript-friendly way.

+

By using native modules and bridges, you can incorporate platform-specific functionality into your React Native app while maintaining a unified JavaScript codebase. This is particularly helpful when you need to integrate with device-specific features, third-party libraries, or optimize performance.

+

Here are some tutorials that dive super in depth for creating a calender native module for Android or IOS.

+

State Management:

+

let's dive into more detail on state management in React Native and provide examples. State management is crucial for handling the data and UI state in your mobile applications. There are various options for managing state in React Native, similar to React for the web, including React's built-in state management, the Context API, and external libraries like Redux or MobX. Below, we'll cover these options and provide examples for better understanding:

+

1. React's Built-in State Management:

+

React Native, like React, allows you to manage state locally within a component using the useState hook.

+

Example:

+
import React, { useState } from 'react';
+import { View, Text, Button } from 'react-native';
+
+function Counter() {
+  const [count, setCount] = useState(0);
+
+  const increment = () => setCount(count + 1);
+  const decrement = () => setCount(count - 1);
+
+  return (
+    <View>
+      <Text>Count: {count}</Text>
+      <Button title="Increment" onPress={increment} />
+      <Button title="Decrement" onPress={decrement} />
+    </View>
+  );
+}
+
+

In this example, the useState hook is used to manage the count state variable within the Counter component.

+

2. Context API:

+

The Context API allows you to manage global state that can be accessed by multiple components without having to pass props down through the component tree.

+

Example:

+
import React, { createContext, useContext, useState } from 'react';
+import { View, Text, Button } from 'react-native';
+
+const CountContext = createContext();
+
+function Counter() {
+  const [count, setCount] = useContext(CountContext);
+
+  const increment = () => setCount(count + 1);
+  const decrement = () => setCount(count - 1);
+
+  return (
+    <View>
+      <Text>Count: {count}</Text>
+      <Button title="Increment" onPress={increment} />
+      <Button title="Decrement" onPress={decrement} />
+    </View>
+  );
+}
+
+function App() {
+  const [count, setCount] = useState(0);
+
+  return (
+    <CountContext.Provider value={[count, setCount]}>
+      <View>
+        <Text>My App</Text>
+        <Counter />
+      </View>
+    </CountContext.Provider>
+  );
+}
+
+

In this example, the CountContext is created and used to share the count state between the Counter component and the App component.

+

3. Redux:

+

Redux is a popular external state management library for React Native. It provides a central store for managing application state and allows for predictable state updates using actions and reducers.

+

Example:

+

To use Redux in React Native, you need to set up a store, actions, and reducers. Here's a simplified example:

+
// Define actions
+const increment = () => ({ type: 'INCREMENT' });
+const decrement = () => ({ type: 'DECREMENT' });
+
+// Define a reducer
+const counterReducer = (state = 0, action) => {
+  switch (action.type) {
+    case 'INCREMENT':
+      return state + 1;
+    case 'DECREMENT':
+      return state - 1;
+    default:
+      return state;
+  }
+};
+
+// Create the Redux store
+import { createStore } from 'redux';
+const store = createStore(counterReducer);
+
+// Connect components to the store
+import { connect } from 'react-redux';
+
+function Counter({ count, increment, decrement }) {
+  return (
+    <View>
+      <Text>Count: {count}</Text>
+      <Button title="Increment" onPress={increment} />
+      <Button title="Decrement" onPress={decrement} />
+    </View>
+  );
+}
+
+const mapStateToProps = (state) => ({ count: state });
+const mapDispatchToProps = { increment, decrement };
+
+const ConnectedCounter = connect(mapStateToProps, mapDispatchToProps)(Counter);
+
+

This example demonstrates a basic setup of Redux in React Native. It involves defining actions, a reducer, creating the store, and connecting a component to the store.

+

The choice of state management in your React Native project depends on the complexity and scalability of your application. React's built-in state management and the Context API are great for simple state needs, while Redux or MobX are more suitable for larger, complex applications with extensive state management requirements.

+

Async Storage:

+

AsyncStorage is a crucial concept in React Native, allowing you to store data locally on the user's device. It's similar to the localStorage in web development but tailored for mobile applications. AsyncStorage is often used to store user preferences, app settings, or any data that needs to persist across app sessions. Here, I'll dive into more detail about AsyncStorage and provide some examples.

+

Using AsyncStorage in React Native

+
    +
  1. +

    Importing AsyncStorage: +To use AsyncStorage, you need to import it from 'react-native':

    +
    import { AsyncStorage } from 'react-native';
    +
    +
  2. +
  3. +

    Storing Data: +You can store data in AsyncStorage by using the setItem method. Here's an example of how to store a simple string:

    +
    AsyncStorage.setItem('username', 'JohnDoe')
    +  .then(() => {
    +    console.log('Data stored successfully');
    +  })
    +  .catch((error) => {
    +    console.error('Error storing data: ', error);
    +  });
    +
    +
  4. +
  5. +

    Retrieving Data: +To retrieve data, you can use the getItem method:

    +
    AsyncStorage.getItem('username')
    +  .then((value) => {
    +    if (value !== null) {
    +      console.log('Retrieved data: ', value);
    +    } else {
    +      console.log('Data not found');
    +    }
    +  })
    +  .catch((error) => {
    +    console.error('Error retrieving data: ', error);
    +  });
    +
    +
  6. +
  7. +

    Updating Data: +You can update stored data by simply setting a new value for the same key:

    +
    AsyncStorage.setItem('username', 'NewUsername')
    +  .then(() => {
    +    console.log('Data updated successfully');
    +  })
    +  .catch((error) => {
    +    console.error('Error updating data: ', error);
    +  });
    +
    +
  8. +
  9. +

    Deleting Data: +To remove data from AsyncStorage, use the removeItem method:

    +
    AsyncStorage.removeItem('username')
    +  .then(() => {
    +    console.log('Data removed successfully');
    +  })
    +  .catch((error) => {
    +    console.error('Error removing data: ', error);
    +  });
    +
    +
  10. +
  11. +

    Handling Errors: +It's essential to handle errors, as reading from or writing to AsyncStorage may fail due to various reasons, such as storage limitations or permissions. Always use try...catch or promise-based error handling to ensure your app gracefully handles errors.

    +
  12. +
  13. +

    Working with JSON Data: +AsyncStorage stores data as strings, so if you need to store complex data structures like objects or arrays, you should serialize them to JSON when storing and parse them when retrieving:

    +
    const user = {
    +  name: 'John Doe',
    +  email: 'john@example.com',
    +};
    +
    +AsyncStorage.setItem('user', JSON.stringify(user))
    +  .then(() => {
    +    console.log('User data stored successfully');
    +  })
    +  .catch((error) => {
    +    console.error('Error storing user data: ', error);
    +  });
    +
    +// Retrieving and parsing the user data
    +AsyncStorage.getItem('user')
    +  .then((value) => {
    +    if (value !== null) {
    +      const userData = JSON.parse(value);
    +      console.log('Retrieved user data: ', userData);
    +    } else {
    +      console.log('User data not found');
    +    }
    +  })
    +  .catch((error) => {
    +    console.error('Error retrieving user data: ', error);
    +  });
    +
    +
  14. +
+

Remember that AsyncStorage is a simple key-value store and should be used for relatively small amounts of data. For larger datasets, consider using a more robust storage solution or a database. Additionally, be mindful of security considerations when storing sensitive information and ensure that you have the necessary permissions to access AsyncStorage on the user's device.

+

Network Requests:

+

Making network requests in React Native is a common task when you need to fetch data from an API or send data to a server. You can use libraries like Axios or the built-in fetch API to perform these requests. Here, I'll dive into more detail about how to make network requests in React Native using both Axios and fetch, and provide examples for each:

+

Using Axios

+

Axios is a popular library for making HTTP requests. You can use it in your React Native project by following these steps:

+
    +
  1. +

    Installation:

    +

    First, you need to install Axios in your project. You can do this with npm or yarn:

    +
    npm install axios
    +# or
    +yarn add axios
    +
    +
  2. +
  3. +

    Making a GET Request:

    +

    Here's an example of making a GET request to a remote API using Axios:

    +
    import axios from 'axios';
    +
    +const fetchUserData = async () => {
    +  try {
    +    const response = await axios.get('https://api.example.com/users');
    +    const userData = response.data;
    +    console.log(userData);
    +  } catch (error) {
    +    console.error('Error fetching user data:', error);
    +  }
    +};
    +
    +// Call the function to fetch user data
    +fetchUserData();
    +
    +
  4. +
  5. +

    Making a POST Request:

    +

    To make a POST request with Axios, you can do the following:

    +
    import axios from 'axios';
    +
    +const sendDataToServer = async (data) => {
    +  try {
    +    const response = await axios.post('https://api.example.com/postData', data);
    +    console.log('Data sent successfully:', response.data);
    +  } catch (error) {
    +    console.error('Error sending data:', error);
    +  }
    +};
    +
    +const dataToSend = {
    +  key1: 'value1',
    +  key2: 'value2',
    +};
    +
    +// Call the function to send data to the server
    +sendDataToServer(dataToSend);
    +
    +
  6. +
+

Using the fetch API

+

The fetch API is a built-in way to make network requests in JavaScript and is available in React Native:

+
    +
  1. +

    Making a GET Request:

    +

    Here's an example of making a GET request using the fetch API:

    +
    const fetchUserData = () => {
    +  fetch('https://api.example.com/users')
    +    .then((response) => {
    +      if (!response.ok) {
    +        throw new Error('Network response was not ok');
    +      }
    +      return response.json();
    +    })
    +    .then((userData) => {
    +      console.log(userData);
    +    })
    +    .catch((error) => {
    +      console.error('Error fetching user data:', error);
    +    });
    +};
    +
    +// Call the function to fetch user data
    +fetchUserData();
    +
    +
  2. +
  3. +

    Making a POST Request:

    +

    Making a POST request with fetch involves a similar structure:

    +
    const sendDataToServer = (data) => {
    +  fetch('https://api.example.com/postData', {
    +    method: 'POST',
    +    headers: {
    +      'Content-Type': 'application/json',
    +    },
    +    body: JSON.stringify(data),
    +  })
    +    .then((response) => {
    +      if (!response.ok) {
    +        throw new Error('Network response was not ok');
    +      }
    +      return response.json();
    +    })
    +    .then((responseData) => {
    +      console.log('Data sent successfully:', responseData);
    +    })
    +    .catch((error) => {
    +      console.error('Error sending data:', error);
    +    });
    +};
    +
    +const dataToSend = {
    +  key1: 'value1',
    +  key2: 'value2',
    +};
    +
    +// Call the function to send data to the server
    +sendDataToServer(dataToSend);
    +
    +
  4. +
+

Both Axios and the fetch API allow you to make various types of requests (GET, POST, PUT, DELETE, etc.) and handle responses. The choice between the two often comes down to personal preference and specific project requirements. Axios is a popular choice due to its simplicity and ease of use for handling requests and responses.

+

Advanced Topics

+

Debugging and Troubleshooting:

+
    +
  • Familiarize yourself with debugging tools, error messages, and common troubleshooting techniques specific to React Native.
  • +
  • RESOURCE: https://reactnative.dev/docs/debugging
  • +
+

Testing:

+
    +
  • Learn how to write unit tests and integration tests for your React Native components using testing frameworks like Jest.
  • +
  • RESOURCE: https://reactnative.dev/docs/testing-overview
  • +
+

Performance Optimization:

+
    +
  • Explore techniques for optimizing the performance of your app, including reducing renders and optimizing images.
  • +
  • RESOURCE: https://reactnative.dev/docs/performance
  • +
+

Publishing and Deployment:

+
    +
  • Understand how to build, sign, and deploy your app to the Google Play Store and Apple App Store.
  • +
  • IOS RESOURCE: https://reactnative.dev/docs/publishing-to-app-store
  • +
  • ANDROID RESOURCE: https://reactnative.dev/docs/signed-apk-android
  • +
+

Third-Party Integrations:

+

Third-party integrations in React Native are crucial for adding functionality and features to your app without having to build everything from scratch. Here, I'll provide more detail on some common third-party integrations in React Native along with links to the relevant libraries:

+
    +
  1. +

    Push Notifications:

    +
      +
    • Implementing push notifications is essential for engaging users. Libraries like react-native-firebase or react-native-push-notification provide the tools to send and receive push notifications on both iOS and Android.
    • +
    • react-native-firebase
    • +
    • react-native-push-notification
    • +
    +
  2. +
  3. +

    Analytics:

    + +
  4. +
  5. +

    Maps and Location:

    + +
  6. +
  7. +

    Camera and Image Capture:

    + +
  8. +
  9. +

    Social Media Sharing:

    +
      +
    • To enable users to share content on social media platforms, libraries like react-native-share provide sharing functionality with support for various services.
    • +
    • react-native-share
    • +
    +
  10. +
  11. +

    Payment Gateways:

    + +
  12. +
  13. +

    Authentication:

    +
      +
    • Implementing user authentication is a common requirement. Libraries like react-native-firebase/auth and react-native-auth0 offer easy integration with Firebase Authentication and Auth0, respectively.
    • +
    • react-native-firebase/auth
    • +
    • react-native-auth0
    • +
    +
  14. +
  15. +

    In-App Messaging:

    +
      +
    • If your app needs real-time chat or messaging features, libraries like react-native-gifted-chat can be used to quickly add chat functionality.
    • +
    • react-native-gifted-chat
    • +
    +
  16. +
  17. +

    Audio and Video Playback:

    + +
  18. +
  19. +

    AR/VR Integration:

    + +
  20. +
+

When integrating third-party libraries, make sure to check their documentation for installation and usage instructions, as well as any specific requirements or configurations. Carefully consider your app's requirements and select the libraries that best meet your needs while ensuring they are well-maintained and compatible with your React Native version.

+

Security Best Practices:

+

Security is a critical aspect of any mobile app, including those built with React Native. Here are some security best practices in React Native, along with examples:

+
    +
  1. +

    Secure Storage:

    +
      +
    • Use secure storage mechanisms to store sensitive data, such as user authentication tokens and API keys. Avoid storing them in plain text or insecure locations.
    • +
    +

    Example:

    +
    // Insecure storage
    +const apiKey = 'my-insecure-api-key';
    +
    +// Secure storage using a library like react-native-secure-storage
    +import SecureStorage from 'react-native-secure-storage';
    +
    +SecureStorage.set('api_key', 'my-secure-api-key');
    +
    +
  2. +
  3. +

    API Key Management:

    +
      +
    • Avoid hardcoding API keys directly in your source code. Instead, use environment variables or configuration files that are excluded from source control.
    • +
    +

    Example:

    +
    // Insecure API key storage
    +const apiKey = 'my-insecure-api-key';
    +
    +// Secure API key storage using environment variables
    +const apiKey = process.env.REACT_NATIVE_API_KEY;
    +
    +
  4. +
  5. +

    Authentication and Authorization:

    +
      +
    • Implement secure authentication and authorization mechanisms to protect user data and control access to sensitive parts of your app.
    • +
    +

    Example:

    +
    // Use a secure authentication library like Firebase Authentication or Auth0
    +import { Firebase } from 'react-native-firebase';
    +
    +// Ensure that only authenticated users can access certain features
    +if (user.isAuthenticated) {
    +  // Display sensitive data or allow certain actions
    +}
    +
    +
  6. +
  7. +

    Network Security:

    +
      +
    • Use HTTPS for all network requests to encrypt data in transit. Avoid sending sensitive information via unencrypted HTTP.
    • +
    +

    Example:

    +
    // Use HTTPS for network requests
    +fetch('https://api.example.com/data', {
    +  method: 'GET',
    +  headers: {
    +    'Content-Type': 'application/json',
    +    'Authorization': 'Bearer ' + user.token,
    +  },
    +})
    +
    +
  8. +
  9. +

    Code Obfuscation:

    +
      +
    • Obfuscate your JavaScript code to make it more difficult for malicious actors to reverse engineer your app. Obfuscation is typically done using third-party tools, and the specific steps and tools used may vary depending on the project.
    • +
    +
  10. +
  11. +

    Secure Communication with Native Modules:

    +
      +
    • When communicating with native modules, validate and sanitize data to prevent injection attacks.
    • +
    +

    Example:

    +
    import { NativeModules } from 'react-native';
    +
    +// Ensure the data passed to a native module is properly sanitized
    +const userInput = 'user-input-data';
    +NativeModules.MyModule.someMethod(validateInput(userInput));
    +
    +
  12. +
  13. +

    Input Validation:

    +
      +
    • Validate user input to prevent common security issues like SQL injection and cross-site scripting (XSS).
    • +
    +

    Example:

    +
    // Validate and sanitize user input to prevent XSS
    +const userInput = '<script>alert("XSS attack");</script>';
    +const sanitizedInput = sanitizeInput(userInput);
    +
    +
  14. +
  15. +

    Error Handling:

    +
      +
    • Implement proper error handling to prevent sensitive information from being exposed to users in error messages.
    • +
    +

    Example:

    +
    // Handle errors gracefully and do not expose sensitive information to the user
    +try {
    +  // Code that may throw an error
    +} catch (error) {
    +  console.error('An error occurred. Please try again later.');
    +}
    +
    +
  16. +
+

These are essential security best practices for React Native apps, but it's important to note that the specific implementation details may vary depending on your project and the libraries you use. Regularly staying informed about security developments in the React Native ecosystem and taking proactive measures to address vulnerabilities will help ensure the security of your app.

+

Conclusion:

+

This guide was meant to be a starting/middle point for learning React Native across its many topics, ranging from front-end to back-end(mainly back-end because that is what really matters, am I right!). Jokes aside, as you progress through these topics, you'll find that your React experience serves as a strong foundation for learning React Native. React Native allows you to leverage your JavaScript skills to build mobile apps for both iOS and Android, making it a valuable addition to your toolkit.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/guides/Tech_Demo/index.html b/guides/Tech_Demo/index.html new file mode 100644 index 0000000..cb02496 --- /dev/null +++ b/guides/Tech_Demo/index.html @@ -0,0 +1,231 @@ + + + + + + Giving a good Technical Demo - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Technical Demos

+

Overview

+

At some point in your career you will need to demo some work you've done to both technical and non-technical stakeholders (people with an interest in the work you're doing).

+

When you do this, you want to make sure you give yourself and your team the best opportunity to show off your hard work. Here are some tips and ideas to think about when preparing, and do prepare if it's for anyone other than your own team.

+

Purpose

+

The work you did will have achieved something, whether it's fixing a bug, solving a problem for your users, or presenting an entirely new idea.

+

It's important to show this if you want to convince others that your work is important. Feel free to show the existing problem and then go into how you have addressed it, this will make the change that much more impactful.

+

Presentation

+

Live demos are always best, it proves to your audience that it actually works and that there's no smoke and mirrors hiding flaws. However, there are cases where live demos don't work out. Maybe you have a very slow running process, or your code just decides it's not going to work that day.

+

For slow processes, explain that it's slow and why, and let the audience know how you've addressed it in the demo to set the right expectations.

+

Here are some methods:

+
    +
  1. Run the process before starting the demo in another tab/instance/device, and switch to that when you need to show what happens after it.
  2. +
  3. Do something else while it's running, e.g. talk about some other detail in your presentation.
  4. +
  5. Pre-record the whole demo and speed up or cut out the slow parts.
  6. +
+

It's a good idea to have a well-edited pre-recorded demo to switch to as well, sometimes code just decides not to work!

+

Make sure you've practiced talking over the pre-recorded demo as well as the live demo so you're prepared for all cases, including switching from live to recorded halfway through.

+

Avoid Distractions

+

It's not the end of the world, but a notification popping up on your screen is distracting to the audience.

+

It's best to fully close all unneeded apps, turn on do-not-disturb, and full-screen what you're presenting.

+

This also goes for browser tabs and bookmarks, have everything as clean and empty as possible so all the focus is on what you're presenting.

+

Use Virtual Desktops on Windows and full-screen apps on MacOS. Place your presentation in one, and the demo in another, that way you can quickly and seamlessly switch between the two without alt-tabbing or exiting the presentation.

+

Prepare

+

Most importantly, rehearse the demo! Go through everything you want to show off, and have a good idea of what you want to say. It doesn't need to be perfectly memorized, but you should know exactly what you're doing next all the time. If you're working with a team, and one person is speaking and the other controlling the demo, make sure both of you are in sync. If you say "looking at the user profile page", the demo should immediately go there, without you having to ask your partner to do things which breaks the flow.

+

Finally, if (and when) something goes wrong, the best thing to do is to move past it. Bringing more attention to an issue can make it seem worse than it is. If things are really bad (app fully crashes, laptop catches fire), you have a recorded demo to switch to. Right?

+

References/Further Reading

+

How to create great tech demos and presentations - Thomas Maurer

+

13 Demoing Strategies That Make Tech Software Compelling

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/guides/UI_UX_Design_Guide/images/component.png b/guides/UI_UX_Design_Guide/images/component.png new file mode 100644 index 0000000..255e9b3 Binary files /dev/null and b/guides/UI_UX_Design_Guide/images/component.png differ diff --git a/guides/UI_UX_Design_Guide/images/designdocumentation.png b/guides/UI_UX_Design_Guide/images/designdocumentation.png new file mode 100644 index 0000000..ba033b4 Binary files /dev/null and b/guides/UI_UX_Design_Guide/images/designdocumentation.png differ diff --git a/guides/UI_UX_Design_Guide/images/doublediamond.jpeg b/guides/UI_UX_Design_Guide/images/doublediamond.jpeg new file mode 100644 index 0000000..5e76f0c Binary files /dev/null and b/guides/UI_UX_Design_Guide/images/doublediamond.jpeg differ diff --git a/guides/UI_UX_Design_Guide/images/figmascreen.png b/guides/UI_UX_Design_Guide/images/figmascreen.png new file mode 100644 index 0000000..24e4c46 Binary files /dev/null and b/guides/UI_UX_Design_Guide/images/figmascreen.png differ diff --git a/guides/UI_UX_Design_Guide/images/grid.png b/guides/UI_UX_Design_Guide/images/grid.png new file mode 100644 index 0000000..2e3d538 Binary files /dev/null and b/guides/UI_UX_Design_Guide/images/grid.png differ diff --git a/guides/UI_UX_Design_Guide/images/researchmethods.png b/guides/UI_UX_Design_Guide/images/researchmethods.png new file mode 100644 index 0000000..13e2adf Binary files /dev/null and b/guides/UI_UX_Design_Guide/images/researchmethods.png differ diff --git a/guides/UI_UX_Design_Guide/index.html b/guides/UI_UX_Design_Guide/index.html new file mode 100644 index 0000000..7d86004 --- /dev/null +++ b/guides/UI_UX_Design_Guide/index.html @@ -0,0 +1,403 @@ + + + + + + UI/UX Design - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

UI/UX Design Guide

+

Welcome to Tech Start’s UI/UX design guide, your roadmap to mastering the art of crafting user-friendly and visually appealing digital experiences!

+

Our goal is simple: to provide you with the tools and guidance necessary to understand the principles of effective design and apply them to your projects. Instead of overwhelming you with tutorials, we've curated a selection of online resources that cover everything from the basics to advanced techniques.

+

While this guide is a good starting point, there's a ton of resources available online. Everyone learns differently, so we encourage you to explore and find what methods work best for you!

+

Enjoy the guide and have fun designing! :)

+
+

Table of Contents

+ +
+

Design Process

+

Purpose: a design process helps you break down a project into manageable chunks and gives your work structure.

+

Terms like “design thinking” and “human-centered design” all boil down to the idea of understanding the needs and behaviors of users, and translating that understanding into a well-designed interface. So, keep the user front and center in your design approach!

+

There’s various design processes out there but we recommend using the double diamond design process.

+

The double diamond design process has 4 stages:

+
    +
  1. Discover
  2. +
  3. Define
  4. +
  5. Develop
  6. +
  7. Deliver
  8. +
+

Note: this design process is not linear— it’s iterative. That means you may be revisiting certain stages to tweak and improve your designs as you work through the process.

+

alt_text

+
+

We recommend taking a look at the following resources to get started:

+ +
+

Tasks to do at each stage/ Methods to use

+

As you make your way through the design process there’s various tasks/ methods you may use at each stage.

+

Discover phase:

+
    +
  • Competitive analysis
  • +
  • User research
  • +
+

Define phase(at this stage you’ll be synthesizing your user research findings):

+
    +
  • Affinity mapping
  • +
  • Empathy mapping
  • +
  • Form a problem statement and How Might We (HMW) questions
  • +
  • Ideate potential solutions
  • +
  • Product Requirement Doc (PRD)
  • +
+

Note: to make your work easier, use FigJam templates to do the tasks for this phase.

+

Here’s some great FigJam Templates:

+ +

Develop phase:

+
    +
  • User flows & site maps
  • +
  • Wireframes & low-fidelity prototypes
  • +
  • User testing prototypes and iterating on your designs based on user feedback
  • +
+

Here’s some great FigJam Templates:

+ +

Deliver phase:

+
    +
  • High-fidelity prototypes (in Figma)
  • +
+

Below are some great resources to get you started with the tasks/ methods:

+ +
+

User Research

+

Purpose: user research is conducted to understand user needs and preferences— it’ll ensure that your designs are intuitive and meet user expectations.

+

User research happens throughout the design process and there’s different methods you can use at each stage. Some user research methods provide qualitative data (like user interviews) and others may provide more quantitative data (like close-ended surveys). Choosing which research method to use depends on various things like time availability, your research goals, type of product you’re building, etc.

+

alt_text

+

We recommend starting with simple methods such as surveys and user interviews.

+

Best practices to keep in mind for your research questions:

+
    +
  • Keep it short (5-10 questions)
  • +
  • Keep it simple (use clear and concise language)
  • +
  • Avoid leading questions
  • +
+

Best practices to keep in mind for user interviews:

+
    +
  • Use active listing techniques (build rapport with the participant, ask relevant follow-up questions)
  • +
  • Record & transcribe your interviews
  • +
+

Here’s an example of what a good survey question may look like:

+
    +
  • What problems do you face while trying to do [task]? (select all that apply)
  • +
+

Here’s some examples of what good user interview questions may look like:

+
    +
  • How do you currently go about doing [task]?
  • +
  • What do you like about how you currently perform [task]?
  • +
  • What is the biggest pain point when performing [task]?
  • +
+

Below are some great resources to get started with user research:

+ +
+

Usability Testing

+

Purpose: usability testing will identify and address any usability issues— it’ll ensure your designs are intuitive and easy to use for its intended audience.

+

Once you have a working prototype, you’ll want to test that with users to get feedback on your designs.

+

With your usability testing, focus on exploratory tasks where you give users a realistic scenario and tasks to perform. For example, you could ask the user “add an item to your cart”, or “find an event to attend”. You want to see if (and where) users may get stuck doing a task— this will let you know which part of your design needs more work.

+

NOTE: testing with at least 5 users will give you sufficient feedback on your designs (these users can be fellow students, etc.)

+

Resources to get your started:

+ +
+

Working in Figma

+

Purpose: use Figma to create your low and high fidelity prototypes that you can share with your team.

+

Figma's official website offers a ton of learning resources to guide you on your Figma learning journey!

+

alt_text

+

An important consideration as you work on your designs is to share your Figma file with your team members to get feedback on the technical feasibility of your designs.

+

Resources to get started with Figma:

+ +
+

Knowing how to use various things in Figma like: components, auto layout, and grids will help you design more efficiently.

+
+

Using Components

+

“Components are elements you can reuse across your designs. They help to create and manage consistent designs across projects.” - Figma

+

alt_text

+

Here’s a great resource to get your stated:

+ +
+

Using Auto Layout

+

Auto layout is important for creating responsive interfaces. “It lets you create designs that grow to fill or shrink to fit, and reflow as their contents change” - Figma

+

Resources for learning auto layout:

+ +
+

Using Grids

+

Using grids will provide visual structure to your designs. They’ll make your designs look clean & organized.

+

alt_text

+

Here’s a good rule of thumb to follow for designing layouts for different screen sizes:

+
    +
  • For desktops - 12 columns
  • +
  • For tablets - 8 columns
  • +
  • For mobile devices - 4 columns
  • +
+

Resources to learn more:

+ +
+

Other Resources

+

There’s various Figma plugins, UI kits, and other resources you can use to make your workflow easier.

+

What you use will depend on your needs & project— so feel free to find ones suited for you!

+

Here’s an example of a plugin for Figma:

+ +

Figma community is also a great resource for finding templates, plugins and UI kits.

+

Also, for a more comprehensive guide on design methods, take a look at this article.

+
+

Other Design Considerations

+

Where to Look for Inspiration

+

You might want to look at existing user interfaces to get inspiration for your own project. We recommend the following resources:

+
    +
  • Dribbble
  • +
  • Behance
  • +
  • Scope existing platforms that are similar to your app that have good UI/UX & take inspo from their designs
  • +
+
+

Design Documentation

+

It’s essential to document your designs. It’ll help you communicate the specifics of your designs with your team members and others.

+

Below is a good example of a card that documents the design of a screen. Your major screens and user flows should be documented.

+

alt_text

+
+

Accessibility and Inclusion in Design

+

Here’s something important to keep in mind as you design. You want to ensure that everyone can use your designs— regardless of their abilities.

+

That means using colors, typography, etc. that are accessible to all users.

+

Here’s a great article to get started: Accessibility Guidelines for UX Designers

+
+

That’s all for now! :)

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/guides/Web_Dev_Guide/images/image1.png b/guides/Web_Dev_Guide/images/image1.png new file mode 100644 index 0000000..3efb287 Binary files /dev/null and b/guides/Web_Dev_Guide/images/image1.png differ diff --git a/guides/Web_Dev_Guide/images/image2.png b/guides/Web_Dev_Guide/images/image2.png new file mode 100644 index 0000000..2793bfa Binary files /dev/null and b/guides/Web_Dev_Guide/images/image2.png differ diff --git a/guides/Web_Dev_Guide/images/image3.png b/guides/Web_Dev_Guide/images/image3.png new file mode 100644 index 0000000..53c2d49 Binary files /dev/null and b/guides/Web_Dev_Guide/images/image3.png differ diff --git a/guides/Web_Dev_Guide/images/image4.png b/guides/Web_Dev_Guide/images/image4.png new file mode 100644 index 0000000..2b86ff9 Binary files /dev/null and b/guides/Web_Dev_Guide/images/image4.png differ diff --git a/guides/Web_Dev_Guide/images/image5.png b/guides/Web_Dev_Guide/images/image5.png new file mode 100644 index 0000000..23087c6 Binary files /dev/null and b/guides/Web_Dev_Guide/images/image5.png differ diff --git a/guides/Web_Dev_Guide/images/image6.png b/guides/Web_Dev_Guide/images/image6.png new file mode 100644 index 0000000..8453ca8 Binary files /dev/null and b/guides/Web_Dev_Guide/images/image6.png differ diff --git a/guides/Web_Dev_Guide/images/image7.png b/guides/Web_Dev_Guide/images/image7.png new file mode 100644 index 0000000..677009d Binary files /dev/null and b/guides/Web_Dev_Guide/images/image7.png differ diff --git a/guides/Web_Dev_Guide/images/image8.png b/guides/Web_Dev_Guide/images/image8.png new file mode 100644 index 0000000..48a0360 Binary files /dev/null and b/guides/Web_Dev_Guide/images/image8.png differ diff --git a/guides/Web_Dev_Guide/index.html b/guides/Web_Dev_Guide/index.html new file mode 100644 index 0000000..eafa005 --- /dev/null +++ b/guides/Web_Dev_Guide/index.html @@ -0,0 +1,305 @@ + + + + + + Web Dev - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+
+
+
+

Tech Start's Super Awesome Mega Web Dev Guide:)

+

Want to get into web dev? This guide should be your best friend. It covers some of the basic tools and languages you'll need to dive into the world of web development. Rather than providing tutorials, this guide focuses on directing you towards the best free online content to teach you the fundamentals.

+

Our advice:

+
    +
  • Go through at your own pace! You may need to spend more or less time on a particular topic depending on your experience level.
  • +
  • Build practice websites and apps as you learn - you learn by doing.
  • +
  • Take your own notes, especially for problems you encounter frequently
  • +
  • Go beyond this guide! Tons of resources, courses, and tutorials are out there if you want to learn. Remember: google is a programmer's best friend.
  • +
+

This guide was originally developed for Tech Start UCalgary, an undergraduate club for software development and entrepreneurship at the University of Calgary. Check us out here -----> https://linktr.ee/techstartuofc <-----

+

Or at our website here ---> https://techstartucalgary.com <-----

+

If you're interested in contributing to this guide or in building similar guides for other areas (like Git, project management, or mobile development), please send me an email at joel.happ1@ucalgary.ca

+

Good luck on your web dev journey and enjoy the guide!

+

Part 1 - HTML

+

HTML is the building block of all webpages. It's ubiquitous throughout application design - everything from websites to mobile apps to desktop apps use HTML as the base for their frontend.

+

alt_text

+

Luckily for you, HTML is also very simple. Don't spend too much time learning it as a beginner - while more advanced HTML concepts do exist, all you need to get started is a basic understanding of how it works.

+

To get started, I recommend watching this video and experimenting by building your own HTML document alongside it: https://www.youtube.com/watch?v=UB1O30fR-EE

+

To generate a favicon for your site, use this site: https://realfavicongenerator.net/

+

No matter which text editor you use (Atom, VSCode, Sublime Text, or something else), I recommend searching for editor plugins to improve your experience writing HTML. Google is your friend here.

+

Part 2 - CSS

+

If HTML is the backbone of frontends, CSS is the paint. It's an extremely versatile and powerful way of styling and beautifying your content. CSS is easy to get into, but very difficult to master- if front-end development interests you, I recommend dedicating a significant amount of time towards learning CSS.

+

alt_text

+

To get started, check out this 1 hour introductory video to CSS:

+

https://www.youtube.com/watch?v=yfoY53QXEnI

+

Another alternative is this free course on Scrimba, which also covers HTML: https://scrimba.com/learn/htmlcss

+

One topic that isn't covered in much detail in the previous video is CSS selectors. For most purposes, you'll probably want to keep your selectors simple (using only class names the vast majority of the time). If you want to learn more about advanced selectors, check out this video: https://www.youtube.com/watch?v=Bcr70LIJcOk

+

When working on projects with other people, I recommend avoiding element-level selectors, as they can easily screw with work that others are doing.

+

Once you have a good grasp of the basics of CSS, one area that I highly recommend learning is CSS Grid. CSS Grid is a fantastic way of organizing and positioning html content, and it comes with loads of features that make it easy to build adaptive web pages. By combining CSS Grid with CSS breakpoints, you can design interfaces that look great on any size of screen, whether it's a big desktop computer or a small mobile phone.

+

Highly recommended course for CSS Grid: https://scrimba.com/learn/cssgrid

+

(Warning: CSS grid is not supported by some outdated browsers and browsers like Opera Mini which are used mostly in third world countries to save data. If your intended audience includes these people, do not use CSS Grid.)

+

How should you organize and refactor your CSS? I recommend using the BEM strategy for your CSS selectors. https://css-tricks.com/bem-101/

+

BEM is a particularly helpful methodology to adopt when you're building websites from components like in React, since you can keep the CSS for each component in a separate file. However, it's far from the only strategy for CSS organization, so you can research and adopt others if they suit your needs better.

+

Knowing CSS Flexbox is also helpful for arranging the layouts of websites. It's like

+

Finally, here is a great video to watch for some simple, powerful tips for writing modern CSS:

+

https://www.youtube.com/watch?v=Qhaz36TZG5Y

+

+

Part 3 - Javascript

+

JavaScript drives the interactivity and functionality of websites. Using it, you can respond to the user's interactions on your website and you can modify the properties of your HTML dynamically.

+

alt_text

+

To get started with JavaScript, you can watch this playlist: https://www.youtube.com/playlist?list=PLDyQo7g0_nsX8_gZAB8KD1lL4j4halQBJ

+

If you're brand new to programming, you should spend more time learning the fundamentals of JavaScript.

+

There are a few areas of JavaScript which may be confusing to any newcomers to the language, even if you have previously learned other languages. I recommend practicing and studying to get used to these features.

+

Array functions: https://www.youtube.com/watch?v=rRgD1yVwIvE

+

_Asynchronous JavaScript (Await, Promises, Callbacks): _https://www.youtube.com/watch?v=_8gHHBlbziw

+

_JSON (JavaScript object notation): _https://www.youtube.com/watch?v=wI1CWzNtE-M

+

If you encounter another area of JavaScript that gives you troubles let me know and I'll add a section to this guide.

+

3.1 Node.js

+

alt_text

+

Here's an introduction to Node.js: JavaScript, but for your operating system instead of your browser. https://www.youtube.com/watch?v=ENrzD9HAZK4 Node.js is frequently used as the backend for the server side of an application or web app.

+

Installing Node.js

+

We recommend using NVM (node version manager) to install node.js. It allows you to install, uninstall, and switch between different versions of node.js very quickly. Often, you'll need to switch between different versions of node for different projects, so you'll save time by using nvm from the start.

+

NVM (Mac/Linux): https://github.com/nvm-sh/nvm

+

NVM for windows: https://github.com/coreybutler/nvm-windows

+

Once installed, you can type "nvm" in your CLI to see a red list of commands you can use. Follow instructions on GitHub for proper usage!

+

Express

+

One of the most common Node.js frameworks is Express. Express is an unopinionated_ (meaning, it doesn't force you to do things any particular way) _framework that excels at allowing you to write APIs. We may include more content on Express here in the future.

+

alt_text

+

+

3.2** TypeScript**

+

TypeScript is a superset of Javascript that introduces new features mostly related to strong typing: this lets you safeguard your variables and functions and helps you catch the most frequent mistakes and bugs from JavaScript code.

+

alt_text

+

TypeScript is contained in .ts files, and using a compiler you can compile it into vanilla JavaScript .js files which run as expected on a computer. If you anticipate doing a lot of work with JavaScript, I highly recommend learning TypeScript - although it isn't necessary for every project, it immensely improves the quality of the coding experience and it can guide you towards mastering tricky concepts from JavaScript like promises and callbacks.

+

TypeScript tutorial by NetNinja:

+

https://www.youtube.com/playlist?list=PL4cUxeGkcC9gUgr39Q_yD6v-bSyMwKPUI

+

TypeScript Basics by JavaBrains: (also includes small project incl. API usage)

+

https://www.youtube.com/playlist?list=PLqq-6Pq4lTTanfgsbnFzfWUhhAz3tIezU

+

+

Part 4 - React

+

NOTE: here is a more indepth React Guide, the better version!!

+

HTML, CSS, and JS are great and all, but what if you want to make a modern, reactive website? Several frontend frameworks exist to empower dynamic, reactive sites, and as of 2021 React is by far the most popular among them. It's a great way to get an introduction into the world of web frameworks and it's a fun tool to use.

+

alt_text

+

Here's a good free overview of the basics of React: https://scrimba.com/learn/learnreact

+

Plenty of similar courses are available on YouTube and other course platforms.

+

When in doubt, consult the React documentation: https://reactjs.org/docs/

+

Note that much of the documentation still uses class-based components, as opposed to function-based components. Nowadays, it is 99% preferable to use function-based components whenever possible. It cuts down on the amount of boilerplate you need to write and enables helpful features from hooks.

+

Learn more about React Hooks: https://www.youtube.com/watch?v=TNhaISOUy6Q

+

The 2 hooks in particular you should be very familiar with:

+
    +
  • **useState - **for basic state/data management
  • +
  • useEffect - ubiquitous in React. It is used for creating consequences ("effects") for changes in data. It's a critical part of designing React applications to have a functional (not object-oriented) architecture, and you should be using it to create custom hooks.
  • +
+

Other hooks that are handy to know about are useRef, useCallback, and useLayoutEffect.

+

To learn React, you should know HTML, CSS, and JS before. You can also build React apps with TypeScript instead of JavaScript. https://www.typescriptlang.org/docs/handbook/react.html

+

React Context API

+

The context API is a tool you can use in React to share state from an upper level component (a provider) to its children. If you have state that needs to be shared across many children, you can use the context API rather than pass everything down manually as props.

+

To learn about the context API, I recommend watching this video:

+

https://www.youtube.com/watch?v=35lXWvCuM8o

+

**React Router **

+

If you want to make React websites with multiple pages, you can use React Router. It is a package that enables your app to have multiple routes. This series gives a quick overview of React Router:

+

https://www.youtube.com/watch?v=aZGzwEjZrXc&list=PL4cUxeGkcC9gZD-Tvwfod2gaISzfRiP9d&index=21

+

React Router is lightweight and best suited for very small projects. If you plan on building a larger website with React, we recommend using Next.js instead - it has a lot more features including pre-rendering pages on the server for SEO optimization. Next.js is also widely used and has industry-level support.

+

alt_text

+

React Redux is a commonly used package for managing global state. It allows you to take care of state in a global store that can be accessed or modified from anywhere in your application.

+

https://www.youtube.com/watch?v=CVpUuw9XSjY

+

Using React with Typescript

+

Here is a great cheatsheet that you should read to get started with using React in combination with Typescript:

+

https://github.com/typescript-cheatsheets/react

+

That's it! .. for now :)

+

Happy hacking!

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/guides/html2Markdown.py b/guides/html2Markdown.py new file mode 100644 index 0000000..b7218d9 --- /dev/null +++ b/guides/html2Markdown.py @@ -0,0 +1,20 @@ + +# import markdownify +import markdownify + + +def get_content(path): + with open(path) as f: + raw = f.read() + return raw + +html = get_content('./Django_Guide/DjangoGuide.html') +print(html) + +# convert html to markdown +h = markdownify.markdownify(html, heading_style="ATX", code_language="python", heading_style_level=2) + +with open('./Django_Guide/DjangoGuide.md', "w", encoding="utf-8") as f: + f.write(h) +f.close() + diff --git a/highlight.css b/highlight.css new file mode 100644 index 0000000..ba57b82 --- /dev/null +++ b/highlight.css @@ -0,0 +1,82 @@ +/* + * An increased contrast highlighting scheme loosely based on the + * "Base16 Atelier Dune Light" theme by Bram de Haan + * (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) + * Original Base16 color scheme by Chris Kempson + * (https://github.com/chriskempson/base16) + */ + +/* Comment */ +.hljs-comment, +.hljs-quote { + color: #575757; +} + +/* Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #d70025; +} + +/* Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #b21e00; +} + +/* Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #008200; +} + +/* Blue */ +.hljs-title, +.hljs-section { + color: #0030f2; +} + +/* Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #9d00ec; +} + +.hljs { + display: block; + overflow-x: auto; + background: #f6f7f6; + color: #000; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-addition { + color: #22863a; + background-color: #f0fff4; +} + +.hljs-deletion { + color: #b31d28; + background-color: #ffeef0; +} diff --git a/highlight.js b/highlight.js new file mode 100644 index 0000000..180385b --- /dev/null +++ b/highlight.js @@ -0,0 +1,6 @@ +/* + Highlight.js 10.1.1 (93fd0d73) + License: BSD-3-Clause + Copyright (c) 2006-2020, Ivan Sagalaev +*/ +var hljs=function(){"use strict";function e(n){Object.freeze(n);var t="function"==typeof n;return Object.getOwnPropertyNames(n).forEach((function(r){!Object.hasOwnProperty.call(n,r)||null===n[r]||"object"!=typeof n[r]&&"function"!=typeof n[r]||t&&("caller"===r||"callee"===r||"arguments"===r)||Object.isFrozen(n[r])||e(n[r])})),n}class n{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data}ignoreMatch(){this.ignore=!0}}function t(e){return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function r(e,...n){var t={};for(const n in e)t[n]=e[n];return n.forEach((function(e){for(const n in e)t[n]=e[n]})),t}function a(e){return e.nodeName.toLowerCase()}var i=Object.freeze({__proto__:null,escapeHTML:t,inherit:r,nodeStream:function(e){var n=[];return function e(t,r){for(var i=t.firstChild;i;i=i.nextSibling)3===i.nodeType?r+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:r,node:i}),r=e(i,r),a(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:r,node:i}));return r}(e,0),n},mergeStreams:function(e,n,r){var i=0,s="",o=[];function l(){return e.length&&n.length?e[0].offset!==n[0].offset?e[0].offset"}function u(e){s+=""}function d(e){("start"===e.event?c:u)(e.node)}for(;e.length||n.length;){var g=l();if(s+=t(r.substring(i,g[0].offset)),i=g[0].offset,g===e){o.reverse().forEach(u);do{d(g.splice(0,1)[0]),g=l()}while(g===e&&g.length&&g[0].offset===i);o.reverse().forEach(c)}else"start"===g[0].event?o.push(g[0].node):o.pop(),d(g.splice(0,1)[0])}return s+t(r.substr(i))}});const s="",o=e=>!!e.kind;class l{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){this.buffer+=t(e)}openNode(e){if(!o(e))return;let n=e.kind;e.sublanguage||(n=`${this.classPrefix}${n}`),this.span(n)}closeNode(e){o(e)&&(this.buffer+=s)}value(){return this.buffer}span(e){this.buffer+=``}}class c{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){this.top.children.push(e)}openNode(e){const n={kind:e,children:[]};this.add(n),this.stack.push(n)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),n.children.forEach(n=>this._walk(e,n)),e.closeNode(n)),e}static _collapse(e){"string"!=typeof e&&e.children&&(e.children.every(e=>"string"==typeof e)?e.children=[e.children.join("")]:e.children.forEach(e=>{c._collapse(e)}))}}class u extends c{constructor(e){super(),this.options=e}addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){return new l(this,this.options).value()}finalize(){return!0}}function d(e){return e?"string"==typeof e?e:e.source:null}const g="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",h={begin:"\\\\[\\s\\S]",relevance:0},f={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[h]},p={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[h]},b={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},m=function(e,n,t={}){var a=r({className:"comment",begin:e,end:n,contains:[]},t);return a.contains.push(b),a.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),a},v=m("//","$"),x=m("/\\*","\\*/"),E=m("#","$");var _=Object.freeze({__proto__:null,IDENT_RE:"[a-zA-Z]\\w*",UNDERSCORE_IDENT_RE:"[a-zA-Z_]\\w*",NUMBER_RE:"\\b\\d+(\\.\\d+)?",C_NUMBER_RE:g,BINARY_NUMBER_RE:"\\b(0b[01]+)",RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",SHEBANG:(e={})=>{const n=/^#![ ]*\//;return e.binary&&(e.begin=function(...e){return e.map(e=>d(e)).join("")}(n,/.*\b/,e.binary,/\b.*/)),r({className:"meta",begin:n,end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)},BACKSLASH_ESCAPE:h,APOS_STRING_MODE:f,QUOTE_STRING_MODE:p,PHRASAL_WORDS_MODE:b,COMMENT:m,C_LINE_COMMENT_MODE:v,C_BLOCK_COMMENT_MODE:x,HASH_COMMENT_MODE:E,NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?",relevance:0},C_NUMBER_MODE:{className:"number",begin:g,relevance:0},BINARY_NUMBER_MODE:{className:"number",begin:"\\b(0b[01]+)",relevance:0},CSS_NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[h,{begin:/\[/,end:/\]/,relevance:0,contains:[h]}]}]},TITLE_MODE:{className:"title",begin:"[a-zA-Z]\\w*",relevance:0},UNDERSCORE_TITLE_MODE:{className:"title",begin:"[a-zA-Z_]\\w*",relevance:0},METHOD_GUARD:{begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:function(e){return Object.assign(e,{"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{n.data._beginMatch!==e[1]&&n.ignoreMatch()}})}}),N="of and for in not or if then".split(" ");function w(e,n){return n?+n:function(e){return N.includes(e.toLowerCase())}(e)?0:1}const R=t,y=r,{nodeStream:k,mergeStreams:O}=i,M=Symbol("nomatch");return function(t){var a=[],i={},s={},o=[],l=!0,c=/(^(<[^>]+>|\t|)+|\n)/gm,g="Could not find the language '{}', did you forget to load/include a language module?";const h={disableAutodetect:!0,name:"Plain text",contains:[]};var f={noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:null,__emitter:u};function p(e){return f.noHighlightRe.test(e)}function b(e,n,t,r){var a={code:n,language:e};S("before:highlight",a);var i=a.result?a.result:m(a.language,a.code,t,r);return i.code=a.code,S("after:highlight",i),i}function m(e,t,a,s){var o=t;function c(e,n){var t=E.case_insensitive?n[0].toLowerCase():n[0];return Object.prototype.hasOwnProperty.call(e.keywords,t)&&e.keywords[t]}function u(){null!=y.subLanguage?function(){if(""!==A){var e=null;if("string"==typeof y.subLanguage){if(!i[y.subLanguage])return void O.addText(A);e=m(y.subLanguage,A,!0,k[y.subLanguage]),k[y.subLanguage]=e.top}else e=v(A,y.subLanguage.length?y.subLanguage:null);y.relevance>0&&(I+=e.relevance),O.addSublanguage(e.emitter,e.language)}}():function(){if(!y.keywords)return void O.addText(A);let e=0;y.keywordPatternRe.lastIndex=0;let n=y.keywordPatternRe.exec(A),t="";for(;n;){t+=A.substring(e,n.index);const r=c(y,n);if(r){const[e,a]=r;O.addText(t),t="",I+=a,O.addKeyword(n[0],e)}else t+=n[0];e=y.keywordPatternRe.lastIndex,n=y.keywordPatternRe.exec(A)}t+=A.substr(e),O.addText(t)}(),A=""}function h(e){return e.className&&O.openNode(e.className),y=Object.create(e,{parent:{value:y}})}function p(e){return 0===y.matcher.regexIndex?(A+=e[0],1):(L=!0,0)}var b={};function x(t,r){var i=r&&r[0];if(A+=t,null==i)return u(),0;if("begin"===b.type&&"end"===r.type&&b.index===r.index&&""===i){if(A+=o.slice(r.index,r.index+1),!l){const n=Error("0 width match regex");throw n.languageName=e,n.badRule=b.rule,n}return 1}if(b=r,"begin"===r.type)return function(e){var t=e[0],r=e.rule;const a=new n(r),i=[r.__beforeBegin,r["on:begin"]];for(const n of i)if(n&&(n(e,a),a.ignore))return p(t);return r&&r.endSameAsBegin&&(r.endRe=RegExp(t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")),r.skip?A+=t:(r.excludeBegin&&(A+=t),u(),r.returnBegin||r.excludeBegin||(A=t)),h(r),r.returnBegin?0:t.length}(r);if("illegal"===r.type&&!a){const e=Error('Illegal lexeme "'+i+'" for mode "'+(y.className||"")+'"');throw e.mode=y,e}if("end"===r.type){var s=function(e){var t=e[0],r=o.substr(e.index),a=function e(t,r,a){let i=function(e,n){var t=e&&e.exec(n);return t&&0===t.index}(t.endRe,a);if(i){if(t["on:end"]){const e=new n(t);t["on:end"](r,e),e.ignore&&(i=!1)}if(i){for(;t.endsParent&&t.parent;)t=t.parent;return t}}if(t.endsWithParent)return e(t.parent,r,a)}(y,e,r);if(!a)return M;var i=y;i.skip?A+=t:(i.returnEnd||i.excludeEnd||(A+=t),u(),i.excludeEnd&&(A=t));do{y.className&&O.closeNode(),y.skip||y.subLanguage||(I+=y.relevance),y=y.parent}while(y!==a.parent);return a.starts&&(a.endSameAsBegin&&(a.starts.endRe=a.endRe),h(a.starts)),i.returnEnd?0:t.length}(r);if(s!==M)return s}if("illegal"===r.type&&""===i)return 1;if(B>1e5&&B>3*r.index)throw Error("potential infinite loop, way more iterations than matches");return A+=i,i.length}var E=T(e);if(!E)throw console.error(g.replace("{}",e)),Error('Unknown language: "'+e+'"');var _=function(e){function n(n,t){return RegExp(d(n),"m"+(e.case_insensitive?"i":"")+(t?"g":""))}class t{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(e,n){n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),this.matchAt+=function(e){return RegExp(e.toString()+"|").exec("").length-1}(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);const e=this.regexes.map(e=>e[1]);this.matcherRe=n(function(e,n="|"){for(var t=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./,r=0,a="",i=0;i0&&(a+=n),a+="(";o.length>0;){var l=t.exec(o);if(null==l){a+=o;break}a+=o.substring(0,l.index),o=o.substring(l.index+l[0].length),"\\"===l[0][0]&&l[1]?a+="\\"+(+l[1]+s):(a+=l[0],"("===l[0]&&r++)}a+=")"}return a}(e),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex;const n=this.matcherRe.exec(e);if(!n)return null;const t=n.findIndex((e,n)=>n>0&&void 0!==e),r=this.matchIndexes[t];return n.splice(0,t),Object.assign(n,r)}}class a{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t;return this.rules.slice(e).forEach(([e,t])=>n.addRule(e,t)),n.compile(),this.multiRegexes[e]=n,n}considerAll(){this.regexIndex=0}addRule(e,n){this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex;const t=n.exec(e);return t&&(this.regexIndex+=t.position+1,this.regexIndex===this.count&&(this.regexIndex=0)),t}}function i(e,n){const t=e.input[e.index-1],r=e.input[e.index+e[0].length];"."!==t&&"."!==r||n.ignoreMatch()}if(e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return function t(s,o){const l=s;if(s.compiled)return l;s.compiled=!0,s.__beforeBegin=null,s.keywords=s.keywords||s.beginKeywords;let c=null;if("object"==typeof s.keywords&&(c=s.keywords.$pattern,delete s.keywords.$pattern),s.keywords&&(s.keywords=function(e,n){var t={};return"string"==typeof e?r("keyword",e):Object.keys(e).forEach((function(n){r(n,e[n])})),t;function r(e,r){n&&(r=r.toLowerCase()),r.split(" ").forEach((function(n){var r=n.split("|");t[r[0]]=[e,w(r[0],r[1])]}))}}(s.keywords,e.case_insensitive)),s.lexemes&&c)throw Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ");return l.keywordPatternRe=n(s.lexemes||c||/\w+/,!0),o&&(s.beginKeywords&&(s.begin="\\b("+s.beginKeywords.split(" ").join("|")+")(?=\\b|\\s)",s.__beforeBegin=i),s.begin||(s.begin=/\B|\b/),l.beginRe=n(s.begin),s.endSameAsBegin&&(s.end=s.begin),s.end||s.endsWithParent||(s.end=/\B|\b/),s.end&&(l.endRe=n(s.end)),l.terminator_end=d(s.end)||"",s.endsWithParent&&o.terminator_end&&(l.terminator_end+=(s.end?"|":"")+o.terminator_end)),s.illegal&&(l.illegalRe=n(s.illegal)),void 0===s.relevance&&(s.relevance=1),s.contains||(s.contains=[]),s.contains=[].concat(...s.contains.map((function(e){return function(e){return e.variants&&!e.cached_variants&&(e.cached_variants=e.variants.map((function(n){return r(e,{variants:null},n)}))),e.cached_variants?e.cached_variants:function e(n){return!!n&&(n.endsWithParent||e(n.starts))}(e)?r(e,{starts:e.starts?r(e.starts):null}):Object.isFrozen(e)?r(e):e}("self"===e?s:e)}))),s.contains.forEach((function(e){t(e,l)})),s.starts&&t(s.starts,o),l.matcher=function(e){const n=new a;return e.contains.forEach(e=>n.addRule(e.begin,{rule:e,type:"begin"})),e.terminator_end&&n.addRule(e.terminator_end,{type:"end"}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n}(l),l}(e)}(E),N="",y=s||_,k={},O=new f.__emitter(f);!function(){for(var e=[],n=y;n!==E;n=n.parent)n.className&&e.unshift(n.className);e.forEach(e=>O.openNode(e))}();var A="",I=0,S=0,B=0,L=!1;try{for(y.matcher.considerAll();;){B++,L?L=!1:(y.matcher.lastIndex=S,y.matcher.considerAll());const e=y.matcher.exec(o);if(!e)break;const n=x(o.substring(S,e.index),e);S=e.index+n}return x(o.substr(S)),O.closeAllNodes(),O.finalize(),N=O.toHTML(),{relevance:I,value:N,language:e,illegal:!1,emitter:O,top:y}}catch(n){if(n.message&&n.message.includes("Illegal"))return{illegal:!0,illegalBy:{msg:n.message,context:o.slice(S-100,S+100),mode:n.mode},sofar:N,relevance:0,value:R(o),emitter:O};if(l)return{illegal:!1,relevance:0,value:R(o),emitter:O,language:e,top:y,errorRaised:n};throw n}}function v(e,n){n=n||f.languages||Object.keys(i);var t=function(e){const n={relevance:0,emitter:new f.__emitter(f),value:R(e),illegal:!1,top:h};return n.emitter.addText(e),n}(e),r=t;return n.filter(T).filter(I).forEach((function(n){var a=m(n,e,!1);a.language=n,a.relevance>r.relevance&&(r=a),a.relevance>t.relevance&&(r=t,t=a)})),r.language&&(t.second_best=r),t}function x(e){return f.tabReplace||f.useBR?e.replace(c,e=>"\n"===e?f.useBR?"
":e:f.tabReplace?e.replace(/\t/g,f.tabReplace):e):e}function E(e){let n=null;const t=function(e){var n=e.className+" ";n+=e.parentNode?e.parentNode.className:"";const t=f.languageDetectRe.exec(n);if(t){var r=T(t[1]);return r||(console.warn(g.replace("{}",t[1])),console.warn("Falling back to no-highlight mode for this block.",e)),r?t[1]:"no-highlight"}return n.split(/\s+/).find(e=>p(e)||T(e))}(e);if(p(t))return;S("before:highlightBlock",{block:e,language:t}),f.useBR?(n=document.createElement("div")).innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n"):n=e;const r=n.textContent,a=t?b(t,r,!0):v(r),i=k(n);if(i.length){const e=document.createElement("div");e.innerHTML=a.value,a.value=O(i,k(e),r)}a.value=x(a.value),S("after:highlightBlock",{block:e,result:a}),e.innerHTML=a.value,e.className=function(e,n,t){var r=n?s[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),e.includes(r)||a.push(r),a.join(" ").trim()}(e.className,t,a.language),e.result={language:a.language,re:a.relevance,relavance:a.relevance},a.second_best&&(e.second_best={language:a.second_best.language,re:a.second_best.relevance,relavance:a.second_best.relevance})}const N=()=>{if(!N.called){N.called=!0;var e=document.querySelectorAll("pre code");a.forEach.call(e,E)}};function T(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]}function A(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach(e=>{s[e]=n})}function I(e){var n=T(e);return n&&!n.disableAutodetect}function S(e,n){var t=e;o.forEach((function(e){e[t]&&e[t](n)}))}Object.assign(t,{highlight:b,highlightAuto:v,fixMarkup:x,highlightBlock:E,configure:function(e){f=y(f,e)},initHighlighting:N,initHighlightingOnLoad:function(){window.addEventListener("DOMContentLoaded",N,!1)},registerLanguage:function(e,n){var r=null;try{r=n(t)}catch(n){if(console.error("Language definition for '{}' could not be registered.".replace("{}",e)),!l)throw n;console.error(n),r=h}r.name||(r.name=e),i[e]=r,r.rawDefinition=n.bind(null,t),r.aliases&&A(r.aliases,{languageName:e})},listLanguages:function(){return Object.keys(i)},getLanguage:T,registerAliases:A,requireLanguage:function(e){var n=T(e);if(n)return n;throw Error("The '{}' language is required, but not loaded.".replace("{}",e))},autoDetection:I,inherit:y,addPlugin:function(e){o.push(e)}}),t.debugMode=function(){l=!1},t.safeMode=function(){l=!0},t.versionString="10.1.1";for(const n in _)"object"==typeof _[n]&&e(_[n]);return Object.assign(t,_),t}({})}();"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);hljs.registerLanguage("php",function(){"use strict";return function(e){var r={begin:"\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*"},t={className:"meta",variants:[{begin:/<\?php/,relevance:10},{begin:/<\?[=]?/},{begin:/\?>/}]},a={className:"string",contains:[e.BACKSLASH_ESCAPE,t],variants:[{begin:'b"',end:'"'},{begin:"b'",end:"'"},e.inherit(e.APOS_STRING_MODE,{illegal:null}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null})]},n={variants:[e.BINARY_NUMBER_MODE,e.C_NUMBER_MODE]},i={keyword:"__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ die echo exit include include_once print require require_once array abstract and as binary bool boolean break callable case catch class clone const continue declare default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile eval extends final finally float for foreach from global goto if implements instanceof insteadof int integer interface isset iterable list new object or private protected public real return string switch throw trait try unset use var void while xor yield",literal:"false null true",built_in:"Error|0 AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Throwable Traversable WeakReference Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass"};return{aliases:["php","php3","php4","php5","php6","php7"],case_insensitive:!0,keywords:i,contains:[e.HASH_COMMENT_MODE,e.COMMENT("//","$",{contains:[t]}),e.COMMENT("/\\*","\\*/",{contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.COMMENT("__halt_compiler.+?;",!1,{endsWithParent:!0,keywords:"__halt_compiler"}),{className:"string",begin:/<<<['"]?\w+['"]?$/,end:/^\w+;?$/,contains:[e.BACKSLASH_ESCAPE,{className:"subst",variants:[{begin:/\$\w+/},{begin:/\{\$/,end:/\}/}]}]},t,{className:"keyword",begin:/\$this\b/},r,{begin:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{className:"function",beginKeywords:"fn function",end:/[;{]/,excludeEnd:!0,illegal:"[$%\\[]",contains:[e.UNDERSCORE_TITLE_MODE,{className:"params",begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:i,contains:["self",r,e.C_BLOCK_COMMENT_MODE,a,n]}]},{className:"class",beginKeywords:"class interface",end:"{",excludeEnd:!0,illegal:/[:\(\$"]/,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"namespace",end:";",illegal:/[\.']/,contains:[e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"use",end:";",contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"=>"},a,n]}}}());hljs.registerLanguage("nginx",function(){"use strict";return function(e){var n={className:"variable",variants:[{begin:/\$\d+/},{begin:/\$\{/,end:/}/},{begin:"[\\$\\@]"+e.UNDERSCORE_IDENT_RE}]},a={endsWithParent:!0,keywords:{$pattern:"[a-z/_]+",literal:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},relevance:0,illegal:"=>",contains:[e.HASH_COMMENT_MODE,{className:"string",contains:[e.BACKSLASH_ESCAPE,n],variants:[{begin:/"/,end:/"/},{begin:/'/,end:/'/}]},{begin:"([a-z]+):/",end:"\\s",endsWithParent:!0,excludeEnd:!0,contains:[n]},{className:"regexp",contains:[e.BACKSLASH_ESCAPE,n],variants:[{begin:"\\s\\^",end:"\\s|{|;",returnEnd:!0},{begin:"~\\*?\\s+",end:"\\s|{|;",returnEnd:!0},{begin:"\\*(\\.[a-z\\-]+)+"},{begin:"([a-z\\-]+\\.)+\\*"}]},{className:"number",begin:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{className:"number",begin:"\\b\\d+[kKmMgGdshdwy]*\\b",relevance:0},n]};return{name:"Nginx config",aliases:["nginxconf"],contains:[e.HASH_COMMENT_MODE,{begin:e.UNDERSCORE_IDENT_RE+"\\s+{",returnBegin:!0,end:"{",contains:[{className:"section",begin:e.UNDERSCORE_IDENT_RE}],relevance:0},{begin:e.UNDERSCORE_IDENT_RE+"\\s",end:";|{",returnBegin:!0,contains:[{className:"attribute",begin:e.UNDERSCORE_IDENT_RE,starts:a}],relevance:0}],illegal:"[^\\s\\}]"}}}());hljs.registerLanguage("csharp",function(){"use strict";return function(e){var n={keyword:"abstract as base bool break byte case catch char checked const continue decimal default delegate do double enum event explicit extern finally fixed float for foreach goto if implicit in int interface internal is lock long object operator out override params private protected public readonly ref sbyte sealed short sizeof stackalloc static string struct switch this try typeof uint ulong unchecked unsafe ushort using virtual void volatile while add alias ascending async await by descending dynamic equals from get global group into join let nameof on orderby partial remove select set value var when where yield",literal:"null false true"},i=e.inherit(e.TITLE_MODE,{begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},s={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}]},t=e.inherit(s,{illegal:/\n/}),l={className:"subst",begin:"{",end:"}",keywords:n},r=e.inherit(l,{illegal:/\n/}),c={className:"string",begin:/\$"/,end:'"',illegal:/\n/,contains:[{begin:"{{"},{begin:"}}"},e.BACKSLASH_ESCAPE,r]},o={className:"string",begin:/\$@"/,end:'"',contains:[{begin:"{{"},{begin:"}}"},{begin:'""'},l]},g=e.inherit(o,{illegal:/\n/,contains:[{begin:"{{"},{begin:"}}"},{begin:'""'},r]});l.contains=[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE],r.contains=[g,c,t,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{illegal:/\n/})];var d={variants:[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},E={begin:"<",end:">",contains:[{beginKeywords:"in out"},i]},_=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",b={begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"],keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0,contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{begin:"\x3c!--|--\x3e"},{begin:""}]}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#",end:"$",keywords:{"meta-keyword":"if else elif endif define undef warning error line region endregion pragma checksum"}},d,a,{beginKeywords:"class interface",end:/[{;=]/,illegal:/[^\s:,]/,contains:[{beginKeywords:"where class"},i,E,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace",end:/[{;=]/,illegal:/[^\s:]/,contains:[i,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta",begin:"^\\s*\\[",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{className:"meta-string",begin:/"/,end:/"/}]},{beginKeywords:"new return throw await else",relevance:0},{className:"function",begin:"("+_+"\\s+)+"+e.IDENT_RE+"\\s*(\\<.+\\>)?\\s*\\(",returnBegin:!0,end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{begin:e.IDENT_RE+"\\s*(\\<.+\\>)?\\s*\\(",returnBegin:!0,contains:[e.TITLE_MODE,E],relevance:0},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0,contains:[d,a,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},b]}}}());hljs.registerLanguage("perl",function(){"use strict";return function(e){var n={$pattern:/[\w.]+/,keyword:"getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qq fileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmget sub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedir ioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when"},t={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:n},s={begin:"->{",end:"}"},r={variants:[{begin:/\$\d/},{begin:/[\$%@](\^\w\b|#\w+(::\w+)*|{\w+}|\w+(::\w*)*)/},{begin:/[\$%@][^\s\w{]/,relevance:0}]},i=[e.BACKSLASH_ESCAPE,t,r],a=[r,e.HASH_COMMENT_MODE,e.COMMENT("^\\=\\w","\\=cut",{endsWithParent:!0}),s,{className:"string",contains:i,variants:[{begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[",end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*\\<",end:"\\>",relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'",contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE]},{begin:"{\\w+}",contains:[],relevance:0},{begin:"-?\\w+\\s*\\=\\>",contains:[],relevance:0}]},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*",keywords:"split return print reverse grep",relevance:0,contains:[e.HASH_COMMENT_MODE,{className:"regexp",begin:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",relevance:10},{className:"regexp",begin:"(m|qr)?/",end:"/[a-z]*",contains:[e.BACKSLASH_ESCAPE],relevance:0}]},{className:"function",beginKeywords:"sub",end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$",subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}]}];return t.contains=a,s.contains=a,{name:"Perl",aliases:["pl","pm"],keywords:n,contains:a}}}());hljs.registerLanguage("swift",function(){"use strict";return function(e){var i={keyword:"#available #colorLiteral #column #else #elseif #endif #file #fileLiteral #function #if #imageLiteral #line #selector #sourceLocation _ __COLUMN__ __FILE__ __FUNCTION__ __LINE__ Any as as! as? associatedtype associativity break case catch class continue convenience default defer deinit didSet do dynamic dynamicType else enum extension fallthrough false fileprivate final for func get guard if import in indirect infix init inout internal is lazy left let mutating nil none nonmutating open operator optional override postfix precedence prefix private protocol Protocol public repeat required rethrows return right self Self set static struct subscript super switch throw throws true try try! try? Type typealias unowned var weak where while willSet",literal:"true false nil",built_in:"abs advance alignof alignofValue anyGenerator assert assertionFailure bridgeFromObjectiveC bridgeFromObjectiveCUnconditional bridgeToObjectiveC bridgeToObjectiveCUnconditional c compactMap contains count countElements countLeadingZeros debugPrint debugPrintln distance dropFirst dropLast dump encodeBitsAsWords enumerate equal fatalError filter find getBridgedObjectiveCType getVaList indices insertionSort isBridgedToObjectiveC isBridgedVerbatimToObjectiveC isUniquelyReferenced isUniquelyReferencedNonObjC join lazy lexicographicalCompare map max maxElement min minElement numericCast overlaps partition posix precondition preconditionFailure print println quickSort readLine reduce reflect reinterpretCast reverse roundUpToAlignment sizeof sizeofValue sort split startsWith stride strideof strideofValue swap toString transcode underestimateCount unsafeAddressOf unsafeBitCast unsafeDowncast unsafeUnwrap unsafeReflect withExtendedLifetime withObjectAtPlusZero withUnsafePointer withUnsafePointerToObject withUnsafeMutablePointer withUnsafeMutablePointers withUnsafePointer withUnsafePointers withVaList zip"},n=e.COMMENT("/\\*","\\*/",{contains:["self"]}),t={className:"subst",begin:/\\\(/,end:"\\)",keywords:i,contains:[]},a={className:"string",contains:[e.BACKSLASH_ESCAPE,t],variants:[{begin:/"""/,end:/"""/},{begin:/"/,end:/"/}]},r={className:"number",begin:"\\b([\\d_]+(\\.[\\deE_]+)?|0x[a-fA-F0-9_]+(\\.[a-fA-F0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b",relevance:0};return t.contains=[r],{name:"Swift",keywords:i,contains:[a,e.C_LINE_COMMENT_MODE,n,{className:"type",begin:"\\b[A-Z][\\wÀ-ʸ']*[!?]"},{className:"type",begin:"\\b[A-Z][\\wÀ-ʸ']*",relevance:0},r,{className:"function",beginKeywords:"func",end:"{",excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/[A-Za-z$_][0-9A-Za-z$_]*/}),{begin://},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:i,contains:["self",r,a,e.C_BLOCK_COMMENT_MODE,{begin:":"}],illegal:/["']/}],illegal:/\[|%/},{className:"class",beginKeywords:"struct protocol class extension enum",keywords:i,end:"\\{",excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/})]},{className:"meta",begin:"(@discardableResult|@warn_unused_result|@exported|@lazy|@noescape|@NSCopying|@NSManaged|@objc|@objcMembers|@convention|@required|@noreturn|@IBAction|@IBDesignable|@IBInspectable|@IBOutlet|@infix|@prefix|@postfix|@autoclosure|@testable|@available|@nonobjc|@NSApplicationMain|@UIApplicationMain|@dynamicMemberLookup|@propertyWrapper)\\b"},{beginKeywords:"import",end:/$/,contains:[e.C_LINE_COMMENT_MODE,n]}]}}}());hljs.registerLanguage("makefile",function(){"use strict";return function(e){var i={className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)",contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin:"",relevance:10,contains:[a,i,t,s,{begin:"\\[",end:"\\]",contains:[{className:"meta",begin:"",contains:[a,s,i,t]}]}]},e.COMMENT("\x3c!--","--\x3e",{relevance:10}),{begin:"<\\!\\[CDATA\\[",end:"\\]\\]>",relevance:10},n,{className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",begin:")",end:">",keywords:{name:"style"},contains:[c],starts:{end:"",returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:")",end:">",keywords:{name:"script"},contains:[c],starts:{end:"<\/script>",returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:"",contains:[{className:"name",begin:/[^\/><\s]+/,relevance:0},c]}]}}}());hljs.registerLanguage("bash",function(){"use strict";return function(e){const s={};Object.assign(s,{className:"variable",variants:[{begin:/\$[\w\d#@][\w\d_]*/},{begin:/\$\{/,end:/\}/,contains:[{begin:/:-/,contains:[s]}]}]});const t={className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},n={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,t]};t.contains.push(n);const a={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,s]},i=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10}),c={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b-?[a-z\._]+\b/,keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},contains:[i,e.SHEBANG(),c,a,e.HASH_COMMENT_MODE,n,{className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},s]}}}());hljs.registerLanguage("c-like",function(){"use strict";return function(e){function t(e){return"(?:"+e+")?"}var n="(decltype\\(auto\\)|"+t("[a-zA-Z_]\\w*::")+"[a-zA-Z_]\\w*"+t("<.*?>")+")",r={className:"keyword",begin:"\\b[a-z\\d_]*_t\\b"},a={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",end:"'",illegal:"."},e.END_SAME_AS_BEGIN({begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},i={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},s={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{"meta-keyword":"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},e.inherit(a,{className:"meta-string"}),{className:"meta-string",begin:/<.*?>/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},o={className:"title",begin:t("[a-zA-Z_]\\w*::")+e.IDENT_RE,relevance:0},c=t("[a-zA-Z_]\\w*::")+e.IDENT_RE+"\\s*\\(",l={keyword:"int float while private char char8_t char16_t char32_t catch import module export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using asm case typeid wchar_t short reinterpret_cast|10 default double register explicit signed typename try this switch continue inline delete alignas alignof constexpr consteval constinit decltype concept co_await co_return co_yield requires noexcept static_assert thread_local restrict final override atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong new throw return and and_eq bitand bitor compl not not_eq or or_eq xor xor_eq",built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr _Bool complex _Complex imaginary _Imaginary",literal:"true false nullptr NULL"},d=[r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,i,a],_={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:l,contains:d.concat([{begin:/\(/,end:/\)/,keywords:l,contains:d.concat(["self"]),relevance:0}]),relevance:0},u={className:"function",begin:"("+n+"[\\*&\\s]+)+"+c,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:l,illegal:/[^\w\s\*&:<>]/,contains:[{begin:"decltype\\(auto\\)",keywords:l,relevance:0},{begin:c,returnBegin:!0,contains:[o],relevance:0},{className:"params",begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,i,r,{begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:["self",e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,i,r]}]},r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s]};return{aliases:["c","cc","h","c++","h++","hpp","hh","hxx","cxx"],keywords:l,disableAutodetect:!0,illegal:"",keywords:l,contains:["self",r]},{begin:e.IDENT_RE+"::",keywords:l},{className:"class",beginKeywords:"class struct",end:/[{;:]/,contains:[{begin://,contains:["self"]},e.TITLE_MODE]}]),exports:{preprocessor:s,strings:a,keywords:l}}}}());hljs.registerLanguage("coffeescript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);return function(r){var t={keyword:e.concat(["then","unless","until","loop","by","when","and","or","is","isnt","not"]).filter((e=>n=>!e.includes(n))(["var","const","let","function","static"])).join(" "),literal:n.concat(["yes","no","on","off"]).join(" "),built_in:a.concat(["npm","print"]).join(" ")},i="[A-Za-z$_][0-9A-Za-z$_]*",s={className:"subst",begin:/#\{/,end:/}/,keywords:t},o=[r.BINARY_NUMBER_MODE,r.inherit(r.C_NUMBER_MODE,{starts:{end:"(\\s*/)?",relevance:0}}),{className:"string",variants:[{begin:/'''/,end:/'''/,contains:[r.BACKSLASH_ESCAPE]},{begin:/'/,end:/'/,contains:[r.BACKSLASH_ESCAPE]},{begin:/"""/,end:/"""/,contains:[r.BACKSLASH_ESCAPE,s]},{begin:/"/,end:/"/,contains:[r.BACKSLASH_ESCAPE,s]}]},{className:"regexp",variants:[{begin:"///",end:"///",contains:[s,r.HASH_COMMENT_MODE]},{begin:"//[gim]{0,3}(?=\\W)",relevance:0},{begin:/\/(?![ *]).*?(?![\\]).\/[gim]{0,3}(?=\W)/}]},{begin:"@"+i},{subLanguage:"javascript",excludeBegin:!0,excludeEnd:!0,variants:[{begin:"```",end:"```"},{begin:"`",end:"`"}]}];s.contains=o;var c=r.inherit(r.TITLE_MODE,{begin:i}),l={className:"params",begin:"\\([^\\(]",returnBegin:!0,contains:[{begin:/\(/,end:/\)/,keywords:t,contains:["self"].concat(o)}]};return{name:"CoffeeScript",aliases:["coffee","cson","iced"],keywords:t,illegal:/\/\*/,contains:o.concat([r.COMMENT("###","###"),r.HASH_COMMENT_MODE,{className:"function",begin:"^\\s*"+i+"\\s*=\\s*(\\(.*\\))?\\s*\\B[-=]>",end:"[-=]>",returnBegin:!0,contains:[c,l]},{begin:/[:\(,=]\s*/,relevance:0,contains:[{className:"function",begin:"(\\(.*\\))?\\s*\\B[-=]>",end:"[-=]>",returnBegin:!0,contains:[l]}]},{className:"class",beginKeywords:"class",end:"$",illegal:/[:="\[\]]/,contains:[{beginKeywords:"extends",endsWithParent:!0,illegal:/[:="\[\]]/,contains:[c]},c]},{begin:i+":",end:":",returnBegin:!0,returnEnd:!0,relevance:0}])}}}());hljs.registerLanguage("ruby",function(){"use strict";return function(e){var n="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",a={keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor",literal:"true false nil"},s={className:"doctag",begin:"@[A-Za-z]+"},i={begin:"#<",end:">"},r=[e.COMMENT("#","$",{contains:[s]}),e.COMMENT("^\\=begin","^\\=end",{contains:[s],relevance:10}),e.COMMENT("^__END__","\\n$")],c={className:"subst",begin:"#\\{",end:"}",keywords:a},t={className:"string",contains:[e.BACKSLASH_ESCAPE,c],variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:"%[qQwWx]?\\(",end:"\\)"},{begin:"%[qQwWx]?\\[",end:"\\]"},{begin:"%[qQwWx]?{",end:"}"},{begin:"%[qQwWx]?<",end:">"},{begin:"%[qQwWx]?/",end:"/"},{begin:"%[qQwWx]?%",end:"%"},{begin:"%[qQwWx]?-",end:"-"},{begin:"%[qQwWx]?\\|",end:"\\|"},{begin:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/},{begin:/<<[-~]?'?(\w+)(?:.|\n)*?\n\s*\1\b/,returnBegin:!0,contains:[{begin:/<<[-~]?'?/},e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,contains:[e.BACKSLASH_ESCAPE,c]})]}]},b={className:"params",begin:"\\(",end:"\\)",endsParent:!0,keywords:a},d=[t,i,{className:"class",beginKeywords:"class module",end:"$|;",illegal:/=/,contains:[e.inherit(e.TITLE_MODE,{begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{begin:"<\\s*",contains:[{begin:"("+e.IDENT_RE+"::)?"+e.IDENT_RE}]}].concat(r)},{className:"function",beginKeywords:"def",end:"$|;",contains:[e.inherit(e.TITLE_MODE,{begin:n}),b].concat(r)},{begin:e.IDENT_RE+"::"},{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(\\!|\\?)?:",relevance:0},{className:"symbol",begin:":(?!\\s)",contains:[t,{begin:n}],relevance:0},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{className:"params",begin:/\|/,end:/\|/,keywords:a},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[i,{className:"regexp",contains:[e.BACKSLASH_ESCAPE,c],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:"%r{",end:"}[a-z]*"},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(r),relevance:0}].concat(r);c.contains=d,b.contains=d;var g=[{begin:/^\s*=>/,starts:{end:"$",contains:d}},{className:"meta",begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+>|(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>)",starts:{end:"$",contains:d}}];return{name:"Ruby",aliases:["rb","gemspec","podspec","thor","irb"],keywords:a,illegal:/\/\*/,contains:r.concat(g).concat(d)}}}());hljs.registerLanguage("yaml",function(){"use strict";return function(e){var n="true false yes no null",a="[\\w#;/?:@&=+$,.~*\\'()[\\]]+",s={className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable",variants:[{begin:"{{",end:"}}"},{begin:"%{",end:"}"}]}]},i=e.inherit(s,{variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),l={end:",",endsWithParent:!0,excludeEnd:!0,contains:[],keywords:n,relevance:0},t={begin:"{",end:"}",contains:[l],illegal:"\\n",relevance:0},g={begin:"\\[",end:"\\]",contains:[l],illegal:"\\n",relevance:0},b=[{className:"attr",variants:[{begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---s*$",relevance:10},{className:"string",begin:"[\\|>]([0-9]?[+-])?[ ]*\\n( *)[\\S ]+\\n(\\2[\\S ]+\\n?)*"},{begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:"!\\w+!"+a},{className:"type",begin:"!<"+a+">"},{className:"type",begin:"!"+a},{className:"type",begin:"!!"+a},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta",begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"\\-(?=[ ]|$)",relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{className:"number",begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b"},{className:"number",begin:e.C_NUMBER_RE+"\\b"},t,g,s],c=[...b];return c.pop(),c.push(i),l.contains=c,{name:"YAML",case_insensitive:!0,aliases:["yml","YAML"],contains:b}}}());hljs.registerLanguage("d",function(){"use strict";return function(e){var a={$pattern:e.UNDERSCORE_IDENT_RE,keyword:"abstract alias align asm assert auto body break byte case cast catch class const continue debug default delete deprecated do else enum export extern final finally for foreach foreach_reverse|10 goto if immutable import in inout int interface invariant is lazy macro mixin module new nothrow out override package pragma private protected public pure ref return scope shared static struct super switch synchronized template this throw try typedef typeid typeof union unittest version void volatile while with __FILE__ __LINE__ __gshared|10 __thread __traits __DATE__ __EOF__ __TIME__ __TIMESTAMP__ __VENDOR__ __VERSION__",built_in:"bool cdouble cent cfloat char creal dchar delegate double dstring float function idouble ifloat ireal long real short string ubyte ucent uint ulong ushort wchar wstring",literal:"false null true"},d="((0|[1-9][\\d_]*)|0[bB][01_]+|0[xX]([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*))",n="\\\\(['\"\\?\\\\abfnrtv]|u[\\dA-Fa-f]{4}|[0-7]{1,3}|x[\\dA-Fa-f]{2}|U[\\dA-Fa-f]{8})|&[a-zA-Z\\d]{2,};",t={className:"number",begin:"\\b"+d+"(L|u|U|Lu|LU|uL|UL)?",relevance:0},_={className:"number",begin:"\\b(((0[xX](([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*)\\.([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*)|\\.?([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*))[pP][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d))|((0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)(\\.\\d*|([eE][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)))|\\d+\\.(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)|\\.(0|[1-9][\\d_]*)([eE][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d))?))([fF]|L|i|[fF]i|Li)?|"+d+"(i|[fF]i|Li))",relevance:0},r={className:"string",begin:"'("+n+"|.)",end:"'",illegal:"."},i={className:"string",begin:'"',contains:[{begin:n,relevance:0}],end:'"[cwd]?'},s=e.COMMENT("\\/\\+","\\+\\/",{contains:["self"],relevance:10});return{name:"D",keywords:a,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s,{className:"string",begin:'x"[\\da-fA-F\\s\\n\\r]*"[cwd]?',relevance:10},i,{className:"string",begin:'[rq]"',end:'"[cwd]?',relevance:5},{className:"string",begin:"`",end:"`[cwd]?"},{className:"string",begin:'q"\\{',end:'\\}"'},_,t,r,{className:"meta",begin:"^#!",end:"$",relevance:5},{className:"meta",begin:"#(line)",end:"$",relevance:5},{className:"keyword",begin:"@[a-zA-Z_][a-zA-Z_\\d]*"}]}}}());hljs.registerLanguage("properties",function(){"use strict";return function(e){var n="[ \\t\\f]*",t="("+n+"[:=]"+n+"|[ \\t\\f]+)",a="([^\\\\:= \\t\\f\\n]|\\\\.)+",s={end:t,relevance:0,starts:{className:"string",end:/$/,relevance:0,contains:[{begin:"\\\\\\n"}]}};return{name:".properties",case_insensitive:!0,illegal:/\S/,contains:[e.COMMENT("^\\s*[!#]","$"),{begin:"([^\\\\\\W:= \\t\\f\\n]|\\\\.)+"+t,returnBegin:!0,contains:[{className:"attr",begin:"([^\\\\\\W:= \\t\\f\\n]|\\\\.)+",endsParent:!0,relevance:0}],starts:s},{begin:a+t,returnBegin:!0,relevance:0,contains:[{className:"meta",begin:a,endsParent:!0,relevance:0}],starts:s},{className:"attr",relevance:0,begin:a+n+"$"}]}}}());hljs.registerLanguage("http",function(){"use strict";return function(e){var n="HTTP/[0-9\\.]+";return{name:"HTTP",aliases:["https"],illegal:"\\S",contains:[{begin:"^"+n,end:"$",contains:[{className:"number",begin:"\\b\\d{3}\\b"}]},{begin:"^[A-Z]+ (.*?) "+n+"$",returnBegin:!0,end:"$",contains:[{className:"string",begin:" ",end:" ",excludeBegin:!0,excludeEnd:!0},{begin:n},{className:"keyword",begin:"[A-Z]+"}]},{className:"attribute",begin:"^\\w",end:": ",excludeEnd:!0,illegal:"\\n|\\s|=",starts:{end:"$",relevance:0}},{begin:"\\n\\n",starts:{subLanguage:[],endsWithParent:!0}}]}}}());hljs.registerLanguage("haskell",function(){"use strict";return function(e){var n={variants:[e.COMMENT("--","$"),e.COMMENT("{-","-}",{contains:["self"]})]},i={className:"meta",begin:"{-#",end:"#-}"},a={className:"meta",begin:"^#",end:"$"},s={className:"type",begin:"\\b[A-Z][\\w']*",relevance:0},l={begin:"\\(",end:"\\)",illegal:'"',contains:[i,a,{className:"type",begin:"\\b[A-Z][\\w]*(\\((\\.\\.|,|\\w+)\\))?"},e.inherit(e.TITLE_MODE,{begin:"[_a-z][\\w']*"}),n]};return{name:"Haskell",aliases:["hs"],keywords:"let in if then else case of where do module import hiding qualified type data newtype deriving class instance as default infix infixl infixr foreign export ccall stdcall cplusplus jvm dotnet safe unsafe family forall mdo proc rec",contains:[{beginKeywords:"module",end:"where",keywords:"module where",contains:[l,n],illegal:"\\W\\.|;"},{begin:"\\bimport\\b",end:"$",keywords:"import qualified as hiding",contains:[l,n],illegal:"\\W\\.|;"},{className:"class",begin:"^(\\s*)?(class|instance)\\b",end:"where",keywords:"class family instance where",contains:[s,l,n]},{className:"class",begin:"\\b(data|(new)?type)\\b",end:"$",keywords:"data family type newtype deriving",contains:[i,s,l,{begin:"{",end:"}",contains:l.contains},n]},{beginKeywords:"default",end:"$",contains:[s,l,n]},{beginKeywords:"infix infixl infixr",end:"$",contains:[e.C_NUMBER_MODE,n]},{begin:"\\bforeign\\b",end:"$",keywords:"foreign import export ccall stdcall cplusplus jvm dotnet safe unsafe",contains:[s,e.QUOTE_STRING_MODE,n]},{className:"meta",begin:"#!\\/usr\\/bin\\/env runhaskell",end:"$"},i,a,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,s,e.inherit(e.TITLE_MODE,{begin:"^[_a-z][\\w']*"}),n,{begin:"->|<-"}]}}}());hljs.registerLanguage("handlebars",function(){"use strict";function e(...e){return e.map(e=>(function(e){return e?"string"==typeof e?e:e.source:null})(e)).join("")}return function(n){const a={"builtin-name":"action bindattr collection component concat debugger each each-in get hash if in input link-to loc log lookup mut outlet partial query-params render template textarea unbound unless view with yield"},t=/\[.*?\]/,s=/[^\s!"#%&'()*+,.\/;<=>@\[\\\]^`{|}~]+/,i=e("(",/'.*?'/,"|",/".*?"/,"|",t,"|",s,"|",/\.|\//,")+"),r=e("(",t,"|",s,")(?==)"),l={begin:i,lexemes:/[\w.\/]+/},c=n.inherit(l,{keywords:{literal:"true false undefined null"}}),o={begin:/\(/,end:/\)/},m={className:"attr",begin:r,relevance:0,starts:{begin:/=/,end:/=/,starts:{contains:[n.NUMBER_MODE,n.QUOTE_STRING_MODE,n.APOS_STRING_MODE,c,o]}}},d={contains:[n.NUMBER_MODE,n.QUOTE_STRING_MODE,n.APOS_STRING_MODE,{begin:/as\s+\|/,keywords:{keyword:"as"},end:/\|/,contains:[{begin:/\w+/}]},m,c,o],returnEnd:!0},g=n.inherit(l,{className:"name",keywords:a,starts:n.inherit(d,{end:/\)/})});o.contains=[g];const u=n.inherit(l,{keywords:a,className:"name",starts:n.inherit(d,{end:/}}/})}),b=n.inherit(l,{keywords:a,className:"name"}),h=n.inherit(l,{className:"name",keywords:a,starts:n.inherit(d,{end:/}}/})});return{name:"Handlebars",aliases:["hbs","html.hbs","html.handlebars","htmlbars"],case_insensitive:!0,subLanguage:"xml",contains:[{begin:/\\\{\{/,skip:!0},{begin:/\\\\(?=\{\{)/,skip:!0},n.COMMENT(/\{\{!--/,/--\}\}/),n.COMMENT(/\{\{!/,/\}\}/),{className:"template-tag",begin:/\{\{\{\{(?!\/)/,end:/\}\}\}\}/,contains:[u],starts:{end:/\{\{\{\{\//,returnEnd:!0,subLanguage:"xml"}},{className:"template-tag",begin:/\{\{\{\{\//,end:/\}\}\}\}/,contains:[b]},{className:"template-tag",begin:/\{\{#/,end:/\}\}/,contains:[u]},{className:"template-tag",begin:/\{\{(?=else\}\})/,end:/\}\}/,keywords:"else"},{className:"template-tag",begin:/\{\{\//,end:/\}\}/,contains:[b]},{className:"template-variable",begin:/\{\{\{/,end:/\}\}\}/,contains:[h]},{className:"template-variable",begin:/\{\{/,end:/\}\}/,contains:[h]}]}}}());hljs.registerLanguage("rust",function(){"use strict";return function(e){var n="([ui](8|16|32|64|128|size)|f(32|64))?",t="drop i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize f32 f64 str char bool Box Option Result String Vec Copy Send Sized Sync Drop Fn FnMut FnOnce ToOwned Clone Debug PartialEq PartialOrd Eq Ord AsRef AsMut Into From Default Iterator Extend IntoIterator DoubleEndedIterator ExactSizeIterator SliceConcatExt ToString assert! assert_eq! bitflags! bytes! cfg! col! concat! concat_idents! debug_assert! debug_assert_eq! env! panic! file! format! format_args! include_bin! include_str! line! local_data_key! module_path! option_env! print! println! select! stringify! try! unimplemented! unreachable! vec! write! writeln! macro_rules! assert_ne! debug_assert_ne!";return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",keyword:"abstract as async await become box break const continue crate do dyn else enum extern false final fn for if impl in let loop macro match mod move mut override priv pub ref return self Self static struct super trait true try type typeof unsafe unsized use virtual where while yield",literal:"true false Some None Ok Err",built_in:t},illegal:""}]}}}());hljs.registerLanguage("cpp",function(){"use strict";return function(e){var t=e.getLanguage("c-like").rawDefinition();return t.disableAutodetect=!1,t.name="C++",t.aliases=["cc","c++","h++","hpp","hh","hxx","cxx"],t}}());hljs.registerLanguage("ini",function(){"use strict";function e(e){return e?"string"==typeof e?e:e.source:null}function n(...n){return n.map(n=>e(n)).join("")}return function(a){var s={className:"number",relevance:0,variants:[{begin:/([\+\-]+)?[\d]+_[\d_]+/},{begin:a.NUMBER_RE}]},i=a.COMMENT();i.variants=[{begin:/;/,end:/$/},{begin:/#/,end:/$/}];var t={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{begin:/\$\{(.*?)}/}]},r={className:"literal",begin:/\bon|off|true|false|yes|no\b/},l={className:"string",contains:[a.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}]},c={begin:/\[/,end:/\]/,contains:[i,r,t,l,s,"self"],relevance:0},g="("+[/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/].map(n=>e(n)).join("|")+")";return{name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/,contains:[i,{className:"section",begin:/\[+/,end:/\]+/},{begin:n(g,"(\\s*\\.\\s*",g,")*",n("(?=",/\s*=\s*[^#\s]/,")")),className:"attr",starts:{end:/$/,contains:[i,c,r,t,l,s]}}]}}}());hljs.registerLanguage("objectivec",function(){"use strict";return function(e){var n=/[a-zA-Z@][a-zA-Z0-9_]*/,_={$pattern:n,keyword:"@interface @class @protocol @implementation"};return{name:"Objective-C",aliases:["mm","objc","obj-c"],keywords:{$pattern:n,keyword:"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign readwrite self @synchronized id typeof nonatomic super unichar IBOutlet IBAction strong weak copy in out inout bycopy byref oneway __strong __weak __block __autoreleasing @private @protected @public @try @property @end @throw @catch @finally @autoreleasepool @synthesize @dynamic @selector @optional @required @encode @package @import @defs @compatibility_alias __bridge __bridge_transfer __bridge_retained __bridge_retain __covariant __contravariant __kindof _Nonnull _Nullable _Null_unspecified __FUNCTION__ __PRETTY_FUNCTION__ __attribute__ getter setter retain unsafe_unretained nonnull nullable null_unspecified null_resettable class instancetype NS_DESIGNATED_INITIALIZER NS_UNAVAILABLE NS_REQUIRES_SUPER NS_RETURNS_INNER_POINTER NS_INLINE NS_AVAILABLE NS_DEPRECATED NS_ENUM NS_OPTIONS NS_SWIFT_UNAVAILABLE NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_REFINED_FOR_SWIFT NS_SWIFT_NAME NS_SWIFT_NOTHROW NS_DURING NS_HANDLER NS_ENDHANDLER NS_VALUERETURN NS_VOIDRETURN",literal:"false true FALSE TRUE nil YES NO NULL",built_in:"BOOL dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once"},illegal:"/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class",begin:"("+_.keyword.split(" ").join("|")+")\\b",end:"({|$)",excludeEnd:!0,keywords:_,contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE,relevance:0}]}}}());hljs.registerLanguage("apache",function(){"use strict";return function(e){var n={className:"number",begin:"\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?"};return{name:"Apache config",aliases:["apacheconf"],case_insensitive:!0,contains:[e.HASH_COMMENT_MODE,{className:"section",begin:"",contains:[n,{className:"number",begin:":\\d{1,5}"},e.inherit(e.QUOTE_STRING_MODE,{relevance:0})]},{className:"attribute",begin:/\w+/,relevance:0,keywords:{nomarkup:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername"},starts:{end:/$/,relevance:0,keywords:{literal:"on off all deny allow"},contains:[{className:"meta",begin:"\\s\\[",end:"\\]$"},{className:"variable",begin:"[\\$%]\\{",end:"\\}",contains:["self",{className:"number",begin:"[\\$%]\\d+"}]},n,{className:"number",begin:"\\d+"},e.QUOTE_STRING_MODE]}}],illegal:/\S/}}}());hljs.registerLanguage("java",function(){"use strict";function e(e){return e?"string"==typeof e?e:e.source:null}function n(e){return a("(",e,")?")}function a(...n){return n.map(n=>e(n)).join("")}function s(...n){return"("+n.map(n=>e(n)).join("|")+")"}return function(e){var t="false synchronized int abstract float private char boolean var static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do",i={className:"meta",begin:"@[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",contains:[{begin:/\(/,end:/\)/,contains:["self"]}]},r=e=>a("[",e,"]+([",e,"_]*[",e,"]+)?"),c={className:"number",variants:[{begin:`\\b(0[bB]${r("01")})[lL]?`},{begin:`\\b(0${r("0-7")})[dDfFlL]?`},{begin:a(/\b0[xX]/,s(a(r("a-fA-F0-9"),/\./,r("a-fA-F0-9")),a(r("a-fA-F0-9"),/\.?/),a(/\./,r("a-fA-F0-9"))),/([pP][+-]?(\d+))?/,/[fFdDlL]?/)},{begin:a(/\b/,s(a(/\d*\./,r("\\d")),r("\\d")),/[eE][+-]?[\d]+[dDfF]?/)},{begin:a(/\b/,r(/\d/),n(/\.?/),n(r(/\d/)),/[dDfFlL]?/)}],relevance:0};return{name:"Java",aliases:["jsp"],keywords:t,illegal:/<\/|#/,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"class",beginKeywords:"class interface",end:/[{;=]/,excludeEnd:!0,keywords:"class interface",illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"new throw return else",relevance:0},{className:"function",begin:"([À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(<[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(\\s*,\\s*[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*)*>)?\\s+)+"+e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:t,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"params",begin:/\(/,end:/\)/,keywords:t,relevance:0,contains:[i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},c,i]}}}());hljs.registerLanguage("x86asm",function(){"use strict";return function(s){return{name:"Intel x86 Assembly",case_insensitive:!0,keywords:{$pattern:"[.%]?"+s.IDENT_RE,keyword:"lock rep repe repz repne repnz xaquire xrelease bnd nobnd aaa aad aam aas adc add and arpl bb0_reset bb1_reset bound bsf bsr bswap bt btc btr bts call cbw cdq cdqe clc cld cli clts cmc cmp cmpsb cmpsd cmpsq cmpsw cmpxchg cmpxchg486 cmpxchg8b cmpxchg16b cpuid cpu_read cpu_write cqo cwd cwde daa das dec div dmint emms enter equ f2xm1 fabs fadd faddp fbld fbstp fchs fclex fcmovb fcmovbe fcmove fcmovnb fcmovnbe fcmovne fcmovnu fcmovu fcom fcomi fcomip fcomp fcompp fcos fdecstp fdisi fdiv fdivp fdivr fdivrp femms feni ffree ffreep fiadd ficom ficomp fidiv fidivr fild fimul fincstp finit fist fistp fisttp fisub fisubr fld fld1 fldcw fldenv fldl2e fldl2t fldlg2 fldln2 fldpi fldz fmul fmulp fnclex fndisi fneni fninit fnop fnsave fnstcw fnstenv fnstsw fpatan fprem fprem1 fptan frndint frstor fsave fscale fsetpm fsin fsincos fsqrt fst fstcw fstenv fstp fstsw fsub fsubp fsubr fsubrp ftst fucom fucomi fucomip fucomp fucompp fxam fxch fxtract fyl2x fyl2xp1 hlt ibts icebp idiv imul in inc incbin insb insd insw int int01 int1 int03 int3 into invd invpcid invlpg invlpga iret iretd iretq iretw jcxz jecxz jrcxz jmp jmpe lahf lar lds lea leave les lfence lfs lgdt lgs lidt lldt lmsw loadall loadall286 lodsb lodsd lodsq lodsw loop loope loopne loopnz loopz lsl lss ltr mfence monitor mov movd movq movsb movsd movsq movsw movsx movsxd movzx mul mwait neg nop not or out outsb outsd outsw packssdw packsswb packuswb paddb paddd paddsb paddsiw paddsw paddusb paddusw paddw pand pandn pause paveb pavgusb pcmpeqb pcmpeqd pcmpeqw pcmpgtb pcmpgtd pcmpgtw pdistib pf2id pfacc pfadd pfcmpeq pfcmpge pfcmpgt pfmax pfmin pfmul pfrcp pfrcpit1 pfrcpit2 pfrsqit1 pfrsqrt pfsub pfsubr pi2fd pmachriw pmaddwd pmagw pmulhriw pmulhrwa pmulhrwc pmulhw pmullw pmvgezb pmvlzb pmvnzb pmvzb pop popa popad popaw popf popfd popfq popfw por prefetch prefetchw pslld psllq psllw psrad psraw psrld psrlq psrlw psubb psubd psubsb psubsiw psubsw psubusb psubusw psubw punpckhbw punpckhdq punpckhwd punpcklbw punpckldq punpcklwd push pusha pushad pushaw pushf pushfd pushfq pushfw pxor rcl rcr rdshr rdmsr rdpmc rdtsc rdtscp ret retf retn rol ror rdm rsdc rsldt rsm rsts sahf sal salc sar sbb scasb scasd scasq scasw sfence sgdt shl shld shr shrd sidt sldt skinit smi smint smintold smsw stc std sti stosb stosd stosq stosw str sub svdc svldt svts swapgs syscall sysenter sysexit sysret test ud0 ud1 ud2b ud2 ud2a umov verr verw fwait wbinvd wrshr wrmsr xadd xbts xchg xlatb xlat xor cmove cmovz cmovne cmovnz cmova cmovnbe cmovae cmovnb cmovb cmovnae cmovbe cmovna cmovg cmovnle cmovge cmovnl cmovl cmovnge cmovle cmovng cmovc cmovnc cmovo cmovno cmovs cmovns cmovp cmovpe cmovnp cmovpo je jz jne jnz ja jnbe jae jnb jb jnae jbe jna jg jnle jge jnl jl jnge jle jng jc jnc jo jno js jns jpo jnp jpe jp sete setz setne setnz seta setnbe setae setnb setnc setb setnae setcset setbe setna setg setnle setge setnl setl setnge setle setng sets setns seto setno setpe setp setpo setnp addps addss andnps andps cmpeqps cmpeqss cmpleps cmpless cmpltps cmpltss cmpneqps cmpneqss cmpnleps cmpnless cmpnltps cmpnltss cmpordps cmpordss cmpunordps cmpunordss cmpps cmpss comiss cvtpi2ps cvtps2pi cvtsi2ss cvtss2si cvttps2pi cvttss2si divps divss ldmxcsr maxps maxss minps minss movaps movhps movlhps movlps movhlps movmskps movntps movss movups mulps mulss orps rcpps rcpss rsqrtps rsqrtss shufps sqrtps sqrtss stmxcsr subps subss ucomiss unpckhps unpcklps xorps fxrstor fxrstor64 fxsave fxsave64 xgetbv xsetbv xsave xsave64 xsaveopt xsaveopt64 xrstor xrstor64 prefetchnta prefetcht0 prefetcht1 prefetcht2 maskmovq movntq pavgb pavgw pextrw pinsrw pmaxsw pmaxub pminsw pminub pmovmskb pmulhuw psadbw pshufw pf2iw pfnacc pfpnacc pi2fw pswapd maskmovdqu clflush movntdq movnti movntpd movdqa movdqu movdq2q movq2dq paddq pmuludq pshufd pshufhw pshuflw pslldq psrldq psubq punpckhqdq punpcklqdq addpd addsd andnpd andpd cmpeqpd cmpeqsd cmplepd cmplesd cmpltpd cmpltsd cmpneqpd cmpneqsd cmpnlepd cmpnlesd cmpnltpd cmpnltsd cmpordpd cmpordsd cmpunordpd cmpunordsd cmppd comisd cvtdq2pd cvtdq2ps cvtpd2dq cvtpd2pi cvtpd2ps cvtpi2pd cvtps2dq cvtps2pd cvtsd2si cvtsd2ss cvtsi2sd cvtss2sd cvttpd2pi cvttpd2dq cvttps2dq cvttsd2si divpd divsd maxpd maxsd minpd minsd movapd movhpd movlpd movmskpd movupd mulpd mulsd orpd shufpd sqrtpd sqrtsd subpd subsd ucomisd unpckhpd unpcklpd xorpd addsubpd addsubps haddpd haddps hsubpd hsubps lddqu movddup movshdup movsldup clgi stgi vmcall vmclear vmfunc vmlaunch vmload vmmcall vmptrld vmptrst vmread vmresume vmrun vmsave vmwrite vmxoff vmxon invept invvpid pabsb pabsw pabsd palignr phaddw phaddd phaddsw phsubw phsubd phsubsw pmaddubsw pmulhrsw pshufb psignb psignw psignd extrq insertq movntsd movntss lzcnt blendpd blendps blendvpd blendvps dppd dpps extractps insertps movntdqa mpsadbw packusdw pblendvb pblendw pcmpeqq pextrb pextrd pextrq phminposuw pinsrb pinsrd pinsrq pmaxsb pmaxsd pmaxud pmaxuw pminsb pminsd pminud pminuw pmovsxbw pmovsxbd pmovsxbq pmovsxwd pmovsxwq pmovsxdq pmovzxbw pmovzxbd pmovzxbq pmovzxwd pmovzxwq pmovzxdq pmuldq pmulld ptest roundpd roundps roundsd roundss crc32 pcmpestri pcmpestrm pcmpistri pcmpistrm pcmpgtq popcnt getsec pfrcpv pfrsqrtv movbe aesenc aesenclast aesdec aesdeclast aesimc aeskeygenassist vaesenc vaesenclast vaesdec vaesdeclast vaesimc vaeskeygenassist vaddpd vaddps vaddsd vaddss vaddsubpd vaddsubps vandpd vandps vandnpd vandnps vblendpd vblendps vblendvpd vblendvps vbroadcastss vbroadcastsd vbroadcastf128 vcmpeq_ospd vcmpeqpd vcmplt_ospd vcmpltpd vcmple_ospd vcmplepd vcmpunord_qpd vcmpunordpd vcmpneq_uqpd vcmpneqpd vcmpnlt_uspd vcmpnltpd vcmpnle_uspd vcmpnlepd vcmpord_qpd vcmpordpd vcmpeq_uqpd vcmpnge_uspd vcmpngepd vcmpngt_uspd vcmpngtpd vcmpfalse_oqpd vcmpfalsepd vcmpneq_oqpd vcmpge_ospd vcmpgepd vcmpgt_ospd vcmpgtpd vcmptrue_uqpd vcmptruepd vcmplt_oqpd vcmple_oqpd vcmpunord_spd vcmpneq_uspd vcmpnlt_uqpd vcmpnle_uqpd vcmpord_spd vcmpeq_uspd vcmpnge_uqpd vcmpngt_uqpd vcmpfalse_ospd vcmpneq_ospd vcmpge_oqpd vcmpgt_oqpd vcmptrue_uspd vcmppd vcmpeq_osps vcmpeqps vcmplt_osps vcmpltps vcmple_osps vcmpleps vcmpunord_qps vcmpunordps vcmpneq_uqps vcmpneqps vcmpnlt_usps vcmpnltps vcmpnle_usps vcmpnleps vcmpord_qps vcmpordps vcmpeq_uqps vcmpnge_usps vcmpngeps vcmpngt_usps vcmpngtps vcmpfalse_oqps vcmpfalseps vcmpneq_oqps vcmpge_osps vcmpgeps vcmpgt_osps vcmpgtps vcmptrue_uqps vcmptrueps vcmplt_oqps vcmple_oqps vcmpunord_sps vcmpneq_usps vcmpnlt_uqps vcmpnle_uqps vcmpord_sps vcmpeq_usps vcmpnge_uqps vcmpngt_uqps vcmpfalse_osps vcmpneq_osps vcmpge_oqps vcmpgt_oqps vcmptrue_usps vcmpps vcmpeq_ossd vcmpeqsd vcmplt_ossd vcmpltsd vcmple_ossd vcmplesd vcmpunord_qsd vcmpunordsd vcmpneq_uqsd vcmpneqsd vcmpnlt_ussd vcmpnltsd vcmpnle_ussd vcmpnlesd vcmpord_qsd vcmpordsd vcmpeq_uqsd vcmpnge_ussd vcmpngesd vcmpngt_ussd vcmpngtsd vcmpfalse_oqsd vcmpfalsesd vcmpneq_oqsd vcmpge_ossd vcmpgesd vcmpgt_ossd vcmpgtsd vcmptrue_uqsd vcmptruesd vcmplt_oqsd vcmple_oqsd vcmpunord_ssd vcmpneq_ussd vcmpnlt_uqsd vcmpnle_uqsd vcmpord_ssd vcmpeq_ussd vcmpnge_uqsd vcmpngt_uqsd vcmpfalse_ossd vcmpneq_ossd vcmpge_oqsd vcmpgt_oqsd vcmptrue_ussd vcmpsd vcmpeq_osss vcmpeqss vcmplt_osss vcmpltss vcmple_osss vcmpless vcmpunord_qss vcmpunordss vcmpneq_uqss vcmpneqss vcmpnlt_usss vcmpnltss vcmpnle_usss vcmpnless vcmpord_qss vcmpordss vcmpeq_uqss vcmpnge_usss vcmpngess vcmpngt_usss vcmpngtss vcmpfalse_oqss vcmpfalsess vcmpneq_oqss vcmpge_osss vcmpgess vcmpgt_osss vcmpgtss vcmptrue_uqss vcmptruess vcmplt_oqss vcmple_oqss vcmpunord_sss vcmpneq_usss vcmpnlt_uqss vcmpnle_uqss vcmpord_sss vcmpeq_usss vcmpnge_uqss vcmpngt_uqss vcmpfalse_osss vcmpneq_osss vcmpge_oqss vcmpgt_oqss vcmptrue_usss vcmpss vcomisd vcomiss vcvtdq2pd vcvtdq2ps vcvtpd2dq vcvtpd2ps vcvtps2dq vcvtps2pd vcvtsd2si vcvtsd2ss vcvtsi2sd vcvtsi2ss vcvtss2sd vcvtss2si vcvttpd2dq vcvttps2dq vcvttsd2si vcvttss2si vdivpd vdivps vdivsd vdivss vdppd vdpps vextractf128 vextractps vhaddpd vhaddps vhsubpd vhsubps vinsertf128 vinsertps vlddqu vldqqu vldmxcsr vmaskmovdqu vmaskmovps vmaskmovpd vmaxpd vmaxps vmaxsd vmaxss vminpd vminps vminsd vminss vmovapd vmovaps vmovd vmovq vmovddup vmovdqa vmovqqa vmovdqu vmovqqu vmovhlps vmovhpd vmovhps vmovlhps vmovlpd vmovlps vmovmskpd vmovmskps vmovntdq vmovntqq vmovntdqa vmovntpd vmovntps vmovsd vmovshdup vmovsldup vmovss vmovupd vmovups vmpsadbw vmulpd vmulps vmulsd vmulss vorpd vorps vpabsb vpabsw vpabsd vpacksswb vpackssdw vpackuswb vpackusdw vpaddb vpaddw vpaddd vpaddq vpaddsb vpaddsw vpaddusb vpaddusw vpalignr vpand vpandn vpavgb vpavgw vpblendvb vpblendw vpcmpestri vpcmpestrm vpcmpistri vpcmpistrm vpcmpeqb vpcmpeqw vpcmpeqd vpcmpeqq vpcmpgtb vpcmpgtw vpcmpgtd vpcmpgtq vpermilpd vpermilps vperm2f128 vpextrb vpextrw vpextrd vpextrq vphaddw vphaddd vphaddsw vphminposuw vphsubw vphsubd vphsubsw vpinsrb vpinsrw vpinsrd vpinsrq vpmaddwd vpmaddubsw vpmaxsb vpmaxsw vpmaxsd vpmaxub vpmaxuw vpmaxud vpminsb vpminsw vpminsd vpminub vpminuw vpminud vpmovmskb vpmovsxbw vpmovsxbd vpmovsxbq vpmovsxwd vpmovsxwq vpmovsxdq vpmovzxbw vpmovzxbd vpmovzxbq vpmovzxwd vpmovzxwq vpmovzxdq vpmulhuw vpmulhrsw vpmulhw vpmullw vpmulld vpmuludq vpmuldq vpor vpsadbw vpshufb vpshufd vpshufhw vpshuflw vpsignb vpsignw vpsignd vpslldq vpsrldq vpsllw vpslld vpsllq vpsraw vpsrad vpsrlw vpsrld vpsrlq vptest vpsubb vpsubw vpsubd vpsubq vpsubsb vpsubsw vpsubusb vpsubusw vpunpckhbw vpunpckhwd vpunpckhdq vpunpckhqdq vpunpcklbw vpunpcklwd vpunpckldq vpunpcklqdq vpxor vrcpps vrcpss vrsqrtps vrsqrtss vroundpd vroundps vroundsd vroundss vshufpd vshufps vsqrtpd vsqrtps vsqrtsd vsqrtss vstmxcsr vsubpd vsubps vsubsd vsubss vtestps vtestpd vucomisd vucomiss vunpckhpd vunpckhps vunpcklpd vunpcklps vxorpd vxorps vzeroall vzeroupper pclmullqlqdq pclmulhqlqdq pclmullqhqdq pclmulhqhqdq pclmulqdq vpclmullqlqdq vpclmulhqlqdq vpclmullqhqdq vpclmulhqhqdq vpclmulqdq vfmadd132ps vfmadd132pd vfmadd312ps vfmadd312pd vfmadd213ps vfmadd213pd vfmadd123ps vfmadd123pd vfmadd231ps vfmadd231pd vfmadd321ps vfmadd321pd vfmaddsub132ps vfmaddsub132pd vfmaddsub312ps vfmaddsub312pd vfmaddsub213ps vfmaddsub213pd vfmaddsub123ps vfmaddsub123pd vfmaddsub231ps vfmaddsub231pd vfmaddsub321ps vfmaddsub321pd vfmsub132ps vfmsub132pd vfmsub312ps vfmsub312pd vfmsub213ps vfmsub213pd vfmsub123ps vfmsub123pd vfmsub231ps vfmsub231pd vfmsub321ps vfmsub321pd vfmsubadd132ps vfmsubadd132pd vfmsubadd312ps vfmsubadd312pd vfmsubadd213ps vfmsubadd213pd vfmsubadd123ps vfmsubadd123pd vfmsubadd231ps vfmsubadd231pd vfmsubadd321ps vfmsubadd321pd vfnmadd132ps vfnmadd132pd vfnmadd312ps vfnmadd312pd vfnmadd213ps vfnmadd213pd vfnmadd123ps vfnmadd123pd vfnmadd231ps vfnmadd231pd vfnmadd321ps vfnmadd321pd vfnmsub132ps vfnmsub132pd vfnmsub312ps vfnmsub312pd vfnmsub213ps vfnmsub213pd vfnmsub123ps vfnmsub123pd vfnmsub231ps vfnmsub231pd vfnmsub321ps vfnmsub321pd vfmadd132ss vfmadd132sd vfmadd312ss vfmadd312sd vfmadd213ss vfmadd213sd vfmadd123ss vfmadd123sd vfmadd231ss vfmadd231sd vfmadd321ss vfmadd321sd vfmsub132ss vfmsub132sd vfmsub312ss vfmsub312sd vfmsub213ss vfmsub213sd vfmsub123ss vfmsub123sd vfmsub231ss vfmsub231sd vfmsub321ss vfmsub321sd vfnmadd132ss vfnmadd132sd vfnmadd312ss vfnmadd312sd vfnmadd213ss vfnmadd213sd vfnmadd123ss vfnmadd123sd vfnmadd231ss vfnmadd231sd vfnmadd321ss vfnmadd321sd vfnmsub132ss vfnmsub132sd vfnmsub312ss vfnmsub312sd vfnmsub213ss vfnmsub213sd vfnmsub123ss vfnmsub123sd vfnmsub231ss vfnmsub231sd vfnmsub321ss vfnmsub321sd rdfsbase rdgsbase rdrand wrfsbase wrgsbase vcvtph2ps vcvtps2ph adcx adox rdseed clac stac xstore xcryptecb xcryptcbc xcryptctr xcryptcfb xcryptofb montmul xsha1 xsha256 llwpcb slwpcb lwpval lwpins vfmaddpd vfmaddps vfmaddsd vfmaddss vfmaddsubpd vfmaddsubps vfmsubaddpd vfmsubaddps vfmsubpd vfmsubps vfmsubsd vfmsubss vfnmaddpd vfnmaddps vfnmaddsd vfnmaddss vfnmsubpd vfnmsubps vfnmsubsd vfnmsubss vfrczpd vfrczps vfrczsd vfrczss vpcmov vpcomb vpcomd vpcomq vpcomub vpcomud vpcomuq vpcomuw vpcomw vphaddbd vphaddbq vphaddbw vphadddq vphaddubd vphaddubq vphaddubw vphaddudq vphadduwd vphadduwq vphaddwd vphaddwq vphsubbw vphsubdq vphsubwd vpmacsdd vpmacsdqh vpmacsdql vpmacssdd vpmacssdqh vpmacssdql vpmacsswd vpmacssww vpmacswd vpmacsww vpmadcsswd vpmadcswd vpperm vprotb vprotd vprotq vprotw vpshab vpshad vpshaq vpshaw vpshlb vpshld vpshlq vpshlw vbroadcasti128 vpblendd vpbroadcastb vpbroadcastw vpbroadcastd vpbroadcastq vpermd vpermpd vpermps vpermq vperm2i128 vextracti128 vinserti128 vpmaskmovd vpmaskmovq vpsllvd vpsllvq vpsravd vpsrlvd vpsrlvq vgatherdpd vgatherqpd vgatherdps vgatherqps vpgatherdd vpgatherqd vpgatherdq vpgatherqq xabort xbegin xend xtest andn bextr blci blcic blsi blsic blcfill blsfill blcmsk blsmsk blsr blcs bzhi mulx pdep pext rorx sarx shlx shrx tzcnt tzmsk t1mskc valignd valignq vblendmpd vblendmps vbroadcastf32x4 vbroadcastf64x4 vbroadcasti32x4 vbroadcasti64x4 vcompresspd vcompressps vcvtpd2udq vcvtps2udq vcvtsd2usi vcvtss2usi vcvttpd2udq vcvttps2udq vcvttsd2usi vcvttss2usi vcvtudq2pd vcvtudq2ps vcvtusi2sd vcvtusi2ss vexpandpd vexpandps vextractf32x4 vextractf64x4 vextracti32x4 vextracti64x4 vfixupimmpd vfixupimmps vfixupimmsd vfixupimmss vgetexppd vgetexpps vgetexpsd vgetexpss vgetmantpd vgetmantps vgetmantsd vgetmantss vinsertf32x4 vinsertf64x4 vinserti32x4 vinserti64x4 vmovdqa32 vmovdqa64 vmovdqu32 vmovdqu64 vpabsq vpandd vpandnd vpandnq vpandq vpblendmd vpblendmq vpcmpltd vpcmpled vpcmpneqd vpcmpnltd vpcmpnled vpcmpd vpcmpltq vpcmpleq vpcmpneqq vpcmpnltq vpcmpnleq vpcmpq vpcmpequd vpcmpltud vpcmpleud vpcmpnequd vpcmpnltud vpcmpnleud vpcmpud vpcmpequq vpcmpltuq vpcmpleuq vpcmpnequq vpcmpnltuq vpcmpnleuq vpcmpuq vpcompressd vpcompressq vpermi2d vpermi2pd vpermi2ps vpermi2q vpermt2d vpermt2pd vpermt2ps vpermt2q vpexpandd vpexpandq vpmaxsq vpmaxuq vpminsq vpminuq vpmovdb vpmovdw vpmovqb vpmovqd vpmovqw vpmovsdb vpmovsdw vpmovsqb vpmovsqd vpmovsqw vpmovusdb vpmovusdw vpmovusqb vpmovusqd vpmovusqw vpord vporq vprold vprolq vprolvd vprolvq vprord vprorq vprorvd vprorvq vpscatterdd vpscatterdq vpscatterqd vpscatterqq vpsraq vpsravq vpternlogd vpternlogq vptestmd vptestmq vptestnmd vptestnmq vpxord vpxorq vrcp14pd vrcp14ps vrcp14sd vrcp14ss vrndscalepd vrndscaleps vrndscalesd vrndscaless vrsqrt14pd vrsqrt14ps vrsqrt14sd vrsqrt14ss vscalefpd vscalefps vscalefsd vscalefss vscatterdpd vscatterdps vscatterqpd vscatterqps vshuff32x4 vshuff64x2 vshufi32x4 vshufi64x2 kandnw kandw kmovw knotw kortestw korw kshiftlw kshiftrw kunpckbw kxnorw kxorw vpbroadcastmb2q vpbroadcastmw2d vpconflictd vpconflictq vplzcntd vplzcntq vexp2pd vexp2ps vrcp28pd vrcp28ps vrcp28sd vrcp28ss vrsqrt28pd vrsqrt28ps vrsqrt28sd vrsqrt28ss vgatherpf0dpd vgatherpf0dps vgatherpf0qpd vgatherpf0qps vgatherpf1dpd vgatherpf1dps vgatherpf1qpd vgatherpf1qps vscatterpf0dpd vscatterpf0dps vscatterpf0qpd vscatterpf0qps vscatterpf1dpd vscatterpf1dps vscatterpf1qpd vscatterpf1qps prefetchwt1 bndmk bndcl bndcu bndcn bndmov bndldx bndstx sha1rnds4 sha1nexte sha1msg1 sha1msg2 sha256rnds2 sha256msg1 sha256msg2 hint_nop0 hint_nop1 hint_nop2 hint_nop3 hint_nop4 hint_nop5 hint_nop6 hint_nop7 hint_nop8 hint_nop9 hint_nop10 hint_nop11 hint_nop12 hint_nop13 hint_nop14 hint_nop15 hint_nop16 hint_nop17 hint_nop18 hint_nop19 hint_nop20 hint_nop21 hint_nop22 hint_nop23 hint_nop24 hint_nop25 hint_nop26 hint_nop27 hint_nop28 hint_nop29 hint_nop30 hint_nop31 hint_nop32 hint_nop33 hint_nop34 hint_nop35 hint_nop36 hint_nop37 hint_nop38 hint_nop39 hint_nop40 hint_nop41 hint_nop42 hint_nop43 hint_nop44 hint_nop45 hint_nop46 hint_nop47 hint_nop48 hint_nop49 hint_nop50 hint_nop51 hint_nop52 hint_nop53 hint_nop54 hint_nop55 hint_nop56 hint_nop57 hint_nop58 hint_nop59 hint_nop60 hint_nop61 hint_nop62 hint_nop63",built_in:"ip eip rip al ah bl bh cl ch dl dh sil dil bpl spl r8b r9b r10b r11b r12b r13b r14b r15b ax bx cx dx si di bp sp r8w r9w r10w r11w r12w r13w r14w r15w eax ebx ecx edx esi edi ebp esp eip r8d r9d r10d r11d r12d r13d r14d r15d rax rbx rcx rdx rsi rdi rbp rsp r8 r9 r10 r11 r12 r13 r14 r15 cs ds es fs gs ss st st0 st1 st2 st3 st4 st5 st6 st7 mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 xmm0 xmm1 xmm2 xmm3 xmm4 xmm5 xmm6 xmm7 xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15 xmm16 xmm17 xmm18 xmm19 xmm20 xmm21 xmm22 xmm23 xmm24 xmm25 xmm26 xmm27 xmm28 xmm29 xmm30 xmm31 ymm0 ymm1 ymm2 ymm3 ymm4 ymm5 ymm6 ymm7 ymm8 ymm9 ymm10 ymm11 ymm12 ymm13 ymm14 ymm15 ymm16 ymm17 ymm18 ymm19 ymm20 ymm21 ymm22 ymm23 ymm24 ymm25 ymm26 ymm27 ymm28 ymm29 ymm30 ymm31 zmm0 zmm1 zmm2 zmm3 zmm4 zmm5 zmm6 zmm7 zmm8 zmm9 zmm10 zmm11 zmm12 zmm13 zmm14 zmm15 zmm16 zmm17 zmm18 zmm19 zmm20 zmm21 zmm22 zmm23 zmm24 zmm25 zmm26 zmm27 zmm28 zmm29 zmm30 zmm31 k0 k1 k2 k3 k4 k5 k6 k7 bnd0 bnd1 bnd2 bnd3 cr0 cr1 cr2 cr3 cr4 cr8 dr0 dr1 dr2 dr3 dr8 tr3 tr4 tr5 tr6 tr7 r0 r1 r2 r3 r4 r5 r6 r7 r0b r1b r2b r3b r4b r5b r6b r7b r0w r1w r2w r3w r4w r5w r6w r7w r0d r1d r2d r3d r4d r5d r6d r7d r0h r1h r2h r3h r0l r1l r2l r3l r4l r5l r6l r7l r8l r9l r10l r11l r12l r13l r14l r15l db dw dd dq dt ddq do dy dz resb resw resd resq rest resdq reso resy resz incbin equ times byte word dword qword nosplit rel abs seg wrt strict near far a32 ptr",meta:"%define %xdefine %+ %undef %defstr %deftok %assign %strcat %strlen %substr %rotate %elif %else %endif %if %ifmacro %ifctx %ifidn %ifidni %ifid %ifnum %ifstr %iftoken %ifempty %ifenv %error %warning %fatal %rep %endrep %include %push %pop %repl %pathsearch %depend %use %arg %stacksize %local %line %comment %endcomment .nolist __FILE__ __LINE__ __SECT__ __BITS__ __OUTPUT_FORMAT__ __DATE__ __TIME__ __DATE_NUM__ __TIME_NUM__ __UTC_DATE__ __UTC_TIME__ __UTC_DATE_NUM__ __UTC_TIME_NUM__ __PASS__ struc endstruc istruc at iend align alignb sectalign daz nodaz up down zero default option assume public bits use16 use32 use64 default section segment absolute extern global common cpu float __utf16__ __utf16le__ __utf16be__ __utf32__ __utf32le__ __utf32be__ __float8__ __float16__ __float32__ __float64__ __float80m__ __float80e__ __float128l__ __float128h__ __Infinity__ __QNaN__ __SNaN__ Inf NaN QNaN SNaN float8 float16 float32 float64 float80m float80e float128l float128h __FLOAT_DAZ__ __FLOAT_ROUND__ __FLOAT__"},contains:[s.COMMENT(";","$",{relevance:0}),{className:"number",variants:[{begin:"\\b(?:([0-9][0-9_]*)?\\.[0-9_]*(?:[eE][+-]?[0-9_]+)?|(0[Xx])?[0-9][0-9_]*\\.?[0-9_]*(?:[pP](?:[+-]?[0-9_]+)?)?)\\b",relevance:0},{begin:"\\$[0-9][0-9A-Fa-f]*",relevance:0},{begin:"\\b(?:[0-9A-Fa-f][0-9A-Fa-f_]*[Hh]|[0-9][0-9_]*[DdTt]?|[0-7][0-7_]*[QqOo]|[0-1][0-1_]*[BbYy])\\b"},{begin:"\\b(?:0[Xx][0-9A-Fa-f_]+|0[DdTt][0-9_]+|0[QqOo][0-7_]+|0[BbYy][0-1_]+)\\b"}]},s.QUOTE_STRING_MODE,{className:"string",variants:[{begin:"'",end:"[^\\\\]'"},{begin:"`",end:"[^\\\\]`"}],relevance:0},{className:"symbol",variants:[{begin:"^\\s*[A-Za-z._?][A-Za-z0-9_$#@~.?]*(:|\\s+label)"},{begin:"^\\s*%%[A-Za-z0-9_$#@~.?]*:"}],relevance:0},{className:"subst",begin:"%[0-9]+",relevance:0},{className:"subst",begin:"%!S+",relevance:0},{className:"meta",begin:/^\s*\.[\w_-]+/}]}}}());hljs.registerLanguage("kotlin",function(){"use strict";return function(e){var n={keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual trait volatile transient native default",built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",literal:"true false null"},a={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@"},i={className:"subst",begin:"\\${",end:"}",contains:[e.C_NUMBER_MODE]},s={className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},t={className:"string",variants:[{begin:'"""',end:'"""(?=[^"])',contains:[s,i]},{begin:"'",end:"'",illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/,contains:[e.BACKSLASH_ESCAPE,s,i]}]};i.contains.push(t);var r={className:"meta",begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?"},l={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/,end:/\)/,contains:[e.inherit(t,{className:"meta-string"})]}]},c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),o={variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,contains:[]}]},d=o;return d.variants[1].contains=[o],o.variants[1].contains=[d],{name:"Kotlin",aliases:["kt"],keywords:n,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword",begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",begin:/@\w+/}]}},a,r,l,{className:"function",beginKeywords:"fun",end:"[(]|$",returnBegin:!0,excludeEnd:!0,keywords:n,illegal:/fun\s+(<.*>)?[^\s\(]+(\s+[^\s\(]+)\s*=/,relevance:5,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://,keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/,endsWithParent:!0,contains:[o,e.C_LINE_COMMENT_MODE,c],relevance:0},e.C_LINE_COMMENT_MODE,c,r,l,t,e.C_NUMBER_MODE]},c]},{className:"class",beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0,illegal:"extends implements",contains:[{beginKeywords:"public protected internal private constructor"},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/,excludeBegin:!0,returnEnd:!0},r,l]},t,{className:"meta",begin:"^#!/usr/bin/env",end:"$",illegal:"\n"},{className:"number",begin:"\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?",relevance:0}]}}}());hljs.registerLanguage("armasm",function(){"use strict";return function(s){const e={variants:[s.COMMENT("^[ \\t]*(?=#)","$",{relevance:0,excludeBegin:!0}),s.COMMENT("[;@]","$",{relevance:0}),s.C_LINE_COMMENT_MODE,s.C_BLOCK_COMMENT_MODE]};return{name:"ARM Assembly",case_insensitive:!0,aliases:["arm"],keywords:{$pattern:"\\.?"+s.IDENT_RE,meta:".2byte .4byte .align .ascii .asciz .balign .byte .code .data .else .end .endif .endm .endr .equ .err .exitm .extern .global .hword .if .ifdef .ifndef .include .irp .long .macro .rept .req .section .set .skip .space .text .word .arm .thumb .code16 .code32 .force_thumb .thumb_func .ltorg ALIAS ALIGN ARM AREA ASSERT ATTR CN CODE CODE16 CODE32 COMMON CP DATA DCB DCD DCDU DCDO DCFD DCFDU DCI DCQ DCQU DCW DCWU DN ELIF ELSE END ENDFUNC ENDIF ENDP ENTRY EQU EXPORT EXPORTAS EXTERN FIELD FILL FUNCTION GBLA GBLL GBLS GET GLOBAL IF IMPORT INCBIN INCLUDE INFO KEEP LCLA LCLL LCLS LTORG MACRO MAP MEND MEXIT NOFP OPT PRESERVE8 PROC QN READONLY RELOC REQUIRE REQUIRE8 RLIST FN ROUT SETA SETL SETS SN SPACE SUBT THUMB THUMBX TTL WHILE WEND ",built_in:"r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 pc lr sp ip sl sb fp a1 a2 a3 a4 v1 v2 v3 v4 v5 v6 v7 v8 f0 f1 f2 f3 f4 f5 f6 f7 p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12 p13 p14 p15 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 q0 q1 q2 q3 q4 q5 q6 q7 q8 q9 q10 q11 q12 q13 q14 q15 cpsr_c cpsr_x cpsr_s cpsr_f cpsr_cx cpsr_cxs cpsr_xs cpsr_xsf cpsr_sf cpsr_cxsf spsr_c spsr_x spsr_s spsr_f spsr_cx spsr_cxs spsr_xs spsr_xsf spsr_sf spsr_cxsf s0 s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11 s12 s13 s14 s15 s16 s17 s18 s19 s20 s21 s22 s23 s24 s25 s26 s27 s28 s29 s30 s31 d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 d10 d11 d12 d13 d14 d15 d16 d17 d18 d19 d20 d21 d22 d23 d24 d25 d26 d27 d28 d29 d30 d31 {PC} {VAR} {TRUE} {FALSE} {OPT} {CONFIG} {ENDIAN} {CODESIZE} {CPU} {FPU} {ARCHITECTURE} {PCSTOREOFFSET} {ARMASM_VERSION} {INTER} {ROPI} {RWPI} {SWST} {NOSWST} . @"},contains:[{className:"keyword",begin:"\\b(adc|(qd?|sh?|u[qh]?)?add(8|16)?|usada?8|(q|sh?|u[qh]?)?(as|sa)x|and|adrl?|sbc|rs[bc]|asr|b[lx]?|blx|bxj|cbn?z|tb[bh]|bic|bfc|bfi|[su]bfx|bkpt|cdp2?|clz|clrex|cmp|cmn|cpsi[ed]|cps|setend|dbg|dmb|dsb|eor|isb|it[te]{0,3}|lsl|lsr|ror|rrx|ldm(([id][ab])|f[ds])?|ldr((s|ex)?[bhd])?|movt?|mvn|mra|mar|mul|[us]mull|smul[bwt][bt]|smu[as]d|smmul|smmla|mla|umlaal|smlal?([wbt][bt]|d)|mls|smlsl?[ds]|smc|svc|sev|mia([bt]{2}|ph)?|mrr?c2?|mcrr2?|mrs|msr|orr|orn|pkh(tb|bt)|rbit|rev(16|sh)?|sel|[su]sat(16)?|nop|pop|push|rfe([id][ab])?|stm([id][ab])?|str(ex)?[bhd]?|(qd?)?sub|(sh?|q|u[qh]?)?sub(8|16)|[su]xt(a?h|a?b(16)?)|srs([id][ab])?|swpb?|swi|smi|tst|teq|wfe|wfi|yield)(eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al|hs|lo)?[sptrx]?(?=\\s)"},e,s.QUOTE_STRING_MODE,{className:"string",begin:"'",end:"[^\\\\]'",relevance:0},{className:"title",begin:"\\|",end:"\\|",illegal:"\\n",relevance:0},{className:"number",variants:[{begin:"[#$=]?0x[0-9a-f]+"},{begin:"[#$=]?0b[01]+"},{begin:"[#$=]\\d+"},{begin:"\\b\\d+"}],relevance:0},{className:"symbol",variants:[{begin:"^[ \\t]*[a-z_\\.\\$][a-z0-9_\\.\\$]+:"},{begin:"^[a-z_\\.\\$][a-z0-9_\\.\\$]+"},{begin:"[=#]\\w+"}],relevance:0}]}}}());hljs.registerLanguage("go",function(){"use strict";return function(e){var n={keyword:"break default func interface select case map struct chan else goto package switch const fallthrough if range type continue for import return var go defer bool byte complex64 complex128 float32 float64 int8 int16 int32 int64 string uint8 uint16 uint32 uint64 int uint uintptr rune",literal:"true false iota nil",built_in:"append cap close complex copy imag len make new panic print println real recover delete"};return{name:"Go",aliases:["golang"],keywords:n,illegal:">>|\.\.\.) /},i={className:"subst",begin:/\{/,end:/\}/,keywords:n,illegal:/#/},s={begin:/\{\{/,relevance:0},r={className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:/(u|b)?r?'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,a],relevance:10},{begin:/(u|b)?r?"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,a],relevance:10},{begin:/(fr|rf|f)'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,a,s,i]},{begin:/(fr|rf|f)"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,a,s,i]},{begin:/(u|r|ur)'/,end:/'/,relevance:10},{begin:/(u|r|ur)"/,end:/"/,relevance:10},{begin:/(b|br)'/,end:/'/},{begin:/(b|br)"/,end:/"/},{begin:/(fr|rf|f)'/,end:/'/,contains:[e.BACKSLASH_ESCAPE,s,i]},{begin:/(fr|rf|f)"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,i]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},l={className:"number",relevance:0,variants:[{begin:e.BINARY_NUMBER_RE+"[lLjJ]?"},{begin:"\\b(0o[0-7]+)[lLjJ]?"},{begin:e.C_NUMBER_RE+"[lLjJ]?"}]},t={className:"params",variants:[{begin:/\(\s*\)/,skip:!0,className:null},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:["self",a,l,r,e.HASH_COMMENT_MODE]}]};return i.contains=[r,l,a],{name:"Python",aliases:["py","gyp","ipython"],keywords:n,illegal:/(<\/|->|\?)|=>/,contains:[a,l,{beginKeywords:"if",relevance:0},r,e.HASH_COMMENT_MODE,{variants:[{className:"function",beginKeywords:"def"},{className:"class",beginKeywords:"class"}],end:/:/,illegal:/[${=;\n,]/,contains:[e.UNDERSCORE_TITLE_MODE,t,{begin:/->/,endsWithParent:!0,keywords:"None"}]},{className:"meta",begin:/^[\t ]*@/,end:/$/},{begin:/\b(print|exec)\(/}]}}}());hljs.registerLanguage("shell",function(){"use strict";return function(s){return{name:"Shell Session",aliases:["console"],contains:[{className:"meta",begin:"^\\s{0,3}[/\\w\\d\\[\\]()@-]*[>%$#]",starts:{end:"$",subLanguage:"bash"}}]}}}());hljs.registerLanguage("scala",function(){"use strict";return function(e){var n={className:"subst",variants:[{begin:"\\$[A-Za-z0-9_]+"},{begin:"\\${",end:"}"}]},a={className:"string",variants:[{begin:'"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:'"""',end:'"""',relevance:10},{begin:'[a-z]+"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE,n]},{className:"string",begin:'[a-z]+"""',end:'"""',contains:[n],relevance:10}]},s={className:"type",begin:"\\b[A-Z][A-Za-z0-9_]*",relevance:0},t={className:"title",begin:/[^0-9\n\t "'(),.`{}\[\]:;][^\n\t "'(),.`{}\[\]:;]+|[^0-9\n\t "'(),.`{}\[\]:;=]/,relevance:0},i={className:"class",beginKeywords:"class object trait type",end:/[:={\[\n;]/,excludeEnd:!0,contains:[{beginKeywords:"extends with",relevance:10},{begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[s]},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[s]},t]},l={className:"function",beginKeywords:"def",end:/[:={\[(\n;]/,excludeEnd:!0,contains:[t]};return{name:"Scala",keywords:{literal:"true false null",keyword:"type yield lazy override def with val var sealed abstract private trait object if forSome for while throw finally protected extends import final return else break new catch super class case package default try this match continue throws implicit"},contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,{className:"symbol",begin:"'\\w[\\w\\d_]*(?!')"},s,l,i,e.C_NUMBER_MODE,{className:"meta",begin:"@[A-Za-z]+"}]}}}());hljs.registerLanguage("julia",function(){"use strict";return function(e){var r="[A-Za-z_\\u00A1-\\uFFFF][A-Za-z_0-9\\u00A1-\\uFFFF]*",t={$pattern:r,keyword:"in isa where baremodule begin break catch ccall const continue do else elseif end export false finally for function global if import importall let local macro module quote return true try using while type immutable abstract bitstype typealias ",literal:"true false ARGS C_NULL DevNull ENDIAN_BOM ENV I Inf Inf16 Inf32 Inf64 InsertionSort JULIA_HOME LOAD_PATH MergeSort NaN NaN16 NaN32 NaN64 PROGRAM_FILE QuickSort RoundDown RoundFromZero RoundNearest RoundNearestTiesAway RoundNearestTiesUp RoundToZero RoundUp STDERR STDIN STDOUT VERSION catalan e|0 eu|0 eulergamma golden im nothing pi γ π φ ",built_in:"ANY AbstractArray AbstractChannel AbstractFloat AbstractMatrix AbstractRNG AbstractSerializer AbstractSet AbstractSparseArray AbstractSparseMatrix AbstractSparseVector AbstractString AbstractUnitRange AbstractVecOrMat AbstractVector Any ArgumentError Array AssertionError Associative Base64DecodePipe Base64EncodePipe Bidiagonal BigFloat BigInt BitArray BitMatrix BitVector Bool BoundsError BufferStream CachingPool CapturedException CartesianIndex CartesianRange Cchar Cdouble Cfloat Channel Char Cint Cintmax_t Clong Clonglong ClusterManager Cmd CodeInfo Colon Complex Complex128 Complex32 Complex64 CompositeException Condition ConjArray ConjMatrix ConjVector Cptrdiff_t Cshort Csize_t Cssize_t Cstring Cuchar Cuint Cuintmax_t Culong Culonglong Cushort Cwchar_t Cwstring DataType Date DateFormat DateTime DenseArray DenseMatrix DenseVecOrMat DenseVector Diagonal Dict DimensionMismatch Dims DirectIndexString Display DivideError DomainError EOFError EachLine Enum Enumerate ErrorException Exception ExponentialBackOff Expr Factorization FileMonitor Float16 Float32 Float64 Function Future GlobalRef GotoNode HTML Hermitian IO IOBuffer IOContext IOStream IPAddr IPv4 IPv6 IndexCartesian IndexLinear IndexStyle InexactError InitError Int Int128 Int16 Int32 Int64 Int8 IntSet Integer InterruptException InvalidStateException Irrational KeyError LabelNode LinSpace LineNumberNode LoadError LowerTriangular MIME Matrix MersenneTwister Method MethodError MethodTable Module NTuple NewvarNode NullException Nullable Number ObjectIdDict OrdinalRange OutOfMemoryError OverflowError Pair ParseError PartialQuickSort PermutedDimsArray Pipe PollingFileWatcher ProcessExitedException Ptr QuoteNode RandomDevice Range RangeIndex Rational RawFD ReadOnlyMemoryError Real ReentrantLock Ref Regex RegexMatch RemoteChannel RemoteException RevString RoundingMode RowVector SSAValue SegmentationFault SerializationState Set SharedArray SharedMatrix SharedVector Signed SimpleVector Slot SlotNumber SparseMatrixCSC SparseVector StackFrame StackOverflowError StackTrace StepRange StepRangeLen StridedArray StridedMatrix StridedVecOrMat StridedVector String SubArray SubString SymTridiagonal Symbol Symmetric SystemError TCPSocket Task Text TextDisplay Timer Tridiagonal Tuple Type TypeError TypeMapEntry TypeMapLevel TypeName TypeVar TypedSlot UDPSocket UInt UInt128 UInt16 UInt32 UInt64 UInt8 UndefRefError UndefVarError UnicodeError UniformScaling Union UnionAll UnitRange Unsigned UpperTriangular Val Vararg VecElement VecOrMat Vector VersionNumber Void WeakKeyDict WeakRef WorkerConfig WorkerPool "},a={keywords:t,illegal:/<\//},n={className:"subst",begin:/\$\(/,end:/\)/,keywords:t},o={className:"variable",begin:"\\$"+r},i={className:"string",contains:[e.BACKSLASH_ESCAPE,n,o],variants:[{begin:/\w*"""/,end:/"""\w*/,relevance:10},{begin:/\w*"/,end:/"\w*/}]},l={className:"string",contains:[e.BACKSLASH_ESCAPE,n,o],begin:"`",end:"`"},s={className:"meta",begin:"@"+r};return a.name="Julia",a.contains=[{className:"number",begin:/(\b0x[\d_]*(\.[\d_]*)?|0x\.\d[\d_]*)p[-+]?\d+|\b0[box][a-fA-F0-9][a-fA-F0-9_]*|(\b\d[\d_]*(\.[\d_]*)?|\.\d[\d_]*)([eEfF][-+]?\d+)?/,relevance:0},{className:"string",begin:/'(.|\\[xXuU][a-zA-Z0-9]+)'/},i,l,s,{className:"comment",variants:[{begin:"#=",end:"=#",relevance:10},{begin:"#",end:"$"}]},e.HASH_COMMENT_MODE,{className:"keyword",begin:"\\b(((abstract|primitive)\\s+)type|(mutable\\s+)?struct)\\b"},{begin:/<:/}],n.contains=a.contains,a}}());hljs.registerLanguage("php-template",function(){"use strict";return function(n){return{name:"PHP template",subLanguage:"xml",contains:[{begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*",end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0},n.inherit(n.APOS_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0}),n.inherit(n.QUOTE_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0})]}]}}}());hljs.registerLanguage("scss",function(){"use strict";return function(e){var t={className:"variable",begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b"},i={className:"number",begin:"#[0-9A-Fa-f]+"};return e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,e.C_BLOCK_COMMENT_MODE,{name:"SCSS",case_insensitive:!0,illegal:"[=/|']",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"selector-id",begin:"\\#[A-Za-z0-9_-]+",relevance:0},{className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0},{className:"selector-attr",begin:"\\[",end:"\\]",illegal:"$"},{className:"selector-tag",begin:"\\b(a|abbr|acronym|address|area|article|aside|audio|b|base|big|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|frame|frameset|(h[1-6])|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|map|mark|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|samp|script|section|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|ul|var|video)\\b",relevance:0},{className:"selector-pseudo",begin:":(visited|valid|root|right|required|read-write|read-only|out-range|optional|only-of-type|only-child|nth-of-type|nth-last-of-type|nth-last-child|nth-child|not|link|left|last-of-type|last-child|lang|invalid|indeterminate|in-range|hover|focus|first-of-type|first-line|first-letter|first-child|first|enabled|empty|disabled|default|checked|before|after|active)"},{className:"selector-pseudo",begin:"::(after|before|choices|first-letter|first-line|repeat-index|repeat-item|selection|value)"},t,{className:"attribute",begin:"\\b(src|z-index|word-wrap|word-spacing|word-break|width|widows|white-space|visibility|vertical-align|unicode-bidi|transition-timing-function|transition-property|transition-duration|transition-delay|transition|transform-style|transform-origin|transform|top|text-underline-position|text-transform|text-shadow|text-rendering|text-overflow|text-indent|text-decoration-style|text-decoration-line|text-decoration-color|text-decoration|text-align-last|text-align|tab-size|table-layout|right|resize|quotes|position|pointer-events|perspective-origin|perspective|page-break-inside|page-break-before|page-break-after|padding-top|padding-right|padding-left|padding-bottom|padding|overflow-y|overflow-x|overflow-wrap|overflow|outline-width|outline-style|outline-offset|outline-color|outline|orphans|order|opacity|object-position|object-fit|normal|none|nav-up|nav-right|nav-left|nav-index|nav-down|min-width|min-height|max-width|max-height|mask|marks|margin-top|margin-right|margin-left|margin-bottom|margin|list-style-type|list-style-position|list-style-image|list-style|line-height|letter-spacing|left|justify-content|initial|inherit|ime-mode|image-orientation|image-resolution|image-rendering|icon|hyphens|height|font-weight|font-variant-ligatures|font-variant|font-style|font-stretch|font-size-adjust|font-size|font-language-override|font-kerning|font-feature-settings|font-family|font|float|flex-wrap|flex-shrink|flex-grow|flex-flow|flex-direction|flex-basis|flex|filter|empty-cells|display|direction|cursor|counter-reset|counter-increment|content|column-width|column-span|column-rule-width|column-rule-style|column-rule-color|column-rule|column-gap|column-fill|column-count|columns|color|clip-path|clip|clear|caption-side|break-inside|break-before|break-after|box-sizing|box-shadow|box-decoration-break|bottom|border-width|border-top-width|border-top-style|border-top-right-radius|border-top-left-radius|border-top-color|border-top|border-style|border-spacing|border-right-width|border-right-style|border-right-color|border-right|border-radius|border-left-width|border-left-style|border-left-color|border-left|border-image-width|border-image-source|border-image-slice|border-image-repeat|border-image-outset|border-image|border-color|border-collapse|border-bottom-width|border-bottom-style|border-bottom-right-radius|border-bottom-left-radius|border-bottom-color|border-bottom|border|background-size|background-repeat|background-position|background-origin|background-image|background-color|background-clip|background-attachment|background-blend-mode|background|backface-visibility|auto|animation-timing-function|animation-play-state|animation-name|animation-iteration-count|animation-fill-mode|animation-duration|animation-direction|animation-delay|animation|align-self|align-items|align-content)\\b",illegal:"[^\\s]"},{begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b"},{begin:":",end:";",contains:[t,i,e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{className:"meta",begin:"!important"}]},{begin:"@(page|font-face)",lexemes:"@[a-z-]+",keywords:"@page @font-face"},{begin:"@",end:"[{;]",returnBegin:!0,keywords:"and or not only",contains:[{begin:"@[a-z-]+",className:"keyword"},t,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,i,e.CSS_NUMBER_MODE]}]}}}());hljs.registerLanguage("r",function(){"use strict";return function(e){var n="([a-zA-Z]|\\.[a-zA-Z.])[a-zA-Z0-9._]*";return{name:"R",contains:[e.HASH_COMMENT_MODE,{begin:n,keywords:{$pattern:n,keyword:"function if in break next repeat else for return switch while try tryCatch stop warning require library attach detach source setMethod setGeneric setGroupGeneric setClass ...",literal:"NULL NA TRUE FALSE T F Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10"},relevance:0},{className:"number",begin:"0[xX][0-9a-fA-F]+[Li]?\\b",relevance:0},{className:"number",begin:"\\d+(?:[eE][+\\-]?\\d*)?L\\b",relevance:0},{className:"number",begin:"\\d+\\.(?!\\d)(?:i\\b)?",relevance:0},{className:"number",begin:"\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d*)?i?\\b",relevance:0},{className:"number",begin:"\\.\\d+(?:[eE][+\\-]?\\d*)?i?\\b",relevance:0},{begin:"`",end:"`",relevance:0},{className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:'"',end:'"'},{begin:"'",end:"'"}]}]}}}());hljs.registerLanguage("sql",function(){"use strict";return function(e){var t=e.COMMENT("--","$");return{name:"SQL",case_insensitive:!0,illegal:/[<>{}*]/,contains:[{beginKeywords:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke comment values with",end:/;/,endsWithParent:!0,keywords:{$pattern:/[\w\.]+/,keyword:"as abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias all allocate allow alter always analyze ancillary and anti any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound bucket buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain explode export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force foreign form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour hours http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lateral lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minutes minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notnull notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second seconds section securefile security seed segment select self semi sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tablesample tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unnest unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace window with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek",literal:"true false null unknown",built_in:"array bigint binary bit blob bool boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text time timestamp tinyint varchar varchar2 varying void"},contains:[{className:"string",begin:"'",end:"'",contains:[{begin:"''"}]},{className:"string",begin:'"',end:'"',contains:[{begin:'""'}]},{className:"string",begin:"`",end:"`"},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,e.HASH_COMMENT_MODE]},e.C_BLOCK_COMMENT_MODE,t,e.HASH_COMMENT_MODE]}}}());hljs.registerLanguage("c",function(){"use strict";return function(e){var n=e.getLanguage("c-like").rawDefinition();return n.name="C",n.aliases=["c","h"],n}}());hljs.registerLanguage("json",function(){"use strict";return function(n){var e={literal:"true false null"},i=[n.C_LINE_COMMENT_MODE,n.C_BLOCK_COMMENT_MODE],t=[n.QUOTE_STRING_MODE,n.C_NUMBER_MODE],a={end:",",endsWithParent:!0,excludeEnd:!0,contains:t,keywords:e},l={begin:"{",end:"}",contains:[{className:"attr",begin:/"/,end:/"/,contains:[n.BACKSLASH_ESCAPE],illegal:"\\n"},n.inherit(a,{begin:/:/})].concat(i),illegal:"\\S"},s={begin:"\\[",end:"\\]",contains:[n.inherit(a)],illegal:"\\S"};return t.push(l,s),i.forEach((function(n){t.push(n)})),{name:"JSON",contains:t,keywords:e,illegal:"\\S"}}}());hljs.registerLanguage("python-repl",function(){"use strict";return function(n){return{aliases:["pycon"],contains:[{className:"meta",starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}}}());hljs.registerLanguage("markdown",function(){"use strict";return function(n){const e={begin:"<",end:">",subLanguage:"xml",relevance:0},a={begin:"\\[.+?\\][\\(\\[].*?[\\)\\]]",returnBegin:!0,contains:[{className:"string",begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0,relevance:0},{className:"link",begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}],relevance:10},i={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},s={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]};i.contains.push(s),s.contains.push(i);var c=[e,a];return i.contains=i.contains.concat(c),s.contains=s.contains.concat(c),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:c=c.concat(i,s)},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:c}]}]},e,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},i,s,{className:"quote",begin:"^>\\s+",contains:c,end:"$"},{className:"code",variants:[{begin:"(`{3,})(.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})(.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{begin:"^[-\\*]{3,}",end:"$"},a,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}}}());hljs.registerLanguage("javascript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);function s(e){return r("(?=",e,")")}function r(...e){return e.map(e=>(function(e){return e?"string"==typeof e?e:e.source:null})(e)).join("")}return function(t){var i="[A-Za-z$_][0-9A-Za-z$_]*",c={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/},o={$pattern:"[A-Za-z$_][0-9A-Za-z$_]*",keyword:e.join(" "),literal:n.join(" "),built_in:a.join(" ")},l={className:"number",variants:[{begin:"\\b(0[bB][01]+)n?"},{begin:"\\b(0[oO][0-7]+)n?"},{begin:t.C_NUMBER_RE+"n?"}],relevance:0},E={className:"subst",begin:"\\$\\{",end:"\\}",keywords:o,contains:[]},d={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,E],subLanguage:"xml"}},g={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,E],subLanguage:"css"}},u={className:"string",begin:"`",end:"`",contains:[t.BACKSLASH_ESCAPE,E]};E.contains=[t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,d,g,u,l,t.REGEXP_MODE];var b=E.contains.concat([{begin:/\(/,end:/\)/,contains:["self"].concat(E.contains,[t.C_BLOCK_COMMENT_MODE,t.C_LINE_COMMENT_MODE])},t.C_BLOCK_COMMENT_MODE,t.C_LINE_COMMENT_MODE]),_={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:b};return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:o,contains:[t.SHEBANG({binary:"node",relevance:5}),{className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,d,g,u,t.C_LINE_COMMENT_MODE,t.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+",contains:[{className:"type",begin:"\\{",end:"\\}",relevance:0},{className:"variable",begin:i+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]}),t.C_BLOCK_COMMENT_MODE,l,{begin:r(/[{,\n]\s*/,s(r(/(((\/\/.*)|(\/\*(.|\n)*\*\/))\s*)*/,i+"\\s*:"))),relevance:0,contains:[{className:"attr",begin:i+s("\\s*:"),relevance:0}]},{begin:"("+t.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE,t.REGEXP_MODE,{className:"function",begin:"(\\([^(]*(\\([^(]*(\\([^(]*\\))?\\))?\\)|"+t.UNDERSCORE_IDENT_RE+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:t.UNDERSCORE_IDENT_RE},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:o,contains:b}]}]},{begin:/,/,relevance:0},{className:"",begin:/\s/,end:/\s*/,skip:!0},{variants:[{begin:"<>",end:""},{begin:c.begin,end:c.end}],subLanguage:"xml",contains:[{begin:c.begin,end:c.end,skip:!0,contains:["self"]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/\{/,excludeEnd:!0,contains:[t.inherit(t.TITLE_MODE,{begin:i}),_],illegal:/\[|%/},{begin:/\$[(.]/},t.METHOD_GUARD,{className:"class",beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends"},t.UNDERSCORE_TITLE_MODE]},{beginKeywords:"constructor",end:/\{/,excludeEnd:!0},{begin:"(get|set)\\s+(?="+i+"\\()",end:/{/,keywords:"get set",contains:[t.inherit(t.TITLE_MODE,{begin:i}),{begin:/\(\)/},_]}],illegal:/#(?!!)/}}}());hljs.registerLanguage("typescript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);return function(r){var t={$pattern:"[A-Za-z$_][0-9A-Za-z$_]*",keyword:e.concat(["type","namespace","typedef","interface","public","private","protected","implements","declare","abstract","readonly"]).join(" "),literal:n.join(" "),built_in:a.concat(["any","void","number","boolean","string","object","never","enum"]).join(" ")},s={className:"meta",begin:"@[A-Za-z$_][0-9A-Za-z$_]*"},i={className:"number",variants:[{begin:"\\b(0[bB][01]+)n?"},{begin:"\\b(0[oO][0-7]+)n?"},{begin:r.C_NUMBER_RE+"n?"}],relevance:0},o={className:"subst",begin:"\\$\\{",end:"\\}",keywords:t,contains:[]},c={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[r.BACKSLASH_ESCAPE,o],subLanguage:"xml"}},l={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[r.BACKSLASH_ESCAPE,o],subLanguage:"css"}},E={className:"string",begin:"`",end:"`",contains:[r.BACKSLASH_ESCAPE,o]};o.contains=[r.APOS_STRING_MODE,r.QUOTE_STRING_MODE,c,l,E,i,r.REGEXP_MODE];var d={begin:"\\(",end:/\)/,keywords:t,contains:["self",r.QUOTE_STRING_MODE,r.APOS_STRING_MODE,r.NUMBER_MODE]},u={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:t,contains:[r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,s,d]};return{name:"TypeScript",aliases:["ts"],keywords:t,contains:[r.SHEBANG(),{className:"meta",begin:/^\s*['"]use strict['"]/},r.APOS_STRING_MODE,r.QUOTE_STRING_MODE,c,l,E,r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,i,{begin:"("+r.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,r.REGEXP_MODE,{className:"function",begin:"(\\([^(]*(\\([^(]*(\\([^(]*\\))?\\))?\\)|"+r.UNDERSCORE_IDENT_RE+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:r.UNDERSCORE_IDENT_RE},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:t,contains:d.contains}]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/[\{;]/,excludeEnd:!0,keywords:t,contains:["self",r.inherit(r.TITLE_MODE,{begin:"[A-Za-z$_][0-9A-Za-z$_]*"}),u],illegal:/%/,relevance:0},{beginKeywords:"constructor",end:/[\{;]/,excludeEnd:!0,contains:["self",u]},{begin:/module\./,keywords:{built_in:"module"},relevance:0},{beginKeywords:"module",end:/\{/,excludeEnd:!0},{beginKeywords:"interface",end:/\{/,excludeEnd:!0,keywords:"interface extends"},{begin:/\$[(.]/},{begin:"\\."+r.IDENT_RE,relevance:0},s,d]}}}());hljs.registerLanguage("plaintext",function(){"use strict";return function(t){return{name:"Plain text",aliases:["text","txt"],disableAutodetect:!0}}}());hljs.registerLanguage("less",function(){"use strict";return function(e){var n="([\\w-]+|@{[\\w-]+})",a=[],s=[],t=function(e){return{className:"string",begin:"~?"+e+".*?"+e}},r=function(e,n,a){return{className:e,begin:n,relevance:a}},i={begin:"\\(",end:"\\)",contains:s,relevance:0};s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,t("'"),t('"'),e.CSS_NUMBER_MODE,{begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]",excludeEnd:!0}},r("number","#[0-9A-Fa-f]+\\b"),i,r("variable","@@?[\\w-]+",10),r("variable","@{[\\w-]+}"),r("built_in","~?`[^`]*?`"),{className:"attribute",begin:"[\\w-]+\\s*:",end:":",returnBegin:!0,excludeEnd:!0},{className:"meta",begin:"!important"});var c=s.concat({begin:"{",end:"}",contains:a}),l={beginKeywords:"when",endsWithParent:!0,contains:[{beginKeywords:"and not"}].concat(s)},o={begin:n+"\\s*:",returnBegin:!0,end:"[;}]",relevance:0,contains:[{className:"attribute",begin:n,end:":",excludeEnd:!0,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:s}}]},g={className:"keyword",begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b",starts:{end:"[;{}]",returnEnd:!0,contains:s,relevance:0}},d={className:"variable",variants:[{begin:"@[\\w-]+\\s*:",relevance:15},{begin:"@[\\w-]+"}],starts:{end:"[;}]",returnEnd:!0,contains:c}},b={variants:[{begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:n,end:"{"}],returnBegin:!0,returnEnd:!0,illegal:"[<='$\"]",relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,l,r("keyword","all\\b"),r("variable","@{[\\w-]+}"),r("selector-tag",n+"%?",0),r("selector-id","#"+n),r("selector-class","\\."+n,0),r("selector-tag","&",0),{className:"selector-attr",begin:"\\[",end:"\\]"},{className:"selector-pseudo",begin:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{begin:"\\(",end:"\\)",contains:c},{begin:"!important"}]};return a.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,g,d,o,b),{name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:a}}}());hljs.registerLanguage("lua",function(){"use strict";return function(e){var t={begin:"\\[=*\\[",end:"\\]=*\\]",contains:["self"]},a=[e.COMMENT("--(?!\\[=*\\[)","$"),e.COMMENT("--\\[=*\\[","\\]=*\\]",{contains:[t],relevance:10})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE,literal:"true false nil",keyword:"and break do else elseif end for goto if in local not or repeat return then until while",built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove"},contains:a.concat([{className:"function",beginKeywords:"function",end:"\\)",contains:[e.inherit(e.TITLE_MODE,{begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params",begin:"\\(",endsWithParent:!0,contains:a}].concat(a)},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string",begin:"\\[=*\\[",end:"\\]=*\\]",contains:[t],relevance:5}])}}}()); diff --git a/index.html b/index.html new file mode 100644 index 0000000..6e3d78e --- /dev/null +++ b/index.html @@ -0,0 +1,203 @@ + + + + + + Tech Start UCalgary Documentation - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Introduction

+

Hi there! +This website contains tutorials, how-to guides, explanations, +and reference documentation of the things we do at +Tech Start UCalgary.

+

If you are looking for our main page, +please visit us at techstartucalgary.com.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/installation/installfest/index.html b/installation/installfest/index.html new file mode 100644 index 0000000..3ce51e0 --- /dev/null +++ b/installation/installfest/index.html @@ -0,0 +1,354 @@ + + + + + + Installfest: from zero to hero - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Installfest: From zero to hero

+

Introduction

+

We understand that setting up your computer for development can be a daunting task. There are so many tools and libraries that you need to install, and it's hard to know where to start. That's why we created this guide to help you get started with your development environment.

+

Lost Kermit

+

This guide will help you install all the tools you need to start coding. It will also help you configure your computer so that you can easily switch between different versions of Node.js and Python. Your don't need to install everything in this guide, only the tools you need for your project. If you are not sure what tools you need, ask your project lead or one of the exec members.

+

Table of Contents

+ +

Windows Users

+

If you are using Windows, we recommend that you install WSL2 and Ubuntu as your development environment. You can find instructions on how to do so here: WSL2 Installation Once you have installed WSL2 and Ubuntu, you can continue with this guide.

+

Installing Homebrew

+

Homebrew is a package manager for macOS (or Linux) that allows you to easily install and manage software packages and libraries. It simplifies the installation process by automating the installation of dependencies and providing a consistent interface for installing software. To install Homebrew, run the following command:

+
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
+
+

If you are using Windows, run the following commands:

+
test -d ~/.linuxbrew && eval "$(~/.linuxbrew/bin/brew shellenv)"
+test -d /home/linuxbrew/.linuxbrew && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
+test -r ~/.bash_profile && echo "eval \"\$($(brew --prefix)/bin/brew shellenv)\"" >> ~/.bash_profile
+echo "eval \"\$($(brew --prefix)/bin/brew shellenv)\"" >> ~/.profile
+
+

To check if Homebrew is installed, run the following command:

+
brew --version
+
+

It should return something like this:

+
Homebrew 3.2.0
+Homebrew/homebrew-core (git revision 3b6; last commit 2021-07-26)
+
+

Installing VSCode: MacOS

+

Visual Studio Code is a free source-code editor made by Microsoft for Windows, Linux and macOS. Features include support for debugging, syntax highlighting, intelligent code completion, snippets, code refactoring, and embedded Git. To install VSCode, run the following command:

+
brew install --cask visual-studio-code
+
+

To check if VSCode is installed, run the following command:

+
code --version
+
+

Installing VSCode: Windows WSFL2

+

To install VSCode, download it from the following link: VSCode Installer Once downloaded, open VScode in Windows.

+

Open the remote explorer by pressing Ctrl+Shift+P and typing View: Show Remote Explorer and selecting WSL Targets.

+

Remote Explorer

+

Then select Ubuntu 20.04 or the version of Ubuntu you installed. This will cause some reinstalling to happen, but once it's done, you will be able to use VSCode with Ubuntu.

+

To check if WSL2 is connected with VSCode, go to the WSFL2 terminal and run the following command:

+
code .
+
+

Installing Git

+

Git is a free and open-source distributed version control system designed to handle everything from small to very large projects with speed and efficiency. It is the most widely used modern version control system in the world today. To start using Git, you need to run the following command:

+
brew install git
+
+

To check if Git is installed, run the following command:

+
git --version
+
+

To configure Git, run the following commands:

+
git config --global user.name "YOUR_NAME"
+
+
git config --global user.email "YOUR_EMAIL"
+
+

Then donwload the github cli:

+
brew install gh
+
+

and authenticate with your github account:

+
gh auth login
+
+

to check if it worked:

+
gh auth status
+
+

Installing bash-completion

+

bash-completion is a collection of shell functions that take advantage of the programmable completion feature of bash. It provides completions for various commands, including git, npm, and others. To install bash-completion, run the following command:

+
brew install bash-completion
+
+

To configure bash-completion, run the following command:

+
code ~/.bash_profile
+
+

And add the following lines at the end of the file and save it:

+
if [ -f $(brew --prefix)/etc/bash_completion ]; then
+    . $(brew --prefix)/etc/bash_completion
+fi
+
+

Installing Node

+

Node.js is an open-source, cross-platform, back-end JavaScript runtime environment that runs on the V8 engine and executes JavaScript code outside a web browser. It allows developers to use JavaScript to write command-line tools and for server-side scripting—running scripts server-side to produce dynamic web page content before the page is sent to the user's web browser. To install Node, run the following command:

+
brew install node
+
+

To check if Node is installed, run the following command:

+
node --version
+
+

Installing Nvm

+

nvm stands for Node Version Manager. It is a tool that allows you to easily install and manage multiple versions of Node.js on a single machine. This is useful for developers who need to work with different versions of Node.js for different projects. To install nvm, run the following command:

+
brew install nvm
+
+

To configure nvm, run the following command:

+
mkdir ~/.nvm
+
+

Then open your ~/.bash_profile using:

+
code ~/.bash_profile
+
+

And at the following lines at the end of the file and save it:

+
export NVM_DIR=~/.nvm
+source $(brew --prefix nvm)/nvm.sh
+
+

Close and reopen your terminal. To check if nvm is installed, run the following command:

+
nvm --version
+
+

To change versions of node, run the following command:

+
nvm install <version>
+
+

for example:

+
nvm install 14.17.6
+
+

To see which version are available, run the following command:

+
nvm ls-remote
+
+

make sure you team is using the same version of node for consistency and to avoid errors.

+

Installing Python

+

Python is an interpreted, high-level, general-purpose programming language. Created by Guido van Rossum and first released in 1991, Python's design philosophy emphasizes code readability with its notable use of significant whitespace. To install Python, run the following command:

+
brew install python
+
+

By default, Homebrew installs Python 3.x. To check if Python is installed, run the following command:

+
python3 --version
+
+

Installing Pip

+

pip is a package management system used to install and manage software packages written in Python. Many packages can be found in the Python Package Index (PyPI).

+
brew install pip
+
+

To check if pip is installed, run the following command:

+
pip --version
+
+

Installing Pyenv

+

pyenv is a simple yet powerful tool that allows you to easily install and manage multiple versions of Python on a single machine. This is useful for developers who need to work with different versions of Python for different projects. Using pyenv will also allow you to group your project dependencies into a single virtual environments, which will make dependency management much easier. To install pyenv, run the following command:

+
brew install pyenv
+
+

To check if pyenv is installed, run the following command:

+
pyenv --version
+
+

pyenv will be useful for those who are working with Django or Flask.

+

Downloading Xcode

+

Recommended for those who are working with React Native. Xcode is an integrated development environment (IDE) for macOS containing a suite of software development tools developed by Apple for developing software for macOS, iOS, iPadOS, watchOS, and tvOS. To download Xcode, go to the App Store and search for Xcode.

+

That's it!

+

Now that you have installed all the tools you need, you are ready to start coding like a PRO. If you have any questions, feel free to ask your project lead or one of the exec members.

+

Typing Kermit

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/installation/installfest/lost-kermit.gif b/installation/installfest/lost-kermit.gif new file mode 100644 index 0000000..b3c68af Binary files /dev/null and b/installation/installfest/lost-kermit.gif differ diff --git a/installation/installfest/remote-explorer.png b/installation/installfest/remote-explorer.png new file mode 100644 index 0000000..aa83ff2 Binary files /dev/null and b/installation/installfest/remote-explorer.png differ diff --git a/installation/installfest/typing-kermit.gif b/installation/installfest/typing-kermit.gif new file mode 100644 index 0000000..254e6e3 Binary files /dev/null and b/installation/installfest/typing-kermit.gif differ diff --git a/installation/wsl2/index.html b/installation/wsl2/index.html new file mode 100644 index 0000000..55586b7 --- /dev/null +++ b/installation/wsl2/index.html @@ -0,0 +1,254 @@ + + + + + + WSL2 Installation - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

WSL2 Installation

+

Introduction

+

WSL2 is a new version of the Windows Subsystem for Linux that is built on top of Hyper-V. It provides a full Linux kernel and userspace environment that runs natively on Windows. This means that you can run Linux applications on Windows without having to install a virtual machine or dual boot your computer. WSL2 is faster than WSL1 because it uses Hyper-V instead of VirtualBox. It also has better support for Docker and other container technologies.

+

Table of Contents

+ +

Installing WSL2

+

To install WSL2, you need to have Windows 10 version 2004 or higher. To check your Windows version, open your Powershell and run the following command:

+
winver
+
+

If you have an older version of Windows, you can upgrade to the latest version by going to Settings > Update & Security > Windows Update > Check for updates.

+

Then search for "Turn Windows features on or off" in the start menu and open it.

+

Turn Windows features on or off

+

Then check the box next to "Windows Subsystem for Linux" and "Windows Hypervisor Platform" and click OK. You will be prompted to restart your computer.

+

Windows Subsystem for Linux

+

Installing Ubuntu

+

To install Ubuntu, go to the Microsoft Store and search for "Ubuntu". Then click on "Ubuntu 20.04 LTS" and click "Get".

+

Ubuntu

+

Ubuntu

+

Once installed, you can launch Ubuntu by opening the terminal from the start menu.

+

Terminal

+

to switch to Ubuntu, click on the Ubuntu icon in the top left corner of the terminal window as shown below:

+

Ubuntu

+

You can configure a default Ubuntu terminal by going to Settings > Terminal > Default profile > Ubuntu.

+

Ubuntu

+

That's it!

+

You have successfully installed WSL2 and Ubuntu. Now you can start using Linux applications on Windows without having to install a virtual machine or dual boot your computer. For your project we recommend using WSFL2 and Ubuntu as your development environment. If you are done working, you can close the terminal window and it will automatically shut down the Ubuntu environment. Continue the installfest here: Installfest

+

I don't know how to use Linux, help!

+

If you are not familiar with Linux, we recommend that you take a look at the following resources:

+ +

At minimum, you should learn the following commands:

+
    +
  • pwd
  • +
  • ls
  • +
  • cd
  • +
  • mkdir
  • +
  • touch
  • +
  • rm
  • +
  • mv
  • +
  • cp
  • +
  • cat
  • +
  • sudo
  • +
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/installation/wsl2/windows1.png b/installation/wsl2/windows1.png new file mode 100644 index 0000000..d07ddc3 Binary files /dev/null and b/installation/wsl2/windows1.png differ diff --git a/installation/wsl2/windows2.png b/installation/wsl2/windows2.png new file mode 100644 index 0000000..eb54802 Binary files /dev/null and b/installation/wsl2/windows2.png differ diff --git a/installation/wsl2/windows3.png b/installation/wsl2/windows3.png new file mode 100644 index 0000000..520f6af Binary files /dev/null and b/installation/wsl2/windows3.png differ diff --git a/installation/wsl2/windows4.png b/installation/wsl2/windows4.png new file mode 100644 index 0000000..f07fa94 Binary files /dev/null and b/installation/wsl2/windows4.png differ diff --git a/installation/wsl2/windows5.png b/installation/wsl2/windows5.png new file mode 100644 index 0000000..81d9151 Binary files /dev/null and b/installation/wsl2/windows5.png differ diff --git a/installation/wsl2/windows6.png b/installation/wsl2/windows6.png new file mode 100644 index 0000000..d70928f Binary files /dev/null and b/installation/wsl2/windows6.png differ diff --git a/installation/wsl2/windows7.png b/installation/wsl2/windows7.png new file mode 100644 index 0000000..6815f4d Binary files /dev/null and b/installation/wsl2/windows7.png differ diff --git a/mark.min.js b/mark.min.js new file mode 100644 index 0000000..1636231 --- /dev/null +++ b/mark.min.js @@ -0,0 +1,7 @@ +/*!*************************************************** +* mark.js v8.11.1 +* https://markjs.io/ +* Copyright (c) 2014–2018, Julian Kühnel +* Released under the MIT license https://git.io/vwTVl +*****************************************************/ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Mark=t()}(this,function(){"use strict";var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},t=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},n=function(){function e(e,t){for(var n=0;n1&&void 0!==arguments[1])||arguments[1],i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:5e3;t(this,e),this.ctx=n,this.iframes=r,this.exclude=i,this.iframesTimeout=o}return n(e,[{key:"getContexts",value:function(){var e=[];return(void 0!==this.ctx&&this.ctx?NodeList.prototype.isPrototypeOf(this.ctx)?Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?this.ctx:"string"==typeof this.ctx?Array.prototype.slice.call(document.querySelectorAll(this.ctx)):[this.ctx]:[]).forEach(function(t){var n=e.filter(function(e){return e.contains(t)}).length>0;-1!==e.indexOf(t)||n||e.push(t)}),e}},{key:"getIframeContents",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},r=void 0;try{var i=e.contentWindow;if(r=i.document,!i||!r)throw new Error("iframe inaccessible")}catch(e){n()}r&&t(r)}},{key:"isIframeBlank",value:function(e){var t="about:blank",n=e.getAttribute("src").trim();return e.contentWindow.location.href===t&&n!==t&&n}},{key:"observeIframeLoad",value:function(e,t,n){var r=this,i=!1,o=null,a=function a(){if(!i){i=!0,clearTimeout(o);try{r.isIframeBlank(e)||(e.removeEventListener("load",a),r.getIframeContents(e,t,n))}catch(e){n()}}};e.addEventListener("load",a),o=setTimeout(a,this.iframesTimeout)}},{key:"onIframeReady",value:function(e,t,n){try{"complete"===e.contentWindow.document.readyState?this.isIframeBlank(e)?this.observeIframeLoad(e,t,n):this.getIframeContents(e,t,n):this.observeIframeLoad(e,t,n)}catch(e){n()}}},{key:"waitForIframes",value:function(e,t){var n=this,r=0;this.forEachIframe(e,function(){return!0},function(e){r++,n.waitForIframes(e.querySelector("html"),function(){--r||t()})},function(e){e||t()})}},{key:"forEachIframe",value:function(t,n,r){var i=this,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},a=t.querySelectorAll("iframe"),s=a.length,c=0;a=Array.prototype.slice.call(a);var u=function(){--s<=0&&o(c)};s||u(),a.forEach(function(t){e.matches(t,i.exclude)?u():i.onIframeReady(t,function(e){n(t)&&(c++,r(e)),u()},u)})}},{key:"createIterator",value:function(e,t,n){return document.createNodeIterator(e,t,n,!1)}},{key:"createInstanceOnIframe",value:function(t){return new e(t.querySelector("html"),this.iframes)}},{key:"compareNodeIframe",value:function(e,t,n){if(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_PRECEDING){if(null===t)return!0;if(t.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING)return!0}return!1}},{key:"getIteratorNode",value:function(e){var t=e.previousNode();return{prevNode:t,node:null===t?e.nextNode():e.nextNode()&&e.nextNode()}}},{key:"checkIframeFilter",value:function(e,t,n,r){var i=!1,o=!1;return r.forEach(function(e,t){e.val===n&&(i=t,o=e.handled)}),this.compareNodeIframe(e,t,n)?(!1!==i||o?!1===i||o||(r[i].handled=!0):r.push({val:n,handled:!0}),!0):(!1===i&&r.push({val:n,handled:!1}),!1)}},{key:"handleOpenIframes",value:function(e,t,n,r){var i=this;e.forEach(function(e){e.handled||i.getIframeContents(e.val,function(e){i.createInstanceOnIframe(e).forEachNode(t,n,r)})})}},{key:"iterateThroughNodes",value:function(e,t,n,r,i){for(var o,a=this,s=this.createIterator(t,e,r),c=[],u=[],l=void 0,h=void 0;void 0,o=a.getIteratorNode(s),h=o.prevNode,l=o.node;)this.iframes&&this.forEachIframe(t,function(e){return a.checkIframeFilter(l,h,e,c)},function(t){a.createInstanceOnIframe(t).forEachNode(e,function(e){return u.push(e)},r)}),u.push(l);u.forEach(function(e){n(e)}),this.iframes&&this.handleOpenIframes(c,e,n,r),i()}},{key:"forEachNode",value:function(e,t,n){var r=this,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},o=this.getContexts(),a=o.length;a||i(),o.forEach(function(o){var s=function(){r.iterateThroughNodes(e,o,t,n,function(){--a<=0&&i()})};r.iframes?r.waitForIframes(o,s):s()})}}],[{key:"matches",value:function(e,t){var n="string"==typeof t?[t]:t,r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector;if(r){var i=!1;return n.every(function(t){return!r.call(e,t)||(i=!0,!1)}),i}return!1}}]),e}(),o=function(){function e(n){t(this,e),this.opt=r({},{diacritics:!0,synonyms:{},accuracy:"partially",caseSensitive:!1,ignoreJoiners:!1,ignorePunctuation:[],wildcards:"disabled"},n)}return n(e,[{key:"create",value:function(e){return"disabled"!==this.opt.wildcards&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),"disabled"!==this.opt.wildcards&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e),new RegExp(e,"gm"+(this.opt.caseSensitive?"":"i"))}},{key:"escapeStr",value:function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}},{key:"createSynonymsRegExp",value:function(e){var t=this.opt.synonyms,n=this.opt.caseSensitive?"":"i",r=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(var i in t)if(t.hasOwnProperty(i)){var o=t[i],a="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(i):this.escapeStr(i),s="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(o):this.escapeStr(o);""!==a&&""!==s&&(e=e.replace(new RegExp("("+this.escapeStr(a)+"|"+this.escapeStr(s)+")","gm"+n),r+"("+this.processSynonyms(a)+"|"+this.processSynonyms(s)+")"+r))}return e}},{key:"processSynonyms",value:function(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}},{key:"setupWildcardsRegExp",value:function(e){return(e=e.replace(/(?:\\)*\?/g,function(e){return"\\"===e.charAt(0)?"?":""})).replace(/(?:\\)*\*/g,function(e){return"\\"===e.charAt(0)?"*":""})}},{key:"createWildcardsRegExp",value:function(e){var t="withSpaces"===this.opt.wildcards;return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}},{key:"setupIgnoreJoinersRegExp",value:function(e){return e.replace(/[^(|)\\]/g,function(e,t,n){var r=n.charAt(t+1);return/[(|)\\]/.test(r)||""===r?e:e+"\0"})}},{key:"createJoinersRegExp",value:function(e){var t=[],n=this.opt.ignorePunctuation;return Array.isArray(n)&&n.length&&t.push(this.escapeStr(n.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join("["+t.join("")+"]*"):e}},{key:"createDiacriticsRegExp",value:function(e){var t=this.opt.caseSensitive?"":"i",n=this.opt.caseSensitive?["aàáảãạăằắẳẵặâầấẩẫậäåāą","AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćč","CÇĆČ","dđď","DĐĎ","eèéẻẽẹêềếểễệëěēę","EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïī","IÌÍỈĨỊÎÏĪ","lł","LŁ","nñňń","NÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøō","OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rř","RŘ","sšśșş","SŠŚȘŞ","tťțţ","TŤȚŢ","uùúủũụưừứửữựûüůū","UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿ","YÝỲỶỸỴŸ","zžżź","ZŽŻŹ"]:["aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćčCÇĆČ","dđďDĐĎ","eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïīIÌÍỈĨỊÎÏĪ","lłLŁ","nñňńNÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rřRŘ","sšśșşSŠŚȘŞ","tťțţTŤȚŢ","uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿYÝỲỶỸỴŸ","zžżźZŽŻŹ"],r=[];return e.split("").forEach(function(i){n.every(function(n){if(-1!==n.indexOf(i)){if(r.indexOf(n)>-1)return!1;e=e.replace(new RegExp("["+n+"]","gm"+t),"["+n+"]"),r.push(n)}return!0})}),e}},{key:"createMergedBlanksRegExp",value:function(e){return e.replace(/[\s]+/gim,"[\\s]+")}},{key:"createAccuracyRegExp",value:function(e){var t=this,n=this.opt.accuracy,r="string"==typeof n?n:n.value,i="";switch(("string"==typeof n?[]:n.limiters).forEach(function(e){i+="|"+t.escapeStr(e)}),r){case"partially":default:return"()("+e+")";case"complementary":return"()([^"+(i="\\s"+(i||this.escapeStr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~¡¿")))+"]*"+e+"[^"+i+"]*)";case"exactly":return"(^|\\s"+i+")("+e+")(?=$|\\s"+i+")"}}}]),e}(),a=function(){function a(e){t(this,a),this.ctx=e,this.ie=!1;var n=window.navigator.userAgent;(n.indexOf("MSIE")>-1||n.indexOf("Trident")>-1)&&(this.ie=!0)}return n(a,[{key:"log",value:function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"debug",r=this.opt.log;this.opt.debug&&"object"===(void 0===r?"undefined":e(r))&&"function"==typeof r[n]&&r[n]("mark.js: "+t)}},{key:"getSeparatedKeywords",value:function(e){var t=this,n=[];return e.forEach(function(e){t.opt.separateWordSearch?e.split(" ").forEach(function(e){e.trim()&&-1===n.indexOf(e)&&n.push(e)}):e.trim()&&-1===n.indexOf(e)&&n.push(e)}),{keywords:n.sort(function(e,t){return t.length-e.length}),length:n.length}}},{key:"isNumeric",value:function(e){return Number(parseFloat(e))==e}},{key:"checkRanges",value:function(e){var t=this;if(!Array.isArray(e)||"[object Object]"!==Object.prototype.toString.call(e[0]))return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];var n=[],r=0;return e.sort(function(e,t){return e.start-t.start}).forEach(function(e){var i=t.callNoMatchOnInvalidRanges(e,r),o=i.start,a=i.end;i.valid&&(e.start=o,e.length=a-o,n.push(e),r=a)}),n}},{key:"callNoMatchOnInvalidRanges",value:function(e,t){var n=void 0,r=void 0,i=!1;return e&&void 0!==e.start?(r=(n=parseInt(e.start,10))+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&r-t>0&&r-n>0?i=!0:(this.log("Ignoring invalid or overlapping range: "+JSON.stringify(e)),this.opt.noMatch(e))):(this.log("Ignoring invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:n,end:r,valid:i}}},{key:"checkWhitespaceRanges",value:function(e,t,n){var r=void 0,i=!0,o=n.length,a=t-o,s=parseInt(e.start,10)-a;return(r=(s=s>o?o:s)+parseInt(e.length,10))>o&&(r=o,this.log("End range automatically set to the max value of "+o)),s<0||r-s<0||s>o||r>o?(i=!1,this.log("Invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)):""===n.substring(s,r).replace(/\s+/g,"")&&(i=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:s,end:r,valid:i}}},{key:"getTextNodes",value:function(e){var t=this,n="",r=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,function(e){r.push({start:n.length,end:(n+=e.textContent).length,node:e})},function(e){return t.matchesExclude(e.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},function(){e({value:n,nodes:r})})}},{key:"matchesExclude",value:function(e){return i.matches(e,this.opt.exclude.concat(["script","style","title","head","html"]))}},{key:"wrapRangeInTextNode",value:function(e,t,n){var r=this.opt.element?this.opt.element:"mark",i=e.splitText(t),o=i.splitText(n-t),a=document.createElement(r);return a.setAttribute("data-markjs","true"),this.opt.className&&a.setAttribute("class",this.opt.className),a.textContent=i.textContent,i.parentNode.replaceChild(a,i),o}},{key:"wrapRangeInMappedTextNode",value:function(e,t,n,r,i){var o=this;e.nodes.every(function(a,s){var c=e.nodes[s+1];if(void 0===c||c.start>t){if(!r(a.node))return!1;var u=t-a.start,l=(n>a.end?a.end:n)-a.start,h=e.value.substr(0,a.start),f=e.value.substr(l+a.start);if(a.node=o.wrapRangeInTextNode(a.node,u,l),e.value=h+f,e.nodes.forEach(function(t,n){n>=s&&(e.nodes[n].start>0&&n!==s&&(e.nodes[n].start-=l),e.nodes[n].end-=l)}),n-=l,i(a.node.previousSibling,a.start),!(n>a.end))return!1;t=a.end}return!0})}},{key:"wrapGroups",value:function(e,t,n,r){return r((e=this.wrapRangeInTextNode(e,t,t+n)).previousSibling),e}},{key:"separateGroups",value:function(e,t,n,r,i){for(var o=t.length,a=1;a-1&&r(t[a],e)&&(e=this.wrapGroups(e,s,t[a].length,i))}return e}},{key:"wrapMatches",value:function(e,t,n,r,i){var o=this,a=0===t?0:t+1;this.getTextNodes(function(t){t.nodes.forEach(function(t){t=t.node;for(var i=void 0;null!==(i=e.exec(t.textContent))&&""!==i[a];){if(o.opt.separateGroups)t=o.separateGroups(t,i,a,n,r);else{if(!n(i[a],t))continue;var s=i.index;if(0!==a)for(var c=1;c + + + + + Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Introduction

+

Hi there! +This website contains tutorials, how-to guides, explanations, +and reference documentation of the things we do at +Tech Start UCalgary.

+

If you are looking for our main page, +please visit us at techstartucalgary.com.

+

Installfest: From zero to hero

+

Introduction

+

We understand that setting up your computer for development can be a daunting task. There are so many tools and libraries that you need to install, and it's hard to know where to start. That's why we created this guide to help you get started with your development environment.

+

Lost Kermit

+

This guide will help you install all the tools you need to start coding. It will also help you configure your computer so that you can easily switch between different versions of Node.js and Python. Your don't need to install everything in this guide, only the tools you need for your project. If you are not sure what tools you need, ask your project lead or one of the exec members.

+

Table of Contents

+ +

Windows Users

+

If you are using Windows, we recommend that you install WSL2 and Ubuntu as your development environment. You can find instructions on how to do so here: WSL2 Installation Once you have installed WSL2 and Ubuntu, you can continue with this guide.

+

Installing Homebrew

+

Homebrew is a package manager for macOS (or Linux) that allows you to easily install and manage software packages and libraries. It simplifies the installation process by automating the installation of dependencies and providing a consistent interface for installing software. To install Homebrew, run the following command:

+
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
+
+

If you are using Windows, run the following commands:

+
test -d ~/.linuxbrew && eval "$(~/.linuxbrew/bin/brew shellenv)"
+test -d /home/linuxbrew/.linuxbrew && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
+test -r ~/.bash_profile && echo "eval \"\$($(brew --prefix)/bin/brew shellenv)\"" >> ~/.bash_profile
+echo "eval \"\$($(brew --prefix)/bin/brew shellenv)\"" >> ~/.profile
+
+

To check if Homebrew is installed, run the following command:

+
brew --version
+
+

It should return something like this:

+
Homebrew 3.2.0
+Homebrew/homebrew-core (git revision 3b6; last commit 2021-07-26)
+
+

Installing VSCode: MacOS

+

Visual Studio Code is a free source-code editor made by Microsoft for Windows, Linux and macOS. Features include support for debugging, syntax highlighting, intelligent code completion, snippets, code refactoring, and embedded Git. To install VSCode, run the following command:

+
brew install --cask visual-studio-code
+
+

To check if VSCode is installed, run the following command:

+
code --version
+
+

Installing VSCode: Windows WSFL2

+

To install VSCode, download it from the following link: VSCode Installer Once downloaded, open VScode in Windows.

+

Open the remote explorer by pressing Ctrl+Shift+P and typing View: Show Remote Explorer and selecting WSL Targets.

+

Remote Explorer

+

Then select Ubuntu 20.04 or the version of Ubuntu you installed. This will cause some reinstalling to happen, but once it's done, you will be able to use VSCode with Ubuntu.

+

To check if WSL2 is connected with VSCode, go to the WSFL2 terminal and run the following command:

+
code .
+
+

Installing Git

+

Git is a free and open-source distributed version control system designed to handle everything from small to very large projects with speed and efficiency. It is the most widely used modern version control system in the world today. To start using Git, you need to run the following command:

+
brew install git
+
+

To check if Git is installed, run the following command:

+
git --version
+
+

To configure Git, run the following commands:

+
git config --global user.name "YOUR_NAME"
+
+
git config --global user.email "YOUR_EMAIL"
+
+

Then donwload the github cli:

+
brew install gh
+
+

and authenticate with your github account:

+
gh auth login
+
+

to check if it worked:

+
gh auth status
+
+

Installing bash-completion

+

bash-completion is a collection of shell functions that take advantage of the programmable completion feature of bash. It provides completions for various commands, including git, npm, and others. To install bash-completion, run the following command:

+
brew install bash-completion
+
+

To configure bash-completion, run the following command:

+
code ~/.bash_profile
+
+

And add the following lines at the end of the file and save it:

+
if [ -f $(brew --prefix)/etc/bash_completion ]; then
+    . $(brew --prefix)/etc/bash_completion
+fi
+
+

Installing Node

+

Node.js is an open-source, cross-platform, back-end JavaScript runtime environment that runs on the V8 engine and executes JavaScript code outside a web browser. It allows developers to use JavaScript to write command-line tools and for server-side scripting—running scripts server-side to produce dynamic web page content before the page is sent to the user's web browser. To install Node, run the following command:

+
brew install node
+
+

To check if Node is installed, run the following command:

+
node --version
+
+

Installing Nvm

+

nvm stands for Node Version Manager. It is a tool that allows you to easily install and manage multiple versions of Node.js on a single machine. This is useful for developers who need to work with different versions of Node.js for different projects. To install nvm, run the following command:

+
brew install nvm
+
+

To configure nvm, run the following command:

+
mkdir ~/.nvm
+
+

Then open your ~/.bash_profile using:

+
code ~/.bash_profile
+
+

And at the following lines at the end of the file and save it:

+
export NVM_DIR=~/.nvm
+source $(brew --prefix nvm)/nvm.sh
+
+

Close and reopen your terminal. To check if nvm is installed, run the following command:

+
nvm --version
+
+

To change versions of node, run the following command:

+
nvm install <version>
+
+

for example:

+
nvm install 14.17.6
+
+

To see which version are available, run the following command:

+
nvm ls-remote
+
+

make sure you team is using the same version of node for consistency and to avoid errors.

+

Installing Python

+

Python is an interpreted, high-level, general-purpose programming language. Created by Guido van Rossum and first released in 1991, Python's design philosophy emphasizes code readability with its notable use of significant whitespace. To install Python, run the following command:

+
brew install python
+
+

By default, Homebrew installs Python 3.x. To check if Python is installed, run the following command:

+
python3 --version
+
+

Installing Pip

+

pip is a package management system used to install and manage software packages written in Python. Many packages can be found in the Python Package Index (PyPI).

+
brew install pip
+
+

To check if pip is installed, run the following command:

+
pip --version
+
+

Installing Pyenv

+

pyenv is a simple yet powerful tool that allows you to easily install and manage multiple versions of Python on a single machine. This is useful for developers who need to work with different versions of Python for different projects. Using pyenv will also allow you to group your project dependencies into a single virtual environments, which will make dependency management much easier. To install pyenv, run the following command:

+
brew install pyenv
+
+

To check if pyenv is installed, run the following command:

+
pyenv --version
+
+

pyenv will be useful for those who are working with Django or Flask.

+

Downloading Xcode

+

Recommended for those who are working with React Native. Xcode is an integrated development environment (IDE) for macOS containing a suite of software development tools developed by Apple for developing software for macOS, iOS, iPadOS, watchOS, and tvOS. To download Xcode, go to the App Store and search for Xcode.

+

That's it!

+

Now that you have installed all the tools you need, you are ready to start coding like a PRO. If you have any questions, feel free to ask your project lead or one of the exec members.

+

Typing Kermit

+

WSL2 Installation

+

Introduction

+

WSL2 is a new version of the Windows Subsystem for Linux that is built on top of Hyper-V. It provides a full Linux kernel and userspace environment that runs natively on Windows. This means that you can run Linux applications on Windows without having to install a virtual machine or dual boot your computer. WSL2 is faster than WSL1 because it uses Hyper-V instead of VirtualBox. It also has better support for Docker and other container technologies.

+

Table of Contents

+ +

Installing WSL2

+

To install WSL2, you need to have Windows 10 version 2004 or higher. To check your Windows version, open your Powershell and run the following command:

+
winver
+
+

If you have an older version of Windows, you can upgrade to the latest version by going to Settings > Update & Security > Windows Update > Check for updates.

+

Then search for "Turn Windows features on or off" in the start menu and open it.

+

Turn Windows features on or off

+

Then check the box next to "Windows Subsystem for Linux" and "Windows Hypervisor Platform" and click OK. You will be prompted to restart your computer.

+

Windows Subsystem for Linux

+

Installing Ubuntu

+

To install Ubuntu, go to the Microsoft Store and search for "Ubuntu". Then click on "Ubuntu 20.04 LTS" and click "Get".

+

Ubuntu

+

Ubuntu

+

Once installed, you can launch Ubuntu by opening the terminal from the start menu.

+

Terminal

+

to switch to Ubuntu, click on the Ubuntu icon in the top left corner of the terminal window as shown below:

+

Ubuntu

+

You can configure a default Ubuntu terminal by going to Settings > Terminal > Default profile > Ubuntu.

+

Ubuntu

+

That's it!

+

You have successfully installed WSL2 and Ubuntu. Now you can start using Linux applications on Windows without having to install a virtual machine or dual boot your computer. For your project we recommend using WSFL2 and Ubuntu as your development environment. If you are done working, you can close the terminal window and it will automatically shut down the Ubuntu environment. Continue the installfest here: Installfest

+

I don't know how to use Linux, help!

+

If you are not familiar with Linux, we recommend that you take a look at the following resources:

+ +

At minimum, you should learn the following commands:

+
    +
  • pwd
  • +
  • ls
  • +
  • cd
  • +
  • mkdir
  • +
  • touch
  • +
  • rm
  • +
  • mv
  • +
  • cp
  • +
  • cat
  • +
  • sudo
  • +
+

Motivation

+

Guess what most of the top Software Developers have in common?

+

They all have cool projects!

+

torvalds, +dtolnay, +sindresorhus, +donnemartin, +kamranahmedse, +jwasham, +trekhleb, +tiangolo, +gre, +vmihailenco, +twpayne, +brycedrennan, +marten-seemann, +rusty1s, +kripken, +krisnova.

+

And those projects are successful:

+

FastAPI and Typer by Tiangolo

+

Tech Start UCalgary mission +is to foster an environment +where people can become a better version of themselves +through creating software projects.

+

This website will guide you +through the elements that make a project awesome +while emphasizing industry best practices.

+

A good README.md

+

A README.md file in the root of the repository +is going to be the first things your users see. +GitHub renders this file on the main page of the repository.

+

This is an example from the NixOS organization:

+

NixOS README

+

It's important that it's professional and colorful, and that it grabs the user's attention.

+

I highly recommend the following elements +are present on the first page:

+
    +
  1. +

    Logo and name: +A good logo is going to make the project look respected +and professional.

    +

    A good name is able to encapsulate the project's purpose, +or, at the very least, should give the project an identity.

    +

    This is an example from the +Prettier +project:

    +

    Prettier logo

    +

    It looks good.

    +

    On the other hand, it encapsulates the purpose of the project: +"Making your code prettier".

    +
  2. +
  3. +

    Slogan: +A short, catchy phrase, +summarizing what the project does and its most hot features.

    +

    This is an example from the +FastAPI +project:

    +
    +

    FastAPI framework, high performance, easy to learn, fast to code, ready for production.

    +
    +

    Wow. Yes, I want high-performance APIs. +I want things easy to learn, +with no boilerplate, +and robust enough for production.

    +

    While short, +this slogan is very important +because it's displayed on the project card:

    +

    FastAPI slogan

    +

    It can be the first thing a new visitor sees +and therefore can be the decisive factor +for a user to click on it.

    +

    It's also displayed on the top of the project home page:

    +

    FastAPI about

    +

    And sets the expectations for what comes next, +it needs to be good.

    +
  4. +
  5. +

    Description: +Here you will have a few paragraphs to +explain what your project does, +what problem it solves for your users, +and why should a user be using it right now.

    +

    This is an example from the +FastAPI +project:

    +
    +

    FastAPI is a modern, fast (high-performance), +web framework for building APIs with Python 3.6+ +based on standard Python type hints.

    +

    The key features are:

    +
      +
    • +

      Fast: Very high performance, on par with NodeJS and Go (thanks to Starlette and Pydantic). One of the fastest Python frameworks available.

      +
    • +
    • +

      Fast to code: Increase the speed to develop features by about 200% to 300%. *

      +
    • +
    • +

      Fewer bugs: Reduce about 40% of human (developer) induced errors. *

      +
    • +
    • +

      Intuitive: Great editor support. Completion everywhere. Less time debugging.

      +
    • +
    • +

      Easy: Designed to be easy to use and learn. Less time reading docs.

      +
    • +
    • +

      Short: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.

      +
    • +
    • +

      Robust: Get production-ready code. With automatic interactive documentation.

      +
    • +
    • +

      Standards-based: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema.

      +
    • +
    +

    * estimation based on tests on an internal development team, building production applications.

    +
    +

    Here the user knows that FastAPI helps build APIs with Python. +They should be using FastAPI right now +because it's fast, intuitive, easy, and so on.

    +

    It's always a good idea to throw a few power-words like: "Fast", "Powerful", "Secure", and "Reliable", +but of course, make sure that this is true.

    +

    You can further improve this section by adding emojis.

    +

    This is an example from the +Alejandra +project:

    +

    Alejandra description

    +

    To this point, your users should have a clear understanding of:

    +
      +
    • What problem does your project solve?
    • +
    • How does it make the user's life easier?
    • +
    • What is special about it? What are the key features?
    • +
    +

    But also make sure not to show unnecessary details. +Try to find a balance. +Too short and you'll leave questions unanswered. +Too long and you'll bore or confuse them.

    +
  6. +
  7. +

    Getting Started: +Users are interested at this point, +they want action now.

    +

    Here we place the shortest path a user can take +to interact with the project. +If there are many, show the fastest/easiest one first, +and then slowly introduce them to the more complex ones.

    +

    This is an example from the +Alejandra +project:

    +

    Alejandra Getting Started

    +

    It simply tells the user to use a web version of the project. +Everybody knows how to click a link, that's easy and nice.

    +

    This is an example from the +Prettier +project:

    +

    Prettier Getting Started

    +

    Users familiar with Node JS +will find the instructions easy to follow. +However, +some steps could have been removed +and it would have worked the same. +There is no need to overwhelm the user with details at this point. +We can introduce the details later.

    +

    For example, a better version would be:

    +
    +

    Install prettier with:

    +

    $ npm install --save-dev prettier

    +

    Make your code beautiful with:

    +

    $ npx prettier --write .

    +
    +

    Remember to keep the first impression simple and intuitive.

    +

    Simplicity is key here.

    +
  8. +
+

Altogether, the following are examples of a good README:

+
    +
  • +

    Prettier:

    +

    Prettier Readme

    +
  • +
  • +

    FastAPI:

    +

    FastAPI Readme

    +
  • +
  • +

    Alejandra:

    +

    Alejandra Readme

    +
  • +
+

Lastly, +makeareadme.com also offers some templates and tips.

+

You may want to have a look over there.

+

A LICENSE.md

+
+

This is no legal advice.

+
+

For good or bad, +all of the code that we write +is subject to the following Intellectual Property rights:

+
    +
  • +

    Copyright: The right to reproduce, +derivate, +distribute copies, and use the copyrighted work, +and to extend these rights to others.

    +
  • +
  • +

    Moral Rights: +The right of being attributed as the author of the work, +and the right to prevent prejudicial distortions of the work (integrity).

    +
  • +
+

Both concepts can be expanded a little bit more +by reading the following documents +from the U.S. Copyright Office: +1, +2. +It is a very interesting topic.

+

For the time being, +think of these rights +as a way for the rights holder +to decide on who and what can be done with the protected work. +Further, without explicit authorization from the rights holder, +you are effectively limited by law from doing anything at all with the work, +unless you can cite Fair Use.

+

If you go and read your employee contract, +you'll find that the rights over the work you do for your employer +are "assigned" to the employer +(transferred from you to them), +that you won't exercise your Moral Right of integrity over the work, +and (with luck) +that they'll respect your Moral Right of being attributed, +plus many more clauses that are similar in nature.

+

There is also a third concept called +The Public Domain, +which are works to which no Intellectual Property rights apply, +either because they expired, +but usually, because they were expressly waived by the holder.

+

Public Domain Logo

+

Whether the existence of these rights is good or bad +I leave it for you to think about, +but I'll throw some good articles and books here: +1, +2, +3, +4.

+

At Tech Start UCalgary we commit to Open Source everything +under an Open Source Initiative approved license, +but we recommend for source code:

+ +

And for documentation:

+ +

You can use the following resources to make an informed decision on your project:

+ +

We believe the previous licenses are good for the following reasons:

+
    +
  • They enable anyone to benefit from the software, +without discrimination, +which aligns well with the club's mission, +and the fact that we are not seeking profit, +but instead, to foster technology.
  • +
  • It allows you +or your team, +or anyone in the world, +to continue growing the project +or creating a company out of it in the future.
  • +
+

Should you not wish to opt-out of the Copyright Monopoly +by releasing your work into the public domain, +remember that the rights are yours and not Tech Start UCalgary. +You haven't signed any Copyright Transfer Agreement +with us (and you won't) +so please use Copyright <year> The <project name>'s contributors, +where the license asks for it.

+

The projects are yours.

+

And in order to ensure future contributions adhere to your license, +make sure to include the following text +somewhere visible in your project, for instance at the end of the README.md:

+
+
    +
  • All of the code that you submit to our code repository will be licensed under the <license>.
  • +
  • By submitting code to our code repository +you also certify that you agree +to the following Developer Certificate of Origin.
  • +
+
+

This constitutes a very simple +Contributor License Agreement.

+

A RoadMap

+

A RoadMap is one of the best ways to manifest the future vision of your product +and the strategy and steps +that will be used for achieving that vision.

+

A RoadMap is also a great tool to cooperate with other people +because you can prioritize on it the steps +that are yet to be done, +and see who's working on what, +what progress has been made, +and so on.

+

This is an example from the Makes project on GitHub:

+

Makes RoadMap

+

That's a simple RoadMap, yet it has all the important information. +That's nice!

+

I highly recommend you create your RoadMap using the Projects feature on GitHub +because it integrates very well with other GitHub features +like Issues, Pull Requests and Milestones, +but it's also fine if you use Jira +or Trello.

+

As a rule of thumb, +anything related to making your project awesome +can (and should) go into the RoadMap. +It's also not limited to just programming tasks, +you could perfectly add to the RoadMap +a meeting with your users, +some market research activity, +or having some Pizza with the team.

+

A RoadMap is also a living creature, +it evolves as the project evolves +and you can iterate on it on the go. +Don't worry if you don't get it perfectly from the beginning, +but make sure you have one from the beginning!

+

How to create a RoadMap?

+

Step 1 - Start with Milestones

+

My suggestion is that you start by creating a few +Milestones.

+

Think about what your project wants to achieve: +Is it maybe a website that allows you to shorten URLs, +like https://tinyurl.com?

+

What's the minimum viable product that you can deliver to your users +so that they can start getting a taste?

+

You are right! +An ugly webpage, with an ugly textbox and an ugly button, +that when clicked, gives you a beautifully shortened URL :)

+

But that's even too far in the future. +What about making your first Milestone +about having an empty webpage? +Your second Milestone could be having a backend that answers a ping request. +Your third Milestone can be designing the database, +such that it stores the shortened URLs; +and your fourth Milestone can be adding the textbox and button to the front-end, +and an endpoint in the back-end that stores and retrieves the shortened URL.

+

You see? +we just planned a minimum viable product, +using an agile methodology.

+

Congratulations!

+

Step 2 - Split the Milestones in smaller Issues

+

Now we can proceed to define the individual tasks (GitHub Issues) +that are needed for completing each Milestone, +and most importantly, +we can assign each member of our team an Issue, +and work collaboratively towards the same goal.

+

Bonus points if we can plan it so that they can all work in parallel.

+

For example, +for Milestone #1 (Having an empty webpage that the user can access), +we could create the following Issues:

+

Milestone 1 Plan

+

In words:

+
    +
  • Issue #1: Create a Git repository. +
      +
    • Priority: Medium.
    • +
    • Assignee: John.
    • +
    +
  • +
  • Issue #2, after Issue #1: Add a license. +
      +
    • Priority: High.
    • +
    • Assignee: Olivia.
    • +
    +
  • +
  • Issue #3, after Issue #1: Add a README.md. +
      +
    • Priority: Medium.
    • +
    • Assignee: Jane.
    • +
    +
  • +
  • Issue #4, after Issue #1: Initialize an empty React project. +
      +
    • Priority: Medium.
    • +
    • Assignee: Oliver.
    • +
    +
  • +
  • Issue #5, after Issue #4: Use GitHub actions to deploy the front-end into GitHub pages. +
      +
    • Priority: Medium.
    • +
    • Assignee: John. (John should be free, since finishing #4 means #1 was finished).
    • +
    +
  • +
+

Boom! Done.

+

Now create more Issues for all of the other Milestones.

+

Step 3 - Add your Issues to the RoadMap

+

My suggestion for this is to keep it simple. +Avoid too many labels, statuses and complexity.

+

First, create a Project (a RoadMap) on GitHub. +This is usually under the Projects tab in the organization view:

+

New Project on GitHub

+

Then define some statuses:

+

Status Field

+
    +
  • 🆕 New: Where you place all of the issues initially.
  • +
  • 📋 Backlog: The issues that are yet to be done, and their priority.
  • +
  • 🏗 In progress: The issues that are being worked on, and who's working on them.
  • +
  • ✅ Done: The issues that have been shipped.
  • +
+

Then, create a priority field:

+

Priority Field

+

This will help your team focus on the things +that are more impactful to your project.

+

You can use the Eisenhower matrix for this:

+
    +
  • 🌋 High priority: Issues that are important and urgent.
  • +
  • 🏔 Medium priority: Issues that are important, but not urgent.
  • +
  • 🏕 Low priority: Issues that are not important, but may be nice to have someday.
  • +
  • 🏝 Never priority: Just close the issue :) don't waste your time on this.
  • +
+

Now you can start adding Issues to your RoadMap:

+

Makes RoadMap

+

And see what is the progress towards each Milestone, for example:

+

Milestones Progress

+

Demo & Pitch Nights

+

All Tech Start UCalgary projects are showcased to the world +at the end of each academic year. +At this event, people from different industries and backgrounds +come and give us feedback on the projects.

+

This is also a great opportunity for you as a professional and us +as a club to connect and network with different companies.

+

It's important to remember that as an entrepreneurial club, you will +also be pitching your ideas to potential investors, so your hard work +on the business strategy will be on display here. Pitching your start-up +in a convincing manner is a critical skill, so we also give you the opportunity to +practice this.

+

This year's showcase is scheduled for April 27th, 2024. +To prepare for this, we want each team to demo and pitch their project to +the club before the showcase. This will help you get experience and valuable +feedback from fellow project teams, execs, and our partners in industry.

+

Dates to Remember

+
+ + + + +
DateEventAudienceLocation
30 November 2023Demo & Pitch Night 1Project Teams & ExecsENC 201
29 February 2024Demo & Pitch Night 2Tech Start & Industry GuestsENC 201
Early AprilDemo & Pitch Night 3TBDTBD
27 April 2024Final ShowcaseOpen to the PublicHunter Hub Collision Space
+

Demo & Pitch Night 1

+

30 November 2023

+

Objectives

+

Demos are intended to be a check-in of your progress so far and a way for your whole team to show off their work, as well as an opportunity to practice pitching your project to the public.

+

This will also let us understand your progress and blockers in order to help you best.

+

Since Tech Start is built off 3 pillars, development, strategy, and design, the demos will also focus on these 3 aspects. +Feel free to divide the allocated time between them as you see fit.

+

In addition, there may or may not be pizza or snacks present.

+

Time Limit: 15 minutes

+

Suggested talking points

+

These are just suggestions and not at all mandatory, but may help get you started.

+

Strategy

+
    +
  • What is your Total Market, Serviceable Market and Obtainable Market?
  • +
  • What is your Market Positioning?
  • +
  • What is your unique value?
  • +
  • Competition Analysis in terms of market, features etc.
  • +
  • Does the user research validate the business plan so far?
  • +
+

Design

+
    +
  • After doing user research and synthesizing the data, what did you learn about your users?
  • +
  • What opportunities / edge have you discovered for your product?
  • +
  • What were some challenges you faced in the user research and synthesis process and how did you overcome them (or not)?
  • +
  • How has user research driven your decision on what to include in your MVP?
  • +
+

Development

+
    +
  • What is your tech stack?
  • +
  • What do you aim to include in your MVP?
  • +
  • How much progress have you made technically?
  • +
  • What does your roadmap look like? Feel free to share your project board.
  • +
+

Milestones

+

These milestones will give you a rough idea of where you should be by the demo, they are not requirements.

+

Strategy

+
    +
  • Competition analysis complete
  • +
  • Features to be made solidified
  • +
  • Unique Value Proposition determined
  • +
+

Design

+
    +
  • User research and synthesis is complete
  • +
  • Product requirement document created (& MVP features prioritized)
  • +
  • Low fidelity prototypes started
  • +
+

Development

+
    +
  • Stack chosen
  • +
  • Cloud services decided upon (if needed)
  • +
  • Development environment set up
  • +
  • First commits made by each dev
  • +
  • Learning of new tech started
  • +
  • Roadmap created
  • +
+

Visual Aids

+

We strongly encourage putting together a presentation to help you. +Consider what you might need to show off your projects (if possible), e.g. if you're building a mobile or VR app, you may need to find a solution to show the screen on the projectors.

+

Demo & Pitch Night 2

+

29 February 2024

+

Objectives

+

Share your progress with the club, get feedback from industry guests, and practice your public speaking and pitching.

+

This is a pitch and demo, you are selling your product to investors.

+

Quick Info

+

Start Time: 6pm sharp

+

Time Limit: 10 minutes

+

Dress Code: Business Casual

+

What to do

+

Keep the focus on the product. +Demo your product live, if it's deployed that's even better but localhost is okay. +Have a pre-recorded demo as a backup, in case things go wrong.

+

What not to do

+

Don't show any code. +Don't talk about your challenges and wins.

+

Suggested talking points

+

These are just suggestions and not at all mandatory, but may help get you started.

+

General

+
    +
  • Talk about the problem space & your solution (create a story around it)
  • +
  • Introduce team members
  • +
  • Talk about features (MVP)
  • +
  • Roadmap of what you'll do next (adding x feature, finalizing for launch, etc.)
  • +
+

Strategy

+
    +
  • STP Analysis
  • +
  • Exploring monetization and revenue models
  • +
  • Income & Expenditure forecasts in the real world
  • +
  • Unique Value Proposition, Problem Statement & Branding (collaborate with design team)
  • +
  • Market size research, figure out Total Addressable Market, Serviceable Addressable
  • +
  • Competition Research
  • +
+

Design

+
    +
  • Create a user persona (based on your user research) to explore the problem space - (collaborate with strategists)
  • +
  • How has user research driven your decision on what to include in your MVP features? List some of the features.
  • +
  • Show your high-fidelity designs / technical demo
  • +
+

Development

+
    +
  • Quick overview of tech stack, showing off tech's best feature +
      +
    • (e.g. we're using NextJS hosted on Vercel because it lets us rapidly deploy changes to our users)
    • +
    +
  • +
  • How are you deploying your app?
  • +
  • Launch plans
  • +
  • Would you like to be on the App Store, etc?
  • +
  • Show a functional demo
  • +
+

Milestones

+

These milestones will give you a rough idea of where you should be by the demo, they are not requirements.

+

Strategy

+
    +
  • Everything money related figured out +
      +
    • business model
    • +
    • revenue forecasts
    • +
    • expenses
    • +
    +
  • +
+

Design

+
    +
  • Usability testing on prototype is complete
  • +
  • High-fidelity designs are complete
  • +
  • Final designs are handed off to development
  • +
+

Development

+
    +
  • Front-end and back-end connected
  • +
  • Deployed to cloud providers (AWS, Vercel, etc.)
  • +
+

Demo & Pitch Night 3

+

Early April 2024

+

Coming soon...

+

Career Paths

+

There are several areas of software development that cover different aspects of the software development life cycle. +Usually, people focus on only one or a couple of them. Each of them is a big area on its own and takes years to learn:

+
    +
  • +

    Front-end development: This area of software development is concerned with the user interface (UI) and user experience (UX) of software applications. Front-end developers work with technologies like HTML, CSS, and JavaScript to create the visual elements that users interact with.

    +
  • +
  • +

    Back-end development: This area of software development is concerned with the server-side of software applications. Back-end developers work with technologies like PHP, Python, Ruby, and Java to create the logic that powers software applications.

    +
  • +
  • +

    Full-stack development: Full-stack developers work on both the front-end and back-end of software applications. They have knowledge and skills in both areas of development and can build complete applications from start to finish.

    +
  • +
  • +

    Mobile development: This area of software development is concerned with creating applications for mobile devices. Mobile developers work with technologies like Java, Swift, and Kotlin to create native apps for iOS and Android devices.

    +
  • +
  • +

    DevOps: DevOps is a methodology that focuses on collaboration between development and operations teams to automate the software delivery process. DevOps engineers use tools like Jenkins, Ansible, and Docker to automate the software development process.

    +
  • +
  • +

    Testing and quality assurance: This area of software development is concerned with ensuring that software applications are reliable, bug-free, and meet the requirements of the end-users. Testing and quality assurance engineers use tools like Selenium, JMeter, and LoadRunner to test software applications.

    +
  • +
  • +

    Data science and analytics: This area of software development is concerned with creating applications that analyze and interpret data. Data science and analytics engineers work with technologies like Python, R, and SQL to build applications that can perform data analysis, machine learning, and statistical modeling.

    +
  • +
  • +

    Artificial intelligence and machine learning: This area of software development is concerned with creating applications that can learn and make decisions based on data. AI and ML developers work with technologies like Python, TensorFlow, and PyTorch to build applications that can perform tasks like natural language processing, image recognition, and predictive modeling.

    +
  • +
  • +

    Cybersecurity: This area of software development is concerned with creating secure software applications and protecting them from malicious attacks. Cybersecurity engineers work with technologies like encryption, firewalls, and intrusion detection systems to secure software applications.

    +
  • +
  • +

    Cloud computing: This area of software development is concerned with creating applications that can run on cloud computing platforms like Amazon Web Services, Microsoft Azure, and Google Cloud Platform. Cloud developers work with technologies like containerization, serverless computing, and cloud storage to build and deploy applications on the cloud.

    +
  • +
  • +

    Embedded systems: This area of software development is concerned with creating software for embedded devices like medical devices, smart appliances, and automotive systems. Embedded systems developers work with technologies like C, C++, and assembly language to create software that runs on these devices.

    +
  • +
  • +

    Augmented and virtual reality: This area of software development is concerned with creating applications that allow users to interact with virtual or augmented environments. AR and VR developers work with technologies like Unity, Unreal Engine, and WebXR to build immersive applications for gaming, education, and training.

    +
  • +
  • +

    Project management: Involves overseeing the entire software development process from conception to delivery. Project managers are responsible for ensuring that the project is completed on time, within budget, and to the required quality standards.

    +
  • +
  • +

    Product owner: The product owner is responsible for defining and prioritizing the features and requirements of a software application. They work closely with development teams, stakeholders, and customers to ensure that the product meets the needs of the users.

    +
  • +
  • +

    Technical writing: Technical writers create documentation and user manuals for software applications. They work with developers and other technical experts to create user-friendly documentation that explains how to use the software application.

    +
  • +
  • +

    User experience (UX) design: UX designers create the visual design and user experience of software applications. They work with developers to ensure that the application is easy to use and visually appealing.

    +
  • +
  • +

    Technical support: Technical support engineers provide support to users who are experiencing issues with software applications. They work with developers to diagnose and resolve technical issues, and provide customer support to users.

    +
  • +
  • +

    Technical architecture: Technical architects are responsible for designing the technical architecture of software applications. They work with development teams to ensure that the architecture meets the scalability, security, and performance requirements of the application.

    +
  • +
  • +

    Database administration: Database administrators are responsible for managing the data that is used by software applications. They work with developers to design and implement databases, and ensure that the data is stored and managed effectively.

    +
  • +
+

Front End

+

A front-end engineer is a software engineer who specializes in building the user interface (UI) and user experience (UX) of a website or application. They are responsible for creating visually appealing and intuitive designs that allow users to interact with the application or website seamlessly.

+

The front-end engineer's job involves using various technologies such as HTML, CSS, and JavaScript to build the visual elements of an application or website. They work closely with designers to turn mockups and wireframes into fully functional websites or applications that are easy to use and navigate.

+

Front-end engineers also collaborate with back-end engineers to integrate the front-end code with the back-end code, ensuring that the entire system functions correctly. They are responsible for testing and debugging the front-end code, optimizing the code for performance, and ensuring that the website or application is compatible with different browsers and devices.

+

How to become a front-end engineer?

+

To become a front-end engineer, you will need to follow these general steps:

+
    +
  1. +

    Learn HTML, CSS, and JavaScript (or TypeScript): HTML is used to structure web pages, CSS is used to style them, and JavaScript is used to add interactivity and dynamic behavior. These are the core technologies used in front-end development.

    +
  2. +
  3. +

    Learn a front-end framework: While it's not strictly necessary, learning a front-end framework like React can help you to build more complex web applications more efficiently.

    +
  4. +
  5. +

    Build projects: To gain practical experience, you should work on building your own projects or contributing to open-source projects. This will help you to develop your skills and build a portfolio of work that you can show to potential employers.

    +
  6. +
  7. +

    Stay up-to-date: Front-end development is a rapidly evolving field, so it's important to stay up-to-date with the latest technologies and best practices. Attend conferences, read blogs and forums, and participate in online communities to stay current.

    +
  8. +
  9. +

    Apply for jobs: Once you have the skills and experience, it's time to start applying for front-end engineering jobs. Look for job postings online, reach out to recruiters or companies directly, and attend networking events to make connections in the industry. Be prepared to showcase your portfolio and be able to talk about your skills and experience during interviews.

    +
  10. +
+

DevOps

+

DevOps is a software development approach that emphasizes collaboration and communication between software developers and IT operations professionals. The goal of DevOps is to improve the efficiency and quality of software development by breaking down silos and promoting a culture of collaboration, automation, and continuous improvement.

+

Traditionally (https://clickup.com/blog/waterfall-project-management/), software development and IT operations have been two separate functions within organizations, with little interaction between them. DevOps seeks to bridge this gap by fostering collaboration between these teams throughout the entire software development lifecycle, from planning and development to deployment and maintenance.

+

DevOps involves using tools and practices such as continuous integration, continuous delivery, and infrastructure automation to streamline the software development process and make it more efficient. By automating tasks like testing, building, and deploying software, teams can reduce errors, speed up the development process, and deliver software more quickly and reliably.

+

Overall, DevOps is a holistic approach to software development that aims to create a culture of collaboration and continuous improvement, with the goal of delivering software more efficiently and with higher quality.

+

How to become a DevOps engineer?

+
    +
  1. +

    Understand the why and the high-level how (the philosophy).

    +

    For instance:

    + +
  2. +
  3. +

    Learn the core skills: DevOps engineers need a strong foundation in software development, You should have a basic understanding of programming languages, and be familiar with version control systems like Git. You should also have experience working with Linux/Unix systems and be familiar with cloud platforms like AWS, Azure, or Google Cloud Platform.

    +
  4. +
  5. +

    Gain experience with DevOps tools and practices: DevOps engineers should be familiar with tools and practices such as continuous integration/continuous delivery (CI/CD), infrastructure as code, configuration management, and monitoring and logging. You can gain experience by working on projects, contributing to open-source projects, or taking online courses.

    +
  6. +
  7. +

    Learn automation: Automation is a key part of DevOps, so you should have experience with containerization tools like Docker and Kubernetes.

    +
  8. +
  9. +

    Build projects: To gain practical experience, you should work on building your own projects or contributing to open-source projects. This will help you to develop your skills and build a portfolio of work that you can show to potential employers.

    +
  10. +
  11. +

    Stay up-to-date: DevOps is a rapidly evolving field, so it's important to stay up-to-date with the latest tools and practices. Attend conferences, read blogs and forums, and participate in online communities to stay current.

    +
  12. +
  13. +

    Apply for jobs: Once you have the skills and experience, it's time to start applying for DevOps engineering jobs. Look for job postings online, reach out to recruiters or companies directly, and attend networking events to make connections in the industry. Be prepared to showcase your portfolio and be able to talk about your skills and experience during interviews.

    +
  14. +
+

Technical Demos

+

Overview

+

At some point in your career you will need to demo some work you've done to both technical and non-technical stakeholders (people with an interest in the work you're doing).

+

When you do this, you want to make sure you give yourself and your team the best opportunity to show off your hard work. Here are some tips and ideas to think about when preparing, and do prepare if it's for anyone other than your own team.

+

Purpose

+

The work you did will have achieved something, whether it's fixing a bug, solving a problem for your users, or presenting an entirely new idea.

+

It's important to show this if you want to convince others that your work is important. Feel free to show the existing problem and then go into how you have addressed it, this will make the change that much more impactful.

+

Presentation

+

Live demos are always best, it proves to your audience that it actually works and that there's no smoke and mirrors hiding flaws. However, there are cases where live demos don't work out. Maybe you have a very slow running process, or your code just decides it's not going to work that day.

+

For slow processes, explain that it's slow and why, and let the audience know how you've addressed it in the demo to set the right expectations.

+

Here are some methods:

+
    +
  1. Run the process before starting the demo in another tab/instance/device, and switch to that when you need to show what happens after it.
  2. +
  3. Do something else while it's running, e.g. talk about some other detail in your presentation.
  4. +
  5. Pre-record the whole demo and speed up or cut out the slow parts.
  6. +
+

It's a good idea to have a well-edited pre-recorded demo to switch to as well, sometimes code just decides not to work!

+

Make sure you've practiced talking over the pre-recorded demo as well as the live demo so you're prepared for all cases, including switching from live to recorded halfway through.

+

Avoid Distractions

+

It's not the end of the world, but a notification popping up on your screen is distracting to the audience.

+

It's best to fully close all unneeded apps, turn on do-not-disturb, and full-screen what you're presenting.

+

This also goes for browser tabs and bookmarks, have everything as clean and empty as possible so all the focus is on what you're presenting.

+

Use Virtual Desktops on Windows and full-screen apps on MacOS. Place your presentation in one, and the demo in another, that way you can quickly and seamlessly switch between the two without alt-tabbing or exiting the presentation.

+

Prepare

+

Most importantly, rehearse the demo! Go through everything you want to show off, and have a good idea of what you want to say. It doesn't need to be perfectly memorized, but you should know exactly what you're doing next all the time. If you're working with a team, and one person is speaking and the other controlling the demo, make sure both of you are in sync. If you say "looking at the user profile page", the demo should immediately go there, without you having to ask your partner to do things which breaks the flow.

+

Finally, if (and when) something goes wrong, the best thing to do is to move past it. Bringing more attention to an issue can make it seem worse than it is. If things are really bad (app fully crashes, laptop catches fire), you have a recorded demo to switch to. Right?

+

References/Further Reading

+

How to create great tech demos and presentations - Thomas Maurer

+

13 Demoing Strategies That Make Tech Software Compelling

+

Tech Start's Django Guide

+

Django is a free and open source python framework that lets you build awesome backends for websites, apps, and more. You can use it to host databases and build secure APIs for them without writing a line of SQL. You can also use it to create multi-page applications with dynamically served content. It makes it easy to get started building complex functionalities by automating a lot of the boilerplate code that you'd normally have to write.

+

We recommend that you have a basic knowledge of python before using django! This will help you debug any errors that you get.

+

alt_text

+

(Img src: https://medium.com/crowdbotics/when-to-use-django-and-when-not-to-9f62f55f693b)

+

Table of Contents

+ +

Requirements

+

First you will need to install Homebrew, Python, Pip, and Pyenv. If you have not done so already, please follow the instructions in the Installfest section.

+

Setup

+

To create a Django project first wee need to create a directory for the project. To do so, run the following command:

+
mkdir <project-name>
+
+

Then, we need to navigate to the directory we just created. To do so, run the following command:

+
cd <project-name>
+
+

Now, we need to create a virtual environment for our project. To do so, run the following command:

+
pyenv virtualenv .venv
+
+

Then, we need to activate the virtual environment. You need to do this every time you want to run your project. To do so, run the following command:

+
source .venv/bin/activate
+
+

If you want to deactivate your virtual environment when you're done working on your project, run the following command:

+
deactivate
+
+

Now, we need to install Django. To do so, run the following command:

+
pip install django
+
+

To check if Django is installed, run the following command:

+
python3 -m django --version 
+
+

Next, let's create a project.

+
django-admin startproject <project-name> . # the dot is important! it will create the project in the current directory
+
+
Good to know: Projects vs. apps
+What's the difference between a django project and a django app? An app is a Web application that does something – e.g., a Weblog system, a database of public records or a small poll app. A project is a collection of configuration and apps for a particular website. A project can contain multiple apps. An app can be in multiple projects.
+
+
python3 manage.py startapp <your-app-name>
+
+

This creates an app within your project. You can create as many apps as you want within a project.

+

Next step: include your app in the INSTALLED_APPS fields in settings.py (just the name)

+
INSTALLED_APPS = [
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+
+    ...
+    'your-app-name',
+]
+
+

Installing Dotenv

+

Dotenv is a zero-dependency module that loads environment variables from a .env file into process.env. Storing configuration in the environment separate from code is based on The Twelve-Factor App methodology. To install dotenv, run the following command:

+
pip install python-dotenv
+
+

Then freeze the requirements. To do so, run the following command:

+
pip freeze > requirements.txt
+
+

This will create a file called requirements.txt that will contain all the packages that are installed in your virtual environment. This file will be useful for when you need to install the same packages in another virtual environment. After adding a new package to your virtual environment, you will need to freeze the requirements again.

+

Next, go to your project and create a .env file. To do so, run the following command:

+
touch .env
+
+

Then go to your settings.py file and add the following code:

+
from django.core.management.utils import get_random_secret_key
+from dotenv import load_dotenv
+
+...
+
+load_dotenv()
+
+# SECURITY WARNING: keep the secret key used in production secret!
+# Copy the secret key from the .env file
+SECRET_KEY = os.getenv("DJANGO_SECRET_KEY", get_random_secret_key())
+
+

Your .env file should look like this:

+
DJANGO_SECRET_KEY=your-secret-key
+
+

Installing Postgres and psycopg2

+

PostgreSQL is a powerful, open source object-relational database system with over 30 years of active development that has earned it a strong reputation for reliability, feature robustness, and performance. To install Postgres, run the following command:

+
brew install postgresql
+
+

To check if Postgres is installed, run the following command:

+
postgres --version
+
+

psycopg2 is a PostgreSQL database adapter for the Python programming language. To install psycopg2, run the following command:

+
pip install psycopg2
+
+

Then freeze the requirements. To do so, run the following command:

+
pip freeze > requirements.txt
+
+

Then go to your settings.py file and add the following code:

+
INSTALLED_APPS = [
+    ...
+    'psycopg2',
+]
+
+

Creating a Postgres database

+

To create a Postgres database, run the following command:

+
createdb <database-name>
+
+

Remember your credentials for the database. You will need them later.

+

It is also recommended to install pgAdmin, a free and open-source administration and development platform for PostgreSQL and its related database management systems. To install pgAdmin, run the following command:

+
brew install --cask pgadmin4
+
+

Connecting Django to Postgres

+

Add the following code to your .env file:

+
DATABASE_NAME=<database-name>
+DATABASE_USER=<database-user>
+DATABASE_PASSWORD=<database-password>
+
+

Now go to your settings.py file and add the following code:

+
import os
+
+...
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.postgresql',
+        'NAME': os.getenv('DATABASE_NAME'),
+        'USER': os.getenv('DATABASE_USER'),
+        'PASSWORD': os.getenv('DATABASE_PASSWORD'),
+        'HOST': "127.0.0.1",
+        'PORT': "5432",
+    }
+}
+
+

Writing Models

+

Models allow you to define the content of your database. If you don't need content in your database, you won't need models.

+

You can follow along with this section here:

+

https://docs.djangoproject.com/en/3.1/intro/tutorial02/

+

More about models: https://docs.djangoproject.com/en/3.1/topics/db/models/

+

You will define all your models in models.py, located within the folder for your app.

+
from django.db import models
+
+# Create your models here.
+class Album(models.Model):
+    name = models.CharField(max_length=200)
+    artist = models.CharField(max_length=100)
+    year_released = models.DateField()
+    def __str__(self):
+        return str(self.name)
+
+class Song(models.Model):
+    song_name = models.CharField(max_length=100)
+    album = models.ForeignKey(Album, on_delete=models.CASCADE)
+    num_streams = models.IntegerField()
+    def __str__(self):
+        return str(self.song_name)
+
+

Each model should correspond to the structure of a table of a relational model of a database. If you don't know what this means, ask someone who has taken CPSC 471 (or an equivalent databases course)

+

Django can convert these into real SQL tables!

+
    +
  • Good to know: Primary Keys: In the above example we didn't specify any ids for our models (normally, with databases, you want an id to be your primary key). Django automatically creates an ID field to be the primary key for each model and takes care of auto-incrementing, unless you specifically override it. I don't recommend overriding, it's not worth the effort (and its doubly complicated and not worth it to have a primary key composed of several fields)
  • +
  • Good to know: str: the str function is Python's default function for string representation. In this case, it's good practice to override this for your models. This will help you understand your data if you login via the admin view (I'll show how to do this later)
  • +
  • Good to know: Foreign Keys: See the Song model class for how you can reference a foreign key belonging to another model (in this case it refers to Album). You don't need to refer to a foreign model's keys directly, all you need to do is specify which table you are referencing. Also note: if you are referring to a table, it needs to be defined above the point in the code where you are referring to it.
  • +
+

There are more options that can be explored about how you can define your models, but this should be a good base for you to do your own research :)

+

Now we're ready to convert these into a real database! By default, Django will make a migration file that has your database.

+
Converting models into your database
+
+https://docs.djangoproject.com/en/3.1/intro/tutorial02/
+
+>> python3 manage.py makemigrations appName
+Creates migrations for the changes you made in appName
+
+>> python3 manage.py migrate
+Migrates the changes you made into your database
+
+
+

Run your app

+

Whenever you are ready to run your server, just call this command!

+
python3 manage.py runserver 
+
+

You should see something like this:

+

django-initial-page

+

By default, this will run the Django server on localhost:8000. View the django documentation to see how you can run it on a different port. You can now access it from your web browser by visiting http://localhost:8000 !

+

You can also create a superuser (admin) to view the inner contents of your database. To do this, you first need to create them from the command line using the following command:

+
python3 manage.py createsuperuser --username yourNameHere --email yours@email.ca
+
+

This will create a super user with your provided info (it will prompt you to enter a password as well).

+

The following command creates a token for the superuser that you can use for authentication in requests. If you are not using Django Rest Framework, this is not applicable to you.

+
python3 manage.py drf_create_token yourSuperUserName
+
+

Note: if you're trying to run these for your deployed app on heroku, you need to prepend heroku run before those commands! See the Heroku section for a description on how you can deploy it.

+

You can see the admin page of your website to view the inner content of your database. This is automatically created by Django. Visit http://localhost:8000/admin and enter your passcode.

+

If you want your models to show up in the admin page, you will need to specify them in admin.py like this:

+
from django.contrib import admin
+from .models import Album, Song
+# Register your models here.
+
+admin.site.register(Album)
+admin.site.register(Song)
+
+

Once you log in to the admin site, you should see something like this. From here, you can add & remove database entries. +alt_text

+

URLs

+

URLs allow you to define the paths that exist in your system, and what happens when you call them.

+

URLs documentation: https://docs.djangoproject.com/en/3.1/ref/urls/

+

How URLs are processed in Django: https://docs.djangoproject.com/en/3.1/topics/http/urls/#how-django-processes-a-request

+

Read more: https://docs.djangoproject.com/en/3.1/intro/tutorial03/

+

If you're constructing a big application, it's standard practice in django to include different _apps _for each part of your system, and link them to the main project.

+

alt_text

+

However, since we're only making small-scale side-projects, it's fine to ignore this best-practice and include everything in a single app. Just understand that in a large industrial scale project you wouldn't necessarily want to do this.

+

// urls.py in a project:

+
from django.contrib import admin
+from django.urls import path, include
+
+urlpatterns = [
+    path('admin/', admin.site.urls),
+    path('myApp/', include('myApp.urls'))
+]
+
+

// example urls.py in myApp folder:

+
from django.urls import path
+from . import views
+
+urlpatterns = [
+    path('hello_world', views.ping, name='Hello World!'),
+    path('hello-x/<str:hello_to>', views.hellox, name='Hello to x'),
+    path('hello-x/<print_me>/print', views.printx, name='Print this!'),
+    path('goodbye', views.goodbye, name='goodbye'),
+]
+
+

Now you can visit a path using http://localhost:8000/myApp/hello-world, for example.

+

Views

+

**Views **allow you to define what happens when you access a certain url in your system (using your browser, an API tool like Postman, or something else altogether). In your views, you could define interactions with the model (your database) or entirely different interactions altogether. You can use the definition of the view to call external processes.

+

If you want to make more complicated views and understand the Request and Response items, read this:

+

https://docs.djangoproject.com/en/3.1/ref/request-response/

+

To understand views more in-depth, read the documentation: https://docs.djangoproject.com/en/3.1/topics/http/views/

+

Here are some simple examples of what you can do with a view. Note that these are just examples and don't represent best practice at all.

+
from django.http import HttpResponse, response
+# views.py
+def ping(request):
+    myRes = "Hello World!"
+    return HttpResponse(myRes)
+
+def hellox(request, hello_to):
+    myRes = {"My Reply": "Hello " + hello_to}
+    return response.JsonResponse(myRes)
+
+def printx(request, print_me):
+    print("Hello to " + print_me)
+    return response.HttpResponseNotFound("I printed it!")
+
+def goodbye(request):
+    if not (request.method == 'GET'):
+        return response.HttpResponseBadRequest()
+    queryParams = request.GET
+    msg = queryParams.get('msg', "Gamers")
+    return response.JsonResponse({"Reply": "Goodbye " + msg})
+
+

Now, we want to adhere to DRY (Don't repeat yourself) when creating views. Therefore, it is almost always best to define your views as Class-Based views (CBVs) which handle more of the boiler plate code for you and help ensure your views follow standards.

+

Please read more about class-based views here: https://docs.djangoproject.com/en/3.1/topics/class-based-views/

+

Both the above docs and the docs for views also show how you can interact with your database items through a view. But, if you're building an API, I highly recommend using the tools in the following section: Django REST Framework.

+

Once you have defined your views and given them a corresponding url, you can test them out.

+
python3 manage.py runserver 
+
+

Run your server, and using either a web browser, or preferably an API testing tool like Postman (https://www.postman.com/) access the proper urls (ex. http://localhost:8000/myApp/hello_world) to see if they have the expected behavior.

+

Django REST Framework

+

Django REST Framework is an add-on to Django that makes it simple to develop REST-compliant APIs. There is great documentation here: https://www.django-rest-framework.org/ <--- FOLLOW INSTALL INSTRUCTIONS

+

What is a RESTful framework? Learn more here: https://restfulapi.net/

+

Django REST Framework provides you with tools to make class-based views to easily implement database CRUD (Create Read Update Destroy) operations, as well as define more complex operations.

+

Before we define any endpoints with Django REST Framework, let's make some serializers.

+

alt_text

+

Serializers

+

Django REST Framework uses serializers as a way to perform **translation **of your models from your python code and your database into data formats like JSON and XML that an API might use. Read more about them here:

+

https://www.django-rest-framework.org/api-guide/serializers/

+

We should define some basic serializers so that we can make API endpoints that interact with the content of our database models.

+
    +
  1. Create a new file called serializers.py inside the app you want to use serializers with.
  2. +
  3. Create your serializers. Give them a relevant name (though the exact syntax is not important)
  4. +
  5. List the fields that you want your serializer to translate. If you don't want it to translate a particular field, then don't include it.
  6. +
+

Here's an example, using the Song and Album models we defined earlier. Here's what's at the top of serializers.py:

+
from rest_framework import serializers
+from .models import *
+
+class SongSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = Song
+        fields = ("id", "song_name", "num_streams")
+
+class AlbumSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = Album
+        fields = ("name", "year_released", "artist", "id")
+
+

Make sure your fields match exactly the names that you used in your models.

+

You may be curious why I also included an id, when we didn't define one in our models- this is because Django auto generated an id for us in this models because we didn't specify a primary key. This id field always has the name id. It is often useful for our API, so we'll include it.

+

We can also create multiple serializers for the same models, if we wanted different behavior. For example, what if we wanted to include the album id of the song?

+
class SongSerializerWithAlbumId(serializers.ModelSerializer):
+    class Meta: 
+        model = Song
+        fields = ("id", "song_name", "num_streams", "album")
+
+

This would include the album's PK (in this case, it's id, but if the PK was different, it'd be something else).

+

What if we wanted to include the full album info when an api request was made to see the song? Here's another example serializer that we could make:

+
class SongSerializerFullAlbum(serializers.ModelSerializer):
+    myFullAlbumDesc = AlbumSerializer("album", read_only=True)
+    class Meta:
+        model = Song
+        fields = ("id", "song_name", "num_streams", "myFullAlbumDesc")
+
+

It's using our album serializer from earlier to serialize a field, which must (read only is an optional parameter that makes it so that it's only included in reading requests, not create/update/destroy.)

+

This was just an introduction to serializers. If you want to use more complex behaviors, you'll have to do the research on your own.

+

Django REST Framework: Class based Views

+
Pre-requisite to this section: understand URLS and views in vanilla Django, and read the serializers section
+
+

More reading: https://www.django-rest-framework.org/tutorial/3-class-based-views/

+

Video overview of similar topic: https://www.youtube.com/watch?v=akvFA5VMXJU

+

You can use Django's Class Based Views to quickly create views that can do CRUD (Create, Read, Update, Destroy) operations on your database.

+

In views.py:

+
from rest_framework.views import APIView
+from rest_framework import generics
+from rest_framework import status
+from .models import *
+from .serializers import *
+
+

Some class based views that we'll define. Right now these are just the generic create, read, update, destroy views. By defining these views with the classes, Django REST Framework takes care of the default behavior for us. It's that easy!

+
class SaveSong(generics.CreateAPIView):
+    queryset = Song.objects.all()
+    serializer_class = SongSerializerWithAlbumId
+
+class GetSongs(generics.ListAPIView):
+    queryset = Song.objects.all()
+    serializer_class = SongSerializer
+
+class DeleteSong(generics.DestroyAPIView):
+    queryset = Song.objects.all()
+    serializer_class = SongSerializer
+
+class UpdateSong(generics.RetrieveUpdateAPIView):
+    queryset = Song.objects.all()
+    serializer_class = SongSerializerWithAlbumId
+
+

Notice that we need to make the create and update serializers include the album ID- if we didn't then you couldn't create song objects since their album id must be _not null._This same principal applies to any model that has a foreign key which isn't allowed to be null.

+

Before we can use the views we created, we need to hook them up to a URL, just like you would for any other view. Do keep in mind that we need to call the as-view function on them, though. Here is an example of the URLs for the previous views. This pattern is how we normally define CRUD endpoint urls for any entity in a database

+
    path('song', views.GetSongs.as_view(), name='songs'),
+    # Create a song
+    path('song/create', views.SaveSong.as_view(), name='Save Song'),
+    #Updates a specified license with information
+    path('song/<int:pk>', views.UpdateSong.as_view(), name='Update Song'),
+    # Deletes a song specified by pk
+    path('song/<int:pk>/delete', views.DeleteSong.as_view(), name='Delete Song'),
+
+

If you are using a pk that is not an int (you manually defined a pk instead of using the default id generated), you'll have to specify that accordingly.

+

What if we want more complex behavior beyond the default predefined classes? We can modify them to add more conditions to what is returned.

+

In this example, we added an optional way to filter songs by album, using a query_param called album. You'll need to read documentation and tutorials if you want to know more about the custom behavior you can define within your Django REST Framework views.

+
class GetSongInAlbum(generics.ListAPIView):
+    serializer_class = SongSerializer
+    def get_queryset(self):
+        queryset = Song.objects.all()
+        alb = self.request.query_params.get('album', None)
+        queryset = queryset.filter(album=alb)
+        return queryset
+
+

If you have a view that isn't necessarily linked to CRUD actions, or has more complex usage and needs more custom defined behavior, you can use APIView.

+

Test out your Django REST API

+

Compile and run your app with

+
python3 manage.py runserver 
+
+

Use your bugfixing wizardry to fix any errors that might show up. Now you should be ready to give those predefined endpoints you made for a spin!

+

Here's some examples that I did using Postman for API testing. If you used Django REST Framework, it should also come with a built-in API testing tool that you can use in your browser.

+

Here's a simple GET request. This is a database read operation, and it's pretty simple. Your browser is making GET requests to every URL you visit while you surf the web.

+ + + + + + + + + +
Request + +alt_text +
Response + +alt_text +
+

Here's a POST request (it's post because we're _creating _or Posting new data) to our create route. We should include the key-value pairs for the song we want to create in the **_Body _**of our request.

+ + + + + + + + + +
Request + +alt_text +
Response + +alt_text +
+

To update, let's follow the URL pattern we defined with the pk of the song we want to update. We can use PUT or PATCH. The info you're sending should be in the _Body _of the request, just like it was for our POST request.

+ + + + + + + + + +
Request + +alt_text +
Response + +alt_text +
+

Let's do the same thing for our deleteSong view, but let's delete Taylor's song this time (pk: 2). I'm sure it was no good anyways.

+ + + + + + + + + +
Request + +alt_text +
Response + +alt_text +alt_text +
+

Let's use our GET view to see what's inside the DB now:

+

alt_text

+

alt_text

+

**unimportant note: in my zeal to delete taylor's song I had a mishap and accidentally deleted song 3, which I have readded here using a post request. but it's id is now 5 :[

+

Finally, let's try out that "song with album" route. We'll add it to our urls.py:

+
    # Probably not the best naming convention
+    path('songInAlbum', views.GetSongInAlbum.as_view(), name='Get song in album'),
+
+

alt_text

+

Here's what our request will look like. ^^^^^^^^

+

Here's the response:

+

alt_text

+
Good to know: Query Parameters
+Notice how our query params don't have to be specified in urls.py - they are dynamically generated from the URL that we try access (everything that comes after a ? in a url is a query parameter, with keys and values separated by '='. If you had multiple query parameters they would be separated by '&'. Next time you're browsing the web, notice how query parameters are used across the different websites you visit!
+It's easy to access query params within Django - see the getSongInAlbum view definition for an example.
+
+

Authtokens, users, logins with Django REST Framework

+

Up to now, we've covered the fundamentals of how to create a database, populate it, and create simple endpoints for creating, updating, and destroying. But what happens when we want our system to be used by real users? How do we store their information and their interactions with our system? There are a few important issues that we'll need to address:

+
    +
  • How do we make sure that users' personal information like their passcodes are being stored in a secure way that protects them from being stolen?
  • +
  • How do we build a system that users can sign up for and log in to? How do we store info about their session?
  • +
  • How do we make certain endpoints in our system behave differently depending on the user who is accessing them?
  • +
+

The answer to these questions can be complicated. In order to save your time and energy, we're going to utilize the resources that Django and Django REST Framework provide for us as much as possible instead of developing our own solutions. Not only is this easier, but it's also much more secure- would you trust a system written from scratch by a novice undergrad student with your password and financial information?

+

How do we store user's personal info?

+

The answer to this question is usually to use Django's built-in User model. You can read the docs on User models here:

+

https://docs.djangoproject.com/en/3.1/ref/contrib/auth/

+

The User model contains common fields that will be used by users, and in your serializers you can define which fields are relevant to your use case.

+

By default, Django builds the User models for you. You can see them after you runserver and check inside the /admin route.

+

We can also utilize the User model to build new endpoints in our API, just like we could with any other model. Here's an example:

+

Models.py

+
from django.contrib.auth.models import User
+
+

+
class UserLikesSong(models.Model):
+    user = models.ForeignKey(User, on_delete=models.CASCADE)
+    song = models.ForeignKey(Song, on_delete=models.CASCADE)
+
+

Serializers.py

+
class UserLikesSongSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = UserLikesSong
+        fields = ("id", "user", "song")
+        #Id of the rel, Id of the user, ID of the song
+
+

You can now make endpoints with this just like you would with any other model/serializer. This specific example could be used to track what songs the User likes, like in Spotify.

+

If you wanted to make a custom User model, you could read more about it here https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html and do more research, as there are many methods you could use. For basic university usage though, it's 99% of the time going to be faster and easier to roll with the User model they give you out of the box.

+

If you want to give different categories of users different permissions, see the_ permissions _section (TODO: this won't be done for a while. In the meantime, these links may help: https://www.django-rest-framework.org/api-guide/permissions/ ← Technical overview

+

https://www.django-rest-framework.org/tutorial/4-authentication-and-permissions/ ← Basic usage example)

+

Signup, Login, Sessions: How do we do them?

+

I highly recommend using Django REST Framework's Authtokens to handle information about user sessions. You can read about authtokens, as well as the other options available, here: https://www.django-rest-framework.org/api-guide/authentication/#tokenauthentication

+

To add Authtoken's, make sure the following items appear in settings.py:

+
###### You will need to add the REST Framework part.
+###### INSTALLED_APPS should already exist.
+
+REST_FRAMEWORK = {
+    'DEFAULT_AUTHENTICATION_CLASSES': [
+        'rest_framework.authentication.TokenAuthentication',  
+    ],
+}
+
+INSTALLED_APPS = [ # There will be more here
+  'rest_framework',
+  'rest_framework.authtoken',
+]
+
+
+
+

Note: I couldn't get these to work, at least not with authtoken. Leaving them here in case some enterprising individual finds them useful, or message us on Discord if you figure this out :)

+

To get REST Framework's default login and logout views (prebuilt), type this in your project's root urls.py file:

+
 urlpatterns = [
+    ...
+    path('api-auth/', include('rest_framework.urls'))
+]
+
+

Your path doesn't have to be api-auth, it can be whatever you want.

+

To use REST Framework's login view, include this in urls.py:

+
    path('whateverPathYouWantToLogin', obtain_auth_token, name='API Token Login'),
+
+

Include this at top of your urls.py:

+
from rest_framework.authtoken.views import obtain_auth_token
+
+

When you access this path and provide a real username and password in the request body, then you should receive an authtoken. This authtoken is associated with your account. Store this authtoken in a safe place. Now, you can use it in the "authorization" section of your next HTTP requests, and all requests you make from the client will be associated with the account you just logged in from.

+

Creating views for signing up is more difficult.

+ + + + + + + + + + + + + +
In serializers.py: +

+from django.contrib.auth.models import User +

+class RegisterSerializer(serializers.ModelSerializer): +

+ class Meta: +

+ model = User +

+ fields = ('id','username','password')#Change fields if u want +

+ extra_kwargs = { +

+ 'password':{'write_only': True}, +

+ } +

+ def create(self, validated_data): +

+ user = User.objects.create_user(validated_data['username'], password = validated_data['password']) +

+ return user +

+This serializer will make sure that the password that the user makes is valid, and that it's write-only for security purposes. Choose which fields us +

In views.py: +

+from django.contrib.auth import get_user_model # If used custom user model +

+from rest_framework import permissions #We'll discuss more about perms later +

+… +

+class RegisterUserView(generics.CreateAPIView): +

+ model = get_user_model() #Will get the right one if you use custom +

+ permission_classes = [ +

+ permissions.AllowAny # Or anon users can't register +

+ ] +

+ serializer_class = RegisterSerializer #What we defined above +

In urls.py: +

+ path('register', views.CreateUserView.as_view(), name='Register user'), +

+(you may want to put your register / login views together in a different Django App (so they are in a distinct section of your API) +

Test Request in Postman: +

+alt_text +

+Response from request: +

+alt_text +

+

Now let's quickly do a login from this user we just created!

+

I did a login request to the login view I made earlier, but here's what I got:

+

alt_text

+

Whenever you see an error like "no such table", that should be a clue that you need to rerun migrations. The app expected there to be a SQL table, but there was none made yet! Running migrations will ensure there is. Recall the commands for migrations are:

+
+
+

python3 manage.py makemigrations yourAppName

+
+
+
+
+

python3 manage.py migrate

+
+
+

In this case, just the second command will be sufficient

+

Request:

+

alt_text

+

Response:

+

alt_text

+

Yay! It worked! Now we can include this token in our request headers to associate all future requests made with the user we logged in.

+

In future requests, you should put the token as a value in your request headers, using the key: token.

+

alt_text

+


+Depending on the front-end you build, you should use a different way to store the authtoken that you get from logging in. Usually storing in local memory is okay. Do your own research for how to store authtokens with whatever system you are using.

+

If you want to improve security further, you can use JWT (JSON webtoken) instead, following the instructions here: https://simpleisbetterthancomplex.com/tutorial/2018/12/19/how-to-use-jwt-authentication-with-django-rest-framework.html

+

How do we make endpoints behave differently depending on which user is accessing them?

+

If a user makes a request while they are authenticated (using authtoken, or some other alternative method), then the system will automatically know what user is associated with the user who made the request.

+

You can access the user within a class-based view through

+
 self.request.user
+
+

You can use this within your views in a variety of ways: to filter, to make more complex queries, and to check if the user should have access.

+

For example, let's make a UserLikesSong endpoint that is limited to the songs that the currently logged in user has liked.

+
class GetUserLikesSongs(generics.ListAPIView):
+    def get_queryset(self):
+        queryset = UserLikesSong.objects.all()
+        queryset = queryset.filter(user=self.request.user)
+	# Leftside of filter: from queryset. Rightside: how we're filtering
+        return queryset
+    serializer_class = UserLikesSongSerializer
+
+

We'll cover this in much more detail in the Permissions section.

+

Permissions

+
NOTE: Everything past here is incomplete - you will need to supplement it with your own research, like I did to make this guide!
+
+

To use generic permissions with Django, all you need to do is:

+
    +
  • In your views.py:
  • +
+
from rest_framework.permissions import IsAdminUser, IsAuthenticated, IsAuthenticatedOrReadOnly
+
+

Now, on any class-based view you want to guard with permissions, you can add the following line:

+
class deleteLicenseType(generics.DestroyAPIView):
+    permission_classes = [IsAdminUser]
+    queryset = License_Type.objects.all()
+    serializer_class = License_TypeSerializer
+
+

(this is from a different project)

+

You can apply multiple permissions to the same view like this:

+
    permission_classes = [IsAdminUser|IsAuthenticatedOrReadOnly]
+
+

Sessions & Cookies

+

Sessions/cookies are very easy to make use of with Django. You can use cookies to store information in a user's browser that you'll be able to access in all subsequent requests that a user makes. One example of a good use of sessions/cookies is to store a user's shopping cart content.

+

Some great videos for learning about sessions & cookies:

+

https://www.youtube.com/watch?v=C75IW38hKI8

+

https://www.youtube.com/watch?v=RjykNmVdcgI

+

alt_text

+

Deploy to Heroku

+

alt_text

+

To get your projects online, you can deploy them to Heroku. Heroku is just one of several possible hosting services for Django- but it's base tier is free, easy to use, and simple to deploy to, so that's what I recommend you use. The biggest downside of using Heroku is that its free tier will automatically shut down your app after a period of downtime, meaning it'll take a long time to respond the next time you try to access it.

+

A guide on getting started:

+

https://devcenter.heroku.com/articles/django-app-configuration

+

Some useful commands:

+
+
+

pip install gunicorn

+
+
+

To deploy to Heroku, you will need to make a file called Procfile (no file ending), and add the following gunicorn text to it:

+
web: gunicorn yourAppName.wsgi
+
+

This gunicorn file should be at the same level as your manage.py file. When you deploy to Heroku, you should be deploying from this level of the project hierarchy to avoid issues.

+

Your remote heroku environment needs to understand what requirements it will need to have to start up. You can do this by providing it with a requirements.txt file which will also be at the same level as your manage.py file.

+

To get the right requirements in a .txt file, type

+
+
+

pip freeze > requirements.txt

+
+
+

These commands will help initialize your heroku repository:

+
+
+

heroku create

+
+
+
+
+

heroku run python3 manage.py migrate

+
+
+
+
+

heroku run python3 manage.py createsuperuser

+
+
+

Important: Your database itself will not transfer to Heroku. You will need to recreate all entities, config, and users.

+

Tech Start's Git Guide

+

alt_text

+

Contents

+ +

Note

+

Unless otherwise stated, all git commands are one line terminal commands

+

We are also assuming that you have set up a project at /path/to/project and had cd'ed to /path/to/project

+

Getting Started - Setting up a Repository

+

GitHub: Create a Repository

+

A Git Repository is virtual storage of your code, allowing you to save versions of your code, as well as share and allow others to edit the code.

+

Initializing a new repository: git init

+
    +
  • This step is typically used by the project manager, or the owner of the project
  • +
+

Cloning an existing repository: git clone [GitHub git link]

+

E.g. git clone https://github.com/techstartucalgary/tsu-website.git

+
    +
  • This step is typically used by the project members, or anyones who wants to add onto the projects after it has already been created
  • +
  • The GitHub git link can be located on the GitHub repository website under the <> Code dropdown
  • +
+

Git Analogy

+

Imagine that we have two people working on the same paper remotely, Person A and Person B. Person B is the laziest of the two, so Person A starts the paper.

+

Person A choses to create a word document on their local machine. This can be seen as Initializing a new repository.

+

After working on the paper for a bit, they realize that Person B also needs to contribute, so they send the paper by email to Person B. This step is equivalent to forking a repository.

+

Person B decides that they would prefer to work on the paper by hand, and so they takes the email that Person A sent, and prints it to work on, cloning the repository

+

GUI vs Command Line?

+

There are a number of great GUI (graphical user interface) tools that simplify the process of +using Git, like GitHub Desktop, GitKraken, and the built-in Source Control tab in VSCode. +There's nothing wrong with using these tools, but we like to encourage our members to use the +command line in order to get a better understanding of what exactly you're doing. It's also universal, +so whatever you learn here can be used in any organization that uses Git!

+

Staging Files & Creating Commits

+

Git works using units of change called commits. These commits are essentially snapshots of your project. To share any changes, additions, and deletions that you make with other people and upload it to the internet, you will need to package them into a commit first.

+

You can think of the staging area of git (the green box that says "staged changes" in the below diagram) like a box. You can add and remove changes from the box on a per-file basis.

+

Committing is like sealing that box and sticking a label on it. The contents of that box are your changes. But, if there are changes in the untracked or unstaged areas, they will not be included in the commit, because they are outside of the box.

+

The following diagram shows how the staging process works, and what commands you can use to move changes (again, per-file basis) between areas. Use the git status command to see a summary of where every change in your project is on this diagram! We recommend using git status frequently.

+

image

+

Common Commands

+

Here are some common commands for using Git to store and prepare the code to be pushed to the remote repository. +They are shown in the general order that you want to use them in.

+

Below is the legend for some common, optional parameters which are shown

+
    +
  • (-text) = optional parameters for command, which are called as is (git command -text)
  • +
  • <helloWorld> = optional parameters for command, which are called with your version of the name (git command helloWorld)
  • +
  • For example: For git add [path], you should replace [path] with path/to/your/file, so the final command is git add path/to/your/file
  • +
+

git status

+

Shows the status of all changes (all staged or unstaged changes, not committed changes). It shows where every change is on the diagram above, and even lists some helpful commands.

+

It will also say what branch you are on, and if you are ahead or behind the remote version of your branch in terms of commits (more on this in later sections).

+

Additionally, if you have a merge conflict, it will show which files caused it.

+

git add [path/to/file]

+
+

git add app/pages/HomePage.tsx

+
+

Selects the specified files, moves it to the “staging area” to be included in the next commit.

+

This command will also allow adding a deleted file to be staged, which after being committed and pushed will remove the file from the git branch.

+

This command will ignore all files in the “.gitignore” file.

+
    +
  • [path/to/file] File path expression. Any files which match the expression are acted upon by git add +
      +
    • You can use git add -p to add parts of a changed file if needed.
    • +
    • Pro tip: You can use git add -A to add all changed files! Read about why you shouldn't always do this.
    • +
    +
  • +
+

git commit -m "[commitMessage]"

+
+

git commit -m "Updated homepage text"

+
+

Creates a new commit that includes all changes that you added to the staging area.

+

You always need to include a commit message (-m) for your commit . It is helpful to be as descriptive as possible!

+

If you don't use the -m flag and provide a commit message in quotations, Git will make you write a commit message using a text editor. However, this can be very confusing since your default Git text editor is often configured to be VIM (stuck in VIM? type :qa to exit). For this reason, we recommend always specifying the commit message using -m.

+

After you commit, these changes are no longer in the staging area - they are in your commit!

+
    +
  • +

    (-m) means you will be specifying a commit message in quotations

    +
  • +
  • +

    "[commitMessage]" the message that will be attached to the commit. Only usable if -m is used, otherwise a text editor will appear for the commit message.

    +
  • +
  • +

    Tip: always wrap your message in double quotes ("). This lets you use abbrevations in your message (... -m "Reverted Ben's Changes")

    +
  • +
+

git restore [path/to/file]

+
+

git restore app/pages/HomePage.tsx

+
+

Discards local changes in a file, thereby restoring its last committed state.

+

Think of it like a super-undo, allowing you to quickly get rid of accidental or unnecessary changes, restoring your files to how they used to be before you changed them.

+

It won't work if your file is already staged - you'll have to unstage it with git restore --staged [path/to/file] first.

+

git restore --staged [path/to/file]

+
+

git restore --staged app/pages/HomePage.tsx

+
+

Removes the file from the Staging Area, but preserve all modifications you made to it. +You can use it if you accidentally added a file to the staging area whose changes shouldn't be included as part of the next commit you are planning to make. +If the file was originally untracked, it becomes untracked again. If it was originally a file with unstaged changes, the changes become unstaged again.

+

Naming commits

+

When you create a commit, you always want to include a descriptive name for the commit that describes exactly what it accomplishes. You wouldn’t label a moving box with kitchen items as simply “stuff”. +Remember that other people will see these commit names, so make it easy for them to understand!

+

For a video tutorial on staging files, watch this

+

If you want to learn about additional flags and commands you can use in the process of staging files and adding commits, see the section Advanced Staging & Commits

+

Branches

+

Branches represent an independent copy of the code that has branched off the main code at a certain time. +They allow new features to be worked on, while ensuring that a working version of the code is not tampered with. +This allows large changes to be made to the code base, with little fear of breaking your projects.

+

git branch

+

Lists all branches in the current repository

+

git branch [branchName]

+
+

git branch ben/updateFont

+
+

Creates a branch called branchName in the current repository.

+

The created branch's commit history will match the branch you were on when you called git branch.

+

We recommend naming branches according to what you want your branch to do, prefixed by your name. +For example, if I was updating the font on a website, I might call my branch ben/updateFont. +Since branch names include whitespace, we recommend using camelCase to name them, but check with your PM +how they want to handle this.

+

git branch -d [branchName]

+
+

git branch -d ben/updateFont

+
+

Deletes the branch called branchName

+

Note: you cannot delete the branch you are one! git checkout to another branch first.

+

(You can use -D instead of -d to force delete the specified branch, even is it has unmerged changes. +It's typically better to use -d, unless you are 100% sure you will never need the branch you are deleting again)

+

git checkout [branchName]

+

Navigates your current directory to the specified branch, allows you to select which line of development you are working on.

+

You can only switch branches if you have no unstaged/staged changes in your current branch. If you can't switch branches because of this, see What happens if you can't checkout? for more instructions.

+

Pro tip: You can use git checkout -b [branchName] to create a branch and switch to it immediately.

+

How to use branches

+

Some rules (more like guidelines):

+
    +
  • Every single time you start modifying the code you should create a new branch to use
  • +
  • Branches should generally only be for one feature
  • +
  • Always branch off main
  • +
+

Before you make your branch, you should make sure you are creating your branch based on the most recent code. Do git checkout main to switch to the primary branch of your repository. You should also do git pull to make sure the primary branch is up to date with the version present on your remote repository (more on this in the next section).

+

Now that you are on the primary branch, use git branch [branchName] to create a new branch based on the current one. Make sure you name it according to what you aim to accomplish there (see the description of the command above).

+

Now that you have created your branch, you'll want to switch to it. Use git checkout [branchName] to switch to your branch. You can do work here and follow the instructions in the staging files and creating commits section to save your changes into commits.

+

Eventually, you'll be done using the branch (perhaps you will follow the instructions in the next few sections to push it to your remote repository and use it in a pull request. or perhaps you need to work somewhere else). Either way, you can switch to a different branch with git checkout [branchName]

+

If you have completed a pull request for your branch to merge it into a different branch of your project, you no longer need to keep the local copy of your branch. We recommend you use git branch -d to delete any branches you will no longer need to use. This makes sure your local repository remains nice and tidy.

+

Here's a quick summary of the commands:

+
git checkout main
+git pull
+git branch ben/updateFont
+git checkout ben/updateFont
+... doing stuff ...
+git checkout main
+git branch -d ben/updateFont
+
+

Git Branch Diagram

+

What happens if you can't checkout?

+

Git will not let you checkout to switch branches if you have staged or unstaged changes.

+

You will have a few choices on what to do:

+
    +
  • Restore files to how they originally were (either by manually undoing, or ideally making use of git restore, described in the previous section). Do this if any of your changes are unnecessary or accidental.
  • +
  • Create a commit, following instructions from the previous section. Only create a commit if you actually want to save the changes you made. +
      +
    • We recommend you avoid making commits on any branches that you share with other people, especially your primary branch (main)! All Tech Start repositories actually prohibit commits to main to prevent this.
    • +
    +
  • +
  • Utilize git stash to move changes from one branch to another without needing to commit them. Do this if your changes are intentional, but you wanted them on a different branch than the one you are currently on. This is described in more detail here.
  • +
+

You can combine these approaches to deal with your changes as necessary.

+

Remote Repositories

+

When you work with Git, you will typically have a local repository (the copy of your project that exists on your personal device) and a remote repository (the copy of your project that exists on the internet, usually on a service like GitHub, GitLab or BitBucket)

+

An absolutely core part of using Git is managing the interactions between your local repository and the associated remote repository. The two key commands you will need to learn are git push (which you can use to push commits from your local repository to the remote repository) +and git pull (which you can use to pull commits from the remote repository and insert them into your own local repository).

+

A common mistake that newcomers to Git will make is assuming that the local repository is the same as the remote repository - when they're actually 2 separate concepts. Your commits won't appear on the remote repository until you manually push them there. If someone else pushes new changes to the remote repository, you won't see their changes on your local repository until you manually pull those changes to your device.

+

Most version control related work happens in a local repository(staging, committing, viewing status, etc.). +Remote repositories come into play when you start working with others on the same project. +You can think of it as a cloud file server that you use to collaborate with others.

+

Remotes

+
+ + + +
LocalRemote
Are located on the computers of the team membersAre on the internet or a local network
Contains branches, commits, tagsContains branches, commits, tags
All “coding work” happens only in the local repository, and needs to be made and committed locally.After the work has been committed locally, it can be “uploaded” to the remote repository in order to share with others.
+
+

Note: You can name a local branch the same name as the remote branch, but they are NOT the same

+

Note: You can also have multiple remote repositories (default is origin), though you probably won't need this, +since each local repository stores what it's remote is.

+

git fetch is what you do when you want to see what everybody else has been working on. It doesn’t force you to actually merge the changes into your repository. This makes fetching a safe way to review commits before integrating them with your local repository.

+

You might be wondering how to set a remote, and the good news is that if you cloned your repository from GitHub, +it's been set for you, so no need to worry! +If you need to change the remote for some reason, you can do git remote set-url origin <url>

+

Intro to Remote Repositories

+

git pull [remoteName] [branchName]

+

git pull origin ben/updateFont

+

Pulls all changes/commits from the specified remote branch, and inserts them into your current branch.

+

Pro tip: Use git pull without any other options to update the branch you're on. You'll most likely only use this to update main.

+

More technical description: fetches from the remote branch (git fetch), and merges your current branch with commits from the remote (git merge)

+
    +
  • [remoteName] [branchName] pulls from a specific branch, which you specify
  • +
+

git pull origin main

+

Fetches commits from the master branch of the origin remote (into the local origin/master branch), and then it merges origin/master into the branch you currently have selected

+

git push

+

Updates the remote branch with your staged, local commits

+

Always pull before pushing to a branch to avoid unwanted merge conflicts and errors..

+

Merge Conflicts

+

Conflicts generally arise when two people have changed the same lines in a file, or if one developer deleted a file while another developer was modifying it. In these cases, Git doesn't know which change is correct. Git will mark the file as being conflicted and halt the merging process. It is then the developers' responsibility to resolve the conflict.

+

Although they look scary, resolving merge conflicts is a completely normal part of working collaboratively.

+

The general steps for resolving merge conflicts can be seen as:

+
    +
  1. Figure out the conflicts and change them accordingly
  2. +
  3. Re-commit the changes
  4. +
  5. Attempt to merge with the selected branches
  6. +
  7. Read error messages (if any) and repeat if necessary
  8. +
+

Some useful commands for attempting to fix merge conflicts

+
+ + + + +
CommandDescription
git statusHelp identify conflicted files
git log --mergeProduces a log with a list of commits that conflict between the merging branches
git diffFinds the differences between the states of a repository, which helps in preventing conflicts
git reset --mixedUndo changes to the working directory and staging area
+
+

Example of Merge Conflicts shown in Command Line

+

alt_text

+

In this case, there are two instances of the file “merge.text” that were modified by different branches/people. Git is unable to determine which lines to keep, as both were changed manually.

+

Resolving Merge Conflicts

+
    +
  1. Identify Conflicted Files
  2. +
+

Git will notify you if there are any merge conflicts after running git status. You can identify these conflicts by looking at your project files. Conflicted files will have markers like <<<<<<< HEAD, =======, and >>>>>>> [branch name] where the conflicting changes are.

+
    +
  1. Open the Conflicted File
  2. +
+

Use a text editor or an integrated development environment (IDE) like VS Code to open the conflicted file. Inside, you will see the conflicting sections clearly marked by symbols.

+
    +
  1. Resolve Conflicts
  2. +
+

Review the conflicting sections and decide which changes to keep. You can choose to keep your changes, the incoming changes from the other branch, or a combination of both. Make your edits, then remove the conflict markers (<<<, ===, >>>).

+
 <<<<<<< HEAD
+// Your changes
+=======
+// Incoming changes
+>>>>>>> [branch name]
+
+
    +
  1. Save the File
  2. +
+

Once you've resolved the conflict, save the file.

+
    +
  1. Add the Resolved File
  2. +
+

Use git add command to stage the resolved file.

+
    +
  1. Continue the Merge
  2. +
+

After resolving all conflicts, use git commit to finalize the merge.

+

git commit -m "Resolved merge conflicts"

+
    +
  1. Push Your Changes
  2. +
+

git push your changes to the remote repository.

+
+

Merge conflicts can be complicated to resolve, so make sure you communicate with the person who created +the branch you have a conflict with to ensure you don't lose their work.

+

Remember that Incoming changes are from the other branch, while Current changes are from your branch.

+

It also doesn't hurt to use a tool that's purpose-built to resolve merge conflicts. +VS Code has one built in, but there are a number of free options available online.

+

Using GitHub

+

GitHub is a company that provides a service of hosting Git repositories online. There are many other alternative companies that provide a similar service, like BitBucket, GitLab, and Azure DevOps, but GitHub is the most popular one and the one our project teams use.

+

The instructions for the rest of this section will focus on GitHub's features. However, almost every feature described here has equivalents in the other git hosts, so if you know how to use one you generally know how to use them all.

+

Pull requests

+

Video intro to pull requests

+

A pull request is a way of merging code from one branch of your remote repository into another.

+

alt_text

+

You are requesting that the base branch pulls the commits from the compare branch. +In the above example, you are requesting that the main branch pulls the commits from the addLaunchEvent. +In other words, you are taking the changes from compare and putting them into base.

+

You will use pull requests extensively as part of your Git workflow.

+

We encourage teams to use small, frequent, single-feature PRs. Ideally each PR should be associated with only one branch, and each branch to only one PR. Each PR should have a name that describes exactly what the PR accomplishes. By doing smaller PRs, you will make sure everyone frequently updates their codebase so you don't end up with massive merge conflicts. By limiting your PR to a single feature, you also make it super easy to roll back that feature and reverse all commits in the PR by reverting the PR itself.

+

Advantages of pull requests:

+
    +
  • They enable your team to do pull request reviews (see more below)
  • +
  • Your team can set up custom tests / deployments using CI/CD methods to ensure that your code runs as expected before you merge it
  • +
  • It enables you to double check what code you are adding
  • +
  • If you ever need to undo a pull request, it's very easy. Most git hosts have an easy way of reverting a pull request- usually it will create a new branch and PR itself, from which you can solve any merge conflicts and quickly roll back the code added from a previous PR.
  • +
  • If you stick to coding 1 feature per pull request, it makes it very easy to understand the history of your repository
  • +
+

Sometimes, when you create a pull request, it will say there is a merge conflict. If this happens, don't force the PR to merge! Instead, you'll want to resolve the merge conflict.

+

Steps:

+
    +
  1. On your local machine, checkout to the "compare" branch - git checkout addLaunchEvent
  2. +
  3. Once you are on the compare branch, do a git pull from the base branch of your PR - git pull origin main
  4. +
  5. This will pull changes from the base into your compare branch. Git will notify you that this caused a merged conflict. This is okay!
  6. +
  7. Resolve the merge conflict according to the instructions in the Merge Conflicts section. You'll need to add and commit the files where you solved the merge conflict.
  8. +
  9. Confirm you have resolved every merge conflict. Try running/building your app again to make sure everything works as expected.
  10. +
  11. Push the commit(s) that solved the merge conflict to your remote compare branch git push origin addLaunchEvent
  12. +
  13. The pull request should now update saying there is no merge conflict! You can merge it now, as long as your team approves of it.
  14. +
+

Additional readings on pull requests:

+

GitHub Docs

+

https://product.hubspot.com/blog/git-and-github-tutorial-for-beginners

+

https://yangsu.github.io/pull-request-tutorial/

+

Pull Request Reviews

+

One of the main advantages of pull requests is that they enable you to do a pull request review, ensuring that code that gets pulled into your primary branches has been reviewed by your team to make sure it won't introduce code smells or bugs.

+

PRs provide the opportunity to review another developer's code and make sure that it meets the guidelines or practices that your organization or team has. For example, if you have a developer who is more familiar with the architecture of the software system, they can provide valuable input towards making sure that your changes fit within the long term architectural vision of the system. +Alternatively, you can have a newer team member who is not yet familiar with the overall code structure and they can add comments to specific parts of the code in a PR to ask for further clarification for why a certain change was made.

+

Aside from learning, PRs generally serve as a major communication channel for developers in industry, because they provide the opportunity for automated testing and improvements before your code changes are moved to the next deployment stages. One example of automated testing is using linter which is a static code analysis tool used to flag errors in your code such as bugs, stylistics errors, and suspicious constructs, like for example declaring a variable twice.

+

Whenever someone wants to merge a pull request, you should require them to get their PR reviewed first. To review a pull request, look at all the changes they made.

+

Best Practices for PR Contributors:

+
    +
  • Review your own PR before adding reviewers. +
      +
    • You may find some work-in-progress or experimental code. There could also be a typo, unintended indentation, or extra line breaks.
    • +
    +
  • +
  • Link your PR to your issue.
  • +
  • Include a brief description of your changes.
  • +
  • Push small incremental commits to your PR. +
      +
    • You can also mark your PR as a DRAFT PR in GitHub. This pre-commit review can be good practice to check with reviewers if you are going in the right direction before making any more code changes.
    • +
    +
  • +
  • Add additional comments to your PR to guide reviewers through the review. +
      +
    • Highlight areas reviewers should focus on.
    • +
    • Clarify changes with comments and additional references.
    • +
    • Favor adding code comments over PR comments as the code comments will out survive the PR comments.
    • +
    +
  • +
+

Best Practices for Reviewers

+
    +
  • Be fast, not furious +
      +
    • Responsiveness and turnaround time are very important to keep PRs healthy and not go stale due to other changes which may have been merged during the time that the PR is open and may even introduce new merge conflicts.
    • +
    • Either as a reviewer or as an author, you should keep the conversation actively going until the issue is resolved.
    • +
    • As a rule of thumb, if the PR is small or trivial, you should review it within one business day.
    • +
    • Plus, context switching is very expensive in industry. Many developers, like myself, have the memory of a goldfish when it comes to remembering the code we wrote a day ago. So, as a courtesy, you can let the developer who opened the PR know if you are planning on looking at their PR at a later time. If there are PRs open, it is also good practice to review them before you create a new one yourself.
    • +
    +
  • +
  • If there are outstanding comments or the PR is in draft mode, do not approve the PR. +
      +
    • Instead, stay involved and follow the discussions and new changes to see how the PR pans out.
    • +
    +
  • +
  • Do NOT rubber stamp reviews. +
      +
    • If you do not understand a change, you can ask for clarification or justification in the comments.
    • +
    • You do not have to approve a PR if you are not actually approving the change. You can let the author know that you have completed your review but are not weighing in on the approval.
    • +
    • Our TechStart website team's default PR policy requires approvals from 2 different reviewers, but an approval that is rubber stamped can be more harmful than abstaining if it promotes bad practices and bugs to be user-facing.
    • +
    +
  • +
  • Provide constructive comments +
      +
    • Code reviews are an important step in ensuring we build high-quality software products. As a reviewer, it's your job to carefully read and think about the code you are reviewing, and provide constructive feedback or ask questions about the code if things are unclear.
    • +
    • If the code isn't formatted correctly, too confusing, contains mistakes, or follows poor conventions, leave a comment to tell them what they did wrong and how they might be able to fix it (but phrase everything constructively! you don't want to seem rude or aggressive).
    • +
    • If you disagree with something, give a reason and an example of a better solution. Let the author know exactly what you think is better.
    • +
    +
  • +
+

GitHub and other Git hosts support adding inline comments, so you can comment on specific areas of the code when necessary. The best place to do this is the "Files Changed" tab of a pull request.

+

It is up to them to address every issue that is brought up, and push the changes back to their branch. They should let you know when they've completed everything, and you can check to make sure you're happy with their changes.

+ +

Let's assume you have some commits on branch yourLocalBranch, and you want to merge them into a branch on your team's GitHub (which uses the default remote alias, origin) called branchYouWantToMergeTo.

+

Part 1 - Set up your branch:

+
    +
  1. Ensure you are on the main branch of your repository. It is usually called main. If you are not on the main branch, switch to it with git checkout main
  2. +
  3. Pull the most recent version of your main branch from GitHub. You can do this with git pull origin main. This will make sure your new branch contains all the most recent changes
  4. +
  5. Create a new branch for yourself. The name of the branch should describe what the code inside will do, and you should prefix it with your name or nickname. For example, git branch joel/changeButtonColor
  6. +
  7. Check out your new branch before you make any changes. Example: git checkout joel/changeButtonColor. Refer to Branches if you make any mistakes.
  8. +
+

Part 2 - Make your commits:

+
    +
  1. Follow the instructions in the Staging Files and Adding Commits section to create a commit containing your desired changes. Use git status frequently to make sure you are doing everything correctly.
  2. +
+

Part 3 - Push your commits to origin:

+
    +
  1. Push your branch to origin. Ex. git push origin joel/changeButtonColor
  2. +
  3. Set up a pull request on GitHub, with the base as main (or the branch you want to merge to) and the compare branch as your branch, (ex joel/changeButtonColor)
  4. +
  5. (Only if your pull request indicates you have a merge conflict): DO NOT merge the branch. Instead, do git pull origin main (or the branch you want to merge to) on your local machine. This will bring up the merge conflict.
  6. +
  7. Follow the instructions in Merge Conflicts to fix any merge conflicts that you get from pulling that branch. Once you have fixed all merge conflicts, remember to double check that your code runs, then git add and git commit your fixes!
  8. +
  9. Push your changes to your remote repository! Do git push origin yourLocalBranch
  10. +
  11. Now that your changes are present on your remote repository, you should create a pull request on GitHub. The base (target branch) should be branchYouWantToMergeTo, and the source should be yourLocalBranch.
  12. +
  13. Check to make sure the pull request says "No merge conflicts". If it does detect merge conflicts, that means you didn't do steps 4-7 correctly, so redo them!
  14. +
  15. Request a reviewer for your pull request. They will read your code and offer suggestions on how to improve it.
  16. +
  17. Resolve the comments of your reviewer. Once they are resolved and your reviewer confirms you can proceed, you can merge the pull request on GitHub. Congratulations! Your code is now merged into your project.
  18. +
+

Clean up:

+
    +
  1. Delete your branch on the remote repository
  2. +
  3. Delete your branch on your local system (checkout to main. Then delete with git branch -d yourBranchName)
  4. +
+

Big Picture Git/GitHub Workflow

+

Now that you understand the complete process on an individual level, let's take a step back to understand how your team will be using git.

+

Here is the Git workflow we recommend:

+

This is what is used at Microsoft. It works well and it's good practice to teach it.

+
    +
  1. When a team member wants to make changes or additions to the code, they should create a new branch for themselves. The branch name should describe what it does, ex. fixButtonGlitch
  2. +
  3. They git push their code to a branch on your origin repo that shares the same name
  4. +
  5. When they're ready, they create a Pull Request on GitHub. The PR's source should be their branch, and the destination should be main.
  6. +
  7. They should describe their Pull Request in the description and provide screenshots if applicable
  8. +
  9. They merge their own PR, once the following 3 conditions are met: +
      +
    1. There are no merge conflicts with the base branch
    2. +
    3. If your project has Continuous Integration (which it should), the PR build succeeds
    4. +
    5. At least 2 people have reviewed the code in the PR (more on code reviews later) and all comments from code reviews have been resolved
    6. +
    +
  10. +
  11. Upon merging the PR, they delete their branch.
  12. +
+

FAQ

+ +

Advanced Section

+

Here are some advanced Git commands you can use to boost your Git game to the next level. They are not essential to using Git, but you may find them helpful. If you're still learning the beginner commands, we recommend focusing on them until you're comfortable with them before worrying about these advanced commands.

+

Advanced Staging and Commits

+

Here are some additional commands and flags for existing commands that you can use while you are staging files and adding commits.

+

If you want descriptions of the basic staging and commits, please see staging files & creating commits in the beginner part of the guide.

+

git status (-s) (-v)

+

(-s) displays information in a shortened and fast format

+

(-v) displays information in more detail, with additions such as the textual changes of uncommitted files

+

git add [fileName or folderName] (-u)

+

You can use the -u flag on git add for the following effects:

+

(-u) adds new/modified files and IGNORES deleted files to the staging area

+

git commit (-a) (-am) "[Commit message here]"

+

You can use the -a and -am flags on git commit for the following effects:

+

(-a) commits all files in the staging area

+

(-am) commits all files in the staging area and allows the addition of the commit message in the command

+

"[Commit message here]" the message that will be attached to the commit. Only usable if -m or -am is used; otherwise, a text editor will appear for the commit message.

+

Git Stash

+

Tutorial

+

🚧 Under Construction 🚧

+ +

Git Clean

+

Tutorial

+

🚧 Under Construction 🚧

+ +

Undoing Commits & Changes

+

Below is the general sequence of commands to check, and undo previous commits. Notice that we must use the commit comments as the easiest factor in differentiating between commits. It is important to use a descriptive comment for each commit.

+

git log

+

Displays old commits with the ID hash and commit comment on the current branch.

+

git checkout [id hash]

+

Will make your working directory match the exact state of the id’ed commit.

+

Nothing you do here will be saved to the current state of the project (to go back do git checkout main).

+

git clean (-f) (-n)

+

git clean -n shows which UNTRACKED files will be removed, should you do git clean -f.

+

Good practice is to always -n before you -f. Learn more

+

(-n) runs a dry run (previews what files would be removed).

+

(-f) to force untracked file detection (removes the files).

+

git revert

+

Undoes a single commit.

+

git reset [id hash]

+

Goes back to the specified commit by removing all subsequent commits.

+

Git Rebase and Git Merge

+

git merge [branchName]

+

Merges the specified branch into the branch that your local directory is currently on. +In a typical workflow, you will not need to use this command ever. +Instead, git pull and pull requests will handle all merging for you.

+

🚧 Under Construction 🚧

+
+
+
+

Tech Start's API Guide

+

alt_text

+

APIs are a ubiquitous component of software engineering. APIs allow different components of a software system to interact with each other in a logical way.

+

Learning about APIs is critical to your growth as a software developer. This guide contains links and advice to get you started!

+

Introduction

+

What is an API?

+

alt_text

+

API stands for Application Programming Interface, and in simple words, allows two applications to talk to each other and send information between the two.

+

Further reading on the basics of APIs: https://www.plektonlabs.com/api-101-what-are-they-and-how-do-they-work/?gclid=Cj0KCQiAhf2MBhDNARIsAKXU5GRbLqWDWBPN0Zh4ZX6KwjevURl9KmQo0EVBzLn5mcePxaI_l1oWQSQaAkGDEALw_wcB

+

Analogy of an API

+

Imagine you are sitting in a restaurant with a menu and you are trying to decide what to order. You are one of the applications and in order to get food, the kitchen will act like the other application. It is the system that will “make” you food. The waiter in this scenario will be the API, and he/she delivers the food from one application(the kitchen) to another(you). The waiter is the messenger that takes your request or order and tells the kitchen – the system – what to do. Then the waiter delivers the response back to you; in this case, it is the food.

+

How API’s Work

+
    +
  1. A client application initiates an API call to retrieve information—also known as a request. This request is processed from an application to the web server via the API’s Uniform Resource Identifier (URI) and includes a request verb(see Types of API calls), headers, and sometimes, a request body.
  2. +
  3. After receiving a valid request, the API makes a call to the external program or web server.
  4. +
  5. The server sends a response to the API with the requested information.
  6. +
  7. The API transfers the data to the initial application that requested the information.
  8. +
+

Why would you need an API?

+

Many companies have APIs built to allow others to build interesting applications using their company data. APIs also allows a project to be dynamic - it will update the frontend information automatically when the back end is updated. This saves the hassle of going through tons of HTML code updating data one by one.

+

Types of APIs

+

GraphQL vs Rest

+

Reading In favor of GraphQl:

+

https://www.howtographql.com/basics/1-graphql-is-the-better-rest/

+

Reading In favor of Rest:

+

https://www.rubrik.com/blog/technology/19/11/graphql-vs-rest-apis

+

Rest APIs

+

About

+

https://www.ibm.com/cloud/learn/rest-apis

+

A REST API is an API that conforms to the design principles of the REST, or representational state transfer architectural style. For this reason, REST APIs are sometimes referred to RESTful APIs.

+

What is a RESTful API? https://www.youtube.com/watch?v=y0U-ZxgLu98

+

Types of API calls

+

alt_text

+

Creating your own API

+

Interactive Resource on APIs

+

https://apiary.io/how-to-build-api#phase-design

+

Tons of help on creating API with different languages https://rapidapi.com/blog/20-tutorials-on-how-to-create-your-own-api-sorted-by-programming-language/

+

Explanations of API’s and more in depth language-specific resources

+

https://www.moesif.com/blog/api-guide/getting-started-with-apis/

+

Using Postman

+

What is Postman?

+

Postman is a platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs faster.

+

Getting Started with Postman: https://www.guru99.com/postman-tutorial.html#1

+

Good Postman Series starting with setting up: https://www.youtube.com/watch?v=juldrxDrSH0&ab_channel=AutomationStepbyStep

+

Further Resources on APIs

+

Collection of Free, premade API’s

+

Most premade API’s will have documentation of how to use/maintain them

+

https://github.com/public-apis/public-apis

+

https://any-api.com/

+

Example of using a premade API

+

https://rapidapi.com/blog/how-to-use-an-api/

+

GraphQL

+

Further Help

+

GraphQL Tutorial: https://www.youtube.com/watch?v=ed8SzALpx1Q&ab_channel=freeCodeCamp.org

+

What is GraphQL (A really good article): https://www.redhat.com/en/topics/api/what-is-graphql

+

Why use GraphQL: https://www.apollographql.com/docs/intro/benefits/

+

Getting started with GraphQL: https://www.apollographql.com/docs/intro/benefits/

+

GraphQL is split into two main parts, A Schema (Basically a model for the response), and a resolver (a collection of functions that generate response for a GraphQL query. In simple terms, a resolver acts as a GraphQL query handler)

+

An article that explains what a Query, Mutation & Subscription are: https://medium.com/software-insight/graphql-queries-mutations-and-subscriptions-286522b263d9

+
+
+
+

Tech Start's React Guide

+

+

alt_text

+

React Main Concepts

+ +

JavaScript For React

+ +

More React

+ +

React Ecosystem

+ +

React Main Concepts

+

React Video

+

Check out this video as a crash course to React:

+

https://www.youtube.com/watch ?v=Ke90Tje7VS0

+

If you find this video confusing, or prefer a different one as a React intro, please let us know :)

+

If you prefer reading to watching videos, this guide is helpful:

+

Components

+

React is built around the concept of components. Components are reusable, self-contained units that encapsulate the UI and behavior of a part of the application. React applications are typically composed of many components.

+
function MyComponent() {
+  return <div>Hello, World!</div>;
+}
+
+

JSX

+

JSX (JavaScript XML) is a syntax extension for JavaScript that allows you to write HTML-like code within your JavaScript. It's used in React to define the structure of components.

+
const element = <h1>Hello, world!</h1>;
+
+

Rendering

+

React renders components into the DOM (Document Object Model). You can use the ReactDOM library to render a component into a specific HTML element.

+
ReactDOM.render(<MyComponent />, document.getElementById('root'));
+
+

Props

+

Props (short for properties) allow you to pass data from a parent component to a child component. This enables you to create dynamic and reusable components.

+
function Greeting(props) {
+  return <div>Hello, {props.name}</div>;
+}
+
+

State

+

State is a way to store and manage data that can change over time. It is used to make components dynamic and interactive.

+
class Counter extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = { count: 0 };
+  }
+}
+
+

Lifecycle Methods

+

React components have a lifecycle, and you can use lifecycle methods to perform actions at various stages of a component's existence. For example, componentDidMount is called after a component is rendered.

+
componentDidMount() {
+  // Perform initialization after rendering.
+}
+
+

Handling Events

+

You can define event handlers in React components to respond to user interactions, such as clicks or input changes.

+
function Button() {
+  function handleClick() {
+    console.log('Button clicked');
+  }
+
+  return <button onClick={handleClick}>Click me</button>;
+}
+
+

Conditional Rendering

+

You can use conditional statements and expressions to conditionally render different parts of a component based on certain conditions.

+
function Greeting(props) {
+  if (props.isLoggedIn) {
+    return <div>Welcome, User!</div>;
+  } else {
+    return <div>Please log in.</div>;
+  }
+}
+
+

Lists and Keys

+

React provides a way to render lists of elements efficiently and assigns unique keys to each item in the list for optimization.

+
const numbers = [1, 2, 3, 4, 5];
+const listItems = numbers.map((number) => <li key={number}>{number}</li>);
+
+

React utilizes several JavaScript features and concepts like arrow functions, classes, callbacks, promises, and async/await to create dynamic and interactive user interfaces. Let's explore each of these in detail and discuss how they are related and integrated in React:

+

Javascript For React:

+

Arrow functions, classes, callbacks, promises, and async/await are fundamental JavaScript concepts that are commonly used in React. Let's explore each of these topics and how they are related and integrated in React:

+

Arrow Functions:

+

Arrow functions are a concise way to write functions in JavaScript. They are commonly used in React for defining components and functions, as they have a more compact syntax compared to traditional function expressions. Arrow functions capture the this value of the enclosing context automatically, making them suitable for working within React components and event handlers.

+

Example of an arrow function defining a React component:

+
const MyComponent = () => {
+  return <div>Hello, World!</div>;
+};
+
+

Classes:

+

Classes in JavaScript are used to define and create objects with methods and properties. In React, components are often defined as classes, especially when they need to manage component state and lifecycle methods. React class components extend the React.Component class and can have methods like render, componentDidMount, and more for handling component behavior.

+

Example of a React class component:

+
class MyComponent extends React.Component {
+  render() {
+    return <div>Hello, World!</div>;
+  }
+}
+
+

**Note on functional versus class-based components**

+

When React was first created, class-based components were the standard. But functional components were introduced later, and they eclipse class-based components in every way.

+

Our advice: Ironically, you should probably never use class-based components!

+

Stick to functional components. They are more modern and more versatile.

+

Lots of tutorial content online still uses class-based components. If you stumble upon a tutorial or explanation that uses a class-based component, and you're new to React, please search for a functional-component alternative instead!

+

Callbacks:

+

Callbacks are functions that are passed as arguments to other functions and are executed at a later time or in response to an event. React uses callbacks extensively, especially in event handling. For example, you can pass callback functions to event handlers to respond to user interactions.

+

Example of a callback function for handling a button click:

+
function handleClick() {
+  console.log('Button clicked');
+}
+
+<button onClick={handleClick}>Click me</button>
+
+

Promises:

+

Promises are a way to handle asynchronous operations in JavaScript. They represent a value that might be available now, or in the future, or never. Promises have three states: pending, fulfilled, and rejected.

+
    +
  • +

    Creating Promises: +You can create a promise using the Promise constructor. It takes a function with two arguments: resolve and reject. You typically perform an asynchronous operation in this function and call resolve when the operation is successful or reject when it fails.

    +
    const myPromise = new Promise((resolve, reject) => {
    +  // Asynchronous operation
    +  if (operationSucceeded) {
    +    resolve(result);
    +  } else {
    +    reject(error);
    +  }
    +});
    +
    +
  • +
  • +

    Chaining Promises: +Promises can be chained together using .then() and .catch() to handle the resolved value or errors. This chaining allows you to compose complex asynchronous operations.

    +
    myPromise
    +  .then((result) => {
    +    // Handle success
    +  })
    +  .catch((error) => {
    +    // Handle error
    +  });
    +
    +
  • +
+

async/await:

+

async and await are modern JavaScript features for working with asynchronous code. They make asynchronous code more readable and maintainable.

+
    +
  • +

    async Function: +An async function is a function that always returns a promise. It allows you to use the await keyword inside the function to pause execution until the promise is resolved.

    +
    async function fetchData() {
    +  const data = await fetch('https://api.example.com/data');
    +  return data.json();
    +}
    +
    +
  • +
  • +

    await Keyword: +The await keyword can only be used inside an async function. It pauses the execution of the function until the promise is resolved, and it returns the resolved value.

    +
    const result = await myPromise;
    +// The code here will not execute until myPromise is resolved.
    +
    +
  • +
+

Promises and Aysnc/Await Integration in React:

+

React applications often involve asynchronous operations, such as fetching data from APIs or making network requests. Promises, async/await, and React's lifecycle methods can be integrated for managing asynchronous tasks effectively:

+
    +
  • +

    Fetching Data: +You can use async/await to fetch data in React components. Typically, you do this inside componentDidMount() or within functional components using the useEffect hook.

    +
    async componentDidMount() {
    +  try {
    +    const response = await fetch('https://api.example.com/data');
    +    const data = await response.json();
    +    this.setState({ data });
    +  } catch (error) {
    +    console.error('Error fetching data:', error);
    +  }
    +}
    +
    +
  • +
  • +

    Updating Component State: +Once the data is fetched, you can update the component state to trigger a re-render with the new data.

    +
  • +
  • +

    Handling Errors: +Use try/catch to handle errors gracefully. You can also integrate error boundaries in React to catch errors in the component tree.

    +
  • +
  • +

    Using Promises: +React works well with Promises, and you can use .then() and .catch() to manage asynchronous operations. However, async/await is often preferred for its more readable and synchronous-like syntax.

    +
  • +
+

Integrating Promises and async/await in React allows you to manage asynchronous operations in a clean and structured way, providing a better user experience by preventing UI blocking during data retrieval.

+

More React:

+

Events in React

+

Event Handling

+

In React, events are used to capture and respond to user interactions, such as clicks, input changes, and mouse movements. Event handling in React is similar to handling events in traditional HTML, but there are some differences due to React's synthetic event system.

+

In React, you define event handlers as functions and attach them to JSX elements using event attributes. Here's an example of how you might handle a click event in React:

+
function Button() {
+  function handleClick() {
+    console.log('Button clicked');
+  }
+
+  return <button onClick={handleClick}>Click me</button>;
+}
+
+

The onClick attribute specifies the event handler function, handleClick, which will be executed when the button is clicked. React's synthetic event system provides a consistent API for handling events across different browsers.

+

Event Object

+

In React, event handlers are passed an event object as an argument. This object contains information about the event, such as the type of event, target element, and any event-specific data. You can access event properties and methods within your event handler functions.

+
function handleChange(event) {
+  console.log('Input value:', event.target.value);
+}
+
+

Higher Order Components (HOCs) in React

+

What Are HOCs?

+

Higher Order Components are a design pattern in React that allows you to reuse component logic by wrapping one or more components with a higher-order component. HOCs are not a part of the React API; they are a pattern that leverages the composability of components.

+

How HOCs Work

+

HOCs are functions that take a component and return a new enhanced component. They can add props, modify behavior, or encapsulate certain functionality. For example, you might create an HOC that provides authentication, access control, or data fetching capabilities to a component.

+

Here's a simplified example of a higher order component that provides a "loading" indicator to a component:

+
function withLoadingIndicator(WrappedComponent) {
+  return function WithLoadingIndicator(props) {
+    if (props.isLoading) {
+      return <div>Loading...</div>;
+    }
+    return <WrappedComponent {...props} />;
+  };
+}
+
+

Using HOCs

+

You can use an HOC by wrapping your component with it. For instance, suppose you have a component called MyComponent, and you want to add a loading indicator using the withLoadingIndicator HOC:

+
const MyComponentWithLoading = withLoadingIndicator(MyComponent);
+
+

Now, MyComponentWithLoading is a new component that includes the loading indicator logic from the HOC. You can render it as you would with any other component.

+
<MyComponentWithLoading isLoading={true} />
+
+

Benefits of HOCs

+

HOCs enable you to separate concerns and promote reusability. They help you avoid code duplication by encapsulating common functionality in a separate function. This makes your code more maintainable and flexible, allowing you to compose and extend component behavior as needed.

+

Relationship Between Events and HOCs

+

Events and HOCs can work together in a React application. For instance, you might create an HOC that handles common event-related logic, such as tracking user interactions, and then wrap components that need that behavior. This can help centralize event handling logic and make it reusable across multiple components. Additionally, you can pass event handling functions as props when composing components with HOCs, allowing for flexible customization of event behavior.

+

In summary, events in React are essential for capturing and responding to user interactions, while Higher Order Components are a design pattern that promotes reusability and composability of component logic. You can use HOCs to encapsulate and extend event-related logic, making it easier to manage event handling across your React application.

+

Props vs. State

+

Props and state are two fundamental concepts in React, and they play distinct roles in how components work.

+

Props

+

Props (short for properties) are a mechanism for passing data from a parent component to a child component. Props are read-only, meaning that the child component cannot modify the props it receives. They are used to customize or configure child components based on data from their parent.

+

Example of using props:

+
function Greeting(props) {
+  return <div>Hello, {props.name}</div>;
+}
+
+

State

+

State is a way to store and manage data that can change over time within a component. State is used to make components dynamic and interactive. Unlike props, state is mutable, and components can change their internal state using the setState method. State is often used for data that the component needs to keep track of, such as user input or UI state.

+

Example of using state:

+
class Counter extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = { count: 0 };
+  }
+
+  render() {
+    return (
+      <div>
+        <p>Count: {this.state.count}</p>
+        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
+          Increment
+        </button>
+      </div>
+    );
+  }
+}
+
+

How They Relate and Are Integrated

+

Props and state are often used together to create dynamic and interactive React applications. Here's how they relate and are integrated:

+
    +
  1. +

    Passing Data: Props are used to pass data from a parent component to its child components. This data can be initial data that a child component uses to render itself.

    +
  2. +
  3. +

    Updating Data: State is used to manage data that can change within a component. Components can have state and use it to keep track of user interactions, input, or changes in data.

    +
  4. +
  5. +

    Reactivity: When a parent component passes props to a child component, any changes to those props in the parent will re-render the child. This allows for dynamic updates.

    +
  6. +
  7. +

    State Management: State is local to the component that owns it, and changes in state trigger re-renders of that component, updating the UI as needed.

    +
  8. +
  9. +

    Lifting State: Sometimes, you might need to manage state at a higher level in the component tree and pass it down as props to child components. This is called "lifting state up."

    +
  10. +
+

In summary, props are for passing data from parent to child, while state is for managing data that can change within a component. Together, they enable you to build interactive and data-driven React applications. Hooks, especially the useState hook, make it easier to manage local state in functional components, further enhancing the capabilities of React functional components.

+

Hooks in Functional Components

+

React introduced Hooks in version 16.8 as a way to add state and side-effects to functional components, which were previously limited to stateless rendering.

+

In React, "stateless rendering" refers to the practice of creating functional components (also known as stateless functional components) that are purely responsible for rendering UI based on the input data provided through props. These components do not manage or maintain any internal state.

+

Out with the old in with the new KING, hooks allow you to reuse stateful logic and side-effects across components, making functional components more powerful and flexible.

+

Some of the most commonly used hooks include:

+

1. useState

+

This one might sound familiar from above, useState hook allows functional components to manage local state. It takes an initial state value and returns an array with the current state and a function to update it.

+
import React, { useState } from 'react';
+
+function Counter() {
+  const [count, setCount] = useState(0);
+
+  return (
+    <div>
+      <p>Count: {count}</p>
+      <button onClick={() => setCount(count + 1)}>Increment</button>
+    </div>
+  );
+}
+
+

2. useEffect

+

The useEffect hook enables you to perform side-effects in functional components. It takes a function that will be executed after every render, and you can specify dependencies to control when the effect should run.

+
import React, { useEffect, useState } from 'react';
+
+function Example() {
+  const [data, setData] = useState([]);
+
+  useEffect(() => {
+    // Fetch data from an API and update the state
+    fetchData().then((result) => setData(result));
+  }, []); // Empty dependency array runs the effect only once
+}
+
+

3. Other Built-in Hooks

+

React provides several other built-in hooks, such as useContext and useReducer, which allow you to manage context, state transitions, and references in functional components, respectively.

+
    +
  • useContext: Allows you to access the context API within functional components. It's useful for sharing data across the component tree without prop drilling.
  • +
+
import React, { useContext } from 'react';
+
+const ThemeContext = React.createContext('light');
+
+function ThemedButton() {
+  const theme = useContext(ThemeContext);
+  return <button className={theme}>Themed Button</button>;
+}
+
+
    +
  • useReducer: This hook is used for more complex state management and state transitions. It's similar to setState but offers more control over how state updates occur.
  • +
+
import React, { useReducer } from 'react';
+
+const initialState = { count: 0 };
+
+function counterReducer(state, action) {
+  switch (action.type) {
+    case 'increment':
+      return { count: state.count + 1 };
+    case 'decrement':
+      return { count: state.count - 1 };
+    default:
+      return state;
+  }
+}
+
+function Counter() {
+  const [state, dispatch] = useReducer(counterReducer, initialState);
+
+  return (
+    <div>
+      <p>Count: {state.count}</p>
+      <button onClick={() => dispatch({ type: 'increment' })}> Increment</button>
+      <button onClick={() => dispatch({ type: 'decrement' })}> Decrement</button>
+    </div>
+  );
+}
+
+

4. Custom Hooks

+

You can create your own custom hooks to encapsulate and share component logic across different components. Custom hooks promote code reuse and maintainability.

+
// Custom hook for handling form input state
+import { useState } from 'react';
+
+function useFormInput(initialValue) {
+  const [value, setValue] = useState(initialValue);
+
+  const handleChange = (e) => {
+    setValue(e.target.value);
+  };
+
+  return {
+    value,
+    onChange: handleChange,
+  };
+}
+
+

In summary, hooks in React are a way to manage state and side-effects in functional components. They integrate seamlessly with functional components, making it easier to write and maintain complex logic and enabling better code reuse. React's built-in hooks and the ability to create custom hooks provide a powerful toolset for building dynamic and interactive applications.

+

Great Resources(videos): https://www.youtube.com/watch?v=Jl4q2cccwf0&ab_channel=TheNetNinja

+
    +
  1. useState: https://www.youtube.com/watch?v=4qVNaohzDWU&ab_channel=LogRocket
  2. +
  3. useEffect:https://www.youtube.com/watch?v=gv9ugDJ1ynU&ab_channel=TheNetNinja
  4. +
  5. useRef: https://www.youtube.com/watch?v=yCS2m01bQ6w&ab_channel=Codevolution
  6. +
  7. useCallback: https://www.youtube.com/watch?v=-Ls48dd-vJE&ab_channel=BenAwad
  8. +
+

React Ecosystem

+

Calling APIs

+

Calling APIs is a key part of any React App. It's what enables your app to communicate with the outside world - including, presumably, your backend.

+

Here's a helpful tutorial on the best practices for calling APIs in React:

+

https://www.youtube.com/watch?v=bYFYF2GnMy8

+

There's also a part 2:

+

https://www.youtube.com/watch?v=1tfd6ANaNRY

+

The best ways to fetch data are using the popular package Axos (https://www.npmjs.com/package/axios) or the vanilla JS _fetch _function (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)

+

Once you have parsed the data, you'll probably want to store it in your state somehow (using useState or a redux store).

+

It is also good practice to encapsulate your entire API call into a custom hook, and name the hook according to what it does (ex. useFetchPokemonStats). This is also much easier to do if you use a state-management system like Redux, which is described below.

+

The methods described above let you call an API immediately upon rendering a certain component. But what happens if you want to manually trigger an API call (ex. after a certain action or event)?

+

Your API call should still use useEffect, and should look mostly like the calls you learned about in Part 1. The 1 difference is you need to guard the useEffect wisely in its dependency array.

+

As you recall, the dependency array of a useEffect contains everything that the useEffect depends upon - if any of its dependencies change, it will have a _side effect _of rerunning the useEffect.

+

So, you can define a specific variable which only changes when you want your API call to run. You can put that variable in the dependency array of the useEffect. When the action or event that you want to trigger the API call occurs, you should change the trigger variable. This change will trigger the useEffect to run. The trigger variable should never change except when you want the useEffect to run.

+

I personally like making my trigger variable an object which also contains any subvariables that my API call needs. So for example, if I was coding a call to a search API that included a text query and target price, my trigger object would contain those.

+

Here is an example of a very basic React application that calls an API to perform a search with a custom hook and a useEffect guarded by a trigger object as described above: https://github.com/Tech-Start-UCalgary/react-api-examples/tree/main/js-no-redux

+

useSWR

+

alt_text

+

useSWR is a useful React hook for data fetching published by Vercel (creators of Next.js).

+

SWR stands for stale-while-revalidate. It allows for smart data fetching and encapsulates a lot of advanced fetching logic (like how often should you refetch? should you have a cache?) in a single line of code.

+

You should read more about useSWR here:

+

https://swr.vercel.app/

+

You can watch a video tutorial here:

+

https://www.youtube.com/watch?v=f7yjEdXgGiM

+

React Router

+

React Router is a popular library used for routing in React applications. Routing is the process of determining which UI components should be displayed based on the current URL or path. React Router helps you create single-page applications with multiple views and navigate between them without requiring full page reloads.

+

Here's an elaboration on React Router and its integration with React:

+

React Router Features:

+
    +
  1. +

    Declarative Routing: React Router uses a declarative approach, where you define the routes and their corresponding components in a clear and organized manner. You specify what component should be rendered when a particular URL is matched.

    +
  2. +
  3. +

    Nested Routing: React Router supports nested routes, allowing you to create complex and hierarchical UI structures. This is especially useful for building multi-level menus or complex application layouts.

    +
  4. +
  5. +

    Route Parameters: You can define route parameters in your routes, allowing you to extract dynamic data from the URL. For example, a route like /users/:id can capture the id as a parameter.

    +
  6. +
  7. +

    Programmatic Navigation: React Router provides a set of functions for programmatic navigation. You can change the route, push to the browser's history, or replace the current route using these functions. This is useful for actions like form submissions or after successful authentication.

    +
  8. +
  9. +

    Route Guards: React Router allows you to implement route guards for protecting routes based on user authentication or other conditions. This ensures that users can only access certain routes if they meet specific criteria.

    +
  10. +
+

Integration with React:

+

React Router is typically integrated into a React application as a separate library. Here's how it's commonly done:

+
    +
  1. +

    Installation: You start by installing React Router as a package in your React project. You can use either react-router-dom (for web applications) or react-router-native (for mobile applications).

    +
    npm install react-router-dom
    +
    +
  2. +
  3. +

    Router Component: You wrap your entire application (or a part of it) with a <BrowserRouter> or <HashRouter> component provided by React Router. This component manages the application's navigation state and listens to changes in the URL.

    +
    import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
    +
    +function App() {
    +  return (
    +    <Router>
    +      {/* Define your routes here */}
    +    </Router>
    +  );
    +}
    +
    +
  4. +
  5. +

    Route Configuration: Inside the <Router>, you define your routes using the <Route> component. Each <Route> component specifies a path and the component to render when the path matches.

    +
    <Route path="/home" component={Home} />
    +<Route path="/about" component={About} />
    +
    +
  6. +
  7. +

    Route Navigation: To navigate between routes, you use the <Link> component to create links or the history object to programmatically navigate.

    +
    <Link to="/home">Home</Link>
    +// OR
    +history.push('/home');
    +
    +
  8. +
  9. +

    Route Parameters: You can use route parameters to capture dynamic values from the URL. These parameters are accessible as props in the routed components.

    +
    <Route path="/user/:id" component={UserProfile} />
    +
    +
  10. +
  11. +

    Nested Routes: You can nest routes by defining routes within the components rendered by other routes. This allows for hierarchical routing structures.

    +
    <Route path="/dashboard" component={Dashboard}>
    +  <Route path="/dashboard/profile" component={Profile} />
    +</Route>
    +
    +
  12. +
+

By integrating React Router into your React application, you can create well-organized, client-side routing that provides a seamless and efficient user experience for navigating different parts of your application.

+

React with Redux

+

Redux is a widely used state container for javascript apps. As soon as your app reaches any level of data complexity, it makes a ton of sense to start using Redux to manage your state.

+

A fair warning: Redux will seem complicated at the beginning. That's completely expected! Push through that initial discomfort and you'll get used to it in no time :)

+

Here is a great introductory video to React-Redux:

+

https://www.youtube.com/watch?v=CVpUuw9XSjY

+

I highly recommend using **createSlice to setup your Redux Store. **It is a simple way to encapsulate creating actions and slicers in a simple, easy-to-read, easy-to-understand way. Here is a short video that does a great job explaining how to use createSlice:

+

https://www.youtube.com/watch?v=e0MEtFaQTZk

+

To access your Redux state and update your Redux state in React, I highly recommend using the twin hooks **useSelector **and useDispatch respectively. They are simple, easy, and elegant.

+

https://www.youtube.com/watch?v=3zoIigieur0

+

Lastly, Next.JS

+

Next.js is a framework built on top of React, designed to simplify and enhance the development of web applications. It provides several features and benefits while seamlessly integrating with React. Let's explore these aspects interactively:

+

Q1: What is Next.js?

+

Next.js is a framework for building web applications that are built on top of the React library. It simplifies many aspects of React development and adds capabilities for server-side rendering, routing, and more.

+

Q2: How does Next.js relate to React?

+

Next.js is an extension of React. It leverages React's component-based structure and allows you to build React applications while providing additional tools and features for server-side rendering, routing, and other optimizations.

+

Q3: What are some key features of Next.js?

+

Next.js offers several key features:

+
    +
  • +

    Server-Side Rendering (SSR): Next.js enables server-side rendering, which improves performance and SEO by rendering pages on the server before sending them to the client.

    +
  • +
  • +

    Routing: It includes a built-in routing system, so you can easily define and navigate between pages.

    +
  • +
  • +

    File-Based Routing: Routes are created based on the file structure, making it intuitive and easy to organize your application.

    +
  • +
  • +

    Automatic Code Splitting: It automatically splits your JavaScript code into smaller, more manageable chunks, optimizing loading times.

    +
  • +
  • +

    Static Site Generation (SSG): Next.js allows you to generate static HTML files at build time for even better performance and SEO.

    +
  • +
+

Q4: How do you create a new Next.js app?

+

To create a new Next.js app, you can use the following commands:

+
npx create-next-app my-nextjs-app
+cd my-nextjs-app
+npm run dev
+
+

This will set up a new Next.js application and start the development server.

+

Q5: Can you explain the pages and routing in Next.js?

+

In Next.js, you create pages by simply adding files to the pages directory. Each file becomes a route. For example, if you create pages/about.js, you will have a route at /about.

+

Q6: How does Next.js handle data fetching?

+

Next.js allows you to fetch data during server-side rendering using the getServerSideProps function. This data can be injected into your React components as props.

+
export async function getServerSideProps() {
+  // Fetch data from an API or database
+  const data = await fetchData();
+
+  return {
+    props: { data },
+  };
+}
+
+

Q7: What's the advantage of server-side rendering in Next.js?

+

Server-side rendering in Next.js improves the initial loading speed of your application and helps with search engine optimization (SEO). It also ensures that users see content more quickly.

+

Q8: How can I build a static website with Next.js?

+

Next.js provides static site generation (SSG) via the getStaticProps function. You can generate static HTML files for your pages at build time.

+
export async function getStaticProps() {
+  // Fetch data from an API or database
+  const data = await fetchData();
+
+  return {
+    props: { data },
+  };
+}
+
+

Q9: Are there any limitations or trade-offs with Next.js?

+

While Next.js offers many advantages, it may introduce complexity to smaller projects. It requires server-side rendering, which might not be necessary for all applications.

+

Q10: Can I deploy Next.js applications to various hosting platforms?

+

Yes, you can deploy Next.js applications to a wide range of hosting platforms, including Vercel, Netlify, and AWS. These platforms often provide built-in support for Next.js, making deployment straightforward.

+

Next.js is a powerful tool that enhances React applications by providing features like server-side rendering, routing, and automatic code splitting. It simplifies the development process and improves performance. If you have more specific questions or need further information about Next.js, feel free to ask!

+
+
+
+

Tech Start's React Native Guide

+

Please get acquainted with our React Guide before you read this page, this is just a recommendation though. Transitioning from a good background in React to React Native is a relatively smooth process, as many concepts carry over. However, there are specific topics and components you should learn to effectively work with React Native. Here's an outline of the topics you need to cover:

+
    +
  1. +

    Video Resources (If you don't Like Reading)

    +
  2. +
  3. +

    React Native Basics Main Concepts

    + +
  4. +
  5. +

    Navigation

    +
  6. +
  7. +

    Platform-Specific Code

    +
  8. +
  9. +

    Accessing Device Features

    +
  10. +
  11. +

    Native Modules and Bridges

    +
  12. +
  13. +

    State Management

    +
  14. +
  15. +

    Async Storage

    +
  16. +
  17. +

    Network Requests

    +
  18. +
  19. +

    Advanced Topics;

    + +
  20. +
  21. +

    Third-Party Integration

    +
  22. +
  23. +

    Security

    +
  24. +
  25. +

    conclusion

    +
  26. +
+

Video Resources:

+

These tutorials should be sufficient to get started but this guide gives many more subtle topics that are not covered in these videos. Choose your weapon wisely.

+
    +
  • https://www.youtube.com/playlist?list=PL4cUxeGkcC9ixPU-QkScoRBVxtPPzVjrQ
  • +
  • https://www.youtube.com/watch?v=0-S5a0eXPoc
  • +
+

React Native Basics:

+

Components in React Native

+

Components in React Native are similar to those in React, but with some variations and additional elements. Here's a more detailed breakdown:

+

1. Core Components:

+

React Native provides a set of core components that are similar to HTML elements. These include:

+
    +
  • View: The fundamental component for creating UI layouts.
  • +
  • Text: Used for displaying text.
  • +
  • Image: For displaying images.
  • +
  • ScrollView: For scrollable content.
  • +
  • TextInput: For text input fields.
  • +
  • And many more.
  • +
+

2. Custom Components:

+

You can create your custom components just like in React. These components can be stateless functional components or class components. To create a custom component, use the View, Text, Image, and other core components to compose your UI.

+

Styling in React Native

+

Styling in React Native is different from traditional web development. You have various options for styling your components:

+

a. Inline Styles:

+

React Native supports inline styles using JavaScript objects. You can apply styles directly to components, like this:

+
<View style={{ flex: 1, backgroundColor: 'lightblue' }}>
+  <Text style={{ fontSize: 20, color: 'black' }}>Hello, React Native!</Text>
+</View>
+
+

b. Stylesheets:

+

Using stylesheets, you can create reusable style definitions:

+
const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+    backgroundColor: 'lightblue',
+  },
+  text: {
+    fontSize: 20,
+    color: 'black',
+  },
+});
+
+<View style={styles.container}>
+  <Text style={styles.text}>Hello, React Native!</Text>
+</View>
+
+

c. Flexbox Layout:

+

React Native relies heavily on flexbox for layout design. It's similar to CSS flexbox but with a few differences. You can use properties like flex, alignItems, and justifyContent to control layout.

+
<View style={{ flex: 1, flexDirection: 'column', justifyContent: 'center', alignItems: 'center' }}>
+  <Text>Hello, React Native!</Text>
+</View>
+
+

Layout in React Native

+

Understanding layout is vital in React Native to create responsive and visually appealing designs.

+
    +
  1. +

    Flexbox Layout: Flexbox is the primary layout system in React Native. It allows you to design flexible and adaptive layouts. Key properties include:

    +
      +
    • flex: Determines how space is distributed among children.
    • +
    • alignItems: Aligns items along the cross-axis (vertical alignment).
    • +
    • justifyContent: Aligns items along the main axis (horizontal alignment).
    • +
    • flexDirection: Sets the direction of the main axis.
    • +
    +
  2. +
  3. +

    Positioning: You can control the position of elements using properties like position, top, left, right, and bottom.

    +
  4. +
  5. +

    Dimensions: Set dimensions using width and height. You can use percentages, fixed values, or dynamic values like flex.

    +
  6. +
  7. +

    Responsive Design: React Native allows you to create responsive designs using Dimensions and the onLayout event.

    +
  8. +
  9. +

    Orientation Handling: Handle changes in device orientation by adjusting your layout accordingly. Use the Dimensions API to detect changes.

    +
  10. +
  11. +

    Stylesheet Composition: Compose styles using stylesheets and conditionally apply styles based on screen dimensions or other criteria.

    +
  12. +
  13. +

    Best Practices:

    +
      +
    • +

      Separation of Concerns: Keep styles, logic, and presentation separate for better maintainability and code clarity.

      +
    • +
    • +

      Optimizing Styles: Optimize styles to reduce unnecessary re-renders and improve app performance.

      +
    • +
    +
  14. +
+

By mastering these concepts related to components, styling, and layout in React Native, you can create rich and visually appealing mobile app user interfaces. Flexbox, in particular, is a powerful tool for creating flexible layouts, and understanding the nuances of styling is crucial for developing a professional-looking app.

+ +

Navigation is a crucial aspect of building mobile applications with React Native. It involves creating the structure and flow of your app, allowing users to move between different screens or views. The most common library for implementing navigation in React Native is React Navigation. Here's a more detailed overview of navigation in React Native:

+

1. Installing React Navigation:

+
    +
  • To get started with React Navigation, you need to install it in your project using npm or yarn: +
    npm install @react-navigation/native @react-navigation/stack
    +
    +
  • +
+

2. Stack Navigator:

+
    +
  • The Stack Navigator is one of the most commonly used navigators in React Navigation. It allows you to create a stack of screens where each screen is placed on top of the previous one. You can navigate between screens by pushing and popping them from the stack.
  • +
  • To set up a Stack Navigator, you need to import it and define your screens. +
    import { createStackNavigator } from '@react-navigation/stack';
    +
    +const Stack = createStackNavigator();
    +
    +
  • +
+

3. Defining Screens:

+
    +
  • Each screen in your app is defined as a React component. For example, you might have a HomeScreen and a ProfileScreen. +
    function HomeScreen() {
    +  // Your screen's content
    +}
    +
    +function ProfileScreen() {
    +  // Your screen's content
    +}
    +
    +
  • +
+

4. Navigating Between Screens:

+
    +
  • You can navigate between screens using navigation functions provided by React Navigation. For example, to navigate from the HomeScreen to the ProfileScreen: +
    import { NavigationContainer } from '@react-navigation/native';
    +import { createStackNavigator } from '@react-navigation/stack';
    +
    +const Stack = createStackNavigator();
    +
    +function App() {
    +    return (
    +        <NavigationContainer>
    +        <Stack.Navigator>
    +            <Stack.Screen name="Home" component={HomeScreen} />
    +            <Stack.Screen name="Profile" component={ProfileScreen} />
    +        </Stack.Navigator>
    +        </NavigationContainer>
    +    );
    +}
    +
    +In your HomeScreen component, you can use navigation.navigate('Profile') to navigate to the ProfileScreen.
  • +
+

5. Passing Data Between Screens:

+
    +
  • You can pass data from one screen to another using parameters. For example, you can send a user's ID to the ProfileScreen: +
    // In HomeScreen
    +navigation.navigate('Profile', { userId: 123 });
    +
    +// In ProfileScreen
    +const userId = route.params.userId;
    +
    +
  • +
+

6. Drawer Navigation and Tab Navigation:

+
    +
  • React Navigation also supports Drawer and Tab navigations. The Drawer Navigator creates a sidebar menu for navigation, while the Tab Navigator allows you to switch between different tabs within an app.
  • +
+

7. Nested Navigation:

+

React Navigation allows you to nest navigators within each other, creating complex navigation structures. This can be useful when you have a tab navigator and want to use a stack navigator within one of the tabs, or if you want to combine different types of navigators for more intricate navigation patterns.

+

Here's an example of nesting a Stack Navigator within a Tab Navigator:

+
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import { createStackNavigator } from '@react-navigation/stack';
+
+const Tab = createBottomTabNavigator();
+const Stack = createStackNavigator();
+
+// Define a tab navigator with a stack navigator in one of the tabs
+function TabNavigator() {
+  return (
+    <Tab.Navigator>
+      <Tab.Screen name="Tab1" component={Tab1Component} />
+      <Tab.Screen name="Tab2" component={Tab2Component} />
+      <Tab.Screen name="Tab3" component={StackScreen} />
+    </Tab.Navigator>
+  );
+}
+
+// Define a stack navigator to use within a tab
+function StackScreen() {
+  return (
+    <Stack.Navigator>
+      <Stack.Screen name="StackScreen1" component={StackScreen1Component} />
+      <Stack.Screen name="StackScreen2" component={StackScreen2Component} />
+    </Stack.Navigator>
+  );
+}
+
+

8. Navigation Lifecycle:

+

React Navigation provides navigation lifecycle events that allow you to perform actions when a screen comes into view or goes out of view. Common lifecycle events include:

+
    +
  • focus: Triggered when a screen comes into focus.
  • +
  • blur: Triggered when a screen loses focus.
  • +
  • didFocus: Triggered after the screen has come into focus.
  • +
+

You can add listeners to these events to perform actions or fetch data when a screen is in focus.

+
import { useFocusEffect } from '@react-navigation/native';
+
+function MyScreen({ navigation }) {
+  // Add a focus event listener
+  useFocusEffect(
+    React.useCallback(() => {
+      // Perform actions when the screen comes into focus
+      console.log('Screen is in focus');
+      // You can also fetch data or make API calls here
+    }, [])
+  );
+
+  // ... rest of the screen component
+}
+
+

9. Screen Options:

+

You can customize the appearance and behavior of each screen's navigation using the options property in your screen component. This allows you to set options like the screen title, header style, and more.

+
function MyScreen({ route, navigation }) {
+  // Define screen-specific options
+  React.useLayoutEffect(() => {
+    navigation.setOptions({
+      title: 'Custom Title',
+      headerStyle: {
+        backgroundColor: 'blue',
+      },
+      headerTintColor: 'white',
+    });
+  }, [navigation]);
+
+  // ... rest of the screen component
+}
+
+

10. Navigation Methods:

+

React Navigation provides a set of methods that allow you to navigate between screens programmatically. Common methods include:

+
    +
  • navigate: Navigate to a new screen in the same stack.
  • +
  • push: Push a new screen onto the stack.
  • +
  • pop: Pop the current screen from the stack.
  • +
  • goBack: Navigate back to the previous screen.
  • +
+

These methods are accessible through the navigation prop in your screen components.

+
function MyScreen({ navigation }) {
+  return (
+    <View>
+      <Button title="Go to Screen2" onPress={() => navigation.navigate('Screen2')} />
+      <Button title="Push Screen3" onPress={() => navigation.push('Screen3')} />
+      <Button title="Go Back" onPress={() => navigation.goBack()} />
+    </View>
+  );
+}
+
+

These features offer extensive flexibility in designing complex navigation structures and allow you to respond to navigation events and customize screen-specific options. Understanding these concepts is crucial for building intuitive and feature-rich navigation in your React Native applications.

+

Platform-Specific Code:

+

Platform-specific code in React Native involves writing code that is specific to either iOS or Android platforms. This is sometimes necessary when you want to implement platform-specific features, handle platform-specific behaviors, or optimize your app for a particular platform. Here's a more detailed overview of this topic:

+

1. Platform-Specific Components and Styling:

+
    +
  • +

    React Native allows you to conditionally render components or apply styles based on the platform. For example, you can use the Platform.OS property to determine the platform:

    +
    import { View, Text } from 'react-native';
    +import { Platform } from 'react-native';
    +
    +const MyComponent = () => (
    +  <View>
    +    <Text>Common Text</Text>
    +    {Platform.OS === 'ios' && <Text>iOS only Text</Text>}
    +    {Platform.OS === 'android' && <Text>Android only Text</Text>}
    +  </View>
    +);
    +
    +
  • +
  • +

    Similarly, you can conditionally apply styles:

    +
    import { StyleSheet } from 'react-native';
    +
    +const styles = StyleSheet.create({
    +  commonStyle: {
    +    // Common styles
    +  },
    +  iosStyle: {
    +    // iOS-specific styles
    +  },
    +  androidStyle: {
    +    // Android-specific styles
    +  },
    +});
    +
    +const MyComponent = () => (
    +  <View>
    +    <Text style={[styles.commonStyle, Platform.OS === 'ios' ? styles.iosStyle : styles.androidStyle]}>
    +      Platform-specific styling
    +    </Text>
    +  </View>
    +);
    +
    +
  • +
+

2. Platform-Specific Modules:

+
    +
  • +

    In some cases, you might need to use platform-specific modules or APIs. React Native provides a way to do this using the .ios.js and .android.js file extensions. For example, you can have separate implementations for iOS and Android as follows:

    +
      +
    • MyModule.ios.js for iOS-specific code.
    • +
    • MyModule.android.js for Android-specific code.
    • +
    +
  • +
  • +

    React Native will automatically pick the right file based on the platform. This is useful when dealing with platform-specific features or APIs.

    +
  • +
+

3. Conditional Logic:

+
    +
  • +

    You can use conditional logic to handle platform-specific behaviors. For instance, you might need to request permissions differently on iOS and Android or use platform-specific libraries.

    +
    import { PermissionsAndroid, Platform } from 'react-native';
    +
    +async function requestLocationPermission() {
    +  if (Platform.OS === 'android') {
    +    // Android-specific logic for requesting permissions
    +    try {
    +      const granted = await PermissionsAndroid.request(
    +        PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
    +      );
    +      if (granted === PermissionsAndroid.RESULTS.GRANTED) {
    +        console.log('Location permission granted.');
    +      } else {
    +        console.log('Location permission denied.');
    +      }
    +    } catch (err) {
    +      console.warn(err);
    +    }
    +  } else if (Platform.OS === 'ios') {
    +    // iOS-specific logic for requesting permissions
    +    // ...
    +  }
    +}
    +
    +
  • +
+

4. Platform-Specific Libraries:

+
    +
  • +

    There are times when you need to use platform-specific libraries or modules. React Native allows you to conditionally include these libraries based on the platform. You can use conditional require statements to achieve this:

    +
    let platformSpecificLibrary;
    +if (Platform.OS === 'ios') {
    +  platformSpecificLibrary = require('ios-specific-library');
    +} else {
    +  platformSpecificLibrary = require('android-specific-library');
    +}
    +
    +
  • +
+

5. Native Modules:

+
    +
  • For highly platform-specific tasks, you might need to write native code (Objective-C/Swift for iOS or Java/Kotlin for Android) and create native modules. These native modules can be called from your React Native code, allowing you to perform platform-specific tasks.
  • +
+

Understanding how to handle platform-specific code is important for ensuring your React Native app functions correctly and efficiently on both iOS and Android devices. By using these techniques, you can create a seamless and native-like experience for users on each platform.

+

Accessing Device Features:

+

Accessing device features in React Native involves interacting with native device functionality, such as the camera, geolocation, sensors, and more. Here, I'll provide more detail on this topic and examples of how to access specific device features:

+
    +
  1. +

    Camera:

    +
      +
    • To access the camera in React Native, you can use the react-native-camera library. This library allows you to capture photos and record videos. You can also customize the camera settings, switch between front and back cameras, and apply real-time image processing.
    • +
    • Example: +
      import { RNCamera } from 'react-native-camera';
      +
      +// In your component
      +<RNCamera
      +  type={RNCamera.Constants.Type.back}
      +  flashMode={RNCamera.Constants.FlashMode.auto}
      +/>
      +
      +
    • +
    +
  2. +
  3. +

    Geolocation:

    +
      +
    • To access the device's location, you can use the built-in Geolocation module in React Native. It provides methods for retrieving the user's current location and monitoring changes in real-time.
    • +
    • Example: +
      import Geolocation from '@react-native-community/geolocation';
      +
      +// Get the current location
      +Geolocation.getCurrentPosition((position) => {
      +  console.log(position.coords.latitude, position.coords.longitude);
      +});
      +
      +
    • +
    +
  4. +
  5. +

    Sensors:

    +
      +
    • React Native provides access to various device sensors, including the accelerometer, gyroscope, and magnetometer, through the react-native-sensors library. You can use this library to collect data from these sensors.
    • +
    • Example: +
      import { Accelerometer } from 'react-native-sensors';
      +
      +const accelerometerObservable = new Accelerometer();
      +
      +const subscription = accelerometerObservable.subscribe((data) => {
      +  console.log('Acceleration X:', data.x);
      +  console.log('Acceleration Y:', data.y);
      +  console.log('Acceleration Z:', data.z);
      +});
      +
      +
    • +
    +
  6. +
  7. +

    Contacts:

    +
      +
    • Accessing device contacts can be achieved using the react-native-contacts library. This allows you to read and write contacts to the user's address book.
    • +
    • Example: +
      import Contacts from 'react-native-contacts';
      +
      +// Fetch all contacts
      +Contacts.getAll()
      +  .then((contacts) => {
      +    console.log(contacts);
      +  })
      +  .catch((error) => {
      +    console.error(error);
      +  });
      +
      +
    • +
    +
  8. +
  9. +

    Device Information:

    +
      +
    • React Native provides device information through the react-native-device-info library. You can retrieve details like the device's manufacturer, model, unique identifier, and more.
    • +
    • Example: +
      import DeviceInfo from 'react-native-device-info';
      +
      +// Get device information
      +console.log('Device Model:', DeviceInfo.getModel());
      +console.log('Device ID:', DeviceInfo.getUniqueId());
      +
      +
    • +
    +
  10. +
  11. +

    Bluetooth and NFC:

    +
      +
    • To work with Bluetooth and NFC, you can use libraries like react-native-ble-manager and react-native-nfc-manager. These libraries enable communication with nearby devices and NFC tags.
    • +
    • Examples can get quite involved, as working with Bluetooth and NFC often requires handling various events and connections. You can refer to the library documentation for detailed examples.
    • +
    +
  12. +
+

When accessing device features in React Native, it's essential to follow the documentation and best practices for the specific libraries and modules you're using. Additionally, consider handling permissions appropriately, especially for features like camera, geolocation, and contacts, which may require user consent.

+

Native Modules and Bridges:

+

Native modules and bridges in React Native are a way to access native code (Java or Objective-C) from JavaScript and vice versa. They are essential for tasks that require platform-specific functionality or performance optimization. Let's dive into more detail and provide examples of how to create and use native modules and bridges in React Native.

+

Native Modules

+

Native modules allow you to expose native code to JavaScript in a structured manner. Here's how to create a simple native module:

+
    +
  1. +

    Create a Native Module for iOS (Objective-C):

    +

    Let's say you want to create a native module that shows a native iOS alert.

    +
    // AlertModule.h
    +#import <React/RCTBridgeModule.h>
    +
    +@interface AlertModule : NSObject <RCTBridgeModule>
    +@end
    +
    +
    // AlertModule.m
    +#import "AlertModule.h"
    +#import <React/RCTLog.h>
    +
    +@implementation AlertModule
    +
    +RCT_EXPORT_MODULE();
    +
    +RCT_EXPORT_METHOD(showAlert:(NSString *)title message:(NSString *)message)
    +{
    +    UIAlertController *alert = [UIAlertController
    +        alertControllerWithTitle:title
    +        message:message
    +        preferredStyle:UIAlertControllerStyleAlert];
    +
    +    UIAlertAction *ok = [UIAlertAction
    +        actionWithTitle:@"OK"
    +        style:UIAlertActionStyleDefault
    +        handler:nil];
    +
    +    [alert addAction:ok];
    +    
    +    UIViewController *rootViewController = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
    +    [rootViewController presentViewController:alert animated:YES completion:nil];
    +}
    +
    +@end
    +
    +
  2. +
  3. +

    Create a Native Module for Android (Java):

    +

    To do the same thing in Android, create a native module to show an alert dialog.

    +
    // AlertModule.java
    +import com.facebook.react.bridge.ReactApplicationContext;
    +import com.facebook.react.bridge.ReactContextBaseJavaModule;
    +import com.facebook.react.bridge.ReactMethod;
    +
    +public class AlertModule extends ReactContextBaseJavaModule {
    +    public AlertModule(ReactApplicationContext reactContext) {
    +        super(reactContext);
    +    }
    +
    +    @Override
    +    public String getName() {
    +        return "AlertModule";
    +    }
    +
    +    @ReactMethod
    +    public void showAlert(String title, String message) {
    +        AlertDialog.Builder builder = new AlertDialog.Builder(getCurrentActivity());
    +        builder.setTitle(title);
    +        builder.setMessage(message);
    +        builder.setPositiveButton("OK", null);
    +        builder.show();
    +    }
    +}
    +
    +
  4. +
  5. +

    Using Native Modules in JavaScript:

    +

    In your JavaScript code, you can now use the native module you created:

    +
    import { NativeModules } from 'react-native';
    +
    +// For iOS
    +NativeModules.AlertModule.showAlert('Hello', 'This is an alert!');
    +
    +// For Android
    +NativeModules.AlertModule.showAlert('Hello', 'This is an alert!');
    +
    +
  6. +
+

Native Bridges

+

Bridges in React Native are responsible for connecting JavaScript and native code. React Native's native modules use bridges to enable communication between the two sides. In the examples above, the React Native framework handles the bridge for you.

+

Behind the scenes, React Native's bridge system serializes and deserializes data and manages the communication between JavaScript and native modules. It abstracts away many of the complexities, making it easier for developers to work with native modules in a JavaScript-friendly way.

+

By using native modules and bridges, you can incorporate platform-specific functionality into your React Native app while maintaining a unified JavaScript codebase. This is particularly helpful when you need to integrate with device-specific features, third-party libraries, or optimize performance.

+

Here are some tutorials that dive super in depth for creating a calender native module for Android or IOS.

+

State Management:

+

let's dive into more detail on state management in React Native and provide examples. State management is crucial for handling the data and UI state in your mobile applications. There are various options for managing state in React Native, similar to React for the web, including React's built-in state management, the Context API, and external libraries like Redux or MobX. Below, we'll cover these options and provide examples for better understanding:

+

1. React's Built-in State Management:

+

React Native, like React, allows you to manage state locally within a component using the useState hook.

+

Example:

+
import React, { useState } from 'react';
+import { View, Text, Button } from 'react-native';
+
+function Counter() {
+  const [count, setCount] = useState(0);
+
+  const increment = () => setCount(count + 1);
+  const decrement = () => setCount(count - 1);
+
+  return (
+    <View>
+      <Text>Count: {count}</Text>
+      <Button title="Increment" onPress={increment} />
+      <Button title="Decrement" onPress={decrement} />
+    </View>
+  );
+}
+
+

In this example, the useState hook is used to manage the count state variable within the Counter component.

+

2. Context API:

+

The Context API allows you to manage global state that can be accessed by multiple components without having to pass props down through the component tree.

+

Example:

+
import React, { createContext, useContext, useState } from 'react';
+import { View, Text, Button } from 'react-native';
+
+const CountContext = createContext();
+
+function Counter() {
+  const [count, setCount] = useContext(CountContext);
+
+  const increment = () => setCount(count + 1);
+  const decrement = () => setCount(count - 1);
+
+  return (
+    <View>
+      <Text>Count: {count}</Text>
+      <Button title="Increment" onPress={increment} />
+      <Button title="Decrement" onPress={decrement} />
+    </View>
+  );
+}
+
+function App() {
+  const [count, setCount] = useState(0);
+
+  return (
+    <CountContext.Provider value={[count, setCount]}>
+      <View>
+        <Text>My App</Text>
+        <Counter />
+      </View>
+    </CountContext.Provider>
+  );
+}
+
+

In this example, the CountContext is created and used to share the count state between the Counter component and the App component.

+

3. Redux:

+

Redux is a popular external state management library for React Native. It provides a central store for managing application state and allows for predictable state updates using actions and reducers.

+

Example:

+

To use Redux in React Native, you need to set up a store, actions, and reducers. Here's a simplified example:

+
// Define actions
+const increment = () => ({ type: 'INCREMENT' });
+const decrement = () => ({ type: 'DECREMENT' });
+
+// Define a reducer
+const counterReducer = (state = 0, action) => {
+  switch (action.type) {
+    case 'INCREMENT':
+      return state + 1;
+    case 'DECREMENT':
+      return state - 1;
+    default:
+      return state;
+  }
+};
+
+// Create the Redux store
+import { createStore } from 'redux';
+const store = createStore(counterReducer);
+
+// Connect components to the store
+import { connect } from 'react-redux';
+
+function Counter({ count, increment, decrement }) {
+  return (
+    <View>
+      <Text>Count: {count}</Text>
+      <Button title="Increment" onPress={increment} />
+      <Button title="Decrement" onPress={decrement} />
+    </View>
+  );
+}
+
+const mapStateToProps = (state) => ({ count: state });
+const mapDispatchToProps = { increment, decrement };
+
+const ConnectedCounter = connect(mapStateToProps, mapDispatchToProps)(Counter);
+
+

This example demonstrates a basic setup of Redux in React Native. It involves defining actions, a reducer, creating the store, and connecting a component to the store.

+

The choice of state management in your React Native project depends on the complexity and scalability of your application. React's built-in state management and the Context API are great for simple state needs, while Redux or MobX are more suitable for larger, complex applications with extensive state management requirements.

+

Async Storage:

+

AsyncStorage is a crucial concept in React Native, allowing you to store data locally on the user's device. It's similar to the localStorage in web development but tailored for mobile applications. AsyncStorage is often used to store user preferences, app settings, or any data that needs to persist across app sessions. Here, I'll dive into more detail about AsyncStorage and provide some examples.

+

Using AsyncStorage in React Native

+
    +
  1. +

    Importing AsyncStorage: +To use AsyncStorage, you need to import it from 'react-native':

    +
    import { AsyncStorage } from 'react-native';
    +
    +
  2. +
  3. +

    Storing Data: +You can store data in AsyncStorage by using the setItem method. Here's an example of how to store a simple string:

    +
    AsyncStorage.setItem('username', 'JohnDoe')
    +  .then(() => {
    +    console.log('Data stored successfully');
    +  })
    +  .catch((error) => {
    +    console.error('Error storing data: ', error);
    +  });
    +
    +
  4. +
  5. +

    Retrieving Data: +To retrieve data, you can use the getItem method:

    +
    AsyncStorage.getItem('username')
    +  .then((value) => {
    +    if (value !== null) {
    +      console.log('Retrieved data: ', value);
    +    } else {
    +      console.log('Data not found');
    +    }
    +  })
    +  .catch((error) => {
    +    console.error('Error retrieving data: ', error);
    +  });
    +
    +
  6. +
  7. +

    Updating Data: +You can update stored data by simply setting a new value for the same key:

    +
    AsyncStorage.setItem('username', 'NewUsername')
    +  .then(() => {
    +    console.log('Data updated successfully');
    +  })
    +  .catch((error) => {
    +    console.error('Error updating data: ', error);
    +  });
    +
    +
  8. +
  9. +

    Deleting Data: +To remove data from AsyncStorage, use the removeItem method:

    +
    AsyncStorage.removeItem('username')
    +  .then(() => {
    +    console.log('Data removed successfully');
    +  })
    +  .catch((error) => {
    +    console.error('Error removing data: ', error);
    +  });
    +
    +
  10. +
  11. +

    Handling Errors: +It's essential to handle errors, as reading from or writing to AsyncStorage may fail due to various reasons, such as storage limitations or permissions. Always use try...catch or promise-based error handling to ensure your app gracefully handles errors.

    +
  12. +
  13. +

    Working with JSON Data: +AsyncStorage stores data as strings, so if you need to store complex data structures like objects or arrays, you should serialize them to JSON when storing and parse them when retrieving:

    +
    const user = {
    +  name: 'John Doe',
    +  email: 'john@example.com',
    +};
    +
    +AsyncStorage.setItem('user', JSON.stringify(user))
    +  .then(() => {
    +    console.log('User data stored successfully');
    +  })
    +  .catch((error) => {
    +    console.error('Error storing user data: ', error);
    +  });
    +
    +// Retrieving and parsing the user data
    +AsyncStorage.getItem('user')
    +  .then((value) => {
    +    if (value !== null) {
    +      const userData = JSON.parse(value);
    +      console.log('Retrieved user data: ', userData);
    +    } else {
    +      console.log('User data not found');
    +    }
    +  })
    +  .catch((error) => {
    +    console.error('Error retrieving user data: ', error);
    +  });
    +
    +
  14. +
+

Remember that AsyncStorage is a simple key-value store and should be used for relatively small amounts of data. For larger datasets, consider using a more robust storage solution or a database. Additionally, be mindful of security considerations when storing sensitive information and ensure that you have the necessary permissions to access AsyncStorage on the user's device.

+

Network Requests:

+

Making network requests in React Native is a common task when you need to fetch data from an API or send data to a server. You can use libraries like Axios or the built-in fetch API to perform these requests. Here, I'll dive into more detail about how to make network requests in React Native using both Axios and fetch, and provide examples for each:

+

Using Axios

+

Axios is a popular library for making HTTP requests. You can use it in your React Native project by following these steps:

+
    +
  1. +

    Installation:

    +

    First, you need to install Axios in your project. You can do this with npm or yarn:

    +
    npm install axios
    +# or
    +yarn add axios
    +
    +
  2. +
  3. +

    Making a GET Request:

    +

    Here's an example of making a GET request to a remote API using Axios:

    +
    import axios from 'axios';
    +
    +const fetchUserData = async () => {
    +  try {
    +    const response = await axios.get('https://api.example.com/users');
    +    const userData = response.data;
    +    console.log(userData);
    +  } catch (error) {
    +    console.error('Error fetching user data:', error);
    +  }
    +};
    +
    +// Call the function to fetch user data
    +fetchUserData();
    +
    +
  4. +
  5. +

    Making a POST Request:

    +

    To make a POST request with Axios, you can do the following:

    +
    import axios from 'axios';
    +
    +const sendDataToServer = async (data) => {
    +  try {
    +    const response = await axios.post('https://api.example.com/postData', data);
    +    console.log('Data sent successfully:', response.data);
    +  } catch (error) {
    +    console.error('Error sending data:', error);
    +  }
    +};
    +
    +const dataToSend = {
    +  key1: 'value1',
    +  key2: 'value2',
    +};
    +
    +// Call the function to send data to the server
    +sendDataToServer(dataToSend);
    +
    +
  6. +
+

Using the fetch API

+

The fetch API is a built-in way to make network requests in JavaScript and is available in React Native:

+
    +
  1. +

    Making a GET Request:

    +

    Here's an example of making a GET request using the fetch API:

    +
    const fetchUserData = () => {
    +  fetch('https://api.example.com/users')
    +    .then((response) => {
    +      if (!response.ok) {
    +        throw new Error('Network response was not ok');
    +      }
    +      return response.json();
    +    })
    +    .then((userData) => {
    +      console.log(userData);
    +    })
    +    .catch((error) => {
    +      console.error('Error fetching user data:', error);
    +    });
    +};
    +
    +// Call the function to fetch user data
    +fetchUserData();
    +
    +
  2. +
  3. +

    Making a POST Request:

    +

    Making a POST request with fetch involves a similar structure:

    +
    const sendDataToServer = (data) => {
    +  fetch('https://api.example.com/postData', {
    +    method: 'POST',
    +    headers: {
    +      'Content-Type': 'application/json',
    +    },
    +    body: JSON.stringify(data),
    +  })
    +    .then((response) => {
    +      if (!response.ok) {
    +        throw new Error('Network response was not ok');
    +      }
    +      return response.json();
    +    })
    +    .then((responseData) => {
    +      console.log('Data sent successfully:', responseData);
    +    })
    +    .catch((error) => {
    +      console.error('Error sending data:', error);
    +    });
    +};
    +
    +const dataToSend = {
    +  key1: 'value1',
    +  key2: 'value2',
    +};
    +
    +// Call the function to send data to the server
    +sendDataToServer(dataToSend);
    +
    +
  4. +
+

Both Axios and the fetch API allow you to make various types of requests (GET, POST, PUT, DELETE, etc.) and handle responses. The choice between the two often comes down to personal preference and specific project requirements. Axios is a popular choice due to its simplicity and ease of use for handling requests and responses.

+

Advanced Topics

+

Debugging and Troubleshooting:

+
    +
  • Familiarize yourself with debugging tools, error messages, and common troubleshooting techniques specific to React Native.
  • +
  • RESOURCE: https://reactnative.dev/docs/debugging
  • +
+

Testing:

+
    +
  • Learn how to write unit tests and integration tests for your React Native components using testing frameworks like Jest.
  • +
  • RESOURCE: https://reactnative.dev/docs/testing-overview
  • +
+

Performance Optimization:

+
    +
  • Explore techniques for optimizing the performance of your app, including reducing renders and optimizing images.
  • +
  • RESOURCE: https://reactnative.dev/docs/performance
  • +
+

Publishing and Deployment:

+
    +
  • Understand how to build, sign, and deploy your app to the Google Play Store and Apple App Store.
  • +
  • IOS RESOURCE: https://reactnative.dev/docs/publishing-to-app-store
  • +
  • ANDROID RESOURCE: https://reactnative.dev/docs/signed-apk-android
  • +
+

Third-Party Integrations:

+

Third-party integrations in React Native are crucial for adding functionality and features to your app without having to build everything from scratch. Here, I'll provide more detail on some common third-party integrations in React Native along with links to the relevant libraries:

+
    +
  1. +

    Push Notifications:

    +
      +
    • Implementing push notifications is essential for engaging users. Libraries like react-native-firebase or react-native-push-notification provide the tools to send and receive push notifications on both iOS and Android.
    • +
    • react-native-firebase
    • +
    • react-native-push-notification
    • +
    +
  2. +
  3. +

    Analytics:

    + +
  4. +
  5. +

    Maps and Location:

    + +
  6. +
  7. +

    Camera and Image Capture:

    + +
  8. +
  9. +

    Social Media Sharing:

    +
      +
    • To enable users to share content on social media platforms, libraries like react-native-share provide sharing functionality with support for various services.
    • +
    • react-native-share
    • +
    +
  10. +
  11. +

    Payment Gateways:

    + +
  12. +
  13. +

    Authentication:

    +
      +
    • Implementing user authentication is a common requirement. Libraries like react-native-firebase/auth and react-native-auth0 offer easy integration with Firebase Authentication and Auth0, respectively.
    • +
    • react-native-firebase/auth
    • +
    • react-native-auth0
    • +
    +
  14. +
  15. +

    In-App Messaging:

    +
      +
    • If your app needs real-time chat or messaging features, libraries like react-native-gifted-chat can be used to quickly add chat functionality.
    • +
    • react-native-gifted-chat
    • +
    +
  16. +
  17. +

    Audio and Video Playback:

    + +
  18. +
  19. +

    AR/VR Integration:

    + +
  20. +
+

When integrating third-party libraries, make sure to check their documentation for installation and usage instructions, as well as any specific requirements or configurations. Carefully consider your app's requirements and select the libraries that best meet your needs while ensuring they are well-maintained and compatible with your React Native version.

+

Security Best Practices:

+

Security is a critical aspect of any mobile app, including those built with React Native. Here are some security best practices in React Native, along with examples:

+
    +
  1. +

    Secure Storage:

    +
      +
    • Use secure storage mechanisms to store sensitive data, such as user authentication tokens and API keys. Avoid storing them in plain text or insecure locations.
    • +
    +

    Example:

    +
    // Insecure storage
    +const apiKey = 'my-insecure-api-key';
    +
    +// Secure storage using a library like react-native-secure-storage
    +import SecureStorage from 'react-native-secure-storage';
    +
    +SecureStorage.set('api_key', 'my-secure-api-key');
    +
    +
  2. +
  3. +

    API Key Management:

    +
      +
    • Avoid hardcoding API keys directly in your source code. Instead, use environment variables or configuration files that are excluded from source control.
    • +
    +

    Example:

    +
    // Insecure API key storage
    +const apiKey = 'my-insecure-api-key';
    +
    +// Secure API key storage using environment variables
    +const apiKey = process.env.REACT_NATIVE_API_KEY;
    +
    +
  4. +
  5. +

    Authentication and Authorization:

    +
      +
    • Implement secure authentication and authorization mechanisms to protect user data and control access to sensitive parts of your app.
    • +
    +

    Example:

    +
    // Use a secure authentication library like Firebase Authentication or Auth0
    +import { Firebase } from 'react-native-firebase';
    +
    +// Ensure that only authenticated users can access certain features
    +if (user.isAuthenticated) {
    +  // Display sensitive data or allow certain actions
    +}
    +
    +
  6. +
  7. +

    Network Security:

    +
      +
    • Use HTTPS for all network requests to encrypt data in transit. Avoid sending sensitive information via unencrypted HTTP.
    • +
    +

    Example:

    +
    // Use HTTPS for network requests
    +fetch('https://api.example.com/data', {
    +  method: 'GET',
    +  headers: {
    +    'Content-Type': 'application/json',
    +    'Authorization': 'Bearer ' + user.token,
    +  },
    +})
    +
    +
  8. +
  9. +

    Code Obfuscation:

    +
      +
    • Obfuscate your JavaScript code to make it more difficult for malicious actors to reverse engineer your app. Obfuscation is typically done using third-party tools, and the specific steps and tools used may vary depending on the project.
    • +
    +
  10. +
  11. +

    Secure Communication with Native Modules:

    +
      +
    • When communicating with native modules, validate and sanitize data to prevent injection attacks.
    • +
    +

    Example:

    +
    import { NativeModules } from 'react-native';
    +
    +// Ensure the data passed to a native module is properly sanitized
    +const userInput = 'user-input-data';
    +NativeModules.MyModule.someMethod(validateInput(userInput));
    +
    +
  12. +
  13. +

    Input Validation:

    +
      +
    • Validate user input to prevent common security issues like SQL injection and cross-site scripting (XSS).
    • +
    +

    Example:

    +
    // Validate and sanitize user input to prevent XSS
    +const userInput = '<script>alert("XSS attack");</script>';
    +const sanitizedInput = sanitizeInput(userInput);
    +
    +
  14. +
  15. +

    Error Handling:

    +
      +
    • Implement proper error handling to prevent sensitive information from being exposed to users in error messages.
    • +
    +

    Example:

    +
    // Handle errors gracefully and do not expose sensitive information to the user
    +try {
    +  // Code that may throw an error
    +} catch (error) {
    +  console.error('An error occurred. Please try again later.');
    +}
    +
    +
  16. +
+

These are essential security best practices for React Native apps, but it's important to note that the specific implementation details may vary depending on your project and the libraries you use. Regularly staying informed about security developments in the React Native ecosystem and taking proactive measures to address vulnerabilities will help ensure the security of your app.

+

Conclusion:

+

This guide was meant to be a starting/middle point for learning React Native across its many topics, ranging from front-end to back-end(mainly back-end because that is what really matters, am I right!). Jokes aside, as you progress through these topics, you'll find that your React experience serves as a strong foundation for learning React Native. React Native allows you to leverage your JavaScript skills to build mobile apps for both iOS and Android, making it a valuable addition to your toolkit.

+
+
+
+

Tech Start's Super Awesome Mega Web Dev Guide:)

+

Want to get into web dev? This guide should be your best friend. It covers some of the basic tools and languages you'll need to dive into the world of web development. Rather than providing tutorials, this guide focuses on directing you towards the best free online content to teach you the fundamentals.

+

Our advice:

+
    +
  • Go through at your own pace! You may need to spend more or less time on a particular topic depending on your experience level.
  • +
  • Build practice websites and apps as you learn - you learn by doing.
  • +
  • Take your own notes, especially for problems you encounter frequently
  • +
  • Go beyond this guide! Tons of resources, courses, and tutorials are out there if you want to learn. Remember: google is a programmer's best friend.
  • +
+

This guide was originally developed for Tech Start UCalgary, an undergraduate club for software development and entrepreneurship at the University of Calgary. Check us out here -----> https://linktr.ee/techstartuofc <-----

+

Or at our website here ---> https://techstartucalgary.com <-----

+

If you're interested in contributing to this guide or in building similar guides for other areas (like Git, project management, or mobile development), please send me an email at joel.happ1@ucalgary.ca

+

Good luck on your web dev journey and enjoy the guide!

+

Part 1 - HTML

+

HTML is the building block of all webpages. It's ubiquitous throughout application design - everything from websites to mobile apps to desktop apps use HTML as the base for their frontend.

+

alt_text

+

Luckily for you, HTML is also very simple. Don't spend too much time learning it as a beginner - while more advanced HTML concepts do exist, all you need to get started is a basic understanding of how it works.

+

To get started, I recommend watching this video and experimenting by building your own HTML document alongside it: https://www.youtube.com/watch?v=UB1O30fR-EE

+

To generate a favicon for your site, use this site: https://realfavicongenerator.net/

+

No matter which text editor you use (Atom, VSCode, Sublime Text, or something else), I recommend searching for editor plugins to improve your experience writing HTML. Google is your friend here.

+

Part 2 - CSS

+

If HTML is the backbone of frontends, CSS is the paint. It's an extremely versatile and powerful way of styling and beautifying your content. CSS is easy to get into, but very difficult to master- if front-end development interests you, I recommend dedicating a significant amount of time towards learning CSS.

+

alt_text

+

To get started, check out this 1 hour introductory video to CSS:

+

https://www.youtube.com/watch?v=yfoY53QXEnI

+

Another alternative is this free course on Scrimba, which also covers HTML: https://scrimba.com/learn/htmlcss

+

One topic that isn't covered in much detail in the previous video is CSS selectors. For most purposes, you'll probably want to keep your selectors simple (using only class names the vast majority of the time). If you want to learn more about advanced selectors, check out this video: https://www.youtube.com/watch?v=Bcr70LIJcOk

+

When working on projects with other people, I recommend avoiding element-level selectors, as they can easily screw with work that others are doing.

+

Once you have a good grasp of the basics of CSS, one area that I highly recommend learning is CSS Grid. CSS Grid is a fantastic way of organizing and positioning html content, and it comes with loads of features that make it easy to build adaptive web pages. By combining CSS Grid with CSS breakpoints, you can design interfaces that look great on any size of screen, whether it's a big desktop computer or a small mobile phone.

+

Highly recommended course for CSS Grid: https://scrimba.com/learn/cssgrid

+

(Warning: CSS grid is not supported by some outdated browsers and browsers like Opera Mini which are used mostly in third world countries to save data. If your intended audience includes these people, do not use CSS Grid.)

+

How should you organize and refactor your CSS? I recommend using the BEM strategy for your CSS selectors. https://css-tricks.com/bem-101/

+

BEM is a particularly helpful methodology to adopt when you're building websites from components like in React, since you can keep the CSS for each component in a separate file. However, it's far from the only strategy for CSS organization, so you can research and adopt others if they suit your needs better.

+

Knowing CSS Flexbox is also helpful for arranging the layouts of websites. It's like

+

Finally, here is a great video to watch for some simple, powerful tips for writing modern CSS:

+

https://www.youtube.com/watch?v=Qhaz36TZG5Y

+

+

Part 3 - Javascript

+

JavaScript drives the interactivity and functionality of websites. Using it, you can respond to the user's interactions on your website and you can modify the properties of your HTML dynamically.

+

alt_text

+

To get started with JavaScript, you can watch this playlist: https://www.youtube.com/playlist?list=PLDyQo7g0_nsX8_gZAB8KD1lL4j4halQBJ

+

If you're brand new to programming, you should spend more time learning the fundamentals of JavaScript.

+

There are a few areas of JavaScript which may be confusing to any newcomers to the language, even if you have previously learned other languages. I recommend practicing and studying to get used to these features.

+

Array functions: https://www.youtube.com/watch?v=rRgD1yVwIvE

+

_Asynchronous JavaScript (Await, Promises, Callbacks): _https://www.youtube.com/watch?v=_8gHHBlbziw

+

_JSON (JavaScript object notation): _https://www.youtube.com/watch?v=wI1CWzNtE-M

+

If you encounter another area of JavaScript that gives you troubles let me know and I'll add a section to this guide.

+

3.1 Node.js

+

alt_text

+

Here's an introduction to Node.js: JavaScript, but for your operating system instead of your browser. https://www.youtube.com/watch?v=ENrzD9HAZK4 Node.js is frequently used as the backend for the server side of an application or web app.

+

Installing Node.js

+

We recommend using NVM (node version manager) to install node.js. It allows you to install, uninstall, and switch between different versions of node.js very quickly. Often, you'll need to switch between different versions of node for different projects, so you'll save time by using nvm from the start.

+

NVM (Mac/Linux): https://github.com/nvm-sh/nvm

+

NVM for windows: https://github.com/coreybutler/nvm-windows

+

Once installed, you can type "nvm" in your CLI to see a red list of commands you can use. Follow instructions on GitHub for proper usage!

+

Express

+

One of the most common Node.js frameworks is Express. Express is an unopinionated_ (meaning, it doesn't force you to do things any particular way) _framework that excels at allowing you to write APIs. We may include more content on Express here in the future.

+

alt_text

+

+

3.2** TypeScript**

+

TypeScript is a superset of Javascript that introduces new features mostly related to strong typing: this lets you safeguard your variables and functions and helps you catch the most frequent mistakes and bugs from JavaScript code.

+

alt_text

+

TypeScript is contained in .ts files, and using a compiler you can compile it into vanilla JavaScript .js files which run as expected on a computer. If you anticipate doing a lot of work with JavaScript, I highly recommend learning TypeScript - although it isn't necessary for every project, it immensely improves the quality of the coding experience and it can guide you towards mastering tricky concepts from JavaScript like promises and callbacks.

+

TypeScript tutorial by NetNinja:

+

https://www.youtube.com/playlist?list=PL4cUxeGkcC9gUgr39Q_yD6v-bSyMwKPUI

+

TypeScript Basics by JavaBrains: (also includes small project incl. API usage)

+

https://www.youtube.com/playlist?list=PLqq-6Pq4lTTanfgsbnFzfWUhhAz3tIezU

+

+

Part 4 - React

+

NOTE: here is a more indepth React Guide, the better version!!

+

HTML, CSS, and JS are great and all, but what if you want to make a modern, reactive website? Several frontend frameworks exist to empower dynamic, reactive sites, and as of 2021 React is by far the most popular among them. It's a great way to get an introduction into the world of web frameworks and it's a fun tool to use.

+

alt_text

+

Here's a good free overview of the basics of React: https://scrimba.com/learn/learnreact

+

Plenty of similar courses are available on YouTube and other course platforms.

+

When in doubt, consult the React documentation: https://reactjs.org/docs/

+

Note that much of the documentation still uses class-based components, as opposed to function-based components. Nowadays, it is 99% preferable to use function-based components whenever possible. It cuts down on the amount of boilerplate you need to write and enables helpful features from hooks.

+

Learn more about React Hooks: https://www.youtube.com/watch?v=TNhaISOUy6Q

+

The 2 hooks in particular you should be very familiar with:

+
    +
  • **useState - **for basic state/data management
  • +
  • useEffect - ubiquitous in React. It is used for creating consequences ("effects") for changes in data. It's a critical part of designing React applications to have a functional (not object-oriented) architecture, and you should be using it to create custom hooks.
  • +
+

Other hooks that are handy to know about are useRef, useCallback, and useLayoutEffect.

+

To learn React, you should know HTML, CSS, and JS before. You can also build React apps with TypeScript instead of JavaScript. https://www.typescriptlang.org/docs/handbook/react.html

+

React Context API

+

The context API is a tool you can use in React to share state from an upper level component (a provider) to its children. If you have state that needs to be shared across many children, you can use the context API rather than pass everything down manually as props.

+

To learn about the context API, I recommend watching this video:

+

https://www.youtube.com/watch?v=35lXWvCuM8o

+

**React Router **

+

If you want to make React websites with multiple pages, you can use React Router. It is a package that enables your app to have multiple routes. This series gives a quick overview of React Router:

+

https://www.youtube.com/watch?v=aZGzwEjZrXc&list=PL4cUxeGkcC9gZD-Tvwfod2gaISzfRiP9d&index=21

+

React Router is lightweight and best suited for very small projects. If you plan on building a larger website with React, we recommend using Next.js instead - it has a lot more features including pre-rendering pages on the server for SEO optimization. Next.js is also widely used and has industry-level support.

+

alt_text

+

React Redux is a commonly used package for managing global state. It allows you to take care of state in a global store that can be accessed or modified from anywhere in your application.

+

https://www.youtube.com/watch?v=CVpUuw9XSjY

+

Using React with Typescript

+

Here is a great cheatsheet that you should read to get started with using React in combination with Typescript:

+

https://github.com/typescript-cheatsheets/react

+

That's it! .. for now :)

+

Happy hacking!

+

UI/UX Design Guide

+

Welcome to Tech Start’s UI/UX design guide, your roadmap to mastering the art of crafting user-friendly and visually appealing digital experiences!

+

Our goal is simple: to provide you with the tools and guidance necessary to understand the principles of effective design and apply them to your projects. Instead of overwhelming you with tutorials, we've curated a selection of online resources that cover everything from the basics to advanced techniques.

+

While this guide is a good starting point, there's a ton of resources available online. Everyone learns differently, so we encourage you to explore and find what methods work best for you!

+

Enjoy the guide and have fun designing! :)

+
+

Table of Contents

+ +
+

Design Process

+

Purpose: a design process helps you break down a project into manageable chunks and gives your work structure.

+

Terms like “design thinking” and “human-centered design” all boil down to the idea of understanding the needs and behaviors of users, and translating that understanding into a well-designed interface. So, keep the user front and center in your design approach!

+

There’s various design processes out there but we recommend using the double diamond design process.

+

The double diamond design process has 4 stages:

+
    +
  1. Discover
  2. +
  3. Define
  4. +
  5. Develop
  6. +
  7. Deliver
  8. +
+

Note: this design process is not linear— it’s iterative. That means you may be revisiting certain stages to tweak and improve your designs as you work through the process.

+

alt_text

+
+

We recommend taking a look at the following resources to get started:

+ +
+

Tasks to do at each stage/ Methods to use

+

As you make your way through the design process there’s various tasks/ methods you may use at each stage.

+

Discover phase:

+
    +
  • Competitive analysis
  • +
  • User research
  • +
+

Define phase(at this stage you’ll be synthesizing your user research findings):

+
    +
  • Affinity mapping
  • +
  • Empathy mapping
  • +
  • Form a problem statement and How Might We (HMW) questions
  • +
  • Ideate potential solutions
  • +
  • Product Requirement Doc (PRD)
  • +
+

Note: to make your work easier, use FigJam templates to do the tasks for this phase.

+

Here’s some great FigJam Templates:

+ +

Develop phase:

+
    +
  • User flows & site maps
  • +
  • Wireframes & low-fidelity prototypes
  • +
  • User testing prototypes and iterating on your designs based on user feedback
  • +
+

Here’s some great FigJam Templates:

+ +

Deliver phase:

+
    +
  • High-fidelity prototypes (in Figma)
  • +
+

Below are some great resources to get you started with the tasks/ methods:

+ +
+

User Research

+

Purpose: user research is conducted to understand user needs and preferences— it’ll ensure that your designs are intuitive and meet user expectations.

+

User research happens throughout the design process and there’s different methods you can use at each stage. Some user research methods provide qualitative data (like user interviews) and others may provide more quantitative data (like close-ended surveys). Choosing which research method to use depends on various things like time availability, your research goals, type of product you’re building, etc.

+

alt_text

+

We recommend starting with simple methods such as surveys and user interviews.

+

Best practices to keep in mind for your research questions:

+
    +
  • Keep it short (5-10 questions)
  • +
  • Keep it simple (use clear and concise language)
  • +
  • Avoid leading questions
  • +
+

Best practices to keep in mind for user interviews:

+
    +
  • Use active listing techniques (build rapport with the participant, ask relevant follow-up questions)
  • +
  • Record & transcribe your interviews
  • +
+

Here’s an example of what a good survey question may look like:

+
    +
  • What problems do you face while trying to do [task]? (select all that apply)
  • +
+

Here’s some examples of what good user interview questions may look like:

+
    +
  • How do you currently go about doing [task]?
  • +
  • What do you like about how you currently perform [task]?
  • +
  • What is the biggest pain point when performing [task]?
  • +
+

Below are some great resources to get started with user research:

+ +
+

Usability Testing

+

Purpose: usability testing will identify and address any usability issues— it’ll ensure your designs are intuitive and easy to use for its intended audience.

+

Once you have a working prototype, you’ll want to test that with users to get feedback on your designs.

+

With your usability testing, focus on exploratory tasks where you give users a realistic scenario and tasks to perform. For example, you could ask the user “add an item to your cart”, or “find an event to attend”. You want to see if (and where) users may get stuck doing a task— this will let you know which part of your design needs more work.

+

NOTE: testing with at least 5 users will give you sufficient feedback on your designs (these users can be fellow students, etc.)

+

Resources to get your started:

+ +
+

Working in Figma

+

Purpose: use Figma to create your low and high fidelity prototypes that you can share with your team.

+

Figma's official website offers a ton of learning resources to guide you on your Figma learning journey!

+

alt_text

+

An important consideration as you work on your designs is to share your Figma file with your team members to get feedback on the technical feasibility of your designs.

+

Resources to get started with Figma:

+ +
+

Knowing how to use various things in Figma like: components, auto layout, and grids will help you design more efficiently.

+
+

Using Components

+

“Components are elements you can reuse across your designs. They help to create and manage consistent designs across projects.” - Figma

+

alt_text

+

Here’s a great resource to get your stated:

+ +
+

Using Auto Layout

+

Auto layout is important for creating responsive interfaces. “It lets you create designs that grow to fill or shrink to fit, and reflow as their contents change” - Figma

+

Resources for learning auto layout:

+ +
+

Using Grids

+

Using grids will provide visual structure to your designs. They’ll make your designs look clean & organized.

+

alt_text

+

Here’s a good rule of thumb to follow for designing layouts for different screen sizes:

+
    +
  • For desktops - 12 columns
  • +
  • For tablets - 8 columns
  • +
  • For mobile devices - 4 columns
  • +
+

Resources to learn more:

+ +
+

Other Resources

+

There’s various Figma plugins, UI kits, and other resources you can use to make your workflow easier.

+

What you use will depend on your needs & project— so feel free to find ones suited for you!

+

Here’s an example of a plugin for Figma:

+ +

Figma community is also a great resource for finding templates, plugins and UI kits.

+

Also, for a more comprehensive guide on design methods, take a look at this article.

+
+

Other Design Considerations

+

Where to Look for Inspiration

+

You might want to look at existing user interfaces to get inspiration for your own project. We recommend the following resources:

+
    +
  • Dribbble
  • +
  • Behance
  • +
  • Scope existing platforms that are similar to your app that have good UI/UX & take inspo from their designs
  • +
+
+

Design Documentation

+

It’s essential to document your designs. It’ll help you communicate the specifics of your designs with your team members and others.

+

Below is a good example of a card that documents the design of a screen. Your major screens and user flows should be documented.

+

alt_text

+
+

Accessibility and Inclusion in Design

+

Here’s something important to keep in mind as you design. You want to ensure that everyone can use your designs— regardless of their abilities.

+

That means using colors, typography, etc. that are accessible to all users.

+

Here’s a great article to get started: Accessibility Guidelines for UX Designers

+
+

That’s all for now! :)

+

Dealing With Conflict

+

Conflict resolution is the process of resolving differences +and disputes between individuals, groups, +or parties through peaceful means. +It involves identifying and addressing the underlying causes of the conflict, +promoting communication and understanding, cooperation, +and finding a mutually acceptable solution, +leading to increased productivity +and satisfaction in personal and professional settings. +When done correctly, +it helps to manage and resolve differences and disputes effectively, +preventing them from escalating into larger and more destructive problems.

+

The following document enumerates the trade-offs +of all conflict management styles, +and I highly encourage you to read it.

+

https://www.valamis.com/hub/conflict-management-styles.

+

Lastly, remember that conflict is not a bad thing. +Instead, learn how to manage it and make the most out of it.

+
+

"If you want to go fast, go alone; if you want to go far, go together."

+
+

CSS

+

Is only recommended to learn CSS after you are familiar with HTML.

+

Fundamentals

+

MDN is all you'll need. +Read it from beginning to end: +https://developer.mozilla.org/en-US/docs/Web/CSS.

+

Particularly, focus on:

+
    +
  1. The basic syntax, common attributes (color, font, border) +and basic selectors.
  2. +
  3. The Box Model.
  4. +
  5. CSS Layouts +(Flexbox and Grids as a minimum).
  6. +
  7. Responsive Design and media queries.
  8. +
+

Related utilities:

+ + +

Learn only after you learn the fundamentals:

+ +

Advanced

+

When you want to architect a big scope system:

+ +

Be aware of

+

But not necessarily learn them:

+ +

HTML

+

Fundamentals

+

MDN is all you'll need. +Read it from beginning to end: +https://developer.mozilla.org/en-US/docs/Learn/HTML.

+

You should focus on the basics only (a, button, h1-h6, p, span, lists, div, input, ...).

+

HTML is not more complicated than that, learn about CSS next.

+

Management Styles

+
+

A management style is the way +in which a manager works to fulfill their goals. +Management style includes the way that a manager plans, organizes, makes decisions, delegates, +and manages their staff.

+
+

All management styles are useful depending on the specific scenario, +but it's important to identify when to use which one, +since a wrong management style conduces the team to a dissatisfied, unengaged, inefficient, unmotivated, or frustrated state.

+

The following document enumerates the trade-offs +of all management styles and I highly encourage you to read it.

+

https://www.valamis.com/hub/management-styles.

+

I would just add a last tip here:

+

Understand what motivates every person on your team.

+

For instance, +remember that a team of volunteers is very different from a team of employees. +On a volunteering team, the motivation factors usually are +self-development and being part of a cause. +The key in this setup +is aligning the team's objectives +with each person's definition of meaningfulness.

+

Secrets Management

+

In this Workshop, we'll learn how to properly store the secrets +that your application's source code needs to run +like database connection strings and third-party API access credentials, +and do so even if people have access to your source code.

+

We'll be exploring three approaches used in industry, +and talking about when to use one or the other:

+
    +
  1. Git Crypt.
  2. +
  3. SOPS - My favorite.
  4. +
  5. Hashicorp's Vault.
  6. +
+

We'll also talk a little bit about the Twelve-Factor app, +particularly about factor #3: Configuration.

+

Pre-requisites

+

To be able to focus on the important aspects of this Workshop (secrets management) +and avoid distractions we'll assume you are familiar with Git +and the command line.

+

Please bring your laptop, +the idea is that we'll work together step by step on small exercises +that will teach you each of the tools.

+

Only MacOS and Linux are supported. +If you are on Windows, +please install WSL.

+

Please come to the workshop with the following tools ready to be used:

+
    +
  1. +

    A terminal where you can enter commands, set environment variables, etc.

    +
  2. +
  3. +

    Git.

    +
  4. +
  5. +

    Git Crypt:

    +

    Run $ brew install git-crypt on MacOS, +or $ apt install git-crypt or similar on Linux/WSL.

    +
  6. +
  7. +

    Sops:

    +

    Run $ brew install sops on MacOS, +or $ apt install sops or similar on Linux/WSL.

    +
  8. +
  9. +

    Age:

    +

    Run $ brew install age on MacOS, +or $ apt install age or similar on Linux/WSL.

    +
  10. +
  11. +

    Vault:

    +

    Please follow the instructions here: +https://developer.hashicorp.com/vault/downloads.

    +
  12. +
+

Why?

+

Application secrets are critical for security. +For example, if an attacker discovers the database credentials, +then immediately this attacker would gain access to all of the applications data. +Application secrets is the entrypoint for everything, they are the Keys of Heaven, +and therefore, it's very important to make sure +that only the right people can get access to those secrets.

+

In this line of making application secrets be only accessible to the right people +we also need to make sure that developers can only access development secrets. +It's very common to have at least 2 environments: Development and Production, +and to have some kind of segmentation where only super admins can access Production secrets.

+

It also doesn't matter if your source code is private, +you still want to protect your secrets because your source code may be leaked, +as it has happened in the past to companies like Twitch.

+

There is also an argument about maintainability. +Secrets are also configuration, namely, their values may change over time, +even if the source code doesn't. For this reason it's recommended to +strictly separate them from the source code.

+

Workshop Step by Step

+

Git-Crypt

+
+

https://github.com/AGWA/git-crypt

+
+

Enables you to encrypt/decrypt the parts of a git of repository.

+

The good:

+
    +
  • Versioned as code.
  • +
  • It's simple to use.
  • +
  • Great for a simple project, with no compliance needs.
  • +
+

The bad:

+
    +
  • You cannot have multiple keys. All people share the same encryption key, +which means you cannot isolate environments, +and therefore is not that useful in highly regulated industries.
  • +
  • Unencrypted secrets touch the disk, +which is not great if someone steals your laptop while unencrypted.
  • +
+

Steps:

+
    +
  1. +

    Visit https://github.com/techstartucalgary/Docs/tree/main/src/workshops/secrets-management/git-crypt/secrets.

    +

    As you can see, there are dev and prod secrets with username and password, but they are encrypted, so we cannot see them unless we have they key.

    +
  2. +
  3. +

    Download the key here

    +

    Note: This should be distributed through a secure channel (e.g. encrypted email). +For the sake of simplicity you can download it here.

    +
  4. +
  5. +

    Now we want to decrypt the secrets, for this we have to:

    +
    $ git clone https://github.com/techstartucalgary/Docs.git docs
    +$ cd docs
    +
    +docs $ cat src/workshops/secrets-management/git-crypt/secrets/dev/username
    +  <you should see gibberish>
    +
    +# Decrypt
    +docs $ git-crypt unlock /path/to/key
    +
    +# You should see the secrets now
    +docs $ cat src/workshops/secrets-management/git-crypt/secrets/dev/username
    +docs $ cat src/workshops/secrets-management/git-crypt/secrets/dev/password
    +
    +# Encrypt
    +docs $ git-crypt lock
    +docs $ cat src/workshops/secrets-management/git-crypt/secrets/dev/username
    +  <you should see gibberish again>
    +
    +
  6. +
  7. +

    The next step is understanding how it works, so essentially you configure which paths of the repository are encrypted in a .gitattributes file like this one: +https://github.com/techstartucalgary/Docs/blob/main/src/workshops/secrets-management/git-crypt/.gitattributes, +where essentially we tell git-crypt to encrypt the files under the secrets/ folder. You can check which files are encrypted with

    +
    $ git-crypt status
    +   not encrypted: src/workshops/secrets-management/README.md
    +       encrypted: src/workshops/secrets-management/git-crypt/secrets/dev/password
    +       encrypted: src/workshops/secrets-management/git-crypt/secrets/dev/username
    +       encrypted: src/workshops/secrets-management/git-crypt/secrets/prod/password
    +       encrypted: src/workshops/secrets-management/git-crypt/secrets/prod/username
    +   not encrypted: src/workshops/secrets-management/git-crypt/unsafe/key
    +
    +
  8. +
+

Sops

+
+

https://github.com/mozilla/sops

+
+

Enables you to encrypt/decrypt JSON, YAML, or whole files.

+

The good:

+
    +
  • Versioned as code.
  • +
  • You can have multiple keys and access control over a whole file, +great for highly regulated industries.
  • +
  • Keys can be connected to an AWS/GCP/Azure identity, +which is great in corporate environments, +and Age/PGP, which is great for other environments.
  • +
+

The neutral:

+
    +
  • Not that easy to use, but reasonable given the features.
  • +
+

The bad:

+
    +
  • Requires some training to get used to it.
  • +
+

Steps:

+
    +
  1. +

    Visit https://github.com/techstartucalgary/Docs/tree/main/src/workshops/secrets-management/sops.

    +

    As you can see, there are dev and prod secrets with username and password, but they are encrypted, so we cannot see them unless we have they key.

    +
  2. +
  3. +

    Download the development key +here +and the production key +here

    +

    Note: This should be distributed through a secure channel (e.g. encrypted email). +For the sake of simplicity you can download it here.

    +
  4. +
  5. +

    Now we want to decrypt the secrets, for this we have to:

    +
    $ git clone https://github.com/techstartucalgary/Docs.git docs
    +$ cd docs
    +
    +$ cd src/workshops/secrets-management/sops
    +
    +src/workshops/secrets-management/sops $ cat dev.yaml
    +  <you should see gibberish>
    +
    +src/workshops/secrets-management/sops $ cat prod.yaml
    +  <you should see gibberish>
    +
    +# Decrypt dev secrets with dev key
    +src/workshops/secrets-management/sops $ SOPS_AGE_KEY_FILE=/path/to/dev/key sops -d dev.yaml
    +
    +# Decrypt prod secrets with dev key
    +src/workshops/secrets-management/sops $ SOPS_AGE_KEY_FILE=/path/to/dev/key sops -d prod.yaml
    +   <you should see a failure, wrong key>
    +
    +# Decrypt prod secrets with prod key
    +src/workshops/secrets-management/sops $ SOPS_AGE_KEY_FILE=/path/to/prod/key sops -d prod.yaml
    +
    +
  6. +
+

Vault

+
+

https://www.hashicorp.com/products/vault

+
+

The good:

+
    +
  • Big enterprises like it. Why? Maybe marketing? I assume is because it allows for centralization, which is important if you have hundreds of teams.
  • +
+

The neutral:

+
    +
  • Very flexible.
  • +
+

The bad:

+
    +
  • Another server to maintain.
  • +
  • Not versioned as code.
  • +
  • Not free.
  • +
+
+

Note: https://vault.kamadorueda.com will be only available during the workshop. If you are following this guide after the workshop, please use your own Vault instance instead.

+
+

Steps:

+
    +
  1. +

    Login to the UI at https://vault.kamadorueda.com/ui. The token is 123.

    +
  2. +
  3. +

    Let's put and get a secret out of it

    +
    $ export VAULT_ADDR=https://vault.kamadorueda.com
    +
    +# Login. The token is: 123
    +$ vault login
    +
    +$ vault kv put secret/your-name password=your-password
    +
    +$ vault kv get -field=password secret/your-name
    +
    +
  4. +
  5. +

    It's possible to define access control lists, policies, and grant each person a different token, or login with OIDC. It's very flexible.

    +
  6. +
+

Contributing

+

Please submit bug reports, +feature requests, +or general feedback to our +Bug Tracker on GitHub.

+

Code contributions

+

The easiest way to contribute to this project +is by clicking on the button in the top right corner of any page. +This will open the corresponding page on GitHub, +where you can add or modify content +and then commit the change.

+

For more elaborate changes please:

+
    +
  1. Fork the project from: https://github.com/techstartucalgary/docs.
  2. +
  3. Follow the tutorial of mdBook, +the tool we use to build and generate this documentation.
  4. +
  5. Before you make a PR, please run markdownlint on the files you changed. I recommend using the VS Code extensions for ease of use.
  6. +
  7. Make a PR!
  8. +
+ +
    +
  1. All of the code that you submit to our code repository +will be licensed under the +Creative Commons CC0 1.0 Universal +and The Unlicense.
  2. +
  3. By submitting code to our code repository you also certify +that you agree to the following +Developer Certificate of Origin.
  4. +
+

Credits

+

Special thanks to Kevin Amado1 for writing these docs.

+
1 +

VP Development 2022. Feel free to connect with me on LinkedIn or GitHub, or read my personal website.

+
+

License

+

This project is released under either +the Creative Commons CC0 1.0 Universal license +and/or under the The Unlicense license, +at your discretion, +whose verbatim copies can be found below.

+
The Unlicense
+-------------
+
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+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 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.
+
+For more information, please refer to <https://unlicense.org>
+
+
Creative Commons Legal Code
+---------------------------
+
+CC0 1.0 Universal
+
+    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+    HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+  i. the right to reproduce, adapt, distribute, perform, display,
+     communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+     likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+     subject to the limitations in paragraph 4(a), below;
+  v. rights protecting the extraction, dissemination, use and reuse of data
+     in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+     European Parliament and of the Council of 11 March 1996 on the legal
+     protection of databases, and under any national implementation
+     thereof, including any amended or successor version of such
+     directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+     world based on applicable law or treaty, and any national
+     implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+    surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+    warranties of any kind concerning the Work, express, implied,
+    statutory or otherwise, including without limitation warranties of
+    title, merchantability, fitness for a particular purpose, non
+    infringement, or the absence of latent or other defects, accuracy, or
+    the present or absence of errors, whether or not discoverable, all to
+    the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+    that may apply to the Work or any use thereof, including without
+    limitation any person's Copyright and Related Rights in the Work.
+    Further, Affirmer disclaims responsibility for obtaining any necessary
+    consents, permissions or other rights required for any use of the
+    Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+    party to this document and has no duty or obligation with respect to
+    this CC0 or use of the Work.
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + +
+ + diff --git a/projects/demos/1/index.html b/projects/demos/1/index.html new file mode 100644 index 0000000..19ba34c --- /dev/null +++ b/projects/demos/1/index.html @@ -0,0 +1,261 @@ + + + + + + Demo 1 - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Demo & Pitch Night 1

+

30 November 2023

+

Objectives

+

Demos are intended to be a check-in of your progress so far and a way for your whole team to show off their work, as well as an opportunity to practice pitching your project to the public.

+

This will also let us understand your progress and blockers in order to help you best.

+

Since Tech Start is built off 3 pillars, development, strategy, and design, the demos will also focus on these 3 aspects. +Feel free to divide the allocated time between them as you see fit.

+

In addition, there may or may not be pizza or snacks present.

+

Time Limit: 15 minutes

+

Suggested talking points

+

These are just suggestions and not at all mandatory, but may help get you started.

+

Strategy

+
    +
  • What is your Total Market, Serviceable Market and Obtainable Market?
  • +
  • What is your Market Positioning?
  • +
  • What is your unique value?
  • +
  • Competition Analysis in terms of market, features etc.
  • +
  • Does the user research validate the business plan so far?
  • +
+

Design

+
    +
  • After doing user research and synthesizing the data, what did you learn about your users?
  • +
  • What opportunities / edge have you discovered for your product?
  • +
  • What were some challenges you faced in the user research and synthesis process and how did you overcome them (or not)?
  • +
  • How has user research driven your decision on what to include in your MVP?
  • +
+

Development

+
    +
  • What is your tech stack?
  • +
  • What do you aim to include in your MVP?
  • +
  • How much progress have you made technically?
  • +
  • What does your roadmap look like? Feel free to share your project board.
  • +
+

Milestones

+

These milestones will give you a rough idea of where you should be by the demo, they are not requirements.

+

Strategy

+
    +
  • Competition analysis complete
  • +
  • Features to be made solidified
  • +
  • Unique Value Proposition determined
  • +
+

Design

+
    +
  • User research and synthesis is complete
  • +
  • Product requirement document created (& MVP features prioritized)
  • +
  • Low fidelity prototypes started
  • +
+

Development

+
    +
  • Stack chosen
  • +
  • Cloud services decided upon (if needed)
  • +
  • Development environment set up
  • +
  • First commits made by each dev
  • +
  • Learning of new tech started
  • +
  • Roadmap created
  • +
+

Visual Aids

+

We strongly encourage putting together a presentation to help you. +Consider what you might need to show off your projects (if possible), e.g. if you're building a mobile or VR app, you may need to find a solution to show the screen on the projectors.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/projects/demos/2/index.html b/projects/demos/2/index.html new file mode 100644 index 0000000..a322407 --- /dev/null +++ b/projects/demos/2/index.html @@ -0,0 +1,277 @@ + + + + + + Demo 2 - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Demo & Pitch Night 2

+

29 February 2024

+

Objectives

+

Share your progress with the club, get feedback from industry guests, and practice your public speaking and pitching.

+

This is a pitch and demo, you are selling your product to investors.

+

Quick Info

+

Start Time: 6pm sharp

+

Time Limit: 10 minutes

+

Dress Code: Business Casual

+

What to do

+

Keep the focus on the product. +Demo your product live, if it's deployed that's even better but localhost is okay. +Have a pre-recorded demo as a backup, in case things go wrong.

+

What not to do

+

Don't show any code. +Don't talk about your challenges and wins.

+

Suggested talking points

+

These are just suggestions and not at all mandatory, but may help get you started.

+

General

+
    +
  • Talk about the problem space & your solution (create a story around it)
  • +
  • Introduce team members
  • +
  • Talk about features (MVP)
  • +
  • Roadmap of what you'll do next (adding x feature, finalizing for launch, etc.)
  • +
+

Strategy

+
    +
  • STP Analysis
  • +
  • Exploring monetization and revenue models
  • +
  • Income & Expenditure forecasts in the real world
  • +
  • Unique Value Proposition, Problem Statement & Branding (collaborate with design team)
  • +
  • Market size research, figure out Total Addressable Market, Serviceable Addressable
  • +
  • Competition Research
  • +
+

Design

+
    +
  • Create a user persona (based on your user research) to explore the problem space - (collaborate with strategists)
  • +
  • How has user research driven your decision on what to include in your MVP features? List some of the features.
  • +
  • Show your high-fidelity designs / technical demo
  • +
+

Development

+
    +
  • Quick overview of tech stack, showing off tech's best feature +
      +
    • (e.g. we're using NextJS hosted on Vercel because it lets us rapidly deploy changes to our users)
    • +
    +
  • +
  • How are you deploying your app?
  • +
  • Launch plans
  • +
  • Would you like to be on the App Store, etc?
  • +
  • Show a functional demo
  • +
+

Milestones

+

These milestones will give you a rough idea of where you should be by the demo, they are not requirements.

+

Strategy

+
    +
  • Everything money related figured out +
      +
    • business model
    • +
    • revenue forecasts
    • +
    • expenses
    • +
    +
  • +
+

Design

+
    +
  • Usability testing on prototype is complete
  • +
  • High-fidelity designs are complete
  • +
  • Final designs are handed off to development
  • +
+

Development

+
    +
  • Front-end and back-end connected
  • +
  • Deployed to cloud providers (AWS, Vercel, etc.)
  • +
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/projects/demos/3/index.html b/projects/demos/3/index.html new file mode 100644 index 0000000..bd90e61 --- /dev/null +++ b/projects/demos/3/index.html @@ -0,0 +1,205 @@ + + + + + + Demo 3 - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Demo & Pitch Night 3

+

Early April 2024

+

Coming soon...

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/projects/demos/index.html b/projects/demos/index.html new file mode 100644 index 0000000..6dab73f --- /dev/null +++ b/projects/demos/index.html @@ -0,0 +1,225 @@ + + + + + + Demos - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Demo & Pitch Nights

+

All Tech Start UCalgary projects are showcased to the world +at the end of each academic year. +At this event, people from different industries and backgrounds +come and give us feedback on the projects.

+

This is also a great opportunity for you as a professional and us +as a club to connect and network with different companies.

+

It's important to remember that as an entrepreneurial club, you will +also be pitching your ideas to potential investors, so your hard work +on the business strategy will be on display here. Pitching your start-up +in a convincing manner is a critical skill, so we also give you the opportunity to +practice this.

+

This year's showcase is scheduled for April 27th, 2024. +To prepare for this, we want each team to demo and pitch their project to +the club before the showcase. This will help you get experience and valuable +feedback from fellow project teams, execs, and our partners in industry.

+

Dates to Remember

+
+ + + + +
DateEventAudienceLocation
30 November 2023Demo & Pitch Night 1Project Teams & ExecsENC 201
29 February 2024Demo & Pitch Night 2Tech Start & Industry GuestsENC 201
Early AprilDemo & Pitch Night 3TBDTBD
27 April 2024Final ShowcaseOpen to the PublicHunter Hub Collision Space
+
+
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/projects/demos/used-by.png b/projects/demos/used-by.png new file mode 100644 index 0000000..01a7e90 Binary files /dev/null and b/projects/demos/used-by.png differ diff --git a/projects/license/index.html b/projects/license/index.html new file mode 100644 index 0000000..533bff7 --- /dev/null +++ b/projects/license/index.html @@ -0,0 +1,307 @@ + + + + + + A LICENSE.md - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

A LICENSE.md

+
+

This is no legal advice.

+
+

For good or bad, +all of the code that we write +is subject to the following Intellectual Property rights:

+
    +
  • +

    Copyright: The right to reproduce, +derivate, +distribute copies, and use the copyrighted work, +and to extend these rights to others.

    +
  • +
  • +

    Moral Rights: +The right of being attributed as the author of the work, +and the right to prevent prejudicial distortions of the work (integrity).

    +
  • +
+

Both concepts can be expanded a little bit more +by reading the following documents +from the U.S. Copyright Office: +1, +2. +It is a very interesting topic.

+

For the time being, +think of these rights +as a way for the rights holder +to decide on who and what can be done with the protected work. +Further, without explicit authorization from the rights holder, +you are effectively limited by law from doing anything at all with the work, +unless you can cite Fair Use.

+

If you go and read your employee contract, +you'll find that the rights over the work you do for your employer +are "assigned" to the employer +(transferred from you to them), +that you won't exercise your Moral Right of integrity over the work, +and (with luck) +that they'll respect your Moral Right of being attributed, +plus many more clauses that are similar in nature.

+

There is also a third concept called +The Public Domain, +which are works to which no Intellectual Property rights apply, +either because they expired, +but usually, because they were expressly waived by the holder.

+

Public Domain Logo

+

Whether the existence of these rights is good or bad +I leave it for you to think about, +but I'll throw some good articles and books here: +1, +2, +3, +4.

+

At Tech Start UCalgary we commit to Open Source everything +under an Open Source Initiative approved license, +but we recommend for source code:

+ +

And for documentation:

+ +

You can use the following resources to make an informed decision on your project:

+ +

We believe the previous licenses are good for the following reasons:

+
    +
  • They enable anyone to benefit from the software, +without discrimination, +which aligns well with the club's mission, +and the fact that we are not seeking profit, +but instead, to foster technology.
  • +
  • It allows you +or your team, +or anyone in the world, +to continue growing the project +or creating a company out of it in the future.
  • +
+

Should you not wish to opt-out of the Copyright Monopoly +by releasing your work into the public domain, +remember that the rights are yours and not Tech Start UCalgary. +You haven't signed any Copyright Transfer Agreement +with us (and you won't) +so please use Copyright <year> The <project name>'s contributors, +where the license asks for it.

+

The projects are yours.

+

And in order to ensure future contributions adhere to your license, +make sure to include the following text +somewhere visible in your project, for instance at the end of the README.md:

+
+
    +
  • All of the code that you submit to our code repository will be licensed under the <license>.
  • +
  • By submitting code to our code repository +you also certify that you agree +to the following Developer Certificate of Origin.
  • +
+
+

This constitutes a very simple +Contributor License Agreement.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/projects/motivation/index.html b/projects/motivation/index.html new file mode 100644 index 0000000..06c9e3a --- /dev/null +++ b/projects/motivation/index.html @@ -0,0 +1,230 @@ + + + + + + Motivation - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Motivation

+

Guess what most of the top Software Developers have in common?

+

They all have cool projects!

+

torvalds, +dtolnay, +sindresorhus, +donnemartin, +kamranahmedse, +jwasham, +trekhleb, +tiangolo, +gre, +vmihailenco, +twpayne, +brycedrennan, +marten-seemann, +rusty1s, +kripken, +krisnova.

+

And those projects are successful:

+

FastAPI and Typer by Tiangolo

+

Tech Start UCalgary mission +is to foster an environment +where people can become a better version of themselves +through creating software projects.

+

This website will guide you +through the elements that make a project awesome +while emphasizing industry best practices.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/projects/motivation/tiangolo-projects.png b/projects/motivation/tiangolo-projects.png new file mode 100644 index 0000000..4dee719 Binary files /dev/null and b/projects/motivation/tiangolo-projects.png differ diff --git a/projects/readme/alejandra-description.png b/projects/readme/alejandra-description.png new file mode 100644 index 0000000..622db49 Binary files /dev/null and b/projects/readme/alejandra-description.png differ diff --git a/projects/readme/alejandra-getting-started.png b/projects/readme/alejandra-getting-started.png new file mode 100644 index 0000000..3d0b538 Binary files /dev/null and b/projects/readme/alejandra-getting-started.png differ diff --git a/projects/readme/alejandra-readme.png b/projects/readme/alejandra-readme.png new file mode 100644 index 0000000..3c73400 Binary files /dev/null and b/projects/readme/alejandra-readme.png differ diff --git a/projects/readme/fast-api-about.png b/projects/readme/fast-api-about.png new file mode 100644 index 0000000..8605250 Binary files /dev/null and b/projects/readme/fast-api-about.png differ diff --git a/projects/readme/fast-api-readme.png b/projects/readme/fast-api-readme.png new file mode 100644 index 0000000..80dd135 Binary files /dev/null and b/projects/readme/fast-api-readme.png differ diff --git a/projects/readme/fastapi-slogan.png b/projects/readme/fastapi-slogan.png new file mode 100644 index 0000000..aa34064 Binary files /dev/null and b/projects/readme/fastapi-slogan.png differ diff --git a/projects/readme/index.html b/projects/readme/index.html new file mode 100644 index 0000000..1c04402 --- /dev/null +++ b/projects/readme/index.html @@ -0,0 +1,369 @@ + + + + + + A good README.md - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

A good README.md

+

A README.md file in the root of the repository +is going to be the first things your users see. +GitHub renders this file on the main page of the repository.

+

This is an example from the NixOS organization:

+

NixOS README

+

It's important that it's professional and colorful, and that it grabs the user's attention.

+

I highly recommend the following elements +are present on the first page:

+
    +
  1. +

    Logo and name: +A good logo is going to make the project look respected +and professional.

    +

    A good name is able to encapsulate the project's purpose, +or, at the very least, should give the project an identity.

    +

    This is an example from the +Prettier +project:

    +

    Prettier logo

    +

    It looks good.

    +

    On the other hand, it encapsulates the purpose of the project: +"Making your code prettier".

    +
  2. +
  3. +

    Slogan: +A short, catchy phrase, +summarizing what the project does and its most hot features.

    +

    This is an example from the +FastAPI +project:

    +
    +

    FastAPI framework, high performance, easy to learn, fast to code, ready for production.

    +
    +

    Wow. Yes, I want high-performance APIs. +I want things easy to learn, +with no boilerplate, +and robust enough for production.

    +

    While short, +this slogan is very important +because it's displayed on the project card:

    +

    FastAPI slogan

    +

    It can be the first thing a new visitor sees +and therefore can be the decisive factor +for a user to click on it.

    +

    It's also displayed on the top of the project home page:

    +

    FastAPI about

    +

    And sets the expectations for what comes next, +it needs to be good.

    +
  4. +
  5. +

    Description: +Here you will have a few paragraphs to +explain what your project does, +what problem it solves for your users, +and why should a user be using it right now.

    +

    This is an example from the +FastAPI +project:

    +
    +

    FastAPI is a modern, fast (high-performance), +web framework for building APIs with Python 3.6+ +based on standard Python type hints.

    +

    The key features are:

    +
      +
    • +

      Fast: Very high performance, on par with NodeJS and Go (thanks to Starlette and Pydantic). One of the fastest Python frameworks available.

      +
    • +
    • +

      Fast to code: Increase the speed to develop features by about 200% to 300%. *

      +
    • +
    • +

      Fewer bugs: Reduce about 40% of human (developer) induced errors. *

      +
    • +
    • +

      Intuitive: Great editor support. Completion everywhere. Less time debugging.

      +
    • +
    • +

      Easy: Designed to be easy to use and learn. Less time reading docs.

      +
    • +
    • +

      Short: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.

      +
    • +
    • +

      Robust: Get production-ready code. With automatic interactive documentation.

      +
    • +
    • +

      Standards-based: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema.

      +
    • +
    +

    * estimation based on tests on an internal development team, building production applications.

    +
    +

    Here the user knows that FastAPI helps build APIs with Python. +They should be using FastAPI right now +because it's fast, intuitive, easy, and so on.

    +

    It's always a good idea to throw a few power-words like: "Fast", "Powerful", "Secure", and "Reliable", +but of course, make sure that this is true.

    +

    You can further improve this section by adding emojis.

    +

    This is an example from the +Alejandra +project:

    +

    Alejandra description

    +

    To this point, your users should have a clear understanding of:

    +
      +
    • What problem does your project solve?
    • +
    • How does it make the user's life easier?
    • +
    • What is special about it? What are the key features?
    • +
    +

    But also make sure not to show unnecessary details. +Try to find a balance. +Too short and you'll leave questions unanswered. +Too long and you'll bore or confuse them.

    +
  6. +
  7. +

    Getting Started: +Users are interested at this point, +they want action now.

    +

    Here we place the shortest path a user can take +to interact with the project. +If there are many, show the fastest/easiest one first, +and then slowly introduce them to the more complex ones.

    +

    This is an example from the +Alejandra +project:

    +

    Alejandra Getting Started

    +

    It simply tells the user to use a web version of the project. +Everybody knows how to click a link, that's easy and nice.

    +

    This is an example from the +Prettier +project:

    +

    Prettier Getting Started

    +

    Users familiar with Node JS +will find the instructions easy to follow. +However, +some steps could have been removed +and it would have worked the same. +There is no need to overwhelm the user with details at this point. +We can introduce the details later.

    +

    For example, a better version would be:

    +
    +

    Install prettier with:

    +

    $ npm install --save-dev prettier

    +

    Make your code beautiful with:

    +

    $ npx prettier --write .

    +
    +

    Remember to keep the first impression simple and intuitive.

    +

    Simplicity is key here.

    +
  8. +
+

Altogether, the following are examples of a good README:

+
    +
  • +

    Prettier:

    +

    Prettier Readme

    +
  • +
  • +

    FastAPI:

    +

    FastAPI Readme

    +
  • +
  • +

    Alejandra:

    +

    Alejandra Readme

    +
  • +
+

Lastly, +makeareadme.com also offers some templates and tips.

+

You may want to have a look over there.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/projects/readme/nixos-readme.png b/projects/readme/nixos-readme.png new file mode 100644 index 0000000..5f7f552 Binary files /dev/null and b/projects/readme/nixos-readme.png differ diff --git a/projects/readme/prettier-getting-started.png b/projects/readme/prettier-getting-started.png new file mode 100644 index 0000000..0a0d55a Binary files /dev/null and b/projects/readme/prettier-getting-started.png differ diff --git a/projects/readme/prettier-logo.svg b/projects/readme/prettier-logo.svg new file mode 100644 index 0000000..72252ab --- /dev/null +++ b/projects/readme/prettier-logo.svg @@ -0,0 +1,79 @@ + + + + prettier-banner-light + Created with sketchtool. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/projects/readme/prettier-readme.png b/projects/readme/prettier-readme.png new file mode 100644 index 0000000..bd57071 Binary files /dev/null and b/projects/readme/prettier-readme.png differ diff --git a/projects/roadmap/eisenhower-matrix.png b/projects/roadmap/eisenhower-matrix.png new file mode 100644 index 0000000..daa0ac6 Binary files /dev/null and b/projects/roadmap/eisenhower-matrix.png differ diff --git a/projects/roadmap/index.html b/projects/roadmap/index.html new file mode 100644 index 0000000..b2f33f7 --- /dev/null +++ b/projects/roadmap/index.html @@ -0,0 +1,333 @@ + + + + + + A RoadMap - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

A RoadMap

+

A RoadMap is one of the best ways to manifest the future vision of your product +and the strategy and steps +that will be used for achieving that vision.

+

A RoadMap is also a great tool to cooperate with other people +because you can prioritize on it the steps +that are yet to be done, +and see who's working on what, +what progress has been made, +and so on.

+

This is an example from the Makes project on GitHub:

+

Makes RoadMap

+

That's a simple RoadMap, yet it has all the important information. +That's nice!

+

I highly recommend you create your RoadMap using the Projects feature on GitHub +because it integrates very well with other GitHub features +like Issues, Pull Requests and Milestones, +but it's also fine if you use Jira +or Trello.

+

As a rule of thumb, +anything related to making your project awesome +can (and should) go into the RoadMap. +It's also not limited to just programming tasks, +you could perfectly add to the RoadMap +a meeting with your users, +some market research activity, +or having some Pizza with the team.

+

A RoadMap is also a living creature, +it evolves as the project evolves +and you can iterate on it on the go. +Don't worry if you don't get it perfectly from the beginning, +but make sure you have one from the beginning!

+

How to create a RoadMap?

+

Step 1 - Start with Milestones

+

My suggestion is that you start by creating a few +Milestones.

+

Think about what your project wants to achieve: +Is it maybe a website that allows you to shorten URLs, +like https://tinyurl.com?

+

What's the minimum viable product that you can deliver to your users +so that they can start getting a taste?

+

You are right! +An ugly webpage, with an ugly textbox and an ugly button, +that when clicked, gives you a beautifully shortened URL :)

+

But that's even too far in the future. +What about making your first Milestone +about having an empty webpage? +Your second Milestone could be having a backend that answers a ping request. +Your third Milestone can be designing the database, +such that it stores the shortened URLs; +and your fourth Milestone can be adding the textbox and button to the front-end, +and an endpoint in the back-end that stores and retrieves the shortened URL.

+

You see? +we just planned a minimum viable product, +using an agile methodology.

+

Congratulations!

+

Step 2 - Split the Milestones in smaller Issues

+

Now we can proceed to define the individual tasks (GitHub Issues) +that are needed for completing each Milestone, +and most importantly, +we can assign each member of our team an Issue, +and work collaboratively towards the same goal.

+

Bonus points if we can plan it so that they can all work in parallel.

+

For example, +for Milestone #1 (Having an empty webpage that the user can access), +we could create the following Issues:

+

Milestone 1 Plan

+

In words:

+
    +
  • Issue #1: Create a Git repository. +
      +
    • Priority: Medium.
    • +
    • Assignee: John.
    • +
    +
  • +
  • Issue #2, after Issue #1: Add a license. +
      +
    • Priority: High.
    • +
    • Assignee: Olivia.
    • +
    +
  • +
  • Issue #3, after Issue #1: Add a README.md. +
      +
    • Priority: Medium.
    • +
    • Assignee: Jane.
    • +
    +
  • +
  • Issue #4, after Issue #1: Initialize an empty React project. +
      +
    • Priority: Medium.
    • +
    • Assignee: Oliver.
    • +
    +
  • +
  • Issue #5, after Issue #4: Use GitHub actions to deploy the front-end into GitHub pages. +
      +
    • Priority: Medium.
    • +
    • Assignee: John. (John should be free, since finishing #4 means #1 was finished).
    • +
    +
  • +
+

Boom! Done.

+

Now create more Issues for all of the other Milestones.

+

Step 3 - Add your Issues to the RoadMap

+

My suggestion for this is to keep it simple. +Avoid too many labels, statuses and complexity.

+

First, create a Project (a RoadMap) on GitHub. +This is usually under the Projects tab in the organization view:

+

New Project on GitHub

+

Then define some statuses:

+

Status Field

+
    +
  • 🆕 New: Where you place all of the issues initially.
  • +
  • 📋 Backlog: The issues that are yet to be done, and their priority.
  • +
  • 🏗 In progress: The issues that are being worked on, and who's working on them.
  • +
  • ✅ Done: The issues that have been shipped.
  • +
+

Then, create a priority field:

+

Priority Field

+

This will help your team focus on the things +that are more impactful to your project.

+

You can use the Eisenhower matrix for this:

+
    +
  • 🌋 High priority: Issues that are important and urgent.
  • +
  • 🏔 Medium priority: Issues that are important, but not urgent.
  • +
  • 🏕 Low priority: Issues that are not important, but may be nice to have someday.
  • +
  • 🏝 Never priority: Just close the issue :) don't waste your time on this.
  • +
+

Now you can start adding Issues to your RoadMap:

+

Makes RoadMap

+

And see what is the progress towards each Milestone, for example:

+

Milestones Progress

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/projects/roadmap/makes-roadmap.png b/projects/roadmap/makes-roadmap.png new file mode 100644 index 0000000..2dd9035 Binary files /dev/null and b/projects/roadmap/makes-roadmap.png differ diff --git a/projects/roadmap/mermaid-diagram-2022-10-26-225437.svg b/projects/roadmap/mermaid-diagram-2022-10-26-225437.svg new file mode 100644 index 0000000..18197bd --- /dev/null +++ b/projects/roadmap/mermaid-diagram-2022-10-26-225437.svg @@ -0,0 +1 @@ +
Milestone1
Create a Git repository (Jhon)
Add a license (Olivia)
Add a README.md (Jane)
Initialize an empty React project (Oliver)
Use GitHub actions to deploy the frontend into GitHub pages (John)
\ No newline at end of file diff --git a/projects/roadmap/milestone-1-plan.png b/projects/roadmap/milestone-1-plan.png new file mode 100644 index 0000000..b458aff Binary files /dev/null and b/projects/roadmap/milestone-1-plan.png differ diff --git a/projects/roadmap/milestones-progress.png b/projects/roadmap/milestones-progress.png new file mode 100644 index 0000000..fddc571 Binary files /dev/null and b/projects/roadmap/milestones-progress.png differ diff --git a/projects/roadmap/new-project.png b/projects/roadmap/new-project.png new file mode 100644 index 0000000..e1a282b Binary files /dev/null and b/projects/roadmap/new-project.png differ diff --git a/projects/roadmap/priority-fields.png b/projects/roadmap/priority-fields.png new file mode 100644 index 0000000..8f14885 Binary files /dev/null and b/projects/roadmap/priority-fields.png differ diff --git a/projects/roadmap/status-field.png b/projects/roadmap/status-field.png new file mode 100644 index 0000000..a19cf99 Binary files /dev/null and b/projects/roadmap/status-field.png differ diff --git a/searcher.js b/searcher.js new file mode 100644 index 0000000..d2b0aee --- /dev/null +++ b/searcher.js @@ -0,0 +1,483 @@ +"use strict"; +window.search = window.search || {}; +(function search(search) { + // Search functionality + // + // You can use !hasFocus() to prevent keyhandling in your key + // event handlers while the user is typing their search. + + if (!Mark || !elasticlunr) { + return; + } + + //IE 11 Compatibility from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith + if (!String.prototype.startsWith) { + String.prototype.startsWith = function(search, pos) { + return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search; + }; + } + + var search_wrap = document.getElementById('search-wrapper'), + searchbar = document.getElementById('searchbar'), + searchbar_outer = document.getElementById('searchbar-outer'), + searchresults = document.getElementById('searchresults'), + searchresults_outer = document.getElementById('searchresults-outer'), + searchresults_header = document.getElementById('searchresults-header'), + searchicon = document.getElementById('search-toggle'), + content = document.getElementById('content'), + + searchindex = null, + doc_urls = [], + results_options = { + teaser_word_count: 30, + limit_results: 30, + }, + search_options = { + bool: "AND", + expand: true, + fields: { + title: {boost: 1}, + body: {boost: 1}, + breadcrumbs: {boost: 0} + } + }, + mark_exclude = [], + marker = new Mark(content), + current_searchterm = "", + URL_SEARCH_PARAM = 'search', + URL_MARK_PARAM = 'highlight', + teaser_count = 0, + + SEARCH_HOTKEY_KEYCODE = 83, + ESCAPE_KEYCODE = 27, + DOWN_KEYCODE = 40, + UP_KEYCODE = 38, + SELECT_KEYCODE = 13; + + function hasFocus() { + return searchbar === document.activeElement; + } + + function removeChildren(elem) { + while (elem.firstChild) { + elem.removeChild(elem.firstChild); + } + } + + // Helper to parse a url into its building blocks. + function parseURL(url) { + var a = document.createElement('a'); + a.href = url; + return { + source: url, + protocol: a.protocol.replace(':',''), + host: a.hostname, + port: a.port, + params: (function(){ + var ret = {}; + var seg = a.search.replace(/^\?/,'').split('&'); + var len = seg.length, i = 0, s; + for (;i': '>', + '"': '"', + "'": ''' + }; + var repl = function(c) { return MAP[c]; }; + return function(s) { + return s.replace(/[&<>'"]/g, repl); + }; + })(); + + function formatSearchMetric(count, searchterm) { + if (count == 1) { + return count + " search result for '" + searchterm + "':"; + } else if (count == 0) { + return "No search results for '" + searchterm + "'."; + } else { + return count + " search results for '" + searchterm + "':"; + } + } + + function formatSearchResult(result, searchterms) { + var teaser = makeTeaser(escapeHTML(result.doc.body), searchterms); + teaser_count++; + + // The ?URL_MARK_PARAM= parameter belongs inbetween the page and the #heading-anchor + var url = doc_urls[result.ref].split("#"); + if (url.length == 1) { // no anchor found + url.push(""); + } + + // encodeURIComponent escapes all chars that could allow an XSS except + // for '. Due to that we also manually replace ' with its url-encoded + // representation (%27). + var searchterms = encodeURIComponent(searchterms.join(" ")).replace(/\'/g, "%27"); + + return '' + result.doc.breadcrumbs + '' + + '' + + teaser + ''; + } + + function makeTeaser(body, searchterms) { + // The strategy is as follows: + // First, assign a value to each word in the document: + // Words that correspond to search terms (stemmer aware): 40 + // Normal words: 2 + // First word in a sentence: 8 + // Then use a sliding window with a constant number of words and count the + // sum of the values of the words within the window. Then use the window that got the + // maximum sum. If there are multiple maximas, then get the last one. + // Enclose the terms in . + var stemmed_searchterms = searchterms.map(function(w) { + return elasticlunr.stemmer(w.toLowerCase()); + }); + var searchterm_weight = 40; + var weighted = []; // contains elements of ["word", weight, index_in_document] + // split in sentences, then words + var sentences = body.toLowerCase().split('. '); + var index = 0; + var value = 0; + var searchterm_found = false; + for (var sentenceindex in sentences) { + var words = sentences[sentenceindex].split(' '); + value = 8; + for (var wordindex in words) { + var word = words[wordindex]; + if (word.length > 0) { + for (var searchtermindex in stemmed_searchterms) { + if (elasticlunr.stemmer(word).startsWith(stemmed_searchterms[searchtermindex])) { + value = searchterm_weight; + searchterm_found = true; + } + }; + weighted.push([word, value, index]); + value = 2; + } + index += word.length; + index += 1; // ' ' or '.' if last word in sentence + }; + index += 1; // because we split at a two-char boundary '. ' + }; + + if (weighted.length == 0) { + return body; + } + + var window_weight = []; + var window_size = Math.min(weighted.length, results_options.teaser_word_count); + + var cur_sum = 0; + for (var wordindex = 0; wordindex < window_size; wordindex++) { + cur_sum += weighted[wordindex][1]; + }; + window_weight.push(cur_sum); + for (var wordindex = 0; wordindex < weighted.length - window_size; wordindex++) { + cur_sum -= weighted[wordindex][1]; + cur_sum += weighted[wordindex + window_size][1]; + window_weight.push(cur_sum); + }; + + if (searchterm_found) { + var max_sum = 0; + var max_sum_window_index = 0; + // backwards + for (var i = window_weight.length - 1; i >= 0; i--) { + if (window_weight[i] > max_sum) { + max_sum = window_weight[i]; + max_sum_window_index = i; + } + }; + } else { + max_sum_window_index = 0; + } + + // add around searchterms + var teaser_split = []; + var index = weighted[max_sum_window_index][2]; + for (var i = max_sum_window_index; i < max_sum_window_index+window_size; i++) { + var word = weighted[i]; + if (index < word[2]) { + // missing text from index to start of `word` + teaser_split.push(body.substring(index, word[2])); + index = word[2]; + } + if (word[1] == searchterm_weight) { + teaser_split.push("") + } + index = word[2] + word[0].length; + teaser_split.push(body.substring(word[2], index)); + if (word[1] == searchterm_weight) { + teaser_split.push("") + } + }; + + return teaser_split.join(''); + } + + function init(config) { + results_options = config.results_options; + search_options = config.search_options; + searchbar_outer = config.searchbar_outer; + doc_urls = config.doc_urls; + searchindex = elasticlunr.Index.load(config.index); + + // Set up events + searchicon.addEventListener('click', function(e) { searchIconClickHandler(); }, false); + searchbar.addEventListener('keyup', function(e) { searchbarKeyUpHandler(); }, false); + document.addEventListener('keydown', function(e) { globalKeyHandler(e); }, false); + // If the user uses the browser buttons, do the same as if a reload happened + window.onpopstate = function(e) { doSearchOrMarkFromUrl(); }; + // Suppress "submit" events so the page doesn't reload when the user presses Enter + document.addEventListener('submit', function(e) { e.preventDefault(); }, false); + + // If reloaded, do the search or mark again, depending on the current url parameters + doSearchOrMarkFromUrl(); + } + + function unfocusSearchbar() { + // hacky, but just focusing a div only works once + var tmp = document.createElement('input'); + tmp.setAttribute('style', 'position: absolute; opacity: 0;'); + searchicon.appendChild(tmp); + tmp.focus(); + tmp.remove(); + } + + // On reload or browser history backwards/forwards events, parse the url and do search or mark + function doSearchOrMarkFromUrl() { + // Check current URL for search request + var url = parseURL(window.location.href); + if (url.params.hasOwnProperty(URL_SEARCH_PARAM) + && url.params[URL_SEARCH_PARAM] != "") { + showSearch(true); + searchbar.value = decodeURIComponent( + (url.params[URL_SEARCH_PARAM]+'').replace(/\+/g, '%20')); + searchbarKeyUpHandler(); // -> doSearch() + } else { + showSearch(false); + } + + if (url.params.hasOwnProperty(URL_MARK_PARAM)) { + var words = decodeURIComponent(url.params[URL_MARK_PARAM]).split(' '); + marker.mark(words, { + exclude: mark_exclude + }); + + var markers = document.querySelectorAll("mark"); + function hide() { + for (var i = 0; i < markers.length; i++) { + markers[i].classList.add("fade-out"); + window.setTimeout(function(e) { marker.unmark(); }, 300); + } + } + for (var i = 0; i < markers.length; i++) { + markers[i].addEventListener('click', hide); + } + } + } + + // Eventhandler for keyevents on `document` + function globalKeyHandler(e) { + if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || e.target.type === 'textarea' || e.target.type === 'text') { return; } + + if (e.keyCode === ESCAPE_KEYCODE) { + e.preventDefault(); + searchbar.classList.remove("active"); + setSearchUrlParameters("", + (searchbar.value.trim() !== "") ? "push" : "replace"); + if (hasFocus()) { + unfocusSearchbar(); + } + showSearch(false); + marker.unmark(); + } else if (!hasFocus() && e.keyCode === SEARCH_HOTKEY_KEYCODE) { + e.preventDefault(); + showSearch(true); + window.scrollTo(0, 0); + searchbar.select(); + } else if (hasFocus() && e.keyCode === DOWN_KEYCODE) { + e.preventDefault(); + unfocusSearchbar(); + searchresults.firstElementChild.classList.add("focus"); + } else if (!hasFocus() && (e.keyCode === DOWN_KEYCODE + || e.keyCode === UP_KEYCODE + || e.keyCode === SELECT_KEYCODE)) { + // not `:focus` because browser does annoying scrolling + var focused = searchresults.querySelector("li.focus"); + if (!focused) return; + e.preventDefault(); + if (e.keyCode === DOWN_KEYCODE) { + var next = focused.nextElementSibling; + if (next) { + focused.classList.remove("focus"); + next.classList.add("focus"); + } + } else if (e.keyCode === UP_KEYCODE) { + focused.classList.remove("focus"); + var prev = focused.previousElementSibling; + if (prev) { + prev.classList.add("focus"); + } else { + searchbar.select(); + } + } else { // SELECT_KEYCODE + window.location.assign(focused.querySelector('a')); + } + } + } + + function showSearch(yes) { + if (yes) { + search_wrap.classList.remove('hidden'); + searchicon.setAttribute('aria-expanded', 'true'); + } else { + search_wrap.classList.add('hidden'); + searchicon.setAttribute('aria-expanded', 'false'); + var results = searchresults.children; + for (var i = 0; i < results.length; i++) { + results[i].classList.remove("focus"); + } + } + } + + function showResults(yes) { + if (yes) { + searchresults_outer.classList.remove('hidden'); + } else { + searchresults_outer.classList.add('hidden'); + } + } + + // Eventhandler for search icon + function searchIconClickHandler() { + if (search_wrap.classList.contains('hidden')) { + showSearch(true); + window.scrollTo(0, 0); + searchbar.select(); + } else { + showSearch(false); + } + } + + // Eventhandler for keyevents while the searchbar is focused + function searchbarKeyUpHandler() { + var searchterm = searchbar.value.trim(); + if (searchterm != "") { + searchbar.classList.add("active"); + doSearch(searchterm); + } else { + searchbar.classList.remove("active"); + showResults(false); + removeChildren(searchresults); + } + + setSearchUrlParameters(searchterm, "push_if_new_search_else_replace"); + + // Remove marks + marker.unmark(); + } + + // Update current url with ?URL_SEARCH_PARAM= parameter, remove ?URL_MARK_PARAM and #heading-anchor . + // `action` can be one of "push", "replace", "push_if_new_search_else_replace" + // and replaces or pushes a new browser history item. + // "push_if_new_search_else_replace" pushes if there is no `?URL_SEARCH_PARAM=abc` yet. + function setSearchUrlParameters(searchterm, action) { + var url = parseURL(window.location.href); + var first_search = ! url.params.hasOwnProperty(URL_SEARCH_PARAM); + if (searchterm != "" || action == "push_if_new_search_else_replace") { + url.params[URL_SEARCH_PARAM] = searchterm; + delete url.params[URL_MARK_PARAM]; + url.hash = ""; + } else { + delete url.params[URL_MARK_PARAM]; + delete url.params[URL_SEARCH_PARAM]; + } + // A new search will also add a new history item, so the user can go back + // to the page prior to searching. A updated search term will only replace + // the url. + if (action == "push" || (action == "push_if_new_search_else_replace" && first_search) ) { + history.pushState({}, document.title, renderURL(url)); + } else if (action == "replace" || (action == "push_if_new_search_else_replace" && !first_search) ) { + history.replaceState({}, document.title, renderURL(url)); + } + } + + function doSearch(searchterm) { + + // Don't search the same twice + if (current_searchterm == searchterm) { return; } + else { current_searchterm = searchterm; } + + if (searchindex == null) { return; } + + // Do the actual search + var results = searchindex.search(searchterm, search_options); + var resultcount = Math.min(results.length, results_options.limit_results); + + // Display search metrics + searchresults_header.innerText = formatSearchMetric(resultcount, searchterm); + + // Clear and insert results + var searchterms = searchterm.split(' '); + removeChildren(searchresults); + for(var i = 0; i < resultcount ; i++){ + var resultElem = document.createElement('li'); + resultElem.innerHTML = formatSearchResult(results[i], searchterms); + searchresults.appendChild(resultElem); + } + + // Display results + showResults(true); + } + + fetch(path_to_root + 'searchindex.json') + .then(response => response.json()) + .then(json => init(json)) + .catch(error => { // Try to load searchindex.js if fetch failed + var script = document.createElement('script'); + script.src = path_to_root + 'searchindex.js'; + script.onload = () => init(window.search); + document.head.appendChild(script); + }); + + // Exported functions + search.hasFocus = hasFocus; +})(window.search); diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 0000000..bb6a90c --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Object.assign(window.search, {"doc_urls":["index.html#introduction","installation/installfest/index.html#installfest-from-zero-to-hero","installation/wsl2/index.html#wsl2-installation","projects/motivation/index.html#motivation","projects/readme/index.html#a-good-readmemd","projects/license/index.html#a-licensemd","projects/roadmap/index.html#a-roadmap","projects/roadmap/index.html#how-to-create-a-roadmap","projects/roadmap/index.html#step-1---start-with-milestones","projects/roadmap/index.html#step-2---split-the-milestones-in-smaller-issues","projects/roadmap/index.html#step-3---add-your-issues-to-the-roadmap","projects/demos/index.html#demo--pitch-nights","projects/demos/index.html#dates-to-remember","projects/demos/1/index.html#demo--pitch-night-1","projects/demos/1/index.html#30-november-2023","projects/demos/1/index.html#objectives","projects/demos/1/index.html#time-limit-15-minutes","projects/demos/1/index.html#suggested-talking-points","projects/demos/1/index.html#strategy","projects/demos/1/index.html#design","projects/demos/1/index.html#development","projects/demos/1/index.html#milestones","projects/demos/1/index.html#strategy-1","projects/demos/1/index.html#design-1","projects/demos/1/index.html#development-1","projects/demos/1/index.html#visual-aids","projects/demos/2/index.html#demo--pitch-night-2","projects/demos/2/index.html#29-february-2024","projects/demos/2/index.html#objectives","projects/demos/2/index.html#quick-info","projects/demos/2/index.html#start-time-6pm-sharp","projects/demos/2/index.html#time-limit-10-minutes","projects/demos/2/index.html#dress-code-business-casual","projects/demos/2/index.html#what-to-do","projects/demos/2/index.html#what-not-to-do","projects/demos/2/index.html#suggested-talking-points","projects/demos/2/index.html#general","projects/demos/2/index.html#strategy","projects/demos/2/index.html#design","projects/demos/2/index.html#development","projects/demos/2/index.html#milestones","projects/demos/2/index.html#strategy-1","projects/demos/2/index.html#design-1","projects/demos/2/index.html#development-1","projects/demos/3/index.html#demo--pitch-night-3","projects/demos/3/index.html#early-april-2024","software/career-paths/index.html#career-paths","software/front-end/index.html#front-end","software/front-end/index.html#how-to-become-a-front-end-engineer","software/devops/index.html#devops","software/devops/index.html#how-to-become-a-devops-engineer","guides/Tech_Demo/index.html#technical-demos","guides/Tech_Demo/index.html#overview","guides/Tech_Demo/index.html#purpose","guides/Tech_Demo/index.html#presentation","guides/Tech_Demo/index.html#avoid-distractions","guides/Tech_Demo/index.html#prepare","guides/Django_Guide/index.html#tech-starts-django-guide","guides/Django_Guide/index.html#urls","guides/Django_Guide/index.html#views","guides/Git_Guide/index.html#tech-starts-git-guide","guides/Git_Guide/index.html#contents","guides/Git_Guide/index.html#note","guides/Git_Guide/index.html#getting-started---setting-up-a-repository","guides/Git_Guide/index.html#git-analogy","guides/Git_Guide/index.html#gui-vs-command-line","guides/Git_Guide/index.html#staging-files--creating-commits","guides/Git_Guide/index.html#common-commands","guides/Git_Guide/index.html#git-status","guides/Git_Guide/index.html#git-add-pathtofile","guides/Git_Guide/index.html#git-commit--m-commitmessage","guides/Git_Guide/index.html#git-restore-pathtofile","guides/Git_Guide/index.html#git-restore---staged-pathtofile","guides/Git_Guide/index.html#naming-commits","guides/Git_Guide/index.html#branches","guides/Git_Guide/index.html#git-branch","guides/Git_Guide/index.html#git-branch-branchname","guides/Git_Guide/index.html#git-branch--d-branchname","guides/Git_Guide/index.html#git-checkout-branchname","guides/Git_Guide/index.html#how-to-use-branches","guides/Git_Guide/index.html#remote-repositories","guides/Git_Guide/index.html#git-pull-remotename-branchname","guides/Git_Guide/index.html#git-push","guides/Git_Guide/index.html#merge-conflicts","guides/Git_Guide/index.html#example-of-merge-conflicts-shown-in-command-line","guides/Git_Guide/index.html#resolving-merge-conflicts","guides/Git_Guide/index.html#using-github","guides/Git_Guide/index.html#pull-requests","guides/Git_Guide/index.html#pull-request-reviews","guides/Git_Guide/index.html#best-practices-for-reviewers","guides/Git_Guide/index.html#our-recommended-git-workflow","guides/Git_Guide/index.html#big-picture-gitgithub-workflow","guides/Git_Guide/index.html#faq","guides/Git_Guide/index.html#advanced-section","guides/Git_Guide/index.html#advanced-staging-and-commits","guides/Git_Guide/index.html#git-status--s--v","guides/Git_Guide/index.html#git-add-filename-or-foldername--u","guides/Git_Guide/index.html#git-commit--a--am-commit-message-here","guides/Git_Guide/index.html#git-stash","guides/Git_Guide/index.html#-under-construction-","guides/Git_Guide/index.html#git-clean","guides/Git_Guide/index.html#-under-construction--1","guides/Git_Guide/index.html#undoing-commits--changes","guides/Git_Guide/index.html#git-log","guides/Git_Guide/index.html#git-clean--f--n","guides/Git_Guide/index.html#git-revert","guides/Git_Guide/index.html#git-rebase-and-git-merge","guides/Git_Guide/index.html#git-merge-branchname","guides/Git_Guide/index.html#-under-construction--2","guides/API_Guide/index.html#tech-starts-api-guide","guides/API_Guide/index.html#introduction","guides/API_Guide/index.html#types-of-apis","guides/API_Guide/index.html#rest-apis","guides/API_Guide/index.html#creating-your-own-api","guides/API_Guide/index.html#using-postman","guides/API_Guide/index.html#further-resources-on-apis","guides/API_Guide/index.html#graphql","guides/React_Guide/index.html#tech-starts-react-guide","guides/React_Guide/index.html#react-main-concepts","guides/React_Guide/index.html#react-video","guides/React_Guide/index.html#components","guides/React_Guide/index.html#jsx","guides/React_Guide/index.html#rendering","guides/React_Guide/index.html#props","guides/React_Guide/index.html#state","guides/React_Guide/index.html#lifecycle-methods","guides/React_Guide/index.html#handling-events","guides/React_Guide/index.html#conditional-rendering","guides/React_Guide/index.html#lists-and-keys","guides/React_Guide/index.html#javascript-for-react","guides/React_Guide/index.html#arrow-functions","guides/React_Guide/index.html#classes","guides/React_Guide/index.html#callbacks","guides/React_Guide/index.html#promises","guides/React_Guide/index.html#asyncawait","guides/React_Guide/index.html#promises-and-aysncawait-integration-in-react","guides/React_Guide/index.html#more-react","guides/React_Guide/index.html#events-in-react","guides/React_Guide/index.html#event-handling","guides/React_Guide/index.html#event-object","guides/React_Guide/index.html#higher-order-components-hocs-in-react","guides/React_Guide/index.html#what-are-hocs","guides/React_Guide/index.html#how-hocs-work","guides/React_Guide/index.html#using-hocs","guides/React_Guide/index.html#benefits-of-hocs","guides/React_Guide/index.html#relationship-between-events-and-hocs","guides/React_Guide/index.html#props-vs-state","guides/React_Guide/index.html#props-1","guides/React_Guide/index.html#state-1","guides/React_Guide/index.html#how-they-relate-and-are-integrated","guides/React_Guide/index.html#hooks-in-functional-components","guides/React_Guide/index.html#1-usestate","guides/React_Guide/index.html#2-useeffect","guides/React_Guide/index.html#3-other-built-in-hooks","guides/React_Guide/index.html#4-custom-hooks","guides/React_Guide/index.html#react-ecosystem","guides/React_Guide/index.html#calling-apis","guides/React_Guide/index.html#useswr","guides/React_Guide/index.html#react-router","guides/React_Guide/index.html#react-router-features","guides/React_Guide/index.html#integration-with-react","guides/React_Guide/index.html#react-with-redux","guides/React_Guide/index.html#lastly-nextjs","guides/React_Native_Guide/index.html#tech-starts-react-native-guide","guides/React_Native_Guide/index.html#video-resources","guides/React_Native_Guide/index.html#react-native-basics","guides/React_Native_Guide/index.html#components-in-react-native","guides/React_Native_Guide/index.html#styling-in-react-native","guides/React_Native_Guide/index.html#layout-in-react-native","guides/React_Native_Guide/index.html#navigation","guides/React_Native_Guide/index.html#platform-specific-code","guides/React_Native_Guide/index.html#accessing-device-features","guides/React_Native_Guide/index.html#native-modules-and-bridges","guides/React_Native_Guide/index.html#native-modules","guides/React_Native_Guide/index.html#native-bridges","guides/React_Native_Guide/index.html#state-management","guides/React_Native_Guide/index.html#1--reacts-built-in-state-management","guides/React_Native_Guide/index.html#2--context-api","guides/React_Native_Guide/index.html#3--redux","guides/React_Native_Guide/index.html#async-storage","guides/React_Native_Guide/index.html#using-asyncstorage-in-react-native","guides/React_Native_Guide/index.html#network-requests","guides/React_Native_Guide/index.html#using-axios","guides/React_Native_Guide/index.html#using-the-fetch-api","guides/React_Native_Guide/index.html#advanced-topics","guides/React_Native_Guide/index.html#debugging-and-troubleshooting","guides/React_Native_Guide/index.html#testing","guides/React_Native_Guide/index.html#performance-optimization","guides/React_Native_Guide/index.html#publishing-and-deployment","guides/React_Native_Guide/index.html#third-party-integrations","guides/React_Native_Guide/index.html#security-best-practices","guides/React_Native_Guide/index.html#conclusion","guides/Web_Dev_Guide/index.html#tech-starts-super-awesome-mega-web-dev-guide","guides/Web_Dev_Guide/index.html#part-1---html","guides/Web_Dev_Guide/index.html#part-2---css","guides/Web_Dev_Guide/index.html#part-3---javascript","guides/Web_Dev_Guide/index.html#31-nodejs","guides/Web_Dev_Guide/index.html#32-typescript","guides/Web_Dev_Guide/index.html#part-4---react","guides/UI_UX_Design_Guide/index.html#uiux-design-guide","guides/UI_UX_Design_Guide/index.html#design-process","guides/UI_UX_Design_Guide/index.html#tasks-to-do-at-each-stage-methods-to-use","guides/UI_UX_Design_Guide/index.html#user-research","guides/UI_UX_Design_Guide/index.html#usability-testing","guides/UI_UX_Design_Guide/index.html#working-in-figma","guides/UI_UX_Design_Guide/index.html#using-components","guides/UI_UX_Design_Guide/index.html#using-auto-layout","guides/UI_UX_Design_Guide/index.html#using-grids","guides/UI_UX_Design_Guide/index.html#other-resources","guides/UI_UX_Design_Guide/index.html#other-design-considerations","guides/UI_UX_Design_Guide/index.html#where-to-look-for-inspiration","guides/UI_UX_Design_Guide/index.html#design-documentation","guides/UI_UX_Design_Guide/index.html#accessibility-and-inclusion-in-design","topics/conflict-management-styles/index.html#dealing-with-conflict","topics/css/index.html#css","topics/css/index.html#fundamentals","topics/css/index.html#popular-libraries","topics/css/index.html#advanced","topics/css/index.html#be-aware-of","topics/html/index.html#html","topics/html/index.html#fundamentals","topics/management-styles/index.html#management-styles","workshops/secrets-management/index.html#secrets-management","workshops/secrets-management/index.html#pre-requisites","workshops/secrets-management/index.html#why","workshops/secrets-management/index.html#workshop-step-by-step","workshops/secrets-management/index.html#git-crypt","workshops/secrets-management/index.html#sops","workshops/secrets-management/index.html#vault","CONTRIBUTING.html#contributing","CONTRIBUTING.html#code-contributions","CONTRIBUTING.html#legal","CREDITS.html#credits","LICENSE.html#license"],"index":{"documentStore":{"docInfo":{"0":{"body":18,"breadcrumbs":5,"title":1},"1":{"body":796,"breadcrumbs":6,"title":3},"10":{"body":96,"breadcrumbs":6,"title":5},"100":{"body":1,"breadcrumbs":3,"title":2},"101":{"body":0,"breadcrumbs":3,"title":2},"102":{"body":23,"breadcrumbs":4,"title":3},"103":{"body":32,"breadcrumbs":3,"title":2},"104":{"body":32,"breadcrumbs":5,"title":4},"105":{"body":14,"breadcrumbs":3,"title":2},"106":{"body":0,"breadcrumbs":5,"title":4},"107":{"body":19,"breadcrumbs":4,"title":3},"108":{"body":0,"breadcrumbs":3,"title":2},"109":{"body":27,"breadcrumbs":5,"title":4},"11":{"body":78,"breadcrumbs":4,"title":3},"110":{"body":158,"breadcrumbs":2,"title":1},"111":{"body":17,"breadcrumbs":3,"title":2},"112":{"body":29,"breadcrumbs":3,"title":2},"113":{"body":32,"breadcrumbs":3,"title":2},"114":{"body":30,"breadcrumbs":3,"title":2},"115":{"body":20,"breadcrumbs":4,"title":3},"116":{"body":52,"breadcrumbs":2,"title":1},"117":{"body":0,"breadcrumbs":5,"title":4},"118":{"body":47,"breadcrumbs":4,"title":3},"119":{"body":24,"breadcrumbs":3,"title":2},"12":{"body":48,"breadcrumbs":3,"title":2},"120":{"body":26,"breadcrumbs":2,"title":1},"121":{"body":22,"breadcrumbs":2,"title":1},"122":{"body":17,"breadcrumbs":2,"title":1},"123":{"body":20,"breadcrumbs":2,"title":1},"124":{"body":22,"breadcrumbs":2,"title":1},"125":{"body":21,"breadcrumbs":3,"title":2},"126":{"body":22,"breadcrumbs":3,"title":2},"127":{"body":22,"breadcrumbs":3,"title":2},"128":{"body":51,"breadcrumbs":3,"title":2},"129":{"body":19,"breadcrumbs":3,"title":2},"13":{"body":0,"breadcrumbs":7,"title":4},"130":{"body":46,"breadcrumbs":3,"title":2},"131":{"body":107,"breadcrumbs":2,"title":1},"132":{"body":39,"breadcrumbs":2,"title":1},"133":{"body":76,"breadcrumbs":2,"title":1},"134":{"body":69,"breadcrumbs":2,"title":1},"135":{"body":125,"breadcrumbs":5,"title":4},"136":{"body":0,"breadcrumbs":3,"title":2},"137":{"body":0,"breadcrumbs":3,"title":2},"138":{"body":75,"breadcrumbs":3,"title":2},"139":{"body":32,"breadcrumbs":3,"title":2},"14":{"body":0,"breadcrumbs":6,"title":3},"140":{"body":0,"breadcrumbs":6,"title":5},"141":{"body":25,"breadcrumbs":2,"title":1},"142":{"body":47,"breadcrumbs":3,"title":2},"143":{"body":32,"breadcrumbs":3,"title":2},"144":{"body":26,"breadcrumbs":3,"title":2},"145":{"body":77,"breadcrumbs":5,"title":4},"146":{"body":11,"breadcrumbs":4,"title":3},"147":{"body":34,"breadcrumbs":2,"title":1},"148":{"body":65,"breadcrumbs":2,"title":1},"149":{"body":137,"breadcrumbs":3,"title":2},"15":{"body":46,"breadcrumbs":4,"title":1},"150":{"body":65,"breadcrumbs":4,"title":3},"151":{"body":41,"breadcrumbs":3,"title":2},"152":{"body":42,"breadcrumbs":3,"title":2},"153":{"body":121,"breadcrumbs":4,"title":3},"154":{"body":89,"breadcrumbs":4,"title":3},"155":{"body":0,"breadcrumbs":3,"title":2},"156":{"body":216,"breadcrumbs":3,"title":2},"157":{"body":39,"breadcrumbs":2,"title":1},"158":{"body":40,"breadcrumbs":3,"title":2},"159":{"body":106,"breadcrumbs":4,"title":3},"16":{"body":0,"breadcrumbs":7,"title":4},"160":{"body":171,"breadcrumbs":3,"title":2},"161":{"body":91,"breadcrumbs":3,"title":2},"162":{"body":378,"breadcrumbs":3,"title":2},"163":{"body":77,"breadcrumbs":7,"title":5},"164":{"body":18,"breadcrumbs":4,"title":2},"165":{"body":0,"breadcrumbs":5,"title":3},"166":{"body":72,"breadcrumbs":5,"title":3},"167":{"body":106,"breadcrumbs":5,"title":3},"168":{"body":170,"breadcrumbs":5,"title":3},"169":{"body":520,"breadcrumbs":3,"title":1},"17":{"body":4,"breadcrumbs":6,"title":3},"170":{"body":311,"breadcrumbs":5,"title":3},"171":{"body":273,"breadcrumbs":5,"title":3},"172":{"body":36,"breadcrumbs":5,"title":3},"173":{"body":148,"breadcrumbs":4,"title":2},"174":{"body":92,"breadcrumbs":4,"title":2},"175":{"body":47,"breadcrumbs":4,"title":2},"176":{"body":59,"breadcrumbs":7,"title":5},"177":{"body":86,"breadcrumbs":5,"title":3},"178":{"body":159,"breadcrumbs":4,"title":2},"179":{"body":39,"breadcrumbs":4,"title":2},"18":{"body":22,"breadcrumbs":4,"title":1},"180":{"body":219,"breadcrumbs":6,"title":4},"181":{"body":39,"breadcrumbs":4,"title":2},"182":{"body":107,"breadcrumbs":4,"title":2},"183":{"body":134,"breadcrumbs":5,"title":3},"184":{"body":0,"breadcrumbs":4,"title":2},"185":{"body":14,"breadcrumbs":4,"title":2},"186":{"body":16,"breadcrumbs":3,"title":1},"187":{"body":12,"breadcrumbs":4,"title":2},"188":{"body":21,"breadcrumbs":4,"title":2},"189":{"body":338,"breadcrumbs":5,"title":3},"19":{"body":24,"breadcrumbs":4,"title":1},"190":{"body":332,"breadcrumbs":5,"title":3},"191":{"body":50,"breadcrumbs":3,"title":1},"192":{"body":114,"breadcrumbs":10,"title":8},"193":{"body":77,"breadcrumbs":5,"title":3},"194":{"body":229,"breadcrumbs":5,"title":3},"195":{"body":73,"breadcrumbs":5,"title":3},"196":{"body":103,"breadcrumbs":4,"title":2},"197":{"body":78,"breadcrumbs":4,"title":2},"198":{"body":278,"breadcrumbs":5,"title":3},"199":{"body":75,"breadcrumbs":5,"title":3},"2":{"body":248,"breadcrumbs":4,"title":2},"20":{"body":16,"breadcrumbs":4,"title":1},"200":{"body":87,"breadcrumbs":4,"title":2},"201":{"body":128,"breadcrumbs":7,"title":5},"202":{"body":156,"breadcrumbs":4,"title":2},"203":{"body":75,"breadcrumbs":4,"title":2},"204":{"body":54,"breadcrumbs":4,"title":2},"205":{"body":19,"breadcrumbs":4,"title":2},"206":{"body":29,"breadcrumbs":5,"title":3},"207":{"body":44,"breadcrumbs":4,"title":2},"208":{"body":44,"breadcrumbs":3,"title":1},"209":{"body":0,"breadcrumbs":4,"title":2},"21":{"body":6,"breadcrumbs":4,"title":1},"210":{"body":22,"breadcrumbs":4,"title":2},"211":{"body":25,"breadcrumbs":4,"title":2},"212":{"body":30,"breadcrumbs":5,"title":3},"213":{"body":82,"breadcrumbs":4,"title":2},"214":{"body":5,"breadcrumbs":2,"title":1},"215":{"body":40,"breadcrumbs":2,"title":1},"216":{"body":5,"breadcrumbs":3,"title":2},"217":{"body":8,"breadcrumbs":2,"title":1},"218":{"body":5,"breadcrumbs":2,"title":1},"219":{"body":0,"breadcrumbs":2,"title":1},"22":{"body":10,"breadcrumbs":4,"title":1},"220":{"body":24,"breadcrumbs":2,"title":1},"221":{"body":88,"breadcrumbs":4,"title":2},"222":{"body":50,"breadcrumbs":4,"title":2},"223":{"body":92,"breadcrumbs":4,"title":2},"224":{"body":96,"breadcrumbs":2,"title":0},"225":{"body":0,"breadcrumbs":5,"title":3},"226":{"body":175,"breadcrumbs":4,"title":2},"227":{"body":136,"breadcrumbs":3,"title":1},"228":{"body":81,"breadcrumbs":3,"title":1},"229":{"body":11,"breadcrumbs":2,"title":1},"23":{"body":15,"breadcrumbs":4,"title":1},"230":{"body":51,"breadcrumbs":3,"title":2},"231":{"body":22,"breadcrumbs":2,"title":1},"232":{"body":18,"breadcrumbs":2,"title":1},"233":{"body":749,"breadcrumbs":2,"title":1},"24":{"body":22,"breadcrumbs":4,"title":1},"25":{"body":23,"breadcrumbs":5,"title":2},"26":{"body":0,"breadcrumbs":7,"title":4},"27":{"body":0,"breadcrumbs":6,"title":3},"28":{"body":15,"breadcrumbs":4,"title":1},"29":{"body":0,"breadcrumbs":5,"title":2},"3":{"body":56,"breadcrumbs":2,"title":1},"30":{"body":0,"breadcrumbs":7,"title":4},"31":{"body":0,"breadcrumbs":7,"title":4},"32":{"body":0,"breadcrumbs":7,"title":4},"33":{"body":21,"breadcrumbs":3,"title":0},"34":{"body":7,"breadcrumbs":3,"title":0},"35":{"body":4,"breadcrumbs":6,"title":3},"36":{"body":22,"breadcrumbs":4,"title":1},"37":{"body":32,"breadcrumbs":4,"title":1},"38":{"body":26,"breadcrumbs":4,"title":1},"39":{"body":29,"breadcrumbs":4,"title":1},"4":{"body":452,"breadcrumbs":4,"title":2},"40":{"body":6,"breadcrumbs":4,"title":1},"41":{"body":10,"breadcrumbs":4,"title":1},"42":{"body":12,"breadcrumbs":4,"title":1},"43":{"body":11,"breadcrumbs":4,"title":1},"44":{"body":0,"breadcrumbs":7,"title":4},"45":{"body":2,"breadcrumbs":6,"title":3},"46":{"body":505,"breadcrumbs":4,"title":2},"47":{"body":92,"breadcrumbs":4,"title":2},"48":{"body":138,"breadcrumbs":6,"title":4},"49":{"body":116,"breadcrumbs":2,"title":1},"5":{"body":296,"breadcrumbs":2,"title":1},"50":{"body":180,"breadcrumbs":4,"title":3},"51":{"body":0,"breadcrumbs":6,"title":2},"52":{"body":37,"breadcrumbs":5,"title":1},"53":{"body":34,"breadcrumbs":5,"title":1},"54":{"body":108,"breadcrumbs":5,"title":1},"55":{"body":56,"breadcrumbs":6,"title":2},"56":{"body":91,"breadcrumbs":5,"title":1},"57":{"body":919,"breadcrumbs":5,"title":4},"58":{"body":110,"breadcrumbs":2,"title":1},"59":{"body":1906,"breadcrumbs":2,"title":1},"6":{"body":102,"breadcrumbs":2,"title":1},"60":{"body":1,"breadcrumbs":5,"title":4},"61":{"body":45,"breadcrumbs":2,"title":1},"62":{"body":16,"breadcrumbs":2,"title":1},"63":{"body":64,"breadcrumbs":6,"title":5},"64":{"body":60,"breadcrumbs":3,"title":2},"65":{"body":44,"breadcrumbs":5,"title":4},"66":{"body":88,"breadcrumbs":5,"title":4},"67":{"body":52,"breadcrumbs":3,"title":2},"68":{"body":33,"breadcrumbs":3,"title":2},"69":{"body":61,"breadcrumbs":4,"title":3},"7":{"body":0,"breadcrumbs":3,"title":2},"70":{"body":100,"breadcrumbs":5,"title":4},"71":{"body":38,"breadcrumbs":4,"title":3},"72":{"body":40,"breadcrumbs":5,"title":4},"73":{"body":48,"breadcrumbs":3,"title":2},"74":{"body":29,"breadcrumbs":2,"title":1},"75":{"body":4,"breadcrumbs":3,"title":2},"76":{"body":45,"breadcrumbs":4,"title":3},"77":{"body":41,"breadcrumbs":5,"title":4},"78":{"body":36,"breadcrumbs":4,"title":3},"79":{"body":271,"breadcrumbs":3,"title":2},"8":{"body":83,"breadcrumbs":5,"title":4},"80":{"body":234,"breadcrumbs":3,"title":2},"81":{"body":65,"breadcrumbs":5,"title":4},"82":{"body":16,"breadcrumbs":3,"title":2},"83":{"body":112,"breadcrumbs":3,"title":2},"84":{"body":17,"breadcrumbs":7,"title":6},"85":{"body":153,"breadcrumbs":4,"title":3},"86":{"body":43,"breadcrumbs":3,"title":2},"87":{"body":288,"breadcrumbs":3,"title":2},"88":{"body":222,"breadcrumbs":4,"title":3},"89":{"body":243,"breadcrumbs":4,"title":3},"9":{"body":113,"breadcrumbs":7,"title":6},"90":{"body":263,"breadcrumbs":4,"title":3},"91":{"body":103,"breadcrumbs":5,"title":4},"92":{"body":72,"breadcrumbs":2,"title":1},"93":{"body":29,"breadcrumbs":3,"title":2},"94":{"body":25,"breadcrumbs":4,"title":3},"95":{"body":17,"breadcrumbs":5,"title":4},"96":{"body":16,"breadcrumbs":6,"title":5},"97":{"body":34,"breadcrumbs":6,"title":5},"98":{"body":1,"breadcrumbs":3,"title":2},"99":{"body":0,"breadcrumbs":3,"title":2}},"docs":{"0":{"body":"Hi there! This website contains tutorials, how-to guides, explanations, and reference documentation of the things we do at Tech Start UCalgary . If you are looking for our main page, please visit us at techstartucalgary.com .","breadcrumbs":"Tech Start UCalgary Documentation » Introduction","id":"0","title":"Introduction"},"1":{"body":"Introduction We understand that setting up your computer for development can be a daunting task. There are so many tools and libraries that you need to install, and it's hard to know where to start. That's why we created this guide to help you get started with your development environment. Lost Kermit This guide will help you install all the tools you need to start coding. It will also help you configure your computer so that you can easily switch between different versions of Node.js and Python. Your don't need to install everything in this guide, only the tools you need for your project. If you are not sure what tools you need, ask your project lead or one of the exec members. Table of Contents Installfest: From zero to hero - Introduction - Table of Contents - Windows Users - Installing Homebrew - Installing VSCode: MacOS - Installing VSCode: Windows WSFL2 - Installing Git - Installing bash-completion - Installing Node - Installing Nvm - Installing Python - Installing Pip - Installing Pyenv - Downloading Xcode - That's it! Windows Users If you are using Windows, we recommend that you install WSL2 and Ubuntu as your development environment. You can find instructions on how to do so here: WSL2 Installation Once you have installed WSL2 and Ubuntu, you can continue with this guide. Installing Homebrew Homebrew is a package manager for macOS (or Linux) that allows you to easily install and manage software packages and libraries. It simplifies the installation process by automating the installation of dependencies and providing a consistent interface for installing software. To install Homebrew, run the following command: /bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\" If you are using Windows, run the following commands: test -d ~/.linuxbrew && eval \"$(~/.linuxbrew/bin/brew shellenv)\"\ntest -d /home/linuxbrew/.linuxbrew && eval \"$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)\"\ntest -r ~/.bash_profile && echo \"eval \\\"\\$($(brew --prefix)/bin/brew shellenv)\\\"\" >> ~/.bash_profile\necho \"eval \\\"\\$($(brew --prefix)/bin/brew shellenv)\\\"\" >> ~/.profile To check if Homebrew is installed, run the following command: brew --version It should return something like this: Homebrew 3.2.0\nHomebrew/homebrew-core (git revision 3b6; last commit 2021-07-26) Installing VSCode: MacOS Visual Studio Code is a free source-code editor made by Microsoft for Windows, Linux and macOS. Features include support for debugging, syntax highlighting, intelligent code completion, snippets, code refactoring, and embedded Git. To install VSCode, run the following command: brew install --cask visual-studio-code To check if VSCode is installed, run the following command: code --version Installing VSCode: Windows WSFL2 To install VSCode, download it from the following link: VSCode Installer Once downloaded, open VScode in Windows. Open the remote explorer by pressing Ctrl+Shift+P and typing View: Show Remote Explorer and selecting WSL Targets. Remote Explorer Then select Ubuntu 20.04 or the version of Ubuntu you installed. This will cause some reinstalling to happen, but once it's done, you will be able to use VSCode with Ubuntu. To check if WSL2 is connected with VSCode, go to the WSFL2 terminal and run the following command: code . Installing Git Git is a free and open-source distributed version control system designed to handle everything from small to very large projects with speed and efficiency. It is the most widely used modern version control system in the world today. To start using Git, you need to run the following command: brew install git To check if Git is installed, run the following command: git --version To configure Git, run the following commands: git config --global user.name \"YOUR_NAME\" git config --global user.email \"YOUR_EMAIL\" Then donwload the github cli: brew install gh and authenticate with your github account: gh auth login to check if it worked: gh auth status Installing bash-completion bash-completion is a collection of shell functions that take advantage of the programmable completion feature of bash. It provides completions for various commands, including git, npm, and others. To install bash-completion, run the following command: brew install bash-completion To configure bash-completion, run the following command: code ~/.bash_profile And add the following lines at the end of the file and save it: if [ -f $(brew --prefix)/etc/bash_completion ]; then . $(brew --prefix)/etc/bash_completion\nfi Installing Node Node.js is an open-source, cross-platform, back-end JavaScript runtime environment that runs on the V8 engine and executes JavaScript code outside a web browser. It allows developers to use JavaScript to write command-line tools and for server-side scripting—running scripts server-side to produce dynamic web page content before the page is sent to the user's web browser. To install Node, run the following command: brew install node To check if Node is installed, run the following command: node --version Installing Nvm nvm stands for Node Version Manager. It is a tool that allows you to easily install and manage multiple versions of Node.js on a single machine. This is useful for developers who need to work with different versions of Node.js for different projects. To install nvm, run the following command: brew install nvm To configure nvm, run the following command: mkdir ~/.nvm Then open your ~/.bash_profile using: code ~/.bash_profile And at the following lines at the end of the file and save it: export NVM_DIR=~/.nvm\nsource $(brew --prefix nvm)/nvm.sh Close and reopen your terminal. To check if nvm is installed, run the following command: nvm --version To change versions of node, run the following command: nvm install for example: nvm install 14.17.6 To see which version are available, run the following command: nvm ls-remote make sure you team is using the same version of node for consistency and to avoid errors. Installing Python Python is an interpreted, high-level, general-purpose programming language. Created by Guido van Rossum and first released in 1991, Python's design philosophy emphasizes code readability with its notable use of significant whitespace. To install Python, run the following command: brew install python By default, Homebrew installs Python 3.x. To check if Python is installed, run the following command: python3 --version Installing Pip pip is a package management system used to install and manage software packages written in Python. Many packages can be found in the Python Package Index (PyPI). brew install pip To check if pip is installed, run the following command: pip --version Installing Pyenv pyenv is a simple yet powerful tool that allows you to easily install and manage multiple versions of Python on a single machine. This is useful for developers who need to work with different versions of Python for different projects. Using pyenv will also allow you to group your project dependencies into a single virtual environments, which will make dependency management much easier. To install pyenv, run the following command: brew install pyenv To check if pyenv is installed, run the following command: pyenv --version pyenv will be useful for those who are working with Django or Flask. Downloading Xcode Recommended for those who are working with React Native. Xcode is an integrated development environment (IDE) for macOS containing a suite of software development tools developed by Apple for developing software for macOS, iOS, iPadOS, watchOS, and tvOS. To download Xcode, go to the App Store and search for Xcode . That's it! Now that you have installed all the tools you need, you are ready to start coding like a PRO. If you have any questions, feel free to ask your project lead or one of the exec members. Typing Kermit","breadcrumbs":"Installfest: from zero to hero » Installfest: From zero to hero","id":"1","title":"Installfest: From zero to hero"},"10":{"body":"My suggestion for this is to keep it simple. Avoid too many labels, statuses and complexity. First, create a Project (a RoadMap) on GitHub. This is usually under the Projects tab in the organization view: New Project on GitHub Then define some statuses: Status Field 🆕 New : Where you place all of the issues initially. 📋 Backlog : The issues that are yet to be done, and their priority. 🏗 In progress : The issues that are being worked on, and who's working on them. ✅ Done : The issues that have been shipped. Then, create a priority field: Priority Field This will help your team focus on the things that are more impactful to your project. You can use the Eisenhower matrix for this: 🌋 High priority : Issues that are important and urgent. 🏔 Medium priority : Issues that are important, but not urgent. 🏕 Low priority : Issues that are not important, but may be nice to have someday. 🏝 Never priority : Just close the issue :) don't waste your time on this. Now you can start adding Issues to your RoadMap: Makes RoadMap And see what is the progress towards each Milestone, for example: Milestones Progress","breadcrumbs":"A RoadMap » Step 3 - Add your Issues to the RoadMap","id":"10","title":"Step 3 - Add your Issues to the RoadMap"},"100":{"body":"Tutorial","breadcrumbs":"Git » Git Clean","id":"100","title":"Git Clean"},"101":{"body":"","breadcrumbs":"Git » 🚧 Under Construction 🚧","id":"101","title":"🚧 Under Construction 🚧"},"102":{"body":"Below is the general sequence of commands to check, and undo previous commits. Notice that we must use the commit comments as the easiest factor in differentiating between commits. It is important to use a descriptive comment for each commit.","breadcrumbs":"Git » Undoing Commits & Changes","id":"102","title":"Undoing Commits & Changes"},"103":{"body":"Displays old commits with the ID hash and commit comment on the current branch. git checkout [id hash] Will make your working directory match the exact state of the id’ed commit. Nothing you do here will be saved to the current state of the project (to go back do git checkout main).","breadcrumbs":"Git » git log","id":"103","title":"git log"},"104":{"body":"git clean -n shows which UNTRACKED files will be removed, should you do git clean -f. Good practice is to always -n before you -f. Learn more (-n) runs a dry run (previews what files would be removed). (-f) to force untracked file detection (removes the files).","breadcrumbs":"Git » git clean (-f) (-n)","id":"104","title":"git clean (-f) (-n)"},"105":{"body":"Undoes a single commit. git reset [id hash] Goes back to the specified commit by removing all subsequent commits.","breadcrumbs":"Git » git revert","id":"105","title":"git revert"},"106":{"body":"","breadcrumbs":"Git » Git Rebase and Git Merge","id":"106","title":"Git Rebase and Git Merge"},"107":{"body":"Merges the specified branch into the branch that your local directory is currently on. In a typical workflow, you will not need to use this command ever. Instead, git pull and pull requests will handle all merging for you.","breadcrumbs":"Git » git merge [branchName]","id":"107","title":"git merge [branchName]"},"108":{"body":"","breadcrumbs":"Git » 🚧 Under Construction 🚧","id":"108","title":"🚧 Under Construction 🚧"},"109":{"body":"alt_text APIs are a ubiquitous component of software engineering. APIs allow different components of a software system to interact with each other in a logical way. Learning about APIs is critical to your growth as a software developer. This guide contains links and advice to get you started!","breadcrumbs":"APIs » Tech Start's API Guide","id":"109","title":"Tech Start's API Guide"},"11":{"body":"All Tech Start UCalgary projects are showcased to the world at the end of each academic year. At this event, people from different industries and backgrounds come and give us feedback on the projects. This is also a great opportunity for you as a professional and us as a club to connect and network with different companies. It's important to remember that as an entrepreneurial club, you will also be pitching your ideas to potential investors, so your hard work on the business strategy will be on display here. Pitching your start-up in a convincing manner is a critical skill, so we also give you the opportunity to practice this. This year's showcase is scheduled for April 27th, 2024 . To prepare for this, we want each team to demo and pitch their project to the club before the showcase. This will help you get experience and valuable feedback from fellow project teams, execs, and our partners in industry.","breadcrumbs":"Demos » Demo & Pitch Nights","id":"11","title":"Demo & Pitch Nights"},"110":{"body":"What is an API? alt_text API stands for Application Programming Interface, and in simple words, allows two applications to talk to each other and send information between the two. Further reading on the basics of APIs: https://www.plektonlabs.com/api-101-what-are-they-and-how-do-they-work/?gclid=Cj0KCQiAhf2MBhDNARIsAKXU5GRbLqWDWBPN0Zh4ZX6KwjevURl9KmQo0EVBzLn5mcePxaI_l1oWQSQaAkGDEALw_wcB Analogy of an API Imagine you are sitting in a restaurant with a menu and you are trying to decide what to order. You are one of the applications and in order to get food, the kitchen will act like the other application. It is the system that will “make” you food. The waiter in this scenario will be the API, and he/she delivers the food from one application(the kitchen) to another(you). The waiter is the messenger that takes your request or order and tells the kitchen – the system – what to do. Then the waiter delivers the response back to you; in this case, it is the food. How API’s Work A client application initiates an API call to retrieve information—also known as a request. This request is processed from an application to the web server via the API’s Uniform Resource Identifier (URI) and includes a request verb(see Types of API calls), headers, and sometimes, a request body. After receiving a valid request, the API makes a call to the external program or web server. The server sends a response to the API with the requested information. The API transfers the data to the initial application that requested the information. Why would you need an API? Many companies have APIs built to allow others to build interesting applications using their company data. APIs also allows a project to be dynamic - it will update the frontend information automatically when the back end is updated. This saves the hassle of going through tons of HTML code updating data one by one.","breadcrumbs":"APIs » Introduction","id":"110","title":"Introduction"},"111":{"body":"GraphQL vs Rest Reading In favor of GraphQl: https://www.howtographql.com/basics/1-graphql-is-the-better-rest/ Reading In favor of Rest: https://www.rubrik.com/blog/technology/19/11/graphql-vs-rest-apis","breadcrumbs":"APIs » Types of APIs","id":"111","title":"Types of APIs"},"112":{"body":"About https://www.ibm.com/cloud/learn/rest-apis A REST API is an API that conforms to the design principles of the REST, or representational state transfer architectural style. For this reason, REST APIs are sometimes referred to RESTful APIs. What is a RESTful API? https://www.youtube.com/watch?v=y0U-ZxgLu98 Types of API calls alt_text","breadcrumbs":"APIs » Rest APIs","id":"112","title":"Rest APIs"},"113":{"body":"Interactive Resource on APIs https://apiary.io/how-to-build-api#phase-design Tons of help on creating API with different languages https://rapidapi.com/blog/20-tutorials-on-how-to-create-your-own-api-sorted-by-programming-la nguage/ Explanations of API’s and more in depth language-specific resources https://www.moesif.com/blog/api-guide/getting-started-with-apis/","breadcrumbs":"APIs » Creating your own API","id":"113","title":"Creating your own API"},"114":{"body":"What is Postman? Postman is a platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs faster. Getting Started with Postman: https://www.guru99.com/postman-tutorial.html#1 Good Postman Series starting with setting up: https://www.youtube.com/watch?v=juldrxDrSH0&ab_channel=AutomationStepbyStep","breadcrumbs":"APIs » Using Postman","id":"114","title":"Using Postman"},"115":{"body":"Collection of Free, premade API’s Most premade API’s will have documentation of how to use/maintain them https://github.com/public-apis/public-apis https://any-api.com/ Example of using a premade API https://rapidapi.com/blog/how-to-use-an-api/","breadcrumbs":"APIs » Further Resources on APIs","id":"115","title":"Further Resources on APIs"},"116":{"body":"Further Help GraphQL Tutorial: https://www.youtube.com/watch?v=ed8SzALpx1Q&ab_channel=freeCodeCamp.org What is GraphQL (A really good article): https://www.redhat.com/en/topics/api/what-is-graphql Why use GraphQL: https://www.apollographql.com/docs/intro/benefits/ Getting started with GraphQL: https://www.apollographql.com/docs/intro/benefits/ GraphQL is split into two main parts, A Schema (Basically a model for the response), and a resolver (a collection of functions that generate response for a GraphQL query. In simple terms, a resolver acts as a GraphQL query handler) An article that explains what a Query, Mutation & Subscription are: https://medium.com/software-insight/graphql-queries-mutations-and-subscriptions-286522b263d9","breadcrumbs":"APIs » GraphQL","id":"116","title":"GraphQL"},"117":{"body":"","breadcrumbs":"React » Tech Start's React Guide","id":"117","title":"Tech Start's React Guide"},"118":{"body":"alt_text React Main Concepts Video (If you don't Like Reading) Components JSX Rendering Props State Lifecycle Methods Handling Events Conditional Rendering Lists and Keys JavaScript For React Arrow Functions Classes Callbacks Promise Await/Async More React Events Higher Order Components Props vs State Hooks React Ecosystem Handling API Requests React Router Redux Next.js","breadcrumbs":"React » » React Main Concepts","id":"118","title":"React Main Concepts"},"119":{"body":"Check out this video as a crash course to React: https://www.youtube.com/watch ?v=Ke90Tje7VS0 If you find this video confusing, or prefer a different one as a React intro, please let us know :) If you prefer reading to watching videos, this guide is helpful:","breadcrumbs":"React » » React Video","id":"119","title":"React Video"},"12":{"body":"Date Event Audience Location 30 November 2023 Demo & Pitch Night 1 Project Teams & Execs ENC 201 29 February 2024 Demo & Pitch Night 2 Tech Start & Industry Guests ENC 201 Early April Demo & Pitch Night 3 TBD TBD 27 April 2024 Final Showcase Open to the Public Hunter Hub Collision Space","breadcrumbs":"Demos » Dates to Remember","id":"12","title":"Dates to Remember"},"120":{"body":"React is built around the concept of components. Components are reusable, self-contained units that encapsulate the UI and behavior of a part of the application. React applications are typically composed of many components. function MyComponent() { return
Hello, World!
;\n}","breadcrumbs":"React » » Components","id":"120","title":"Components"},"121":{"body":"JSX (JavaScript XML) is a syntax extension for JavaScript that allows you to write HTML-like code within your JavaScript. It's used in React to define the structure of components. const element =

Hello, world!

;","breadcrumbs":"React » » JSX","id":"121","title":"JSX"},"122":{"body":"React renders components into the DOM (Document Object Model). You can use the ReactDOM library to render a component into a specific HTML element. ReactDOM.render(, document.getElementById('root'));","breadcrumbs":"React » » Rendering","id":"122","title":"Rendering"},"123":{"body":"Props (short for properties) allow you to pass data from a parent component to a child component. This enables you to create dynamic and reusable components. function Greeting(props) { return
Hello, {props.name}
;\n}","breadcrumbs":"React » » Props","id":"123","title":"Props"},"124":{"body":"State is a way to store and manage data that can change over time. It is used to make components dynamic and interactive. class Counter extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; }\n}","breadcrumbs":"React » » State","id":"124","title":"State"},"125":{"body":"React components have a lifecycle, and you can use lifecycle methods to perform actions at various stages of a component's existence. For example, componentDidMount is called after a component is rendered. componentDidMount() { // Perform initialization after rendering.\n}","breadcrumbs":"React » » Lifecycle Methods","id":"125","title":"Lifecycle Methods"},"126":{"body":"You can define event handlers in React components to respond to user interactions, such as clicks or input changes. function Button() { function handleClick() { console.log('Button clicked'); } return ;\n}","breadcrumbs":"React » » Handling Events","id":"126","title":"Handling Events"},"127":{"body":"You can use conditional statements and expressions to conditionally render different parts of a component based on certain conditions. function Greeting(props) { if (props.isLoggedIn) { return
Welcome, User!
; } else { return
Please log in.
; }\n}","breadcrumbs":"React » » Conditional Rendering","id":"127","title":"Conditional Rendering"},"128":{"body":"React provides a way to render lists of elements efficiently and assigns unique keys to each item in the list for optimization. const numbers = [1, 2, 3, 4, 5];\nconst listItems = numbers.map((number) =>
  • {number}
  • ); React utilizes several JavaScript features and concepts like arrow functions, classes, callbacks, promises, and async/await to create dynamic and interactive user interfaces. Let's explore each of these in detail and discuss how they are related and integrated in React:","breadcrumbs":"React » » Lists and Keys","id":"128","title":"Lists and Keys"},"129":{"body":"Arrow functions, classes, callbacks, promises, and async/await are fundamental JavaScript concepts that are commonly used in React. Let's explore each of these topics and how they are related and integrated in React:","breadcrumbs":"React » » Javascript For React:","id":"129","title":"Javascript For React:"},"13":{"body":"","breadcrumbs":"Demos » Demo 1 » Demo & Pitch Night 1","id":"13","title":"Demo & Pitch Night 1"},"130":{"body":"Arrow functions are a concise way to write functions in JavaScript. They are commonly used in React for defining components and functions, as they have a more compact syntax compared to traditional function expressions. Arrow functions capture the this value of the enclosing context automatically, making them suitable for working within React components and event handlers. Example of an arrow function defining a React component: const MyComponent = () => { return
    Hello, World!
    ;\n};","breadcrumbs":"React » » Arrow Functions:","id":"130","title":"Arrow Functions:"},"131":{"body":"Classes in JavaScript are used to define and create objects with methods and properties. In React, components are often defined as classes, especially when they need to manage component state and lifecycle methods. React class components extend the React.Component class and can have methods like render, componentDidMount, and more for handling component behavior. Example of a React class component: class MyComponent extends React.Component { render() { return
    Hello, World!
    ; }\n} **Note on functional versus class-based components** When React was first created, class-based components were the standard. But functional components were introduced later, and they eclipse class-based components in every way. Our advice: Ironically, you should probably never use class-based components! Stick to functional components. They are more modern and more versatile. Lots of tutorial content online still uses class-based components. If you stumble upon a tutorial or explanation that uses a class-based component, and you're new to React, please search for a functional-component alternative instead!","breadcrumbs":"React » » Classes:","id":"131","title":"Classes:"},"132":{"body":"Callbacks are functions that are passed as arguments to other functions and are executed at a later time or in response to an event. React uses callbacks extensively, especially in event handling. For example, you can pass callback functions to event handlers to respond to user interactions. Example of a callback function for handling a button click: function handleClick() { console.log('Button clicked');\n} ","breadcrumbs":"React » » Callbacks:","id":"132","title":"Callbacks:"},"133":{"body":"Promises are a way to handle asynchronous operations in JavaScript. They represent a value that might be available now, or in the future, or never. Promises have three states: pending, fulfilled, and rejected. Creating Promises: You can create a promise using the Promise constructor. It takes a function with two arguments: resolve and reject. You typically perform an asynchronous operation in this function and call resolve when the operation is successful or reject when it fails. const myPromise = new Promise((resolve, reject) => { // Asynchronous operation if (operationSucceeded) { resolve(result); } else { reject(error); }\n}); Chaining Promises: Promises can be chained together using .then() and .catch() to handle the resolved value or errors. This chaining allows you to compose complex asynchronous operations. myPromise .then((result) => { // Handle success }) .catch((error) => { // Handle error });","breadcrumbs":"React » » Promises:","id":"133","title":"Promises:"},"134":{"body":"async and await are modern JavaScript features for working with asynchronous code. They make asynchronous code more readable and maintainable. async Function: An async function is a function that always returns a promise. It allows you to use the await keyword inside the function to pause execution until the promise is resolved. async function fetchData() { const data = await fetch('https://api.example.com/data'); return data.json();\n} await Keyword: The await keyword can only be used inside an async function. It pauses the execution of the function until the promise is resolved, and it returns the resolved value. const result = await myPromise;\n// The code here will not execute until myPromise is resolved.","breadcrumbs":"React » » async/await:","id":"134","title":"async/await:"},"135":{"body":"React applications often involve asynchronous operations, such as fetching data from APIs or making network requests. Promises, async/await, and React's lifecycle methods can be integrated for managing asynchronous tasks effectively: Fetching Data: You can use async/await to fetch data in React components. Typically, you do this inside componentDidMount() or within functional components using the useEffect hook. async componentDidMount() { try { const response = await fetch('https://api.example.com/data'); const data = await response.json(); this.setState({ data }); } catch (error) { console.error('Error fetching data:', error); }\n} Updating Component State: Once the data is fetched, you can update the component state to trigger a re-render with the new data. Handling Errors: Use try/catch to handle errors gracefully. You can also integrate error boundaries in React to catch errors in the component tree. Using Promises: React works well with Promises, and you can use .then() and .catch() to manage asynchronous operations. However, async/await is often preferred for its more readable and synchronous-like syntax. Integrating Promises and async/await in React allows you to manage asynchronous operations in a clean and structured way, providing a better user experience by preventing UI blocking during data retrieval.","breadcrumbs":"React » » Promises and Aysnc/Await Integration in React:","id":"135","title":"Promises and Aysnc/Await Integration in React:"},"136":{"body":"","breadcrumbs":"React » » More React:","id":"136","title":"More React:"},"137":{"body":"","breadcrumbs":"React » » Events in React","id":"137","title":"Events in React"},"138":{"body":"In React, events are used to capture and respond to user interactions, such as clicks, input changes, and mouse movements. Event handling in React is similar to handling events in traditional HTML, but there are some differences due to React's synthetic event system. In React, you define event handlers as functions and attach them to JSX elements using event attributes. Here's an example of how you might handle a click event in React: function Button() { function handleClick() { console.log('Button clicked'); } return ;\n} The onClick attribute specifies the event handler function, handleClick, which will be executed when the button is clicked. React's synthetic event system provides a consistent API for handling events across different browsers.","breadcrumbs":"React » » Event Handling","id":"138","title":"Event Handling"},"139":{"body":"In React, event handlers are passed an event object as an argument. This object contains information about the event, such as the type of event, target element, and any event-specific data. You can access event properties and methods within your event handler functions. function handleChange(event) { console.log('Input value:', event.target.value);\n}","breadcrumbs":"React » » Event Object","id":"139","title":"Event Object"},"14":{"body":"","breadcrumbs":"Demos » Demo 1 » 30 November 2023","id":"14","title":"30 November 2023"},"140":{"body":"","breadcrumbs":"React » » Higher Order Components (HOCs) in React","id":"140","title":"Higher Order Components (HOCs) in React"},"141":{"body":"Higher Order Components are a design pattern in React that allows you to reuse component logic by wrapping one or more components with a higher-order component. HOCs are not a part of the React API; they are a pattern that leverages the composability of components.","breadcrumbs":"React » » What Are HOCs?","id":"141","title":"What Are HOCs?"},"142":{"body":"HOCs are functions that take a component and return a new enhanced component. They can add props, modify behavior, or encapsulate certain functionality. For example, you might create an HOC that provides authentication, access control, or data fetching capabilities to a component. Here's a simplified example of a higher order component that provides a \"loading\" indicator to a component: function withLoadingIndicator(WrappedComponent) { return function WithLoadingIndicator(props) { if (props.isLoading) { return
    Loading...
    ; } return ; };\n}","breadcrumbs":"React » » How HOCs Work","id":"142","title":"How HOCs Work"},"143":{"body":"You can use an HOC by wrapping your component with it. For instance, suppose you have a component called MyComponent, and you want to add a loading indicator using the withLoadingIndicator HOC: const MyComponentWithLoading = withLoadingIndicator(MyComponent); Now, MyComponentWithLoading is a new component that includes the loading indicator logic from the HOC. You can render it as you would with any other component. ","breadcrumbs":"React » » Using HOCs","id":"143","title":"Using HOCs"},"144":{"body":"HOCs enable you to separate concerns and promote reusability. They help you avoid code duplication by encapsulating common functionality in a separate function. This makes your code more maintainable and flexible, allowing you to compose and extend component behavior as needed.","breadcrumbs":"React » » Benefits of HOCs","id":"144","title":"Benefits of HOCs"},"145":{"body":"Events and HOCs can work together in a React application. For instance, you might create an HOC that handles common event-related logic, such as tracking user interactions, and then wrap components that need that behavior. This can help centralize event handling logic and make it reusable across multiple components. Additionally, you can pass event handling functions as props when composing components with HOCs, allowing for flexible customization of event behavior. In summary, events in React are essential for capturing and responding to user interactions, while Higher Order Components are a design pattern that promotes reusability and composability of component logic. You can use HOCs to encapsulate and extend event-related logic, making it easier to manage event handling across your React application.","breadcrumbs":"React » » Relationship Between Events and HOCs","id":"145","title":"Relationship Between Events and HOCs"},"146":{"body":"Props and state are two fundamental concepts in React, and they play distinct roles in how components work.","breadcrumbs":"React » » Props vs. State","id":"146","title":"Props vs. State"},"147":{"body":"Props (short for properties) are a mechanism for passing data from a parent component to a child component. Props are read-only, meaning that the child component cannot modify the props it receives. They are used to customize or configure child components based on data from their parent. Example of using props: function Greeting(props) { return
    Hello, {props.name}
    ;\n}","breadcrumbs":"React » » Props","id":"147","title":"Props"},"148":{"body":"State is a way to store and manage data that can change over time within a component. State is used to make components dynamic and interactive. Unlike props, state is mutable, and components can change their internal state using the setState method. State is often used for data that the component needs to keep track of, such as user input or UI state. Example of using state: class Counter extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } render() { return (

    Count: {this.state.count}

    ); }\n}","breadcrumbs":"React » » State","id":"148","title":"State"},"149":{"body":"Props and state are often used together to create dynamic and interactive React applications. Here's how they relate and are integrated: Passing Data : Props are used to pass data from a parent component to its child components. This data can be initial data that a child component uses to render itself. Updating Data : State is used to manage data that can change within a component. Components can have state and use it to keep track of user interactions, input, or changes in data. Reactivity : When a parent component passes props to a child component, any changes to those props in the parent will re-render the child. This allows for dynamic updates. State Management : State is local to the component that owns it, and changes in state trigger re-renders of that component, updating the UI as needed. Lifting State : Sometimes, you might need to manage state at a higher level in the component tree and pass it down as props to child components. This is called \"lifting state up.\" In summary, props are for passing data from parent to child, while state is for managing data that can change within a component. Together, they enable you to build interactive and data-driven React applications. Hooks, especially the useState hook, make it easier to manage local state in functional components, further enhancing the capabilities of React functional components.","breadcrumbs":"React » » How They Relate and Are Integrated","id":"149","title":"How They Relate and Are Integrated"},"15":{"body":"Demos are intended to be a check-in of your progress so far and a way for your whole team to show off their work, as well as an opportunity to practice pitching your project to the public. This will also let us understand your progress and blockers in order to help you best. Since Tech Start is built off 3 pillars, development, strategy, and design, the demos will also focus on these 3 aspects. Feel free to divide the allocated time between them as you see fit. In addition, there may or may not be pizza or snacks present.","breadcrumbs":"Demos » Demo 1 » Objectives","id":"15","title":"Objectives"},"150":{"body":"React introduced Hooks in version 16.8 as a way to add state and side-effects to functional components, which were previously limited to stateless rendering. In React, \"stateless rendering\" refers to the practice of creating functional components (also known as stateless functional components) that are purely responsible for rendering UI based on the input data provided through props. These components do not manage or maintain any internal state. Out with the old in with the new KING, hooks allow you to reuse stateful logic and side-effects across components, making functional components more powerful and flexible. Some of the most commonly used hooks include:","breadcrumbs":"React » » Hooks in Functional Components","id":"150","title":"Hooks in Functional Components"},"151":{"body":"This one might sound familiar from above, useState hook allows functional components to manage local state. It takes an initial state value and returns an array with the current state and a function to update it. import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); return (

    Count: {count}

    );\n}","breadcrumbs":"React » » 1. useState","id":"151","title":"1. useState"},"152":{"body":"The useEffect hook enables you to perform side-effects in functional components. It takes a function that will be executed after every render, and you can specify dependencies to control when the effect should run. import React, { useEffect, useState } from 'react'; function Example() { const [data, setData] = useState([]); useEffect(() => { // Fetch data from an API and update the state fetchData().then((result) => setData(result)); }, []); // Empty dependency array runs the effect only once\n}","breadcrumbs":"React » » 2. useEffect","id":"152","title":"2. useEffect"},"153":{"body":"React provides several other built-in hooks, such as useContext and useReducer, which allow you to manage context, state transitions, and references in functional components, respectively. useContext: Allows you to access the context API within functional components. It's useful for sharing data across the component tree without prop drilling. import React, { useContext } from 'react'; const ThemeContext = React.createContext('light'); function ThemedButton() { const theme = useContext(ThemeContext); return ;\n} useReducer: This hook is used for more complex state management and state transitions. It's similar to setState but offers more control over how state updates occur. import React, { useReducer } from 'react'; const initialState = { count: 0 }; function counterReducer(state, action) { switch (action.type) { case 'increment': return { count: state.count + 1 }; case 'decrement': return { count: state.count - 1 }; default: return state; }\n} function Counter() { const [state, dispatch] = useReducer(counterReducer, initialState); return (

    Count: {state.count}

    );\n}","breadcrumbs":"React » » 3. Other Built-in Hooks","id":"153","title":"3. Other Built-in Hooks"},"154":{"body":"You can create your own custom hooks to encapsulate and share component logic across different components. Custom hooks promote code reuse and maintainability. // Custom hook for handling form input state\nimport { useState } from 'react'; function useFormInput(initialValue) { const [value, setValue] = useState(initialValue); const handleChange = (e) => { setValue(e.target.value); }; return { value, onChange: handleChange, };\n} In summary, hooks in React are a way to manage state and side-effects in functional components. They integrate seamlessly with functional components, making it easier to write and maintain complex logic and enabling better code reuse. React's built-in hooks and the ability to create custom hooks provide a powerful toolset for building dynamic and interactive applications. Great Resources(videos): https://www.youtube.com/watch?v=Jl4q2cccwf0&ab_channel=TheNetNinja useState: https://www.youtube.com/watch?v=4qVNaohzDWU&ab_channel=LogRocket useEffect: https://www.youtube.com/watch?v=gv9ugDJ1ynU&ab_channel=TheNetNinja useRef: https://www.youtube.com/watch?v=yCS2m01bQ6w&ab_channel=Codevolution useCallback: https://www.youtube.com/watch?v=-Ls48dd-vJE&ab_channel=BenAwad","breadcrumbs":"React » » 4. Custom Hooks","id":"154","title":"4. Custom Hooks"},"155":{"body":"","breadcrumbs":"React » » React Ecosystem","id":"155","title":"React Ecosystem"},"156":{"body":"Calling APIs is a key part of any React App. It's what enables your app to communicate with the outside world - including, presumably, your backend. Here's a helpful tutorial on the best practices for calling APIs in React: https://www.youtube.com/watch?v=bYFYF2GnMy8 There's also a part 2: https://www.youtube.com/watch?v=1tfd6ANaNRY The best ways to fetch data are using the popular package Axos ( https://www.npmjs.com/package/axios ) or the vanilla JS _fetch _function ( https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch ) Once you have parsed the data, you'll probably want to store it in your state somehow (using useState or a redux store). It is also good practice to encapsulate your entire API call into a custom hook, and name the hook according to what it does (ex. useFetchPokemonStats ). This is also much easier to do if you use a state-management system like Redux, which is described below. The methods described above let you call an API immediately upon rendering a certain component. But what happens if you want to manually trigger an API call (ex. after a certain action or event)? Your API call should still use useEffect, and should look mostly like the calls you learned about in Part 1. The 1 difference is you need to guard the useEffect wisely in its dependency array. As you recall, the dependency array of a useEffect contains everything that the useEffect depends upon - if any of its dependencies change, it will have a _side effect _of rerunning the useEffect. So, you can define a specific variable which only changes when you want your API call to run. You can put that variable in the dependency array of the useEffect. When the action or event that you want to trigger the API call occurs, you should change the trigger variable. This change will trigger the useEffect to run. The trigger variable should never change except when you want the useEffect to run. I personally like making my trigger variable an object which also contains any subvariables that my API call needs. So for example, if I was coding a call to a search API that included a text query and target price, my trigger object would contain those. Here is an example of a very basic React application that calls an API to perform a search with a custom hook and a useEffect guarded by a trigger object as described above: https://github.com/Tech-Start-UCalgary/react-api-examples/tree/main/js-no-redux","breadcrumbs":"React » » Calling APIs","id":"156","title":"Calling APIs"},"157":{"body":"alt_text useSWR is a useful React hook for data fetching published by Vercel (creators of Next.js). SWR stands for stale-while-revalidate. It allows for smart data fetching and encapsulates a lot of advanced fetching logic (like how often should you refetch? should you have a cache?) in a single line of code. You should read more about useSWR here: https://swr.vercel.app/ You can watch a video tutorial here: https://www.youtube.com/watch?v=f7yjEdXgGiM","breadcrumbs":"React » » useSWR","id":"157","title":"useSWR"},"158":{"body":"React Router is a popular library used for routing in React applications. Routing is the process of determining which UI components should be displayed based on the current URL or path. React Router helps you create single-page applications with multiple views and navigate between them without requiring full page reloads. Here's an elaboration on React Router and its integration with React:","breadcrumbs":"React » » React Router","id":"158","title":"React Router"},"159":{"body":"Declarative Routing: React Router uses a declarative approach, where you define the routes and their corresponding components in a clear and organized manner. You specify what component should be rendered when a particular URL is matched. Nested Routing: React Router supports nested routes, allowing you to create complex and hierarchical UI structures. This is especially useful for building multi-level menus or complex application layouts. Route Parameters: You can define route parameters in your routes, allowing you to extract dynamic data from the URL. For example, a route like /users/:id can capture the id as a parameter. Programmatic Navigation: React Router provides a set of functions for programmatic navigation. You can change the route, push to the browser's history, or replace the current route using these functions. This is useful for actions like form submissions or after successful authentication. Route Guards: React Router allows you to implement route guards for protecting routes based on user authentication or other conditions. This ensures that users can only access certain routes if they meet specific criteria.","breadcrumbs":"React » » React Router Features:","id":"159","title":"React Router Features:"},"16":{"body":"","breadcrumbs":"Demos » Demo 1 » Time Limit: 15 minutes","id":"16","title":"Time Limit: 15 minutes"},"160":{"body":"React Router is typically integrated into a React application as a separate library. Here's how it's commonly done: Installation: You start by installing React Router as a package in your React project. You can use either react-router-dom (for web applications) or react-router-native (for mobile applications). npm install react-router-dom Router Component: You wrap your entire application (or a part of it) with a or component provided by React Router. This component manages the application's navigation state and listens to changes in the URL. import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; function App() { return ( {/* Define your routes here */} );\n} Route Configuration: Inside the , you define your routes using the component. Each component specifies a path and the component to render when the path matches. \n Route Navigation: To navigate between routes, you use the component to create links or the history object to programmatically navigate. Home\n// OR\nhistory.push('/home'); Route Parameters: You can use route parameters to capture dynamic values from the URL. These parameters are accessible as props in the routed components. Nested Routes: You can nest routes by defining routes within the components rendered by other routes. This allows for hierarchical routing structures. \n By integrating React Router into your React application, you can create well-organized, client-side routing that provides a seamless and efficient user experience for navigating different parts of your application.","breadcrumbs":"React » » Integration with React:","id":"160","title":"Integration with React:"},"161":{"body":"Redux is a widely used state container for javascript apps. As soon as your app reaches any level of data complexity, it makes a ton of sense to start using Redux to manage your state. A fair warning: Redux will seem complicated at the beginning. That's completely expected! Push through that initial discomfort and you'll get used to it in no time :) Here is a great introductory video to React-Redux: https://www.youtube.com/watch?v=CVpUuw9XSjY I highly recommend using **createSlice to setup your Redux Store . **It is a simple way to encapsulate creating actions and slicers in a simple, easy-to-read, easy-to-understand way. Here is a short video that does a great job explaining how to use createSlice: https://www.youtube.com/watch?v=e0MEtFaQTZk To access your Redux state and update your Redux state in React, I highly recommend using the twin hooks **useSelector **and useDispatch respectively. They are simple, easy, and elegant. https://www.youtube.com/watch?v=3zoIigieur0","breadcrumbs":"React » » React with Redux","id":"161","title":"React with Redux"},"162":{"body":"Next.js is a framework built on top of React, designed to simplify and enhance the development of web applications. It provides several features and benefits while seamlessly integrating with React. Let's explore these aspects interactively: Q1: What is Next.js? Next.js is a framework for building web applications that are built on top of the React library. It simplifies many aspects of React development and adds capabilities for server-side rendering, routing, and more. Q2: How does Next.js relate to React? Next.js is an extension of React. It leverages React's component-based structure and allows you to build React applications while providing additional tools and features for server-side rendering, routing, and other optimizations. Q3: What are some key features of Next.js? Next.js offers several key features: Server-Side Rendering (SSR): Next.js enables server-side rendering, which improves performance and SEO by rendering pages on the server before sending them to the client. Routing: It includes a built-in routing system, so you can easily define and navigate between pages. File-Based Routing: Routes are created based on the file structure, making it intuitive and easy to organize your application. Automatic Code Splitting: It automatically splits your JavaScript code into smaller, more manageable chunks, optimizing loading times. Static Site Generation (SSG): Next.js allows you to generate static HTML files at build time for even better performance and SEO. Q4: How do you create a new Next.js app? To create a new Next.js app, you can use the following commands: npx create-next-app my-nextjs-app\ncd my-nextjs-app\nnpm run dev This will set up a new Next.js application and start the development server. Q5: Can you explain the pages and routing in Next.js? In Next.js, you create pages by simply adding files to the pages directory. Each file becomes a route. For example, if you create pages/about.js, you will have a route at /about. Q6: How does Next.js handle data fetching? Next.js allows you to fetch data during server-side rendering using the getServerSideProps function. This data can be injected into your React components as props. export async function getServerSideProps() { // Fetch data from an API or database const data = await fetchData(); return { props: { data }, };\n} Q7: What's the advantage of server-side rendering in Next.js? Server-side rendering in Next.js improves the initial loading speed of your application and helps with search engine optimization (SEO). It also ensures that users see content more quickly. Q8: How can I build a static website with Next.js? Next.js provides static site generation (SSG) via the getStaticProps function. You can generate static HTML files for your pages at build time. export async function getStaticProps() { // Fetch data from an API or database const data = await fetchData(); return { props: { data }, };\n} Q9: Are there any limitations or trade-offs with Next.js? While Next.js offers many advantages, it may introduce complexity to smaller projects. It requires server-side rendering, which might not be necessary for all applications. Q10: Can I deploy Next.js applications to various hosting platforms? Yes, you can deploy Next.js applications to a wide range of hosting platforms, including Vercel, Netlify, and AWS. These platforms often provide built-in support for Next.js, making deployment straightforward. Next.js is a powerful tool that enhances React applications by providing features like server-side rendering, routing, and automatic code splitting. It simplifies the development process and improves performance. If you have more specific questions or need further information about Next.js, feel free to ask!","breadcrumbs":"React » » Lastly, Next.JS","id":"162","title":"Lastly, Next.JS"},"163":{"body":"Please get acquainted with our React Guide before you read this page, this is just a recommendation though. Transitioning from a good background in React to React Native is a relatively smooth process, as many concepts carry over. However, there are specific topics and components you should learn to effectively work with React Native. Here's an outline of the topics you need to cover: Video Resources (If you don't Like Reading) React Native Basics Main Concepts Components Styling Layout Navigation Platform-Specific Code Accessing Device Features Native Modules and Bridges State Management Async Storage Network Requests Advanced Topics; Debugging and Troubleshooting Testing Performance Optimization Publishing and Deployment Third-Party Integration Security conclusion","breadcrumbs":"React Native » Tech Start's React Native Guide","id":"163","title":"Tech Start's React Native Guide"},"164":{"body":"These tutorials should be sufficient to get started but this guide gives many more subtle topics that are not covered in these videos. Choose your weapon wisely. https://www.youtube.com/playlist?list=PL4cUxeGkcC9ixPU-QkScoRBVxtPPzVjrQ https://www.youtube.com/watch?v=0-S5a0eXPoc","breadcrumbs":"React Native » Video Resources:","id":"164","title":"Video Resources:"},"165":{"body":"","breadcrumbs":"React Native » React Native Basics:","id":"165","title":"React Native Basics:"},"166":{"body":"Components in React Native are similar to those in React, but with some variations and additional elements. Here's a more detailed breakdown: 1. Core Components: React Native provides a set of core components that are similar to HTML elements. These include: View: The fundamental component for creating UI layouts. Text: Used for displaying text. Image: For displaying images. ScrollView: For scrollable content. TextInput: For text input fields. And many more. 2. Custom Components: You can create your custom components just like in React. These components can be stateless functional components or class components. To create a custom component, use the View, Text, Image, and other core components to compose your UI.","breadcrumbs":"React Native » Components in React Native","id":"166","title":"Components in React Native"},"167":{"body":"Styling in React Native is different from traditional web development. You have various options for styling your components: a. Inline Styles: React Native supports inline styles using JavaScript objects. You can apply styles directly to components, like this: Hello, React Native!\n b. Stylesheets: Using stylesheets, you can create reusable style definitions: const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: 'lightblue', }, text: { fontSize: 20, color: 'black', },\n}); Hello, React Native!\n c. Flexbox Layout: React Native relies heavily on flexbox for layout design. It's similar to CSS flexbox but with a few differences. You can use properties like flex, alignItems, and justifyContent to control layout. Hello, React Native!\n","breadcrumbs":"React Native » Styling in React Native","id":"167","title":"Styling in React Native"},"168":{"body":"Understanding layout is vital in React Native to create responsive and visually appealing designs. Flexbox Layout: Flexbox is the primary layout system in React Native. It allows you to design flexible and adaptive layouts. Key properties include: flex: Determines how space is distributed among children. alignItems: Aligns items along the cross-axis (vertical alignment). justifyContent: Aligns items along the main axis (horizontal alignment). flexDirection: Sets the direction of the main axis. Positioning: You can control the position of elements using properties like position, top, left, right, and bottom. Dimensions: Set dimensions using width and height. You can use percentages, fixed values, or dynamic values like flex. Responsive Design: React Native allows you to create responsive designs using Dimensions and the onLayout event. Orientation Handling: Handle changes in device orientation by adjusting your layout accordingly. Use the Dimensions API to detect changes. Stylesheet Composition: Compose styles using stylesheets and conditionally apply styles based on screen dimensions or other criteria. Best Practices : Separation of Concerns: Keep styles, logic, and presentation separate for better maintainability and code clarity. Optimizing Styles: Optimize styles to reduce unnecessary re-renders and improve app performance. By mastering these concepts related to components, styling, and layout in React Native, you can create rich and visually appealing mobile app user interfaces. Flexbox, in particular, is a powerful tool for creating flexible layouts, and understanding the nuances of styling is crucial for developing a professional-looking app.","breadcrumbs":"React Native » Layout in React Native","id":"168","title":"Layout in React Native"},"169":{"body":"Navigation is a crucial aspect of building mobile applications with React Native. It involves creating the structure and flow of your app, allowing users to move between different screens or views. The most common library for implementing navigation in React Native is React Navigation . Here's a more detailed overview of navigation in React Native: 1. Installing React Navigation: To get started with React Navigation, you need to install it in your project using npm or yarn: npm install @react-navigation/native @react-navigation/stack 2. Stack Navigator: The Stack Navigator is one of the most commonly used navigators in React Navigation. It allows you to create a stack of screens where each screen is placed on top of the previous one. You can navigate between screens by pushing and popping them from the stack. To set up a Stack Navigator, you need to import it and define your screens. import { createStackNavigator } from '@react-navigation/stack'; const Stack = createStackNavigator(); 3. Defining Screens: Each screen in your app is defined as a React component. For example, you might have a HomeScreen and a ProfileScreen. function HomeScreen() { // Your screen's content\n} function ProfileScreen() { // Your screen's content\n} 4. Navigating Between Screens: You can navigate between screens using navigation functions provided by React Navigation. For example, to navigate from the HomeScreen to the ProfileScreen: import { NavigationContainer } from '@react-navigation/native';\nimport { createStackNavigator } from '@react-navigation/stack'; const Stack = createStackNavigator(); function App() { return ( );\n} In your HomeScreen component, you can use navigation.navigate('Profile') to navigate to the ProfileScreen. 5. Passing Data Between Screens: You can pass data from one screen to another using parameters. For example, you can send a user's ID to the ProfileScreen: // In HomeScreen\nnavigation.navigate('Profile', { userId: 123 }); // In ProfileScreen\nconst userId = route.params.userId; 6. Drawer Navigation and Tab Navigation: React Navigation also supports Drawer and Tab navigations. The Drawer Navigator creates a sidebar menu for navigation, while the Tab Navigator allows you to switch between different tabs within an app. 7. Nested Navigation: React Navigation allows you to nest navigators within each other, creating complex navigation structures. This can be useful when you have a tab navigator and want to use a stack navigator within one of the tabs, or if you want to combine different types of navigators for more intricate navigation patterns. Here's an example of nesting a Stack Navigator within a Tab Navigator: import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';\nimport { createStackNavigator } from '@react-navigation/stack'; const Tab = createBottomTabNavigator();\nconst Stack = createStackNavigator(); // Define a tab navigator with a stack navigator in one of the tabs\nfunction TabNavigator() { return ( );\n} // Define a stack navigator to use within a tab\nfunction StackScreen() { return ( );\n} 8. Navigation Lifecycle: React Navigation provides navigation lifecycle events that allow you to perform actions when a screen comes into view or goes out of view. Common lifecycle events include: focus: Triggered when a screen comes into focus. blur: Triggered when a screen loses focus. didFocus: Triggered after the screen has come into focus. You can add listeners to these events to perform actions or fetch data when a screen is in focus. import { useFocusEffect } from '@react-navigation/native'; function MyScreen({ navigation }) { // Add a focus event listener useFocusEffect( React.useCallback(() => { // Perform actions when the screen comes into focus console.log('Screen is in focus'); // You can also fetch data or make API calls here }, []) ); // ... rest of the screen component\n} 9. Screen Options: You can customize the appearance and behavior of each screen's navigation using the options property in your screen component. This allows you to set options like the screen title, header style, and more. function MyScreen({ route, navigation }) { // Define screen-specific options React.useLayoutEffect(() => { navigation.setOptions({ title: 'Custom Title', headerStyle: { backgroundColor: 'blue', }, headerTintColor: 'white', }); }, [navigation]); // ... rest of the screen component\n} 10. Navigation Methods: React Navigation provides a set of methods that allow you to navigate between screens programmatically. Common methods include: navigate: Navigate to a new screen in the same stack. push: Push a new screen onto the stack. pop: Pop the current screen from the stack. goBack: Navigate back to the previous screen. These methods are accessible through the navigation prop in your screen components. function MyScreen({ navigation }) { return ( ;\n}","breadcrumbs":"React » » Handling Events","id":"126","title":"Handling Events"},"127":{"body":"You can use conditional statements and expressions to conditionally render different parts of a component based on certain conditions. function Greeting(props) { if (props.isLoggedIn) { return
    Welcome, User!
    ; } else { return
    Please log in.
    ; }\n}","breadcrumbs":"React » » Conditional Rendering","id":"127","title":"Conditional Rendering"},"128":{"body":"React provides a way to render lists of elements efficiently and assigns unique keys to each item in the list for optimization. const numbers = [1, 2, 3, 4, 5];\nconst listItems = numbers.map((number) =>
  • {number}
  • ); React utilizes several JavaScript features and concepts like arrow functions, classes, callbacks, promises, and async/await to create dynamic and interactive user interfaces. Let's explore each of these in detail and discuss how they are related and integrated in React:","breadcrumbs":"React » » Lists and Keys","id":"128","title":"Lists and Keys"},"129":{"body":"Arrow functions, classes, callbacks, promises, and async/await are fundamental JavaScript concepts that are commonly used in React. Let's explore each of these topics and how they are related and integrated in React:","breadcrumbs":"React » » Javascript For React:","id":"129","title":"Javascript For React:"},"13":{"body":"","breadcrumbs":"Demos » Demo 1 » Demo & Pitch Night 1","id":"13","title":"Demo & Pitch Night 1"},"130":{"body":"Arrow functions are a concise way to write functions in JavaScript. They are commonly used in React for defining components and functions, as they have a more compact syntax compared to traditional function expressions. Arrow functions capture the this value of the enclosing context automatically, making them suitable for working within React components and event handlers. Example of an arrow function defining a React component: const MyComponent = () => { return
    Hello, World!
    ;\n};","breadcrumbs":"React » » Arrow Functions:","id":"130","title":"Arrow Functions:"},"131":{"body":"Classes in JavaScript are used to define and create objects with methods and properties. In React, components are often defined as classes, especially when they need to manage component state and lifecycle methods. React class components extend the React.Component class and can have methods like render, componentDidMount, and more for handling component behavior. Example of a React class component: class MyComponent extends React.Component { render() { return
    Hello, World!
    ; }\n} **Note on functional versus class-based components** When React was first created, class-based components were the standard. But functional components were introduced later, and they eclipse class-based components in every way. Our advice: Ironically, you should probably never use class-based components! Stick to functional components. They are more modern and more versatile. Lots of tutorial content online still uses class-based components. If you stumble upon a tutorial or explanation that uses a class-based component, and you're new to React, please search for a functional-component alternative instead!","breadcrumbs":"React » » Classes:","id":"131","title":"Classes:"},"132":{"body":"Callbacks are functions that are passed as arguments to other functions and are executed at a later time or in response to an event. React uses callbacks extensively, especially in event handling. For example, you can pass callback functions to event handlers to respond to user interactions. Example of a callback function for handling a button click: function handleClick() { console.log('Button clicked');\n} ","breadcrumbs":"React » » Callbacks:","id":"132","title":"Callbacks:"},"133":{"body":"Promises are a way to handle asynchronous operations in JavaScript. They represent a value that might be available now, or in the future, or never. Promises have three states: pending, fulfilled, and rejected. Creating Promises: You can create a promise using the Promise constructor. It takes a function with two arguments: resolve and reject. You typically perform an asynchronous operation in this function and call resolve when the operation is successful or reject when it fails. const myPromise = new Promise((resolve, reject) => { // Asynchronous operation if (operationSucceeded) { resolve(result); } else { reject(error); }\n}); Chaining Promises: Promises can be chained together using .then() and .catch() to handle the resolved value or errors. This chaining allows you to compose complex asynchronous operations. myPromise .then((result) => { // Handle success }) .catch((error) => { // Handle error });","breadcrumbs":"React » » Promises:","id":"133","title":"Promises:"},"134":{"body":"async and await are modern JavaScript features for working with asynchronous code. They make asynchronous code more readable and maintainable. async Function: An async function is a function that always returns a promise. It allows you to use the await keyword inside the function to pause execution until the promise is resolved. async function fetchData() { const data = await fetch('https://api.example.com/data'); return data.json();\n} await Keyword: The await keyword can only be used inside an async function. It pauses the execution of the function until the promise is resolved, and it returns the resolved value. const result = await myPromise;\n// The code here will not execute until myPromise is resolved.","breadcrumbs":"React » » async/await:","id":"134","title":"async/await:"},"135":{"body":"React applications often involve asynchronous operations, such as fetching data from APIs or making network requests. Promises, async/await, and React's lifecycle methods can be integrated for managing asynchronous tasks effectively: Fetching Data: You can use async/await to fetch data in React components. Typically, you do this inside componentDidMount() or within functional components using the useEffect hook. async componentDidMount() { try { const response = await fetch('https://api.example.com/data'); const data = await response.json(); this.setState({ data }); } catch (error) { console.error('Error fetching data:', error); }\n} Updating Component State: Once the data is fetched, you can update the component state to trigger a re-render with the new data. Handling Errors: Use try/catch to handle errors gracefully. You can also integrate error boundaries in React to catch errors in the component tree. Using Promises: React works well with Promises, and you can use .then() and .catch() to manage asynchronous operations. However, async/await is often preferred for its more readable and synchronous-like syntax. Integrating Promises and async/await in React allows you to manage asynchronous operations in a clean and structured way, providing a better user experience by preventing UI blocking during data retrieval.","breadcrumbs":"React » » Promises and Aysnc/Await Integration in React:","id":"135","title":"Promises and Aysnc/Await Integration in React:"},"136":{"body":"","breadcrumbs":"React » » More React:","id":"136","title":"More React:"},"137":{"body":"","breadcrumbs":"React » » Events in React","id":"137","title":"Events in React"},"138":{"body":"In React, events are used to capture and respond to user interactions, such as clicks, input changes, and mouse movements. Event handling in React is similar to handling events in traditional HTML, but there are some differences due to React's synthetic event system. In React, you define event handlers as functions and attach them to JSX elements using event attributes. Here's an example of how you might handle a click event in React: function Button() { function handleClick() { console.log('Button clicked'); } return ;\n} The onClick attribute specifies the event handler function, handleClick, which will be executed when the button is clicked. React's synthetic event system provides a consistent API for handling events across different browsers.","breadcrumbs":"React » » Event Handling","id":"138","title":"Event Handling"},"139":{"body":"In React, event handlers are passed an event object as an argument. This object contains information about the event, such as the type of event, target element, and any event-specific data. You can access event properties and methods within your event handler functions. function handleChange(event) { console.log('Input value:', event.target.value);\n}","breadcrumbs":"React » » Event Object","id":"139","title":"Event Object"},"14":{"body":"","breadcrumbs":"Demos » Demo 1 » 30 November 2023","id":"14","title":"30 November 2023"},"140":{"body":"","breadcrumbs":"React » » Higher Order Components (HOCs) in React","id":"140","title":"Higher Order Components (HOCs) in React"},"141":{"body":"Higher Order Components are a design pattern in React that allows you to reuse component logic by wrapping one or more components with a higher-order component. HOCs are not a part of the React API; they are a pattern that leverages the composability of components.","breadcrumbs":"React » » What Are HOCs?","id":"141","title":"What Are HOCs?"},"142":{"body":"HOCs are functions that take a component and return a new enhanced component. They can add props, modify behavior, or encapsulate certain functionality. For example, you might create an HOC that provides authentication, access control, or data fetching capabilities to a component. Here's a simplified example of a higher order component that provides a \"loading\" indicator to a component: function withLoadingIndicator(WrappedComponent) { return function WithLoadingIndicator(props) { if (props.isLoading) { return
    Loading...
    ; } return ; };\n}","breadcrumbs":"React » » How HOCs Work","id":"142","title":"How HOCs Work"},"143":{"body":"You can use an HOC by wrapping your component with it. For instance, suppose you have a component called MyComponent, and you want to add a loading indicator using the withLoadingIndicator HOC: const MyComponentWithLoading = withLoadingIndicator(MyComponent); Now, MyComponentWithLoading is a new component that includes the loading indicator logic from the HOC. You can render it as you would with any other component. ","breadcrumbs":"React » » Using HOCs","id":"143","title":"Using HOCs"},"144":{"body":"HOCs enable you to separate concerns and promote reusability. They help you avoid code duplication by encapsulating common functionality in a separate function. This makes your code more maintainable and flexible, allowing you to compose and extend component behavior as needed.","breadcrumbs":"React » » Benefits of HOCs","id":"144","title":"Benefits of HOCs"},"145":{"body":"Events and HOCs can work together in a React application. For instance, you might create an HOC that handles common event-related logic, such as tracking user interactions, and then wrap components that need that behavior. This can help centralize event handling logic and make it reusable across multiple components. Additionally, you can pass event handling functions as props when composing components with HOCs, allowing for flexible customization of event behavior. In summary, events in React are essential for capturing and responding to user interactions, while Higher Order Components are a design pattern that promotes reusability and composability of component logic. You can use HOCs to encapsulate and extend event-related logic, making it easier to manage event handling across your React application.","breadcrumbs":"React » » Relationship Between Events and HOCs","id":"145","title":"Relationship Between Events and HOCs"},"146":{"body":"Props and state are two fundamental concepts in React, and they play distinct roles in how components work.","breadcrumbs":"React » » Props vs. State","id":"146","title":"Props vs. State"},"147":{"body":"Props (short for properties) are a mechanism for passing data from a parent component to a child component. Props are read-only, meaning that the child component cannot modify the props it receives. They are used to customize or configure child components based on data from their parent. Example of using props: function Greeting(props) { return
    Hello, {props.name}
    ;\n}","breadcrumbs":"React » » Props","id":"147","title":"Props"},"148":{"body":"State is a way to store and manage data that can change over time within a component. State is used to make components dynamic and interactive. Unlike props, state is mutable, and components can change their internal state using the setState method. State is often used for data that the component needs to keep track of, such as user input or UI state. Example of using state: class Counter extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } render() { return (

    Count: {this.state.count}

    ); }\n}","breadcrumbs":"React » » State","id":"148","title":"State"},"149":{"body":"Props and state are often used together to create dynamic and interactive React applications. Here's how they relate and are integrated: Passing Data : Props are used to pass data from a parent component to its child components. This data can be initial data that a child component uses to render itself. Updating Data : State is used to manage data that can change within a component. Components can have state and use it to keep track of user interactions, input, or changes in data. Reactivity : When a parent component passes props to a child component, any changes to those props in the parent will re-render the child. This allows for dynamic updates. State Management : State is local to the component that owns it, and changes in state trigger re-renders of that component, updating the UI as needed. Lifting State : Sometimes, you might need to manage state at a higher level in the component tree and pass it down as props to child components. This is called \"lifting state up.\" In summary, props are for passing data from parent to child, while state is for managing data that can change within a component. Together, they enable you to build interactive and data-driven React applications. Hooks, especially the useState hook, make it easier to manage local state in functional components, further enhancing the capabilities of React functional components.","breadcrumbs":"React » » How They Relate and Are Integrated","id":"149","title":"How They Relate and Are Integrated"},"15":{"body":"Demos are intended to be a check-in of your progress so far and a way for your whole team to show off their work, as well as an opportunity to practice pitching your project to the public. This will also let us understand your progress and blockers in order to help you best. Since Tech Start is built off 3 pillars, development, strategy, and design, the demos will also focus on these 3 aspects. Feel free to divide the allocated time between them as you see fit. In addition, there may or may not be pizza or snacks present.","breadcrumbs":"Demos » Demo 1 » Objectives","id":"15","title":"Objectives"},"150":{"body":"React introduced Hooks in version 16.8 as a way to add state and side-effects to functional components, which were previously limited to stateless rendering. In React, \"stateless rendering\" refers to the practice of creating functional components (also known as stateless functional components) that are purely responsible for rendering UI based on the input data provided through props. These components do not manage or maintain any internal state. Out with the old in with the new KING, hooks allow you to reuse stateful logic and side-effects across components, making functional components more powerful and flexible. Some of the most commonly used hooks include:","breadcrumbs":"React » » Hooks in Functional Components","id":"150","title":"Hooks in Functional Components"},"151":{"body":"This one might sound familiar from above, useState hook allows functional components to manage local state. It takes an initial state value and returns an array with the current state and a function to update it. import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); return (

    Count: {count}

    );\n}","breadcrumbs":"React » » 1. useState","id":"151","title":"1. useState"},"152":{"body":"The useEffect hook enables you to perform side-effects in functional components. It takes a function that will be executed after every render, and you can specify dependencies to control when the effect should run. import React, { useEffect, useState } from 'react'; function Example() { const [data, setData] = useState([]); useEffect(() => { // Fetch data from an API and update the state fetchData().then((result) => setData(result)); }, []); // Empty dependency array runs the effect only once\n}","breadcrumbs":"React » » 2. useEffect","id":"152","title":"2. useEffect"},"153":{"body":"React provides several other built-in hooks, such as useContext and useReducer, which allow you to manage context, state transitions, and references in functional components, respectively. useContext: Allows you to access the context API within functional components. It's useful for sharing data across the component tree without prop drilling. import React, { useContext } from 'react'; const ThemeContext = React.createContext('light'); function ThemedButton() { const theme = useContext(ThemeContext); return ;\n} useReducer: This hook is used for more complex state management and state transitions. It's similar to setState but offers more control over how state updates occur. import React, { useReducer } from 'react'; const initialState = { count: 0 }; function counterReducer(state, action) { switch (action.type) { case 'increment': return { count: state.count + 1 }; case 'decrement': return { count: state.count - 1 }; default: return state; }\n} function Counter() { const [state, dispatch] = useReducer(counterReducer, initialState); return (

    Count: {state.count}

    );\n}","breadcrumbs":"React » » 3. Other Built-in Hooks","id":"153","title":"3. Other Built-in Hooks"},"154":{"body":"You can create your own custom hooks to encapsulate and share component logic across different components. Custom hooks promote code reuse and maintainability. // Custom hook for handling form input state\nimport { useState } from 'react'; function useFormInput(initialValue) { const [value, setValue] = useState(initialValue); const handleChange = (e) => { setValue(e.target.value); }; return { value, onChange: handleChange, };\n} In summary, hooks in React are a way to manage state and side-effects in functional components. They integrate seamlessly with functional components, making it easier to write and maintain complex logic and enabling better code reuse. React's built-in hooks and the ability to create custom hooks provide a powerful toolset for building dynamic and interactive applications. Great Resources(videos): https://www.youtube.com/watch?v=Jl4q2cccwf0&ab_channel=TheNetNinja useState: https://www.youtube.com/watch?v=4qVNaohzDWU&ab_channel=LogRocket useEffect: https://www.youtube.com/watch?v=gv9ugDJ1ynU&ab_channel=TheNetNinja useRef: https://www.youtube.com/watch?v=yCS2m01bQ6w&ab_channel=Codevolution useCallback: https://www.youtube.com/watch?v=-Ls48dd-vJE&ab_channel=BenAwad","breadcrumbs":"React » » 4. Custom Hooks","id":"154","title":"4. Custom Hooks"},"155":{"body":"","breadcrumbs":"React » » React Ecosystem","id":"155","title":"React Ecosystem"},"156":{"body":"Calling APIs is a key part of any React App. It's what enables your app to communicate with the outside world - including, presumably, your backend. Here's a helpful tutorial on the best practices for calling APIs in React: https://www.youtube.com/watch?v=bYFYF2GnMy8 There's also a part 2: https://www.youtube.com/watch?v=1tfd6ANaNRY The best ways to fetch data are using the popular package Axos ( https://www.npmjs.com/package/axios ) or the vanilla JS _fetch _function ( https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch ) Once you have parsed the data, you'll probably want to store it in your state somehow (using useState or a redux store). It is also good practice to encapsulate your entire API call into a custom hook, and name the hook according to what it does (ex. useFetchPokemonStats ). This is also much easier to do if you use a state-management system like Redux, which is described below. The methods described above let you call an API immediately upon rendering a certain component. But what happens if you want to manually trigger an API call (ex. after a certain action or event)? Your API call should still use useEffect, and should look mostly like the calls you learned about in Part 1. The 1 difference is you need to guard the useEffect wisely in its dependency array. As you recall, the dependency array of a useEffect contains everything that the useEffect depends upon - if any of its dependencies change, it will have a _side effect _of rerunning the useEffect. So, you can define a specific variable which only changes when you want your API call to run. You can put that variable in the dependency array of the useEffect. When the action or event that you want to trigger the API call occurs, you should change the trigger variable. This change will trigger the useEffect to run. The trigger variable should never change except when you want the useEffect to run. I personally like making my trigger variable an object which also contains any subvariables that my API call needs. So for example, if I was coding a call to a search API that included a text query and target price, my trigger object would contain those. Here is an example of a very basic React application that calls an API to perform a search with a custom hook and a useEffect guarded by a trigger object as described above: https://github.com/Tech-Start-UCalgary/react-api-examples/tree/main/js-no-redux","breadcrumbs":"React » » Calling APIs","id":"156","title":"Calling APIs"},"157":{"body":"alt_text useSWR is a useful React hook for data fetching published by Vercel (creators of Next.js). SWR stands for stale-while-revalidate. It allows for smart data fetching and encapsulates a lot of advanced fetching logic (like how often should you refetch? should you have a cache?) in a single line of code. You should read more about useSWR here: https://swr.vercel.app/ You can watch a video tutorial here: https://www.youtube.com/watch?v=f7yjEdXgGiM","breadcrumbs":"React » » useSWR","id":"157","title":"useSWR"},"158":{"body":"React Router is a popular library used for routing in React applications. Routing is the process of determining which UI components should be displayed based on the current URL or path. React Router helps you create single-page applications with multiple views and navigate between them without requiring full page reloads. Here's an elaboration on React Router and its integration with React:","breadcrumbs":"React » » React Router","id":"158","title":"React Router"},"159":{"body":"Declarative Routing: React Router uses a declarative approach, where you define the routes and their corresponding components in a clear and organized manner. You specify what component should be rendered when a particular URL is matched. Nested Routing: React Router supports nested routes, allowing you to create complex and hierarchical UI structures. This is especially useful for building multi-level menus or complex application layouts. Route Parameters: You can define route parameters in your routes, allowing you to extract dynamic data from the URL. For example, a route like /users/:id can capture the id as a parameter. Programmatic Navigation: React Router provides a set of functions for programmatic navigation. You can change the route, push to the browser's history, or replace the current route using these functions. This is useful for actions like form submissions or after successful authentication. Route Guards: React Router allows you to implement route guards for protecting routes based on user authentication or other conditions. This ensures that users can only access certain routes if they meet specific criteria.","breadcrumbs":"React » » React Router Features:","id":"159","title":"React Router Features:"},"16":{"body":"","breadcrumbs":"Demos » Demo 1 » Time Limit: 15 minutes","id":"16","title":"Time Limit: 15 minutes"},"160":{"body":"React Router is typically integrated into a React application as a separate library. Here's how it's commonly done: Installation: You start by installing React Router as a package in your React project. You can use either react-router-dom (for web applications) or react-router-native (for mobile applications). npm install react-router-dom Router Component: You wrap your entire application (or a part of it) with a or component provided by React Router. This component manages the application's navigation state and listens to changes in the URL. import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; function App() { return ( {/* Define your routes here */} );\n} Route Configuration: Inside the , you define your routes using the component. Each component specifies a path and the component to render when the path matches. \n Route Navigation: To navigate between routes, you use the component to create links or the history object to programmatically navigate. Home\n// OR\nhistory.push('/home'); Route Parameters: You can use route parameters to capture dynamic values from the URL. These parameters are accessible as props in the routed components. Nested Routes: You can nest routes by defining routes within the components rendered by other routes. This allows for hierarchical routing structures. \n By integrating React Router into your React application, you can create well-organized, client-side routing that provides a seamless and efficient user experience for navigating different parts of your application.","breadcrumbs":"React » » Integration with React:","id":"160","title":"Integration with React:"},"161":{"body":"Redux is a widely used state container for javascript apps. As soon as your app reaches any level of data complexity, it makes a ton of sense to start using Redux to manage your state. A fair warning: Redux will seem complicated at the beginning. That's completely expected! Push through that initial discomfort and you'll get used to it in no time :) Here is a great introductory video to React-Redux: https://www.youtube.com/watch?v=CVpUuw9XSjY I highly recommend using **createSlice to setup your Redux Store . **It is a simple way to encapsulate creating actions and slicers in a simple, easy-to-read, easy-to-understand way. Here is a short video that does a great job explaining how to use createSlice: https://www.youtube.com/watch?v=e0MEtFaQTZk To access your Redux state and update your Redux state in React, I highly recommend using the twin hooks **useSelector **and useDispatch respectively. They are simple, easy, and elegant. https://www.youtube.com/watch?v=3zoIigieur0","breadcrumbs":"React » » React with Redux","id":"161","title":"React with Redux"},"162":{"body":"Next.js is a framework built on top of React, designed to simplify and enhance the development of web applications. It provides several features and benefits while seamlessly integrating with React. Let's explore these aspects interactively: Q1: What is Next.js? Next.js is a framework for building web applications that are built on top of the React library. It simplifies many aspects of React development and adds capabilities for server-side rendering, routing, and more. Q2: How does Next.js relate to React? Next.js is an extension of React. It leverages React's component-based structure and allows you to build React applications while providing additional tools and features for server-side rendering, routing, and other optimizations. Q3: What are some key features of Next.js? Next.js offers several key features: Server-Side Rendering (SSR): Next.js enables server-side rendering, which improves performance and SEO by rendering pages on the server before sending them to the client. Routing: It includes a built-in routing system, so you can easily define and navigate between pages. File-Based Routing: Routes are created based on the file structure, making it intuitive and easy to organize your application. Automatic Code Splitting: It automatically splits your JavaScript code into smaller, more manageable chunks, optimizing loading times. Static Site Generation (SSG): Next.js allows you to generate static HTML files at build time for even better performance and SEO. Q4: How do you create a new Next.js app? To create a new Next.js app, you can use the following commands: npx create-next-app my-nextjs-app\ncd my-nextjs-app\nnpm run dev This will set up a new Next.js application and start the development server. Q5: Can you explain the pages and routing in Next.js? In Next.js, you create pages by simply adding files to the pages directory. Each file becomes a route. For example, if you create pages/about.js, you will have a route at /about. Q6: How does Next.js handle data fetching? Next.js allows you to fetch data during server-side rendering using the getServerSideProps function. This data can be injected into your React components as props. export async function getServerSideProps() { // Fetch data from an API or database const data = await fetchData(); return { props: { data }, };\n} Q7: What's the advantage of server-side rendering in Next.js? Server-side rendering in Next.js improves the initial loading speed of your application and helps with search engine optimization (SEO). It also ensures that users see content more quickly. Q8: How can I build a static website with Next.js? Next.js provides static site generation (SSG) via the getStaticProps function. You can generate static HTML files for your pages at build time. export async function getStaticProps() { // Fetch data from an API or database const data = await fetchData(); return { props: { data }, };\n} Q9: Are there any limitations or trade-offs with Next.js? While Next.js offers many advantages, it may introduce complexity to smaller projects. It requires server-side rendering, which might not be necessary for all applications. Q10: Can I deploy Next.js applications to various hosting platforms? Yes, you can deploy Next.js applications to a wide range of hosting platforms, including Vercel, Netlify, and AWS. These platforms often provide built-in support for Next.js, making deployment straightforward. Next.js is a powerful tool that enhances React applications by providing features like server-side rendering, routing, and automatic code splitting. It simplifies the development process and improves performance. If you have more specific questions or need further information about Next.js, feel free to ask!","breadcrumbs":"React » » Lastly, Next.JS","id":"162","title":"Lastly, Next.JS"},"163":{"body":"Please get acquainted with our React Guide before you read this page, this is just a recommendation though. Transitioning from a good background in React to React Native is a relatively smooth process, as many concepts carry over. However, there are specific topics and components you should learn to effectively work with React Native. Here's an outline of the topics you need to cover: Video Resources (If you don't Like Reading) React Native Basics Main Concepts Components Styling Layout Navigation Platform-Specific Code Accessing Device Features Native Modules and Bridges State Management Async Storage Network Requests Advanced Topics; Debugging and Troubleshooting Testing Performance Optimization Publishing and Deployment Third-Party Integration Security conclusion","breadcrumbs":"React Native » Tech Start's React Native Guide","id":"163","title":"Tech Start's React Native Guide"},"164":{"body":"These tutorials should be sufficient to get started but this guide gives many more subtle topics that are not covered in these videos. Choose your weapon wisely. https://www.youtube.com/playlist?list=PL4cUxeGkcC9ixPU-QkScoRBVxtPPzVjrQ https://www.youtube.com/watch?v=0-S5a0eXPoc","breadcrumbs":"React Native » Video Resources:","id":"164","title":"Video Resources:"},"165":{"body":"","breadcrumbs":"React Native » React Native Basics:","id":"165","title":"React Native Basics:"},"166":{"body":"Components in React Native are similar to those in React, but with some variations and additional elements. Here's a more detailed breakdown: 1. Core Components: React Native provides a set of core components that are similar to HTML elements. These include: View: The fundamental component for creating UI layouts. Text: Used for displaying text. Image: For displaying images. ScrollView: For scrollable content. TextInput: For text input fields. And many more. 2. Custom Components: You can create your custom components just like in React. These components can be stateless functional components or class components. To create a custom component, use the View, Text, Image, and other core components to compose your UI.","breadcrumbs":"React Native » Components in React Native","id":"166","title":"Components in React Native"},"167":{"body":"Styling in React Native is different from traditional web development. You have various options for styling your components: a. Inline Styles: React Native supports inline styles using JavaScript objects. You can apply styles directly to components, like this: Hello, React Native!\n b. Stylesheets: Using stylesheets, you can create reusable style definitions: const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: 'lightblue', }, text: { fontSize: 20, color: 'black', },\n}); Hello, React Native!\n c. Flexbox Layout: React Native relies heavily on flexbox for layout design. It's similar to CSS flexbox but with a few differences. You can use properties like flex, alignItems, and justifyContent to control layout. Hello, React Native!\n","breadcrumbs":"React Native » Styling in React Native","id":"167","title":"Styling in React Native"},"168":{"body":"Understanding layout is vital in React Native to create responsive and visually appealing designs. Flexbox Layout: Flexbox is the primary layout system in React Native. It allows you to design flexible and adaptive layouts. Key properties include: flex: Determines how space is distributed among children. alignItems: Aligns items along the cross-axis (vertical alignment). justifyContent: Aligns items along the main axis (horizontal alignment). flexDirection: Sets the direction of the main axis. Positioning: You can control the position of elements using properties like position, top, left, right, and bottom. Dimensions: Set dimensions using width and height. You can use percentages, fixed values, or dynamic values like flex. Responsive Design: React Native allows you to create responsive designs using Dimensions and the onLayout event. Orientation Handling: Handle changes in device orientation by adjusting your layout accordingly. Use the Dimensions API to detect changes. Stylesheet Composition: Compose styles using stylesheets and conditionally apply styles based on screen dimensions or other criteria. Best Practices : Separation of Concerns: Keep styles, logic, and presentation separate for better maintainability and code clarity. Optimizing Styles: Optimize styles to reduce unnecessary re-renders and improve app performance. By mastering these concepts related to components, styling, and layout in React Native, you can create rich and visually appealing mobile app user interfaces. Flexbox, in particular, is a powerful tool for creating flexible layouts, and understanding the nuances of styling is crucial for developing a professional-looking app.","breadcrumbs":"React Native » Layout in React Native","id":"168","title":"Layout in React Native"},"169":{"body":"Navigation is a crucial aspect of building mobile applications with React Native. It involves creating the structure and flow of your app, allowing users to move between different screens or views. The most common library for implementing navigation in React Native is React Navigation . Here's a more detailed overview of navigation in React Native: 1. Installing React Navigation: To get started with React Navigation, you need to install it in your project using npm or yarn: npm install @react-navigation/native @react-navigation/stack 2. Stack Navigator: The Stack Navigator is one of the most commonly used navigators in React Navigation. It allows you to create a stack of screens where each screen is placed on top of the previous one. You can navigate between screens by pushing and popping them from the stack. To set up a Stack Navigator, you need to import it and define your screens. import { createStackNavigator } from '@react-navigation/stack'; const Stack = createStackNavigator(); 3. Defining Screens: Each screen in your app is defined as a React component. For example, you might have a HomeScreen and a ProfileScreen. function HomeScreen() { // Your screen's content\n} function ProfileScreen() { // Your screen's content\n} 4. Navigating Between Screens: You can navigate between screens using navigation functions provided by React Navigation. For example, to navigate from the HomeScreen to the ProfileScreen: import { NavigationContainer } from '@react-navigation/native';\nimport { createStackNavigator } from '@react-navigation/stack'; const Stack = createStackNavigator(); function App() { return ( );\n} In your HomeScreen component, you can use navigation.navigate('Profile') to navigate to the ProfileScreen. 5. Passing Data Between Screens: You can pass data from one screen to another using parameters. For example, you can send a user's ID to the ProfileScreen: // In HomeScreen\nnavigation.navigate('Profile', { userId: 123 }); // In ProfileScreen\nconst userId = route.params.userId; 6. Drawer Navigation and Tab Navigation: React Navigation also supports Drawer and Tab navigations. The Drawer Navigator creates a sidebar menu for navigation, while the Tab Navigator allows you to switch between different tabs within an app. 7. Nested Navigation: React Navigation allows you to nest navigators within each other, creating complex navigation structures. This can be useful when you have a tab navigator and want to use a stack navigator within one of the tabs, or if you want to combine different types of navigators for more intricate navigation patterns. Here's an example of nesting a Stack Navigator within a Tab Navigator: import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';\nimport { createStackNavigator } from '@react-navigation/stack'; const Tab = createBottomTabNavigator();\nconst Stack = createStackNavigator(); // Define a tab navigator with a stack navigator in one of the tabs\nfunction TabNavigator() { return ( );\n} // Define a stack navigator to use within a tab\nfunction StackScreen() { return ( );\n} 8. Navigation Lifecycle: React Navigation provides navigation lifecycle events that allow you to perform actions when a screen comes into view or goes out of view. Common lifecycle events include: focus: Triggered when a screen comes into focus. blur: Triggered when a screen loses focus. didFocus: Triggered after the screen has come into focus. You can add listeners to these events to perform actions or fetch data when a screen is in focus. import { useFocusEffect } from '@react-navigation/native'; function MyScreen({ navigation }) { // Add a focus event listener useFocusEffect( React.useCallback(() => { // Perform actions when the screen comes into focus console.log('Screen is in focus'); // You can also fetch data or make API calls here }, []) ); // ... rest of the screen component\n} 9. Screen Options: You can customize the appearance and behavior of each screen's navigation using the options property in your screen component. This allows you to set options like the screen title, header style, and more. function MyScreen({ route, navigation }) { // Define screen-specific options React.useLayoutEffect(() => { navigation.setOptions({ title: 'Custom Title', headerStyle: { backgroundColor: 'blue', }, headerTintColor: 'white', }); }, [navigation]); // ... rest of the screen component\n} 10. Navigation Methods: React Navigation provides a set of methods that allow you to navigate between screens programmatically. Common methods include: navigate: Navigate to a new screen in the same stack. push: Push a new screen onto the stack. pop: Pop the current screen from the stack. goBack: Navigate back to the previous screen. These methods are accessible through the navigation prop in your screen components. function MyScreen({ navigation }) { return ( + + + + + +

    Tech Start UCalgary Documentation

    + + + + + + + + + +
    +
    +

    Career Paths

    +

    There are several areas of software development that cover different aspects of the software development life cycle. +Usually, people focus on only one or a couple of them. Each of them is a big area on its own and takes years to learn:

    +
      +
    • +

      Front-end development: This area of software development is concerned with the user interface (UI) and user experience (UX) of software applications. Front-end developers work with technologies like HTML, CSS, and JavaScript to create the visual elements that users interact with.

      +
    • +
    • +

      Back-end development: This area of software development is concerned with the server-side of software applications. Back-end developers work with technologies like PHP, Python, Ruby, and Java to create the logic that powers software applications.

      +
    • +
    • +

      Full-stack development: Full-stack developers work on both the front-end and back-end of software applications. They have knowledge and skills in both areas of development and can build complete applications from start to finish.

      +
    • +
    • +

      Mobile development: This area of software development is concerned with creating applications for mobile devices. Mobile developers work with technologies like Java, Swift, and Kotlin to create native apps for iOS and Android devices.

      +
    • +
    • +

      DevOps: DevOps is a methodology that focuses on collaboration between development and operations teams to automate the software delivery process. DevOps engineers use tools like Jenkins, Ansible, and Docker to automate the software development process.

      +
    • +
    • +

      Testing and quality assurance: This area of software development is concerned with ensuring that software applications are reliable, bug-free, and meet the requirements of the end-users. Testing and quality assurance engineers use tools like Selenium, JMeter, and LoadRunner to test software applications.

      +
    • +
    • +

      Data science and analytics: This area of software development is concerned with creating applications that analyze and interpret data. Data science and analytics engineers work with technologies like Python, R, and SQL to build applications that can perform data analysis, machine learning, and statistical modeling.

      +
    • +
    • +

      Artificial intelligence and machine learning: This area of software development is concerned with creating applications that can learn and make decisions based on data. AI and ML developers work with technologies like Python, TensorFlow, and PyTorch to build applications that can perform tasks like natural language processing, image recognition, and predictive modeling.

      +
    • +
    • +

      Cybersecurity: This area of software development is concerned with creating secure software applications and protecting them from malicious attacks. Cybersecurity engineers work with technologies like encryption, firewalls, and intrusion detection systems to secure software applications.

      +
    • +
    • +

      Cloud computing: This area of software development is concerned with creating applications that can run on cloud computing platforms like Amazon Web Services, Microsoft Azure, and Google Cloud Platform. Cloud developers work with technologies like containerization, serverless computing, and cloud storage to build and deploy applications on the cloud.

      +
    • +
    • +

      Embedded systems: This area of software development is concerned with creating software for embedded devices like medical devices, smart appliances, and automotive systems. Embedded systems developers work with technologies like C, C++, and assembly language to create software that runs on these devices.

      +
    • +
    • +

      Augmented and virtual reality: This area of software development is concerned with creating applications that allow users to interact with virtual or augmented environments. AR and VR developers work with technologies like Unity, Unreal Engine, and WebXR to build immersive applications for gaming, education, and training.

      +
    • +
    • +

      Project management: Involves overseeing the entire software development process from conception to delivery. Project managers are responsible for ensuring that the project is completed on time, within budget, and to the required quality standards.

      +
    • +
    • +

      Product owner: The product owner is responsible for defining and prioritizing the features and requirements of a software application. They work closely with development teams, stakeholders, and customers to ensure that the product meets the needs of the users.

      +
    • +
    • +

      Technical writing: Technical writers create documentation and user manuals for software applications. They work with developers and other technical experts to create user-friendly documentation that explains how to use the software application.

      +
    • +
    • +

      User experience (UX) design: UX designers create the visual design and user experience of software applications. They work with developers to ensure that the application is easy to use and visually appealing.

      +
    • +
    • +

      Technical support: Technical support engineers provide support to users who are experiencing issues with software applications. They work with developers to diagnose and resolve technical issues, and provide customer support to users.

      +
    • +
    • +

      Technical architecture: Technical architects are responsible for designing the technical architecture of software applications. They work with development teams to ensure that the architecture meets the scalability, security, and performance requirements of the application.

      +
    • +
    • +

      Database administration: Database administrators are responsible for managing the data that is used by software applications. They work with developers to design and implement databases, and ensure that the data is stored and managed effectively.

      +
    • +
    + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/software/devops/index.html b/software/devops/index.html new file mode 100644 index 0000000..8b6178e --- /dev/null +++ b/software/devops/index.html @@ -0,0 +1,238 @@ + + + + + + DevOps - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    DevOps

    +

    DevOps is a software development approach that emphasizes collaboration and communication between software developers and IT operations professionals. The goal of DevOps is to improve the efficiency and quality of software development by breaking down silos and promoting a culture of collaboration, automation, and continuous improvement.

    +

    Traditionally (https://clickup.com/blog/waterfall-project-management/), software development and IT operations have been two separate functions within organizations, with little interaction between them. DevOps seeks to bridge this gap by fostering collaboration between these teams throughout the entire software development lifecycle, from planning and development to deployment and maintenance.

    +

    DevOps involves using tools and practices such as continuous integration, continuous delivery, and infrastructure automation to streamline the software development process and make it more efficient. By automating tasks like testing, building, and deploying software, teams can reduce errors, speed up the development process, and deliver software more quickly and reliably.

    +

    Overall, DevOps is a holistic approach to software development that aims to create a culture of collaboration and continuous improvement, with the goal of delivering software more efficiently and with higher quality.

    +

    How to become a DevOps engineer?

    +
      +
    1. +

      Understand the why and the high-level how (the philosophy).

      +

      For instance:

      + +
    2. +
    3. +

      Learn the core skills: DevOps engineers need a strong foundation in software development, You should have a basic understanding of programming languages, and be familiar with version control systems like Git. You should also have experience working with Linux/Unix systems and be familiar with cloud platforms like AWS, Azure, or Google Cloud Platform.

      +
    4. +
    5. +

      Gain experience with DevOps tools and practices: DevOps engineers should be familiar with tools and practices such as continuous integration/continuous delivery (CI/CD), infrastructure as code, configuration management, and monitoring and logging. You can gain experience by working on projects, contributing to open-source projects, or taking online courses.

      +
    6. +
    7. +

      Learn automation: Automation is a key part of DevOps, so you should have experience with containerization tools like Docker and Kubernetes.

      +
    8. +
    9. +

      Build projects: To gain practical experience, you should work on building your own projects or contributing to open-source projects. This will help you to develop your skills and build a portfolio of work that you can show to potential employers.

      +
    10. +
    11. +

      Stay up-to-date: DevOps is a rapidly evolving field, so it's important to stay up-to-date with the latest tools and practices. Attend conferences, read blogs and forums, and participate in online communities to stay current.

      +
    12. +
    13. +

      Apply for jobs: Once you have the skills and experience, it's time to start applying for DevOps engineering jobs. Look for job postings online, reach out to recruiters or companies directly, and attend networking events to make connections in the industry. Be prepared to showcase your portfolio and be able to talk about your skills and experience during interviews.

      +
    14. +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + +
    + + diff --git a/software/front-end/index.html b/software/front-end/index.html new file mode 100644 index 0000000..426f763 --- /dev/null +++ b/software/front-end/index.html @@ -0,0 +1,225 @@ + + + + + + Front End - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Front End

    +

    A front-end engineer is a software engineer who specializes in building the user interface (UI) and user experience (UX) of a website or application. They are responsible for creating visually appealing and intuitive designs that allow users to interact with the application or website seamlessly.

    +

    The front-end engineer's job involves using various technologies such as HTML, CSS, and JavaScript to build the visual elements of an application or website. They work closely with designers to turn mockups and wireframes into fully functional websites or applications that are easy to use and navigate.

    +

    Front-end engineers also collaborate with back-end engineers to integrate the front-end code with the back-end code, ensuring that the entire system functions correctly. They are responsible for testing and debugging the front-end code, optimizing the code for performance, and ensuring that the website or application is compatible with different browsers and devices.

    +

    How to become a front-end engineer?

    +

    To become a front-end engineer, you will need to follow these general steps:

    +
      +
    1. +

      Learn HTML, CSS, and JavaScript (or TypeScript): HTML is used to structure web pages, CSS is used to style them, and JavaScript is used to add interactivity and dynamic behavior. These are the core technologies used in front-end development.

      +
    2. +
    3. +

      Learn a front-end framework: While it's not strictly necessary, learning a front-end framework like React can help you to build more complex web applications more efficiently.

      +
    4. +
    5. +

      Build projects: To gain practical experience, you should work on building your own projects or contributing to open-source projects. This will help you to develop your skills and build a portfolio of work that you can show to potential employers.

      +
    6. +
    7. +

      Stay up-to-date: Front-end development is a rapidly evolving field, so it's important to stay up-to-date with the latest technologies and best practices. Attend conferences, read blogs and forums, and participate in online communities to stay current.

      +
    8. +
    9. +

      Apply for jobs: Once you have the skills and experience, it's time to start applying for front-end engineering jobs. Look for job postings online, reach out to recruiters or companies directly, and attend networking events to make connections in the industry. Be prepared to showcase your portfolio and be able to talk about your skills and experience during interviews.

      +
    10. +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + +
    + + diff --git a/tomorrow-night.css b/tomorrow-night.css new file mode 100644 index 0000000..5b4aca7 --- /dev/null +++ b/tomorrow-night.css @@ -0,0 +1,102 @@ +/* Tomorrow Night Theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ + +/* Tomorrow Comment */ +.hljs-comment { + color: #969896; +} + +/* Tomorrow Red */ +.hljs-variable, +.hljs-attribute, +.hljs-tag, +.hljs-regexp, +.ruby .hljs-constant, +.xml .hljs-tag .hljs-title, +.xml .hljs-pi, +.xml .hljs-doctype, +.html .hljs-doctype, +.css .hljs-id, +.css .hljs-class, +.css .hljs-pseudo { + color: #cc6666; +} + +/* Tomorrow Orange */ +.hljs-number, +.hljs-preprocessor, +.hljs-pragma, +.hljs-built_in, +.hljs-literal, +.hljs-params, +.hljs-constant { + color: #de935f; +} + +/* Tomorrow Yellow */ +.ruby .hljs-class .hljs-title, +.css .hljs-rule .hljs-attribute { + color: #f0c674; +} + +/* Tomorrow Green */ +.hljs-string, +.hljs-value, +.hljs-inheritance, +.hljs-header, +.hljs-name, +.ruby .hljs-symbol, +.xml .hljs-cdata { + color: #b5bd68; +} + +/* Tomorrow Aqua */ +.hljs-title, +.css .hljs-hexcolor { + color: #8abeb7; +} + +/* Tomorrow Blue */ +.hljs-function, +.python .hljs-decorator, +.python .hljs-title, +.ruby .hljs-function .hljs-title, +.ruby .hljs-title .hljs-keyword, +.perl .hljs-sub, +.javascript .hljs-title, +.coffeescript .hljs-title { + color: #81a2be; +} + +/* Tomorrow Purple */ +.hljs-keyword, +.javascript .hljs-function { + color: #b294bb; +} + +.hljs { + display: block; + overflow-x: auto; + background: #1d1f21; + color: #c5c8c6; +} + +.coffeescript .javascript, +.javascript .xml, +.tex .hljs-formula, +.xml .javascript, +.xml .vbscript, +.xml .css, +.xml .hljs-cdata { + opacity: 0.5; +} + +.hljs-addition { + color: #718c00; +} + +.hljs-deletion { + color: #c82829; +} diff --git a/topics/conflict-management-styles/index.html b/topics/conflict-management-styles/index.html new file mode 100644 index 0000000..7bebcc6 --- /dev/null +++ b/topics/conflict-management-styles/index.html @@ -0,0 +1,223 @@ + + + + + + Dealing With Conflict - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Dealing With Conflict

    +

    Conflict resolution is the process of resolving differences +and disputes between individuals, groups, +or parties through peaceful means. +It involves identifying and addressing the underlying causes of the conflict, +promoting communication and understanding, cooperation, +and finding a mutually acceptable solution, +leading to increased productivity +and satisfaction in personal and professional settings. +When done correctly, +it helps to manage and resolve differences and disputes effectively, +preventing them from escalating into larger and more destructive problems.

    +

    The following document enumerates the trade-offs +of all conflict management styles, +and I highly encourage you to read it.

    +

    https://www.valamis.com/hub/conflict-management-styles.

    +

    Lastly, remember that conflict is not a bad thing. +Instead, learn how to manage it and make the most out of it.

    +
    +

    "If you want to go fast, go alone; if you want to go far, go together."

    +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + +
    + + diff --git a/topics/css/index.html b/topics/css/index.html new file mode 100644 index 0000000..d115354 --- /dev/null +++ b/topics/css/index.html @@ -0,0 +1,238 @@ + + + + + + CSS - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    CSS

    +

    Is only recommended to learn CSS after you are familiar with HTML.

    +

    Fundamentals

    +

    MDN is all you'll need. +Read it from beginning to end: +https://developer.mozilla.org/en-US/docs/Web/CSS.

    +

    Particularly, focus on:

    +
      +
    1. The basic syntax, common attributes (color, font, border) +and basic selectors.
    2. +
    3. The Box Model.
    4. +
    5. CSS Layouts +(Flexbox and Grids as a minimum).
    6. +
    7. Responsive Design and media queries.
    8. +
    +

    Related utilities:

    + + +

    Learn only after you learn the fundamentals:

    + +

    Advanced

    +

    When you want to architect a big scope system:

    + +

    Be aware of

    +

    But not necessarily learn them:

    + + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + +
    + + diff --git a/topics/html/index.html b/topics/html/index.html new file mode 100644 index 0000000..17d5ff1 --- /dev/null +++ b/topics/html/index.html @@ -0,0 +1,209 @@ + + + + + + HTML - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    HTML

    +

    Fundamentals

    +

    MDN is all you'll need. +Read it from beginning to end: +https://developer.mozilla.org/en-US/docs/Learn/HTML.

    +

    You should focus on the basics only (a, button, h1-h6, p, span, lists, div, input, ...).

    +

    HTML is not more complicated than that, learn about CSS next.

    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + +
    + + diff --git a/topics/management-styles/index.html b/topics/management-styles/index.html new file mode 100644 index 0000000..d0d50b2 --- /dev/null +++ b/topics/management-styles/index.html @@ -0,0 +1,224 @@ + + + + + + Management Styles - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Management Styles

    +
    +

    A management style is the way +in which a manager works to fulfill their goals. +Management style includes the way that a manager plans, organizes, makes decisions, delegates, +and manages their staff.

    +
    +

    All management styles are useful depending on the specific scenario, +but it's important to identify when to use which one, +since a wrong management style conduces the team to a dissatisfied, unengaged, inefficient, unmotivated, or frustrated state.

    +

    The following document enumerates the trade-offs +of all management styles and I highly encourage you to read it.

    +

    https://www.valamis.com/hub/management-styles.

    +

    I would just add a last tip here:

    +

    Understand what motivates every person on your team.

    +

    For instance, +remember that a team of volunteers is very different from a team of employees. +On a volunteering team, the motivation factors usually are +self-development and being part of a cause. +The key in this setup +is aligning the team's objectives +with each person's definition of meaningfulness.

    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + +
    + + diff --git a/workshops/secrets-management/git-crypt/.gitattributes b/workshops/secrets-management/git-crypt/.gitattributes new file mode 100644 index 0000000..4239af9 --- /dev/null +++ b/workshops/secrets-management/git-crypt/.gitattributes @@ -0,0 +1 @@ +secrets/**/* filter=git-crypt diff=git-crypt diff --git a/workshops/secrets-management/git-crypt/secrets/dev/password b/workshops/secrets-management/git-crypt/secrets/dev/password new file mode 100644 index 0000000..33513d3 Binary files /dev/null and b/workshops/secrets-management/git-crypt/secrets/dev/password differ diff --git a/workshops/secrets-management/git-crypt/secrets/dev/username b/workshops/secrets-management/git-crypt/secrets/dev/username new file mode 100644 index 0000000..422a0e1 Binary files /dev/null and b/workshops/secrets-management/git-crypt/secrets/dev/username differ diff --git a/workshops/secrets-management/git-crypt/secrets/prod/password b/workshops/secrets-management/git-crypt/secrets/prod/password new file mode 100644 index 0000000..dd6d80b Binary files /dev/null and b/workshops/secrets-management/git-crypt/secrets/prod/password differ diff --git a/workshops/secrets-management/git-crypt/secrets/prod/username b/workshops/secrets-management/git-crypt/secrets/prod/username new file mode 100644 index 0000000..2d712f1 Binary files /dev/null and b/workshops/secrets-management/git-crypt/secrets/prod/username differ diff --git a/workshops/secrets-management/git-crypt/unsafe/key b/workshops/secrets-management/git-crypt/unsafe/key new file mode 100644 index 0000000..4f7fc25 Binary files /dev/null and b/workshops/secrets-management/git-crypt/unsafe/key differ diff --git a/workshops/secrets-management/index.html b/workshops/secrets-management/index.html new file mode 100644 index 0000000..9d544f8 --- /dev/null +++ b/workshops/secrets-management/index.html @@ -0,0 +1,442 @@ + + + + + + Secrets Management - Tech Start UCalgary Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    +
    +

    Secrets Management

    +

    In this Workshop, we'll learn how to properly store the secrets +that your application's source code needs to run +like database connection strings and third-party API access credentials, +and do so even if people have access to your source code.

    +

    We'll be exploring three approaches used in industry, +and talking about when to use one or the other:

    +
      +
    1. Git Crypt.
    2. +
    3. SOPS - My favorite.
    4. +
    5. Hashicorp's Vault.
    6. +
    +

    We'll also talk a little bit about the Twelve-Factor app, +particularly about factor #3: Configuration.

    +

    Pre-requisites

    +

    To be able to focus on the important aspects of this Workshop (secrets management) +and avoid distractions we'll assume you are familiar with Git +and the command line.

    +

    Please bring your laptop, +the idea is that we'll work together step by step on small exercises +that will teach you each of the tools.

    +

    Only MacOS and Linux are supported. +If you are on Windows, +please install WSL.

    +

    Please come to the workshop with the following tools ready to be used:

    +
      +
    1. +

      A terminal where you can enter commands, set environment variables, etc.

      +
    2. +
    3. +

      Git.

      +
    4. +
    5. +

      Git Crypt:

      +

      Run $ brew install git-crypt on MacOS, +or $ apt install git-crypt or similar on Linux/WSL.

      +
    6. +
    7. +

      Sops:

      +

      Run $ brew install sops on MacOS, +or $ apt install sops or similar on Linux/WSL.

      +
    8. +
    9. +

      Age:

      +

      Run $ brew install age on MacOS, +or $ apt install age or similar on Linux/WSL.

      +
    10. +
    11. +

      Vault:

      +

      Please follow the instructions here: +https://developer.hashicorp.com/vault/downloads.

      +
    12. +
    +

    Why?

    +

    Application secrets are critical for security. +For example, if an attacker discovers the database credentials, +then immediately this attacker would gain access to all of the applications data. +Application secrets is the entrypoint for everything, they are the Keys of Heaven, +and therefore, it's very important to make sure +that only the right people can get access to those secrets.

    +

    In this line of making application secrets be only accessible to the right people +we also need to make sure that developers can only access development secrets. +It's very common to have at least 2 environments: Development and Production, +and to have some kind of segmentation where only super admins can access Production secrets.

    +

    It also doesn't matter if your source code is private, +you still want to protect your secrets because your source code may be leaked, +as it has happened in the past to companies like Twitch.

    +

    There is also an argument about maintainability. +Secrets are also configuration, namely, their values may change over time, +even if the source code doesn't. For this reason it's recommended to +strictly separate them from the source code.

    +

    Workshop Step by Step

    +

    Git-Crypt

    +
    +

    https://github.com/AGWA/git-crypt

    +
    +

    Enables you to encrypt/decrypt the parts of a git of repository.

    +

    The good:

    +
      +
    • Versioned as code.
    • +
    • It's simple to use.
    • +
    • Great for a simple project, with no compliance needs.
    • +
    +

    The bad:

    +
      +
    • You cannot have multiple keys. All people share the same encryption key, +which means you cannot isolate environments, +and therefore is not that useful in highly regulated industries.
    • +
    • Unencrypted secrets touch the disk, +which is not great if someone steals your laptop while unencrypted.
    • +
    +

    Steps:

    +
      +
    1. +

      Visit https://github.com/techstartucalgary/Docs/tree/main/src/workshops/secrets-management/git-crypt/secrets.

      +

      As you can see, there are dev and prod secrets with username and password, but they are encrypted, so we cannot see them unless we have they key.

      +
    2. +
    3. +

      Download the key here

      +

      Note: This should be distributed through a secure channel (e.g. encrypted email). +For the sake of simplicity you can download it here.

      +
    4. +
    5. +

      Now we want to decrypt the secrets, for this we have to:

      +
      $ git clone https://github.com/techstartucalgary/Docs.git docs
      +$ cd docs
      +
      +docs $ cat src/workshops/secrets-management/git-crypt/secrets/dev/username
      +  <you should see gibberish>
      +
      +# Decrypt
      +docs $ git-crypt unlock /path/to/key
      +
      +# You should see the secrets now
      +docs $ cat src/workshops/secrets-management/git-crypt/secrets/dev/username
      +docs $ cat src/workshops/secrets-management/git-crypt/secrets/dev/password
      +
      +# Encrypt
      +docs $ git-crypt lock
      +docs $ cat src/workshops/secrets-management/git-crypt/secrets/dev/username
      +  <you should see gibberish again>
      +
      +
    6. +
    7. +

      The next step is understanding how it works, so essentially you configure which paths of the repository are encrypted in a .gitattributes file like this one: +https://github.com/techstartucalgary/Docs/blob/main/src/workshops/secrets-management/git-crypt/.gitattributes, +where essentially we tell git-crypt to encrypt the files under the secrets/ folder. You can check which files are encrypted with

      +
      $ git-crypt status
      +   not encrypted: src/workshops/secrets-management/README.md
      +       encrypted: src/workshops/secrets-management/git-crypt/secrets/dev/password
      +       encrypted: src/workshops/secrets-management/git-crypt/secrets/dev/username
      +       encrypted: src/workshops/secrets-management/git-crypt/secrets/prod/password
      +       encrypted: src/workshops/secrets-management/git-crypt/secrets/prod/username
      +   not encrypted: src/workshops/secrets-management/git-crypt/unsafe/key
      +
      +
    8. +
    +

    Sops

    +
    +

    https://github.com/mozilla/sops

    +
    +

    Enables you to encrypt/decrypt JSON, YAML, or whole files.

    +

    The good:

    +
      +
    • Versioned as code.
    • +
    • You can have multiple keys and access control over a whole file, +great for highly regulated industries.
    • +
    • Keys can be connected to an AWS/GCP/Azure identity, +which is great in corporate environments, +and Age/PGP, which is great for other environments.
    • +
    +

    The neutral:

    +
      +
    • Not that easy to use, but reasonable given the features.
    • +
    +

    The bad:

    +
      +
    • Requires some training to get used to it.
    • +
    +

    Steps:

    +
      +
    1. +

      Visit https://github.com/techstartucalgary/Docs/tree/main/src/workshops/secrets-management/sops.

      +

      As you can see, there are dev and prod secrets with username and password, but they are encrypted, so we cannot see them unless we have they key.

      +
    2. +
    3. +

      Download the development key +here +and the production key +here

      +

      Note: This should be distributed through a secure channel (e.g. encrypted email). +For the sake of simplicity you can download it here.

      +
    4. +
    5. +

      Now we want to decrypt the secrets, for this we have to:

      +
      $ git clone https://github.com/techstartucalgary/Docs.git docs
      +$ cd docs
      +
      +$ cd src/workshops/secrets-management/sops
      +
      +src/workshops/secrets-management/sops $ cat dev.yaml
      +  <you should see gibberish>
      +
      +src/workshops/secrets-management/sops $ cat prod.yaml
      +  <you should see gibberish>
      +
      +# Decrypt dev secrets with dev key
      +src/workshops/secrets-management/sops $ SOPS_AGE_KEY_FILE=/path/to/dev/key sops -d dev.yaml
      +
      +# Decrypt prod secrets with dev key
      +src/workshops/secrets-management/sops $ SOPS_AGE_KEY_FILE=/path/to/dev/key sops -d prod.yaml
      +   <you should see a failure, wrong key>
      +
      +# Decrypt prod secrets with prod key
      +src/workshops/secrets-management/sops $ SOPS_AGE_KEY_FILE=/path/to/prod/key sops -d prod.yaml
      +
      +
    6. +
    +

    Vault

    +
    +

    https://www.hashicorp.com/products/vault

    +
    +

    The good:

    +
      +
    • Big enterprises like it. Why? Maybe marketing? I assume is because it allows for centralization, which is important if you have hundreds of teams.
    • +
    +

    The neutral:

    +
      +
    • Very flexible.
    • +
    +

    The bad:

    +
      +
    • Another server to maintain.
    • +
    • Not versioned as code.
    • +
    • Not free.
    • +
    +
    +

    Note: https://vault.kamadorueda.com will be only available during the workshop. If you are following this guide after the workshop, please use your own Vault instance instead.

    +
    +

    Steps:

    +
      +
    1. +

      Login to the UI at https://vault.kamadorueda.com/ui. The token is 123.

      +
    2. +
    3. +

      Let's put and get a secret out of it

      +
      $ export VAULT_ADDR=https://vault.kamadorueda.com
      +
      +# Login. The token is: 123
      +$ vault login
      +
      +$ vault kv put secret/your-name password=your-password
      +
      +$ vault kv get -field=password secret/your-name
      +
      +
    4. +
    5. +

      It's possible to define access control lists, policies, and grant each person a different token, or login with OIDC. It's very flexible.

      +
    6. +
    + +
    + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + +
    + + diff --git a/workshops/secrets-management/sops/dev.yaml b/workshops/secrets-management/sops/dev.yaml new file mode 100644 index 0000000..85c5b1f --- /dev/null +++ b/workshops/secrets-management/sops/dev.yaml @@ -0,0 +1,22 @@ +username: ENC[AES256_GCM,data:kWtcGA==,iv:4+7Usm7Z4QCBENuVKjdUCSVDRxmyMflPUdyW1ClQJzc=,tag:2zxu5/HZ38ZY9ya1Agy8+g==,type:str] +password: ENC[AES256_GCM,data:k4TjataJMD7XX+vNQOpcgX5zRdHJc86C,iv:8hjdssY3LS3YI+JgrNjoJbvwmenAd1qQ+qNHMNhU4UA=,tag:R0vWZJFITUtMNyQAEX7rbg==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1ehr903kf80pnd5fzcdssau9pgjv2talthe55e4h8p0tu68exqvvq0za8xx + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArczlhZlVyNWloOEE4dWl0 + WWo0S3doWW92R3owRCtJdVAxL2t5a3IySVJZCmZKS2VMQ3pBTHZBNFZXdTl6aTF2 + VGVxSmxHL0JXaHNVSTU5cndURWswdGMKLS0tIFU0ZkczTmNkK2tjSTN2aTJhOGZI + MFNmbC9Yck9rMWJndE9zWWsveURVbU0K1TdgwpHKQ0lCiuNRd79gVwg5Hf2j/INm + gysQm/kgmOw53eH8WmY6/nm7Yy/tTtaiu1XPGhmBKt41F9S0rpbrbw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2023-02-09T19:14:03Z" + mac: ENC[AES256_GCM,data:Ulmk3eHxjFZZk1kfYHfzSdN8jSeaWyW87rzeL+4QvCGUCkhq0KZ72cQBNaesPeh2tM43348fCEhDF7msLXFm6Biz6amSEifh9NpyMFiMrOPwDBe8rWFWhA4xTQCpoTq0X73VonAhZzzoGjHEq5HTb8lGPyx5XlWB6ECbLG6nFwg=,iv:cCKPEDmPbMxT4LbPBzCNrhrcUELA1LCAcs+ZBkrSAyk=,tag:Ns5qeFvoCjqFqoblgzlK4A==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.7.3 diff --git a/workshops/secrets-management/sops/prod.yaml b/workshops/secrets-management/sops/prod.yaml new file mode 100644 index 0000000..fc803d2 --- /dev/null +++ b/workshops/secrets-management/sops/prod.yaml @@ -0,0 +1,22 @@ +username: ENC[AES256_GCM,data:vcMex+I=,iv:eY1MrNUES93AGHs24nYVnuqFHYmG1B4i6VqQZ7PVPDA=,tag:/8HMYqx023QudYse7TmwlA==,type:str] +password: ENC[AES256_GCM,data:O6rHH6bMbcdPfoAyfUrJphlM4iwUcj6p5SxV,iv:qLKe+ZbEvS3jH/nCkSCHsIeYz0ibdPtuZ50HOJHqlNo=,tag:U4zjqgSHAVH4lRffRFXADw==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1csncr656c24tu37as6h9upms7fyrz8xmc8d6cej07a8ck4wfyv0q8vphqn + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtOXBkNlc0L3RMSHh1amt6 + eFRjWXJGejB3aGQ0K2pzT2hicCsxVlI0MXpVCnBTSkpjSGhPRXQ4M3F2YnVRbHZT + VkRsTXhTcXFBZkJsbkRKUGdySFZ3S1EKLS0tIDdPeHRaWjYrVTJjWC84b2c2ajQ5 + cWVVem0xbzJiLzJndG9FVW1NT1BxL2MKOb/COpF4bib+YD0jAyz/VzUQP6D85TGE + eFr6umtM8wpauuXqOgVN2xOwIbx6BkXV18w7gPPRgKuHCLjsgpyt0A== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2023-02-09T19:16:03Z" + mac: ENC[AES256_GCM,data:VfYbTj0BvPPHBj7Vsv5MUnzt5qkhUcw+N30La9I/k29rBOVj/Z7xZyEn/5N1A62T/EprB1afXwI3zP2WXiVVy2oieFKCvvxekQtwwbqqEqpBoxR0cawRmAbp+dP57zWVoi6O4wE1FO7tDL94r10Z9w685vSnfWqH3VZJ6TuL5jo=,iv:qROVIqaCoYvGsTx9CACBsb3WtqwI6MbfqJNzMit5T0Y=,tag:BBdl4xQY38jsBgShOy2NXA==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.7.3 diff --git a/workshops/secrets-management/sops/unsafe/dev-key.txt b/workshops/secrets-management/sops/unsafe/dev-key.txt new file mode 100644 index 0000000..47f6c15 --- /dev/null +++ b/workshops/secrets-management/sops/unsafe/dev-key.txt @@ -0,0 +1,3 @@ +# created: 2023-02-09T12:09:08-07:00 +# public key: age1ehr903kf80pnd5fzcdssau9pgjv2talthe55e4h8p0tu68exqvvq0za8xx +AGE-SECRET-KEY-16QDKFYUFY78YQ5D34RFQMT49T2ERHD3K09LP832R6R6QUMSN8AVQU2UWAF diff --git a/workshops/secrets-management/sops/unsafe/prod-key.txt b/workshops/secrets-management/sops/unsafe/prod-key.txt new file mode 100644 index 0000000..9420468 --- /dev/null +++ b/workshops/secrets-management/sops/unsafe/prod-key.txt @@ -0,0 +1,3 @@ +# created: 2023-02-09T12:15:31-07:00 +# public key: age1csncr656c24tu37as6h9upms7fyrz8xmc8d6cej07a8ck4wfyv0q8vphqn +AGE-SECRET-KEY-1UEDV76T0EC6WGZT9NF0DA69XJCQQ0HFNPR8PAN7ZEH2S2RKZQD9Q44NSVY