From 37f01135d295aa5676576a263ae8dad05ea0c657 Mon Sep 17 00:00:00 2001 From: viv-codes Date: Sun, 3 Jul 2022 22:01:50 -0400 Subject: [PATCH 01/11] Started bringing changes from old re-write to dev --- _sass/_project_images.scss | 86 +++++++++++++++++++++++ _sass/_triple_image.scss | 130 +++++++++++++++++++++++++++++++++++ assets/css/main.scss | 21 ++++++ index.html | 136 ++++++++++++++++++++----------------- 4 files changed, 312 insertions(+), 61 deletions(-) create mode 100644 _sass/_project_images.scss create mode 100644 _sass/_triple_image.scss diff --git a/_sass/_project_images.scss b/_sass/_project_images.scss new file mode 100644 index 00000000..bdad158a --- /dev/null +++ b/_sass/_project_images.scss @@ -0,0 +1,86 @@ +.content { + position: relative; + width: 100%; + margin: auto; + overflow: hidden; +} + +.content-overlay { + background: rgba(0,0,0,0.7); + position: absolute; + height: 100%; + width: 100%; + left: 0; + top: 0; + bottom: 0; + right: 0; + opacity: 0; + -webkit-transition: all 0.4s ease-in-out 0s; + -moz-transition: all 0.4s ease-in-out 0s; + transition: all 0.4s ease-in-out 0s; +} + +.content:hover .content-overlay{ + opacity: 1; +} + +.content-image{ + width: 100%; +} + +.content-background { + background: rgba(0, 0, 0, 0.45); +} + +.content-details { + position: absolute; + text-align: center; + padding-left: 1em; + padding-right: 1em; + width: 100%; + top: 50%; + left: 50%; + opacity: 0; + -webkit-transform: translate(-50%, -50%); + -moz-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + -webkit-transition: all 0.3s ease-in-out 0s; + -moz-transition: all 0.3s ease-in-out 0s; + transition: all 0.3s ease-in-out 0s; +} + +.content:hover .content-details{ + top: 50%; + left: 50%; + opacity: 1; +} + +.content-details h3{ + color: #fff; + font-weight: 500; + letter-spacing: 0.15em; + margin-bottom: 0.5rem; + padding: auto; + text-transform: uppercase; +} + +.content-details p{ + color: #fff; + font-size: 0.8em; +} + +.fadeIn-bottom{ + top: 80%; +} + +@media screen and (max-width: 700px) { + .content-details{ + top: 50%; + left: 50%; + opacity: 1; + } + .content-overlay{ + opacity: 1; + } +} + diff --git a/_sass/_triple_image.scss b/_sass/_triple_image.scss new file mode 100644 index 00000000..7c16e331 --- /dev/null +++ b/_sass/_triple_image.scss @@ -0,0 +1,130 @@ +$card-size: 300px; +$p-m-default: 20px; + +$black: #111; +$white: #FFF; + +$csh-pink: #b0197e; +$csh-blue: #404b69; +$gray: #f4f4f6; + +// Easing Properties +$easeOutQuad: cubic-bezier(0.250, 0.460, 0.450, 0.940); + +// PX to EM +$browser-context: 16; + +@function em($pixels, $context: $browser-context) { + @if (unitless($pixels)) { + $pixels: $pixels * 1px; + } + + @if (unitless($context)) { + $context: $context * 1px; + } + + @return $pixels / $context * 1em; +} + +// Transition Mixin +@mixin transition($transition...) { + -moz-transition: $transition; + -o-transition: $transition; + -webkit-transition: $transition; + transition: $transition; +} + + +.triple_a { + @include transition(all 300ms $easeOutQuad); + &:hover { + @include transition(all 300ms $easeOutQuad); + } +} + +#wrapper { + position: relative; + display: flex; + height: 100vh; + align-items: center; + justify-content: center; +} + +.card { + background-image: linear-gradient(0deg, $csh-blue 0%, $csh-pink 100%); + width: $card-size; + height: $card-size; + margin: $p-m-default; + position: relative; + overflow: hidden; +} + +.card-image { + max-width: 100%; + width: 100%; + height: $card-size; + object-fit: cover; + transform: translate(0,0); + @include transition(all 400ms $easeOutQuad); +} + +.card-meta { + font-size: em(11); + text-transform: uppercase; + letter-spacing: 1px; + &:before { + content: ''; + height: 1px; + width: 30px; + background-color: #fff; + position: relative; + display: block; + margin-bottom: 10px; + backface-visibility: hidden; + opacity: 0; + transform: translate(0,-10px); + @include transition(all 200ms $easeOutQuad); + } +} + +.card-text { + color: #FFF; + // This next line controls the background opacity + background-color: rgba($black, .40); + position: absolute; + padding: $p-m-default; + z-index: 10; + width:100%; + height: 100%; + display: flex; + flex-wrap: wrap; + align-content: flex-end; + @include transition(all 200ms $easeOutQuad); +} + +.card-title { + margin: 8px 0; + font-weight: 300; + font-size: em(30); +} + +.card a { + &:hover { + .card-text { + background-color: rgba($black, .86); + } + .card-meta { + &:before { + transform: translate(0,0); + opacity: 1; + @include transition(all 200ms $easeOutQuad); + } + } + + .card-image { + transform: translate(20px,0); + @include transition(all 400ms $easeOutQuad); + } + } +} + diff --git a/assets/css/main.scss b/assets/css/main.scss index c4abc3ab..98764d85 100644 --- a/assets/css/main.scss +++ b/assets/css/main.scss @@ -41,6 +41,19 @@ img.rounded, box-shadow: 0 2px 15px darken($gray, 20%); } +.container { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-evenly; + align-items: flex-start; +} + +.quad_image { + display:grid; + grid-template-columns: 25% 25% 25% 25%; +} + .card-header { white-space: nowrap; overflow: hidden; @@ -79,6 +92,12 @@ a.btn { margin-bottom: 1em; } +@media screen and (max-width: 600px) { + .quad_image { + display: block; + } +} + @import "typography"; @import "nav"; @import "slider"; @@ -92,3 +111,5 @@ a.btn { @import "insights"; @import "footer"; @import "hackathon"; +@import "triple_image"; +@import "project_images.scss"; diff --git a/index.html b/index.html index fc48c975..c64871c0 100644 --- a/index.html +++ b/index.html @@ -59,6 +59,47 @@ + +

Getting more done after 2am than most people do all day.

+ + +
+ +
+
@@ -77,70 +118,43 @@
-
-
-
-

Recent posts

-
- {% for post in site.posts limit:2 %} - {% include post.html post=post %} - {% endfor %} - +

Things we're working on ...

+
+
+ +
+ A picture of CSH's server racks +
+

Server room upgrade

+

Bringing our servers up to date.

+ +
+
-
- -
-
-
-
-

Things we've done

+
+ +
+ TUNES, an old jukebox that's being made digital +
+

TUNES

+

Modernizing a jukebox

+ +
+
+
+ A LED matrix that makes up CSH's Infosys +
+

Infosys

+

A legacy CSH project that is being modernized.

-
-
-

Personal projects are a big part of CSH culture. Some of our biggest include Schedule Maker, CSH Arcade, Drink, and HAROLD.

- More projects -
-
-
- -
- - - - Two custom arcade machines in the CSH library - -
- - -
-
+
+
+
+ A raspberry pi and pencil sharpener on the wall, CSH's letmein system +
+

Letmein

+

A CSH project that is being modernized.

From 18dcbdb23693491e49a3dff77860905d612ac6f3 Mon Sep 17 00:00:00 2001 From: viv-codes Date: Sun, 3 Jul 2022 22:32:00 -0400 Subject: [PATCH 02/11] Fixed sizing of h2 elements --- _sass/_typography.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_sass/_typography.scss b/_sass/_typography.scss index d3e9c2e4..16cfa11e 100644 --- a/_sass/_typography.scss +++ b/_sass/_typography.scss @@ -19,7 +19,7 @@ h2 { } h3 { - font-size: 1em; + font-size: 1.2em; } .long-form { From 90fe872577d637f4c129212f8afba23b69722b9f Mon Sep 17 00:00:00 2001 From: viv-codes Date: Tue, 5 Jul 2022 11:10:13 -0400 Subject: [PATCH 03/11] Copied over scss to main.scss and added stats Copied over my scss to main.scss and added stats Most of my changes are done Most of my changes are done --- ...40b622142f1c98125abcfe89a76a661b0e8e343910 | 1 + ...4afa3e7e96fc556f465c0992924ebabfd6292af756 | 14 ++ ...1a9b212f16bc40feb65954b3a3669068809a9e5aaf | 34 +++++ ...a78fbdd8e880bf8defe68efecf24f1bf8c77cd23be | 7 + ...3ecfdc540f5a264222816a16463ae09e4b363d218d | 51 +++++++ ...cced91716603a100275d49d8a491d82bb112f09468 | 8 ++ ...f01829532ebdc7640729e41aa9587e5155b15c375c | 104 ++++++++++++++ ...3d511065ce1ab68e03b05974d239cede721ad0f2c1 | 4 + ...5908afba1a4bd28e0d7b39ad0d58ecfaea57fa5fd4 | 3 + ...ac6915a24f63eb28bffce1475458af57287624d086 | 66 +++++++++ ...bd88e00ff1834d33c6101e01810de1417a333f065d | 3 + ...26d441285a482edfb93b64d2cf349860d65878d3fd | 46 +++++++ ...c0a528532a8105201273036b461713342e15acf945 | 3 + ...c81e845f801e7e7e7d468f0e1b4b995f478d9885e1 | 2 + ...4fe311b6ba595a4d409feb98c8202b2135a36339af | 2 + ...c26c17c845deafd2461b961e7927eaeffdaa1b04ee | 11 ++ ...f2b2048c612ecb212df3a9aeb671468fa61ad1c067 | 102 ++++++++++++++ ...ad04cd44275496666eaf0a01d651f03b61a221eb77 | 2 + ...9e550d3271e53dfa6b7cbfffa7f5f6b62ae92d3e55 | 46 +++++++ ...bcdcb0e438b65c4b332365f11468c16186283c4735 | 15 +++ ...e2738b476459f7324a17156ee974382f440b47aae5 | 2 + ...d0ff10b5062fe22e50383ffd37f2e4024419c7e694 | 20 +++ ...9c12098e2281d6442011c23008f09767a7c028d2e8 | 8 ++ ...205f0c0e7bb4f401a7f03f286ed988f08dd54c8c64 | 127 ++++++++++++++++++ ...08e9b0f4c7a9c1a97908ef067056391f398d285c40 | 8 ++ ...f42b9ba45a00532717e136061b524ce73a6b26d45d | 21 +++ ...f18cf5c0b393bc5318616f882ef02b91515fd50bf3 | 15 +++ ...46bf8e096a2b055a696235d778f7fe5dca8483f93b | 19 +++ ...23bc6aee8306a8d99ed2ed61ac34b98ab3e530c261 | 30 +++++ ...067783866f8048ad0e2535e8111aaafb31a964ef5a | 21 +++ assets/css/main.scss | 29 ++++ index.html | 116 ++++++++++------ 32 files changed, 900 insertions(+), 40 deletions(-) create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Cache/b7/9606fb3afea5bd1609ed40b622142f1c98125abcfe89a76a661b0e8e343910 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/15/961cb7e9488ba78081074afa3e7e96fc556f465c0992924ebabfd6292af756 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/1d/9b3b71b82c85e9a7aa091a9b212f16bc40feb65954b3a3669068809a9e5aaf create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/33/33a70f253f5e69ec8367a78fbdd8e880bf8defe68efecf24f1bf8c77cd23be create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/39/2c071fc32472f89cd6f23ecfdc540f5a264222816a16463ae09e4b363d218d create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/50/ca0388e0cadc38b482f6cced91716603a100275d49d8a491d82bb112f09468 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/53/a1675002b9a85f6ff5d1f01829532ebdc7640729e41aa9587e5155b15c375c create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/5b/f859bd5210bcb9e0382c3d511065ce1ab68e03b05974d239cede721ad0f2c1 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/61/9a67067806d4685414df5908afba1a4bd28e0d7b39ad0d58ecfaea57fa5fd4 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/65/38e7727759bd92babc13ac6915a24f63eb28bffce1475458af57287624d086 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/65/95c5eada61eb054e98cfbd88e00ff1834d33c6101e01810de1417a333f065d create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/74/6719e16695760fd0951726d441285a482edfb93b64d2cf349860d65878d3fd create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/78/d39a7bd850bf08976c38c0a528532a8105201273036b461713342e15acf945 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/7b/e76c68504da603d660d6c81e845f801e7e7e7d468f0e1b4b995f478d9885e1 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/7f/a45229059b46a69c0b334fe311b6ba595a4d409feb98c8202b2135a36339af create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/87/c1fa14bbdf23c2488e77c26c17c845deafd2461b961e7927eaeffdaa1b04ee create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/96/91aa222263ed9d73ec34f2b2048c612ecb212df3a9aeb671468fa61ad1c067 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/96/e919bedc30d13e853fc5ad04cd44275496666eaf0a01d651f03b61a221eb77 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/98/08e8890a4d5c53cd9e2b9e550d3271e53dfa6b7cbfffa7f5f6b62ae92d3e55 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/98/447a95073f5707cb01adbcdcb0e438b65c4b332365f11468c16186283c4735 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/9e/644d899762f4766b529be2738b476459f7324a17156ee974382f440b47aae5 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/a7/ccec5326d17eadc5fd5dd0ff10b5062fe22e50383ffd37f2e4024419c7e694 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/ab/18ff029d3d3b134eed299c12098e2281d6442011c23008f09767a7c028d2e8 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/ac/afd3822c6c3644a6ca4c205f0c0e7bb4f401a7f03f286ed988f08dd54c8c64 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/ad/8affb1b769807241f87b08e9b0f4c7a9c1a97908ef067056391f398d285c40 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/b5/738787bf2d5b10a61c7df42b9ba45a00532717e136061b524ce73a6b26d45d create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/ba/5863a78508f264df4541f18cf5c0b393bc5318616f882ef02b91515fd50bf3 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/d3/5589a6c29bc05790123546bf8e096a2b055a696235d778f7fe5dca8483f93b create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/dc/896d487a831a97cb3d2823bc6aee8306a8d99ed2ed61ac34b98ab3e530c261 create mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/f5/b9218d5b026907fa5fb4067783866f8048ad0e2535e8111aaafb31a964ef5a diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Cache/b7/9606fb3afea5bd1609ed40b622142f1c98125abcfe89a76a661b0e8e343910 b/.jekyll-cache/Jekyll/Cache/Jekyll--Cache/b7/9606fb3afea5bd1609ed40b622142f1c98125abcfe89a76a661b0e8e343910 new file mode 100644 index 00000000..b44347fa --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Cache/b7/9606fb3afea5bd1609ed40b622142f1c98125abcfe89a76a661b0e8e343910 @@ -0,0 +1 @@ +I"B{"source"=>"/home/vivi/projects/CSHPublicSite", "destination"=>"/home/vivi/projects/CSHPublicSite/_site", "collections_dir"=>"", "cache_dir"=>".jekyll-cache", "plugins_dir"=>"_plugins", "layouts_dir"=>"_layouts", "data_dir"=>"_data", "includes_dir"=>"_includes", "collections"=>{"posts"=>{"output"=>true, "permalink"=>"/:categories/:year/:month/:day/:title:output_ext"}}, "safe"=>false, "include"=>[".htaccess"], "exclude"=>[".sass-cache", ".jekyll-cache", "gemfiles", "Gemfile", "Gemfile.lock", "node_modules", "vendor/bundle/", "vendor/cache/", "vendor/gems/", "vendor/ruby/"], "keep_files"=>[".git", ".svn"], "encoding"=>"utf-8", "markdown_ext"=>"markdown,mkdown,mkdn,mkd,md", "strict_front_matter"=>false, "show_drafts"=>nil, "limit_posts"=>0, "future"=>false, "unpublished"=>false, "whitelist"=>[], "plugins"=>["jekyll-feed", "liquid-md5", "jekyll-regex-replace"], "markdown"=>"kramdown", "highlighter"=>"rouge", "lsi"=>false, "excerpt_separator"=>"\n\n", "incremental"=>false, "detach"=>false, "port"=>"4000", "host"=>"127.0.0.1", "baseurl"=>"", "show_dir_listing"=>false, "permalink"=>"date", "paginate_path"=>"/page:num", "timezone"=>nil, "quiet"=>false, "verbose"=>false, "defaults"=>[], "liquid"=>{"error_mode"=>"warn", "strict_filters"=>false, "strict_variables"=>false}, "kramdown"=>{"auto_ids"=>true, "toc_levels"=>[1, 2, 3, 4, 5, 6], "entity_output"=>"as_char", "smart_quotes"=>"lsquo,rsquo,ldquo,rdquo", "input"=>"GFM", "hard_wrap"=>false, "guess_lang"=>true, "footnote_nr"=>1, "show_warnings"=>false, "syntax_highlighter"=>"rouge", "syntax_highlighter_opts"=>{:default_lang=>"plaintext", :guess_lang=>true}, "coderay"=>{}}, "title"=>"Computer Science House", "email"=>"webmaster@csh.rit.edu", "description"=>"Write an awesome description for your new site here. You can edit this line in _config.yml. It will appear in your document head meta (for Google search results) and in your feed.xml site description.", "url"=>"http://localhost:4000", "twitter_username"=>"CSH_HISTORY", "github_username"=>"computersciencehouse", "theme"=>"minima", "livereload_port"=>35729, "serving"=>true, "watch"=>true}:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/15/961cb7e9488ba78081074afa3e7e96fc556f465c0992924ebabfd6292af756 b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/15/961cb7e9488ba78081074afa3e7e96fc556f465c0992924ebabfd6292af756 new file mode 100644 index 00000000..4717f0e1 --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/15/961cb7e9488ba78081074afa3e7e96fc556f465c0992924ebabfd6292af756 @@ -0,0 +1,14 @@ +I"7

The Problem

+

CSH currently uses Proxmox for VM hosting. It has been working great for every use case we have for it with one exception: member VM self-service. The interface isn’t very intuitive to someone who might not have created a VM before, creating a higher barrier to entry than we would like for members who might want to start learning how to use Linux for the first time. It also lacked the ability to enforce resource limits and automatically cleanup VMs that members weren’t using anymore. All of my previous major projects were much more operations and/or security focused so I figured writing something to solve this problem would be a great way to do a much more development focused project and expand my developer skillset.

+ +

The Solution

+

Proxstar (a mashup of Proxmox, a VM hosting solution, and STARRS, an IP/DNS/DHCP management system) is a web application that allows for easy VM self-service for the members of CSH. It is written in Python using Flask and runs on the CSH OpenShift cluster. RQ is being used as a task queue for tasks that take more than a second or two and periodic tasks (RQ-Scheduler). Proxstar allowed members to create, edit, and delete VMs and will automatically handle any network registration that needs to be done in STARRS for them. During creation, they can specify to either create it from a template or to install it themselves from an ISO. If creating it from a template, Proxstar will spin up a ready-to-go VM with a a user that has a randomly generated password for the member to use.

+ +

Making RTPs’ Lives Easier

+

Having to periodically go through and clean up VMs that haven’t been touched by members in months can be a tedious task. Enforcing usage limits can also be difficult since Proxmox doesn’t have a mechanism for doing so. Proxstar allows RTPs to set a limit on the number of CPU cores and amount of memory and disk space a member can utilize. It also sets an expiration date on each new VM, emails the member before it expires, and automatically deletes any VMs that aren’t renewed.

+ +

Struggles

+

The hardest part of the project was figuring out how to give console access to members. Proxmox does not provide a friendly way to access their VNC consoles, so I had to dig into it to figure out how they did it and try to do a similar thing within Proxstar. Upon clicking the ‘Console’ button, Proxstar generates a valid token for the port that the noVNC session will be spun up on. It then forwards the port that the actual VNC session will be spun up on from the respective Proxmox host to the noVNC instance within Proxstar and starts the VNC session for the VM on Proxmox. Finally, Proxstar opens a new tab with the noVNC session and a valid token to access it. It isn’t the cleanest solution, but it has held up pretty well.

+ +
Feel free to check out the source code for Proxstar here!
+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/1d/9b3b71b82c85e9a7aa091a9b212f16bc40feb65954b3a3669068809a9e5aaf b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/1d/9b3b71b82c85e9a7aa091a9b212f16bc40feb65954b3a3669068809a9e5aaf new file mode 100644 index 00000000..359f5c3f --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/1d/9b3b71b82c85e9a7aa091a9b212f16bc40feb65954b3a3669068809a9e5aaf @@ -0,0 +1,34 @@ +I"

Check out this post on Galen’s blog!

+ +

Today, a friend posted the following snippet in Slack:

+
 [~/Documents/shelflife] [±docker✗] $ docker run -v -it --rm --name my-running-app shelflife-rust-docker
+    Error: NotPresent
+

The first guess was that they had deleted the docker image and forgot to rebuild it. That wasn't the case, leading me to dive into this cryptic error message that we assumed was some hidden Rust or Docker error. We weren't able to find any example of this error message for Rust or Docker online, so I knew this would be a fun challenge.

+ +

The first thing I did was to make sure the path to the binary was working, as it'd be silly if this wasn't working because /usr/local/bin wasn't in the container's PATH. I changed the last line in the Dockerfile from CMD ["shelflife"] to ENTRYPOINT ["/usr/local/bin/shelflife"]. The error persisted, which meant it wasn't a PATH error. Of course this couldn't be easy.

+ +

The next step in diagnosis was to get a shell on the container. That would typically be done via docker exec, but that only works on a running container, which we didn't have. To get around this, I changed the last line of the Dockerfile to ENTRYPOINT ["/bin/bash"], which makes docker run -it drop you into an interactive bash shell. This means I could easily see what was going on and run commands from inside the container.

+ +

Now that I had a shell, I navigated to /usr/local/bin/ and ran ./shelflife to check if there was any output docker was hiding. Unfortunately, there wasn't. I was at roughly the same place as when I started - a cryptic error message and no idea where it was coming from. At least now I was decently sure it wasn't not a docker issue.

+ +

I'd run into issues with dynamically linked libraries not being installed in the past, so I used ldd (List Dynamic Dependencies) to make sure all the dependencies existed. Everything looked fine, and I double-checked by manually installing the library packages for everything ldd said was linked. Everything was already installed, but the error persisted.

+ +

The last thing I tried was installing strace, a tool for tracing system calls, and running strace ./shelflife. This gave me a huge output full of system calls, but near the bottom was something that looked familiar, the text "NotPresent". Now I knew I was on the right path! The relevant output that got me to the final answer was the following:

+ +
getcwd("/usr/local/bin", 512)           = 15
+statx(0, NULL, AT_STATX_SYNC_AS_STAT, STATX_ALL, NULL) = -1 EFAULT (Bad address)
+statx(AT_FDCWD, "/usr/local/bin/.env", AT_STATX_SYNC_AS_STAT, STATX_ALL, 0x7ffc04639b10) = -1 ENOENT (No such file or directory)
+statx(AT_FDCWD, "/usr/local/.env", AT_STATX_SYNC_AS_STAT, STATX_ALL, 0x7ffc04639930) = -1 ENOENT (No such file or directory)
+statx(AT_FDCWD, "/usr/.env", AT_STATX_SYNC_AS_STAT, STATX_ALL, 0x7ffc04639750) = -1 ENOENT (No such file or directory)
+statx(AT_FDCWD, "/.env", AT_STATX_SYNC_AS_STAT, STATX_ALL, 0x7ffc04639570) = -1 ENOENT (No such file or directory)
+write(2, "Error: ", 7Error: )                  = 7
+write(2, "NotPresent", 10NotPresent)              = 10
+write(2, "\n", 1
+)                       = 1
+sigaltstack({ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=8192}, NULL) = 0
+munmap(0x7fb5000f2000, 8192)            = 0
+exit_group(1)                           = ?
++++ exited with 1 +++
+ +

There it is! Right before exiting, there's several checks for a .env file that all fail. This error didn't happen when run locally, because my friend already made a .env file. However, I never created one, and more critically, the Dockerfile never copied their version of the file into the image. Once we created a .env file and added COPY .env . to the Dockerfile, it started as intended! This wasn't an issue with Docker or Rust at all, but a library giving an unhelpful error message. We couldn't find any documentation of this online, so I hope this post might serve to help anyone else who runs into this issue!

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/33/33a70f253f5e69ec8367a78fbdd8e880bf8defe68efecf24f1bf8c77cd23be b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/33/33a70f253f5e69ec8367a78fbdd8e880bf8defe68efecf24f1bf8c77cd23be new file mode 100644 index 00000000..14e8a452 --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/33/33a70f253f5e69ec8367a78fbdd8e880bf8defe68efecf24f1bf8c77cd23be @@ -0,0 +1,7 @@ +I"

Summary

+

Capsule Killer is a first-person shooter that I developed to learn more about the skills and +processes involved with game development. Upon launching the game, the player will be met with a main menu that allows them to start a game, +view the controls, or exit the game. When a player starts a game, they will spawn in the center of the map and enemies will begin spawning +at random locations throughout the map every 2-5 seconds. The enemies move towards the player, doing damage upon collision with the player. +The player has the ability to run away from and shoot enemies. The goal of the game is to defeat as many enemies as possible.

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/39/2c071fc32472f89cd6f23ecfdc540f5a264222816a16463ae09e4b363d218d b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/39/2c071fc32472f89cd6f23ecfdc540f5a264222816a16463ae09e4b363d218d new file mode 100644 index 00000000..d80545a0 --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/39/2c071fc32472f89cd6f23ecfdc540f5a264222816a16463ae09e4b363d218d @@ -0,0 +1,51 @@ +I"E

Summary

+

Smart shades is a web service that allows one to control their window shades using a website. +The hardware requirement is a Raspberry Pi (connected to the Internet), a stepper motor, housing for the stepper motor (3D printed), a stepper motor driver (I used the Pololu A4988), a 10K ohm resistor, and a domain. +The application uses Python, Flask, OpenShift in the back end, Bootstrap, JavaScript, and Ajax. +In short, there are two Flask apps running, one on a CSH domain and one on the Pi. +The Flask app on the CSH website has the JavaScript and Ajax to make requests to the Flask app on the Pi, which can then take care of changing the window shades.

+ +

The Story

+

I picked up this IOT project from R&D. +Spencer, our current R&D director, had the hardware (stepper motor, housing for stepper motor, and the stepper motor driver) and asked if someone could do the software by ImagineRIT. +I had some ideas for ImagineRIT, but this one seemed more fun than the rest of them. +I went into this knowing how to code, specifically in Python, but not having a great understanding of how to incorporate the hardware with the software, including web application integration. +I started the project by figuring out how to use RPi.GPIO library by making a simple program with LEDs. +Then I started using the stepper motor driver and the stepper motor. +This ended up being a hardware problem, not a software one. +After countless hours I figured out that I can connect an LED to 2 of the 4 pins of the motor and if the LED lights up upon turning the motor then I have found a pair of wires. +From there I had to figure out how stepper motors work in software, which comparatively was not that difficult.

+ +

The next part of this project was controlling the motor from a website. +I started by reading about Flask and making a quick Hello world application on the IP on the Pi. +Since Flask uses python, and so does my code for the shades, I was simply able to combine the two. +I learned about HTML and bootstrap while creating the index page for this application.

+ +

I now needed a domain that people could type in, because remembering an IP address is only possible when you type it in countless times as the developer. +Thankfully, our OpComm director, Steven, helped me out during the OpCommathon by showing me OpenShift. +As soon as I ran it up, it crashed. +Rpi.GPIO imports can only be run on a Raspberry Pi… I eventually decided to make a second Flask app that would simply run on the CSH domain and link to the IP of the Pi. +This, however, was not ideal because every time you changed the height of the shade, the page would reload. +That is neither pretty nor efficient. +To make the matters worse, the link was to an IP address, and a real world application should not be pointing to an IP address. +I asked around, and upon the suggestion of our financial director, Devin, I decided to implement Ajax.

+ +

I had never used JavaScript, nor Ajax prior to this, so it was a bit of learning curve. +Obstacle one was making the script work; aside from syntax, it took a while to realize that script needed to be called after the buttons were created. +Then came other obstacles, such as not being able to POST to Pi because it ran on HTTP and the website ran on HTTPS. +Somewhere in there I had to implement CORS or Cross-Origin Resource Sharing, lack of it crashes the program. +With the help of our chairman, Jordan, I was able to get the Flask application on the Pi running on HTTPS, thereby allowing communication between the CSH domain and the Pi.

+ +

I proceeded to add some more functionality to this application after OpCommathon. +This took a couple day’s worth of work because I was still learning JavaScript. +Now you can click buttons to set the height as a percentage, change how many steps or pulses the motor requires to make the shade go from completely down to completely up, and move the motor n steps at a time for debugging purposes. +Furthermore, it shows the current shade percentage. +The idea behind showing that information is that if it does not match up with what you have physically in front of you, then you will know that you need to change your values for the program. +The best part is that the page does not reload upon calling a function, the two apps simply talk to each other.

+ +

Altogether, this project was a lot of fun. +I learned quite a bit, both in the software world and hardware world. +ImagineRIT is still weeks from now, and as a result I plan on adding Amazon Alexa Skill to this, or someway of using voice command to perform the same actions.

+ +

P.S. For details on wiring components, please visit the GitHub source of this project here.

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/50/ca0388e0cadc38b482f6cced91716603a100275d49d8a491d82bb112f09468 b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/50/ca0388e0cadc38b482f6cced91716603a100275d49d8a491d82bb112f09468 new file mode 100644 index 00000000..7f8e417d --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/50/ca0388e0cadc38b482f6cced91716603a100275d49d8a491d82bb112f09468 @@ -0,0 +1,8 @@ +I">

SUDS, or the Shower Use Detection System, shows the status of the showers in our dorm hall, which is located on the third floor of Nathaniel Rochester Hall. When someone is in the shower and the door is locked, an LED on a panel in the hall next to the bathroom illuminates. In addition to the LEDs outside of the bathroom, I will be creating a web app to track live status updates remotely, and potentially collect statistics on when the showers/stalls are most used.

+ +

SUDS is the first big hardware project that I have ever actually done, and the first time I have soldered my own board (outside of soldering headers onto MCUs and chips). The web app that I am going to build will be my first time using a MySQL database and creating a server-side backend that handles all of the input from the bathrooms.

+ +

SUDS is a project that was first created by CSHers a few years ago. It was originally a simple circuit driven by AA batteries, but my version runs on a Raspberry Pi.

+ +

SUDS is driven by a Raspberry Pi in the bathroom ceiling, which outputs 5V; for future versions I will be making the circuit draw 3.3V to decrease the brightness of the LEDs. The current then goes to a limit switch on the door lock which closes the circuit and illuminates the LED for that shower. The wiring diagrams can be found on the GitHub page. On the proto-board, on the same row as the anode of the LED, there is a pulldown resistor that leads to the GPIO pin corresponding to that shower.

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/53/a1675002b9a85f6ff5d1f01829532ebdc7640729e41aa9587e5155b15c375c b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/53/a1675002b9a85f6ff5d1f01829532ebdc7640729e41aa9587e5155b15c375c new file mode 100644 index 00000000..e0119e5f --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/53/a1675002b9a85f6ff5d1f01829532ebdc7640729e41aa9587e5155b15c375c @@ -0,0 +1,104 @@ +I"]

What is Swiftfall?

+ +

Swiftfall is an API wrapper written in Swift for the API Scryfall.

+ +

Scryfall is an API which handles information about the card game Magic: The Gathering.

+ +

I like Magic the Gathering, but getting tons of information about Magic cards is really annoying, especially if you don’t want to or don’t know how to implement a JSON parser or make requests to a website. Many newer developers would like to combine their passions but it’s not always easy.

+ +

Thankfully, Scrython does this already, but in Python.

+ +

Why Swift Was Appealing

+
    +
  1. Swift’s use of optionals was really appealing. Sometimes you can’t be absolutely sure about whether or not a request has been successful. Optionals allow a developer to handle those situations extremely safely.
  2. +
  3. Swift has a JSON decoder built in and it is appealing to have no dependencies.
  4. +
  5. iOS, Apple TV, Apple Watch, and MacOS development are all far easier in Swift
  6. +
  7. Swift is new, and it is fun to do things never done before
  8. +
+ +

How do you use Swiftfall?

+

First, create an executable package. The executable includes a Hello World function by default.

+ +
$ mkdir MyExecutable
+$ cd MyExecutable
+$ swift package init --type executable
+$ swift build
+$ swift run
+Hello, World!
+
+ +

Next,

+ +
$ swift package generate-xcodeproj
+
+ +

This creates the correct package files so you can add dependencies.

+ +

Then, add Swiftfall as a dependency for the executable.

+ +
import PackageDescription
+
+let package = Package(
+    name: "MyExecutable",
+    dependencies: [
+        // Dependencies declare other packages that this package depends on.
+        // .package(url: /* package url */, from: "1.0.0"),
+        .package(url:"https://github.com/bmbowdish/Swiftfall.git", from: "1.2.0")
+    ],
+    targets: [
+        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
+        // Targets can depend on other targets in this package, and on products in packages which this package depends on.
+        .target(
+            name: "MyExecutable",
+            dependencies: ["Swiftfall"]),
+    ]
+)
+
+ +

Then, run:

+ +
$ swift package generate-xcodeproj
+
+ +

I believe this is because you need to pull down the new dependencies from the source.

+ +

Now you’re ready to use Swiftfall!

+ +

Actually Using Swiftfall

+ +

Getting a Card

+

Swiftfall.getCard(fuzzy:String) -> Card? _(Fuzzy search)_

+ +

Swiftfall.getCard(exact:String) -> Card? _(Exact search)_

+ +

Swiftfall.getRandomCard() -> Card? _(Random Card)_

+ +

Ex.

+ +
import Swiftfall
+let card = Swiftfall.getCard(exact:"Black Lotus")
+card?.simplePrint()
+
+ +

Out.

+ +
Name: Black Lotus
+Cost: {0}
+Type Line: Artifact
+Oracle Text:
+{T}, Sacrifice Black Lotus: Add three mana of any one color to your mana pool.
+
+ +

Other Things

+

Swiftfall supports more than just cards. Other items you can retrieve include:

+ +
    +
  • Sets
  • +
  • Rulings
  • +
  • Ruling Lists
  • +
  • Card Lists
  • +
  • Set Lists
  • +
+ +

You can find more information about Swiftfall on GitHub.com

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/5b/f859bd5210bcb9e0382c3d511065ce1ab68e03b05974d239cede721ad0f2c1 b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/5b/f859bd5210bcb9e0382c3d511065ce1ab68e03b05974d239cede721ad0f2c1 new file mode 100644 index 00000000..da4a409a --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/5b/f859bd5210bcb9e0382c3d511065ce1ab68e03b05974d239cede721ad0f2c1 @@ -0,0 +1,4 @@ +I"j

Overview

+

Resume Review is a web app written for CSHers to upload their resumes and receive feedback on them. +Members can prepare for career fairs, company visits, and job applications by running their resumes by their peers, requesting specific changes or just asking for general opinions.

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/61/9a67067806d4685414df5908afba1a4bd28e0d7b39ad0d58ecfaea57fa5fd4 b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/61/9a67067806d4685414df5908afba1a4bd28e0d7b39ad0d58ecfaea57fa5fd4 new file mode 100644 index 00000000..2266a07d --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/61/9a67067806d4685414df5908afba1a4bd28e0d7b39ad0d58ecfaea57fa5fd4 @@ -0,0 +1,3 @@ +I"

What Is It?

+

This program, Clādēs Cimicum, (which means ‘Bane of Bugs’ in Latin) is a very small and simple debugger for interprocess debugging. This is slightly different from that of GDB, since GDB actually creates a child process when debugging. Cladēs Cimicum can read the memory of any running process, without having to be run in some special environment beforehand.

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/65/38e7727759bd92babc13ac6915a24f63eb28bffce1475458af57287624d086 b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/65/38e7727759bd92babc13ac6915a24f63eb28bffce1475458af57287624d086 new file mode 100644 index 00000000..906fb2e4 --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/65/38e7727759bd92babc13ac6915a24f63eb28bffce1475458af57287624d086 @@ -0,0 +1,66 @@ +I"

Hey there!

+ +

If you’ve made it this far, you’re probably thinking about becoming a member. +That’s great! We need curious and motivated people like you. I want to take a +minute and walk you through our intro process so that you know what to expect; +there’s a handful of steps involved and I want you to have a clear idea of +what you’re getting yourself into.

+ +

The majority of the intro process takes place during the first 10 weeks of +school. The first 2 weeks are what we call “packet season”. Packet season is +all about meeting people - we want CSH to be a tight-knit community, so we +believe that every member should meet every other member. A Packet is a list +of the names of all active CSH members, and one is given to every intro member. +Your job as an incoming CSHer is to seek out and meet as many active members +as you can. This isn’t as easy as hide-and-seek. Once you find an upperclassman, +you have to put in an effort to genuinely get to know them! Ask them about what +their interests are, what projects they’ve done, or how their co-op experiences +have gone. Active members will sign your packet if they think you’d make a good +member of CSH, which is usually the case if you show that you’re passionate and +interested in what you do. After packet season is over, we’ll count up all of +the signatures you’ve collected. If you get a passing percentage of signatures, +congratulations! You’ll receive a CSH account and gain access to all of our +house computer services. If not, there’s still hope! The packet is just one +component of your 10-week evaluation.

+ +

We have a handful of other objectives for you during the 10-week intro process. +These requirements are intended to introduce you to our house culture and +traditions, and are things that active members continue to do throughout their +entire membership. One of the first things we ask you to do is attend some of +our directorship meetings. Each of our 7 directors hosts a weekly meeting where +they discuss ongoing projects, upcoming events, or other news that falls in +their domain. Intro members are expected to attend any 10 directorship meetings +during the 10-week evaluation period, preferably at least one a week. Another +cornerstone of CSH culture is the presentation of technical seminars! Technical +seminars early in the year are usually given by upperclassmen and tend to focus +on introducing you to the world of computer science. Common early-year topics +include setting up basic coding tools, intro to Linux operating systems, +version control for code, and more. Upperclassmen volunteer a lot of time to +prepare seminars, so we ask every intro member to attend at least 2 of them +during their 10 weeks. Plus, this is a special-interest house for computer +science, you probably want to attend as many seminars as you can.

+ +

Our last but most important requirement is for you to attend all of our house +meetings. House meetings happen every Sunday at 7:15pm, and are where the +directors summarize house news and events for the past week and upcoming weeks. +This meeting is required because it’s the one time we have a chance to address +all of house together, and is when we make large decisions as a group. Though +we require you to attend every house meeting, we also understand that life +happens. If you can’t make it because you’re sick or out of town, just let +our Evaluations director know and they’ll write a note about your absence.

+ +

At the end of the 10-week intro process, all of the upperclassmen gather +together to vote on intro members. During this meeting, we look at the big +picture of how well you’ve met the requirements and who you are as a person. +Did you attend at least 10 directorship meetings? Did you get a good score on +packet? Are you a curious and engaged member? Are you friendly and +light-hearted? Remember, we want CSH to be a welcoming and inclusive +community, but we’re also looking for the mad scientist in each of you.

+ +

I hope that this has given you a good idea of what to expect when signing up +for CSH. It’s a crazy ride for sure, but it’s totally worth it. If anything, +I hope I’ve talked you into applying. I look forward to meeting you all when +school starts!

+ +

-@nickm

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/65/95c5eada61eb054e98cfbd88e00ff1834d33c6101e01810de1417a333f065d b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/65/95c5eada61eb054e98cfbd88e00ff1834d33c6101e01810de1417a333f065d new file mode 100644 index 00000000..c177078c --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/65/95c5eada61eb054e98cfbd88e00ff1834d33c6101e01810de1417a333f065d @@ -0,0 +1,3 @@ +I"

Background

+

Computer Science House purchased a robot chasis from one of our members in the Spring semester of 2017. I had worked on previous versions of the CSH H.E.R.O.I.N project and thought I would be able to make significant strides given we now had a stable robot chassis. So, using robot operating system constructs and several new pieces of hardware/sensors, I added mapping functionality to Kudos.

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/74/6719e16695760fd0951726d441285a482edfb93b64d2cf349860d65878d3fd b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/74/6719e16695760fd0951726d441285a482edfb93b64d2cf349860d65878d3fd new file mode 100644 index 00000000..97b63521 --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/74/6719e16695760fd0951726d441285a482edfb93b64d2cf349860d65878d3fd @@ -0,0 +1,46 @@ +I"V

Background

+ +

In the Fall of 2017, I created a Slack channel for Computer Science House called #game-night (formerly known as #card-games). The purpose of the channel was to help the organization’s members get together to play many of the fun board and card games owned by CSH. As of the Spring of 2018, the channel has really been taking off. Seeing that rise in popularity, I decided to do more with this neat corner of CSH and develop a web application that would benefit those who frequented the game nights and the organization as a whole.

+ +

Introducing Game Night

+ +

I created a fully searchable database of our available games called Game Night. When landing on the home page, the web application lists out all of the games in the database, but since it could be a lot to scroll through, there are ways in which the results can be filtered down.

+ +

The site provides a search field at the top to help users match games in the database that contain a certain keyword or string. If one happens to be familiar with regular expressions, they can use those in their queries. For example, searching with the query b will match all games that contain a b in their name, and searching with the regex query ^b will match all games that start with a b. These queries are case-insensitive.

+ +

In a situation where a number of people have gathered together and would like to figure out which games support that number of players, there is an additional search option for doing just that. By clicking on the button next to the search field, a small menu will appear with a dropdown selection for choosing the number of players. Since each game in the database has properties that represent the minimum and maximum number of players it supports, all the games returned in this query will be those that have the user-specified number of players fall within those ranges. This filtering option can be combined with the textual search option.

+ +

Lastly, in that same menu there is a button for retrieving a random game from the database. This random option can be filtered by the aforementioned search options too.

+ +

The RESTful API

+ +

I made sure from the very beginning that Game Night would have a RESTful API exposed for CSH members to use. The API endpoint starts at https://game-night.csh.rit.edu/api. Similar to the index page without a search query, it returns all of CSH’s games, but in JSON format. The API can be filtered by adding on URL query parameters such as name and players to the end. An example would be https://game-night.csh.rit.edu/api?players=10, which returns all games in JSON format that support 10 players. The API endpoint for retrieving a random game is also available at https://game-night.csh.rit.edu/api/random and is filterable in the same way.

+ +

The Technology Stack

+ +

The primary tools I used to develop this web application were Python, Bootstrap 4, Flask and MongoDB. I had never used Flask before, but I was familiar with the similar Express framework used in Node.js. Going from Express to Flask, I grew to absolutely love the Flask framework even more than Express. I found its methodology of using decorators to handle responses to URL routes very elegant. I decided to use MongoDB over the more common MySQL or PostgreSQL for a few reasons:

+ +
    +
  1. It was an opportunity to learn something new.
  2. +
  3. Since I was only storing games in the database and there were no dependencies on other types of data, I did not need to make use of features offered by typical SQL-based relational database management systems such as foreign keys and joins.
  4. +
  5. MongoDB stores data in a format almost identical to JSON called BSON, meaning it is simpler to translate that to a format suitable for rendering in a view or returning in a RESTful API. Using a SQL-based RDMS typically requires an ORM.
  6. +
+ +

Like many other CSH services, Game Night is behind OIDC authentication.

+ +

Future Plans

+ +

A project like this has a lot of room for augmentation, and I plan on continuing work on it throughout the remainder of my time at RIT. Some features I’ve already thought about implementing are:

+ +
    +
  1. A way for users to upload games to the database through the web interface. Currently, only I can upload games.
  2. +
  3. Including games that are owned by individual CSH members. If the above feature were implemented, then a user uploading a game could specify whether they own it or it belongs to floor.
  4. +
  5. Keeping track of games that are up for trade or being borrowed. If a member would like to borrow a game to use outside of CSH for some time, there should be a way of updating that game’s entry in the database to show that it’s currently in use by someone.
  6. +
+ +

Any changes made will be pushed to the project’s GitHub repository.

+ +

Special Thanks

+ +

Thank you to Jordan for creating my OIDC client credentials and thank you to Zoe for helping me compile the initial list of the games.

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/78/d39a7bd850bf08976c38c0a528532a8105201273036b461713342e15acf945 b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/78/d39a7bd850bf08976c38c0a528532a8105201273036b461713342e15acf945 new file mode 100644 index 00000000..376041f5 --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/78/d39a7bd850bf08976c38c0a528532a8105201273036b461713342e15acf945 @@ -0,0 +1,3 @@ +I"

The Problem

+

CSH currently uses Proxmox for VM hosting. It has been working great for every use case we have for it with one exception: member VM self-service. The interface isn’t very intuitive to someone who might not have created a VM before, creating a higher barrier to entry than we would like for members who might want to start learning how to use Linux for the first time. It also lacked the ability to enforce resource limits and automatically cleanup VMs that members weren’t using anymore. All of my previous major projects were much more operations and/or security focused so I figured writing something to solve this problem would be a great way to do a much more development focused project and expand my developer skillset.

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/7b/e76c68504da603d660d6c81e845f801e7e7e7d468f0e1b4b995f478d9885e1 b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/7b/e76c68504da603d660d6c81e845f801e7e7e7d468f0e1b4b995f478d9885e1 new file mode 100644 index 00000000..761b8aaf --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/7b/e76c68504da603d660d6c81e845f801e7e7e7d468f0e1b4b995f478d9885e1 @@ -0,0 +1,2 @@ +I"

Check out this post on Galen’s blog!

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/7f/a45229059b46a69c0b334fe311b6ba595a4d409feb98c8202b2135a36339af b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/7f/a45229059b46a69c0b334fe311b6ba595a4d409feb98c8202b2135a36339af new file mode 100644 index 00000000..93078f2c --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/7f/a45229059b46a69c0b334fe311b6ba595a4d409feb98c8202b2135a36339af @@ -0,0 +1,2 @@ +I"0

Why it exists:

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/87/c1fa14bbdf23c2488e77c26c17c845deafd2461b961e7927eaeffdaa1b04ee b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/87/c1fa14bbdf23c2488e77c26c17c845deafd2461b961e7927eaeffdaa1b04ee new file mode 100644 index 00000000..f5bdbed3 --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/87/c1fa14bbdf23c2488e77c26c17c845deafd2461b961e7927eaeffdaa1b04ee @@ -0,0 +1,11 @@ +I"<

This project involves the use of a simple four layer deep-learning neural network written in C that I built from scratch which leverages the sigmoid activation function along with backpropagation to assist previous layers with correction. The option for variable size and count of the training data allows for the network to optimally determine and associate patterns in any zero padded binary data. This also allows for the simulation of full-batch training. The option to export the trained synaptic weights is also available. This allows you to train the network on a certain set of data, export the synapses, and then later import them to run the network in validation mode.

+ +

Thanks to OpenGL, ( more specifically the OpenGL, OpenGL ES, and Vulkan development library GLFW, and GLEW for function pointer association ) you are able to watch the neural network learn. The fact that the base network is 4 layers is important for this implementation because that means that there are 3 synaptic weight matrices, therefore, allows me to easily map each synapse to a respective Cartesian coordinate axis (X,Y,Z). I then render the location of the normalized ( -1.0 to 1.0 ) synaptic weight values to the screen and redraw each frame without clearing so a path can be seen ( default mode ).

+ +

Three visualization modes are available: Default, Line, Dot, and Tri. ( The picture shown is tri ). These options can be changed via compiling with the respective flag. I have yet to implement rotation so all that can really be seen right now is X and Y.

+ +

The visualization of the synapse deltas during training greatly slows the training loop due to the overhead of OpenGL, but this could probably be minimized with a multi-threaded support.

+ +

For more info on running/compiling and more screen shots, Check it out on Github!

+ +:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/96/91aa222263ed9d73ec34f2b2048c612ecb212df3a9aeb671468fa61ad1c067 b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/96/91aa222263ed9d73ec34f2b2048c612ecb212df3a9aeb671468fa61ad1c067 new file mode 100644 index 00000000..ea7235f8 --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/96/91aa222263ed9d73ec34f2b2048c612ecb212df3a9aeb671468fa61ad1c067 @@ -0,0 +1,102 @@ +I"

Computers do math quite fast, but how fast? Well, the answer to that question changes quite significantly depending on +the programming language being used.

+ +

To explore this relationship I implemented a common collision detection algorithm called separating axis theorem +in Python, Rust, and Kotlin. This algorithm uses linear algebra to check if two convex 2D polygons are overlapping. +Since this is a linear algebra algorithm most of the work is repetitive arithmetic. This makes it a relatively good +test of raw execution speed.

+ +

Even before running the code I can expect Python to be +the slowest since it’s the only interpreted language being tested. Rust, +on the other hand, is compiled down to machine code so it should be significantly faster. Kotlin +should be somewhere in the middle since it’s compiled but runs in the Java Virtual Machine instead of directly on the +hardware.

+ +

The metric I’ll be measuring here is the wall-clock execution time. Note that this approach has an inherent amount of +inaccuracy due to how operating systems handle process scheduling. However, it’s also the metric that’s most immediately +understandable and comparable so it works well for this situation.

+ +

The actual program that I’m using takes two objects and sets their center points 100 pixels away from each other. Then +one object is moved towards the other in steps of 1 pixel at a time until the algorithm detects collision. This process +is then repeated 10,000 times in order to build up a sufficiently long execution time to get an accurate comparision.

+ +

Here are the results from running this test. Note how Kotlin and Rust have fairly similar results even though Kotlin +runs in the JVM.

+ + + + + + + + + + + + + + + + + + + + + + + + +
CPU used for the testTime for PythonTime for KotlinTime for Rust
Intel Core i7-8550U21.800 seconds0.308 seconds0.230 seconds
AMD A10-6800K40.617 seconds0.767 seconds0.465 seconds
+ +

Now this is a pretty naive implementation. The two objects are 10 and 1 pixels across respectively so it takes a lot of +iterations before they collide. This algorithm takes the most time to run when the objects aren’t touching so it would +be quite helpful if there was a way to skip over at least some of the iterations where they aren’t touching.

+ +

It turns out that it’s trivial to calculate a rough estimate of the distance between the two objects by taking one point +from each and applying the Pythagorean theorem. Now, this would be a very rough estimate since it doesn’t take into +account the rotation or shape of the objects in question. However, if that rough separation estimate is greater than the +combined width of the two objects at their widest points then it can be assumed that the objects aren’t touching. In +all other cases the program would still have to run the collision detection algorithm as before to get an accurate +result.

+ +

With this optimization in play the execution times drop significantly. Note that due to the the inherent inaccuracy of +the timing method used, the results for Rust on the two computers should be interpreted as roughly equal.

+ + + + + + + + + + + + + + + + + + + + + + + + +
CPU used for the testTime for PythonTime for KotlinTime for Rust
Intel Core i7-8550U8.250 seconds0.145 seconds0.033 seconds
AMD A10-6800K15.844 seconds0.346 seconds0.027 seconds
+ +

Even though Python is quite slow in comparison to Kotlin and Rust, it turns out that it’s still easily fast enough to +do this math in real time for a game. In fact the very Python code I tested here is used in game server of my pyTanks +project to check for collisions between the game objects. This just goes to show the trade off that exists with +interpreted languages. While they may be more convenient to work with you’re paying the price for that convenience in +the execution speed.

+ +

If you’re interested in playing with these programs yourself you can find the Rust version here +and the Kotlin version here. The Python code is part of the +server portion of my pyTanks project here. Specifically, the Python +script that implements the algorithm is located here +in that repository. All of these repositories are under the MIT licence so if you’d like to make use of this code in one +of your own projects you’re more than welcome to.

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/96/e919bedc30d13e853fc5ad04cd44275496666eaf0a01d651f03b61a221eb77 b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/96/e919bedc30d13e853fc5ad04cd44275496666eaf0a01d651f03b61a221eb77 new file mode 100644 index 00000000..1d70d229 --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/96/e919bedc30d13e853fc5ad04cd44275496666eaf0a01d651f03b61a221eb77 @@ -0,0 +1,2 @@ +I"

Hey there!

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/98/08e8890a4d5c53cd9e2b9e550d3271e53dfa6b7cbfffa7f5f6b62ae92d3e55 b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/98/08e8890a4d5c53cd9e2b9e550d3271e53dfa6b7cbfffa7f5f6b62ae92d3e55 new file mode 100644 index 00000000..bd8214b5 --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/98/08e8890a4d5c53cd9e2b9e550d3271e53dfa6b7cbfffa7f5f6b62ae92d3e55 @@ -0,0 +1,46 @@ +I"

What Is It?

+

This program, Clādēs Cimicum, (which means ‘Bane of Bugs’ in Latin) is a very small and simple debugger for interprocess debugging. This is slightly different from that of GDB, since GDB actually creates a child process when debugging. Cladēs Cimicum can read the memory of any running process, without having to be run in some special environment beforehand.

+ +

Why I Wrote It

+

A while back, I found this challenge, and figured that I could do it. I started doing research into the best way to read the memory of another process, and found a few options:

+ +
    +
  1. Using ptrace to attach to the process and read its memory (This is what GDB does to a child proces)
  2. +
  3. Manually stopping the process and reading from its mem file in /proc
  4. +
+ +

I chose the latter of the two options because I wanted a bit of a challenge.

+ +

How To Use It

+

Program usage

+ +
debugger PID offset nbytes
+
+ +

where PID is the process ID of the target process, offset is the address in the virtual memory of the process that you wish to read from, and nbytes is the number of bytes to read from the target process

+ +

How It Works

+ +

First of all, a distinction must be made between the concept of a program, and the concept of a process. A program is the code that you write, and the binary file that it becomes when compiled, or the set of instructions executed as it is interpreted, or any number of other programming paradigms. In essence, it is the blueprint for behavior of the computer when that program is ‘run’. A process on the other hand, is an individual instance of that program running. For example, you can have two instances of vim running, each their own separate process, but using the same program.

+ +

As it turns out, a process on UNIX systems is nothing more than a collection of pseudo files stored in /proc. Everything about the process is stored in a folder within /proc, and the name of that folder for each process is the PID (Process ID) for that process. For example, if there is an instance of vim running with PID 413, everything about that specific process will be stored at /proc/413. In general, for any process, I will be referring to this location as /proc/PID.

+ +

Among the numerous useful files and folders within /proc/PID, one stands out as immediately useful for the problem at hand: /proc/PID/mem. This file holds ALL of the virtual memory mapped to a process. (I am aware that it is not technically a file, but going into the mechanics of what a pseudo filesystem is is beyond the scope of the description of this project). Therefore, you should be able to read all of the memory of a running process just by opening that file right? Well yes, but it is slightly more involved than that.

+ +

Firstly, the process that is to be examined (from here on out the target process) must not be running if you want to read the mem file. This is extrememly important in avoiding race conditions.. My solution to this is to simply pause the execution of the process by utilizing signalling. Before I attempt to read the mem file, the target process is stopped with SIGSTOP. The once reading is done, the process is continued with SIGCONT.

+ +

Secondly, you must be root to read the memory of another process in this way. It would be extremely unsafe for non-root or super users to be able to read the memory of any process on a machine at any time.

+ +

Thirdly, and maybe most importantly, you must know the exact memory address of the memory you want to access. This is because attempting to accesss an address in virtual memory that is not mapped to a physical address by /proc/PID/maps will result in an IO error. This makes sense, because there is no physical representation of the area of memory attemting to be accessed. Thus, you must be extremely familiar with the target process in order to effectively use this method.

+ +

How I Solved the Captcha Problem

+ +

The biggest challenge for this problem was actually finding the memory address of the answer to the captcha. Input is read in 1 by 1 so there is no array to immediately check against in the input function, where there is a blocking call to scanf. The solution I found however, does involve a simple array of ints that holds the answer. A stack frame always holds a pointer to the previous stack frame’s stack pointer. The stack pointer is a register that holds a memory address to the last piece of memory that was requested to be allocated on the stack. This piece of memory just so happened, in the previous stack frame, to be an array holding the answer. Done. Using GDB to grab this value (There is absolutely a way to do this not using GDB, but there was not enought time to research how to search the stack for this exact value), I simply used the Clādēs Cimicum program to grab the memory at that pointer and print it out. This is the solution to the captcha.

+ +

What I Learned

+ +

Pretty much everything that I know about the /proc folder, and how stack frames work.

+ +

The Project

+

The project is hosted here. The master branch is the general debugger, whilst the injection branch is the solution for the captcha challenge.

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/98/447a95073f5707cb01adbcdcb0e438b65c4b332365f11468c16186283c4735 b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/98/447a95073f5707cb01adbcdcb0e438b65c4b332365f11468c16186283c4735 new file mode 100644 index 00000000..479c736a --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/98/447a95073f5707cb01adbcdcb0e438b65c4b332365f11468c16186283c4735 @@ -0,0 +1,15 @@ +I"T

This project is an implementation of the board game ‘Go’ for iOS using Swift and and the SpriteKit framework. Go is a board game focused on surrounding enemy tiles to capture territory and remove the tiles from play. To accomplish this, I had to develop an algorithm to efficiently detect if a tile (or group of tiles) was fully surrounded, as well as practice the MVC structure for cleaner code. Using SpriteKit allowed me to take advantage of the sprite system to make logical ‘tile’ objects, as well as buttons and informational labels that could be animated.

+ +

The algorithm behind the checking of surrounded tiles works by iterating though all the tiles on the board. For each tile, if any of the tiles directly next to it (up, down, left, or right) are blank, it is considered able to “breath,” so it is not removed. If there are no blank tiles, it checks if any tiles of the same color next to it are also able to “breath” (since in Go, tiles connected to other tiles of the same color can “breath” through each other). If none of these conditions are met, the tile must be surrounded, so it gets removed.

+ +

When working on this algorithm I ran into two major issues. The first issue had to do with the fact that when I determined a tile to be surrounded, I would remove it instantly. This would cause problems when checking the rest of the tiles on the board, because they would then consider the previously-removed tile as blank. To solve this, I would add each surrounded tile to an array, then iterate through it so they would effectively all be removed at once.

+ +

The second major issue had to do with a special rule in Go. The rule states that even if a spot on the board is already surrounded, you can still place a piece there if it would result in the surrounding tiles to be removed. My algorithm initially did not account for that, so I had to adjust it. I solved this issue by first removing any surrounded tiles regardless of their effect, and then placing them down a second time before running the algorithm again. This meant that if a tile had no effect, it would get placed and removed twice — easy. If placing it down would result in other tiles being removed, however, it would remove them on the first pass and then successfully place the tile down during the second pass.

+ +

SpriteKit was also a large part of the project. I intended to use SpriteKit in this project both to learn how to use it and to make the game feel more responsive with the use of animations. I had never used SpriteKit before this game, and a chunk of the time spent on the project was dedicated to learning how to use it correctly. SpriteKit made it easy to create the exact animations I wanted for all the UI elements, without a major performance hit.

+ +

Overall, the project was a great learning experience, both improving my general development skills and giving me more experience with iOS programming. In the future I plan to expand the game further, and build a strategy game based on Go.

+ +

To see the code, [check out the GitHub project] +(https://github.com/ZachTheSloth/NIKHEDONIA).

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/9e/644d899762f4766b529be2738b476459f7324a17156ee974382f440b47aae5 b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/9e/644d899762f4766b529be2738b476459f7324a17156ee974382f440b47aae5 new file mode 100644 index 00000000..41ccdcea --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/9e/644d899762f4766b529be2738b476459f7324a17156ee974382f440b47aae5 @@ -0,0 +1,2 @@ +I")

Background

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/a7/ccec5326d17eadc5fd5dd0ff10b5062fe22e50383ffd37f2e4024419c7e694 b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/a7/ccec5326d17eadc5fd5dd0ff10b5062fe22e50383ffd37f2e4024419c7e694 new file mode 100644 index 00000000..20099d9b --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/a7/ccec5326d17eadc5fd5dd0ff10b5062fe22e50383ffd37f2e4024419c7e694 @@ -0,0 +1,20 @@ +I"

Why it exists:

+ +

I play in a lot of D&D one shot sessions, and I was sick and tired of wasting brain cells on character ideas I would only use for about 6 hours and then never again. This website will roll stats, select a race, and finally a class with subclass for you, all at the click of a button.

+ +

How it’s built:

+ +

I used a Python backend to roll stats and select optimal character options. I used Flask to integrate my backend with a simple HTML page and simple CSS to make it a bit prettier. I used a modified version of the Colville character generation method, which involves rolling 4d6 dropping the lowest 6 times, and using each roll down the line of stats (Strength first, then Dexterity, and so on). After the stats have been rolled, it looks at the two highest stats and assigns a race based on those. Finally, it again compares the stats to pick a class well suited to the current character.

+ +

Challenges it presented:

+ +

Before I started this project, I was unfamiliar with web development, so that was a big learning experience. The longer I worked on the website, the more comfortable I felt with making changes and improving the design. On the back end, I encountered an issue with code readability when I tried to automatically select a race for the player. Python doesn’t have switch statements, so I had to make something similar using a Python dictionary. The project was relatively straightforward once I solved the initial web issues and the switch problem, and was more focused on adding in new features.

+ +

What could be redone:

+ +

I had to use a Python dictionary as a form of “pseudo-switch,” which feels wrong to me. I can’t find a better solution that doesn’t involve a complex series of conditionals. I’d like to refactor the code to be a lot cleaner overall, and I plan on doing so over the summer. I also plan on adding in random background generation, and potentially automatic backstory details as well.

+ +

Create a character

+ +

View the code

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/ab/18ff029d3d3b134eed299c12098e2281d6442011c23008f09767a7c028d2e8 b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/ab/18ff029d3d3b134eed299c12098e2281d6442011c23008f09767a7c028d2e8 new file mode 100644 index 00000000..7f26f1bf --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/ab/18ff029d3d3b134eed299c12098e2281d6442011c23008f09767a7c028d2e8 @@ -0,0 +1,8 @@ +I"

Soft calendar is an Android app that helps keep Google Calendars clean and organized, making an easy to view checklist of events and their due dates. It is integrated with Google Calendar, so when you want to commit to an event, just select it from the list and push it to your calendar!

+ +

Soft calendar was the first Android app I’ve ever built, and with it came a lot of challenges. In all honesty, I would say that the hardest step was configuring my development environment, and learning about how Android Studio worked. After that, I had to learn about how the Google Calendar API worked, how authentication worked, how to pass data through forms, how to save user input, (and fix all of the bugs that naturally crop up along the way when you have no idea what you’re doing!)

+ +

I came up with the idea during my first week or so of school, when there were a ton of things to do all happening at the same time, and I was a little overwhelmed. My soft calendar idea was so I could make a visual representation of the things I wanted to do without having to clutter my Google Calendar with things that I may or may not end up at. The irony is that coding the soft calendar actually ended up taking up all my time, as opposed to going places, rendering the whole thing pretty counterintuitive!

+ +

But all things considered, working on an Android app really taught me a lot about how to work on (and finish!) a project instead of just going halfway and leaving it unfinished forever. Though I wouldn’t recommend working on an Android app as a first project, it was really a worthwhile experience regardless. You can see all of the source on my GitHub page If you think it’s cool, or that you could use something like this in your life, you can download it right onto your phone from the releases

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/ac/afd3822c6c3644a6ca4c205f0c0e7bb4f401a7f03f286ed988f08dd54c8c64 b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/ac/afd3822c6c3644a6ca4c205f0c0e7bb4f401a7f03f286ed988f08dd54c8c64 new file mode 100644 index 00000000..95bf89b3 --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/ac/afd3822c6c3644a6ca4c205f0c0e7bb4f401a7f03f286ed988f08dd54c8c64 @@ -0,0 +1,127 @@ +I"&

Before we begin, a bit about what FreeIPA actually is: FreeIPA, or Red Hat Identity Management, is a management interface and API built on top of several well-known, open source projects: 389 Directory Server, MIT Kerberos, DogTag for managing certificates and SSSD for client enrollment. The goal of the FreeIPA project is to create a cohesive, central, extensible, and easy to maintain user management and authentication system. FreeIPA provides an easy to use UI/UX for managing everything from user accounts, permissions, host based access controls to global sudo rules and certificate control. If you would like to play around with the interface, there is a public demo instance available.

+ +

Our Situation

+

For years Computer Science House has relied on LDAP and Kerberos for user management and single sign-on. The culture and communication within our organization and the services we provide revolve around these accounts, so it is essential that the infrastructure around them is solid. We will go more in-depth on this in the next section, but we also store information about a person’s membership in custom LDAP attributes, making LDAP a source-of-truth for many of the projects our members work on. This also presents the hurdle of properly handling ACLs to user data for service accounts used by these projects.

+ +

FreeIPA also supports an ongoing initiative within CSH to have fully redundant services between our data center and RIT’s datacenter across campus. csh-ds01 and csh-ds02 are both in our data center on different hypervisors and csh-ds03 is on a hypervisor in the secondary data center.

+ +

Handling Custom Attributes

+ +

As aforementioned, we store a lot of our membership data in LDAP. We have groups for Active Membership, Current Students, and even a group for those who have been taught how to use the 3D printers (for regulating access). Also, we store information like social media accounts, RIT usernames, and drink balances for our on-floor vending machines. Over the years, we have expanded out LDAP schema to hold values like these, so it was important that this data get carried over. FreeIPA comes with a built-in LDAP migration tool, yet before we could migrate this data we needed to make sure the schema was there to support it.

+ +

Extending the Schema

+ +

Because FreeIPA is 389 Server under-the-hood, it is possible to write LDIFs that add custom objectTypes with new attributeTypes. By default, in our setup, each user gets assigned two more objectTypes: ritStudent and cshMember. ritStudent has attributes for fields like majors, minors, graduation year, RIT username, etc. cshMember allows us to store drink balances, membership dates, external accounts, etc.

+ +

By default, FreeIPA schema gets loaded from /etc/dirsrv/slapd-{REALM}/schema. In this directory we defined both of the objectTypes and assigned them their respective attributeTypes. For example ritStudent has been included below:

+ +

+dn: cn=schema
+
+attributeTypes: ( 1.3.6.1.4.1.3319.8.501 NAME 'ritDn' SINGLE-VALUE EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch DESC 'RIT Account' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributeTypes: ( 1.3.6.1.4.1.3319.8.502 NAME 'major' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch DESC 'RIT Major' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributeTypes: ( 1.3.6.1.4.1.3319.8.503 NAME 'minor' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch DESC 'RIT Minor' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributeTypes: ( 1.3.6.1.4.1.3319.8.504 NAME 'ritYear' SINGLE-VALUE EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch DESC 'RIT Year' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+
+
+dn: cn=schema
+
+objectClasses: ( 1.3.6.1.4.1.3319.8.500 NAME 'ritStudent' AUXILIARY MAY ( ritDn $ major $ minor $ ritYear ) )
+
+
+ +

Extending the UI/API

+ +

Once the attributes are added to LDAP, you need to modify the API and Web UI they exist as well as the values that they are meant to hold.

+ +

The API is written in Python and plugins are loaded from /usr/lib/python2.7/site-packages/ipalib/plugins/. Again, using ritStudent as an example:

+ +
from ipalib.plugins import user
+from ipalib.parameters import Str
+from ipalib import _
+
+user.user.takes_params = user.user.takes_params + (
+    Str('ritdn?',
+        cli_name = 'ritdn',
+        label = _('RIT Account'),
+    ),
+    Str('major*',
+        cli_name = 'major',
+        label = _('RIT Major'),
+    ),
+    Str('minor*',
+        cli_name = 'minor',
+        label = _('RIT Minor'),
+    ),
+    Str('rityear?',
+        cli_name = 'rityear',
+        label = _('RIT Year'),
+    ),
+)
+
+ +

Now that the CLI and API know about the attributes, we need to extend the Web UI to show the attributes we added. The frontend is written in Javascript and extensions are loaded from /usr/share/ipa/ui/js/plugins/ where each extension has a folder with a Javascript file in it. Example: /usr/share/ipa/ui/js/plugins/rit-student/rit-student.js

+ +
define([
+        'freeipa/phases',
+        'freeipa/user'
+    ],
+    function(phases, user_mod) {
+        // helper function
+        function get_item(array, attr, value) {
+            for (var i = 0, l = array.length; i < l; i++) {
+                if (array[i][attr] === value) return array[i];
+            }
+            return null;
+        }
+        var student_plugin = {};
+        student_plugin.add_student_pre_op = function() {
+            var facet = get_item(user_mod.entity_spec.facets, '$type', 'details');
+            var section = get_item(facet.sections, 'name', 'identity');
+
+            section.fields.push({
+                name: 'ritdn',
+                label: 'RIT Account'
+            });
+
+            section.fields.push({
+                name: 'major',
+                label: 'RIT Major',
+                $type: 'multivalued'
+            });
+
+            section.fields.push({
+                name: 'minor',
+                label: 'RIT Minor',
+                $type: 'multivalued'
+            });
+
+            section.fields.push({
+                name: 'rityear',
+                label: 'RIT Year'
+            });
+
+            return true;
+
+        };
+        phases.on('customization', student_plugin.add_student_pre_op);
+        return student_plugin;
+    });
+
+ +

These Python and Javascript plugins need to be replicated to each IPA server in order for the fields to be accessible through those servers. Schema though, is automatically replicated.

+ +

FreeRADIUS and Wireless

+ +

Computer Science House administers its own wireless network which uses WPA2 Enterprise authentication through RADIUS authentication over TLS. In the past we have used a custom script which used MD4 hashes stored in Kerberos and handled the MSCHAPv2 challenge response protocol manually. Though this solution worked, it was not well documented and difficult to troubleshoot. FreeIPA though has the ability to support cross-domain trusts with Active Directory out-of-the-box. We used this feature to have IPA generate the necessary hashes, store them in LDAP, and then gave FreeRADIUS’s service account the ability to view this field.

+ +

This greatly simplifies our FreeRADIUS configuration since we can just use the default LDAP module and point it at the ipaNtHash attribute of the user trying to authenticate.

+ +

Deployment

+ +

Since we use Puppet as our configuration management platform, we decided that to efficiently enroll our existing hosts, we would push out a manifest that installed the freeipa-client package and ran ipa-client-install for us with the proper parameters. The easiest way to do this, that I could think of, was to create a puppet account in FreeIPA and give the necessary permissions to enroll hosts and create host objects. (Both operations are necessary to enroll a new host from scratch.) Our Puppet environments are controlled by a Git repo using r10k with Heira and secrets are encrypted using Heira-Eyaml. We are able to automatically enroll hosts in our domain after: configuring the user, encrypting the password in the Heira config, and configuring the ipaclient puppet module. This allows for the rapid bootstrapping of a new server with a single Puppet run.

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/ad/8affb1b769807241f87b08e9b0f4c7a9c1a97908ef067056391f398d285c40 b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/ad/8affb1b769807241f87b08e9b0f4c7a9c1a97908ef067056391f398d285c40 new file mode 100644 index 00000000..c40b5369 --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/ad/8affb1b769807241f87b08e9b0f4c7a9c1a97908ef067056391f398d285c40 @@ -0,0 +1,8 @@ +I"_

The Alexa RSS Skill is an Alexa skill, which is an app for Amazon’s Alexa platform, that reads content in tags from an RSS Feed. It works by asking the user for an input for which RSS Feed they would like hear and then from the user’s input it reads out the appropriate feed. The data for the different feeds like that name and links to the feeds are all stored in MySQL. Due to the skill needing to pull information from a database, I decided to make a companion web app to go with it. The RSS Companion App is a simple Python Flask web app that connects to the same MySQL database as the Alexa skill and lets the user add, edit, and delete RSS feeds from the database.

+ +

The Alexa RSS Skill and its companion app is the first big coding project that I have ever made. When I first started on this project, I had very little coding experience and had no knowledge on how Amazon Alexa and AWS Lambda worked. While working on this project I had learned how to use Git, GitHub, Node.js, Amazon AWS, and Python Flask. The skill went through many iterations until I finally understood how Amazon AWS Lambda and the Alexa Skill Builder worked and communicated with each other.

+ +

All in all, I found this project enjoyable and it was a great learning experience. Though I am finished with this project, I plan to try to make another Alexa skill using another coding language like Python. Although I might now know the basics about making a skill, I could learn something new and have more fun troubleshooting through the problems that arise in coding projects.

+ +

You can see the all of the source for the Alexa Skill here and for the web app here.

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/b5/738787bf2d5b10a61c7df42b9ba45a00532717e136061b524ce73a6b26d45d b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/b5/738787bf2d5b10a61c7df42b9ba45a00532717e136061b524ce73a6b26d45d new file mode 100644 index 00000000..382f4c90 --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/b5/738787bf2d5b10a61c7df42b9ba45a00532717e136061b524ce73a6b26d45d @@ -0,0 +1,21 @@ +I"4

Overview

+

Resume Review is a web app written for CSHers to upload their resumes and receive feedback on them. +Members can prepare for career fairs, company visits, and job applications by running their resumes by their peers, requesting specific changes or just asking for general opinions.

+ +

The site allows for the upload of PDF files, and reinforces good file naming practices. +Members can comment on posts, and comments can be threaded to allow for direct responses to feedback. +Once posted, users can leave comments on their own resumes to act as a description, if they want to denote things like past versions, recent changes, etc. +Members can also delete their own resumes or comments if they choose to.

+ +

The homepage of Resume Review

+ +

The homepage shows a list of recently posted resumes, so users can browse through people looking for review on their resumes.

+ +

Technical Details

+

Resume Review is the first project that I’ve made using Express, a Node.js framework. +It runs on CSH’s OpenShift Origin cluster, and uses our internal S3 to store files. +The site uses a PostgreSQL database for storing resume metadata and comments. +It’s also the first Node.js project to use CSH’s OpenID Connect authentication.

+ +

Resume Review can be found at resumes.csh.rit.edu, and even though the site itself is behind CSH authentication, its source code is open source on GitHub.

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/ba/5863a78508f264df4541f18cf5c0b393bc5318616f882ef02b91515fd50bf3 b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/ba/5863a78508f264df4541f18cf5c0b393bc5318616f882ef02b91515fd50bf3 new file mode 100644 index 00000000..5ef02a86 --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/ba/5863a78508f264df4541f18cf5c0b393bc5318616f882ef02b91515fd50bf3 @@ -0,0 +1,15 @@ +I"

Audiophiler is a Python Flask web app that serves audio files. +Audiophiler uses CSH’s Ceph storage cluster to hold audio files and serves them through an easy to use API. +The Audiophiler API allows other house services to quickly retrieve a member’s uploaded audio files. +When members come off of the NRH elevators and walk onto floor, they can tap their iButton against one of the +readers in the elevator lobby to load up songs on Audiophiler and play them aloud.

+ +

Audiophiler is the first web app that I’ve written entirely by myself. While working on the project, I learned a lot about +writing code for the web. Within my web app, I leverage a Postgres database to store audio file information. I also use +CSH’s Ceph environment to hand out links to audio files, allowing for very fast file retrieval.

+ +

Audiophiler went through many changes before I passed it as a major project, and is still being worked on now. In my opinion, Audiophiler is a great example of what CSH computer resources are capable of. The CSH OpenShift cluster lets me “deploy” my web app to the internet without any hassle.

+ +

In the future, I plan on cleaning up and optimizing Audiophiler. Recently, I have gotten some other CSHers to help me tweak my web app and offer feedback. +I look forward to working with more people on my project and creating something that house members will use for a while.

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/d3/5589a6c29bc05790123546bf8e096a2b055a696235d778f7fe5dca8483f93b b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/d3/5589a6c29bc05790123546bf8e096a2b055a696235d778f7fe5dca8483f93b new file mode 100644 index 00000000..70ca7fe8 --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/d3/5589a6c29bc05790123546bf8e096a2b055a696235d778f7fe5dca8483f93b @@ -0,0 +1,19 @@ +I" +

Background

+

Computer Science House purchased a robot chasis from one of our members in the Spring semester of 2017. I had worked on previous versions of the CSH H.E.R.O.I.N project and thought I would be able to make significant strides given we now had a stable robot chassis. So, using robot operating system constructs and several new pieces of hardware/sensors, I added mapping functionality to Kudos.

+ +

Details

+

First, I needed to install a LiDAR sensor on the robot. Standard off-the-shelf LiDAR solutions, such as the 16-channel Velodyne puck, start at upwards of $5000. Being a student organization, we needed a more financially sensible solution. I decided on using a replacement LiDAR sensor from the NeatoXV robot vacuum cleaner. Once the serial communication between the LiDAR controller board was setup with the Raspberry Pi, ROS development began. The LiDAR scans were “off-boarded” from the robot via the rostopic /laserscan over the network to a VM running on CSH Proxmox. On this VM, a program subscribed to this data and performed an algorithm to simultaneously localize the robot within a map and build the map as the robot moved through its enviornment. A navigation goal could be set for the robot to navigate to, and a path to follow to obtain this goal was computed. From this path, individual robot movements were calculated and streamed to the robot via Computer Science House’s WiFi network. This robot movement was actuated upon by the robot through its move base controller. See the figure below for a drawing of the control topology for Kudos.

+ +

Kudos Control Topology

+ +

Future Iterations

+

For anyone thinking about working on this project in future student generations, make sure to develop/use a SLAM algorithm that takes its odometry data from encoders. Currently the software setup relies on a fairly consistent LiDAR scan update rate and a large difference between LiDAR scan frames. Unfortunately, most walls are very flat and not very feature-rich. Even more unfortunate, most of CSH is comprised of very flat walls, so Kudos had some difficulty navigating when traveling through long, straight hallways. Kudos has gearboxes that allow for easy install of AndyMark standard encoders.

+ + +

Have a look at the project setup and code below!

+ +

Kudos ROS package

+ +

MoveBase Controller

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/dc/896d487a831a97cb3d2823bc6aee8306a8d99ed2ed61ac34b98ab3e530c261 b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/dc/896d487a831a97cb3d2823bc6aee8306a8d99ed2ed61ac34b98ab3e530c261 new file mode 100644 index 00000000..19a63e7a --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/dc/896d487a831a97cb3d2823bc6aee8306a8d99ed2ed61ac34b98ab3e530c261 @@ -0,0 +1,30 @@ +I": +

Summary

+

Capsule Killer is a first-person shooter that I developed to learn more about the skills and +processes involved with game development. Upon launching the game, the player will be met with a main menu that allows them to start a game, +view the controls, or exit the game. When a player starts a game, they will spawn in the center of the map and enemies will begin spawning +at random locations throughout the map every 2-5 seconds. The enemies move towards the player, doing damage upon collision with the player. +The player has the ability to run away from and shoot enemies. The goal of the game is to defeat as many enemies as possible.

+ +

The Enemies

+

The enemies in the game are pretty simple. Once they spawn, they find the player in the game and begin moving towards them. +If the enemy is able to collide with the player they stop moving to avoid pushing the player aroundand then begin doing damage +to the player. Damage is continually dealt until the enemy and player are no longer colliding. It takes 4 shots to destroy an +enemy in the current build of the game.

+ +

The Player

+

Much like the enemies, the player isn’t too complex. Input is recorded from the mouse and the W, A, S, and D keys on the keyboard +and translated into movement of the player using some fun vector math. The player also has the ability to press the Space key +to jump. Jumping was actually one of the most difficult aspects of the game for me to figure out. I wanted it to feel smooth, responsive, +and reasonable; I didn’t want the player to be able to jump super high. Shooting uses simple raycasting and input detection. If the left +mouse button is clicked, a ray is casted forwad from the player camera’s position. If it hits an enemy, the enemy loses 25 health points.

+ +

Conclusion

+

Overall, I had a blast with this project. Developing Capsule Killer was my first true experience working on a large project. +Before this I had never used Git, Unity, or C#, so I had my fair share of issues along the way. These issues, however, were +valuable opportunities to further my understanding of what I was doing. Although the game itself is pretty simple, I think +the experience I gained made it worthwhile, as it has furthered my understanding of things like version control, game engines, +and programming in general.

+ +

Feel free to check out the source code for Capsule Killer here!

+:ET \ No newline at end of file diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/f5/b9218d5b026907fa5fb4067783866f8048ad0e2535e8111aaafb31a964ef5a b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/f5/b9218d5b026907fa5fb4067783866f8048ad0e2535e8111aaafb31a964ef5a new file mode 100644 index 00000000..51a7e748 --- /dev/null +++ b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/f5/b9218d5b026907fa5fb4067783866f8048ad0e2535e8111aaafb31a964ef5a @@ -0,0 +1,21 @@ +I"

What is Jumpstart?

+

Jumpstart is a dashboard that runs on a TV in the CSH Elevator Lobby. Its primary goal is to display +relevant information to members of CSH to jumpstart their days. +​

+

Features

+
    +
  • Displays the date & time
  • +
  • CSH Logo that changes colors based on time of day. The logo can also change for holidays
  • +
  • A spot for announcements, which Eboard members can make through our Slack. This is done using a custom slack app that utilizes Slack’s APIs.
  • +
  • A module that displays a random title from r/showerthoughts every 30 seconds.
  • +
  • A module that displays real-time status information from CSH’s server room.
  • +
  • A calendar module that uses the Google calendar API to display a contdown to the next 10 + events from the CSH calendar.
  • +
  • A module that displays a daily forecast.
  • +
  • A module that shows the name of the file that Harold is playing.
  • +
+ +

What I learned through Jumpstart

+

Through working on Jumpstart, I learned how to make an app using the Flask framework. I also learned how to use fetch in JavaScript along with how to make a slack bot using the Slack API. In addition + to that, I learned how to work with the Google calendar API and a whole bunch of other cool stuff.

+:ET \ No newline at end of file diff --git a/assets/css/main.scss b/assets/css/main.scss index 98764d85..ad01f2db 100644 --- a/assets/css/main.scss +++ b/assets/css/main.scss @@ -49,6 +49,35 @@ img.rounded, align-items: flex-start; } +.container_stat { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-evenly; + align-items: flex-start; + } + + .stat_big { + color: #b0197e; + font-size: 2.5em; + font-weight: 600; + margin: 0%; + } + + .stat_tag { + margin: 0.2em; + } + + .stat_card { + text-align: center; + width: 200px; + } + + .stat_desc { + font-size: 0.6em; + font-weight: 600; + } + .quad_image { display:grid; grid-template-columns: 25% 25% 25% 25%; diff --git a/index.html b/index.html index c64871c0..82d2b760 100644 --- a/index.html +++ b/index.html @@ -118,7 +118,7 @@

Visit CSH

-

Things we're working on ...

+

Things we're working on ...

@@ -126,7 +126,7 @@

Things we're working on ...< A picture of CSH's server racks

Server room upgrade

-

Bringing our servers up to date.

+

Bringing our servers up to date with the help of Wayfair.

@@ -146,7 +146,7 @@

TUNES

A LED matrix that makes up CSH's Infosys

Infosys

-

A legacy CSH project that is being modernized.

+

An information display system

@@ -154,47 +154,83 @@

Infosys

A raspberry pi and pencil sharpener on the wall, CSH's letmein system

Letmein

-

A CSH project that is being modernized.

+

A physical notification system for members

-
-
- - - - - - -
-
TUNES, an old jukebox that's being made digital
@@ -180,7 +179,7 @@

Provide current CSH members with a large network of knowledge and professional connections.

-

25

+

38

Rooms on-floor

In RIT's Nathaniel Rochester Hall, a hub of campus life.

From 5790196ffd9ea7d4fd689b5f406b043267163dc4 Mon Sep 17 00:00:00 2001 From: viv-codes Date: Tue, 5 Jul 2022 21:39:01 -0400 Subject: [PATCH 06/11] Fixed blog card issue --- _sass/_triple_image.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_sass/_triple_image.scss b/_sass/_triple_image.scss index 7c16e331..5ac080b0 100644 --- a/_sass/_triple_image.scss +++ b/_sass/_triple_image.scss @@ -50,7 +50,7 @@ $browser-context: 16; justify-content: center; } -.card { +article.card { background-image: linear-gradient(0deg, $csh-blue 0%, $csh-pink 100%); width: $card-size; height: $card-size; From eef9ea2ebc3198b4ff6d207b895152d73c086155 Mon Sep 17 00:00:00 2001 From: viv-codes Date: Tue, 5 Jul 2022 22:05:54 -0400 Subject: [PATCH 07/11] Fixed issue with tour dropdown button --- about/tour.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/about/tour.html b/about/tour.html index 0869e96c..92e9f81c 100644 --- a/about/tour.html +++ b/about/tour.html @@ -6,7 +6,7 @@
-
+