├── .gitattributes ├── .dockerignore ├── entrypoint.sh ├── .firebaserc ├── .github ├── CODEOWNERS └── dependabot.yml ├── _layouts ├── page.html ├── default.html └── post.html ├── .gitignore ├── _sass ├── _projects.scss ├── _tour.scss ├── _insights.scss ├── _sponsors.scss ├── _eboard.scss ├── _hackathon.scss ├── _about.scss ├── _splash.scss ├── _typography.scss ├── _footer.scss ├── _slider.scss ├── _post.scss ├── _project_images.scss ├── _nav.scss └── _triple_image.scss ├── firebase.json ├── assets ├── js │ ├── utility.js │ ├── footer.js │ ├── nav.js │ ├── slider.js │ ├── sponsors.js │ └── tour.js └── css │ └── main.scss ├── blog └── index.html ├── httpd-suffix.conf ├── .travis.yml ├── 404.html ├── Dockerfile ├── package.json ├── Gemfile ├── README.md ├── _includes ├── post.html ├── footer.html ├── head.html └── nav.html ├── contact └── index.html ├── _posts ├── 2019-11-28-jumpstart.md ├── 2017-11-03-suds.md ├── 2017-11-02-audiophiler.md ├── 2018-01-22-alexa-rss-skill-and-companion-web-app.md ├── 2018-04-30-resume-review.md ├── 2017-11-27-soft-calendar.md ├── 2018-04-12-oneshot-character-generator.md ├── 2017-12-27-deepnet-synapse-delta-visualizer.md ├── 2018-04-18-capsule-killer.md ├── 2018-04-11-kudos-mapping-and-slam.md ├── 2018-04-12-proxstar.md ├── 2018-03-28-creating-go-in-swift.md ├── 2018-02-28-swiftfall.md ├── 2022-10-04-slate.md ├── 2023-02-20-datadog.md ├── 2025-03-26-netbox.md ├── 2020-05-19-docker-rust-notpresent.md ├── 2019-08-26-nickm-intro-letter.md ├── 2018-02-28-smart-window-shades.md ├── 2018-04-08-game-night.md ├── 2018-03-28-benchmarking-programing-languages.md ├── 2018-04-10-clades-cimicum.md └── 2018-02-26-freeipa.md ├── _config.yml ├── about ├── tour.html ├── faq.html ├── index.html ├── projects.html ├── eboard.html └── sponsors.html ├── Rakefile ├── membership ├── insights.html ├── index.html ├── traditions.html └── intro-process.html ├── Gemfile.lock └── index.html /.gitattributes: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | .gitignore 3 | 4 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sssd -i & 4 | echo "Running: $@" 5 | $@ 6 | -------------------------------------------------------------------------------- /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "csh-public-site" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @ComputerScienceHouse/active-webmasters @ComputerScienceHouse/public-relations 2 | -------------------------------------------------------------------------------- /_layouts/page.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 |
5 |

{{ page.title }}

6 |
7 | 8 | {{ content }} 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | _site 3 | .sass-cache 4 | .jekyll-metadata 5 | .jekyll-cache 6 | npm-debug.log 7 | .bundle/ 8 | node_modules/ 9 | .firebase/ 10 | -------------------------------------------------------------------------------- /_sass/_projects.scss: -------------------------------------------------------------------------------- 1 | #homepage-projects { 2 | p, 3 | a { 4 | font-size: 0.8em; 5 | } 6 | h2 { 7 | margin-top: 0; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "_site", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /_sass/_tour.scss: -------------------------------------------------------------------------------- 1 | #tour-page { 2 | .dropdown-toggle, 3 | .dropdown-menu, 4 | .dropdown-item { 5 | width: 100%; 6 | } 7 | .dropdown-item { 8 | font-size: 0.8em; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /_sass/_insights.scss: -------------------------------------------------------------------------------- 1 | #insights-page { 2 | #insights-dates { 3 | text-align: center; 4 | } 5 | #insights-buttons { 6 | text-align: center; 7 | & .btn { 8 | margin: 0.25em 0; 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /assets/js/utility.js: -------------------------------------------------------------------------------- 1 | export const pathJoin = (...args) => 2 | args.map((part, i) => i === 0 3 | ? part.trim().replace(/[\/]*$/g, '') 4 | : part.trim().replace(/(^[\/]*|[\/]*$)/g, '')) 5 | .filter(x => x.length).join('/'); 6 | 7 | export default { pathJoin }; -------------------------------------------------------------------------------- /blog/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Blog 4 | active: blog 5 | --- 6 | 7 |
8 |
9 | {% for post in site.posts %} 10 | {% include post.html post=post %} 11 | {% endfor %} 12 |
13 | -------------------------------------------------------------------------------- /_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% include head.html %} 4 | 5 | 6 | {% include nav.html %} 7 | 8 |
9 | {{ content }} 10 |
11 | 12 | {% include footer.html %} 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /assets/js/footer.js: -------------------------------------------------------------------------------- 1 | const fixFooterPadding = () => { 2 | if ($('footer')) { 3 | const footerHeight = $('footer').first().height(); 4 | $('main').css('padding-bottom', footerHeight + 'px'); 5 | } 6 | } 7 | 8 | $(document).ready(fixFooterPadding); 9 | $(window).resize(fixFooterPadding); 10 | -------------------------------------------------------------------------------- /_sass/_sponsors.scss: -------------------------------------------------------------------------------- 1 | #homepage-sponsors { 2 | padding-bottom: 75px; 3 | & img { 4 | margin: 15px 0; 5 | width: 100%; 6 | border-radius: 8px; 7 | box-shadow: 0 2px 15px darken($gray, 20%); 8 | transition: 0.3s opacity; 9 | &:hover { 10 | opacity: 0.75; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /_sass/_eboard.scss: -------------------------------------------------------------------------------- 1 | .eboard-photo-container { 2 | & img { 3 | width: calc(100% - 30px); 4 | position: absolute; 5 | transition: 0.3s opacity ease-in-out; 6 | &.real { 7 | width: 100%; 8 | position: relative; 9 | &:hover { 10 | opacity: 0; 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /httpd-suffix.conf: -------------------------------------------------------------------------------- 1 | Include conf/extra/httpd-autoindex.conf 2 | 3 | AddDefaultCharset utf-8 4 | LoadModule userdir_module modules/mod_userdir.so 5 | UserDir public_html 6 | 7 | #php_admin_value engine Off 8 | Options all MultiViews -Indexes 9 | AllowOverride Options=Indexes 10 | DirectoryIndex index.html index.htm 11 | 12 | Require all denied 13 | 14 | Require all granted 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "12.6" 4 | before_install: 5 | - rvm install 2.6.3 6 | install: 7 | - gem install bundler 8 | - npm install 9 | before_script: 10 | - bundle install 11 | - npm install -g firebase-tools 12 | script: 13 | - bundle exec jekyll build 14 | after_success: 15 | - firebase deploy --token $FIREBASE_TOKEN --non-interactive 16 | - npm run lh --perf=85 --a11y=85 --bp=85 --seo=85 https://csh-public-site.web.app 17 | -------------------------------------------------------------------------------- /_sass/_hackathon.scss: -------------------------------------------------------------------------------- 1 | #csh-hacks-wrapper { 2 | color: rgba(217, 184, 206, 1); 3 | background: rgba(37, 2, 26, 1) repeat top/2.5em 4 | url("/assets/images/csh_tilted.png"); 5 | & h2 { 6 | color: white; 7 | margin-top: 0; 8 | } 9 | & img { 10 | width: 100%; 11 | margin-top: 1.5em; 12 | } 13 | @media screen and (max-width: 992px) { 14 | h2 { 15 | margin-top: 1em; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /_sass/_about.scss: -------------------------------------------------------------------------------- 1 | #homepage-about { 2 | p { 3 | font-size: 0.9em; 4 | font-weight: 500; 5 | margin: 1em 0; 6 | } 7 | a.btn { 8 | font-size: 0.75em; 9 | margin-bottom: 1em; 10 | } 11 | } 12 | 13 | #faq-page { 14 | ul { 15 | list-style-type: none; 16 | } 17 | li { 18 | margin-top: 2em; 19 | } 20 | h3 { 21 | font-weight: bold; 22 | margin: 0; 23 | } 24 | p { 25 | font-size: 0.9em; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "bundler" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | -------------------------------------------------------------------------------- /404.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: "Error 404" 4 | --- 5 |
6 |
7 |
8 |
9 |

Page not found :(

10 |

The requested page could not be found.

11 |
12 |
13 | 14 |
15 |
16 |
17 |
18 | -------------------------------------------------------------------------------- /_sass/_splash.scss: -------------------------------------------------------------------------------- 1 | $size: 350px; 2 | 3 | .splash { 4 | height: $size; 5 | display: flex; 6 | align-items: center; 7 | justify-content: center; 8 | text-align: center; 9 | background: url('#{$CSHPUBSITE_ASSETS_URL}/hallway_blurred.jpg') 30% 30% no-repeat; 10 | background-size: cover; 11 | 12 | h1 { 13 | color: white; 14 | font-size: 3em; 15 | margin: 0; 16 | padding: 0 1rem; 17 | max-width: 100%; 18 | word-wrap: break-word; 19 | } 20 | 21 | @media (max-width: 992px) { 22 | height: 400px; 23 | 24 | h1 { 25 | font-size: 2em; 26 | padding: 0 1rem; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.io/jekyll/builder as builder 2 | RUN gem install bundler:2.2.3 3 | RUN mkdir /site; \ 4 | chown -R jekyll:jekyll /site 5 | WORKDIR /site 6 | COPY Gemfile Gemfile.lock /site/ 7 | RUN bundle install 8 | COPY . /site/ 9 | RUN bundle exec rake build:production 10 | 11 | FROM docker.io/httpd:2.4 12 | RUN apt update && apt install -y sssd 13 | RUN rm -rf /usr/local/apache2/htdocs/* 14 | COPY --from=builder /site/_site/ /usr/local/apache2/htdocs/ 15 | COPY httpd-suffix.conf httpd-suffix.conf 16 | RUN cat httpd-suffix.conf >> /usr/local/apache2/conf/httpd.conf 17 | COPY entrypoint.sh /entrypoint.sh 18 | EXPOSE 80 19 | ENTRYPOINT ["/usr/bin/bash", "/entrypoint.sh"] 20 | CMD ["httpd-foreground"] 21 | -------------------------------------------------------------------------------- /assets/js/nav.js: -------------------------------------------------------------------------------- 1 | $(document).ready(() => { 2 | $('nav .dropdown-toggle').click(e => e.preventDefault()); // prevent scrolling for href=# 3 | if ($('nav').length) { 4 | $(window).scroll(() => { 5 | if ($(window).width() < 1000) { // don't condense nav on smaller screens 6 | $('nav').first().removeClass('condensed'); 7 | return; 8 | } 9 | let currentScroll = document.documentElement.scrollTop || document.body.scrollTop; 10 | if (currentScroll > 150) { 11 | $('nav').first().addClass('condensed'); 12 | } else { 13 | $('nav').first().removeClass('condensed'); 14 | } 15 | }); 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cshpublicsite", 3 | "version": "3.0.0", 4 | "description": "The public facing website for [Rochester Institute of Technology](https://rit.edu/)'s [Computer Science House](https://csh.rit.edu).", 5 | "main": "_site/index.html", 6 | "dependencies": {}, 7 | "devDependencies": { 8 | "lighthousebot": "git+https://github.com/ebidel/lighthousebot.git" 9 | }, 10 | "scripts": { 11 | "lh": "lighthousebot" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/ComputerScienceHouse/CSHPublicSite.git" 16 | }, 17 | "author": "", 18 | "license": "GPL-3.0", 19 | "bugs": { 20 | "url": "https://github.com/ComputerScienceHouse/CSHPublicSite/issues" 21 | }, 22 | "homepage": "https://csh.rit.edu" 23 | } 24 | -------------------------------------------------------------------------------- /_sass/_typography.scss: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: calc(1em + 1vmax); 3 | } 4 | 5 | @media(min-width: 992px) { 6 | html { 7 | font-size: calc(1em + 1vmin); 8 | } 9 | } 10 | 11 | body { 12 | font-family: 'Poppins', 'Roboto', sans-serif; 13 | color: $blue; 14 | } 15 | 16 | h2 { 17 | margin-top: 1em; 18 | font-size: 1.5em; 19 | } 20 | 21 | h3 { 22 | font-size: 1.2em; 23 | } 24 | 25 | .long-form { 26 | color: #333; 27 | line-height: 1.5; 28 | font-size: 0.8em; 29 | margin: 1em 0; 30 | } 31 | 32 | .row.spaced { 33 | margin-top: 2em; 34 | } 35 | 36 | #headline { 37 | font-size: 1.4em; 38 | } 39 | @media screen and (max-width: 400px) { 40 | #headline { 41 | font-size: 1.0em; 42 | padding-right: 0.4em; 43 | padding-left: 0.4em; 44 | } 45 | } -------------------------------------------------------------------------------- /_sass/_footer.scss: -------------------------------------------------------------------------------- 1 | footer { 2 | position: absolute; 3 | bottom: 0; 4 | left: 0; 5 | width: 100%; 6 | font-size: 0.7em; 7 | text-align: center; 8 | color: white; 9 | img { 10 | width: 100%; 11 | max-width: 300px; 12 | margin-bottom: 10px; 13 | } 14 | & .footer-top { 15 | padding: 20px 0; 16 | background: $csh-pink; 17 | color: white; 18 | & a { 19 | margin: 0 10px; 20 | white-space: nowrap; 21 | } 22 | } 23 | .footer-bottom { 24 | padding: 8px 0; 25 | background: $blue; 26 | } 27 | .container { 28 | padding-top: 0; 29 | padding-bottom: 0; 30 | } 31 | .site-map { 32 | text-align: left; 33 | & a { 34 | display: block; 35 | } 36 | } 37 | h2 { 38 | margin-top: 0; 39 | } 40 | a { 41 | color: white; 42 | &:hover { 43 | color: white; 44 | } 45 | &.indented { 46 | padding-left: 30px; 47 | } 48 | @media(max-width: 992px) { 49 | text-decoration: underline; // underline links on smaller screens 50 | } 51 | } 52 | i { 53 | margin-right: 5px; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | # Hello! This is where you manage which Jekyll version is used to run. 4 | # When you want to use a different version, change it below, save the 5 | # file and run `bundle install`. Run Jekyll with `bundle exec`, like so: 6 | # 7 | # bundle exec jekyll serve 8 | # 9 | # This will help ensure the proper Jekyll version is running. 10 | # Happy Jekylling! 11 | gem "jekyll" 12 | 13 | # This is the default theme for new Jekyll sites. You may change this to anything you like. 14 | gem "minima", "~> 2.5" 15 | 16 | # If you want to use GitHub Pages, remove the "gem "jekyll"" above and 17 | # uncomment the line below. To upgrade, run `bundle update github-pages`. 18 | # gem "github-pages", group: :jekyll_plugins 19 | 20 | # If you have any plugins, put them here! 21 | group :jekyll_plugins do 22 | gem "jekyll-feed", "~> 0.6" 23 | gem "liquid-md5" 24 | gem "jekyll-regex-replace" 25 | gem 'jekyll-environment-variables' 26 | gem "webrick" 27 | end 28 | 29 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem 30 | gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby] 31 | 32 | # Performance-booster for watching directories on Windows 33 | gem "wdm", "~> 0.1.0" if Gem.win_platform? 34 | 35 | 36 | gem "rake", "~> 12.3" 37 | -------------------------------------------------------------------------------- /_layouts/post.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | active: blog 4 | --- 5 |
6 |

{{ page.title }}

7 |
8 | 9 |
10 |
11 |
12 |

13 | {% if page.author-image %} 14 | 15 | {% endif %} 16 | {{ page.author }} 17 | 18 | {% for social in page.author-social %} 19 | {% if social[0] != 'website' %} 20 | 21 | {% else %} 22 | 23 | {% endif %} 24 | {% endfor %} 25 | {{ page.date | date: "%B %-d, %Y" }} 26 |

27 |
28 | {% if page.image %} 29 | 30 | {% endif %} 31 | {{ content }} 32 |
33 | More blog posts 34 |
35 |
36 |
37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CSHPublicSite - [csh.rit.edu](https://csh.rit.edu) 2 | 3 | The public facing website for [Rochester Institute of Technology](https://rit.edu/)'s [Computer Science House](https://csh.rit.edu). 4 | 5 | ## Overview 6 | 7 | This site is written using [Jekyll](https://jekyllrb.com/), a static site generator built with Ruby, and uses Sass and JavaScript ES6. 8 | 9 | ## Local Development 10 | 11 | Build the container: `docker build -t cshpublicsite .` 12 | Run the container: `docker run -p 4000:80 cshpublicsite` 13 | You will be able to access the site at http://localhost:4000. 14 | 15 | You can either edit files in the container, or rebuild the container when you want to test changes. 16 | 17 | ## Contributing 18 | 19 | 1. [Fork](https://help.github.com/en/articles/fork-a-repo) this repository 20 | - Create a new [git branch](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell) if your change is more than a small tweak (`git checkout -b BRANCH-NAME-HERE`) 21 | 3. Make your changes locally, commit, and push to your fork 22 | 4. Create a [Pull Request](https://help.github.com/en/articles/about-pull-requests) on this repo for our Webmasters to review 23 | 24 | ## Questions/Concerns 25 | 26 | Please file an [Issue](https://github.com/ComputerScienceHouse/CSHPublicSite/issues/new) on this repository or contact [webmaster@csh.rit.edu](mailto:webmaster@csh.rit.edu) with inquiries about the site. 27 | -------------------------------------------------------------------------------- /_includes/post.html: -------------------------------------------------------------------------------- 1 | {% if include.post %} 2 | {% assign post = include.post %} 3 | {% assign image = "/logo_background.png" | prepend: site.env.CSHPUBSITE_ASSETS_URL %} 4 | {% if post.image %} 5 | {% assign image = post.image | prepend: site.env.CSHPUBSITE_ASSETS_URL %} 6 | {% else %} 7 | {% assign hash = post.title | md5 | regex_replace: '[^\d]', '' %} 8 | {% endif %} 9 |
10 | 11 |
12 |
13 | {{ post.title }} 14 |
15 | 16 |
19 |
20 |
21 |
22 |
23 | {% else %} 24 |
25 |
26 |
27 | No post provided. 28 |
29 |
30 |
31 |
32 | {% endif %} 33 | -------------------------------------------------------------------------------- /contact/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Contact 4 | active: contact 5 | --- 6 | 7 |
8 |
9 |
10 |
11 |

Send us a message

12 |

For more information about CSH or to apply, contact our Evaluations Director: evals@csh.rit.edu. 13 |

To schedule a company visit, or for more information about sponsoring CSH, contact our Chairman: chairman@csh.rit.edu. 14 |

For inquiries about our website, reach out to webmaster@csh.rit.edu. 15 |

16 |
17 |

Visit us

18 |

We're on the third-floor of Fredericka Douglass Sprague Perry Hall at RIT.

19 |

Mailing address

20 |

21 | Computer Science House
22 | 3999 Fredericka Douglass Sprague Perry Hall
23 | Rochester, NY 14623 24 |

25 |
26 |
27 |
28 |
29 | -------------------------------------------------------------------------------- /_sass/_slider.scss: -------------------------------------------------------------------------------- 1 | $carousel-breakpoint: 600px; 2 | 3 | $carousel-scroll-down-button-size-larger: 50px; 4 | $carousel-scroll-down-button-size-smaller: 25px; 5 | 6 | #slider { 7 | width: 100%; 8 | margin-bottom: 0; 9 | height: auto; 10 | overflow-y: hidden; 11 | & img { 12 | width: 100%; 13 | } 14 | background: $gray; 15 | } 16 | 17 | #carousel-scroll-down-button { 18 | position: absolute; 19 | z-index: 98; 20 | left: 50vw; 21 | right: 0; 22 | width: auto; 23 | height: auto; 24 | background: none; 25 | border: none; 26 | padding: 0; 27 | cursor: pointer; 28 | } 29 | 30 | #carousel-scroll-down-button:active, #carousel-scroll-down-button:focus { 31 | outline: 0; 32 | -moz-outline-style: none; 33 | } 34 | 35 | #carousel-scroll-down-button > svg { 36 | max-width: $carousel-scroll-down-button-size-larger; 37 | width: $carousel-scroll-down-button-size-larger; 38 | height: auto; 39 | -webkit-filter: drop-shadow(0px 0px 2px black); 40 | filter: drop-shadow(0px 0px 2px black); 41 | } 42 | @media screen and (max-width: $carousel-breakpoint) { 43 | #carousel-scroll-down-button > svg { 44 | max-width: $carousel-scroll-down-button-size-smaller; 45 | } 46 | } 47 | .slick-prev { 48 | left: 10px; 49 | z-index: 2; 50 | } 51 | 52 | .slick-next { 53 | right: 10px; 54 | } 55 | 56 | .slick-prev:before, 57 | .slick-next:before { 58 | color: white; 59 | text-shadow: 0 0 5px black; 60 | } 61 | 62 | .slick-dots { 63 | bottom: 10px; 64 | } 65 | -------------------------------------------------------------------------------- /_sass/_post.scss: -------------------------------------------------------------------------------- 1 | .post { 2 | display: block; // attempt at fixing https://github.com/ComputerScienceHouse/CSHPublicSite/issues/331 3 | img { 4 | max-width: 100%; 5 | margin: 20px 0; 6 | } 7 | a.btn { 8 | margin-top: 20px; 9 | } 10 | #details { 11 | font-size: 1em; 12 | img { 13 | width: 32px; 14 | height: 32px; 15 | border-radius: 50%; 16 | } 17 | a { 18 | text-decoration: none; 19 | } 20 | #date { 21 | margin-left: 20px; 22 | } 23 | } 24 | h3 { 25 | font-size: 1.5em; 26 | } 27 | p { 28 | font-size: 0.9em; 29 | } 30 | } 31 | 32 | #post-list { 33 | a.btn { 34 | margin-top: 20px; 35 | } 36 | ul { 37 | list-style-type: none; 38 | padding: 0; 39 | } 40 | img { 41 | width: 50px; 42 | height: 50px; 43 | border-radius: 50%; 44 | margin-right: 10px; 45 | } 46 | h2 { 47 | margin-top: 0; 48 | } 49 | .card { 50 | margin: 10px 0; 51 | transition: 0.3s opacity; 52 | &:hover { 53 | opacity: 0.75; 54 | } 55 | } 56 | .card-header { 57 | padding: 10px 20px; 58 | a { 59 | text-decoration: underline; 60 | } 61 | } 62 | .card-body { 63 | height: 200px; 64 | background-repeat: no-repeat; 65 | background-position: center; 66 | background-size: cover; 67 | position: relative; 68 | background-color: $csh-pink; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /_sass/_project_images.scss: -------------------------------------------------------------------------------- 1 | .content { 2 | position: relative; 3 | width: 100%; 4 | margin: auto; 5 | overflow: hidden; 6 | } 7 | 8 | .content-overlay { 9 | background: rgba(0,0,0,0.6); 10 | position: absolute; 11 | height: 100%; 12 | width: 100%; 13 | left: 0; 14 | top: 0; 15 | bottom: 0; 16 | right: 0; 17 | opacity: 0; 18 | -webkit-transition: all 0.4s ease-in-out 0s; 19 | -moz-transition: all 0.4s ease-in-out 0s; 20 | transition: all 0.4s ease-in-out 0s; 21 | } 22 | 23 | .content:hover .content-overlay{ 24 | opacity: 1; 25 | } 26 | 27 | .content-image{ 28 | width: 100%; 29 | } 30 | 31 | .content-background { 32 | background: rgba(0, 0, 0, 0.45); 33 | } 34 | 35 | .content-details { 36 | position: absolute; 37 | text-align: center; 38 | padding-left: 1em; 39 | padding-right: 1em; 40 | width: 100%; 41 | top: 50%; 42 | left: 50%; 43 | opacity: 0; 44 | -webkit-transform: translate(-50%, -50%); 45 | -moz-transform: translate(-50%, -50%); 46 | transform: translate(-50%, -50%); 47 | -webkit-transition: all 0.3s ease-in-out 0s; 48 | -moz-transition: all 0.3s ease-in-out 0s; 49 | transition: all 0.3s ease-in-out 0s; 50 | } 51 | 52 | .content:hover .content-details{ 53 | top: 50%; 54 | left: 50%; 55 | opacity: 1; 56 | } 57 | 58 | .content-details h3{ 59 | color: #fff; 60 | font-weight: 500; 61 | letter-spacing: 0.15em; 62 | margin-bottom: 0.5rem; 63 | padding: auto; 64 | text-transform: uppercase; 65 | } 66 | 67 | .content-details p{ 68 | color: #fff; 69 | font-size: 0.8em; 70 | } 71 | 72 | .fadeIn-bottom{ 73 | top: 80%; 74 | } 75 | 76 | @media screen and (max-width: 700px) { 77 | .content-details{ 78 | top: 50%; 79 | left: 50%; 80 | opacity: 1; 81 | } 82 | .content-overlay{ 83 | opacity: 1; 84 | } 85 | } 86 | 87 | -------------------------------------------------------------------------------- /_posts/2019-11-28-jumpstart.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: JumpStart 4 | date: 2019-11-28 5 | categories: 6 | - projects 7 | description: A display to jumpstart your day! 8 | image: /projects/Jumpstart.png 9 | image-sm: /projects/Jumpstart.png 10 | author: Beckett Jenen 11 | author-image: https://www.csh.rit.edu/~mom/drno/me.jpg 12 | author-bio: First year Computer Science major. 13 | author-email: beckettjenen@gmail.com 14 | author-social: 15 | github: https://github.com/Dr-N0 16 | linkedin: https://www.linkedin.com/in/beckettjenen/ 17 | --- 18 | 19 | # What is Jumpstart? 20 | Jumpstart is a dashboard that runs on a TV in the CSH Elevator Lobby. Its primary goal is to display 21 | relevant information to members of CSH to jumpstart their days. 22 | ​ 23 | # Features 24 | - Displays the date & time 25 | - CSH Logo that changes colors based on time of day. The logo can also change for holidays 26 | - 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. 27 | - A module that displays a random title from r/showerthoughts every 30 seconds. 28 | - A module that displays real-time status information from CSH's server room. 29 | - A calendar module that uses the Google calendar API to display a contdown to the next 10 30 | events from the CSH calendar. 31 | - A module that displays a daily forecast. 32 | - A module that shows the name of the file that [Harold](https://csh.rit.edu/about/projects.html) is playing. 33 | 34 | # What I learned through Jumpstart 35 | 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 36 | to that, I learned how to work with the Google calendar API and a whole bunch of other cool stuff. -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Jekyll! 2 | # 3 | # This config file is meant for settings that affect your whole blog, values 4 | # which you are expected to set up once and rarely edit after that. If you find 5 | # yourself editing this file very often, consider using Jekyll's data files 6 | # feature for the data you need to update frequently. 7 | # 8 | # For technical reasons, this file is *NOT* reloaded automatically when you use 9 | # 'bundle exec jekyll serve'. If you change this file, please restart the server process. 10 | 11 | # Site settings 12 | # These are used to personalize your new site. If you look in the HTML files, 13 | # you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. 14 | # You can create any custom variable you would like, and they will be accessible 15 | # in the templates via {{ site.myvariable }}. 16 | title: Computer Science House 17 | email: webmaster@csh.rit.edu 18 | description: >- # this means to ignore newlines until "baseurl:" 19 | Write an awesome description for your new site here. You can edit this 20 | line in _config.yml. It will appear in your document head meta (for 21 | Google search results) and in your feed.xml site description. 22 | baseurl: "" # the subpath of your site, e.g. /blog 23 | url: "https://pubsite.a.csh.rit.edu" # the base hostname & protocol for your site, e.g. http://example.com 24 | twitter_username: CSH_HISTORY 25 | github_username: computersciencehouse 26 | 27 | # Build settings 28 | markdown: kramdown 29 | theme: minima 30 | plugins: 31 | - jekyll-feed 32 | - liquid-md5 33 | - jekyll-regex-replace 34 | 35 | # Exclude from processing. 36 | # The following items will not be processed, by default. Create a custom list 37 | # to override the default setting. 38 | # exclude: 39 | # - Gemfile 40 | # - Gemfile.lock 41 | # - node_modules 42 | # - vendor/bundle/ 43 | # - vendor/cache/ 44 | # - vendor/gems/ 45 | # - vendor/ruby/ 46 | -------------------------------------------------------------------------------- /about/tour.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Tour 4 | active: about-tour 5 | --- 6 | 7 |
8 |
9 |
10 |
11 | 25 |
26 |
27 |
28 |
29 |

Dorm Room

30 |

31 | Though the walls are the same as regular dorm rooms, our rooms usually look rather different than the standard RIT room layout. 32 |

33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | -------------------------------------------------------------------------------- /_posts/2017-11-03-suds.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: SUDS 4 | date: 2017-11-2 5 | categories: 6 | - projects 7 | description: Shower Use Detection System 8 | author: Seth Gower 9 | author-image: https://avatars3.githubusercontent.com/u/19225089 10 | author-bio: First year Computer Engineering student 11 | author-email: seth@sethgower.com 12 | author-social: 13 | github: https://github.com/SethGower 14 | linkedin: https://www.linkedin.com/in/sethgower/ 15 | --- 16 | [SUDS](https://github.com/sethgower/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 Fredericka Douglass Sprague Perry 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. 17 | 18 | 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. 19 | 20 | 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. 21 | 22 | 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](https://github.com/sethgower/suds). 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. 23 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # require 'html-proofer' 2 | 3 | # Add environment variables below 4 | envvars = { 5 | CSHPUBSITE_ASSETS_URL: "https://assets.csh.rit.edu/pubsite", 6 | CSHPUBSITE_S3_URL: "https://s3.csh.rit.edu" 7 | }.map { |k,v| ["#{k}=#{v}"]}.join(" ") 8 | 9 | $outputDir = "./_site" 10 | $testOpts = { 11 | # An array of Strings containing domains that will be treated as internal urls 12 | :internal_domains => ["pubsite.a.csh.rit.edu"], 13 | # Ignore errors "linking to internal hash # that does not exist" 14 | :url_ignore => ["#"], 15 | # Allow empty alt tags (e.g. alt="") as these represent presentational images 16 | :empty_alt_ignore => true, 17 | # Automatically add extension (e.g. .html) to file paths, to allow extensionless URLs 18 | :assume_extension => true, 19 | # LinkedIn blocks connections from html-proofer, ignore 999 error 20 | :http_status_ignore => [999], 21 | # SSL seems to be broken on TravisCI, so we'll ignore SSL errors. 22 | :typhoeus => { 23 | :ssl_verifypeer => 0, 24 | :ssl_verifyhost => 0, 25 | } 26 | } 27 | 28 | task :default => ["serve:development"] 29 | 30 | desc "cleans the output directory" 31 | task :clean do 32 | sh "jekyll clean" 33 | end 34 | 35 | namespace :build do 36 | 37 | desc "build development site" 38 | task :development => [:clean] do 39 | sh "#{envvars} jekyll build --drafts" 40 | end 41 | 42 | desc "build production site" 43 | task :production => [:clean] do 44 | sh "#{envvars} JEKYLL_ENV=production jekyll build --config=_config.yml" 45 | end 46 | end 47 | 48 | namespace :serve do 49 | 50 | desc "serve development site" 51 | task :development => [:clean] do 52 | sh "#{envvars} jekyll serve --drafts" 53 | end 54 | 55 | desc "serve production site" 56 | task :production => [:clean] do 57 | sh "#{envvars} JEKYLL_ENV=production jekyll serve --config=_config.yml" 58 | end 59 | end 60 | 61 | # desc "test production build" 62 | # task :test => ["build:production"] do 63 | # HTMLProofer.check_directory($outputDir, $testOpts).run 64 | # end 65 | -------------------------------------------------------------------------------- /membership/insights.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Insights 4 | active: membership-insights 5 | --- 6 | 7 |
8 |
9 |
10 |
11 |

Accepted Student Open House

12 |

April 7-8, 2018

13 |
14 |

ImagineRIT Weekend

15 |

April 27-28, 2018

16 |
17 |
18 |
19 |
20 |

21 | Insights is a promotional program where prospective students have the option to spend a weekend at Computer Science House. As the name would suggest, Insights gives students a real, first-hand experience of campus life the likes of which no tour guide can convey. Students will spend a weekend hosted by members of CSH, a Special Interest Floor dedicated to students interested in computing. They will have to opportunity to participate in learning workshops hosted by house members, join in on CSH traditions like Capture the Disk, and much more. 22 |

23 |

24 | Available spots for Insights will be given out on a first come first serve basis. Also, your interest and possible participation in Insights in no way effects your application to or evaluations process in Computer Science House. 25 |

26 |
27 | Schedule 28 | Registration Form 29 | Contact Us 30 |
31 |
32 |
33 |
34 |
35 | -------------------------------------------------------------------------------- /_posts/2017-11-02-audiophiler.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Creating Audiophiler 4 | date: 2017-11-02 21:25:00 5 | categories: projects 6 | description: Audiophiler, a neat python web app for serving music 7 | author: Stephen Greene 8 | image: /projects/Audiophiler.png 9 | image-sm: /projects/Audiophiler.png 10 | author-image: https://avatars0.githubusercontent.com/u/17414243?s=460&v=4 11 | author-bio: Second Year Computer Science Student at Rochester Institute of Technology and a System Administrator for CSH as well as KGCOE 12 | author-email: purple@csh.rit.edu 13 | author-social: 14 | github: https://github.com/sgreene570 15 | --- 16 | [Audiophiler](https://github.com/sgreene570/audiophiler) is a Python Flask web app that serves audio files. 17 | Audiophiler uses CSH's Ceph storage cluster to hold audio files and serves them through an easy to use API. 18 | The Audiophiler API allows other house services to quickly retrieve a member's uploaded audio files. 19 | When members come off of the DSP elevators and walk onto floor, they can tap their iButton against one of the 20 | readers in the elevator lobby to load up songs on Audiophiler and play them aloud. 21 | 22 | Audiophiler is the first web app that I've written entirely by myself. While working on the project, I learned _a lot_ about 23 | writing code for the web. Within my web app, I leverage a Postgres database to store audio file information. I also use 24 | CSH's Ceph environment to hand out links to audio files, allowing for very fast file retrieval. 25 | 26 | 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. 27 | 28 | 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. 29 | I look forward to working with more people on my project and creating something that house members will use for a while. 30 | -------------------------------------------------------------------------------- /_posts/2018-01-22-alexa-rss-skill-and-companion-web-app.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Alexa RSS Skill 4 | date: 2018-01-22 5 | categories: 6 | - projects 7 | description: Alexa Skill that reads out tags from an RSS Feed 8 | image: 9 | image-sm: 10 | author: Fred Rybin 11 | author-image: https://avatars0.githubusercontent.com/u/17693407?s=460&v=4 12 | author-bio: First Year Computing Security student 13 | author-email: fredrybin@gmail.com 14 | author-social: 15 | github: https://github.com/frybin 16 | linkedin: https://www.linkedin.com/in/frybin/ 17 | --- 18 | 19 | The [Alexa RSS Skill](https://github.com/frybin/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](https://github.com/frybin/RSS-Web-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. 20 | 21 | 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. 22 | 23 | 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. 24 | 25 | You can see the all of the source for the Alexa Skill [here](https://github.com/frybin/Alexa-RSS-Skill) and for the web app [here](https://github.com/frybin/RSS-Web-App). 26 | -------------------------------------------------------------------------------- /_posts/2018-04-30-resume-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | permalink: /:categories/:title:output_ext 4 | title: Resume Review 5 | date: 2018-04-30 6 | categories: 7 | - projects 8 | description: A webapp to upload resumes and review those of your peers 9 | image: /projects/resume.png 10 | image-sm: /projects/resume.png 11 | author: Ram Zallan 12 | author-image: https://avatars3.githubusercontent.com/u/5818258 13 | author-bio: Second year Computer Science major, full stack software engineer. ramzallan.me 14 | author-email: ram@csh.rit.edu 15 | author-social: 16 | github: https://github.com/ramzallan 17 | linkedin: https://linkedin.com/in/ramzallan 18 | --- 19 | 20 | ### Overview 21 | [Resume Review](https://resumes.csh.rit.edu) is a web app written for CSHers to upload their resumes and receive feedback on them. 22 | 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. 23 | 24 | The site allows for the upload of PDF files, and [reinforces good file naming practices](https://github.com/RamZallan/resume-review/blob/d3ca7f68bf940e5aeaea42061b5278369b89a90d/routes/upload.js#L29). 25 | Members can comment on posts, and comments can be threaded to allow for direct responses to feedback. 26 | 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. 27 | Members can also delete their own resumes or comments if they choose to. 28 | 29 | ![The homepage of Resume Review](https://csh.rit.edu/~ram/resumes/homepage.png) 30 | 31 | The homepage shows a list of recently posted resumes, so users can browse through people looking for review on their resumes. 32 | 33 | 34 | ### Technical Details 35 | Resume Review is the first project that I've made using [Express](https://expressjs.com/), a Node.js framework. 36 | It runs on CSH's OpenShift Origin cluster, and uses our internal S3 to store files. 37 | The site uses a PostgreSQL database for storing resume metadata and comments. 38 | It's also the first Node.js project to use CSH's OpenID Connect authentication. 39 | 40 | Resume Review can be found at [resumes.csh.rit.edu](https://resumes.csh.rit.edu), and even though the site itself is behind CSH authentication, its source code is open source on [GitHub](https://github.com/ramzallan/resume-review/). 41 | -------------------------------------------------------------------------------- /_posts/2017-11-27-soft-calendar.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Soft Calendar 4 | date: 2017-11-27 5 | categories: 6 | - projects 7 | description: A Calendar Event Manager! 8 | image: /projects/softCalendar.jpg 9 | image-sm: /projects/softCalendar.jpg 10 | author: Skyler Clark 11 | author-image: https://avatars0.githubusercontent.com/u/4897492?s=400&v=4 12 | author-bio: A freshman computer science student! 13 | author-email: sjc1689@rit.edu 14 | author-social: 15 | github: https://github.com/SkylerJaneClark 16 | linkedin: https://www.linkedin.com/in/skyler-c-58962012b/ 17 | --- 18 | 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! 19 | 20 | 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!) 21 | 22 | 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! 23 | 24 | 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](https://github.com/SkylerJaneClark/softCalendar) 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](https://github.com/SkylerJaneClark/softCalendar/releases) 25 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | addressable (2.8.0) 5 | public_suffix (>= 2.0.2, < 5.0) 6 | colorator (1.1.0) 7 | concurrent-ruby (1.1.10) 8 | em-websocket (0.5.3) 9 | eventmachine (>= 0.12.9) 10 | http_parser.rb (~> 0) 11 | eventmachine (1.2.7) 12 | ffi (1.15.5) 13 | forwardable-extended (2.6.0) 14 | http_parser.rb (0.8.0) 15 | i18n (1.10.0) 16 | concurrent-ruby (~> 1.0) 17 | jekyll (4.2.2) 18 | addressable (~> 2.4) 19 | colorator (~> 1.0) 20 | em-websocket (~> 0.5) 21 | i18n (~> 1.0) 22 | jekyll-sass-converter (~> 2.0) 23 | jekyll-watch (~> 2.0) 24 | kramdown (~> 2.3) 25 | kramdown-parser-gfm (~> 1.0) 26 | liquid (~> 4.0) 27 | mercenary (~> 0.4.0) 28 | pathutil (~> 0.9) 29 | rouge (~> 3.0) 30 | safe_yaml (~> 1.0) 31 | terminal-table (~> 2.0) 32 | jekyll-environment-variables (1.0.1) 33 | jekyll (>= 3.0, < 5.x) 34 | jekyll-feed (0.16.0) 35 | jekyll (>= 3.7, < 5.0) 36 | jekyll-regex-replace (1.1.0) 37 | jekyll-sass-converter (2.2.0) 38 | sassc (> 2.0.1, < 3.0) 39 | jekyll-seo-tag (2.8.0) 40 | jekyll (>= 3.8, < 5.0) 41 | jekyll-watch (2.2.1) 42 | listen (~> 3.0) 43 | kramdown (2.4.0) 44 | rexml 45 | kramdown-parser-gfm (1.1.0) 46 | kramdown (~> 2.0) 47 | liquid (4.0.3) 48 | liquid-md5 (0.0.3) 49 | liquid (>= 2.5, < 5.0) 50 | listen (3.7.1) 51 | rb-fsevent (~> 0.10, >= 0.10.3) 52 | rb-inotify (~> 0.9, >= 0.9.10) 53 | mercenary (0.4.0) 54 | minima (2.5.1) 55 | jekyll (>= 3.5, < 5.0) 56 | jekyll-feed (~> 0.9) 57 | jekyll-seo-tag (~> 2.1) 58 | pathutil (0.16.2) 59 | forwardable-extended (~> 2.6) 60 | public_suffix (4.0.7) 61 | rake (12.3.3) 62 | rb-fsevent (0.11.1) 63 | rb-inotify (0.10.1) 64 | ffi (~> 1.0) 65 | rexml (3.2.5) 66 | rouge (3.29.0) 67 | safe_yaml (1.0.5) 68 | sassc (2.4.0) 69 | ffi (~> 1.9) 70 | terminal-table (2.0.0) 71 | unicode-display_width (~> 1.1, >= 1.1.1) 72 | unicode-display_width (1.8.0) 73 | webrick (1.7.0) 74 | 75 | PLATFORMS 76 | x86_64-linux 77 | 78 | DEPENDENCIES 79 | jekyll 80 | jekyll-environment-variables 81 | jekyll-feed (~> 0.6) 82 | jekyll-regex-replace 83 | liquid-md5 84 | minima (~> 2.5) 85 | rake (~> 12.3) 86 | tzinfo-data 87 | webrick 88 | 89 | BUNDLED WITH 90 | 2.3.17 91 | -------------------------------------------------------------------------------- /_posts/2018-04-12-oneshot-character-generator.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: One Shot Character Generator 4 | date: 2018-04-12 5 | categories: 6 | - projects 7 | description: D&D Character Generator 8 | author: Kevin Schwenk 9 | author-bio: Second year CS major 10 | author-email: kss3800@rit.edu 11 | author-social: 12 | github: https://github.com/mouseexe 13 | website: http://kevinschwenk.com 14 | --- 15 | ## Why it exists: 16 | 17 | 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. 18 | 19 | ## How it's built: 20 | 21 | 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. 22 | 23 | ## Challenges it presented: 24 | 25 | 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. 26 | 27 | ## What could be redone: 28 | 29 | 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. 30 | 31 | [Create a character](http://charactergen.win) 32 | 33 | [View the code](https://github.com/mouseexe/OneShotCharacterGenerator) 34 | -------------------------------------------------------------------------------- /_sass/_nav.scss: -------------------------------------------------------------------------------- 1 | // override csh-material-bootstrap 2 | .navbar { 3 | position: fixed; 4 | top: 0; 5 | left: 0; 6 | z-index: 99; 7 | box-shadow: none; 8 | width: 100%; 9 | background: rgba(0, 0, 0, 0.6); 10 | padding: 0.25em 0.5em; 11 | } 12 | 13 | nav { 14 | & .navbar-brand { 15 | transition: 0.4s max-height, 0.4s margin; 16 | max-height: 100px; 17 | padding-top: 15px; 18 | padding-bottom: 15px; 19 | margin: 10px 0; 20 | background-image: url('#{$CSHPUBSITE_ASSETS_URL}/csh_logo_square.svg'); 21 | background-repeat: no-repeat; 22 | background-size: contain; 23 | background-position: left center; 24 | } 25 | & img { 26 | display: inline; 27 | } 28 | 29 | & ul { 30 | list-style-type: none; 31 | display: inline; 32 | padding: 0; 33 | & li { 34 | display: inline-block; 35 | padding: 5px 10px; 36 | font-size: 0.75em; 37 | font-weight: 600; 38 | text-transform: uppercase; 39 | } 40 | & a { 41 | color: white; 42 | letter-spacing: 1px; 43 | padding: 2px 0; 44 | border-bottom: 3px solid transparent; 45 | transition: 0.4s border-color; 46 | &:hover { 47 | text-decoration: none; 48 | color: lighten($csh-pink, 50%); 49 | border-color: lighten($csh-pink, 50%); 50 | } 51 | &.active, 52 | &:active { 53 | border-color: lighten($csh-pink, 30%); 54 | } 55 | } 56 | } 57 | & .dropdown-menu { 58 | min-width: 170px; 59 | width: auto; 60 | padding: 10px; 61 | background: rgba(0, 0, 0, 0.6); 62 | & li { 63 | display: block; 64 | } 65 | } 66 | .dropdown:hover .dropdown-menu { 67 | display: block; 68 | } 69 | &.condensed { 70 | .navbar-brand { 71 | max-height: 40px; 72 | margin: 5px 0; 73 | } 74 | & .dropdown-menu { 75 | font-size: 1.2em; 76 | } 77 | } 78 | @media(max-width: 992px) { 79 | .navbar-brand { 80 | max-height: 50px; 81 | } 82 | .navbar-toggler-icon { 83 | width: 30px; 84 | height: 30px; 85 | } 86 | } 87 | } 88 | 89 | .btn.dropdown-toggle:before { 90 | display: none; // remove beginning caret for dropdowns 91 | } 92 | -------------------------------------------------------------------------------- /_includes/footer.html: -------------------------------------------------------------------------------- 1 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /_posts/2017-12-27-deepnet-synapse-delta-visualizer.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Deepnet Synapse Delta Visualizer 4 | date: 2017-12-27 5 | categories: 6 | - projects 7 | description: Four Layer Deep-Learning Neural Network with OpenGL Visualization 8 | image: /projects/neuralNetwork.png 9 | image-sm: /projects/neuralNetwork.png 10 | author: Jacob Potter 11 | author-image: https://csh.rit.edu/~jpotter/jpotter.jpg 12 | author-bio: Second year Computer Science major. 13 | author-email: jmp1617@rit.edu 14 | author-social: 15 | github: https://github.com/jmp1617 16 | linkedin: https://www.linkedin.com/in/jacob-potter-325754129/ 17 | --- 18 | 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](https://en.wikipedia.org/wiki/Sigmoid_function) activation function along with [backpropagation](https://en.wikipedia.org/wiki/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](https://visualstudiomagazine.com/articles/2014/08/01/batch-training.aspx) 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. 19 | 20 | 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 ). 21 | 22 | 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. 23 | 24 | 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. 25 | 26 | For more info on running/compiling and more screen shots, [Check it out on Github!](https://github.com/jmp1617/deepnet) 27 | 28 | -------------------------------------------------------------------------------- /_includes/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ site.title }} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /about/faq.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Frequently Asked Questions 4 | active: about-faq 5 | --- 6 | 7 |
8 |
9 |
10 |
11 |
    12 |
  • 13 |

    Do I need to be a Computer Science major to join?

    14 |

    Nope, CSH accepts students from any program at RIT!

    15 |
  • 16 |
  • 17 |

    Do I need to be a 1st year to join?

    18 |

    19 | Also no! You can join our introductory process at any point of your RIT academic career! 20 | Learn more about applying. 21 |

    22 |
  • 23 |
  • 24 |

    How do I join?

    25 |

    26 | Check out our page on New Members to learn more about applying and joining CSH. 27 |

    28 |
  • 29 |
  • 30 |

    Does being a member cost anything?

    31 |

    32 | Our active membership dues are $80/semester. 33 | Our operating budget is formed every year from dues paid by members in addition to sponsorships, and helps fund improvements to our floor, member projects, and social events! 34 | Members unable to afford their dues can speak to our Financial Director and have their dues waived or adjusted. 35 |

    36 |
  • 37 |
  • 38 |

    Is CSH a fraternity?

    39 |

    40 | No, we're a Special Interest House: a space in RIT's dorms designed for students who share common interests to live together. 41 | Read more here about SIHs here, 42 | and more about RIT Fraternity and Sorority Life here. 43 |

    44 |
  • 45 |
  • 46 |

    47 | Can't find your question here? 48 | Contact us. 49 |

    50 |
  • 51 |
52 |
53 |
54 |
55 |
56 | -------------------------------------------------------------------------------- /assets/js/slider.js: -------------------------------------------------------------------------------- 1 | const SCROLL_ANIMATION_DURATION = 1000; 2 | const CAROUSEL_SCROLL_DOWN_BUTTON_OFFSET = {X: -5, Y: -25}; 3 | 4 | $(document).ready(() => { 5 | let slider = $("#slider"); 6 | if(slider.length === 0) return; 7 | if (slider.length) { 8 | slider.slick({ 9 | dots: true, 10 | autoplay: true, 11 | autoplaySpeed: 5000, 12 | mobileFirst: true, 13 | swipe: true, 14 | }); 15 | } 16 | // Setup carousel scroll-down button click event 17 | let carousel_scroll_down_button = $("#carousel-scroll-down-button"); 18 | if(carousel_scroll_down_button.length === 0) return; 19 | let scrollTopOffset = 1; 20 | carousel_scroll_down_button.on("click", () => { 21 | let calculateFinalPosition = () => slider.find("img").height() + scrollTopOffset - $("nav").outerHeight(); 22 | let animateProperties = { scrollTop: calculateFinalPosition() } 23 | $("html, body").animate(animateProperties, {duration: SCROLL_ANIMATION_DURATION, specialEasing: {scrollTop: "easeOutCubic"}, step: function(now, fx) {fx.end = calculateFinalPosition();}} ); 24 | carousel_scroll_down_button.blur(); 25 | }); 26 | 27 | // Carousel arrow positioning function 28 | let recalculate_arrow_position = () => { 29 | let sliderBottom = slider.height() + slider.offset().top; 30 | let windowBottom = $(window).scrollTop() + $(window).height(); 31 | if ($(window).scrollTop() > sliderBottom) { 32 | carousel_scroll_down_button.css("visibility", "hidden"); 33 | } else { 34 | if(windowBottom < sliderBottom){ 35 | carousel_scroll_down_button.css("transform", `translate3d(${-carousel_scroll_down_button.width()/2 + CAROUSEL_SCROLL_DOWN_BUTTON_OFFSET.X}px, ${windowBottom-carousel_scroll_down_button.height() + CAROUSEL_SCROLL_DOWN_BUTTON_OFFSET.Y}px,0px)`); 36 | } else{ 37 | carousel_scroll_down_button.css("transform", `translate3d(${-carousel_scroll_down_button.width()/2 + CAROUSEL_SCROLL_DOWN_BUTTON_OFFSET.X}px, ${slider.height()-carousel_scroll_down_button.height() + CAROUSEL_SCROLL_DOWN_BUTTON_OFFSET.Y}px, 0px)`); 38 | } 39 | carousel_scroll_down_button.css("visibility", "visible"); 40 | } 41 | } 42 | 43 | // Position carousel scroll-down button 44 | $(window).on("scroll load resize focus blur", recalculate_arrow_position); 45 | // Set interval (necessary for ensuring positioning when resize events don't trigger properly) 46 | $(window).on("resize", () => { 47 | const maxLoops = 10; 48 | let loops = 0; 49 | let tempInterval = setInterval(() => { 50 | if(loops >= maxLoops) clearInterval(tempInterval); 51 | recalculate_arrow_position(); 52 | loops++; 53 | }, 100); 54 | }); 55 | recalculate_arrow_position(); 56 | }); 57 | -------------------------------------------------------------------------------- /_posts/2018-04-18-capsule-killer.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Capsule Killer 4 | date: 2018-04-18 5 | categories: 6 | - projects 7 | description: A first-person shooter developed using Unity and C#. 8 | image: /projects/capsuleKiller.png 9 | image-sm: /projects/capsuleKiller.png 10 | author: Zack Yenchik 11 | author-image: https://avatars0.githubusercontent.com/u/34044719?s=460&v=4 12 | author-bio: First Year Computer Science Student at Rochester Institute of Technology 13 | author-email: zyenchik@gmail.com 14 | author-social: 15 | github: https://github.com/zackyenchik 16 | --- 17 | # Summary 18 | [Capsule Killer](https://github.com/zcy3071/CapsuleKiller) is a first-person shooter that I developed to learn more about the skills and 19 | 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, 20 | 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 21 | at random locations throughout the map every 2-5 seconds. The enemies move towards the player, doing damage upon collision with the player. 22 | 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. 23 | 24 | ## The Enemies 25 | The enemies in the game are pretty simple. Once they spawn, they find the player in the game and begin moving towards them. 26 | If the enemy is able to collide with the player they stop moving to avoid pushing the player aroundand then begin doing damage 27 | to the player. Damage is continually dealt until the enemy and player are no longer colliding. It takes 4 shots to destroy an 28 | enemy in the current build of the game. 29 | 30 | ## The Player 31 | 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 32 | and translated into movement of the player using some fun vector math. The player also has the ability to press the Space key 33 | 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, 34 | 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 35 | 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. 36 | 37 | ## Conclusion 38 | Overall, I had a blast with this project. Developing Capsule Killer was my first true experience working on a large project. 39 | 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 40 | valuable opportunities to further my understanding of what I was doing. Although the game itself is pretty simple, I think 41 | the experience I gained made it worthwhile, as it has furthered my understanding of things like version control, game engines, 42 | and programming in general. 43 | 44 | Feel free to check out the source code for Capsule Killer [here](https://github.com/zcy3071/CapsuleKiller)! -------------------------------------------------------------------------------- /about/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: About CSH 4 | active: about 5 | --- 6 | 7 |
8 |
9 |
10 |
11 |

12 | Founded in 1976, Computer Science House is one of the oldest and most active Special Interest Houses of the Rochester Institute of Technology in Rochester, NY. Located on the third floor of the Fredericka Douglass Sprague Perry Hall dormitory, CSH provides a revolutionary living environment for over fifty on-floor and many more off-floor students. 13 |

14 |

15 | In addition to RIT's standard residence hall facilities, CSH has several special multi-purpose rooms, filled with technical and material resources for members to use. CSH's computing resources include student maintained e-mail, newsgroups, database, web space services, a private wired network, and plenty of servers and workstations. Hands-on learning is emphasized to help members get an advantage in their professional and academic careers. 16 |

17 |
18 |
19 | Three CSHers hanging out during a Lounge In The Quad event 20 |
21 |
22 |
23 |
24 |

25 | CSH is an exciting place to live and learn. There are always fun things to do, interesting projects to work on, and members who are eager to share their expertise in a wide variety of subjects. Members share a feeling of kinship, belonging, and commitment to each other and the organization. The floor has a unique social and academic atmosphere: people here like to learn. 26 |

27 |
28 |
29 |
30 |
31 | CSHers on our annual fall camping trip 32 |
33 |
34 |

35 | CSH organizes annual events such as Tour de Rochester, Welcome Back, Fall Camping, and Holiday Dinner. Other events such as educational seminars, study jams, hackathons, movie nights, Capture the Disk, road trips and bowling nights also occur frequently. Members play intramural sports such as volleyball, dodge ball, soccer, and broomball together. 36 |

37 |

38 | While much has changed over the years, CSH's mission to help its members grow intellectually, socially, and professionally continues to succeed and surpass expectations. 39 |

40 | More events 41 |
42 |
43 |
44 |
45 | -------------------------------------------------------------------------------- /_sass/_triple_image.scss: -------------------------------------------------------------------------------- 1 | $card-size: 300px; 2 | $p-m-default: 20px; 3 | 4 | $black: #111; 5 | $white: #FFF; 6 | 7 | $csh-pink: #b0197e; 8 | $csh-blue: #404b69; 9 | $gray: #f4f4f6; 10 | 11 | // Easing Properties 12 | $easeOutQuad: cubic-bezier(0.250, 0.460, 0.450, 0.940); 13 | 14 | // PX to EM 15 | $browser-context: 16; 16 | 17 | @function em($pixels, $context: $browser-context) { 18 | @if (unitless($pixels)) { 19 | $pixels: $pixels * 1px; 20 | } 21 | 22 | @if (unitless($context)) { 23 | $context: $context * 1px; 24 | } 25 | 26 | @return $pixels / $context * 1em; 27 | } 28 | 29 | // Transition Mixin 30 | @mixin transition($transition...) { 31 | -moz-transition: $transition; 32 | -o-transition: $transition; 33 | -webkit-transition: $transition; 34 | transition: $transition; 35 | } 36 | 37 | 38 | .triple_a { 39 | @include transition(all 300ms $easeOutQuad); 40 | &:hover { 41 | @include transition(all 300ms $easeOutQuad); 42 | } 43 | } 44 | 45 | #wrapper { 46 | position: relative; 47 | display: flex; 48 | height: 100vh; 49 | align-items: center; 50 | justify-content: center; 51 | } 52 | 53 | article.card { 54 | background-image: linear-gradient(0deg, $csh-blue 0%, $csh-pink 100%); 55 | width: $card-size; 56 | height: $card-size; 57 | margin: $p-m-default; 58 | position: relative; 59 | overflow: hidden; 60 | } 61 | 62 | .card-image { 63 | max-width: 100%; 64 | width: 100%; 65 | height: $card-size; 66 | object-fit: cover; 67 | transform: translate(0,0); 68 | @include transition(all 400ms $easeOutQuad); 69 | } 70 | 71 | .card-meta { 72 | font-size: em(11); 73 | text-transform: uppercase; 74 | letter-spacing: 1px; 75 | &:before { 76 | content: ''; 77 | height: 1px; 78 | width: 30px; 79 | background-color: #fff; 80 | position: relative; 81 | display: block; 82 | margin-bottom: 10px; 83 | backface-visibility: hidden; 84 | opacity: 0; 85 | transform: translate(0,-10px); 86 | @include transition(all 200ms $easeOutQuad); 87 | } 88 | } 89 | 90 | .card-text { 91 | color: #FFF; 92 | // This next line controls the background opacity 93 | background-color: rgba($black, .40); 94 | position: absolute; 95 | padding: $p-m-default; 96 | z-index: 10; 97 | width:100%; 98 | height: 100%; 99 | display: flex; 100 | flex-wrap: wrap; 101 | align-content: flex-end; 102 | @include transition(all 200ms $easeOutQuad); 103 | } 104 | 105 | .card-title { 106 | margin: 8px 0; 107 | font-weight: 300; 108 | font-size: em(30); 109 | } 110 | 111 | @media screen and (min-width: 800px) { 112 | .card a { 113 | &:hover { 114 | .card-text { 115 | background-color: rgba($black, .60); 116 | } 117 | .card-meta { 118 | &:before { 119 | transform: translate(0,0); 120 | opacity: 1; 121 | @include transition(all 200ms $easeOutQuad); 122 | } 123 | } 124 | 125 | .card-image { 126 | transform: translate(20px,0); 127 | @include transition(all 400ms $easeOutQuad); 128 | } 129 | } 130 | } 131 | } 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /_includes/nav.html: -------------------------------------------------------------------------------- 1 | 36 | -------------------------------------------------------------------------------- /_posts/2018-04-11-kudos-mapping-and-slam.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Kudos Mapping and SLAM Project 4 | date: 2018-04-11 5 | categories: 6 | - Robotics 7 | - SLAM 8 | - ROS 9 | - Mapping 10 | - Project 11 | description: Added LiDAR mapping functionality to Computer Science House's floor robot, Kudos. 12 | image: /projects/CSH_Map_2.png 13 | image-sm: /projects/CSH_Map_2.png 14 | author: Trevor Sherrard 15 | author-image: http://www.trevorsherrard.com/images/profile_pics.jpg 16 | author-bio: Electrical Engineer, roboticist, computer vision enthusiast. I have a strong passion for seeing my software come alive in my projects. 17 | author-email: tws4129@rit.edu 18 | author-social: 19 | github: https://github.com/sherrardTr4129 20 | linkedin: https://www.linkedin.com/in/trevor-sherrard 21 | --- 22 | 23 | ## Background 24 | 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. 25 | 26 | ## Details 27 | 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. 28 | 29 | ![Kudos Control Topology](http://www.trevorsherrard.com/images/KudosCommProtocol.png) 30 | 31 | ## Future Iterations 32 | 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. 33 | 34 | ## GitHub Links 35 | Have a look at the project setup and code below! 36 | 37 | [Kudos ROS package](https://github.com/ComputerScienceHouse/Kudos/tree/master/kudos_csh) 38 | 39 | [MoveBase Controller](https://github.com/ComputerScienceHouse/Kudos/tree/master/KudosROS) 40 | -------------------------------------------------------------------------------- /_posts/2018-04-12-proxstar.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Proxstar 4 | date: 2018-04-12 5 | categories: projects 6 | description: Proxstar is a VM self-service tool that integrates with Proxmox and STARRS 7 | image: /projects/proxstar.png 8 | image-sm: /projects/proxstar.png 9 | author: Jordan Rodgers 10 | author-image: https://avatars1.githubusercontent.com/u/5183608?s=460&v=4 11 | author-bio: Fourth Year Networking & Systems Administration Student at Rochester Institute of Technology 12 | author-email: com6056@csh.rit.edu 13 | author-social: 14 | github: https://github.com/com6056 15 | --- 16 | 17 | ## The Problem 18 | 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. 19 | 20 | ## The Solution 21 | 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. 22 | 23 | #### Making RTPs' Lives Easier 24 | 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. 25 | 26 | #### Struggles 27 | 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. 28 | 29 | ##### Feel free to check out the source code for Proxstar [here](https://github.com/com6056/proxstar)! 30 | -------------------------------------------------------------------------------- /assets/css/main.scss: -------------------------------------------------------------------------------- 1 | --- 2 | # this ensures Jekyll reads the file to be transformed into CSS later 3 | # only Main files contain this front matter, not partials. 4 | --- 5 | 6 | $CSHPUBSITE_ASSETS_URL: "{{site.env.CSHPUBSITE_ASSETS_URL}}"; 7 | $blue: #404b69; 8 | $gray: #f4f4f6; 9 | $csh-pink: #b0197e; 10 | 11 | body { 12 | position: relative; 13 | width: 100%; 14 | height: 100%; 15 | padding: 0; 16 | margin: 0; 17 | overflow: overlay; // For transparent scrollbar 18 | background: white; 19 | } 20 | 21 | /* Scrollbar (only supported by some browsers) */ 22 | ::-webkit-scrollbar { 23 | width: 12px; 24 | } 25 | 26 | ::-webkit-scrollbar-track { 27 | background: transparent; 28 | } 29 | 30 | ::-webkit-scrollbar-thumb { 31 | box-shadow: inset 0px 0px 10px 10px rgba(0,0,0,0.2); 32 | border: 3px solid transparent; 33 | border-radius: 5px; 34 | } 35 | 36 | ::-webkit-scrollbar-thumb:hover { 37 | box-shadow: inset 0px 0px 10px 10px rgba(0, 0, 0, 0.4); 38 | border: 2px solid transparent; 39 | } 40 | 41 | .container.spaced { 42 | padding-top: 50px; 43 | padding-bottom: 50px; 44 | } 45 | 46 | .gray-wrapper { 47 | padding-top: 10px; 48 | padding-bottom: 10px; 49 | background: $gray; 50 | &.padded { 51 | padding-top: 30px; 52 | padding-bottom: 30px; 53 | } 54 | } 55 | 56 | img.rounded, 57 | .card { 58 | width: 100%; 59 | border-radius: 8px; 60 | box-shadow: 0 2px 15px darken($gray, 20%); 61 | } 62 | 63 | .container { 64 | display: flex; 65 | flex-direction: row; 66 | flex-wrap: wrap; 67 | justify-content: space-evenly; 68 | align-items: flex-start; 69 | } 70 | 71 | .container_stat { 72 | display: flex; 73 | flex-direction: row; 74 | flex-wrap: wrap; 75 | justify-content: space-evenly; 76 | align-items: flex-start; 77 | } 78 | 79 | .stat_big { 80 | color: $csh-pink; 81 | font-size: 2.5em; 82 | font-weight: 600; 83 | margin: 0%; 84 | } 85 | 86 | .stat_tag { 87 | margin: 0.2em; 88 | } 89 | 90 | .stat_card { 91 | text-align: center; 92 | width: 200px; 93 | } 94 | 95 | .stat_desc { 96 | font-size: 0.6em; 97 | font-weight: 600; 98 | } 99 | 100 | .card-header { 101 | overflow: hidden; 102 | text-overflow: ellipsis; 103 | } 104 | 105 | img.center-vertically { 106 | width: 80%; 107 | height: auto; 108 | position: relative; 109 | top: 50%; 110 | transform: translateY(-50%); 111 | } 112 | 113 | img.padded-gray { 114 | padding: 10%; 115 | background: #EEEEEE; 116 | } 117 | 118 | .logo-grid { 119 | & img { 120 | width: 100%; 121 | margin-top: 1.5em; 122 | transition: 0.3s opacity; 123 | &:hover { 124 | opacity: 0.75; 125 | } 126 | @media (max-width: 992px) { 127 | margin-top: 1em; 128 | } 129 | } 130 | } 131 | 132 | a.btn { 133 | font-size: 0.75em; 134 | margin-bottom: 1em; 135 | } 136 | 137 | @media screen and (max-width: 570px) { 138 | .quad_image { 139 | display: block; 140 | } 141 | } 142 | 143 | @media screen and (min-width: 571px) { 144 | .quad_image { 145 | display:grid; 146 | grid-template-columns: 50% 50%; 147 | } 148 | } 149 | 150 | @media screen and (min-width: 1100px) { 151 | .quad_image { 152 | display:grid; 153 | grid-template-columns: 25% 25% 25% 25%; 154 | } 155 | } 156 | 157 | 158 | 159 | @import "typography"; 160 | @import "nav"; 161 | @import "slider"; 162 | @import "about"; 163 | @import "projects"; 164 | @import "sponsors"; 165 | @import "splash"; 166 | @import "post"; 167 | @import "eboard"; 168 | @import "tour"; 169 | @import "insights"; 170 | @import "footer"; 171 | @import "hackathon"; 172 | @import "triple_image"; 173 | @import "project_images.scss"; 174 | -------------------------------------------------------------------------------- /_posts/2018-03-28-creating-go-in-swift.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Creating Go in Swift 4 | date: 2018-03-28 5 | categories: 6 | - projects 7 | description: A functional version of Go in Swift, using SpriteKit 8 | author: Zachary Williams 9 | image: /projects/nikhedonia.png 10 | image-sm: /projects/nikhedonia.png 11 | author-image: https://avatars0.githubusercontent.com/u/5004737?s=460&v=4 12 | author-bio: Undergraduate student studying computer science at the Rochester Institute of Technology. I specialize in web & app development, as well as user experience design. 13 | author-email: zachwilliams.me@gmail.com 14 | author-social: 15 | github: https://github.com/ZachTheSloth 16 | linkedin: https://www.linkedin.com/in/z-n-w/ 17 | --- 18 | 19 | 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. 20 | 21 | 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. 22 | 23 | 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. 24 | 25 | 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. 26 | 27 | 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. 28 | 29 | 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. 30 | 31 | To see the code, [check out the GitHub project] 32 | (https://github.com/ZachTheSloth/NIKHEDONIA). 33 | -------------------------------------------------------------------------------- /assets/js/sponsors.js: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | import {pathJoin} from "./utility.js"; 5 | 6 | class Sponsor { // this may be extra, ¯\_(ツ)_/¯ 7 | constructor(image, url, name) { 8 | this.image = pathJoin("{{ site.env.CSHPUBSITE_ASSETS_URL }}", image); 9 | this.url = url; 10 | this.name = name; 11 | } 12 | } 13 | 14 | $(document).ready(() => { 15 | if ($('#homepage-sponsors').length) { 16 | const sponsors = [ 17 | new Sponsor('/sponsors/ritLarge.png', 'http://rit.edu', 'Rochester Institute of Technology'), 18 | new Sponsor('/sponsors/symantec.png', 'http://symantec.com', 'Symantec'), 19 | new Sponsor('/sponsors/att.png', 'http://att.com', 'AT&T'), 20 | new Sponsor('/sponsors/datto.png', 'http://datto.com', 'Datto'), 21 | new Sponsor('/sponsors/UofR.png', 'http://rochester.edu', 'University of Rochester'), 22 | new Sponsor('/sponsors/linkedin.png', 'http://linkedin.com', 'LinkedIn'), 23 | new Sponsor('/sponsors/microsoft.png', 'http://microsoft.com', 'Microsoft'), 24 | new Sponsor('/sponsors/cisco.png', 'http://cicso.com', 'Cisco'), 25 | new Sponsor('/sponsors/google.png', 'http://google.com', 'Google'), 26 | new Sponsor('/sponsors/hp.png', 'http://hp.com', 'HP'), 27 | new Sponsor('/sponsors/johnsonjohnson.png', 'http://jnj.com', 'Johnson and Johnson'), 28 | new Sponsor('/sponsors/lourdesindustries.png', 'http://lourdesinc.com', 'Lourdres Industries'), 29 | new Sponsor('/sponsors/mooreresearchcenter.png', 'http://mrci.com', 'Moore Research Center'), 30 | new Sponsor('/sponsors/intergraph.png', 'http://intergraph.com', 'Intergraph'), 31 | new Sponsor('/sponsors/janestreet.png', 'http://janestreet.com', 'Jane Street'), 32 | new Sponsor('/sponsors/northropgrumman.png', 'http://northropgrumman.com', 'Northrop Grumman'), 33 | new Sponsor('/sponsors/sonus.png', 'http://sonus.net', 'Sonus'), 34 | new Sponsor('/sponsors/oracle.png', 'http://oracle.com', 'Oracle'), 35 | new Sponsor('/sponsors/perforce.png', 'http://perforce.com', 'Perforce'), 36 | new Sponsor('/sponsors/cadence.png', 'http://cadence.com', 'Cadence'), 37 | new Sponsor('/sponsors/podi.png', 'http://podi.com', 'Potomac Digitek'), 38 | new Sponsor('/sponsors/dupont.png', 'http://dupont.com', 'DuPont'), 39 | new Sponsor('/sponsors/amdex.png', 'http://amdexcorp.com', 'Amdex'), 40 | new Sponsor('/sponsors/ti.png', 'http://ti.com', 'Texas Instruments'), 41 | new Sponsor('/sponsors/xerox.png', 'http://xerox.com', 'Xerox'), 42 | new Sponsor('/sponsors/citrix.png', 'http://citrix.com', 'Citrix'), 43 | new Sponsor('/sponsors/fxcm.png', 'http://fxcm.com', 'FXCM'), 44 | new Sponsor('/sponsors/pdhi.png', 'http://pdhi.com', 'PDHI'), 45 | new Sponsor('/sponsors/datadog.png', 'http://www.datadoghq.com/', 'Datadog'), 46 | new Sponsor('/sponsors/dmarcian.svg', 'http://dmarcian.com/', 'dmarcian'), 47 | new Sponsor('/sponsors/pritunl.png', 'https://pritunl.com/', 'Pritunl'), 48 | new Sponsor('/sponsors/sentry.svg', 'https://sentry.io/', 'Sentry'), 49 | new Sponsor('/sponsors/slack.png', 'https://slack.com/', 'Slack'), 50 | new Sponsor('/sponsors/proxmox.png', 'https://proxmox.com/', 'Proxmox'), 51 | new Sponsor('/sponsors/tenable.png', 'https://tenable.com/', 'Tenable'), 52 | new Sponsor('/sponsors/wayfair.png', 'https://wayfair.com/', 'Wayfair'), 53 | new Sponsor('/sponsors/johonnot.png', 'https://johonnottechnologies.com/', 'Johonnot'), 54 | 55 | ]; 56 | 57 | for (let i = 0; i <= 6; i++) { 58 | var index = Math.floor(Math.random() * sponsors.length) 59 | var item = sponsors[index]; 60 | $('#sponsor-' + i + ' img').attr('src', item.image); 61 | $('#sponsor-' + i + ' a').attr('href', item.url); 62 | $('#sponsor-' + i + ' img').attr('alt', item.name); 63 | sponsors.splice(index, 1); 64 | } 65 | } 66 | }); 67 | -------------------------------------------------------------------------------- /_posts/2018-02-28-swiftfall.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Swiftfall 4 | date: 2018-02-28 21:25:00 5 | categories: projects 6 | description: A wrapper for an API called Scryfall. 7 | author: Braden Bowdish 8 | image: /projects/swiftfall_screenshot.png 9 | image-sm: /projects/swiftfall_screenshot.png 10 | author-image: https://avatars2.githubusercontent.com/u/15185628?s=460&v=4 11 | author-bio: Lover of Swift and Magic. 3rd year member of Computer Science House. 12 | author-email: bmbowdish@csh.rit.edu 13 | author-social: 14 | github: https://github.com/bmbowdish 15 | --- 16 | 17 | # What is Swiftfall? 18 | 19 | Swiftfall is an API wrapper written in Swift for the API Scryfall. 20 | 21 | [Scryfall](https://scryfall.com/docs/api) is an API which handles information about the card game Magic: The Gathering. 22 | 23 | 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. 24 | 25 | Thankfully, [Scrython](https://github.com/nandascott/Scrython) does this already, but in Python. 26 | 27 | ### Why Swift Was Appealing 28 | 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. 29 | 2. Swift has a JSON decoder built in and it is appealing to have no dependencies. 30 | 3. iOS, Apple TV, Apple Watch, and MacOS development are all far easier in Swift 31 | 4. Swift is new, and it is fun to do things never done before 32 | 33 | # How do you use Swiftfall? 34 | First, create an executable package. The executable includes a Hello World function by default. 35 | 36 | ``` 37 | $ mkdir MyExecutable 38 | $ cd MyExecutable 39 | $ swift package init --type executable 40 | $ swift build 41 | $ swift run 42 | Hello, World! 43 | ``` 44 | 45 | Next, 46 | 47 | ``` 48 | $ swift package generate-xcodeproj 49 | ``` 50 | 51 | This creates the correct package files so you can add dependencies. 52 | 53 | Then, add Swiftfall as a dependency for the executable. 54 | 55 | ``` 56 | import PackageDescription 57 | 58 | let package = Package( 59 | name: "MyExecutable", 60 | dependencies: [ 61 | // Dependencies declare other packages that this package depends on. 62 | // .package(url: /* package url */, from: "1.0.0"), 63 | .package(url:"https://github.com/bmbowdish/Swiftfall.git", from: "1.2.0") 64 | ], 65 | targets: [ 66 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 67 | // Targets can depend on other targets in this package, and on products in packages which this package depends on. 68 | .target( 69 | name: "MyExecutable", 70 | dependencies: ["Swiftfall"]), 71 | ] 72 | ) 73 | ``` 74 | 75 | Then, run: 76 | 77 | ``` 78 | $ swift package generate-xcodeproj 79 | ``` 80 | 81 | I believe this is because you need to pull down the new dependencies from the source. 82 | 83 | 84 | Now you're ready to use Swiftfall! 85 | 86 | # Actually Using Swiftfall 87 | 88 | ## Getting a Card 89 | `Swiftfall.getCard(fuzzy:String) -> Card? _(Fuzzy search)_` 90 | 91 | `Swiftfall.getCard(exact:String) -> Card? _(Exact search)_` 92 | 93 | `Swiftfall.getRandomCard() -> Card? _(Random Card)_` 94 | 95 | Ex. 96 | 97 | ``` 98 | import Swiftfall 99 | let card = Swiftfall.getCard(exact:"Black Lotus") 100 | card?.simplePrint() 101 | ``` 102 | 103 | Out. 104 | 105 | ``` 106 | Name: Black Lotus 107 | Cost: {0} 108 | Type Line: Artifact 109 | Oracle Text: 110 | {T}, Sacrifice Black Lotus: Add three mana of any one color to your mana pool. 111 | ``` 112 | 113 | ## Other Things 114 | Swiftfall supports more than just cards. Other items you can retrieve include: 115 | 116 | * Sets 117 | * Rulings 118 | * Ruling Lists 119 | * Card Lists 120 | * Set Lists 121 | 122 | You can find more information about [Swiftfall on GitHub.com](https://github.com/bmbowdish/Swiftfall) 123 | -------------------------------------------------------------------------------- /_posts/2022-10-04-slate.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Slate 4 | date: 2022-10-04 5 | categories: 6 | - projects 7 | description: Event scheduling, simplified. 8 | image: /projects/slate.png 9 | image-sm: /projects/slate.png 10 | author: Andrew Simonson 11 | author-image: https://profiles.csh.rit.edu/image/cinnamon 12 | author-bio: Third year Computer Science major, focusing on data science and predictive analytics. 13 | author-email: asimonson1125@gmail.com 14 | author-social: 15 | github: https://github.com/asimonson1125 16 | linkedin: https://www.linkedin.com/in/simonsonandrew/ 17 | website: https://asimonson.com 18 | --- 19 | 20 | This project started with a phone call. I needed to reserve a room for a presentation with some friends and to do that, I had to open the phone app on my phone. I had to converse with a real person, suggesting that, if not Thursday at noon, maybe the following Monday at 4 PM would work. 21 | 22 | Luckily for this scenario, I already knew the schedules of everyone in attendance and I only had to find a time the room was open. But event coordinators greater than myself have always had to juggle the plans of a dozen people, sometimes without actually knowing their schedules, and that's work. Even during the dark ages (read: 2020), that's unacceptable. Let's fix that. 23 | 24 | # Slate 25 | [Slate](https://slate.csh.rit.edu) is an event coordination tool that compiles the calendars of participants to generate a table representing when the most participants can attend. CSH members can link their calendar to their profile, allowing coordinators to load up to date schedules and select event times with maximal attendance. 26 | 27 | # How it works 28 | - Organization members add icalendar (.ics) files from any online calendar service (Google Calendar, Apple Calendar, etc.) to their profile for live calendar updates 29 | - Coordinators select participant members and add additional external calendars and define the searched time period 30 | - Slate uses an LDAP connection to the organization services to download calendars 31 | - date and time intervals are scored with the weighted availabilities of the participants, discarding time intervals where mandatory attendees are unavailable 32 | - Average weekly analysis is generated for planning recurring weekly events 33 | 34 | # Timeline 35 | ## Ver. 1.0 (2020-21) 36 | My freshman year's contribution to Slate was dedicated to creating the calendar compiler and a primitive web interface to interact with the service. Time, as it turns out, is hardly a linear thing in the minds of humans. Even with widely accepted libraries for datetime and icalendar, managing timezone-naive events, daylight savings, and the different calendar services' methodology was by far the greatest challenge Slate faced. 37 | 38 | Working on Slate's web application also introduced me to the Flask framework, Docker, and Openshift. And since all three of these tools became my first choices for all subsequent projects, I'd like to extend my personal thanks to the CSH sysadmin people and RTPs. Thanks to these chads, I'm officially a computer person now. 39 | 40 | ## Ver. 2.0 (2021-22) 41 | Slate should be, by definition, a boring project to work on. Time math is warm and bad. And yet, I couldn't stop working on it. Over the summer, I overhauled the calendar compiler, speeding it up by 12,000% for 3 calendars over a 3 month period. Now it's fast enough to be an actual product to society. I also made the weekly analysis with a much improved UI (websockets! That's new to me) and added the LDAP (also new to me) connection to CSH. CSH members can now add their calendars to their profiles. Guests can still use an open version of Slate without organization profiles. 42 | 43 | # Future 44 | Yeah, I plan.
45 | As of version 2.0 I believe Slate is in a servicable state, but, as with all good ideas, expanding it is totally doable. It might not be much coming from the guy who wrote it, but Slate is more than a gimmick. Slate can easily be made faster, more user friendly, and, Machine Learning Ultimate aside, more helpful in its analysis. I could work on this project until the end of time. If this project taught me anything, it's that these little projects stemming from a mundane phone call can become real products and that it doesn't take a company or even a startup team to make them real. I might be moving on for now, but don't count it out - good projects always have the potential for us to come back to them. -------------------------------------------------------------------------------- /_posts/2023-02-20-datadog.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: CSH's Use of Datadog in the Server Room 4 | date: 2023-02-20 5 | categories: 6 | - projects 7 | description: "With so many servers in our server room, we need a good way to manage them all. Introducing: Datadog!" 8 | image: /projects/dd.png 9 | image-sm: /projects/dd.png 10 | author: Joe Abbate 11 | author-image: https://profiles.csh.rit.edu/image/skyz 12 | author-bio: Second/Third Year Computing Security BS/MS Major 13 | author-email: joe.abbate@mail.rit.edu 14 | author-social: 15 | github: https://github.com/jabbate19 16 | linkedin: https://www.linkedin.com/in/jabbate19/ 17 | website: https://joeabbate.me 18 | --- 19 | 20 | As a student organization, we try to provide our members with tools and experience that will apply to the real world. When it comes to our server room, we wanted a mainstream location to monitor all of our nodes, containers, and virtual machines that keep us going. With the generous donation of [Datadog](https://www.datadoghq.com/) software, we are able to do this using industry-level tools. 21 | 22 | ## What is Datadog? 23 | Datadog provides system and security monitoring to multiple machines, display them in a unified format, and provide alerts for system administrators to see. An Agent is installed on all machines, and these agents communicate to the Datadog servers with data. This data can be compiled into dashboards that provide network-wide statistics, or be used to alert us via Slack. 24 | 25 | ## How do we use it? 26 | 27 | ### Machine Management 28 | All agents on phyisical or virtual machines are installed on our machines via Puppet, which is our preferred method of system management. Once the agent is installed, we receive data on that machine's usage, uptime, and potential security issues. 29 | For containers, we run an [OKD](https://www.okd.io/) cluster that has Datadog's implementation installed. This allows the agent to monitor our containers alongside the bare metal machines. This way, if there happens to be a security issue within a container, it can be identified before it can potentially break out or cause issues. 30 | 31 | ### Website Automation/Checks 32 | Alongside getting statistics from machines, we use Datadog to ensure our websites are functional. We run a lot of websites that are both public and private, so being alerted when these run into an issue is a big plus. The two ways we do this are API checks and workflow checks. In API checks, a Datadog agent reaches out to a specific API on a website and ensures it gets an OK response. If not, it will trigger an alert. In a workflow check, an agent will attempt to load a website like a user and go through a common activity to ensure the user experience is also functional. 33 | 34 | ### Dashboard and Slack Notifications 35 | With all of these alerts and statistics, we need a way to gather and display it all. We have about 70 machines and many websites all producing data. To see all of this, we use dashboards that are displayed on our floor in RIT Dorms. When you get off the elevator to our floor, you can quickly see statistics of our infrastructure and identify if there are any current issues to be addressed. An example of our most popular dashboard is above! 36 | 37 | Alongside this, we enjoy getting detailed, immediate alerts if something happens to go down. Since Slack is our form of communication across the organization, we have channels for Slack alerts. These are also able to be divided by severity or node, so we can pay more attention to alerts that may impact our core infrastructure before we handle a website with a bug. 38 | 39 | ## Open Source! 40 | Personally, I love any project that is open source so I can see how it works and find ways to contribute. A lot of Datadog's code is available on [Github](https://github.com/DataDog), so it can be seen by anyone! In the past, I made a contribution to their MongoDB module to update the parameters used in a Puppet config to set up a database monitor for that server. 41 | 42 | ## Future Implementations 43 | We hope to add custom statistics to our Datadog dashboards in the future to get our members more involved and comfortable with the Datadog experience. A recent project in the works in an Arduino that will provide plant moisture levels for our plants across the floor. Once it gets the data, it will send a UDP packet to one of our nodes using DogStatsd. As we continue to expand our infrastructure, I can guarantee Datadog will be there to help us manage it all. We are college students, and we appreciate the help that Datadog gives us! 44 | -------------------------------------------------------------------------------- /assets/js/tour.js: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | const content = { 4 | 'dorm': { 5 | 'title': 'Dorm Room', 6 | 'photos': ['{{site.env.CSHPUBSITE_ASSETS_URL}}/tour/dorm/1'], 7 | 'description': 'Though the walls are the same as regular dorm rooms, our rooms usually look rather different than the standard RIT room layout.', 8 | }, 9 | 'user-center': { 10 | 'title': 'User Center', 11 | 'photos': ['{{site.env.CSHPUBSITE_ASSETS_URL}}/tour/usercenter/1', '{{site.env.CSHPUBSITE_ASSETS_URL}}/tour/usercenter/2'], 12 | 'description': 'The User Center is a productive social room. It is often sought out as a place for members to socialize and get work done. It also serves as a meeting place, a project work room, and a technical seminar room.', 13 | }, 14 | 'lounge': { 15 | 'title': 'Lounge', 16 | 'photos': ['{{site.env.CSHPUBSITE_ASSETS_URL}}/tour/lounge/1', '{{site.env.CSHPUBSITE_ASSETS_URL}}/tour/lounge/2'], 17 | 'description': 'The Lounge is CSH\'s main social hub. This room is used to host movie nights, social events, technical seminars, company visits, and E-Board meetings.', 18 | }, 19 | 'server-room': { 20 | 'title': 'Server Room', 21 | 'photos': ['{{site.env.CSHPUBSITE_ASSETS_URL}}/tour/server/1', '{{site.env.CSHPUBSITE_ASSETS_URL}}/tour/server/2'], 22 | 'description': 'CSH\'s server room serves as a place for members to learn and practice their networking skills. It also serves as a place to host the variety of network services provided to our members.', 23 | }, 24 | 'software-room': { 25 | 'title': 'Software Room', 26 | 'photos': ['{{site.env.CSHPUBSITE_ASSETS_URL}}/tour/software/1', '{{site.env.CSHPUBSITE_ASSETS_URL}}/tour/software/2'], 27 | 'description': 'The Software Room is the perfect place for small group tasks. It is a quiet room that is away from the normal hustle and bustle of floor which makes it great for taking phone calls, playing board games, and working on group assignments. The Software Room also houses CSH\'s book collection as well as a variety of board games.', 28 | }, 29 | 'research-room': { 30 | 'title': 'Research Room', 31 | 'photos': ['{{site.env.CSHPUBSITE_ASSETS_URL}}/tour/research/1', '{{site.env.CSHPUBSITE_ASSETS_URL}}/tour/research/2', '{{site.env.CSHPUBSITE_ASSETS_URL}}/tour/research/3', '{{site.env.CSHPUBSITE_ASSETS_URL}}/tour/research/4'], 32 | 'description': 'The Research Room is CSH\'s workshop. It houses our two 3D Printers, as well as the tools and materials for members\' electronics projects.', 33 | }, 34 | 'library': { 35 | 'title': 'Library', 36 | 'photos': ['{{site.env.CSHPUBSITE_ASSETS_URL}}/tour/library/1', '{{site.env.CSHPUBSITE_ASSETS_URL}}/tour/library/2'], 37 | 'description': 'The Library is CSH\'s multi-function archive and arcade. It serves as a storage place for all of our historical records and keepsakes as well as a variety of arcade machines, both vintage and custom-built.', 38 | }, 39 | }; 40 | 41 | const constructSliderHTML = (room) => { 42 | let innerHTML = ''; 43 | for (let photo of room.photos) { 44 | innerHTML += ` 45 | 46 | 47 | 48 | CSH ${room.title} 49 | `; 50 | } 51 | return innerHTML; 52 | }; 53 | 54 | $(document).ready(() => { 55 | if ($('#tour-page').length) { 56 | const room = content['dorm']; 57 | $('#slider').slick('unslick'); 58 | $('#tour-description').text(room.description); 59 | $('#tour-title').text(room.title); 60 | $('#slider').html(constructSliderHTML(room)); 61 | $('#slider').slick({ 62 | dots: true, 63 | autoplay: true, 64 | autoplaySpeed: 5000, 65 | mobileFirst: true, 66 | }); 67 | $('.dropdown-item').click(function(e) { 68 | e.preventDefault(); 69 | $('.dropdown-item.active').first().removeClass('active'); 70 | $(this).addClass('active'); 71 | $('#slider').slick('unslick'); 72 | const room = content[$(this).attr('id')]; 73 | $('#tour-description').text(room.description); 74 | $('#tour-title').text(room.title); 75 | $('#slider').html(constructSliderHTML(room)); 76 | $('#slider').slick({ 77 | dots: true, 78 | autoplay: true, 79 | autoplaySpeed: 5000, 80 | mobileFirst: true, 81 | }); 82 | }); 83 | } 84 | }); 85 | -------------------------------------------------------------------------------- /_posts/2025-03-26-netbox.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Upgrading NetBox 4 | date: 2025-03-26 5 | categories: 6 | - projects 7 | description: "With so many servers in our server room, we need a good way to manage them all. Introducing: Datadog!" 8 | image: /projects/netbox.png 9 | image-sm: /projects/netbox.png 10 | author: Cecilia Lau 11 | author-image: https://profiles.csh.rit.edu/image/pixel 12 | author-bio: Computer Science Major 13 | author-email: pixel@csh.rit.edu 14 | author-social: 15 | github: https://github.com/cecilialau6776 16 | linkedin: https://www.linkedin.com/in/lau-cecilia/ 17 | --- 18 | 19 | # NetBox 20 | So we had started an update to NetBox, a solution for modelling and documenting networks. Unfortunately, we never finished the update, leaving the application in a broken state for several months. This article describes the troubleshooting done and actual steps taken to get NetBox back up and running. While we plan to move to NetBox for our IP management and resource registration, we have several more steps to take before we fully migrate. At the moment, we use STARRS, an in-house solution for IP management and resource registration. STARRS has served us well thus far, but it's long overdue for us to move to a more complete solution. 21 | 22 | ## What is NetBox? What does it do? 23 | NetBox is a Django application that models and documents networks. We define systems, the interfaces attached to the systems, and assign them IP addresses. It also has the capability to visualize what and where things are in our server racks and even documents cables, helping tremendously for when we have to do maintenance. However, by default, it doesn't have the ability to write entries to our DNS and DHCP servers, which is one of the primary features we need to replace [STARRS](https://github.com/ComputerScienceHouse/starrs-web), our current IPAM and DNS solution. Luckily, NetBox's community has created plugins that allow for this and even for syncing switch and router configuration. Using and configuring these plugins would let use NetBox as a single source of truth, simplifying how we configure our network. 24 | 25 | ## Troubleshooting and Fixing NetBox 26 | What we had was an incompletely upgraded NetBox, and internal server errors with strange errors in the logs. Initially, we thought that we had tried to migrate the database directly from 3.6.X to 4.X, but NetBox requires migrating to the latest minor release of the major version (3.7.X) before updating to the next major version (4.X). If that was the case, the best solution would have been to restore the database from a backup (which we didn't have). Luckily for us, this wasn't the problem, so we moved on. 27 | 28 | We had several plugins (`netbox-topology-views`, `social-auth-app-django`, and `netbox-plugin-dns`) installed and enabled. So, first things first - let's find out if the problem is one of the plugins by disabling them all. And... voila! We are no longer presented with an error page. Our prime suspect was `netbox-topology-views`, since it'd caused problems in the past. And after simply bumping the version to its latest, everything seemed to work fine. 29 | 30 | However, a while ago, we'd commented out a few lines of our OIDC groups handler which would sync NetBox user groups with our groups in LDAP. This means that while the page _was_ running, users wouldn't get their groups synced, so our fix would be mildly incomplete. Since I was the one who wrote that handler, I looked into a bit more. I was getting errors like `Field id expected number but got Group`, but the documentation said that everything should've been fine, since the argument I'm passing into `user.groups.set()` was correct. After a little bit of poking around in the Django shell, I find that my import (`from django.contrib.auth.models import Group`) fails, with an error basically saying that this "Group" model is disabled in favor of something else. Turns out that NetBox had updated their system to use a custom `Group` instead of Django's built-in version. A simple change to the import fixed group syncing. 31 | 32 | The largest issues seemed to be fixed, but a few clicks around would again present internal server errors. The messages we got looked to be the database columns not being quite right, so I went ahead and ran the database migrations, and like magic, all the errors are gone! 33 | 34 | The [actual changes](https://github.com/ComputerScienceHouse/netbox-images/pull/5/files) needed were remarkably simple, but let this be a lesson to take database backups and document what was done if you don't complete a migration. 35 | 36 | For NetBox to actually replace STARRS, we still need to work out the plugins that [do the thing that starrs does] and also work towards having NetBox manage our switch and router configurations. For now though, having a working version at all is a major improvement from three months ago and will allow us to actually take these next steps. 37 | -------------------------------------------------------------------------------- /_posts/2020-05-19-docker-rust-notpresent.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Debugging Error: NotPresent with Rust in Docker" 3 | description: "A friend's Docker container was exiting with Error: NotPresent and no other information. I embarked on a deep dive for an ultimately simple cause." 4 | layout: post 5 | date: 2020-05-19 6 | image: /projects/carbon.png 7 | image-sm: /projects/carbon.png 8 | author: Galen Guyer 9 | author-image: https://cdn.galenguyer.com/img/avatars/headshot.jpg 10 | author-email: chef@csh.rit.edu 11 | author-social: 12 | github: https://github.com/galenguyer/ 13 | categories: [docker, rust] 14 | --- 15 | 16 | Check out this post on Galen's blog! 17 | 18 |

Today, a friend posted the following snippet in Slack:

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

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.

22 | 23 |

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.

24 | 25 |

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.

26 | 27 |

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.

28 | 29 |

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.

30 | 31 |

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:

32 | 33 |
getcwd("/usr/local/bin", 512)           = 15
34 | statx(0, NULL, AT_STATX_SYNC_AS_STAT, STATX_ALL, NULL) = -1 EFAULT (Bad address)
35 | statx(AT_FDCWD, "/usr/local/bin/.env", AT_STATX_SYNC_AS_STAT, STATX_ALL, 0x7ffc04639b10) = -1 ENOENT (No such file or directory)
36 | statx(AT_FDCWD, "/usr/local/.env", AT_STATX_SYNC_AS_STAT, STATX_ALL, 0x7ffc04639930) = -1 ENOENT (No such file or directory)
37 | statx(AT_FDCWD, "/usr/.env", AT_STATX_SYNC_AS_STAT, STATX_ALL, 0x7ffc04639750) = -1 ENOENT (No such file or directory)
38 | statx(AT_FDCWD, "/.env", AT_STATX_SYNC_AS_STAT, STATX_ALL, 0x7ffc04639570) = -1 ENOENT (No such file or directory)
39 | write(2, "Error: ", 7Error: )                  = 7
40 | write(2, "NotPresent", 10NotPresent)              = 10
41 | write(2, "\n", 1
42 | )                       = 1
43 | sigaltstack({ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=8192}, NULL) = 0
44 | munmap(0x7fb5000f2000, 8192)            = 0
45 | exit_group(1)                           = ?
46 | +++ exited with 1 +++
47 | 48 |

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!

49 | -------------------------------------------------------------------------------- /_posts/2019-08-26-nickm-intro-letter.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: A Letter to Prospective Members 4 | date: 2019-08-26 21:25:00 5 | categories: intro 6 | description: An explanation of CSH's intro process and the motivations behind it. 7 | author: Nick Mosher 8 | image: /projects/envelope.jpg 9 | image-sm: /projects/envelope.jpg 10 | author-image: https://2.gravatar.com/avatar/82615a3c73fe853714af7b51337a4fac?s=400 11 | author-bio: Software Engineering '20 at RIT and R&D Director at CSH 12 | author-email: nicholastmosher@gmail.com 13 | author-social: 14 | github: https://github.com/nicholastmosher 15 | --- 16 | 17 | Hey there! 18 | 19 | If you’ve made it this far, you’re probably thinking about becoming a member. 20 | That’s great! We need curious and motivated people like you. I want to take a 21 | minute and walk you through our intro process so that you know what to expect; 22 | there’s a handful of steps involved and I want you to have a clear idea of 23 | what you’re getting yourself into. 24 | 25 | The majority of the intro process takes place during the first 10 weeks of 26 | school. The first 2 weeks are what we call “packet season”. Packet season is 27 | all about meeting people - we want CSH to be a tight-knit community, so we 28 | believe that every member should meet every other member. A Packet is a list 29 | of the names of all active CSH members, and one is given to every intro member. 30 | Your job as an incoming CSHer is to seek out and meet as many active members 31 | as you can. This isn’t as easy as hide-and-seek. Once you find an upperclassman, 32 | you have to put in an effort to genuinely get to know them! Ask them about what 33 | their interests are, what projects they’ve done, or how their co-op experiences 34 | have gone. Active members will sign your packet if they think you’d make a good 35 | member of CSH, which is usually the case if you show that you’re passionate and 36 | interested in what you do. After packet season is over, we’ll count up all of 37 | the signatures you’ve collected. If you get a passing percentage of signatures, 38 | congratulations! You’ll receive a CSH account and gain access to all of our 39 | house computer services. If not, there’s still hope! The packet is just one 40 | component of your 10-week evaluation. 41 | 42 | We have a handful of other objectives for you during the 10-week intro process. 43 | These requirements are intended to introduce you to our house culture and 44 | traditions, and are things that active members continue to do throughout their 45 | entire membership. One of the first things we ask you to do is attend some of 46 | our directorship meetings. Each of our 7 directors hosts a weekly meeting where 47 | they discuss ongoing projects, upcoming events, or other news that falls in 48 | their domain. Intro members are expected to attend any 10 directorship meetings 49 | during the 10-week evaluation period, preferably at least one a week. Another 50 | cornerstone of CSH culture is the presentation of technical seminars! Technical 51 | seminars early in the year are usually given by upperclassmen and tend to focus 52 | on introducing you to the world of computer science. Common early-year topics 53 | include setting up basic coding tools, intro to Linux operating systems, 54 | version control for code, and more. Upperclassmen volunteer a lot of time to 55 | prepare seminars, so we ask every intro member to attend at least 2 of them 56 | during their 10 weeks. Plus, this is a special-interest house for computer 57 | science, you probably want to attend as many seminars as you can. 58 | 59 | Our last but most important requirement is for you to attend all of our house 60 | meetings. House meetings happen every Sunday at 7:15pm, and are where the 61 | directors summarize house news and events for the past week and upcoming weeks. 62 | This meeting is required because it’s the one time we have a chance to address 63 | all of house together, and is when we make large decisions as a group. Though 64 | we require you to attend every house meeting, we also understand that life 65 | happens. If you can’t make it because you’re sick or out of town, just let 66 | our Evaluations director know and they’ll write a note about your absence. 67 | 68 | At the end of the 10-week intro process, all of the upperclassmen gather 69 | together to vote on intro members. During this meeting, we look at the big 70 | picture of how well you’ve met the requirements and who you are as a person. 71 | Did you attend at least 10 directorship meetings? Did you get a good score on 72 | packet? Are you a curious and engaged member? Are you friendly and 73 | light-hearted? Remember, we want CSH to be a welcoming and inclusive 74 | community, but we’re also looking for the mad scientist in each of you. 75 | 76 | I hope that this has given you a good idea of what to expect when signing up 77 | for CSH. It’s a crazy ride for sure, but it’s totally worth it. If anything, 78 | I hope I’ve talked you _into_ applying. I look forward to meeting you all when 79 | school starts! 80 | 81 | -@nickm 82 | -------------------------------------------------------------------------------- /membership/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Membership 4 | active: membership 5 | --- 6 | 7 |
8 |
9 |
10 |
11 |

12 | Computer Science House boasts some of the best minds in almost every computer-related field. As a member, you will be meeting people who can help you with your classes, teach you new tricks, and assist you in making the absolute most of your college experience, as well as making professional connections and friendships that will last you your entire life. 13 |

14 |

15 | You don't need to be majoring in Computer Science, Software Engineering, or even anything related. Maybe you're a business major, or perhaps an art student; all we expect is that you have an interest in computers, a willingness to be active on floor, and a desire to excel in all aspects of your life. 16 |

17 |
18 |
19 |
20 |
21 |

Incoming Students

22 |

23 | Even before college, a great way to meet members and learn about CSH is to take a tour during RIT's open houses. 24 | On those days, members lead personalized tours of floor, highlighting our unique facilities, exemplary projects, and social atmosphere. 25 | For open house dates, visit the RIT admissions web site. 26 | If you are unable to attend an open house, email our Evaluations Director to schedule a time that is best for you. 27 | After being accepted to RIT, look for the Special Interest Housing selection in your RIT housing application to apply to CSH. 28 |

29 |

Current Students

30 |

31 | Students already enrolled at RIT can apply to join CSH at any time. The best way to apply is to visit CSH (on the third floor of Fredericka Douglass Sprague Perry Hall) and pick up an application from our Evaluations Director. All majors and years are accepted and members can live on or off floor. 32 |

33 |
34 |
35 | CSHers manning a booth at an RIT Open House 36 |
37 |
38 |
39 |
40 |

Member Expectations

41 |

42 | CSH has a number of requirements for its members, made to both maintain involvement and ensure growth as members and professionals. CSH expects its members to: 43 |

44 |
    45 |
  • Attend weekly committee and House meetings
  • 46 |
  • Attend some of our many social events and technical seminars
  • 47 |
  • Complete a "Major Project" each year to contribute to CSH or enhance one's knowledge
  • 48 | 49 |
50 |

51 | For more information on our introductory process, click here. 52 |

53 |
54 |
55 |
56 |
57 | Two CSHers utilizing tools in our Project Room wood shop 58 |
59 |
60 |

Member Benefits

61 |

62 | CSH's perks more than make up for all the work that goes into membership. All members, both on-floor and off-floor, get the following benefits: 63 |

64 |
    65 |
  • Access to all of CSH's facilities (i.e. the Project room) and resources (i.e. web hosting and email)
  • 66 |
  • Ability to request funds for technical projects, social events, and more
  • 67 |
  • Voting privileges at all committee and House meetings to approve funds, accept new members, and have a say in how CSH is run
  • 68 |
  • Knowledge and advice from some of the brightest minds in computing and related fields
  • 69 |
  • Networking, storytelling, and donations from alumni in the industry
  • 70 |
  • Professional and personal connections that last a lifetime
  • 71 |
72 |
73 |
74 |
75 |
76 | -------------------------------------------------------------------------------- /_posts/2018-02-28-smart-window-shades.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Smart Window Shades 4 | date: 2018-03-01 00:00:00 5 | categories: projects 6 | description: A web service that allows one to control their window shades using a website 7 | author: Ayush Goel 8 | author-image: https://avatars2.githubusercontent.com/u/10407155?s=460&v=4 9 | author-bio: First Year Computer Science Student at Rochester Institute of Technology 10 | author-email: axg4975@rit.edu 11 | author-social: 12 | github: https://github.com/ag-ayush 13 | linkedin: https://www.linkedin.com/in/ayush-goel-589ba215a/ 14 | --- 15 | # Summary 16 | Smart shades is a web service that allows one to control their window shades using a website. 17 | 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. 18 | The application uses Python, Flask, OpenShift in the back end, Bootstrap, JavaScript, and Ajax. 19 | In short, there are two Flask apps running, one on [a CSH domain](https://shades.csh.rit.edu) and one on the Pi. 20 | 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. 21 | 22 | # The Story 23 | I picked up this IOT project from R&D. 24 | 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. 25 | I had some ideas for ImagineRIT, but this one seemed more fun than the rest of them. 26 | 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. 27 | I started the project by figuring out how to use RPi.GPIO library by making a simple program with LEDs. 28 | Then I started using the stepper motor driver and the stepper motor. 29 | This ended up being a hardware problem, not a software one. 30 | 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. 31 | From there I had to figure out how stepper motors work in software, which comparatively was not that difficult. 32 | 33 | The next part of this project was controlling the motor from a website. 34 | I started by reading about **Flask** and making a quick Hello world application on the IP on the Pi. 35 | Since Flask uses python, and so does my code for the shades, I was simply able to combine the two. 36 | I learned about **HTML** and **bootstrap** while creating the index page for this application. 37 | 38 | 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. 39 | Thankfully, our OpComm director, Steven, helped me out during the OpCommathon by showing me OpenShift. 40 | As soon as I ran it up, it crashed. 41 | 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. 42 | This, however, was not ideal because every time you changed the height of the shade, the page would reload. 43 | That is neither pretty nor efficient. 44 | 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. 45 | I asked around, and upon the suggestion of our financial director, Devin, I decided to implement **Ajax**. 46 | 47 | I had never used JavaScript, nor Ajax prior to this, so it was a bit of learning curve. 48 | 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. 49 | Then came other obstacles, such as not being able to POST to Pi because it ran on HTTP and the website ran on HTTPS. 50 | Somewhere in there I had to implement CORS or Cross-Origin Resource Sharing, lack of it crashes the program. 51 | 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. 52 | 53 | I proceeded to add some more functionality to this application after OpCommathon. 54 | This took a couple day's worth of work because I was still learning JavaScript. 55 | 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. 56 | Furthermore, it shows the current shade percentage. 57 | 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. 58 | The best part is that the page does not reload upon calling a function, the two apps simply talk to each other. 59 | 60 | Altogether, this project was a lot of fun. 61 | I learned quite a bit, both in the software world and hardware world. 62 | 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. 63 | 64 | P.S. For details on wiring components, please visit the GitHub source of this project [here](https://github.com/ag-ayush/smart-window-shades). 65 | -------------------------------------------------------------------------------- /membership/traditions.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Traditions 4 | active: membership-traditions 5 | --- 6 | 7 |
8 |
9 |
10 |
11 |

12 | CSH isn’t just about working on projects. Our members love to engage 13 | in a variety of social activities. Many of these activities have 14 | persisted through the years to become traditions. 15 |

16 |
17 |
18 |
19 |
20 | CSHers hanging out at Welcome Back 21 |
22 |
23 |

Welcome Back

24 |

25 | Welcome Back is a barbecue held at the beginning of each year to 26 | welcome the incoming freshman class. Traditionally, alumni come from 27 | far and wide to visit current floor members. We cook way too much 28 | food, tell stories, and participate in a variety of outdoor 29 | activities. 30 |

31 |
32 |
33 |
34 |
35 | An aerial shot of the cabin we camp at for Fall Camping 36 |
37 |
38 |

Camping

39 |

40 | Every year, CSH goes out on an adventure to see if we can survive for 41 | a weekend in the wild. Surprisingly, a bunch of computer nerds can 42 | thrive without electricity for a few days. 43 |

44 |
45 |
46 | 64 |
65 |
66 | A group of CSHers dressed formally for Holiday Dinner 67 |
68 |
69 |

Holiday Dinner

70 |

71 | Holiday Dinner is our annual formal dinner that takes place right 72 | before Winter Break. All of CSH gets dressed up and has dinner at a 73 | classy restaurant. 74 |

75 |
76 |
77 |
78 |
79 | CSHers in our User Center watching a member give a seminar 80 |
81 |
82 |

Seminars

83 |

84 | Any member can hold a seminar to teach others a bit about a topic of 85 | their choosing. Subjects can range from programming to juggling and 86 | everything in between, and anyone can give one at any time. 87 |

88 |
89 |
90 |
91 |
92 | A CSHer playing intramural Broomball 93 |
94 |
95 |

Intramural Sports

96 |

97 | We participate in most of the intramural sports RIT offers, including 98 | broomball, hockey, soccer, basketball, softball, dodgeball, and volleyball. While 99 | we aren’t always the best team out there, we’re always the 100 | best-looking (with our CSH jerseys) and have the most fans cheering us 101 | on! We’ve even won quite an impressive number of trophies in the past, 102 | which are proudly displayed in our library. 103 |

104 |
105 |
106 |
107 |
108 | -------------------------------------------------------------------------------- /_posts/2018-04-08-game-night.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Game Night 4 | date: 2018-04-08 5 | categories: projects 6 | description: A Board and Card Games Database 7 | author: Michael Francis 8 | author-image: https://avatars0.githubusercontent.com/u/4574480?s=460&v=4 9 | author-bio: First Year Computer Science Masters Student at Rochester Institute of Technology 10 | author-email: maf1144@rit.edu 11 | image: /projects/game-night.png 12 | image-sm: /projects/game-night.png 13 | author-social: 14 | github: https://github.com/mfrancis95 15 | linkedin: https://www.linkedin.com/in/mfrancis95/ 16 | --- 17 | 18 | ## Background 19 | 20 | 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. 21 | 22 | ## Introducing Game Night 23 | 24 | I created a fully searchable database of our available games called **[Game Night](https://game-night.csh.rit.edu)**. 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. 25 | 26 | 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. 27 | 28 | 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. 29 | 30 | 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. 31 | 32 | ## The RESTful API 33 | 34 | 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](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](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](https://game-night.csh.rit.edu/api/random)** and is filterable in the same way. 35 | 36 | ## The Technology Stack 37 | 38 | 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: 39 | 40 | 1. It was an opportunity to learn something new. 41 | 2. 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. 42 | 3. 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. 43 | 44 | Like many other CSH services, **Game Night** is behind OIDC authentication. 45 | 46 | ## Future Plans 47 | 48 | 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: 49 | 50 | 1. A way for users to upload games to the database through the web interface. Currently, only I can upload games. 51 | 2. 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. 52 | 3. 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. 53 | 54 | Any changes made will be pushed to the project's **[GitHub repository](https://github.com/mfrancis95/game-night)**. 55 | 56 | ## Special Thanks 57 | 58 | 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. -------------------------------------------------------------------------------- /_posts/2018-03-28-benchmarking-programing-languages.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Benchmarking Programing Languages 4 | date: 2018-03-28 5 | categories: projects 6 | description: Testing the speed of separating axis theorem based collision detection in Python, Rust, and Kotlin 7 | author: Joel Eager 8 | image: /projects/benchmarking.png 9 | image-sm: /projects/benchmarking.png 10 | author-image: https://avatars1.githubusercontent.com/u/14286106?s=460&v=4 11 | author-bio: A 3rd year CS student at Computer Science House who enjoys messing with Python. 12 | author-email: joel@csh.rit.edu 13 | author-social: 14 | github: https://github.com/JoelEager 15 | --- 16 | 17 | Computers do math quite fast, but how fast? Well, the answer to that question changes quite significantly depending on 18 | the programming language being used. 19 | 20 | To explore this relationship I implemented a common collision detection algorithm called [separating axis theorem](https://gamedevelopment.tutsplus.com/tutorials/collision-detection-using-the-separating-axis-theorem--gamedev-169) 21 | in Python, Rust, and Kotlin. This algorithm uses linear algebra to check if two convex 2D polygons are overlapping. 22 | Since this is a linear algebra algorithm most of the work is repetitive arithmetic. This makes it a relatively good 23 | test of raw execution speed. 24 | 25 | Even before running the code I can expect [Python](https://en.wikipedia.org/wiki/Python_(programming_language)) to be 26 | the slowest since it's the only interpreted language being tested. [Rust](https://en.wikipedia.org/wiki/Rust_(programming_language)), 27 | on the other hand, is compiled down to machine code so it should be significantly faster. [Kotlin](https://en.wikipedia.org/wiki/Kotlin_(programming_language)) 28 | should be somewhere in the middle since it's compiled but runs in the Java Virtual Machine instead of directly on the 29 | hardware. 30 | 31 | The metric I'll be measuring here is the wall-clock execution time. Note that this approach has an inherent amount of 32 | inaccuracy due to how operating systems handle process scheduling. However, it's also the metric that's most immediately 33 | understandable and comparable so it works well for this situation. 34 | 35 | The actual program that I'm using takes two objects and sets their center points 100 pixels away from each other. Then 36 | one object is moved towards the other in steps of 1 pixel at a time until the algorithm detects collision. This process 37 | is then repeated 10,000 times in order to build up a sufficiently long execution time to get an accurate comparision. 38 | 39 | Here are the results from running this test. Note how Kotlin and Rust have fairly similar results even though Kotlin 40 | runs in the JVM. 41 | 42 | | CPU used for the test | Time for Python | Time for Kotlin | Time for Rust | 43 | | --------------------- | --------------- | --------------- | ------------- | 44 | | Intel Core i7-8550U | 21.800 seconds | 0.308 seconds | 0.230 seconds | 45 | | AMD A10-6800K | 40.617 seconds | 0.767 seconds | 0.465 seconds | 46 | 47 | Now this is a pretty naive implementation. The two objects are 10 and 1 pixels across respectively so it takes a lot of 48 | iterations before they collide. This algorithm takes the most time to run when the objects aren't touching so it would 49 | be quite helpful if there was a way to skip over at least some of the iterations where they aren't touching. 50 | 51 | It turns out that it's trivial to calculate a rough estimate of the distance between the two objects by taking one point 52 | from each and applying the Pythagorean theorem. Now, this would be a very rough estimate since it doesn't take into 53 | account the rotation or shape of the objects in question. However, if that rough separation estimate is greater than the 54 | combined width of the two objects at their widest points then it can be assumed that the objects aren't touching. In 55 | all other cases the program would still have to run the collision detection algorithm as before to get an accurate 56 | result. 57 | 58 | With this optimization in play the execution times drop significantly. Note that due to the the inherent inaccuracy of 59 | the timing method used, the results for Rust on the two computers should be interpreted as roughly equal. 60 | 61 | | CPU used for the test | Time for Python | Time for Kotlin | Time for Rust | 62 | | --------------------- | --------------- | --------------- | ------------- | 63 | | Intel Core i7-8550U | 8.250 seconds | 0.145 seconds | 0.033 seconds | 64 | | AMD A10-6800K | 15.844 seconds | 0.346 seconds | 0.027 seconds | 65 | 66 | Even though Python is quite slow in comparison to Kotlin and Rust, it turns out that it's still easily fast enough to 67 | 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](https://github.com/JoelEager/pyTanks.Server) 68 | project to check for collisions between the game objects. This just goes to show the trade off that exists with 69 | interpreted languages. While they may be more convenient to work with you're paying the price for that convenience in 70 | the execution speed. 71 | 72 | If you're interested in playing with these programs yourself you can find the Rust version [here](https://github.com/JoelEager/Rust-Collision-Detector) 73 | and the Kotlin version [here](https://github.com/JoelEager/Kotlin-Collision-Detector). The Python code is part of the 74 | server portion of my pyTanks project [here](https://github.com/JoelEager/pyTanks.Server). Specifically, the Python 75 | script that implements the algorithm is located [here](https://github.com/JoelEager/pyTanks.Server/blob/master/gameLogic/collisionDetector.py) 76 | 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 77 | of your own projects you're more than welcome to. 78 | -------------------------------------------------------------------------------- /_posts/2018-04-10-clades-cimicum.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Clādēs Cimicum 4 | date: 2018-04-10 5 | categories: 6 | - debugger,c 7 | description: A small debugger that can read memory from another process. 8 | author: Collin Tod 9 | image: /projects/cDebugger.png 10 | image-sm: /projects/cDebugger.png 11 | author-image: https://avatars2.githubusercontent.com/u/9722413?s=400&u=58f02226ffe89fa4f69ad4a7f89f07efb1b72f4f&v=4 12 | author-bio: First year computer science student at Rochester Institute of Technology 13 | author-email: squables@csh.rit.edu 14 | author-social: 15 | github: https://github.com/squablyScientist 16 | --- 17 | # What Is It? 18 | 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. 19 | 20 | # Why I Wrote It 21 | A while back, I found [this](https://github.com/scvalencia/MNIST_ASCII_challenge) 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: 22 | 23 | 1. Using ptrace to attach to the process and read its memory (This is what GDB does to a child proces) 24 | 2. Manually stopping the process and reading from its mem file in `/proc` 25 | 26 | I chose the latter of the two options because I wanted a bit of a challenge. 27 | 28 | # How To Use It 29 | Program usage 30 | 31 | ```sh 32 | debugger PID offset nbytes 33 | ``` 34 | 35 | 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 36 | 37 | # How It Works 38 | 39 | 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. 40 | 41 | 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`. 42 | 43 | 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. 44 | 45 | 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.](https://en.wikipedia.org/wiki/Race_condition). 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. 46 | 47 | 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. 48 | 49 | 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. 50 | 51 | # How I Solved the Captcha Problem 52 | 53 | 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. 54 | 55 | # What I Learned 56 | 57 | Pretty much everything that I know about the `/proc` folder, and how stack frames work. 58 | 59 | # The Project 60 | The project is hosted [here](https://github.com/squablyScientist/Clades-Cimicum). The `master` branch is the general debugger, whilst the `injection` branch is the solution for the captcha challenge. 61 | -------------------------------------------------------------------------------- /membership/intro-process.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: New Members 4 | active: membership-intro 5 | --- 6 | 7 |
8 |
9 |
10 |
11 |

Applying to CSH

12 |

13 | Incoming Freshman can apply through their RIT Housing Application, when asked about Special Interest Houses. 14 | Current students can either visit us on the 3rd floor of Fredericka Douglass Sprague Perry Hall, or submit a 15 | completed application to our Evaluations Director 16 | by emailing the filled out document to evals@csh.rit.edu 17 |

18 | 19 |

Note that RIT Housing caps us at 50 acceptances every summer, so if you weren't accepted at first, feel free to re-apply at any time! 20 | Applications are reviewed during the first week of each semester.

21 |
22 |
23 |

Introductory Process

24 |

25 | Once accepted to Computer Science House after the application stage, you are considered an introductory member. 26 | This means that you're invited to all our events, involved in our process, and considered to be a member in almost all cases. 27 |

28 |

29 | However, in order to become a full voting member, you need to complete our 6-week introductory process. 30 | The process should take no more than a few hours each week to complete. 31 | Our introductory process is defined in our Constitution and outlines completion of a few requirements: 32 |

33 |
34 |
35 |

Directorship Meetings

36 |

37 | You must attend an average of 1 directorship meeting for each week of the introductory process. 38 | This means that you must attend 6 directorship meetings before the end of the 6 week introductory period. 39 | There are between 7 and 10 directorship meetings occuring every week, each lasting about half an hour. 40 | During one, an Executive Board member conveys to house what they've done in their role recently and what they plan to do in the coming weeks. 41 |

42 |
43 |
44 |

Packet

45 |

46 | In order to keep CSH a tight-knit community, we want every member to meet and get to know every other member. 47 | In order to do this, we give each intro member a Packet — a list of all on-floor members and upperclassmen. 48 | Your job as an intro member is to seek out and meet as many of the upperclassmen as you can, and in return, they’ll sign your packet. 49 | The packet process takes place during the first two weeks of the semester, after which we’ll count all of the signatures that you’ve collected. 50 | 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. 51 | If not, there’s still hope! There is still more time in the intro process for you to continue meeting people, coming to events, and learning at seminars. 52 |

53 |
54 |
55 |

House Meetings

56 |

57 | There is a house meeting every Sunday at 7:15pm. 58 | You are required to attend all of them, as is every active upperclassman. 59 | During these, we go over upcoming and recent events, vote to spend money on member projects, and discuss changes to our Constitution. 60 |

61 |
62 |
63 |

Technical Seminars

64 |

65 | Over the 6 week introductory process, you must attend at least 2 technical seminars. 66 | These seminars are hosted on floor and go over a range of topics from Git and Python to more complex concepts like OpenGL or OpenShift. 67 |

68 |
69 |
70 |

Social Events

71 |

72 | All members are expected to attend some social events. 73 | Including camping trips, video game tournaments, movie nights, and much more, just participate in events on floor. 74 |

75 |
76 |
77 |

Evaluations

78 |

79 | At the 6-week mark, all of the upperclassmen meet and make a decision based on how well you’ve met the intro requirements. 80 | Members keep in mind your other responsibilities, such as other club meetings or classes, so don't worry if you're just shy of a requirement. 81 | If you’re voted in at this meeting, you become a full member! 82 |

83 |
84 |
85 |

Questions or concerns? Reach out to our Evaluations Director

86 |
87 |
88 |
89 |
90 | -------------------------------------------------------------------------------- /about/projects.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Projects 4 | active: about-projects 5 | --- 6 | 7 |
8 |
9 |
10 |
11 |

12 | Projects are an integral part of the living, learning experience at 13 | Computer Science House. This is a small sample of notable projects 14 | that our members have created: 15 |

16 |
17 |
18 |
19 |
20 | 21 | 22 | 23 | Two of CSH's networked vending machines, Drink and Snack. 24 | 25 |
26 |
27 |

Drink/Snack

28 |

29 | Drink and Snack are two of CSH's oldest projects. Networked vending 30 | machines allow members to order items from any internet browser using 31 | a credits system. A timer can also be specified to delay the release 32 | of a purchased item. 33 |

34 |
35 |
36 |
37 |
38 | 39 | 40 | 41 | The logo for CSH Schedule Maker 42 | 43 |
44 |
45 |

Schedule Maker

46 |

47 | Schedule Maker allows RIT students to plan their schedule for upcoming 48 | semesters. Users simply enter their course numbers and custom events 49 | and a list of all schedules that match their parameters will be shown. 50 | Because it is so easy and simple, Schedule Maker is now used by over 51 | 90% of RIT students. 52 |

53 |
54 |
55 | 56 |
57 |
58 | 59 | 60 | 61 | CSH's custom built arcade cabinet, Devcade. 62 | 63 |
64 |
65 |

Devcade

66 |

67 | Devcade is a fully custom arcade machine made by a team of over a dozen CSH members. 68 | Devcade is an arcade built for developers, by developers. The arcade cabinet, software, 69 | and games for Devcade were mainly built during the Fall 2022 semester and the project 70 | is still being maintained and updated. 71 |

72 |
73 |
74 | 75 |
76 |
77 | 78 | 79 | 80 | Harold, a box with a sensor on it, that plays members' music 81 | 82 |
83 |
84 |

Harold

85 |

86 | With Harold, every member of CSH gets their own theme song. After 87 | a user uploads either their song or playlist to a web app, all they 88 | have to do is touch their iButton or RFID tag (received upon 89 | membership) to the appropriate reader. 90 |

91 |
92 |
93 |
94 |
95 | 96 | 97 | 98 | Two custom arcade machines in the CSH library 99 | 100 |
101 |
102 |

CSH Arcade

103 |

104 | Two CSH members built this arcade cabinet from scratch. It emulates 105 | many classic arcade games from varying consoles and supports 106 | multiplayer. A second cabinet featuring a custom-made platforming game 107 | was also built. Both machines, along with other arcade cabinets CSH 108 | has acquired, are housed in our Library. 109 |

110 |
111 |
112 |
113 |
114 | 115 | 116 | 117 | An automated display in our User Center displaying the weather, high scores, and more 118 | 119 |
120 |
121 |

InfoSys

122 |

123 | InfoSys is a multi-purpose display board located in our User Center. 124 | It is capable of displaying weather statistics, custom messages, and 125 | even real-time player data from video games. 126 |

127 |
128 |
129 |
130 |
131 | -------------------------------------------------------------------------------- /_posts/2018-02-26-freeipa.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Deploying FreeIPA 4 | date: 2018-02-26 21:25:00 5 | categories: projects 6 | description: Migrating from custom LDAP/Kerberos setup to Red Hat's identity management platform. 7 | image: /projects/FreeIPA.png 8 | image-sm: /projects/FreeIPA.png 9 | author: Marc Billow 10 | author-image: https://2.gravatar.com/avatar/254e59006e0d907f97c529c62689c0e0?s=400 11 | author-bio: Networking and System Administration '18 at the Rochester Institute of Technology and System Administrator for Computer Science House 12 | author-email: mbillow@csh.rit.edu 13 | author-social: 14 | github: https://github.com/mbillow 15 | --- 16 | 17 | 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](https://www.freeipa.org/page/Demo) available. 18 | 19 | ## Our Situation 20 | 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. 21 | 22 | 23 | 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. 24 | 25 | 26 | 27 | ## Handling Custom Attributes 28 | 29 | 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. 30 | 31 | 32 | 33 | ### Extending the Schema 34 | 35 | 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. 36 | 37 | 38 | 39 | 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: 40 | 41 | 42 | 43 | ``` 44 | 45 | dn: cn=schema 46 | 47 | 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 ) 48 | 49 | 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 ) 50 | 51 | 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 ) 52 | 53 | 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 ) 54 | 55 | 56 | 57 | dn: cn=schema 58 | 59 | objectClasses: ( 1.3.6.1.4.1.3319.8.500 NAME 'ritStudent' AUXILIARY MAY ( ritDn $ major $ minor $ ritYear ) ) 60 | 61 | ``` 62 | 63 | 64 | 65 | ### Extending the UI/API 66 | 67 | 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. 68 | 69 | 70 | 71 | 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: 72 | 73 | 74 | 75 | ``` 76 | from ipalib.plugins import user 77 | from ipalib.parameters import Str 78 | from ipalib import _ 79 | 80 | user.user.takes_params = user.user.takes_params + ( 81 | Str('ritdn?', 82 | cli_name = 'ritdn', 83 | label = _('RIT Account'), 84 | ), 85 | Str('major*', 86 | cli_name = 'major', 87 | label = _('RIT Major'), 88 | ), 89 | Str('minor*', 90 | cli_name = 'minor', 91 | label = _('RIT Minor'), 92 | ), 93 | Str('rityear?', 94 | cli_name = 'rityear', 95 | label = _('RIT Year'), 96 | ), 97 | ) 98 | ``` 99 | 100 | 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` 101 | 102 | 103 | 104 | ``` 105 | define([ 106 | 'freeipa/phases', 107 | 'freeipa/user' 108 | ], 109 | function(phases, user_mod) { 110 | // helper function 111 | function get_item(array, attr, value) { 112 | for (var i = 0, l = array.length; i < l; i++) { 113 | if (array[i][attr] === value) return array[i]; 114 | } 115 | return null; 116 | } 117 | var student_plugin = {}; 118 | student_plugin.add_student_pre_op = function() { 119 | var facet = get_item(user_mod.entity_spec.facets, '$type', 'details'); 120 | var section = get_item(facet.sections, 'name', 'identity'); 121 | 122 | section.fields.push({ 123 | name: 'ritdn', 124 | label: 'RIT Account' 125 | }); 126 | 127 | section.fields.push({ 128 | name: 'major', 129 | label: 'RIT Major', 130 | $type: 'multivalued' 131 | }); 132 | 133 | section.fields.push({ 134 | name: 'minor', 135 | label: 'RIT Minor', 136 | $type: 'multivalued' 137 | }); 138 | 139 | section.fields.push({ 140 | name: 'rityear', 141 | label: 'RIT Year' 142 | }); 143 | 144 | return true; 145 | 146 | }; 147 | phases.on('customization', student_plugin.add_student_pre_op); 148 | return student_plugin; 149 | }); 150 | ``` 151 | 152 | 153 | 154 | 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. 155 | 156 | 157 | 158 | ## FreeRADIUS and Wireless 159 | 160 | 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. 161 | 162 | 163 | 164 | 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. 165 | 166 | 167 | 168 | ## Deployment 169 | 170 | 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](https://forge.puppet.com/joshuabaird/ipaclient) puppet module. This allows for the rapid bootstrapping of a new server with a single Puppet run. 171 | -------------------------------------------------------------------------------- /about/eboard.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Executive Board 4 | active: about-eboard 5 | --- 6 | 7 |
8 |
9 |
10 |
11 |

12 | The executive board is responsible for ensuring the functions integral to the CSH experience go off 13 | as smoothly as possible. 14 | Elected at the end of every academic year, they volunteer their time to help make floor an even 15 | better place to be. 16 |

17 |
18 |
19 |
20 |
21 |
22 | CSH Chairperson 23 | CSH Chairperson 24 |
25 |
26 |
27 |

Chair

28 |

Isaac Ingram

29 |

30 | The Chair of CSH serves as the head of E-Board, supervising the activities of the directors and 31 | presiding over our weekly house meetings. 32 | They are also the primary spokesperson for the House, representing the interests of our 33 | members in communications with RIT and the rest of the world. 34 |

35 |
36 |
37 |
38 |
39 |
40 | CSH Evaluations Director 41 | CSH Evaluations Director 42 |
43 |
44 |
45 |

Evaluations

46 |

Ian Kopke

47 |

48 | Evaluations is responsible for connecting with the RIT student community, as well as 49 | organizing the process of screening, accepting, and welcoming new members. 50 | Members wouldn't be here without evals! 51 |

52 |

53 | If you would like to visit or tour the floor, let the Eval Director know and 54 | they can arrange this. 55 |

56 |
57 |
58 |
59 |
60 |
61 | CSH Financial Director 62 | CSH Financial Director 63 |
64 |
65 |
66 |

Financial

67 |

Matthew Wilkins

68 |

69 | Financial is responsible for managing CSH's finances, collecting semesterly member 70 | dues, and hatching new fundraising schemes. 71 | All of our money goes towards new resources and project components for members to use; CSH is a 72 | registered non-profit organization with an annual self-generated budget. 73 |

74 |
75 |
76 |
77 |
78 |
79 | CSH History Director 80 | CSH History Director 81 |
82 |
83 |
84 |

House History

85 |

Logan Endes

86 |

87 | The primary responsibility of the History director is keeping the line of communication between CSH 88 | and our alumni open. 89 | We believe members should have a well-developed understanding of House's origins and 90 | accomplishments. 91 | History keeps the past alive through the yearbook, Coredump newsletter, floor displays, archiving, 92 | updating the media database, and managing alumni relations. 93 | History also coordinates alumni storytelling nights and other traditional events. 94 |

95 |
96 |
97 |
98 |
99 |
100 | CSH House Improvements Director 101 | CSH House Improvements Director 102 |
103 |
104 |
105 |

House Improvements

106 |

Shaela Spring

107 |

108 | House Improvements is responsible for keeping our living space respectable and 109 | comfortable. 110 | They delegate projects that improve the physical aspects of floor, such as painting, 111 | cleaning, building, and organizing House's resources. 112 | While we may not be the tidiest group of people, we like to take care of our floor, and it shows. 113 |

114 |
115 |
116 |
117 |
118 |
119 | CSH OpComm Director 120 | CSH OpComm Director 121 |
122 |
123 |
124 |

OpComm

125 |

Tyler Allen

126 |

127 | The OpComm director, together with a group of technically skilled members known as RTPs, is 128 | responsible for maintaining CSH's servers and network infrastructure. 129 | Becoming an RTP allows members to develop and practice skills that are essential for working in 130 | computing fields. 131 | If you have any questions about House's technical resources, the OpComm director should be your 132 | first stop! 133 |

134 |
135 |
136 |
137 |
138 |
139 | CSH Reserach and Development Director 140 | CSH Research and Development Director 141 |
142 |
143 |
144 |

Research and Development

145 |

Cole Stowell & Will Hellinger

146 |

147 | R&D is responsible for organizing seminars and assisting with technical projects, with the goal of 148 | encouraging members to learn new skills and gain experience. 149 |

150 |
151 |
152 |
153 |
154 |
155 | CSH Social Director 156 | CSH Social Director 157 |
158 |
159 |
160 |

Social

161 |

Grant Hawerlander & Conner Meagher

162 |

163 | Social is responsible for planning and running social events for our members, such as 164 | Welcome Back, movie nights, and other events on floor and around Rochester. 165 |

166 |
167 |
168 |
169 |
170 |
171 | CSH Public Relations Director 172 | CSH Public Relations Director 173 |
174 |
175 |
176 |

Public Relations

177 |

Ava McCaffrey

178 |

179 | Public Relations is responsible for maintaining CSH's public facing image, primarily 180 | through the management of our various social media accounts. 181 | They work to share all information regarding the organization, and the goings-on therein, 182 | as well as contacting various outside parties, including but not limited to employers, students, and 183 | media outlets to share what we're up to! Follow us on: 184 | Twitter, 185 | Instagram, and 186 | Facebook. 187 |

188 |
189 |
190 |
191 |
192 | -------------------------------------------------------------------------------- /about/sponsors.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Sponsors 4 | active: about-sponsors 5 | --- 6 | 7 |
8 |
9 |
10 |
11 |

12 | Computer Science House has been fortunate enough to have a myriad of very generous sponsors. Without their support it would be impossible to learn, grow, and innovate as we do. 13 |

14 |
15 |
16 |
17 |
18 | 19 | RIT 20 | 21 |
22 |
23 | 24 | Symantec 25 | 26 |
27 |
28 | 29 | ATT 30 | 31 |
32 |
33 | 34 | Datto 35 | 36 |
37 |
38 | 39 | Slack 40 | 41 |
42 |
43 | 44 | University of Rochester 45 | 46 |
47 |
48 | 49 | LinkedIn 50 | 51 |
52 |
53 | 54 | Microsoft 55 | 56 |
57 |
58 | 59 | Cisco 60 | 61 |
62 |
63 | 64 | Google 65 | 66 |
67 |
68 | 69 | HP 70 | 71 |
72 |
73 | 74 | Johnson and Johnson 75 | 76 |
77 |
78 | 79 | Lourdes Industrial 80 | 81 |
82 |
83 | 84 | Moore Research Center 85 | 86 |
87 |
88 | 89 | Intergraph 90 | 91 |
92 |
93 | 94 | Jane Street 95 | 96 |
97 |
98 | 99 | Northrop Grumman 100 | 101 |
102 |
103 | 104 | Sonus 105 | 106 |
107 |
108 | 109 | Oracle 110 | 111 |
112 |
113 | 114 | Perforce 115 | 116 |
117 |
118 | 119 | Cadence 120 | 121 |
122 |
123 | 124 | Podi 125 | 126 |
127 |
128 | 129 | Dupont 130 | 131 |
132 |
133 | 134 | Amdex 135 | 136 |
137 |
138 | 139 | Texas Instruments 140 | 141 |
142 |
143 | 144 | Xerox 145 | 146 |
147 |
148 | 149 | Citrix 150 | 151 |
152 |
153 | 154 | FXCM 155 | 156 |
157 |
158 | 159 | PDHI 160 | 161 |
162 |
163 | 164 | DataDog 165 | 166 |
167 |
168 | 169 | Dmarcian 170 | 171 |
172 |
173 | 174 | Pritunl 175 | 176 |
177 |
178 | 179 | Sentry 180 | 181 |
182 |
183 | 184 | Proxmox 185 | 186 |
187 |
188 | 189 | Tenable 190 | 191 |
192 |
193 | 194 | Wayfair 195 | 196 |
197 |
198 | 199 | Johonnot 200 | 201 |
202 | 203 |
204 |
205 |
206 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | active: home 4 | --- 5 | 6 |
7 | 8 | 16 |
17 | 18 |
19 |
20 | 21 | 22 | 23 | A group of CSHers standing in front of a lake 24 | 25 |
26 |
27 | 28 | 29 | 30 | A CSH member stands at a terminal in the CSH server room 31 | 32 |
33 |
34 | 35 | 36 | 37 | CSHers crowd around a rock painted red with a CSH logo on it in white 38 | 39 |
40 |
41 | 42 | 43 | 44 | A sign that reads Science House with CSHers in the background. Taken at Fall Camping 2019 45 | 46 |
47 |
48 | 49 | 50 | 51 | CSHers pose for a group photo after Holiday Dinner 2019 52 | 53 |
54 |
55 | 56 | 57 | 58 | A group of CSHers at Fall Camping 2019 59 | 60 |
61 |
62 | 63 | 64 | 65 | a man looks through a microscope to solder with a large screen on the left showing the circuit board being soldered 66 | 67 |
68 |
69 | 70 |

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

71 | 72 | 73 |
74 |
75 | 85 | 86 | 96 | 97 | 107 |
108 |
109 | 110 |
111 |
112 |
113 |
114 | 115 | 116 | 117 | A group of CSHers at our annual camping trip 118 | 119 |
120 |
121 |

Since 1976, Computer Science House has provided a revolutionary living and learning environment for its members. With unique facilities, an emphasis on hands-on learning, and a strong social atmosphere, CSH helps its members grow as professionals and more.

122 | More about CSH 123 |
124 |
125 |
126 |
127 | 128 |

Things we're working on ...

129 |
130 |
131 | 132 |
133 | A picture of CSH's server racks 134 |
135 |

Server room upgrade

136 |

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

137 | 138 |
139 | 140 |
141 |
142 |
143 | TUNES, an old jukebox that's being made digital 144 |
145 |

TUNES

146 |

Modernizing a jukebox

147 |
148 | 149 |
150 |
151 |
152 | A LED matrix that makes up CSH's Infosys 153 |
154 |

Infosys

155 |

An information display system

156 |
157 |
158 |
159 |
160 | A raspberry pi and pencil sharpener on the wall, CSH's letmein system 161 |
162 |

Letmein

163 |

A physical notification system for members

164 |
165 |
166 |
167 | 168 |
169 |

Some facts about us ...

170 |
171 | 172 |
173 |
174 |

91

175 |

Active Members

176 |

Who make up the heart of our community.

177 |
178 |
179 |

3rd

180 |

Greatest Hack

181 |

Of all time (as ranked by PCMAG in 2008) was the creation of CSH's internet-connected drink machines.

182 |
183 |
184 |

1388

185 |

Alumni

186 |

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

187 |
188 |
189 |

38

190 |

Rooms on-floor

191 |

In RIT's Fredericka Douglass Sprague Perry Hall, a hub of campus life.

192 |
193 |
194 |

9

195 |

Special-purpose rooms

196 |

That provide members with spaces to work on projects, hang out, or study.

197 |
198 |
199 |
200 |
201 | 202 |
203 |
204 |
205 | 210 | 215 | 220 | 225 | 230 | 235 | 240 |
241 |
242 |
243 | --------------------------------------------------------------------------------