├── .env ├── .gitignore ├── .rspec ├── .ruby-version ├── .travis.yml ├── Bowerfile ├── Brewfile ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── Procfile ├── README.md ├── Rakefile ├── Vagrantfile ├── ansible.cfg ├── app ├── assets │ ├── config │ │ └── manifest.js │ ├── fonts │ │ ├── Dosis │ │ │ ├── Dosis-Bold.ttf │ │ │ ├── Dosis-ExtraBold.ttf │ │ │ ├── Dosis-ExtraLight.ttf │ │ │ ├── Dosis-Light.ttf │ │ │ ├── Dosis-Medium.ttf │ │ │ ├── Dosis-Regular.ttf │ │ │ ├── Dosis-SemiBold.ttf │ │ │ └── OFL.txt │ │ ├── SourceCodePro │ │ │ ├── OFL.txt │ │ │ ├── SourceCodePro-Black.otf │ │ │ ├── SourceCodePro-Black.ttf │ │ │ ├── SourceCodePro-Bold.otf │ │ │ ├── SourceCodePro-Bold.ttf │ │ │ ├── SourceCodePro-ExtraLight.otf │ │ │ ├── SourceCodePro-ExtraLight.ttf │ │ │ ├── SourceCodePro-Light.otf │ │ │ ├── SourceCodePro-Light.ttf │ │ │ ├── SourceCodePro-Medium.otf │ │ │ ├── SourceCodePro-Medium.ttf │ │ │ ├── SourceCodePro-Regular.otf │ │ │ ├── SourceCodePro-Regular.ttf │ │ │ ├── SourceCodePro-Semibold.otf │ │ │ └── SourceCodePro-Semibold.ttf │ │ ├── SourceSansPro │ │ │ ├── OFL.txt │ │ │ ├── SourceSansPro-Black.otf │ │ │ ├── SourceSansPro-Black.ttf │ │ │ ├── SourceSansPro-BlackIt.otf │ │ │ ├── SourceSansPro-BlackIt.ttf │ │ │ ├── SourceSansPro-Bold.otf │ │ │ ├── SourceSansPro-Bold.ttf │ │ │ ├── SourceSansPro-BoldIt.otf │ │ │ ├── SourceSansPro-BoldIt.ttf │ │ │ ├── SourceSansPro-ExtraLight.otf │ │ │ ├── SourceSansPro-ExtraLight.ttf │ │ │ ├── SourceSansPro-ExtraLightIt.otf │ │ │ ├── SourceSansPro-ExtraLightIt.ttf │ │ │ ├── SourceSansPro-It.otf │ │ │ ├── SourceSansPro-It.ttf │ │ │ ├── SourceSansPro-Light.otf │ │ │ ├── SourceSansPro-Light.ttf │ │ │ ├── SourceSansPro-LightIt.otf │ │ │ ├── SourceSansPro-LightIt.ttf │ │ │ ├── SourceSansPro-Regular.otf │ │ │ ├── SourceSansPro-Regular.ttf │ │ │ ├── SourceSansPro-Semibold.otf │ │ │ ├── SourceSansPro-Semibold.ttf │ │ │ ├── SourceSansPro-SemiboldIt.otf │ │ │ └── SourceSansPro-SemiboldIt.ttf │ │ └── Tinos │ │ │ ├── OFL.txt │ │ │ ├── Tinos-Bold.ttf │ │ │ ├── Tinos-BoldItalic.ttf │ │ │ ├── Tinos-Italic.ttf │ │ │ └── Tinos-Regular.ttf │ ├── images │ │ ├── favicon.ico │ │ ├── icons │ │ │ ├── add.png │ │ │ ├── admin.png │ │ │ ├── blocked.png │ │ │ ├── checkmark.png │ │ │ ├── config.png │ │ │ ├── contacts.png │ │ │ ├── course_list.png │ │ │ ├── dashboard.png │ │ │ ├── deadline.png │ │ │ ├── deadline_missed.png │ │ │ ├── deadline_overdue.png │ │ │ ├── debug.png │ │ │ ├── destroy.png │ │ │ ├── download.png │ │ │ ├── draft.png │ │ │ ├── edit.png │ │ │ ├── email_resolvers.png │ │ │ ├── email_send.png │ │ │ ├── error.png │ │ │ ├── feed.png │ │ │ ├── filter.png │ │ │ ├── grades.png │ │ │ ├── help.png │ │ │ ├── homework.png │ │ │ ├── job.png │ │ │ ├── next.png │ │ │ ├── print.png │ │ │ ├── public.png │ │ │ ├── publish.png │ │ │ ├── recitation.png │ │ │ ├── recompute.png │ │ │ ├── register.png │ │ │ ├── release.png │ │ │ ├── report.png │ │ │ ├── revert.png │ │ │ ├── revisions.png │ │ │ ├── running.png │ │ │ ├── save.png │ │ │ ├── search.png │ │ │ ├── staff.png │ │ │ ├── student.png │ │ │ ├── submissions.png │ │ │ ├── survey.png │ │ │ ├── team.png │ │ │ ├── timer.png │ │ │ ├── tools.png │ │ │ ├── upload.png │ │ │ ├── upload_fail.png │ │ │ ├── upload_win.png │ │ │ └── waiting.png │ │ └── igor_white.svg │ ├── javascripts │ │ ├── application.js │ │ ├── attendance-roster.js.coffee │ │ ├── cable.coffee │ │ ├── channels │ │ │ └── .keep │ │ ├── grade-editor.js.coffee │ │ ├── grade-index.js.coffee │ │ ├── initialize_clipboard.coffee │ │ ├── initialize_foundation.coffee │ │ ├── initialize_pwnfx.js.coffee │ │ ├── recitation-index.js.coffee │ │ └── submission-dashboard.js.coffee │ └── stylesheets │ │ ├── _settings │ │ └── foundation.scss │ │ ├── application.css.scss │ │ ├── foundation_and_overrides.scss │ │ ├── mixins │ │ ├── headers.scss │ │ ├── lists.scss │ │ └── tables.scss │ │ └── web │ │ ├── activity_feed.scss │ │ ├── alerts.scss │ │ ├── analyses.scss │ │ ├── api_tokens.scss │ │ ├── assignment_builder.scss │ │ ├── assignment_dashboard.scss │ │ ├── assignments_index.scss │ │ ├── assignments_sidebar.scss │ │ ├── attendance_roster.scss │ │ ├── buttons.scss │ │ ├── colors.scss │ │ ├── deadline_extensions.scss │ │ ├── deadlines_sidebar.scss │ │ ├── exam_sessions_list.scss │ │ ├── fonts.scss │ │ ├── forms.scss │ │ ├── grade_editor.scss │ │ ├── grades.scss │ │ ├── grades_index.scss │ │ ├── headers.scss │ │ ├── icons.scss │ │ ├── inputs.scss │ │ ├── layouts.scss │ │ ├── links.scss │ │ ├── lists.scss │ │ ├── markdpwn.scss │ │ ├── profile_photos.scss │ │ ├── profiles.scss │ │ ├── progress_indicator.scss │ │ ├── pwnstyles.scss │ │ ├── recitation_partitions.scss │ │ ├── recitation_sections.scss │ │ ├── registrations.scss │ │ ├── role_requests.scss │ │ ├── sidebar_menu.scss │ │ ├── smtp_servers.scss │ │ ├── student_submissions_list.scss │ │ ├── submission_dashboard.scss │ │ ├── survey_answers.scss │ │ ├── survey_questions.scss │ │ ├── surveys.scss │ │ ├── tables.scss │ │ ├── team_partitions.scss │ │ ├── text.scss │ │ ├── time_slots.scss │ │ └── tooltips.scss ├── channels │ └── application_cable │ │ ├── channel.rb │ │ └── connection.rb ├── controllers │ ├── analyses_controller.rb │ ├── analyzers_controller.rb │ ├── api_controller.rb │ ├── api_docs_controller.rb │ ├── application_controller.rb │ ├── assignment_files_controller.rb │ ├── assignments_controller.rb │ ├── collaborations_controller.rb │ ├── concerns │ │ ├── .keep │ │ ├── course_filters.rb │ │ ├── cover_sheet.rb │ │ ├── grade_editor.rb │ │ ├── route_helpers.rb │ │ ├── sidebar_layout.rb │ │ └── user_filters.rb │ ├── courses_controller.rb │ ├── crash_controller.rb │ ├── deadline_extensions_controller.rb │ ├── deliverables_controller.rb │ ├── email_resolvers_controller.rb │ ├── exam_attendances_controller.rb │ ├── feedback_controller.rb │ ├── grade_comments_controller.rb │ ├── grades_controller.rb │ ├── jobs_controller.rb │ ├── prerequisites_controller.rb │ ├── profile_photos_controller.rb │ ├── recitation_partitions_controller.rb │ ├── recitation_sections_controller.rb │ ├── registrations_controller.rb │ ├── role_requests_controller.rb │ ├── roles_controller.rb │ ├── session_controller.rb │ ├── smtp_servers_controller.rb │ ├── submissions_controller.rb │ ├── survey_responses_controller.rb │ ├── surveys_controller.rb │ ├── team_memberships_controller.rb │ ├── team_partitions_controller.rb │ ├── teams_controller.rb │ ├── teams_student_controller.rb │ ├── time_slots_controller.rb │ └── users_controller.rb ├── helpers │ ├── analyses_helper.rb │ ├── analyzers_helper.rb │ ├── api_docs_helper.rb │ ├── api_helper.rb │ ├── application_helper.rb │ ├── assignments_helper.rb │ ├── courses_helper.rb │ ├── deadlines_helper.rb │ ├── email_resolvers_helper.rb │ ├── exam_sessions_helper.rb │ ├── foundation_form_builder.rb │ ├── grades_helper.rb │ ├── icons_helper.rb │ ├── menu_helper.rb │ ├── profile_photos_helper.rb │ ├── profiles_helper.rb │ ├── recitation_sections_helper.rb │ ├── registrations_helper.rb │ ├── smtp_servers_helper.rb │ ├── submissions_helper.rb │ ├── survey_questions_helper.rb │ ├── survey_responses_helper.rb │ ├── surveys_helper.rb │ ├── time_slot_helper.rb │ └── users_helper.rb ├── jobs │ ├── application_job.rb │ ├── recitation_assigner_job.rb │ └── submission_analysis_job.rb ├── mailers │ ├── application_mailer.rb │ ├── concerns │ │ └── dynamic_smtp_server.rb │ ├── exception_mailer.rb │ ├── recitation_assignment_mailer.rb │ ├── role_request_mailer.rb │ └── session_mailer.rb ├── models │ ├── action_item.rb │ ├── analysis.rb │ ├── analyzer.rb │ ├── application_record.rb │ ├── assignment.rb │ ├── assignment_file.rb │ ├── assignment_metric.rb │ ├── collaboration.rb │ ├── concerns │ │ ├── assignment_feedback.rb │ │ ├── average_score.rb │ │ ├── has_deadline.rb │ │ ├── is_released.rb │ │ ├── permission_validator.rb │ │ ├── role_base.rb │ │ └── submittable.rb │ ├── course.rb │ ├── credential.rb │ ├── deadline.rb │ ├── deadline_extension.rb │ ├── deliverable.rb │ ├── docker_analyzer.rb │ ├── email_resolver.rb │ ├── exam.rb │ ├── exam_attendance.rb │ ├── exam_session.rb │ ├── feed_item.rb │ ├── file_blob.rb │ ├── grade.rb │ ├── grade_comment.rb │ ├── invitation.rb │ ├── prerequisite.rb │ ├── prerequisite_answer.rb │ ├── proc_analyzer.rb │ ├── profile.rb │ ├── profile_photo.rb │ ├── quantitative_open_question.rb │ ├── quantitative_scaled_question.rb │ ├── recitation_assigner.rb │ ├── recitation_assignment.rb │ ├── recitation_conflict.rb │ ├── recitation_partition.rb │ ├── recitation_section.rb │ ├── registration.rb │ ├── role.rb │ ├── role_request.rb │ ├── session.rb │ ├── smtp_server.rb │ ├── submission.rb │ ├── survey.rb │ ├── survey_answer.rb │ ├── survey_question.rb │ ├── survey_response.rb │ ├── team.rb │ ├── team_membership.rb │ ├── team_partition.rb │ ├── time_slot.rb │ ├── time_slot_allotment.rb │ └── user.rb └── views │ ├── analyses │ ├── _status_icon.html.erb │ ├── refresh.html.erb │ └── show.html.erb │ ├── api │ ├── assignments.json.jbuilder │ ├── submissions.json.jbuilder │ └── user_info.json.jbuilder │ ├── api_docs │ ├── _assignments.html.erb │ ├── _submissions.html.erb │ ├── _user_info.html.erb │ └── index.html.erb │ ├── assignment_files │ ├── _fields.html.erb │ └── _list.html.erb │ ├── assignment_metrics │ └── _fields.html.erb │ ├── assignments │ ├── _deadline.html.erb │ ├── _deliverable_dashboard.html.erb │ ├── _deliverable_release.html.erb │ ├── _deliverables_builder.html.erb │ ├── _exam_builder.html.erb │ ├── _exam_sessions_builder.html.erb │ ├── _exam_sessions_dashboard.html.erb │ ├── _extensions_dashboard.html.erb │ ├── _fields.html.erb │ ├── _form.html.erb │ ├── _grade_release.html.erb │ ├── _grades_dashboard.html.erb │ ├── _grading_process_dashboard.html.erb │ ├── _list.html.erb │ ├── _metrics_builder.html.erb │ ├── _recitations_dashboard.html.erb │ ├── _resource_files_builder.html.erb │ ├── _show.html.erb │ ├── _sidebar.html.erb │ ├── _sidebar_list.erb │ ├── _submissions_dashboard.html.erb │ ├── dashboard.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── index.json.jbuilder │ ├── new.html.erb │ └── show.html.erb │ ├── collaborations │ ├── _collaborator.html.erb │ └── _form.html.erb │ ├── courses │ ├── _fields.html.erb │ ├── connect.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb │ ├── deadline_extensions │ ├── _fields.html.erb │ └── index.html.erb │ ├── deliverables │ ├── _dashboard_submission_list.html.erb │ ├── _fields.html.erb │ ├── _no_submission.html.erb │ ├── _student_submission_list.html.erb │ ├── _student_submission_list_entry.html.erb │ ├── _submission_figure.html.erb │ └── submission_dashboard.html.erb │ ├── docker_analyzers │ ├── _fields.html.erb │ └── help.html.erb │ ├── email_resolvers │ ├── _form.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb │ ├── exam_attendances │ ├── _form.html.erb │ ├── edit.html.erb │ └── index.html.erb │ ├── exam_sessions │ ├── _fields.html.erb │ └── _list.html.erb │ ├── grades │ ├── _individual_form.html.erb │ ├── _request_missing.html.erb │ ├── edit.html.erb │ ├── editor.html.erb │ ├── editor_blank.html.erb │ ├── index.html.erb │ ├── missing.html.erb │ ├── request_missing.html.erb │ └── request_report.html.erb │ ├── jobs │ ├── index.html.erb │ └── show.html.erb │ ├── layouts │ ├── _analytics.html.erb │ ├── _feed_item.html.erb │ ├── _feed_item_reply.html.erb │ ├── _footer.html.erb │ ├── _groups.html.erb │ ├── _header.html.erb │ ├── _newsfeed.html.erb │ ├── _status_bar.html.erb │ ├── application.html.erb │ ├── assignments.html.erb │ ├── mailer.html.erb │ ├── mailer.text.erb │ ├── session.html.erb │ └── teams.html.erb │ ├── menu │ ├── _account_menu.html.erb │ ├── _course.html.erb │ ├── _courses_menu.html.erb │ ├── _for_admin.html.erb │ ├── _for_grader.html.erb │ ├── _for_guided.html.erb │ ├── _for_staff.html.erb │ ├── _for_student.html.erb │ ├── _grades.html.erb │ ├── _homework.html.erb │ ├── _menu.html.erb │ └── _staff.html.erb │ ├── prerequisites │ ├── _fields.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ └── new.html.erb │ ├── proc_analyzers │ └── _fields.html.erb │ ├── profile_photos │ ├── _for_user.html.erb │ ├── _form.html.erb │ ├── edit.html.erb │ ├── edit.js.rjs │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb │ ├── profiles │ ├── _fields.html.erb │ ├── _form.html.erb │ ├── _show.html.erb │ └── edit.html.erb │ ├── quantitative_open_questions │ └── _fields.html.erb │ ├── quantitative_scaled_questions │ └── _fields.html.erb │ ├── recitation_assignment_mailer │ ├── recitation_assignment_email.html.erb │ └── recitation_assignment_email.text.erb │ ├── recitation_partitions │ ├── index.html.erb │ └── show.html.erb │ ├── recitation_sections │ ├── _form.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb │ ├── registrations │ ├── _availability.html.erb │ ├── _conflicts.html.erb │ ├── _fields.html.erb │ ├── _prerequisites.html.erb │ ├── _recitation_section.html.erb │ ├── _registration.html.erb │ ├── _time_slot_days_header.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb │ ├── role_request_mailer │ ├── decision_email.html.erb │ ├── decision_email.text.erb │ ├── notice_email.html.erb │ └── notice_email.text.erb │ ├── role_requests │ ├── _approved_staff.html.erb │ ├── _pending_staff.html.erb │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb │ ├── session │ ├── _deadlines.html.erb │ ├── _login_form.html.erb │ ├── _sidebar.html.erb │ ├── api_token.html.erb │ ├── forbidden.html.erb │ ├── home.html.erb │ ├── new.html.erb │ └── password_change.html.erb │ ├── session_mailer │ ├── email_verification_email.html.erb │ ├── email_verification_email.text.erb │ ├── reset_password_email.html.erb │ ├── reset_password_email.text.erb │ ├── team_invite_email.html.erb │ └── team_invite_email.text.erb │ ├── smtp_servers │ └── edit.html.erb │ ├── submissions │ ├── _filename_spec.erb │ ├── _form.html.erb │ ├── _main_submission.html.erb │ ├── _request_assignment.html.erb │ ├── _xhr_deliverables.html.erb │ ├── index.html.erb │ ├── request_package.html.erb │ └── xhr_deliverables.html.erb │ ├── survey_answers │ └── _fields.html.erb │ ├── survey_questions │ └── _fields.html.erb │ ├── survey_responses │ ├── _form.html.erb │ └── index.html.erb │ ├── surveys │ ├── _fields.html.erb │ ├── _form.html.erb │ ├── _list.html.erb │ ├── _show.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb │ ├── team_memberships │ ├── _form.html.erb │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb │ ├── team_partitions │ ├── index.html.erb │ ├── issues.html.erb │ ├── new_edit.html.erb │ ├── show.html.erb │ └── unlock.html.erb │ ├── teams │ ├── _form.html.erb │ ├── _team.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb │ ├── teams_student │ ├── accept_invitation.html.erb │ ├── create_team.html.erb │ ├── ignore_invitation.html.erb │ ├── leave_team.html.erb │ └── show.html.erb │ ├── time_slots │ ├── _fields.html.erb │ ├── _list.html.erb │ └── index.html.erb │ └── users │ ├── _new.html.erb │ ├── _new_fields.html.erb │ ├── _user.html.erb │ ├── check_email.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb ├── bin ├── bundle ├── delayed_job ├── puma ├── pumactl ├── rails ├── rake ├── setup ├── spring └── update ├── clouds.yaml ├── config.ru ├── config ├── application.rb ├── autoprefixer.yml ├── boot.rb ├── cable.yml ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── action_mailer.rb │ ├── active_record_belongs_to_required_by_default.rb │ ├── application_controller_renderer.rb │ ├── assets.rb │ ├── authpwn.rb │ ├── autoload_mailer_concerns.rb │ ├── backtrace_silencers.rb │ ├── bower_rails.rb │ ├── cookies_serializer.rb │ ├── cors.rb │ ├── delayed_job.rb │ ├── exception_notifier.rb │ ├── field_error_proc.rb │ ├── filter_parameter_logging.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── per_form_csrf_tokens.rb │ ├── rack_mini_profiler.rb │ ├── request_forgery_protection.rb │ ├── session_store.rb │ ├── silence_view_logging.rb │ ├── stdlib.rb │ ├── time_formats.rb │ └── wrap_parameters.rb ├── locales │ └── en.yml ├── mongrel_cluster.yml ├── puma.rb ├── routes.rb └── secrets.yml ├── db ├── migrate │ ├── 20100725000001_create_users.rb │ ├── 20100725000003_create_credentials.rb │ ├── 20110703010001_create_file_blobs.rb │ ├── 20110703010002_create_delayed_jobs.rb │ ├── 20110704010001_create_roles.rb │ ├── 20110704010002_create_profiles.rb │ ├── 20110704010003_create_profile_photos.rb │ ├── 20110704010004_create_robot_user.rb │ ├── 20110704010005_create_photo_blobs.rb │ ├── 20110704010006_create_role_requests.rb │ ├── 20110704010007_create_email_resolvers.rb │ ├── 20110704010008_create_smtp_servers.rb │ ├── 20110704020001_create_courses.rb │ ├── 20110704020003_create_prerequisites.rb │ ├── 20110704020004_create_registrations.rb │ ├── 20110704020005_create_recitation_conflicts.rb │ ├── 20110704020006_create_prerequisite_answers.rb │ ├── 20110704030000_create_deadlines.rb │ ├── 20110704030001_create_deadline_extensions.rb │ ├── 20110704030002_create_assignments.rb │ ├── 20110704030003_create_assignment_files.rb │ ├── 20110704030004_create_assignment_metrics.rb │ ├── 20110704030005_create_grades.rb │ ├── 20110704030006_create_grade_comments.rb │ ├── 20110704040001_create_deliverables.rb │ ├── 20110704040002_create_analyzers.rb │ ├── 20110704040003_create_submissions.rb │ ├── 20110704040004_create_collaborations.rb │ ├── 20110704040005_create_analyses.rb │ ├── 20110704050001_create_surveys.rb │ ├── 20110704050002_create_survey_questions.rb │ ├── 20110704050003_create_survey_responses.rb │ ├── 20110704050004_create_survey_answers.rb │ ├── 20110704060001_create_team_partitions.rb │ ├── 20110704060002_create_teams.rb │ ├── 20110704060003_create_team_memberships.rb │ ├── 20110704060004_create_invitations.rb │ ├── 20110704060005_create_recitation_sections.rb │ ├── 20110704060006_create_recitation_partition.rb │ ├── 20110704060007_create_recitation_assignment.rb │ ├── 20110704060008_create_time_slots.rb │ ├── 20110704060009_create_time_slot_allotments.rb │ ├── 20110704080001_create_exams.rb │ ├── 20110704080002_create_exam_sessions.rb │ └── 20110704080003_create_exam_attendances.rb ├── schema.rb ├── seeds.rb └── seeds │ ├── depts.txt │ └── names.txt ├── deploy ├── ansible │ ├── clouds.yaml.example │ ├── inventory │ │ └── openstack.py │ ├── keys.yml │ ├── library │ │ ├── TODO.txt │ │ └── os_server_custom.py │ ├── openstack_up.yml │ ├── prod.yml │ ├── roles │ │ ├── disable_cockpit │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── docker │ │ │ ├── defaults │ │ │ │ └── main.yml │ │ │ ├── handlers │ │ │ │ └── main.yml │ │ │ ├── tasks │ │ │ │ ├── main.yml │ │ │ │ └── packages.yml │ │ │ └── templates │ │ │ │ └── sysconfig_docker.j2 │ │ ├── docker_client_keys │ │ │ ├── defaults │ │ │ │ └── main.yml │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── docker_facts │ │ │ ├── defaults │ │ │ │ └── main.yml │ │ │ ├── meta │ │ │ │ └── main.yml │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── docker_network │ │ │ ├── handlers │ │ │ │ └── main.yml │ │ │ ├── tasks │ │ │ │ └── main.yml │ │ │ └── templates │ │ │ │ └── sysconfig_docker_network.j2 │ │ ├── docker_storage │ │ │ ├── handlers │ │ │ │ └── main.yml │ │ │ ├── tasks │ │ │ │ └── main.yml │ │ │ └── templates │ │ │ │ └── docker-storage-setup.j2 │ │ ├── docker_swarm_master │ │ │ ├── defaults │ │ │ │ └── main.yml │ │ │ ├── handlers │ │ │ │ └── main.yml │ │ │ ├── tasks │ │ │ │ └── main.yml │ │ │ └── templates │ │ │ │ └── docker_swarm_master_service.j2 │ │ ├── docker_swarm_worker │ │ │ ├── defaults │ │ │ │ └── main.yml │ │ │ ├── handlers │ │ │ │ └── main.yml │ │ │ ├── tasks │ │ │ │ └── main.yml │ │ │ └── templates │ │ │ │ └── docker_swarm_worker_service.j2 │ │ ├── etcd_client │ │ │ ├── defaults │ │ │ │ └── main.yml │ │ │ ├── meta │ │ │ │ └── main.yml │ │ │ └── tasks │ │ │ │ ├── etc_hosts.yml │ │ │ │ └── main.yml │ │ ├── etcd_server │ │ │ ├── handlers │ │ │ │ └── main.yml │ │ │ ├── tasks │ │ │ │ └── main.yml │ │ │ └── templates │ │ │ │ └── etcd.conf.j2 │ │ ├── gen_certs_cluster │ │ │ ├── defaults │ │ │ │ └── main.yml │ │ │ ├── files │ │ │ │ └── openssl.cnf │ │ │ └── tasks │ │ │ │ ├── docker.yml │ │ │ │ ├── etcd.yml │ │ │ │ └── main.yml │ │ ├── gen_certs_web │ │ │ ├── defaults │ │ │ │ └── main.yml │ │ │ ├── files │ │ │ │ └── openssl.cnf │ │ │ ├── tasks │ │ │ │ └── main.yml │ │ │ └── templates │ │ │ │ └── certbot.yml.j2 │ │ ├── nginx │ │ │ ├── handlers │ │ │ │ └── main.yml │ │ │ ├── tasks │ │ │ │ └── main.yml │ │ │ └── templates │ │ │ │ └── nginx.conf.j2 │ │ ├── nodejs_npm │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── os_cluster │ │ │ ├── defaults │ │ │ │ └── main.yml │ │ │ ├── handlers │ │ │ │ └── main.yml │ │ │ ├── tasks │ │ │ │ ├── image.yml │ │ │ │ ├── main.yml │ │ │ │ ├── network.yml │ │ │ │ ├── ssh_keys.yml │ │ │ │ ├── volumes_data.yml │ │ │ │ └── volumes_root.yml │ │ │ └── templates │ │ │ │ ├── known_hosts.j2 │ │ │ │ ├── master_userdata.j2 │ │ │ │ └── worker_userdata.j2 │ │ ├── pgsql │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── ruby_bundler │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── skydns_client │ │ │ ├── defaults │ │ │ │ └── main.yml │ │ │ ├── handlers │ │ │ │ └── main.yml │ │ │ ├── meta │ │ │ │ └── main.yml │ │ │ ├── tasks │ │ │ │ ├── etc_hosts.yml │ │ │ │ └── main.yml │ │ │ └── templates │ │ │ │ └── 99-z-cancel-cloud-init.conf │ │ ├── skydns_name_master │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── skydns_name_worker │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── skydns_server │ │ │ ├── defaults │ │ │ │ └── main.yml │ │ │ ├── handlers │ │ │ │ └── main.yml │ │ │ ├── tasks │ │ │ │ ├── etcd_config.yml │ │ │ │ ├── etcd_tls_keys.yml │ │ │ │ └── main.yml │ │ │ └── templates │ │ │ │ ├── etcdctl_peers.j2 │ │ │ │ ├── skydns.conf.j2 │ │ │ │ └── skydns.etcd.json.j2 │ │ ├── skydns_update_service │ │ │ ├── defaults │ │ │ │ └── main.yml │ │ │ ├── handlers │ │ │ │ └── main.yml │ │ │ ├── meta │ │ │ │ └── main.yml │ │ │ ├── tasks │ │ │ │ └── main.yml │ │ │ └── templates │ │ │ │ ├── skydns_update_service.j2 │ │ │ │ └── skydns_update_sh.j2 │ │ ├── sudo_nopasswd │ │ │ ├── tasks │ │ │ │ └── main.yml │ │ │ └── templates │ │ │ │ └── nopasswd.j2 │ │ ├── sys_facts │ │ │ ├── defaults │ │ │ │ └── main.yml │ │ │ ├── meta │ │ │ │ └── main.yml │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── sys_network_manager │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── sys_package_update │ │ │ ├── defaults │ │ │ │ └── main.yml │ │ │ ├── handlers │ │ │ │ └── main.yml │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── sys_python2 │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── web_certs │ │ │ ├── defaults │ │ │ │ └── main.yml │ │ │ ├── handlers │ │ │ │ └── main.yml │ │ │ ├── meta │ │ │ │ └── main.yml │ │ │ ├── tasks │ │ │ │ ├── bootstrap.yml │ │ │ │ ├── config.yml │ │ │ │ ├── deps.yml │ │ │ │ ├── files.yml │ │ │ │ ├── main.yml │ │ │ │ ├── nginx.yml │ │ │ │ ├── surrogate.yml │ │ │ │ └── systemd.yml │ │ │ └── templates │ │ │ │ ├── certbot.service.j2 │ │ │ │ ├── certbot.timer.j2 │ │ │ │ ├── certbot_bootstrap.service.j2 │ │ │ │ └── nginx.conf.j2 │ │ ├── web_db │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── web_frontend │ │ │ ├── defaults │ │ │ │ └── main.yml │ │ │ ├── handlers │ │ │ │ └── main.yml │ │ │ ├── meta │ │ │ │ └── main.yml │ │ │ ├── tasks │ │ │ │ ├── docker.yml │ │ │ │ ├── main.yml │ │ │ │ ├── nginx.yml │ │ │ │ ├── packages.yml │ │ │ │ └── systemd.yml │ │ │ └── templates │ │ │ │ ├── jobs_systemd.service.j2 │ │ │ │ ├── main_systemd.service.j2 │ │ │ │ └── nginx.conf.j2 │ │ ├── web_frontend_motd │ │ │ ├── meta │ │ │ │ └── main.yml │ │ │ ├── tasks │ │ │ │ └── main.yml │ │ │ └── templates │ │ │ │ ├── motd-tail.sh.j2 │ │ │ │ └── motd.j2 │ │ └── web_user │ │ │ └── tasks │ │ │ └── main.yml │ └── web_update.yml └── openstack_vars.yml ├── doc ├── admin_guide.md ├── deployment.md └── docker_benchmark.md ├── lib ├── analyzer_sources │ ├── fib │ │ ├── Dockerfile │ │ ├── cases │ │ │ ├── 1.in │ │ │ ├── 1.out │ │ │ ├── 10.in │ │ │ ├── 10.out │ │ │ ├── 11.in │ │ │ ├── 11.out │ │ │ ├── 12.in │ │ │ ├── 12.out │ │ │ ├── 13.in │ │ │ ├── 13.out │ │ │ ├── 14.in │ │ │ ├── 14.out │ │ │ ├── 2.in │ │ │ ├── 2.out │ │ │ ├── 3.in │ │ │ ├── 3.out │ │ │ ├── 4.in │ │ │ ├── 4.out │ │ │ ├── 5.in │ │ │ ├── 5.out │ │ │ ├── 6.in │ │ │ ├── 6.out │ │ │ ├── 7.in │ │ │ ├── 7.out │ │ │ ├── 8.in │ │ │ ├── 8.out │ │ │ ├── 9.in │ │ │ └── 9.out │ │ ├── mapper.py │ │ ├── mapreduced.yml │ │ └── reducer.py │ └── fib_small │ │ ├── Dockerfile │ │ ├── cases │ │ ├── 1.in │ │ ├── 1.out │ │ ├── 2.in │ │ ├── 2.out │ │ ├── 3.in │ │ └── 3.out │ │ ├── mapper.py │ │ ├── mapreduced.yml │ │ └── reducer.py ├── assets │ └── .keep └── tasks │ ├── .gitkeep │ ├── .keep │ ├── auto_annotate_models.rake │ └── docker_benchmark.rake ├── log └── .keep ├── package-lock.json ├── package.json ├── public ├── 404.html ├── 422.html ├── 500.html ├── _static_images │ ├── 404.png │ └── 500.png ├── favicon.ico └── robots.txt ├── test ├── controllers │ ├── .keep │ ├── analyses_controller_test.rb │ ├── analytics_partial_test.rb │ ├── analyzers_controller_test.rb │ ├── api_controller_test.rb │ ├── api_docs_controller_test.rb │ ├── assignments_controller_test.rb │ ├── collaborations_controller_test.rb │ ├── deadline_extensions_controller_test.rb │ ├── deliverables_controller_test.rb │ ├── exam_attendances_controller_test.rb │ ├── grade_comments_controller_test.rb │ ├── grades_controller_test.rb │ ├── recitation_sections_controller_test.rb │ ├── registrations_controller_test.rb │ ├── session_controller_test.rb │ ├── submissions_controller_test.rb │ ├── survey_responses_controller_test.rb │ └── users_controller_test.rb ├── fixtures │ ├── analyses.yml │ ├── analyzers.yml │ ├── assignment_files.yml │ ├── assignment_metrics.yml │ ├── assignments.yml │ ├── collaborations.yml │ ├── courses.yml │ ├── credentials.yml │ ├── deadline_extensions.yml │ ├── deadlines.yml │ ├── deliverables.yml │ ├── email_resolvers.yml │ ├── exam_attendances.yml │ ├── exam_sessions.yml │ ├── exams.yml │ ├── file_blobs.yml │ ├── files │ │ ├── analyzer │ │ │ ├── fib.zip │ │ │ ├── fib_bench.zip │ │ │ └── fib_small.zip │ │ ├── hello.html │ │ ├── hello.xhtml │ │ ├── large_file.txt │ │ ├── pics │ │ │ ├── costan.png │ │ │ ├── costan_profile.png │ │ │ └── costan_thumb.png │ │ └── submission │ │ │ ├── deadlock_fib.py │ │ │ ├── good_fib.py │ │ │ ├── slow_fib.py │ │ │ ├── small.pdf │ │ │ └── truncated.pdf │ ├── grade_comments.yml │ ├── grades.yml │ ├── photo_blobs.yml │ ├── prerequisite_answers.yml │ ├── prerequisites.yml │ ├── profile_photos.yml │ ├── profiles.yml │ ├── recitation_assignments.yml │ ├── recitation_conflicts.yml │ ├── recitation_partitions.yml │ ├── recitation_sections.yml │ ├── registrations.yml │ ├── role_requests.yml │ ├── roles.yml │ ├── smtp_servers.yml │ ├── submissions.yml │ ├── survey_answers.yml │ ├── survey_questions.yml │ ├── survey_responses.yml │ ├── surveys.yml │ ├── team_memberships.yml │ ├── team_partitions.yml │ ├── teams.yml │ ├── time_slot_allotments.yml │ ├── time_slots.yml │ └── users.yml ├── functional │ ├── courses_controller_test.rb │ ├── prerequisites_controller_test.rb │ ├── profile_photos_controller_test.rb │ └── surveys_controller_test.rb ├── helpers │ ├── analyzers_helper_test.rb │ ├── application_helper_test.rb │ ├── assignments_helper_test.rb │ ├── deadlines_helper_test.rb │ ├── exam_sessions_helper_test.rb │ ├── menu_helper_test.rb │ ├── profiles_helper_test.rb │ ├── submissions_helper_test.rb │ ├── survey_questions_helper_test.rb │ ├── survey_responses_helper_test.rb │ └── surveys_helper_test.rb ├── integration │ ├── .keep │ └── uploading_submissions_test.rb ├── jobs │ └── submission_analysis_job_test.rb ├── load │ └── uploading_submissions_test.rb ├── mailers │ ├── .keep │ ├── previews │ │ └── session_mailer_preview.rb │ └── session_mailer_test.rb ├── models │ ├── action_item_test.rb │ ├── analysis_test.rb │ ├── assignment_feedback_test.rb │ ├── assignment_file_test.rb │ ├── assignment_metric_test.rb │ ├── assignment_test.rb │ ├── collaboration_test.rb │ ├── course_test.rb │ ├── deadline_extension_test.rb │ ├── deadline_test.rb │ ├── deliverable_test.rb │ ├── docker_analyzer_test.rb │ ├── email_resolver_test.rb │ ├── exam_attendance_test.rb │ ├── exam_session_test.rb │ ├── exam_test.rb │ ├── file_blob_test.rb │ ├── grade_comment_test.rb │ ├── grade_test.rb │ ├── prerequisite_answer_test.rb │ ├── proc_analyzer_test.rb │ ├── profile_test.rb │ ├── quantitative_open_question_test.rb │ ├── quantitative_scaled_question_test.rb │ ├── recitation_assignment_test.rb │ ├── recitation_conflict_test.rb │ ├── recitation_partition_test.rb │ ├── recitation_section_test.rb │ ├── registration_test.rb │ ├── role_request_test.rb │ ├── role_test.rb │ ├── smtp_server_test.rb │ ├── submission_test.rb │ ├── survey_answer_test.rb │ ├── survey_response_test.rb │ ├── survey_test.rb │ ├── team_test.rb │ ├── time_slot_allotment_test.rb │ ├── time_slot_test.rb │ └── user_test.rb ├── support │ ├── file_generator.rb │ └── user_session.rb └── test_helper.rb └── vendor └── assets ├── .bowerrc ├── bower.json ├── javascripts ├── .keep ├── es6-promise-install.js └── pwn-fx.js.coffee └── stylesheets └── .keep /.env: -------------------------------------------------------------------------------- 1 | PORT=3000 2 | RAILS_ENV=development 3 | 4 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --colour 2 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.3.3 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | language: ruby 4 | cache: bundler 5 | addons: 6 | postgresql: "9.6" 7 | services: 8 | - postgresql 9 | before_script: 10 | - npm install bower 11 | - RAILS_ENV=test bin/bundle exec rake db:create db:migrate 12 | - RAILS_ENV=production bin/bundle exec rake assets:precompile 13 | script: bin/rails test test/models test/controllers test/helpers 14 | test/mailers test/jobs 15 | rvm: 16 | - "2.4.1" 17 | -------------------------------------------------------------------------------- /Bowerfile: -------------------------------------------------------------------------------- 1 | asset 'clipboard', '1.5.12' 2 | asset 'es6-promise', '3.2.2' 3 | asset 'fetch', '0.11.1' 4 | asset 'motion-ui', '1.2.2' 5 | 6 | resolution 'jquery', '2.2.4' 7 | -------------------------------------------------------------------------------- /Brewfile: -------------------------------------------------------------------------------- 1 | tap 'caskroom/cask' 2 | cask 'osxfuse' 3 | 4 | # Using a custom-brewed Ansible because the mainstream Ansible is broken. 5 | # # https://github.com/Homebrew/homebrew-core/issues/9337 6 | brew 'pwnall/brews/ansible' 7 | 8 | brew 'docker' 9 | brew 'docker-machine' 10 | brew 'docker-swarm' 11 | brew 'imagemagick', args: ['with-librsvg'] 12 | brew 'libxml2' 13 | brew 'libxslt' 14 | brew 'openssl' 15 | brew 'pkg-config' 16 | brew 'postgresql', restart_service: :changed 17 | brew 'sshfs' 18 | cask 'kitematic' 19 | cask 'vagrant' 20 | cask 'virtualbox' 21 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: bin/puma -C config/puma.rb 2 | dj: bin/rake jobs:work 3 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | Igor::Application.load_tasks 7 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | host_key_checking = True 3 | inventory = deploy/ansible/inventory 4 | nocows = 1 5 | retry_files_enabled = False 6 | 7 | [ssh_connection] 8 | ssh_args = -o GlobalKnownHostsFile=deploy/keys/known_hosts -o ControlMaster=auto -o ControlPersist=60s 9 | -------------------------------------------------------------------------------- /app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../fonts 2 | //= link_tree ../images 3 | //= link_directory ../javascripts .js 4 | //= link_directory ../stylesheets .css 5 | 6 | // TODO(pwnall): Remove this workaround when font-awesome-rails gets Rails 5 7 | // support. 8 | //= link fontawesome-webfont.eot 9 | //= link fontawesome-webfont.woff2 10 | //= link fontawesome-webfont.woff 11 | //= link fontawesome-webfont.ttf 12 | //= link fontawesome-webfont.svg 13 | -------------------------------------------------------------------------------- /app/assets/fonts/Dosis/Dosis-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/Dosis/Dosis-Bold.ttf -------------------------------------------------------------------------------- /app/assets/fonts/Dosis/Dosis-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/Dosis/Dosis-ExtraBold.ttf -------------------------------------------------------------------------------- /app/assets/fonts/Dosis/Dosis-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/Dosis/Dosis-ExtraLight.ttf -------------------------------------------------------------------------------- /app/assets/fonts/Dosis/Dosis-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/Dosis/Dosis-Light.ttf -------------------------------------------------------------------------------- /app/assets/fonts/Dosis/Dosis-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/Dosis/Dosis-Medium.ttf -------------------------------------------------------------------------------- /app/assets/fonts/Dosis/Dosis-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/Dosis/Dosis-Regular.ttf -------------------------------------------------------------------------------- /app/assets/fonts/Dosis/Dosis-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/Dosis/Dosis-SemiBold.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceCodePro/SourceCodePro-Black.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceCodePro/SourceCodePro-Black.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceCodePro/SourceCodePro-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceCodePro/SourceCodePro-Black.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceCodePro/SourceCodePro-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceCodePro/SourceCodePro-Bold.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceCodePro/SourceCodePro-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceCodePro/SourceCodePro-Bold.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceCodePro/SourceCodePro-ExtraLight.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceCodePro/SourceCodePro-ExtraLight.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceCodePro/SourceCodePro-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceCodePro/SourceCodePro-ExtraLight.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceCodePro/SourceCodePro-Light.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceCodePro/SourceCodePro-Light.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceCodePro/SourceCodePro-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceCodePro/SourceCodePro-Light.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceCodePro/SourceCodePro-Medium.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceCodePro/SourceCodePro-Medium.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceCodePro/SourceCodePro-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceCodePro/SourceCodePro-Medium.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceCodePro/SourceCodePro-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceCodePro/SourceCodePro-Regular.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceCodePro/SourceCodePro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceCodePro/SourceCodePro-Regular.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceCodePro/SourceCodePro-Semibold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceCodePro/SourceCodePro-Semibold.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceCodePro/SourceCodePro-Semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceCodePro/SourceCodePro-Semibold.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-Black.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-Black.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-Black.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-BlackIt.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-BlackIt.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-BlackIt.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-BlackIt.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-Bold.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-Bold.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-BoldIt.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-BoldIt.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-BoldIt.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-BoldIt.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-ExtraLight.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-ExtraLight.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-ExtraLight.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-ExtraLightIt.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-ExtraLightIt.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-ExtraLightIt.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-ExtraLightIt.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-It.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-It.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-It.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-It.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-Light.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-Light.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-Light.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-LightIt.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-LightIt.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-LightIt.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-LightIt.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-Regular.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-Regular.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-Semibold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-Semibold.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-Semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-Semibold.ttf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-SemiboldIt.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-SemiboldIt.otf -------------------------------------------------------------------------------- /app/assets/fonts/SourceSansPro/SourceSansPro-SemiboldIt.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/SourceSansPro/SourceSansPro-SemiboldIt.ttf -------------------------------------------------------------------------------- /app/assets/fonts/Tinos/Tinos-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/Tinos/Tinos-Bold.ttf -------------------------------------------------------------------------------- /app/assets/fonts/Tinos/Tinos-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/Tinos/Tinos-BoldItalic.ttf -------------------------------------------------------------------------------- /app/assets/fonts/Tinos/Tinos-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/Tinos/Tinos-Italic.ttf -------------------------------------------------------------------------------- /app/assets/fonts/Tinos/Tinos-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/fonts/Tinos/Tinos-Regular.ttf -------------------------------------------------------------------------------- /app/assets/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/favicon.ico -------------------------------------------------------------------------------- /app/assets/images/icons/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/add.png -------------------------------------------------------------------------------- /app/assets/images/icons/admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/admin.png -------------------------------------------------------------------------------- /app/assets/images/icons/blocked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/blocked.png -------------------------------------------------------------------------------- /app/assets/images/icons/checkmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/checkmark.png -------------------------------------------------------------------------------- /app/assets/images/icons/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/config.png -------------------------------------------------------------------------------- /app/assets/images/icons/contacts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/contacts.png -------------------------------------------------------------------------------- /app/assets/images/icons/course_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/course_list.png -------------------------------------------------------------------------------- /app/assets/images/icons/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/dashboard.png -------------------------------------------------------------------------------- /app/assets/images/icons/deadline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/deadline.png -------------------------------------------------------------------------------- /app/assets/images/icons/deadline_missed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/deadline_missed.png -------------------------------------------------------------------------------- /app/assets/images/icons/deadline_overdue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/deadline_overdue.png -------------------------------------------------------------------------------- /app/assets/images/icons/debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/debug.png -------------------------------------------------------------------------------- /app/assets/images/icons/destroy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/destroy.png -------------------------------------------------------------------------------- /app/assets/images/icons/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/download.png -------------------------------------------------------------------------------- /app/assets/images/icons/draft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/draft.png -------------------------------------------------------------------------------- /app/assets/images/icons/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/edit.png -------------------------------------------------------------------------------- /app/assets/images/icons/email_resolvers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/email_resolvers.png -------------------------------------------------------------------------------- /app/assets/images/icons/email_send.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/email_send.png -------------------------------------------------------------------------------- /app/assets/images/icons/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/error.png -------------------------------------------------------------------------------- /app/assets/images/icons/feed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/feed.png -------------------------------------------------------------------------------- /app/assets/images/icons/filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/filter.png -------------------------------------------------------------------------------- /app/assets/images/icons/grades.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/grades.png -------------------------------------------------------------------------------- /app/assets/images/icons/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/help.png -------------------------------------------------------------------------------- /app/assets/images/icons/homework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/homework.png -------------------------------------------------------------------------------- /app/assets/images/icons/job.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/job.png -------------------------------------------------------------------------------- /app/assets/images/icons/next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/next.png -------------------------------------------------------------------------------- /app/assets/images/icons/print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/print.png -------------------------------------------------------------------------------- /app/assets/images/icons/public.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/public.png -------------------------------------------------------------------------------- /app/assets/images/icons/publish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/publish.png -------------------------------------------------------------------------------- /app/assets/images/icons/recitation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/recitation.png -------------------------------------------------------------------------------- /app/assets/images/icons/recompute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/recompute.png -------------------------------------------------------------------------------- /app/assets/images/icons/register.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/register.png -------------------------------------------------------------------------------- /app/assets/images/icons/release.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/release.png -------------------------------------------------------------------------------- /app/assets/images/icons/report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/report.png -------------------------------------------------------------------------------- /app/assets/images/icons/revert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/revert.png -------------------------------------------------------------------------------- /app/assets/images/icons/revisions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/revisions.png -------------------------------------------------------------------------------- /app/assets/images/icons/running.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/running.png -------------------------------------------------------------------------------- /app/assets/images/icons/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/save.png -------------------------------------------------------------------------------- /app/assets/images/icons/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/search.png -------------------------------------------------------------------------------- /app/assets/images/icons/staff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/staff.png -------------------------------------------------------------------------------- /app/assets/images/icons/student.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/student.png -------------------------------------------------------------------------------- /app/assets/images/icons/submissions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/submissions.png -------------------------------------------------------------------------------- /app/assets/images/icons/survey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/survey.png -------------------------------------------------------------------------------- /app/assets/images/icons/team.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/team.png -------------------------------------------------------------------------------- /app/assets/images/icons/timer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/timer.png -------------------------------------------------------------------------------- /app/assets/images/icons/tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/tools.png -------------------------------------------------------------------------------- /app/assets/images/icons/upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/upload.png -------------------------------------------------------------------------------- /app/assets/images/icons/upload_fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/upload_fail.png -------------------------------------------------------------------------------- /app/assets/images/icons/upload_win.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/upload_win.png -------------------------------------------------------------------------------- /app/assets/images/icons/waiting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/images/icons/waiting.png -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // Shims. 2 | //= require es6-promise/promise 3 | //= require es6-promise-install 4 | //= require fetch/fetch 5 | // 6 | // Libraries. 7 | //= require clipboard 8 | //= require jquery2 9 | //= require jquery_ujs 10 | //= require motion-ui 11 | //= require pwn-fx 12 | //= require foundation 13 | // 14 | // Application assets. 15 | //= require_tree . 16 | -------------------------------------------------------------------------------- /app/assets/javascripts/cable.coffee: -------------------------------------------------------------------------------- 1 | # Action Cable provides the framework to deal with WebSockets in Rails. 2 | # You can generate new channels where WebSocket features live using the rails generate channel command. 3 | # 4 | # Turn on the cable connection by removing the comments after the require statements (and ensure it's also on in config/routes.rb). 5 | # 6 | #= require action_cable 7 | #= require_self 8 | #= require_tree ./channels 9 | # 10 | # @App ||= {} 11 | # App.cable = ActionCable.createConsumer() 12 | -------------------------------------------------------------------------------- /app/assets/javascripts/channels/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/assets/javascripts/channels/.keep -------------------------------------------------------------------------------- /app/assets/javascripts/grade-index.js.coffee: -------------------------------------------------------------------------------- 1 | $ -> 2 | $('.comments-toggle-button').click -> 3 | gradeList = $(this).closest('.assignment-name').next('.grades-list') 4 | gradeList.toggleClass 'show-comments' 5 | if gradeList.hasClass 'show-comments' 6 | $(this).html('Hide Comments') 7 | else 8 | $(this).html('Show Comments') 9 | -------------------------------------------------------------------------------- /app/assets/javascripts/initialize_clipboard.coffee: -------------------------------------------------------------------------------- 1 | $ -> 2 | clipboard = new Clipboard 'button[data-clipboard-target]' 3 | clipboard.on 'success', (event) -> 4 | # TODO(pwnall): show some notification 5 | clipboard.on 'error', (event) -> 6 | # TODO(pwnall): show some notification 7 | -------------------------------------------------------------------------------- /app/assets/javascripts/initialize_foundation.coffee: -------------------------------------------------------------------------------- 1 | $(document).foundation() 2 | 3 | $(document).on 'change.zf.tabs', (event) -> 4 | if href = $('.is-active a', event.target).attr 'href' 5 | if window.location.hash != href 6 | window.history.pushState null, '', href 7 | true 8 | 9 | onHashChange = -> 10 | hash = window.location.hash 11 | if hash 12 | # Open the Foundation tab whose URL matches the requested hash. 13 | # http://foundation.zurb.com/sites/docs/tabs.html 14 | $("[data-tabs] [href=\"#{hash}\"]").click() 15 | true 16 | $(window).on 'hashchange', onHashChange 17 | onHashChange() 18 | -------------------------------------------------------------------------------- /app/assets/javascripts/initialize_pwnfx.js.coffee: -------------------------------------------------------------------------------- 1 | PwnFx.hiddenClassName = 'hide' 2 | -------------------------------------------------------------------------------- /app/assets/javascripts/submission-dashboard.js.coffee: -------------------------------------------------------------------------------- 1 | $ -> 2 | $('.collaborator-form-toggle-button').click -> 3 | collaboratorForm = $(this).closest('.collaborators-list'). 4 | next('.new-collaborator-form') 5 | collaboratorForm.toggleClass 'hide' 6 | $(this).children('button.open-form').toggleClass 'hide' 7 | $(this).children('button.close-form').toggleClass 'hide' 8 | 9 | tabPanel = $(this).closest('.tabs-panel.is-active') 10 | tabPanel.css 'height', 'auto' 11 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css.scss: -------------------------------------------------------------------------------- 1 | @import "font-awesome"; 2 | @import "foundation_and_overrides"; 3 | @import "mixins/**/*"; 4 | @import "web/**/*"; 5 | -------------------------------------------------------------------------------- /app/assets/stylesheets/mixins/lists.scss: -------------------------------------------------------------------------------- 1 | @mixin tab-panel-list-item { 2 | @include flex-grid-row(null, null, null, true); 3 | margin-bottom: 0.5rem; 4 | padding: 0.2rem 0; 5 | align-items: center; 6 | border: 1px solid $medium-gray; 7 | border-radius: $global-radius; 8 | } 9 | -------------------------------------------------------------------------------- /app/assets/stylesheets/mixins/tables.scss: -------------------------------------------------------------------------------- 1 | // Tables for quickly looking up students by name and submitting data. 2 | @mixin quick-fill-table { 3 | $indicator-width: 2em; 4 | 5 | thead { 6 | background: none; 7 | border: none; 8 | 9 | span#search-wrapper { 10 | display: inline-block; 11 | padding-right: 1rem; 12 | } 13 | input[type="search"], p { 14 | margin: 0; 15 | } 16 | } 17 | tbody { 18 | border: none; 19 | 20 | th[scope="row"] { 21 | font-weight: normal; 22 | text-align: left; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/activity_feed.scss: -------------------------------------------------------------------------------- 1 | .feed-item { 2 | .media-object-section:first-child { 3 | padding: 0.25rem 0.5rem 0 0; 4 | } 5 | p { 6 | margin: 0; 7 | line-height: 1.4; 8 | } 9 | .headline { 10 | font-weight: 500; 11 | } 12 | .time-with-actions { 13 | @include text-with-actions($title-action-spacing: 0.5rem, 14 | $row-wrap-spacing: 0); 15 | line-height: 1.3; 16 | 17 | > .time { 18 | margin-bottom: 0; 19 | font-style: italic; 20 | color: $dark-gray; 21 | } 22 | } 23 | .replies > .feed-item { 24 | margin: 0.5rem 0 0 0; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/alerts.scss: -------------------------------------------------------------------------------- 1 | .status-bar { 2 | @include callout-base; 3 | margin: 0; 4 | } 5 | #flash-notice-box { 6 | @include callout-style($primary-color); 7 | } 8 | #flash-warning-box { 9 | @include callout-style($warning-color); 10 | } 11 | #flash-alert-box { 12 | @include callout-style($alert-color); 13 | } 14 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/analyses.scss: -------------------------------------------------------------------------------- 1 | .analysis-status-icon { 2 | padding: 0 0.4rem; 3 | 4 | @each $name, $color in $foundation-palette { 5 | &.#{$name} { 6 | color: $color; 7 | } 8 | } 9 | } 10 | section.analysis-logs { 11 | margin-bottom: 2rem; 12 | } 13 | article.log, article.private-log { 14 | margin: 1rem 0; 15 | 16 | p { 17 | margin-bottom: 0; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/api_tokens.scss: -------------------------------------------------------------------------------- 1 | #api-token-actions { 2 | @include flex-grid-row(null, null, null, true); 3 | margin-top: 3rem; 4 | margin-bottom: 1rem; 5 | 6 | > .input-group { 7 | @include flex-grid-column(); 8 | } 9 | > .link-button-wrapper { 10 | @include flex-grid-column(shrink); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/assignment_builder.scss: -------------------------------------------------------------------------------- 1 | .assignment-builder { 2 | #docker-analyzer-help.badge { 3 | line-height: 1; 4 | vertical-align: text-bottom; 5 | } 6 | p.help-text { 7 | margin: 0; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/assignments_index.scss: -------------------------------------------------------------------------------- 1 | ol#assignments-list { 2 | li.submission-dashboard { 3 | margin-bottom: 1rem; 4 | padding-bottom: 1rem; 5 | border-bottom: 1px solid $primary-color; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/attendance_roster.scss: -------------------------------------------------------------------------------- 1 | table#attendances-table { 2 | @include quick-fill-table; 3 | 4 | td.attendance { 5 | text-align: center; 6 | 7 | input[type="checkbox"] { 8 | margin: 0.5em 0 0.5em 2em; 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/colors.scss: -------------------------------------------------------------------------------- 1 | $promoted-color: #ffe500; 2 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/deadline_extensions.scss: -------------------------------------------------------------------------------- 1 | table.extensions { 2 | tr.extension { 3 | td.extended-deadline { 4 | .date, .time, .in-words { 5 | display: inline-block; 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/grades.scss: -------------------------------------------------------------------------------- 1 | .stats-summary { 2 | &.high-precision { 3 | min-width: 8rem; 4 | } 5 | &.low-precision { 6 | min-width: 5rem; 7 | } 8 | min-width: 7rem; 9 | @include flex-grid-row(null, null, null, true); 10 | 11 | .score, .max-score, .current-count, .max-count { 12 | @include flex-grid-column(expand, 0.5rem); 13 | text-align: right; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/headers.scss: -------------------------------------------------------------------------------- 1 | h2, h3, h4 { 2 | &.title-with-actions { 3 | @include text-with-actions; 4 | } 5 | .labels { 6 | vertical-align: text-bottom; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/links.scss: -------------------------------------------------------------------------------- 1 | a.contains-tooltip .has-tip { 2 | cursor: pointer; 3 | } 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/lists.scss: -------------------------------------------------------------------------------- 1 | ol { 2 | li .actions { 3 | padding-left: 1rem; 4 | text-align: right; 5 | 6 | > form { 7 | display: inline; 8 | } 9 | .link-button-wrapper > a, .button, form.button_to > input[type="submit"] { 10 | margin: 0.25rem; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/profile_photos.scss: -------------------------------------------------------------------------------- 1 | .profile-photo-container { 2 | display: inline-block; 3 | margin-right: 0.8rem; 4 | 5 | > img { 6 | display: block; 7 | } 8 | } 9 | // Image generated by user_image_tag helper method. 10 | img.profile-image { 11 | border-radius: $global-radius; 12 | margin-right: 0.25rem; 13 | } 14 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/profiles.scss: -------------------------------------------------------------------------------- 1 | .profile-header { 2 | margin-bottom: 1rem; 3 | 4 | > h2 { 5 | display: inline-flex; 6 | vertical-align: top; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/pwnstyles.scss: -------------------------------------------------------------------------------- 1 | .destroyed-blur { 2 | opacity: 0.25; 3 | } 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/recitation_sections.scss: -------------------------------------------------------------------------------- 1 | form.recitation-section-form { 2 | input.serial-number { 3 | width: 4rem; 4 | } 5 | input.location { 6 | width: 10rem; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/registrations.scss: -------------------------------------------------------------------------------- 1 | h2.registrant-name { 2 | margin-bottom: 0; 3 | } 4 | .registrant-email { 5 | color: $secondary-color; 6 | } 7 | section.registration-settings, section.prerequisite-answers, 8 | section.recitation-section, section.recitation-conflicts { 9 | margin: 1rem 0 2rem; 10 | } 11 | .registration-setting, .prerequisite { 12 | @include flex-grid-row(null, null, null, true); 13 | margin-bottom: 0.5rem; 14 | 15 | .setting-name, .prerequisite-question { 16 | @include flex-grid-column(2); 17 | font-weight: bold; 18 | } 19 | .setting-value, .prerequisite-answer { 20 | @include flex-grid-column(6); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/role_requests.scss: -------------------------------------------------------------------------------- 1 | section.staff-registration-forms { 2 | @include flex-grid-row(null, null, null, true); 3 | margin-top: 2rem; 4 | 5 | article.staff-role-form { 6 | @include flex-grid-column(expand); 7 | display: flex; 8 | flex-flow: row wrap; 9 | 10 | > h3, > p, > div { 11 | flex: 1 1 100%; 12 | } 13 | 14 | .form-wrapper { 15 | align-self: flex-end; 16 | margin-top: 1rem 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/sidebar_menu.scss: -------------------------------------------------------------------------------- 1 | section#menu-sidebar { 2 | li > a > i.fa, li > a > span.stacked-icons { 3 | vertical-align: baseline; 4 | margin-right: $menu-icon-spacing; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/smtp_servers.scss: -------------------------------------------------------------------------------- 1 | #smtp-server-form { 2 | input.port { 3 | width: 5rem; 4 | } 5 | input.domain { 6 | width: 10rem; 7 | } 8 | input.hostname, select.auth-kind, input.username, input.password { 9 | width: 20rem; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/survey_questions.scss: -------------------------------------------------------------------------------- 1 | .survey-builder { 2 | .step-size, .scale-limit { 3 | width: 4rem; 4 | } 5 | .scale-label { 6 | width: 10rem; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/surveys.scss: -------------------------------------------------------------------------------- 1 | section.survey { 2 | margin-bottom: 2rem; 3 | padding-bottom: 1.5rem; 4 | border-bottom: 1px solid $secondary-color; 5 | } 6 | 7 | .privacy-policy { 8 | @include flex-grid-row(null, null, null, true); 9 | font-weight: bold; 10 | } 11 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/team_partitions.scss: -------------------------------------------------------------------------------- 1 | #team-partition-form { 2 | .min-size, .max-size, .optimal-size { 3 | width: 4rem; 4 | } 5 | } 6 | .team-list { 7 | @include flex-grid-row(null, null, null, true); 8 | justify-content: space-between; 9 | 10 | .team-roster { 11 | @include flex-grid-column(shrink); 12 | margin-bottom: 2rem; 13 | 14 | .button { 15 | white-space: nowrap; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/text.scss: -------------------------------------------------------------------------------- 1 | .optional-text { 2 | color: $secondary-color; 3 | } 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/time_slots.scss: -------------------------------------------------------------------------------- 1 | ol.time-slot-list { 2 | margin-bottom: 0; 3 | 4 | .time-slot-day { 5 | display: inline-block; 6 | padding-right: 0.5rem; 7 | width: 3.5rem; 8 | text-align: right; 9 | font-weight: bold; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/assets/stylesheets/web/tooltips.scss: -------------------------------------------------------------------------------- 1 | span.has-tip { 2 | border: none; 3 | } 4 | -------------------------------------------------------------------------------- /app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. Action Cable runs in an EventMachine loop that does not support auto reloading. 2 | module ApplicationCable 3 | class Channel < ActionCable::Channel::Base 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. Action Cable runs in an EventMachine loop that does not support auto reloading. 2 | module ApplicationCable 3 | class Connection < ActionCable::Connection::Base 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/controllers/analyses_controller.rb: -------------------------------------------------------------------------------- 1 | class AnalysesController < ApplicationController 2 | before_action :set_current_course 3 | before_action :authenticated_as_user, only: :show 4 | 5 | # GET /6.006/analyses/1 6 | def show 7 | @analysis = Analysis.find params[:id] 8 | @author = @analysis.submission.subject 9 | return bounce_user unless @analysis.can_read? current_user 10 | 11 | respond_to do |format| 12 | format.html # show.html.erb 13 | end 14 | end 15 | 16 | # XHR GET /6.006/analyses/1/refresh 17 | def refresh 18 | @analysis = Analysis.find params[:id] 19 | return bounce_user unless @analysis.can_read? current_user 20 | render layout: false 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /app/controllers/api_docs_controller.rb: -------------------------------------------------------------------------------- 1 | class ApiDocsController < ApplicationController 2 | before_action :authenticated_as_user 3 | skip_before_action :verify_authenticity_token 4 | 5 | # GET /_/api_docs 6 | def index 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | include FileBlobs::ActionControllerDataStreamingExtensions 3 | 4 | # Prevent CSRF attacks by raising an exception. 5 | # For APIs, you may want to use :null_session instead. 6 | protect_from_forgery with: :exception 7 | 8 | authenticates_using_session 9 | 10 | before_action do 11 | if current_user && current_user.email_credential.verified? 12 | Rack::MiniProfiler.authorize_request if current_user.admin? 13 | end 14 | end 15 | 16 | include CourseFilters 17 | include UserFilters 18 | include RouteHelpers 19 | end 20 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /app/controllers/concerns/sidebar_layout.rb: -------------------------------------------------------------------------------- 1 | # Choose the 'assignments' or 'session' layout, depending on the current user. 2 | module SidebarLayout 3 | extend ActiveSupport::Concern 4 | 5 | included do 6 | layout lambda { 7 | if current_course.is_staff?(current_user) || current_user.admin? 8 | 'assignments' 9 | else 10 | 'session' 11 | end 12 | } 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/controllers/concerns/user_filters.rb: -------------------------------------------------------------------------------- 1 | module UserFilters 2 | # (before-action) ensures that the session belongs to a registered user 3 | def authenticated_as_user 4 | return bounce_user if current_user.nil? 5 | return true if current_user.email_credential.verified? 6 | 7 | # Inactive user. 8 | set_session_current_user nil 9 | bounce_user 10 | end 11 | 12 | # (before-action) ensures that the session belongs to an administrator 13 | def authenticated_as_admin 14 | authenticated_as_user 15 | return if performed? 16 | 17 | bounce_user unless current_user.admin? 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /app/controllers/crash_controller.rb: -------------------------------------------------------------------------------- 1 | class CrashController < ApplicationController 2 | before_action :authenticated_as_admin 3 | 4 | # GET /_/crash 5 | def crash 6 | raise Exception, "This is a crash handling test." 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/controllers/feedback_controller.rb: -------------------------------------------------------------------------------- 1 | class FeedbackController < ApplicationController 2 | # GET /_/feedback/new 3 | def new 4 | title = 'User Feedback: ' 5 | body = <= Time.current 6 | "(in #{time})" 7 | else 8 | "(#{time} ago)" 9 | end 10 | end 11 | 12 | # The class of the element containing the assignment's original deadline. 13 | def deadline_class(assignment, user) 14 | user.extension_for(assignment) ? 'inapplicable' : 'applicable' 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/helpers/email_resolvers_helper.rb: -------------------------------------------------------------------------------- 1 | module EmailResolversHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/grades_helper.rb: -------------------------------------------------------------------------------- 1 | module GradesHelper 2 | # Option tags for the assignments in the given course that will be graded. 3 | def gradeable_assignment_options(course, selected) 4 | assignments = course.assignments.by_deadline 5 | options_from_collection_for_select assignments, :id, :name, selected.id 6 | end 7 | 8 | # The weighted sum of all the scores in an array of grades. 9 | def grades_sum(grades) 10 | grades.map { |grade| grade ? grade.score * grade.metric.weight : 0 }.sum 11 | end 12 | 13 | # The text shown to a student looking at a grade. 14 | def grade_display_text(grade) 15 | (grade && grade.score) || 'N' 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/helpers/profile_photos_helper.rb: -------------------------------------------------------------------------------- 1 | module ProfilePhotosHelper 2 | # Send users here to get a Gravatar that shows up as their profile photo. 3 | def gravatar_signup_url(user) 4 | "https://en.gravatar.com/site/signup/#{CGI.escape(user.email)}" 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /app/helpers/recitation_sections_helper.rb: -------------------------------------------------------------------------------- 1 | module RecitationSectionsHelper 2 | def recitation_leader_label(recitation) 3 | leader_name = recitation.leader ? recitation.leader.name : '(no leader)' 4 | end 5 | 6 | def recitation_name_label(recitation) 7 | "#{recitation.location} #{recitation_leader_label recitation}" 8 | end 9 | 10 | def display_name_for_recitation_section(recitation, format = :short) 11 | return 'Unassigned' unless recitation 12 | "R#{'%02d' % recitation.serial} - #{recitation.location} #{recitation.leader.display_name_for}" 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/helpers/smtp_servers_helper.rb: -------------------------------------------------------------------------------- 1 | module SmtpServersHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/surveys_helper.rb: -------------------------------------------------------------------------------- 1 | module SurveysHelper 2 | # The text to show on the button that (un)releasees a survey. 3 | def survey_release_text(survey) 4 | survey.released? ? 'Pull release' : 'Release' 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /app/helpers/users_helper.rb: -------------------------------------------------------------------------------- 1 | module UsersHelper 2 | def user_image_tag(user, options = {}) 3 | user = current_user if user.instance_of? Team 4 | size = options[:size] || :small 5 | size_pixels = {small: 20, small_medium: 30, medium: 40, large: 100}[size] 6 | klass = options[:class] 7 | 8 | url = Gravatar.new(user.email).image_url size: size_pixels, secure: true, 9 | default: :retro 10 | image_tag url, alt: "avatar for #{user.name}", 11 | class: "#{klass} profile-image", 12 | style: "width: #{size_pixels}px; height: #{size_pixels}px;" 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | end 3 | -------------------------------------------------------------------------------- /app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | layout 'mailer' 3 | 4 | include DynamicSmtpServer 5 | end 6 | -------------------------------------------------------------------------------- /app/mailers/concerns/dynamic_smtp_server.rb: -------------------------------------------------------------------------------- 1 | # Included by the mailers that use SMTP settings defined in SmtpServer. 2 | module DynamicSmtpServer 3 | extend ActiveSupport::Concern 4 | 5 | def set_smtp 6 | smtp_server = SmtpServer.first 7 | if smtp_server.nil? 8 | mail.perform_deliveries = false 9 | else 10 | mail.delivery_method.settings.merge! smtp_server.action_mailer_options 11 | mail.from = smtp_server.from 12 | end 13 | end 14 | private :set_smtp 15 | 16 | included do 17 | after_action :set_smtp 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /app/mailers/exception_mailer.rb: -------------------------------------------------------------------------------- 1 | class ExceptionMailer < ApplicationMailer 2 | end 3 | -------------------------------------------------------------------------------- /app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | self.abstract_class = true 3 | end 4 | -------------------------------------------------------------------------------- /app/models/concerns/average_score.rb: -------------------------------------------------------------------------------- 1 | require 'active_support' 2 | 3 | # Calculations handling scores on Assignments and AssignmentMetrics. 4 | module AverageScore 5 | extend ActiveSupport::Concern 6 | 7 | included do 8 | # The average score converted to a number out of 100. 9 | def average_score_percentage 10 | return nil if respond_to?(:metrics) && metrics.empty? 11 | return 0 if max_score.zero? 12 | average_score * 100 / max_score.to_f 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/models/credential.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: credentials 4 | # 5 | # id :integer not null, primary key 6 | # user_id :integer not null 7 | # type :string(32) not null 8 | # name :string(128) 9 | # updated_at :datetime not null 10 | # key :binary 11 | # 12 | 13 | # Credential used to prove the identity of a user. 14 | class Credential < ApplicationRecord 15 | include Authpwn::CredentialModel 16 | 17 | # Add your extensions to the Credential class here. 18 | end 19 | 20 | # namespace for all Credential subclasses 21 | module Credentials 22 | 23 | # Add your custom Credential types here. 24 | 25 | end 26 | -------------------------------------------------------------------------------- /app/models/invitation.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: invitations 4 | # 5 | # id :integer not null, primary key 6 | # inviter_id :integer 7 | # invitee_id :integer 8 | # team_id :integer 9 | # created_at :datetime not null 10 | # updated_at :datetime not null 11 | # 12 | 13 | class Invitation < ApplicationRecord 14 | end 15 | -------------------------------------------------------------------------------- /app/models/session.rb: -------------------------------------------------------------------------------- 1 | # Virtual model for the information collected when a user signs in. 2 | class Session 3 | include Authpwn::SessionModel 4 | 5 | # Add your extensions to the Session class here. 6 | end 7 | -------------------------------------------------------------------------------- /app/views/analyses/_status_icon.html.erb: -------------------------------------------------------------------------------- 1 | <%= analysis_status_tag analysis %> 2 | -------------------------------------------------------------------------------- /app/views/analyses/refresh.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'analyses/status_icon', analysis: @analysis %> 2 | -------------------------------------------------------------------------------- /app/views/api/assignments.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.array! @assignments do |assignment| 2 | json.name assignment.name 3 | json.stated_deadline assignment.due_at.iso8601 4 | json.due_at assignment.due_at_for(current_user).iso8601 5 | 6 | json.deliverables assignment.deliverables do |deliverable| 7 | json.id deliverable.id.to_s 8 | json.name deliverable.name 9 | end 10 | 11 | json.metrics assignment.metrics do |metric| 12 | next unless metric.can_read? current_user 13 | json.name metric.name 14 | json.max_score metric.max_score 15 | json.weight metric.weight.to_f 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/views/api/submissions.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.array! @submissions do |submission| 2 | json.deliverable_id submission.deliverable_id.to_s 3 | json.submitted_at submission.created_at.iso8601 4 | json.analysis do 5 | json.status submission.analysis.status 6 | json.scores submission.analysis.scores 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/views/api/user_info.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.email @user.email 2 | json.profile do 3 | json.name @user.profile.name 4 | json.nickname @user.profile.nickname 5 | end 6 | json.registrations @user.registrations do |registration| 7 | json.course registration.course.number 8 | json.for_credit registration.for_credit 9 | end 10 | json.roles @user.roles do |role| 11 | json.name role.name 12 | json.course role.course && role.course.number 13 | end 14 | -------------------------------------------------------------------------------- /app/views/assignments/_exam_builder.html.erb: -------------------------------------------------------------------------------- 1 |
3 | <%= f.fields_for :exam do |ef| %> 4 | <%= render 'assignments/exam_sessions_builder', f: ef %> 5 | <% end %> 6 |
7 | -------------------------------------------------------------------------------- /app/views/assignments/_exam_sessions_dashboard.html.erb: -------------------------------------------------------------------------------- 1 | <% if exam.requires_confirmation? %> 2 |

A staff member must confirm a student's attendance before the student can 3 | view and start the exam.

4 | <% else %> 5 |

Students do not require their attendance to be confirmed, and can begin the 6 | exam as soon as the session they have selected begins.

7 | <% end %> 8 | 9 |
10 | <% if exam.exam_sessions.length > 0 %> 11 | <%= render 'exam_sessions/list', exam_sessions: exam.exam_sessions %> 12 | <% else %> 13 |

No exam sessions have been set up yet.

14 | <% end %> 15 |
16 | -------------------------------------------------------------------------------- /app/views/assignments/_extensions_dashboard.html.erb: -------------------------------------------------------------------------------- 1 | 2 | <%= link_to assignment_extensions_path(assignment_id: assignment, 3 | course_id: assignment.course) do %> 4 | <%= edit_icon_tag %> Grant extensions 5 | <% end %> 6 | 7 | 8 |

<%= assignment.extensions.length %> extension(s) granted.

9 | -------------------------------------------------------------------------------- /app/views/assignments/_list.html.erb: -------------------------------------------------------------------------------- 1 |
    2 | <% assignments.each do |assignment| %> 3 |
  1. 4 | <%= render 'assignments/show', assignment: assignment %> 5 |
  2. 6 | <% end %> 7 |
8 | -------------------------------------------------------------------------------- /app/views/assignments/_recitations_dashboard.html.erb: -------------------------------------------------------------------------------- 1 |

2 | <%= grades_icon_tag %> Recitation Grades 3 |

4 | 5 | 18 | -------------------------------------------------------------------------------- /app/views/assignments/_sidebar.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

3 | Assignments 4 | 5 | 6 | <%= link_to create_icon_tag, new_assignment_path( 7 | course_id: current_course), class: 'no-text' %> 8 | 9 | 10 |

11 | 12 | <%= render 'assignments/sidebar_list', 13 | assignments: current_course.assignments_for(current_user) %> 14 |
15 | -------------------------------------------------------------------------------- /app/views/assignments/index.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'assignments/list', assignments: @assignments %> 2 | -------------------------------------------------------------------------------- /app/views/assignments/index.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.array!(@assignments) do |assignment| 2 | json.extract! assignment, :id, :name 3 | end 4 | -------------------------------------------------------------------------------- /app/views/assignments/new.html.erb: -------------------------------------------------------------------------------- 1 |

New Assignment

2 | 3 | <%= foundation_form_for @assignment, url: polymorphic_path(@assignment, 4 | course_id: @assignment.course), 5 | html: { class: 'new-assignment-form' } do |f| %> 6 | <%= render 'assignments/fields', f: f %> 7 | 8 | <%= submit_button_tag do %> 9 | <%= build_icon_tag %> Build Assignment 10 | <% end %> 11 | <% end %> 12 | -------------------------------------------------------------------------------- /app/views/assignments/show.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'assignments/show', assignment: @assignment %> 2 | -------------------------------------------------------------------------------- /app/views/collaborations/_collaborator.html.erb: -------------------------------------------------------------------------------- 1 | 4 |
5 | <%= user_image_tag collaboration.collaborator, size: :small_medium %> 6 | <%= link_to collaboration_path(collaboration, 7 | course_id: collaboration.course), class: 'remove-collaborator', 8 | method: :delete do %> 9 | <%= fa_icon :times %> 10 | <% end %> 11 |
12 |
13 | -------------------------------------------------------------------------------- /app/views/collaborations/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= foundation_form_for new_collaboration(@collaboration, submission), 2 | url: submission_collaborations_path(course_id: submission.course, 3 | submission_id: submission) do |f| %> 4 | <%= f.input_group do %> 5 | <%= f.text_field :collaborator_email, placeholder: 'jdoe@mit.edu', 6 | size: 25 %> 7 | <%= f.button type: :submit do %> 8 | <%= create_icon_tag %> Add Collaborator 9 | <% end %> 10 | <% end %> 11 | <% end %> 12 | -------------------------------------------------------------------------------- /app/views/courses/edit.html.erb: -------------------------------------------------------------------------------- 1 |

Course Information

2 | 3 | <%= foundation_form_for @course do |f| %> 4 | <%= render 'courses/fields', f: f %> 5 | 6 | <%= submit_button_tag do %> 7 | <%= save_icon_tag %> Update Course 8 | <% end %> 9 | <% end %> 10 | -------------------------------------------------------------------------------- /app/views/courses/new.html.erb: -------------------------------------------------------------------------------- 1 |

New Course

2 | 3 | <%= foundation_form_for @course do |f| %> 4 | <%= render 'courses/fields', f: f %> 5 | 6 | <%= submit_button_tag do %> 7 | <%= save_icon_tag %> Save Course 8 | <% end %> 9 | <% end %> 10 | -------------------------------------------------------------------------------- /app/views/courses/show.html.erb: -------------------------------------------------------------------------------- 1 |

<%= @course.number %> <%= @course.title %>

2 | 3 | -------------------------------------------------------------------------------- /app/views/deadline_extensions/_fields.html.erb: -------------------------------------------------------------------------------- 1 | <%= fields_for extension, nil, builder: FoundationFormBuilder do |ef| %> 2 | 3 | <%= ef.collection_select :user_exuid, 4 | current_course.students.without_extensions_for(@assignment).by_name, 5 | :to_param, :name, { prompt: 'Select a student' }, { required: true, 6 | form: 'extension-form' } %> 7 | 8 | 9 | <%= ef.datetime_local_field :due_at, required: true, step: 1, 10 | form: 'extension-form' %> 11 | 12 | 13 | <%= button_tag type: :submit, form: 'extension-form' do %> 14 | <%= create_icon_tag %> Grant Extension 15 | <% end %> 16 | 17 | <% end %> 18 | -------------------------------------------------------------------------------- /app/views/deliverables/_dashboard_submission_list.html.erb: -------------------------------------------------------------------------------- 1 |
    2 | <%= render partial: 'deliverables/submission_figure', 3 | collection: deliverable.submissions, as: :submission %> 4 | <% if deliverable.submissions.any? { |s| s.analysis && s.analysis.status_will_change? } %> 5 | <%= content_tag :li, ajax_loading_icon_tag, data: { 6 | pwnfx_delayed: 'submission-states', pwnfx_delayed_method: 'GET', 7 | pwnfx_delayed_scope: 'submissions-list', pwnfx_delayed_ms: 5000, 8 | pwnfx_delayed_url: submission_dashboard_deliverable_path(deliverable, 9 | course_id: deliverable.course) } %> 10 | <% end %> 11 |
12 | -------------------------------------------------------------------------------- /app/views/deliverables/_no_submission.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 | <%= invalid_icon_tag %> No submission yet 4 | 5 |
6 | -------------------------------------------------------------------------------- /app/views/deliverables/_student_submission_list.html.erb: -------------------------------------------------------------------------------- 1 |

2 | <%= deliverable.description %> 3 |

4 | 5 | <% if deliverable.assignment.can_submit?(current_user) %> 6 | <%= render 'submissions/form', 7 | submission: Submission.new(deliverable: deliverable) %> 8 | <% end %> 9 | 10 |
11 | <% if submissions.length > 0 %> 12 |
    13 | <% submissions.map do |submission| %> 14 | <%= render 'deliverables/student_submission_list_entry', 15 | submission: submission %> 16 | <% end %> 17 |
18 | <% else %> 19 | <%= render 'deliverables/no_submission' %> 20 | <% end %> 21 |
22 | -------------------------------------------------------------------------------- /app/views/deliverables/_submission_figure.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 | <% if submission.analysis %> 3 | <%= link_to submission_figure(submission), analysis_path(submission.analysis, 4 | course_id: submission.course) %> 5 | <% else %> 6 | <%= submission_figure submission %> 7 | <% end %> 8 |
  • 9 | -------------------------------------------------------------------------------- /app/views/deliverables/submission_dashboard.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'deliverables/dashboard_submission_list', 2 | deliverable: @deliverable %> 3 | -------------------------------------------------------------------------------- /app/views/email_resolvers/edit.html.erb: -------------------------------------------------------------------------------- 1 |

    Email Resolver Configuration

    2 | 3 | <%= render 'form', email_resolver: @email_resolver %> 4 | -------------------------------------------------------------------------------- /app/views/email_resolvers/new.html.erb: -------------------------------------------------------------------------------- 1 |

    New Email Resolver

    2 | 3 | <%= render 'form', email_resolver: @email_resolver %> 4 | -------------------------------------------------------------------------------- /app/views/email_resolvers/show.html.erb: -------------------------------------------------------------------------------- 1 |

    @<%= @email_resolver.domain %> E-mail Resolver

    2 | -------------------------------------------------------------------------------- /app/views/exam_attendances/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= check_box_tag :confirmed, '1', attendance.confirmed? %> 2 | 3 | -------------------------------------------------------------------------------- /app/views/exam_attendances/edit.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'exam_attendances/form', attendance: @attendance %> 2 | -------------------------------------------------------------------------------- /app/views/grades/_individual_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= number_field_tag :score, grade && grade.score, min: 0, step: :any %> 2 | 3 | / <%= metric.max_score %> 4 | 5 | 6 |
    7 | <%= text_area_tag :comment, comment && comment.text, size: '15x3', 8 | placeholder: "Type 'c' to add a comment", tabindex: -1 %> 9 |
    10 | -------------------------------------------------------------------------------- /app/views/grades/edit.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'grades/individual_form', metric: @metric, grade: @grade, 2 | comment: @comment %> 3 | -------------------------------------------------------------------------------- /app/views/grades/editor_blank.html.erb: -------------------------------------------------------------------------------- 1 |

    Grade Entry

    2 | 3 |

    4 | <%= invalid_icon_tag %> No assignments defined. 5 |

    6 | -------------------------------------------------------------------------------- /app/views/grades/request_missing.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'grades/request_missing', assignments: @assignments %> 2 | -------------------------------------------------------------------------------- /app/views/layouts/_analytics.html.erb: -------------------------------------------------------------------------------- 1 | <% if current_course && current_course.ga_account %> 2 | 14 | <% end %> 15 | -------------------------------------------------------------------------------- /app/views/layouts/_footer.html.erb: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /app/views/layouts/_groups.html.erb: -------------------------------------------------------------------------------- 1 | <% unless current_user.teams.empty? %> 2 |

    Groups

    3 | 4 |
    5 | <% current_user.teams.includes(:partition, :users => :profile).sort_by(&:created_at). 6 | reverse.each do |team| %> 7 | <%= render team %> 8 | <% end %> 9 |
    10 | <% end %> 11 | -------------------------------------------------------------------------------- /app/views/layouts/_header.html.erb: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /app/views/layouts/_newsfeed.html.erb: -------------------------------------------------------------------------------- 1 |

    Activity Feed

    2 | 3 | <% FeedItem.for(current_user).each do |item| %> 4 | <% next if @news_flavor and item.flavor != @news_flavor %> 5 | <%= render 'layouts/feed_item', feed_item: item %> 6 | <% end %> 7 | -------------------------------------------------------------------------------- /app/views/layouts/assignments.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :sidebar do %> 2 | <%= render 'assignments/sidebar' %> 3 | <% end %> 4 | <%= render template: 'layouts/application' %> 5 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | <%= yield %> 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /app/views/layouts/session.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :sidebar do %> 2 | <%= render 'session/sidebar' %> 3 | <% end %> 4 | <%= render template: 'layouts/application' %> 5 | -------------------------------------------------------------------------------- /app/views/layouts/teams.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :sidebar do %> 2 | <%= render 'teams/sidebar' %> 3 | <% end %> 4 | <%= render template: 'layouts/application' %> 5 | -------------------------------------------------------------------------------- /app/views/menu/_for_grader.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 | <%= link_to root_path do %> 3 | <%= feed_icon_tag %> Activity 4 | <% end %> 5 |
  • 6 |
  • 7 | <%= link_to editor_grades_path(course_id: current_course) do %> 8 | <%= edit_icon_tag %> Enter Grades 9 | <% end %> 10 |
  • 11 | -------------------------------------------------------------------------------- /app/views/menu/_for_guided.html.erb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/views/menu/_for_guided.html.erb -------------------------------------------------------------------------------- /app/views/menu/_for_staff.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 | <%= link_to root_path do %> 3 | <%= feed_icon_tag %> Activity 4 | <% end %> 5 |
  • 6 | 7 | <%= render 'menu/homework' %> 8 | <%= render 'menu/grades' %> 9 | <%= render 'menu/course' %> 10 | 11 | -------------------------------------------------------------------------------- /app/views/menu/_menu.html.erb: -------------------------------------------------------------------------------- 1 | <%= render menu_type(current_user, current_course) %> 2 | 3 |
  • 4 | <%= link_to current_user do %> 5 | <%= user_image_tag current_user %> 6 | 7 | <%= current_user.name %> 8 | 9 | ▼ 10 | <% end %> 11 |
      12 |
    1. 13 | <%= link_to 'Profile', current_user %> 14 |
    2. 15 |
    3. 16 | <%= link_to 'Change Password', change_password_session_path %> 17 |
    4. 18 |
    5. 19 | <%= link_to 'Sign out', session_path, :method => :delete %> 20 |
    6. 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/views/menu/_staff.html.erb: -------------------------------------------------------------------------------- 1 |
    7. 2 | <%= link_to root_path do %> 3 | <%= feed_icon_tag %> Activity 4 | <% end %> 5 |
    8. 6 | <%= render 'menu/homework' %> 7 | <%= render 'menu/grades' %> 8 | <%= render 'menu/course' %> 9 | 10 | -------------------------------------------------------------------------------- /app/views/prerequisites/_fields.html.erb: -------------------------------------------------------------------------------- 1 |
      2 | <%= f.text_field :prerequisite_number, placeholder: '6.01', 3 | label: 'Course number(s)' %> 4 | <%= f.text_field :waiver_question, placeholder: 'Programming experience', 5 | label: 'Question if Missing Prerequisite' %> 6 |
      7 | -------------------------------------------------------------------------------- /app/views/prerequisites/edit.html.erb: -------------------------------------------------------------------------------- 1 |

      Editing Prerequisite

      2 | 3 | <%= foundation_form_for @prerequisite, url: prerequisite_url(@prerequisite, 4 | course_id: @prerequisite.course) do |f| %> 5 | 6 | <%= render 'prerequisites/fields', f: f %> 7 | 8 | <%= submit_button_tag do %> 9 | <%= save_icon_tag %> Update Prerequisite 10 | <% end %> 11 | <% end %> 12 | -------------------------------------------------------------------------------- /app/views/prerequisites/new.html.erb: -------------------------------------------------------------------------------- 1 |

      Add Prerequisite

      2 | 3 | <%= foundation_form_for @prerequisite, url: prerequisites_url(@prerequisite, 4 | course_id: @prerequisite.course) do |f| %> 5 | 6 | <%= render 'prerequisites/fields', f: f %> 7 | 8 | <%= submit_button_tag do %> 9 | <%= save_icon_tag %> Save Prerequisite 10 | <% end %> 11 | <% end %> 12 | -------------------------------------------------------------------------------- /app/views/proc_analyzers/_fields.html.erb: -------------------------------------------------------------------------------- 1 |
      2 |
      3 |

      Built-in Analyzer Parameters

      4 | <%= f.select :message_name, proc_analyzer_messages_for_select, 5 | label: 'Built-in analyzer' %> 6 | <%= f.input_field_set label: 'Auto grading' do %> 7 | <%= f.check_box :auto_grading, 8 | label: 'invalid submissions get 0 (zero) grades' %> 9 | <% end %> 10 |
      11 |
      12 | -------------------------------------------------------------------------------- /app/views/profile_photos/_for_user.html.erb: -------------------------------------------------------------------------------- 1 |
      2 | <%= user_image_tag user, size: :large %> 3 | <% if user.profile and user.profile.can_edit?(current_user) %> 4 | <%= link_to gravatar_signup_url(user) do %> 5 | Change Photo 6 | <% end %> 7 | <% end %> 8 |
      9 | -------------------------------------------------------------------------------- /app/views/profile_photos/_form.html.erb: -------------------------------------------------------------------------------- 1 |
      2 | <%= form_for @profile_photo, :html => {:multipart => true} do |f| %> 3 | <%= f.error_messages %> 4 | <%= f.hidden_field :profile_id %> 5 | 6 |
      7 |
      <%= f.label :pic, 'Photo file' %>
      8 |
      9 | <%= f.file_field :pic %> 10 | 11 | Use a PNG or JPEG file. Maximum size 1Mb. 12 | 13 |
      14 |
      15 | 16 |

      17 | Every registered user can see this. 18 |

      19 | 20 | <%= f.submit 'Upload' %> 21 | 22 | <% end %> 23 |
      24 | -------------------------------------------------------------------------------- /app/views/profile_photos/edit.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'profile_photos/form' %> 2 | -------------------------------------------------------------------------------- /app/views/profile_photos/edit.js.rjs: -------------------------------------------------------------------------------- 1 | page.select('.profile-photo-container').each do |element| 2 | element.replace render('profile_photos/form') 3 | end 4 | -------------------------------------------------------------------------------- /app/views/profile_photos/index.html.erb: -------------------------------------------------------------------------------- 1 |

      Listing profile_photos

      2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | <% @profile_photos.each do |profile_photo| %> 12 | 13 | 14 | 15 | 16 | 20 | 21 | <% end %> 22 |
      Pic
      <%= profile_photo.pic %><%= link_to 'Show', profile_photo %><%= link_to 'Edit', edit_profile_photo_path(profile_photo) %> 17 | <%= link_to 'Destroy', profile_photo, data: { confirm: 'Are you sure?' }, 18 | method: :delete %> 19 |
      23 | 24 |
      25 | 26 | <%= link_to 'New Profile photo', new_profile_photo_path %> 27 | -------------------------------------------------------------------------------- /app/views/profile_photos/new.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'profile_photos/form' %> 2 | -------------------------------------------------------------------------------- /app/views/profile_photos/show.html.erb: -------------------------------------------------------------------------------- 1 |

      <%= notice %>

      2 | 3 |

      4 | Pic: 5 | <%= @profile_photo.pic %> 6 |

      7 | 8 | 9 | <%= link_to 'Edit', edit_profile_photo_path(@profile_photo) %> | 10 | <%= link_to 'Back', profile_photos_path %> 11 | -------------------------------------------------------------------------------- /app/views/profiles/_fields.html.erb: -------------------------------------------------------------------------------- 1 |
      2 | <%= f.text_field :name, id: 'profile_name', label: 'Full name' %> 3 | <%= f.text_field :nickname, id: 'profile_nickname', label: 'Call me' %> 4 | <%= f.text_field :university, id: 'profile_university', label: 'School' %> 5 | <%= f.text_field :department, id: 'profile_department', label: 'Department' %> 6 | <%= f.select :year, profile_year_options(f.object), { label: 'Year' }, 7 | id: 'profile_year' %> 8 |
      9 | -------------------------------------------------------------------------------- /app/views/profiles/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= foundation_form_for profile.user do |fu| %> 2 | <%= fu.fields_for :profile do |f| %> 3 | <%= render 'profiles/fields', f: f %> 4 | <% end %> 5 | <%= submit_button_tag do %> 6 | <%= save_icon_tag %> Update Profile 7 | <% end %> 8 | <% end %> 9 | -------------------------------------------------------------------------------- /app/views/profiles/edit.html.erb: -------------------------------------------------------------------------------- 1 |

      2 | <%= user_image_tag @profile.user, size: :large %> 3 | <%= @profile.name %> 4 |

      5 | 6 | <%= render 'profile_photos/for_user', user: @profile.user %> 7 | 8 | <%= render 'profiles/form', profile: @profile %> 9 | -------------------------------------------------------------------------------- /app/views/quantitative_open_questions/_fields.html.erb: -------------------------------------------------------------------------------- 1 | <%= f.number_field :step_size, min: 0, step: 0.01, placeholder: '0.1', 2 | class: 'step-size', label: 'Step Size', 3 | help_text: 'the granularity for acceptable numerical answers' %> 4 | 5 | <%= f.hidden_field :type %> 6 | -------------------------------------------------------------------------------- /app/views/quantitative_scaled_questions/_fields.html.erb: -------------------------------------------------------------------------------- 1 | <%= f.number_field :scale_min, step: 1, placeholder: '1', required: true, 2 | class: 'scale-limit', label: 'Low value' %> 3 | <%= f.number_field :scale_max, step: 1, placeholder: '5', required: true, 4 | class: 'scale-limit', label: 'High value' %> 5 | <%= f.text_field :scale_min_label, placeholder: 'Too easy', required: true, 6 | maxlength: 64, class: 'scale-label', label: 'Low value text' %> 7 | <%= f.text_field :scale_max_label, placeholder: 'Too hard', required: true, 8 | maxlength: 64, class: 'scale-label', label: 'High value text' %> 9 | 10 | <%= f.hidden_field :type %> 11 | -------------------------------------------------------------------------------- /app/views/recitation_assignment_mailer/recitation_assignment_email.text.erb: -------------------------------------------------------------------------------- 1 | A new recitation assignment proposal has been created. 2 | 3 | Please go to the address below to inspect the assignment. 4 | <%= recitation_partition_url @recitation_partition, 5 | course_id: @recitation_partition.course, host: @host, 6 | protocol: @protocol %> 7 | -------------------------------------------------------------------------------- /app/views/recitation_sections/edit.html.erb: -------------------------------------------------------------------------------- 1 |

      Editing Recitation Section

      2 | 3 | <%= render 'form' %> 4 | 5 |

      Section Students

      6 | 7 |
        8 | <% @recitation_section.users.each do |user| %> 9 |
      • 10 | <%= user.name %> 11 |
      • 12 | <% end %> 13 |
      14 | -------------------------------------------------------------------------------- /app/views/recitation_sections/new.html.erb: -------------------------------------------------------------------------------- 1 |

      New Recitation Section

      2 | 3 | <%= render 'recitation_sections/form' %> 4 | -------------------------------------------------------------------------------- /app/views/recitation_sections/show.html.erb: -------------------------------------------------------------------------------- 1 |

      <%= notice %>

      2 | 3 | 4 | <%= link_to 'Edit', edit_recitation_section_path(@recitation_section) %> | 5 | <%= link_to 'Back', recitation_sections_path %> 6 | -------------------------------------------------------------------------------- /app/views/registrations/_availability.html.erb: -------------------------------------------------------------------------------- 1 |

      Availability

      2 |
      3 | 4 | 5 | 6 | <%= render 'registrations/time_slot_days_header' %> 7 | 8 | 9 | <% @time_slot_periods.each do |period| %> 10 | 11 | 12 | <% @time_slot_days.each do |day| %> 13 | <%= conflict_td_tag @time_slots[period][day], @recitation_conflicts %> 14 | <% end %> 15 | 16 | <% end %> 17 | 18 |
      Time
      <%= conflict_time_period_label period.first, period.last %>
      19 |
      20 | -------------------------------------------------------------------------------- /app/views/registrations/_recitation_section.html.erb: -------------------------------------------------------------------------------- 1 |

      Recitation Section

      2 |
      3 |
      4 | <%= display_name_for_recitation_section section %> 5 |
      6 | <%= render 'time_slots/list', time_slots: section.time_slots if section %> 7 |
      8 | -------------------------------------------------------------------------------- /app/views/registrations/_time_slot_days_header.html.erb: -------------------------------------------------------------------------------- 1 | <% @time_slot_days.each do |day| %> 2 | <%= day_label day %> 3 | <% end %> 4 | -------------------------------------------------------------------------------- /app/views/registrations/edit.html.erb: -------------------------------------------------------------------------------- 1 |

      Student Registration

      2 | 3 | <%= foundation_form_for @registration, url: polymorphic_url(@registration, 4 | course_id: @registration.course), html: { class: 'compact' } do |f| %> 5 | <%= render 'registrations/fields', f: f %> 6 | <%= render 'registrations/conflicts', conflicts: @recitation_conflicts, f: f %> 7 | 8 | <%= submit_button_tag do %> 9 | <%= save_icon_tag %> Update <%= @registration.course.number %> Registration 10 | <% end %> 11 | <% end %> 12 | -------------------------------------------------------------------------------- /app/views/registrations/new.html.erb: -------------------------------------------------------------------------------- 1 |

      <%= @registration.course.number %> Student Registration

      2 | 3 | <%= foundation_form_for @registration, url: polymorphic_url(@registration, 4 | course_id: @registration.course), html: { class: 'compact' } do |f| %> 5 | <%= render 'registrations/fields', f: f %> 6 | <%= render 'registrations/conflicts', conflicts: @recitation_conflicts, f: f %> 7 | 8 | <%= submit_button_tag do %> 9 | <%= register_icon_tag %> Register for <%= @registration.course.number %> 10 | <% end %> 11 | <% end %> 12 | -------------------------------------------------------------------------------- /app/views/role_request_mailer/decision_email.html.erb: -------------------------------------------------------------------------------- 1 |

      Dear <%= @role_request.user.name %>,

      2 |

      3 | Your request for <%= @role_request.course.number %> 4 | <%= @role_request.name == 'staff' ? 'instructor' : 'grader' %> 5 | access has been 6 | <%= @was_approved ? 'approved' : 'denied' %>. 7 |

      8 | 9 | <% if @was_approved %> 10 |

      11 | Please go 12 | <%= link_to 'here', course_root_url(host: @host, protocol: @protocol, 13 | course_id: @role_request.course) %> 14 | to work on the course. 15 |

      16 | <% end %> 17 | -------------------------------------------------------------------------------- /app/views/role_request_mailer/decision_email.text.erb: -------------------------------------------------------------------------------- 1 | Dear <%= @role_request.user.name %>, 2 | 3 | Your request for <%= @role_request.course.number %> <%= @role_request.name == 'staff' ? 'instructor' : 'grader' %> access has been <%= @was_approved ? 'approved' : 'denied' %>. 4 | 5 | <% if @was_approved %> 6 | Please go to the address below to work on the course. 7 | <%= course_root_url host: @host, protocol: @protocol, course_id: @role_request.course %> 8 | <% end %> 9 | -------------------------------------------------------------------------------- /app/views/role_request_mailer/notice_email.html.erb: -------------------------------------------------------------------------------- 1 |

      Dear <%= @role_request.course.number %> staff members,

      2 |

      3 | <%= @role_request.user.name %> <<%= @role_request.user.email %>> has 4 | requested <%= @role_request.course.number %> 5 | <%= @role_request.name == 'staff' ? 'instructor' : 'grader' %> 6 | access. 7 |

      8 | 9 |

      10 | Please go 11 | <%= link_to 'here', role_requests_url(host: @host, protocol: @protocol, 12 | course_id: @role_request.course) %> 13 | to approve or deny the request. 14 |

      15 | -------------------------------------------------------------------------------- /app/views/role_request_mailer/notice_email.text.erb: -------------------------------------------------------------------------------- 1 | Dear <%= @role_request.course.number %> staff members, 2 | 3 | <%= @role_request.user.name %> <<%= @role_request.user.email %>> has requested 4 | <%= @role_request.course.number %> <%= @role_request.name == 'staff' ? 'instructor' : 'grader' %>access. 5 | 6 | Please go to the address below to approve or deny the request. 7 | <%= role_requests_url host: @host, protocol: @protocol, course_id: @role_request.course %> 8 | -------------------------------------------------------------------------------- /app/views/role_requests/show.html.erb: -------------------------------------------------------------------------------- 1 |

      Staff Registration

      2 | 3 |

      4 | You have registered as a <%= @role_request.course.number %> staff member. 5 | Your registration must be approved before it becomes effective. 6 |

      7 | 8 |

      9 | If your registration is incorrect, you may cancel it here. 10 |

      11 | 12 | <%= foundation_form_for @role_request, url: polymorphic_url(@role_request, 13 | course_id: @role_request.course), method: :delete do |f| %> 14 | <%= submit_button_tag do %> 15 | <%= destroy_icon_tag %> 16 | Cancel <%= @role_request.course.number %> staff registration 17 | <% end %> 18 | <% end %> 19 | -------------------------------------------------------------------------------- /app/views/session/_sidebar.html.erb: -------------------------------------------------------------------------------- 1 | <% if current_user %> 2 | <%= render 'session/deadlines' %> 3 | <%= render 'layouts/groups' %> 4 | <% else %> 5 |

      Welcome

      6 | 7 | <% if current_course %> 8 |

      9 | This is the homework submission website for MIT course 10 | <%= current_course.number %>, <%= current_course.title %>. 11 |

      12 | <%= render 'session/deadlines' %> 13 | <% end %> 14 | <% end %> 15 | -------------------------------------------------------------------------------- /app/views/session/forbidden.html.erb: -------------------------------------------------------------------------------- 1 | <% if current_user %> 2 |

      3 | You are not allowed to perform this action. 4 | Please <%= link_to 'sign off', session_path, :method => :delete %>, and 5 | sign in as a different user. 6 |

      7 | <% else %> 8 |

      9 | Unfortunately, you have disabled JavaScript in your browser. Please go to the 10 | <%= link_to 'home page', new_session_path %> manually. 11 |

      12 | 15 | <% end %> 16 | -------------------------------------------------------------------------------- /app/views/session/home.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'layouts/newsfeed' %> 2 | -------------------------------------------------------------------------------- /app/views/session/new.html.erb: -------------------------------------------------------------------------------- 1 | 5 | 6 |
      7 |

      No account?

      8 | <%= form_tag new_user_path, method: :get do %> 9 |
      10 |
      11 | 12 |
      13 |
      14 | <% end %> 15 |
      16 | -------------------------------------------------------------------------------- /app/views/session_mailer/email_verification_email.html.erb: -------------------------------------------------------------------------------- 1 |

      Dear <%= @token.user.name %>,

      2 | 3 |

      4 | You are receiving this e-mail because someone (hopefully you) registered 5 | an account at 6 | <%= link_to @host, root_url(host: @host, protocol: @protocol) %> 7 | using your e-mail address. 8 |

      9 | 10 |

      11 | Please go 12 | <%= link_to 'here', token_session_url(@token, host: @host, 13 | protocol: @protocol) %> 14 | to confirm your e-mail address. 15 |

      16 | 17 |

      18 | If you haven't registered an account, please ignore this e-mail. Someone 19 | most likely mistyped their e-mail. 20 |

      21 | -------------------------------------------------------------------------------- /app/views/session_mailer/email_verification_email.text.erb: -------------------------------------------------------------------------------- 1 | Dear <%= @token.user.name %>, 2 | 3 | 4 | You are receiving this e-mail because someone (hopefully you) registered an 5 | account at <%= @host %> using your e-mail address. 6 | 7 | Please go to the address below to confirm your e-mail address. 8 | <%= token_session_url @token, :host => @host, :protocol => @protocol %> 9 | 10 | If you haven't registered an account, please ignore this e-mail. Someone most 11 | likely mistyped their e-mail. 12 | -------------------------------------------------------------------------------- /app/views/session_mailer/reset_password_email.html.erb: -------------------------------------------------------------------------------- 1 |

      Dear <%= @token.user.name %>,

      2 | 3 |

      4 | You are receiving this e-mail because someone (hopefully you) requested a 5 | password reset for your 6 | <%= link_to @host, root_url(:host => @host, :protocol => @protocol) %> 7 | account. 8 |

      9 | 10 |

      11 | Please go 12 | <%= link_to 'here', token_session_url(@token, :host => @host, 13 | :protocol => @protocol) %> 14 | to reset your password. 15 |

      16 | 17 |

      18 | If you haven't requested a password reset, please ignore this e-mail. 19 | Someone most likely mistyped their e-mail. 20 |

      21 | -------------------------------------------------------------------------------- /app/views/session_mailer/reset_password_email.text.erb: -------------------------------------------------------------------------------- 1 | Dear <%= @token.user.name %>, 2 | 3 | 4 | You are receiving this e-mail because someone (hopefully you) requested a 5 | password reset for your <%= @host %> account. 6 | 7 | Please go to the address below to reset your password. 8 | <%= token_session_url @token, :host => @host, :protocol => @protocol %> 9 | 10 | If you haven't requested a password reset, please ignore this e-mail. Someone 11 | most likely mistyped their e-mail. 12 | -------------------------------------------------------------------------------- /app/views/session_mailer/team_invite_email.html.erb: -------------------------------------------------------------------------------- 1 |

      Dear <%= @invitee_name %>,

      2 | 3 |

      4 | You are receiving this e-mail because <%= @inviter_name %> invited you to 5 | Team "<%= @team_name %>" for the partition <%= @partition_name %> 6 |

      7 | -------------------------------------------------------------------------------- /app/views/session_mailer/team_invite_email.text.erb: -------------------------------------------------------------------------------- 1 | Dear <%= @invitee_name %>, 2 | 3 | You are receiving this e-mail because <%= @inviter_name %> 4 | invited you to Team "<%= @team_name %>" for the partition 5 | <%= @partition_name %>. 6 | -------------------------------------------------------------------------------- /app/views/submissions/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= foundation_form_for submission, 2 | url: submissions_path(course_id: submission.course), 3 | html: { multipart: true, class: 'new-submission-form' } do |f| %> 4 | <%= f.input_group do %> 5 | <%= f.file_field :file %> 6 | <%= f.button type: :submit do %> 7 | <%= upload_icon_tag %> Submit 8 | <% end %> 9 | <% end %> 10 | <%= f.hidden_field :deliverable_id %> 11 | <% end %> 12 | -------------------------------------------------------------------------------- /app/views/submissions/_main_submission.html.erb: -------------------------------------------------------------------------------- 1 |
      2 |

      <%= deliverable.name %>

      3 | <% submission = deliverable.submission_for_grading current_user %> 4 | <% if submission %> 5 | <%= render 'deliverables/student_submission_list_entry', 6 | submission: submission %> 7 | <% else %> 8 | <%= render 'deliverables/no_submission' %> 9 | <% end %> 10 |
      11 | -------------------------------------------------------------------------------- /app/views/submissions/request_package.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'submissions/request_assignment' %> 2 | -------------------------------------------------------------------------------- /app/views/submissions/xhr_deliverables.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'submissions/xhr_deliverables', :assignment => @assignment %> 2 | -------------------------------------------------------------------------------- /app/views/survey_responses/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= foundation_form_for response, url: polymorphic_path(response, 2 | course_id: response.course, survey_id: response.survey), 3 | html: { class: 'compact' } do |f| %> 4 | 5 | <% response.build_answers %> 6 | <%= f.fields_for :answers do |af| %> 7 | <%= render 'survey_answers/fields', response: response, f: af %> 8 | <% end %> 9 | 10 |

      11 | Only you and <%= response.course.number %> Staff can see this response. 12 |

      13 | 14 | <%= submit_button_tag do %> 15 | <%= save_icon_tag %> Save Response 16 | <% end %> 17 | <% end %> 18 | -------------------------------------------------------------------------------- /app/views/surveys/_fields.html.erb: -------------------------------------------------------------------------------- 1 | <%= f.text_field :name, placeholder: 'Lab 1 Survey', required: true, 2 | autofocus: true, label: 'Name' %> 3 | <%= f.datetime_local_field :due_at, step: 1, label: 'Response Deadline' %> 4 | -------------------------------------------------------------------------------- /app/views/surveys/_list.html.erb: -------------------------------------------------------------------------------- 1 | <% surveys.each do |survey| %> 2 | <%= render 'surveys/show', survey: survey %> 3 | <% end %> 4 | -------------------------------------------------------------------------------- /app/views/surveys/edit.html.erb: -------------------------------------------------------------------------------- 1 |

      Survey Builder

      2 | 3 | <%= render 'surveys/form', survey: @survey %> 4 | -------------------------------------------------------------------------------- /app/views/surveys/index.html.erb: -------------------------------------------------------------------------------- 1 |

      2 | Surveys 3 | <% if current_course.can_edit? current_user %> 4 | 5 | 6 | <%= link_to new_survey_path(course_id: current_course), 7 | class: 'hollow button' do %> 8 | <%= create_icon_tag %> New 9 | <% end %> 10 | 11 | 12 | <% end %> 13 |

      14 | <%= render 'surveys/list', surveys: @surveys %> 15 | -------------------------------------------------------------------------------- /app/views/surveys/new.html.erb: -------------------------------------------------------------------------------- 1 |

      New Survey

      2 | 3 | <%= foundation_form_for @survey, url: polymorphic_path(@survey, 4 | course_id: @survey.course) do |f| %> 5 | <%= render 'surveys/fields', f: f %> 6 | 7 | <%= submit_button_tag do %> 8 | <%= build_icon_tag %> Build Survey 9 | <% end %> 10 | <% end %> 11 | -------------------------------------------------------------------------------- /app/views/surveys/show.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'surveys/show', survey: @survey %> 2 | -------------------------------------------------------------------------------- /app/views/team_memberships/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_for(@team_membership) do |f| %> 2 | <% if @team_membership.errors.any? %> 3 |
      4 |

      <%= pluralize(@team_membership.errors.count, "error") %> prohibited this team_membership from being saved:

      5 | 6 |
        7 | <% @team_membership.errors.full_messages.each do |msg| %> 8 |
      • <%= msg %>
      • 9 | <% end %> 10 |
      11 |
      12 | <% end %> 13 | 14 |
      15 | <%= f.submit %> 16 |
      17 | <% end %> 18 | -------------------------------------------------------------------------------- /app/views/team_memberships/index.html.erb: -------------------------------------------------------------------------------- 1 |

      Listing team_memberships

      2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | <% @team_memberships.each do |team_membership| %> 11 | 12 | 13 | 14 | 18 | 19 | <% end %> 20 |
      <%= link_to 'Show', team_membership %><%= link_to 'Edit', edit_team_membership_path(team_membership) %> 15 | <%= link_to 'Destroy', team_membership, method: :delete 16 | data: { confirm: 'Are you sure?' } %> 17 |
      21 | 22 |
      23 | 24 | <%= link_to 'New Team membership', new_team_membership_path %> 25 | -------------------------------------------------------------------------------- /app/views/team_memberships/new.html.erb: -------------------------------------------------------------------------------- 1 |

      New team_membership

      2 | 3 | <%= render 'form' %> 4 | 5 | <%= link_to 'Back', team_memberships_path %> 6 | -------------------------------------------------------------------------------- /app/views/team_memberships/show.html.erb: -------------------------------------------------------------------------------- 1 |

      <%= notice %>

      2 | 3 | 4 | <%= link_to 'Edit', edit_team_membership_path(@team_membership) %> | 5 | <%= link_to 'Back', team_memberships_path %> 6 | -------------------------------------------------------------------------------- /app/views/team_partitions/unlock.html.erb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/views/team_partitions/unlock.html.erb -------------------------------------------------------------------------------- /app/views/teams/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_for @team, 2 | url: polymorphic_url(@team, course_id: @team.course) do |f| %> 3 | <%= f.error_messages %> 4 | <%= f.hidden_field :partition_id %> 5 | 6 |
      7 |
      8 | <%= f.label :name, class: 'text-right middle' %> 9 |
      10 |
      11 | <%= f.text_field :name, placeholder: 'Team A' %> 12 |
      13 |
      14 | <%= button_tag class: 'hollow button' do %> 15 | <%= create_icon_tag %> Add New Team 16 | <% end %> 17 |
      18 |
      19 | <% end %> 20 | -------------------------------------------------------------------------------- /app/views/teams/edit.html.erb: -------------------------------------------------------------------------------- 1 |

      Editing team

      2 | 3 | <%= render 'form' %> 4 | 5 | <%= link_to 'Show', @team %> | 6 | <%= link_to 'Back', teams_path %> 7 | -------------------------------------------------------------------------------- /app/views/teams/index.html.erb: -------------------------------------------------------------------------------- 1 |

      Listing teams

      2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | <% @teams.each do |team| %> 13 | 14 | 15 | 16 | 17 | 18 | 22 | 23 | <% end %> 24 |
      Team setName
      <%= team.team_set_id %><%= team.name %><%= link_to 'Show', team %><%= link_to 'Edit', edit_team_path(team) %> 19 | <%= link_to 'Destroy', team, data: { confirm: 'Are you sure?' }, 20 | method: :delete %> 21 |
      25 | 26 |
      27 | 28 | <%= link_to 'New team', new_team_path %> 29 | -------------------------------------------------------------------------------- /app/views/teams/new.html.erb: -------------------------------------------------------------------------------- 1 |

      New team

      2 | 3 | <%= render 'form' %> 4 | 5 | <%= link_to 'Back', teams_path %> 6 | -------------------------------------------------------------------------------- /app/views/teams/show.html.erb: -------------------------------------------------------------------------------- 1 |

      2 | Team partition: 3 | <%= @team.partition.name %> 4 |

      5 | 6 |

      7 | Name: 8 | <%= @team.name %> 9 |

      10 | 11 | 12 | <%= link_to 'Edit', edit_team_path(@team) %> | 13 | <%= link_to 'Back', teams_path %> 14 | -------------------------------------------------------------------------------- /app/views/teams_student/accept_invitation.html.erb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/views/teams_student/accept_invitation.html.erb -------------------------------------------------------------------------------- /app/views/teams_student/create_team.html.erb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/views/teams_student/create_team.html.erb -------------------------------------------------------------------------------- /app/views/teams_student/ignore_invitation.html.erb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/views/teams_student/ignore_invitation.html.erb -------------------------------------------------------------------------------- /app/views/teams_student/leave_team.html.erb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/app/views/teams_student/leave_team.html.erb -------------------------------------------------------------------------------- /app/views/time_slots/_fields.html.erb: -------------------------------------------------------------------------------- 1 | 2 | <%= f.select :day, day_select_option_tags, { form: 'time-slot-form' } %> 3 | 4 | 5 | <%= f.time_select :start_time, { ampm: true, minute_step: 5 }, 6 | { form: 'time-slot-form' } %> 7 | 8 | 9 | <%= f.time_select :end_time, { ampm: true, minute_step: 5 }, 10 | { form: 'time-slot-form' } %> 11 | 12 | 13 | 14 | <%= button_tag(form: 'time-slot-form', class: 'hollow button') do %> 15 | <%= create_icon_tag %> Create Time Slot 16 | <% end %> 17 | 18 | -------------------------------------------------------------------------------- /app/views/time_slots/_list.html.erb: -------------------------------------------------------------------------------- 1 |
        2 | <% time_slots.each do |time_slot| %> 3 |
      1. <%= time_slot_label time_slot, max_length: 3 %>
      2. 4 | <% end %> 5 |
      6 | -------------------------------------------------------------------------------- /app/views/users/_new.html.erb: -------------------------------------------------------------------------------- 1 |
      2 | <%= foundation_form_for user do |f| %> 3 | 4 | <%= render 'users/new_fields', f: f %> 5 | 6 |

      Profile

      7 | <%= f.fields_for :profile do |pf| %> 8 | <%= render 'profiles/fields', f: pf %> 9 | <% end %> 10 | 11 | <%= submit_button_tag do %> 12 | <%= create_icon_tag %> Create my account 13 | <% end %> 14 | <% end %> 15 |
      16 | -------------------------------------------------------------------------------- /app/views/users/_user.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%= user_image_tag user %> 4 | <%= link_to user.display_name_for(current_user, :long), user %> 5 | 6 | 7 | <% if current_user.admin? %> 8 | <%= button_to impersonate_user_path(user), method: :post, 9 | class: 'small hollow button' do %> 10 | <%= debug_icon_tag %> Impersonate 11 | <% end %> 12 | <% end %> 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/views/users/edit.html.erb: -------------------------------------------------------------------------------- 1 |
      2 | <%= render 'profile_photos/for_user', user: @user %> 3 |

      <%= @user.name %>

      4 |
      5 | 6 | <%= render 'profiles/form', profile: @user.profile %> 7 | -------------------------------------------------------------------------------- /app/views/users/new.html.erb: -------------------------------------------------------------------------------- 1 |
      2 |

      New Account

      3 | 4 | 7 |
      8 | -------------------------------------------------------------------------------- /app/views/users/show.html.erb: -------------------------------------------------------------------------------- 1 |
      2 | <%= render 'profile_photos/for_user', user: @user %> 3 |

      4 | 5 | <%= @user.name %> 6 | 7 | 8 | <% if @user.profile.can_edit? current_user %> 9 | 10 | <%= link_to edit_user_path(@user), class: 'hollow button' do %> 11 | <%= edit_icon_tag %> Edit Profile 12 | <% end %> 13 | 14 | <% end %> 15 | 16 |

      17 |
      18 | 19 | <%= render 'profiles/show', profile: @user.profile %> 20 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /bin/delayed_job: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment')) 4 | require 'delayed/command' 5 | Delayed::Command.new(ARGV).daemonize 6 | -------------------------------------------------------------------------------- /bin/puma: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'puma' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('puma', 'puma') 17 | -------------------------------------------------------------------------------- /bin/pumactl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # This file was generated by Bundler. 4 | # 5 | # The application 'pumactl' is installed as part of a gem, and 6 | # this file is here to facilitate running it. 7 | # 8 | 9 | require 'pathname' 10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 11 | Pathname.new(__FILE__).realpath) 12 | 13 | require 'rubygems' 14 | require 'bundler/setup' 15 | 16 | load Gem.bin_path('puma', 'pumactl') 17 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../../config/application', __FILE__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /bin/spring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This file loads spring without using Bundler, in order to be fast. 4 | # It gets overwritten when you run the `spring binstub` command. 5 | 6 | unless defined?(Spring) 7 | require "rubygems" 8 | require "bundler" 9 | 10 | if (match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m)) 11 | Gem.paths = { "GEM_PATH" => [Bundler.bundle_path.to_s, *Gem.path].uniq } 12 | gem "spring", match[1] 13 | require "spring/binstub" 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /clouds.yaml: -------------------------------------------------------------------------------- 1 | deploy/ansible/clouds.yaml -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative 'config/environment' 4 | 5 | run Rails.application 6 | -------------------------------------------------------------------------------- /config/autoprefixer.yml: -------------------------------------------------------------------------------- 1 | browsers: 2 | - "> 1%" 3 | - "not IE > 0" 4 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 2 | 3 | require 'bundler/setup' # Set up gems listed in the Gemfile. 4 | -------------------------------------------------------------------------------- /config/cable.yml: -------------------------------------------------------------------------------- 1 | # Action Cable uses Redis by default to administer connections, channels, and sending/receiving messages over the WebSocket. 2 | production: 3 | adapter: redis 4 | url: redis://localhost:6379/1 5 | 6 | development: 7 | adapter: redis 8 | url: redis://localhost:6379/2 9 | 10 | test: 11 | adapter: redis 12 | url: redis://localhost:6379/3 13 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /config/initializers/action_mailer.rb: -------------------------------------------------------------------------------- 1 | unless Rails.env.test? 2 | Rails.application.config.action_mailer.delivery_method = :smtp 3 | end 4 | -------------------------------------------------------------------------------- /config/initializers/active_record_belongs_to_required_by_default.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Require `belongs_to` associations by default. This is a new Rails 5.0 4 | # default, so it is introduced as a configuration option to ensure that apps 5 | # made on earlier versions of Rails are not affected when upgrading. 6 | Rails.application.config.active_record.belongs_to_required_by_default = true 7 | -------------------------------------------------------------------------------- /config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ApplicationController.renderer.defaults.merge!( 4 | # http_host: 'example.org', 5 | # https: false 6 | # ) 7 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 11 | # Rails.application.config.assets.precompile += %w( search.js ) 12 | -------------------------------------------------------------------------------- /config/initializers/autoload_mailer_concerns.rb: -------------------------------------------------------------------------------- 1 | Rails.application.config.autoload_paths += %w( app/mailers/concerns ) 2 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /config/initializers/cors.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Avoid CORS issues when API is called from the frontend app. 4 | # Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests. 5 | 6 | # Read more: https://github.com/cyu/rack-cors 7 | 8 | # Rails.application.config.middleware.insert_before 0, Rack::Cors do 9 | # allow do 10 | # origins 'example.com' 11 | # 12 | # resource '*', 13 | # headers: :any, 14 | # methods: [:get, :post, :put, :patch, :delete, :options, :head] 15 | # end 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/delayed_job.rb: -------------------------------------------------------------------------------- 1 | Rails.application.config.active_job.queue_adapter = :delayed_job 2 | 3 | Delayed::Worker.destroy_failed_jobs = false 4 | Delayed::Worker.sleep_delay = 2 5 | Delayed::Worker.max_attempts = 3 6 | Delayed::Worker.max_run_time = 4.hours 7 | # Delayed::Worker.read_ahead = 5 8 | # Delayed::Worker.default_queue_name = 'default' 9 | 10 | if Rails.env.development? && !ENV['DELAY_JOBS'] 11 | Delayed::Worker.delay_jobs = false 12 | else 13 | Delayed::Worker.delay_jobs = true 14 | end 15 | #Delayed::Worker.raise_signal_exceptions = :term 16 | Delayed::Worker.logger = Logger.new( 17 | File.join(Rails.root, 'log', 'delayed_job.log')) 18 | -------------------------------------------------------------------------------- /config/initializers/exception_notifier.rb: -------------------------------------------------------------------------------- 1 | if Rails.env.production? || ENV['EXCEPTION_NOTIFIER'] 2 | Rails.application.config.middleware.use ExceptionNotification::Rack, 3 | email: { 4 | email_prefix: "[igor] ", 5 | sender_address: %{"Victor Costan" }, 6 | exception_recipients: %w{costan@alum.mit.edu spark008@alum.mit.edu}, 7 | mailer_parent: 'ExceptionMailer', 8 | } 9 | end 10 | -------------------------------------------------------------------------------- /config/initializers/field_error_proc.rb: -------------------------------------------------------------------------------- 1 | # Do not add special markup for fields with validation errors. 2 | # 3 | # Additional markup should be specified within a custom form builder. 4 | ActionView::Base.field_error_proc = Proc.new { |html_tag, instance| 5 | html_tag.html_safe 6 | } 7 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password, :file_contents] 5 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /config/initializers/per_form_csrf_tokens.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Enable per-form CSRF tokens. 4 | Rails.application.config.action_controller.per_form_csrf_tokens = true 5 | -------------------------------------------------------------------------------- /config/initializers/rack_mini_profiler.rb: -------------------------------------------------------------------------------- 1 | require 'rack-mini-profiler' 2 | 3 | Rack::MiniProfilerRails.initialize!(Rails.application) 4 | 5 | Rack::MiniProfiler.config.base_url_path = '/_/mini-profiler-resources/' 6 | -------------------------------------------------------------------------------- /config/initializers/request_forgery_protection.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Enable origin-checking CSRF mitigation. 4 | Rails.application.config.action_controller.forgery_protection_origin_check = true 5 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_igor_session' 4 | -------------------------------------------------------------------------------- /config/initializers/silence_view_logging.rb: -------------------------------------------------------------------------------- 1 | # Disable the "Rendered ..." lines that show up when rendering partials. 2 | if Rails.env.production? 3 | ActionView::LogSubscriber.class_eval do 4 | def logger 5 | nil 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /config/initializers/stdlib.rb: -------------------------------------------------------------------------------- 1 | require 'csv' 2 | require 'digest/sha2' 3 | require 'openssl' 4 | require 'tempfile' 5 | require 'tmpdir' 6 | require 'yaml' 7 | -------------------------------------------------------------------------------- /config/initializers/time_formats.rb: -------------------------------------------------------------------------------- 1 | Time::DATE_FORMATS.merge!( 2 | datetime_local_field: '%Y-%m-%dT%T', 3 | deadline_short: '%b %e', 4 | deadline_long: '%a %b %e, %l:%M%p', 5 | exam_session_date: '%a %b %e', 6 | exam_session_time: '%l:%M%P', 7 | exam_session_datetime: '%a %b %e, %l:%M%P', 8 | extension_date: '%m/%d/%y', 9 | extension_time: '%l:%M %p', 10 | submission_short: '%b %e, %l:%M%p', 11 | submission_long: '%b %d %I:%M:%S%p', 12 | time_slot_short: '%l:%M%P', 13 | time_slot_long: '%l:%M%P (%Z)' 14 | ) 15 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /config/mongrel_cluster.yml: -------------------------------------------------------------------------------- 1 | --- 2 | user: victor 3 | cwd: /prod/apps/six 4 | log_file: log/mongrel.log 5 | port: "8100" 6 | environment: production 7 | group: victor 8 | address: 127.0.0.1 9 | pid_file: tmp/pids/mongrel.pid 10 | servers: 4 11 | -------------------------------------------------------------------------------- /config/secrets.yml: -------------------------------------------------------------------------------- 1 | development: 2 | secret_key_base: b91855f287eb4ad40633d4dd9697f7c284c9549def3acf548cc00469d42cd86b9a89ea475ee88faa93600ab0c1e4df6cf144de0dda36537687493f136a2c1c07 3 | 4 | test: 5 | secret_key_base: b91855f287eb4ad40633d4dd9697f7c284c9549def3acf548cc00469d42cd86b9a89ea475ee88faa93600ab0c1e4df6cf144de0dda36537687493f136a2c1c07 6 | 7 | production: 8 | secret_key_base: 1ce837365cb5d097b7185fb4347e804d2c99d667c4f0272b0f43fecf63cce852ee6640d5df9b7eee419fd295f79aafff8d2a39467b811358961ff27c9f53eb94 9 | -------------------------------------------------------------------------------- /db/migrate/20100725000001_create_users.rb: -------------------------------------------------------------------------------- 1 | class CreateUsers < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :users do |t| 4 | t.string :exuid, limit: 32, null: false 5 | 6 | t.timestamps null: false 7 | 8 | t.index :exuid, unique: true 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20110703010001_create_file_blobs.rb: -------------------------------------------------------------------------------- 1 | class CreateFileBlobs < ActiveRecord::Migration[5.0] 2 | def change 3 | create_file_blobs_table :file_blobs, blob_limit: 128.megabytes do |t| 4 | # Build any custom table structure here. 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20110704010001_create_roles.rb: -------------------------------------------------------------------------------- 1 | class CreateRoles < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :roles do |t| 4 | t.references :user, null: false 5 | t.string :name, limit: 8, null: false 6 | t.references :course 7 | 8 | t.timestamps null: false 9 | end 10 | 11 | # List all staff members in a course. Prevent duplicate role entries. 12 | add_index :roles, [:course_id, :name, :user_id], unique: true 13 | 14 | # Lists all the courses that a user has privileges for. 15 | add_index :roles, [:user_id, :course_id] 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /db/migrate/20110704010002_create_profiles.rb: -------------------------------------------------------------------------------- 1 | class CreateProfiles < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :profiles do |t| 4 | t.references :user, null: false, index: { unique: true } 5 | t.string :name, null: false, limit: 128 6 | t.string :nickname, null: false, limit: 64 7 | t.string :university, null: false, limit: 64 8 | t.string :department, null: false, limit: 64 9 | t.string :year, null: false, limit: 4 10 | 11 | t.timestamps null: false 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20110704010003_create_profile_photos.rb: -------------------------------------------------------------------------------- 1 | class CreateProfilePhotos < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :profile_photos do |t| 4 | t.references :profile, null: false, 5 | index: { unique: true }, foreign_key: true 6 | 7 | t.file_blob :image, null: false, mime_type_limit: 64, 8 | file_name_limit: 256 9 | 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20110704010004_create_robot_user.rb: -------------------------------------------------------------------------------- 1 | class CreateRobotUser < ActiveRecord::Migration[4.2] 2 | def up 3 | robot = User.new email: 'robot@localhost.edu', 4 | password: '_', password_confirmation: '_', 5 | profile_attributes: { 6 | name: 'Staff Robot', nickname: 'Robot', 7 | university: 'MIT', department: 'EECS', year: 'G' 8 | } 9 | robot.email_credential.verified = true 10 | robot.save! 11 | robot.password_credential.destroy 12 | Role.create! user: robot, name: 'bot' 13 | end 14 | 15 | def down 16 | User.robot && User.robot.destroy 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /db/migrate/20110704010005_create_photo_blobs.rb: -------------------------------------------------------------------------------- 1 | class CreatePhotoBlobs < ActiveRecord::Migration[4.2] 2 | def self.up 3 | create_table :photo_blobs do |t| 4 | t.integer :profile_photo_id, null: false 5 | t.string :style, limit: 16 6 | t.binary :file_contents, limit: 1.megabyte, null: false 7 | end 8 | 9 | change_table :photo_blobs do |t| 10 | t.index [:profile_photo_id, :style], unique: true 11 | end 12 | end 13 | 14 | def self.down 15 | drop_table :pics 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /db/migrate/20110704010006_create_role_requests.rb: -------------------------------------------------------------------------------- 1 | class CreateRoleRequests < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :role_requests do |t| 4 | t.references :user, null: false 5 | t.string :name, limit: 8, null: false 6 | t.references :course 7 | 8 | t.timestamps null: false 9 | end 10 | 11 | # List all requests in a course. Prevent duplicate requests. 12 | add_index :role_requests, [:course_id, :name, :user_id], unique: true 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20110704010008_create_smtp_servers.rb: -------------------------------------------------------------------------------- 1 | class CreateSmtpServers < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :smtp_servers do |t| 4 | t.string :host, null: false, limit: 128 5 | t.integer :port, null: false 6 | t.string :domain, null: false, limit: 128 7 | t.string :user_name, null: false, limit: 128 8 | t.string :password, null: false, limit: 128 9 | t.string :from, null: false, limit: 128 10 | t.string :auth_kind, null: true 11 | t.boolean :auto_starttls, null: false 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20110704020003_create_prerequisites.rb: -------------------------------------------------------------------------------- 1 | class CreatePrerequisites < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :prerequisites do |t| 4 | t.references :course, null: false 5 | t.string :prerequisite_number, limit: 64, null: false 6 | t.string :waiver_question, limit: 256, null: false 7 | 8 | t.timestamps null: false 9 | end 10 | 11 | add_index :prerequisites, [:course_id, :prerequisite_number], unique: true 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20110704020005_create_recitation_conflicts.rb: -------------------------------------------------------------------------------- 1 | class CreateRecitationConflicts < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :recitation_conflicts do |t| 4 | t.references :registration, null: false 5 | t.references :time_slot, null: false 6 | t.string :class_name, null: false 7 | 8 | t.index [:registration_id, :time_slot_id], unique: true 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20110704020006_create_prerequisite_answers.rb: -------------------------------------------------------------------------------- 1 | class CreatePrerequisiteAnswers < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :prerequisite_answers do |t| 4 | t.references :registration, null: false 5 | t.references :prerequisite, null: false 6 | t.boolean :took_course, null: false 7 | t.text :waiver_answer, limit: 4.kilobytes 8 | 9 | t.timestamps null: false 10 | end 11 | 12 | # Optimize getting prerequisite answers for a registration. 13 | add_index :prerequisite_answers, [:registration_id, :prerequisite_id], 14 | unique: true, name: 'prerequisites_for_a_registration' 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /db/migrate/20110704030000_create_deadlines.rb: -------------------------------------------------------------------------------- 1 | class CreateDeadlines < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :deadlines do |t| 4 | t.references :subject, polymorphic: true, index: { unique: true }, 5 | null: false 6 | t.datetime :due_at, null: false 7 | # Get all deadlines for a course. 8 | t.references :course, index: true, null: false 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20110704030003_create_assignment_files.rb: -------------------------------------------------------------------------------- 1 | class CreateAssignmentFiles < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :assignment_files do |t| 4 | t.string :description, limit: 64, null: false 5 | t.references :assignment, index: true, foreign_key: true, null: false 6 | t.file_blob :file, null: false, mime_type_limit: 64, file_name_limit: 256 7 | t.datetime :released_at, null: true 8 | 9 | t.timestamps null: false 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20110704030004_create_assignment_metrics.rb: -------------------------------------------------------------------------------- 1 | class CreateAssignmentMetrics < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :assignment_metrics do |t| 4 | t.references :assignment, null: false 5 | t.string :name, limit: 64, null: false 6 | t.integer :max_score, null: false 7 | t.decimal :weight, precision: 16, scale: 8, null: false 8 | 9 | t.timestamps null: false 10 | 11 | t.index [:assignment_id, :name], unique: true 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20110704040001_create_deliverables.rb: -------------------------------------------------------------------------------- 1 | class CreateDeliverables < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :deliverables do |t| 4 | t.references :assignment, null: false 5 | t.string :name, limit: 80, null: false 6 | t.string :description, limit: 2.kilobytes, null: false 7 | 8 | t.timestamps null: false 9 | end 10 | 11 | add_index :deliverables, [:assignment_id, :name], unique: true 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20110704040002_create_analyzers.rb: -------------------------------------------------------------------------------- 1 | class CreateAnalyzers < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :analyzers do |t| 4 | t.references :deliverable, null: false, unique: true 5 | t.string :type, limit: 32, null: false 6 | t.boolean :auto_grading, null: false 7 | 8 | t.text :exec_limits, null: true 9 | t.file_blob :file, null: true, mime_type_limit: 64, file_name_limit: 256 10 | 11 | t.string :message_name, limit: 64, null: true 12 | 13 | t.timestamps null: false 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /db/migrate/20110704040004_create_collaborations.rb: -------------------------------------------------------------------------------- 1 | class CreateCollaborations < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :collaborations do |t| 4 | t.references :submission, foreign_key: true, null: false 5 | t.references :collaborator, null: false 6 | 7 | t.index [:submission_id, :collaborator_id], unique: true 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20110704040005_create_analyses.rb: -------------------------------------------------------------------------------- 1 | class CreateAnalyses < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :analyses do |t| 4 | t.references :submission, null: false 5 | t.integer :status_code, null: false 6 | 7 | t.text :log, limit: 64.kilobytes, null: false 8 | t.text :private_log, limit: 64.kilobytes, null: false 9 | t.text :scores, limit: 16.kilobytes, null: true 10 | 11 | t.timestamps null: false 12 | 13 | t.index :submission_id, unique: true 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /db/migrate/20110704050001_create_surveys.rb: -------------------------------------------------------------------------------- 1 | class CreateSurveys < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :surveys do |t| 4 | t.string :name, limit: 128, null: false 5 | t.boolean :released, null: false 6 | t.references :course, null: false 7 | 8 | t.timestamps null: false 9 | 10 | t.index [:course_id, :name], unique: true 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20110704050002_create_survey_questions.rb: -------------------------------------------------------------------------------- 1 | class CreateSurveyQuestions < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :survey_questions do |t| 4 | t.references :survey, null: false 5 | t.string :prompt, limit: 1.kilobyte, null: false 6 | t.boolean :allows_comments, null: false 7 | t.string :type, limit: 32, null: false 8 | t.text :features, null: false 9 | 10 | t.timestamps null: false 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20110704050003_create_survey_responses.rb: -------------------------------------------------------------------------------- 1 | class CreateSurveyResponses < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :survey_responses do |t| 4 | t.references :course, null: false, index: true 5 | t.references :user, null: false 6 | t.references :survey, null: false 7 | 8 | t.timestamps null: false 9 | 10 | # Get a user's response to a survey. 11 | t.index [:user_id, :survey_id], unique: true 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20110704050004_create_survey_answers.rb: -------------------------------------------------------------------------------- 1 | class CreateSurveyAnswers < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :survey_answers do |t| 4 | t.references :question, null: false 5 | t.references :response, null: false 6 | t.decimal :number, null: true, precision: 7, scale: 2 7 | t.string :comment, limit: 1.kilobyte, null: true 8 | 9 | t.timestamps null: false 10 | 11 | t.index [:response_id, :question_id], unique: true 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20110704060001_create_team_partitions.rb: -------------------------------------------------------------------------------- 1 | class CreateTeamPartitions < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :team_partitions do |t| 4 | t.references :course, null: false 5 | t.string :name, limit: 64, null: false 6 | t.integer :min_size, null: false 7 | t.integer :max_size, null: false 8 | 9 | t.boolean :automated, null: false, default: true 10 | t.boolean :editable, null: false, default: true 11 | t.boolean :released, null: false, default: false 12 | 13 | t.timestamps null: false 14 | 15 | t.index [:course_id, :name], unique: true 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /db/migrate/20110704060002_create_teams.rb: -------------------------------------------------------------------------------- 1 | class CreateTeams < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :teams do |t| 4 | t.references :partition, null: false 5 | t.string :name, limit: 64, null: false 6 | 7 | t.timestamps null: false 8 | end 9 | 10 | # Prevent duplicate names in a partition. 11 | add_index :teams, [:partition_id, :name], unique: true 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20110704060003_create_team_memberships.rb: -------------------------------------------------------------------------------- 1 | class CreateTeamMemberships < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :team_memberships do |t| 4 | t.references :team, null: false 5 | t.references :user, null: false 6 | t.references :course, null: false 7 | 8 | t.datetime :created_at 9 | 10 | # Ensure no duplicates. 11 | t.index [:user_id, :team_id], unique: true 12 | # The users on a team. 13 | t.index [:team_id, :user_id], unique: true 14 | # All the user's teams for a course. 15 | t.index [:user_id, :course_id] 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /db/migrate/20110704060004_create_invitations.rb: -------------------------------------------------------------------------------- 1 | class CreateInvitations < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :invitations do |t| 4 | t.integer :inviter_id 5 | t.integer :invitee_id 6 | t.integer :team_id 7 | 8 | t.timestamps null: false 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20110704060005_create_recitation_sections.rb: -------------------------------------------------------------------------------- 1 | class CreateRecitationSections < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :recitation_sections do |t| 4 | t.references :course, null: false 5 | t.references :leader, null: true 6 | t.integer :serial, null: false 7 | t.string :location, limit: 64, null: false 8 | 9 | t.timestamps null: false 10 | 11 | t.index [:course_id, :serial], unique: true 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20110704060006_create_recitation_partition.rb: -------------------------------------------------------------------------------- 1 | class CreateRecitationPartition < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :recitation_partitions do |t| 4 | t.references :course, null: false, index: { unique: false } 5 | t.integer :section_size, null: false 6 | t.integer :section_count, null: false 7 | 8 | t.datetime :created_at 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20110704060007_create_recitation_assignment.rb: -------------------------------------------------------------------------------- 1 | class CreateRecitationAssignment < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :recitation_assignments do |t| 4 | t.references :recitation_partition, null: false 5 | t.references :user, null: false 6 | t.references :recitation_section, null: false 7 | 8 | t.index [:recitation_partition_id, :user_id], unique: true, 9 | name: 'recitation_assignments_to_partitions' 10 | t.index [:recitation_partition_id, :recitation_section_id], unique: false, 11 | name: 'recitation_assignments_to_sections' 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20110704060008_create_time_slots.rb: -------------------------------------------------------------------------------- 1 | class CreateTimeSlots < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :time_slots do |t| 4 | t.references :course, null: false 5 | t.integer :day, limit: 1, null: false 6 | t.integer :starts_at, limit: 4, null: false 7 | t.integer :ends_at, limit: 4, null: false 8 | 9 | t.index [:course_id, :day, :starts_at, :ends_at], unique: true 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20110704060009_create_time_slot_allotments.rb: -------------------------------------------------------------------------------- 1 | class CreateTimeSlotAllotments < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :time_slot_allotments do |t| 4 | t.references :time_slot, index: true, foreign_key: true, null: false 5 | t.references :recitation_section, index: true, foreign_key: true, 6 | null: false 7 | 8 | t.index [:recitation_section_id, :time_slot_id], unique: true, 9 | name: 'index_time_slot_allotments_on_recitation_section_and_time_slot' 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20110704080001_create_exams.rb: -------------------------------------------------------------------------------- 1 | class CreateExams < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :exams do |t| 4 | t.references :assignment, index: { unique: true }, foreign_key: true, 5 | null: false 6 | t.boolean :requires_confirmation, null: false 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20110704080002_create_exam_sessions.rb: -------------------------------------------------------------------------------- 1 | class CreateExamSessions < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :exam_sessions do |t| 4 | t.references :course, foreign_key: true, null: false 5 | t.references :exam, foreign_key: true, null: false 6 | t.string :name, limit: 64, null: false 7 | t.datetime :starts_at, null: false 8 | t.datetime :ends_at, null: false 9 | t.integer :capacity, null: false 10 | 11 | t.index [:exam_id, :name], unique: true 12 | t.index [:course_id, :starts_at] 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20110704080003_create_exam_attendances.rb: -------------------------------------------------------------------------------- 1 | class CreateExamAttendances < ActiveRecord::Migration[4.2] 2 | def change 3 | create_table :exam_attendances do |t| 4 | t.references :user, index: true, foreign_key: true, null: false 5 | t.references :exam, foreign_key: true, null: false 6 | t.references :exam_session, foreign_key: true, null: false 7 | t.boolean :confirmed, null: false 8 | 9 | t.timestamps null: false 10 | 11 | t.index [:exam_id, :user_id], unique: true 12 | t.index [:exam_session_id, :user_id], unique: true 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /deploy/ansible/clouds.yaml.example: -------------------------------------------------------------------------------- 1 | --- 2 | ansible: 3 | use_hostnames: False 4 | expand_hostvars: False 5 | 6 | clouds: 7 | test: 8 | auth: 9 | auth_url: https://nimbus.csail.mit.edu:5001/v2.0 10 | username: costan@csail.mit.edu 11 | password: mysekretpassword 12 | project_name: usersandbox_costan 13 | region_name: CSAIL_Stata 14 | -------------------------------------------------------------------------------- /deploy/ansible/keys.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible playbook that generates the TLS keys and certificates used by the 3 | # cluster. 4 | 5 | - hosts: localhost 6 | connection: local 7 | vars_files: 8 | - ../openstack_vars.yml 9 | roles: 10 | - gen_certs_cluster 11 | - gen_certs_web 12 | -------------------------------------------------------------------------------- /deploy/ansible/library/TODO.txt: -------------------------------------------------------------------------------- 1 | Remove os_server_custom.py when the following ansible PR gets merged: 2 | https://github.com/ansible/ansible/pull/20969 3 | 4 | os_sever_custom is referenced in os_cluster/tasks/main.yml. The reference must 5 | be replaced with os_server. 6 | -------------------------------------------------------------------------------- /deploy/ansible/openstack_up.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible playbook that brings up an OpenStack cluster for Kubernetes. 3 | 4 | - hosts: localhost 5 | connection: local 6 | vars_files: 7 | - ../openstack_vars.yml 8 | roles: 9 | - os_cluster 10 | -------------------------------------------------------------------------------- /deploy/ansible/roles/docker/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # The Docker package repository branch used to install the engine. 3 | # 4 | # The valid options are "main", "testing" and "experimental". 5 | # * main is the current release 6 | # * testing is the next bugfix release 7 | # * experimental is the next release (most likley cut off the GitHub master) 8 | docker_engine_branch: main 9 | -------------------------------------------------------------------------------- /deploy/ansible/roles/docker/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart docker daemon 3 | become: true 4 | become_user: root 5 | service: name=docker state=restarted 6 | -------------------------------------------------------------------------------- /deploy/ansible/roles/docker_client_keys/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # The user who will receive the Docker client keys. 3 | docker_client_user: root 4 | 5 | # The home directory of the user receiving the Docker client keys. 6 | docker_client_user_homedir: '{{ 7 | "/root" if docker_client_user == "root" else "/home/" + docker_client_user 8 | }}' 9 | -------------------------------------------------------------------------------- /deploy/ansible/roles/docker_facts/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # The interface used to connect to other computers in the cluster. 3 | # 4 | # This is generally eth0. Currently, only Vagrant VMs are special-cased. 5 | cluster_net_interface: "{{ 'eth1' if ansible_ssh_user == 'vagrant' 6 | else 'eth0' }}" 7 | -------------------------------------------------------------------------------- /deploy/ansible/roles/docker_facts/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependencies: [] 3 | -------------------------------------------------------------------------------- /deploy/ansible/roles/docker_facts/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Sets facts used by the Docker cluster. 3 | 4 | # This could be computed at runtime, but the engineering effort isn't currently 5 | # warranted. 6 | - name: set docker_swarm_net_interface fact 7 | set_fact: 8 | docker_swarm_net_interface: "{{ cluster_net_interface }}" 9 | -------------------------------------------------------------------------------- /deploy/ansible/roles/docker_network/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart docker daemon 3 | become: true 4 | become_user: root 5 | service: name=docker state=restarted 6 | -------------------------------------------------------------------------------- /deploy/ansible/roles/docker_network/templates/sysconfig_docker_network.j2: -------------------------------------------------------------------------------- 1 | # /etc/default/docker-network 2 | # /etc/sysconfig/docker-network 3 | DOCKER_NETWORK_OPTIONS="--tlsverify --tlscacert=/etc/docker/ca.pem --tlscert=/etc/docker/server-cert.pem --tlskey=/etc/docker/server-key.pem --host=tcp://0.0.0.0:2376 --host=unix:///var/run/docker.sock" 4 | -------------------------------------------------------------------------------- /deploy/ansible/roles/docker_storage/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: stop the docker daemon 3 | become: true 4 | become_user: root 5 | service: name=docker state=stopped 6 | 7 | - name: reconfigure Docker LVM storage 8 | command: docker-storage-setup 9 | become: true 10 | become_user: root 11 | 12 | - name: restart docker daemon 13 | become: true 14 | become_user: root 15 | service: name=docker state=restarted 16 | -------------------------------------------------------------------------------- /deploy/ansible/roles/docker_storage/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: check if /dev/vdb exists 3 | stat: path=/dev/vdb 4 | register: dev_vdb_stat 5 | 6 | - name: write docker-storage-setup config 7 | become: true 8 | become_user: root 9 | when: dev_vdb_stat.stat.exists 10 | template: 11 | src: docker-storage-setup.j2 12 | dest: /etc/sysconfig/docker-storage-setup 13 | notify: 14 | - reconfigure Docker LVM storage 15 | - restart docker daemon 16 | -------------------------------------------------------------------------------- /deploy/ansible/roles/docker_storage/templates/docker-storage-setup.j2: -------------------------------------------------------------------------------- 1 | DEVS="/dev/vdb" 2 | -------------------------------------------------------------------------------- /deploy/ansible/roles/docker_swarm_master/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # The Docker Hub repository tag used to install Docker Swarm. 3 | # 4 | # The "latest" tag points to the most recent stable release, which is generally 5 | # guaranteed to work with the current stable release of Docker. 6 | # 7 | # The valid tags are listed at https://hub.docker.com/r/library/swarm/tags/ 8 | # The supported tags are documented at https://hub.docker.com/r/library/swarm/ 9 | docker_swarm_tag: latest 10 | -------------------------------------------------------------------------------- /deploy/ansible/roles/docker_swarm_master/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart docker swarm master 3 | become: true 4 | become_user: root 5 | service: name=docker-swarm-master state=restarted 6 | -------------------------------------------------------------------------------- /deploy/ansible/roles/docker_swarm_worker/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # The Docker Hub repository tag used to install Docker Swarm. 3 | # 4 | # The "latest" tag points to the most recent stable release, which is generally 5 | # guaranteed to work with the current stable release of Docker. 6 | # 7 | # The valid tags are listed at https://hub.docker.com/r/library/swarm/tags/ 8 | # The supported tags are documented at https://hub.docker.com/r/library/swarm/ 9 | docker_swarm_tag: latest 10 | -------------------------------------------------------------------------------- /deploy/ansible/roles/docker_swarm_worker/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart docker swarm worker agent 3 | become: true 4 | become_user: root 5 | service: name=docker-swarm-worker state=restarted 6 | -------------------------------------------------------------------------------- /deploy/ansible/roles/etcd_client/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # The Ansible group that contains the etcd servers. 3 | etcd_group_name: "{{ prod_master_group_name }}" 4 | -------------------------------------------------------------------------------- /deploy/ansible/roles/etcd_client/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependencies: 3 | - role: docker_facts 4 | # NOTE: etcd_client also depends on docker_facts running for the masters. 5 | # Unfortunately, that cannot be expressed using Ansible dependencies. 6 | -------------------------------------------------------------------------------- /deploy/ansible/roles/etcd_client/tasks/etc_hosts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: add etcd entries to /etc/hosts 3 | become: true 4 | become_user: root 5 | lineinfile: 6 | dest: /etc/hosts 7 | line: "{{ 8 | hostvars[item.1][ 9 | 'ansible_' + hostvars[item.1]['docker_swarm_net_interface'] 10 | ].ipv4.address }} 11 | etcd-master{{ item.0 + 1 }}.clusterlocal" 12 | regexp: ".* etcd-master{{ item.0 + 1 }}.clusterlocal" 13 | with_indexed_items: "{{ groups[etcd_group_name] }}" 14 | -------------------------------------------------------------------------------- /deploy/ansible/roles/etcd_server/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart etcd server 3 | become: true 4 | become_user: root 5 | service: name=etcd state=restarted 6 | -------------------------------------------------------------------------------- /deploy/ansible/roles/gen_certs_cluster/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Used to identify and separate deployments. 3 | # 4 | # Other playbooks assume that this matches the os_prefix variable defined in 5 | # openstack_vars.yml, which is used to distinguish a deployment's hosts from 6 | # other OpenStack resources in the same project. 7 | os_prefix: igorprod 8 | 9 | # The number of Docker workers. 10 | # 11 | # Other playbooks assume that this matches the worker_count variable defined in 12 | # openstack_vars.yml. 13 | worker_count: 2 14 | 15 | # The directory that holds all the keys for the deployment. 16 | # 17 | # Other playbooks expect to find keys in the directory below. 18 | keys_dir: ../keys/{{ os_prefix }} 19 | -------------------------------------------------------------------------------- /deploy/ansible/roles/gen_certs_web/files/openssl.cnf: -------------------------------------------------------------------------------- 1 | [ca_extensions] 2 | basicConstraints = critical, CA:TRUE, pathlen:0 3 | keyUsage = critical, digitalSignature, keyCertSign, cRLSign 4 | subjectKeyIdentifier = hash 5 | authorityKeyIdentifier = keyid:always, issuer:always 6 | 7 | [web_server_extensions] 8 | basicConstraints = critical, CA:FALSE 9 | keyUsage = critical, digitalSignature, keyEncipherment 10 | extendedKeyUsage = critical, serverAuth 11 | subjectKeyIdentifier = hash 12 | authorityKeyIdentifier = keyid:always, issuer:always 13 | 14 | # The openssl req util complains if these sections aren't present. 15 | [req] 16 | distinguished_name = req_distinguished_name 17 | [req_distinguished_name] 18 | -------------------------------------------------------------------------------- /deploy/ansible/roles/gen_certs_web/templates/certbot.yml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | certbot: {{ "yes" if really_use_certbot else "no" }} 3 | domain: {{ app_certs_domain }} 4 | email: {{ app_certs_email }} 5 | -------------------------------------------------------------------------------- /deploy/ansible/roles/nginx/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart nginx daemon 3 | become: true 4 | become_user: root 5 | service: name=nginx state=restarted 6 | -------------------------------------------------------------------------------- /deploy/ansible/roles/nodejs_npm/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Installs the packages that make up a good build environment for npm packages. 3 | 4 | - name: install dnf packages used by npm packages 5 | when: ansible_pkg_mgr == 'dnf' 6 | become: true 7 | become_user: root 8 | dnf: name={{ item }} state=present 9 | with_items: 10 | - nodejs 11 | - npm 12 | 13 | - name: install apt packages used by npm packages 14 | when: ansible_pkg_mgr == 'apt' 15 | become: true 16 | become_user: root 17 | apt: name={{ item }} state=present 18 | with_items: 19 | - nodejs 20 | - npm 21 | -------------------------------------------------------------------------------- /deploy/ansible/roles/os_cluster/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: refresh the dynamic inventory cache 3 | command: ./inventory/openstack.py --refresh --list 4 | changed_when: false 5 | 6 | - meta: refresh_inventory 7 | -------------------------------------------------------------------------------- /deploy/ansible/roles/os_cluster/tasks/volumes_root.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Creates the storage volume holding the master VM's root filesystem. 3 | 4 | - name: create master root volume 5 | os_volume: 6 | display_name: "{{ master_volume_name }}" 7 | display_description: "Root filesystem for {{ master_instance_name }}" 8 | image: "{{ image_name }}" 9 | size: "{{ os_master_volume_gb }}" 10 | volume_type: "{{ os_volume_type }}" 11 | # NOTE: Copying the image into the volume tends to take a while. 12 | timeout: 3600 13 | cloud: "{{ os_cloud }}" 14 | -------------------------------------------------------------------------------- /deploy/ansible/roles/os_cluster/templates/known_hosts.j2: -------------------------------------------------------------------------------- 1 | * {{ master_public_key }} 2 | * {{ worker_public_key }} 3 | -------------------------------------------------------------------------------- /deploy/ansible/roles/os_cluster/templates/master_userdata.j2: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | user: {{ os_image_user }} 3 | password: {{ os_console_password }} 4 | chpasswd: 5 | list: | 6 | root:{{ os_console_password }} 7 | {{ os_image_user }}:{{ os_console_password }} 8 | expire: False 9 | ssh_pwauth: False 10 | ssh_authorized_keys: 11 | - {{ public_key }} 12 | ssh_keys: 13 | rsa_private: | 14 | {{ master_private_key | regex_replace('\n', '\n ') }} 15 | rsa_public: {{ master_public_key }} 16 | -------------------------------------------------------------------------------- /deploy/ansible/roles/os_cluster/templates/worker_userdata.j2: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | user: {{ os_image_user }} 3 | password: {{ os_console_password }} 4 | chpasswd: 5 | list: | 6 | root:{{ os_console_password }} 7 | {{ os_image_user }}:{{ os_console_password }} 8 | expire: False 9 | ssh_pwauth: False 10 | ssh_authorized_keys: 11 | - {{ public_key }} 12 | ssh_keys: 13 | rsa_private: | 14 | {{ worker_private_key | regex_replace('\n', '\n ') }} 15 | rsa_public: {{ worker_public_key }} 16 | -------------------------------------------------------------------------------- /deploy/ansible/roles/skydns_client/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # The Ansible group that contains the skydns servers. 3 | skydns_group_name: "{{ prod_master_group_name }}" 4 | -------------------------------------------------------------------------------- /deploy/ansible/roles/skydns_client/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: reload NetworkManager configuration 3 | become: true 4 | become_user: root 5 | command: nmcli connection reload 6 | 7 | - name: restart NetworkManager 8 | become: true 9 | become_user: root 10 | service: name=NetworkManager state=restarted 11 | -------------------------------------------------------------------------------- /deploy/ansible/roles/skydns_client/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependencies: 3 | - role: docker_facts 4 | -------------------------------------------------------------------------------- /deploy/ansible/roles/skydns_client/tasks/etc_hosts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: add skydns entries to /etc/hosts 3 | become: true 4 | become_user: root 5 | lineinfile: 6 | dest: /etc/hosts 7 | line: "{{ 8 | hostvars[item.1][ 9 | 'ansible_' + hostvars[item.1]['docker_swarm_net_interface'] 10 | ].ipv4.address }} 11 | skydns-server{{ item.0 + 1 }}.clusterlocal" 12 | regexp: ".* skydns-server{{ item.0 + 1 }}.clusterlocal" 13 | with_indexed_items: "{{ groups[skydns_group_name] }}" 14 | -------------------------------------------------------------------------------- /deploy/ansible/roles/skydns_client/templates/99-z-cancel-cloud-init.conf: -------------------------------------------------------------------------------- 1 | # cloud-init creates a 99-cloud-init.conf disabling /etc/resolv.conf management. 2 | # This brings it back, because our skydns configuration relies on it. 3 | 4 | # See https://bugs.launchpad.net/cloud-init/+bug/1693251 5 | # See https://developer.gnome.org/NetworkManager/stable/NetworkManager.conf.html 6 | 7 | [main] 8 | dns = default 9 | -------------------------------------------------------------------------------- /deploy/ansible/roles/skydns_name_master/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Computes the skydns name for a master. 3 | 4 | # NOTE: We currently only support only one master. This will change if we ever 5 | # get around to doing high availability. 6 | - name: computes the master's index 7 | set_fact: 8 | skydns_name: swarm-master1 9 | -------------------------------------------------------------------------------- /deploy/ansible/roles/skydns_name_worker/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Computes the skydns name for a worker. 3 | 4 | # NOTE: The computation is currently based on the worker's OpenStack host name, 5 | # with a fallback on the Ansible inventory name. At some point, we might 6 | # add OpenStack metadata as a primary source. 7 | - name: computes the worker's index 8 | set_fact: 9 | skydns_name: 'worker{{ 10 | (openstack | default({})).name | default(inventory_hostname) | 11 | regex_replace("^.*[^\d]([\d]*)$", "\1") }}' 12 | -------------------------------------------------------------------------------- /deploy/ansible/roles/skydns_server/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # The Ansible group that contains the etcd servers. 3 | etcd_group_name: "{{ prod_master_group_name }}" 4 | -------------------------------------------------------------------------------- /deploy/ansible/roles/skydns_server/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart skydns server 3 | become: true 4 | become_user: root 5 | service: name=skydns state=restarted 6 | -------------------------------------------------------------------------------- /deploy/ansible/roles/skydns_server/templates/etcdctl_peers.j2: -------------------------------------------------------------------------------- 1 | {%- set join_comma = joiner(",") -%} 2 | {%- for etcd_server in groups[etcd_group_name] -%} 3 | https://etcd-master{{ loop.index }}.clusterlocal:2379 4 | {{- join_comma() -}} 5 | {%- endfor -%} 6 | -------------------------------------------------------------------------------- /deploy/ansible/roles/skydns_server/templates/skydns.etcd.json.j2: -------------------------------------------------------------------------------- 1 | {"ttl": 3600, "systemd": true, "domain": "skydns.local.", "no_rec": true} 2 | -------------------------------------------------------------------------------- /deploy/ansible/roles/skydns_update_service/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # The Ansible group that contains the etcd servers. 3 | etcd_group_name: "{{ prod_master_group_name }}" 4 | -------------------------------------------------------------------------------- /deploy/ansible/roles/skydns_update_service/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: kick the skydns update service 3 | become: true 4 | become_user: root 5 | service: 6 | name: "skydns-update@{{ skydns_name }}" 7 | state: restarted 8 | 9 | -------------------------------------------------------------------------------- /deploy/ansible/roles/skydns_update_service/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependencies: 3 | - role: docker_facts 4 | -------------------------------------------------------------------------------- /deploy/ansible/roles/skydns_update_service/templates/skydns_update_sh.j2: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This script updates the node's IP address in the etcd store used by skydns. 4 | 5 | set -o errexit # Stop the script on the first error. 6 | set -o nounset # Catch un-initialized variables. 7 | set +o histexpand # No history expansion, because of arcane ! treatment. 8 | 9 | IP_ADDRESS="$(ifdata -pa {{ docker_swarm_net_interface }})" 10 | 11 | etcdctl --peers="$ETCD_PEERS" --output=extended --ca-file=/etc/etcd/ca.pem \ 12 | --cert-file=/etc/etcd/client_cert.pem --key-file=/etc/etcd/client_key.pem \ 13 | set /skydns/local/skydns/$DNS_NAME \ 14 | "{\"host\": \"$IP_ADDRESS\"}" 15 | -------------------------------------------------------------------------------- /deploy/ansible/roles/sudo_nopasswd/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: configure password-less sudo 3 | become: true 4 | become_user: root 5 | template: 6 | src: nopasswd.j2 7 | dest: /etc/sudoers.d/{{ ansible_ssh_user }}-nopasswd 8 | validate: visudo -cf %s 9 | -------------------------------------------------------------------------------- /deploy/ansible/roles/sudo_nopasswd/templates/nopasswd.j2: -------------------------------------------------------------------------------- 1 | {{ ansible_ssh_user }} ALL=(ALL:ALL) NOPASSWD: ALL 2 | -------------------------------------------------------------------------------- /deploy/ansible/roles/sys_facts/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # The interface used to connect to other computers in the cluster. 3 | # 4 | # This is generally eth0. Currently, only Vagrant VMs are special-cased. 5 | cluster_net_interface: "{{ 'eth1' if ansible_ssh_user == 'vagrant' 6 | else 'eth0' }}" 7 | -------------------------------------------------------------------------------- /deploy/ansible/roles/sys_facts/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependencies: [] 3 | -------------------------------------------------------------------------------- /deploy/ansible/roles/sys_facts/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Sets generally useful facts. 3 | 4 | # NOTE: This probably belongs in Ansible, but it will not get added there. 5 | # https://github.com/ansible/ansible/pull/12288 6 | - name: look for firewalld 7 | stat: path=/usr/bin/firewall-cmd 8 | register: firewall_cmd_stat 9 | - name: set has_firewalld fact 10 | set_fact: 11 | has_firewalld: "{{ firewall_cmd_stat.stat.exists }}" 12 | 13 | - name: set root_fs_type fact 14 | set_fact: 15 | root_fs_type: "{{ 16 | (ansible_mounts | selectattr('mount', 'equalto', '/') | first).fstype 17 | }}" 18 | -------------------------------------------------------------------------------- /deploy/ansible/roles/sys_package_update/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | sys_package_update: true 3 | -------------------------------------------------------------------------------- /deploy/ansible/roles/web_certs/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: reload systemd configuration 3 | command: systemctl daemon-reload 4 | become: true 5 | become_user: root 6 | 7 | - name: restart nginx daemon 8 | become: true 9 | become_user: root 10 | service: name=nginx state=restarted 11 | 12 | - name: kick the certbot update service 13 | become: true 14 | become_user: root 15 | service: 16 | name: certbot 17 | state: restarted 18 | -------------------------------------------------------------------------------- /deploy/ansible/roles/web_certs/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependencies: 3 | - role: nodejs_npm 4 | - role: sys_facts 5 | -------------------------------------------------------------------------------- /deploy/ansible/roles/web_certs/tasks/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: load certbot configuration 3 | set_fact: 4 | certbot_config: "{{ lookup('file', '../keys/{{ os_prefix }}/certbot.yml') | 5 | from_yaml }}" 6 | 7 | - name: compute certbot bootstrap parameters 8 | set_fact: 9 | app_certs_domain: "{{ certbot_config.domain }}" 10 | app_certs_email: "{{ certbot_config.email }}" 11 | app_certs_live_dir: "{{ app_certs_config_dir }}/live/{{ 12 | certbot_config.domain }}" 13 | -------------------------------------------------------------------------------- /deploy/ansible/roles/web_certs/tasks/deps.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: install certbot with dnf 3 | when: ansible_pkg_mgr == 'dnf' 4 | become: true 5 | become_user: root 6 | dnf: name=certbot state=present 7 | 8 | - name: install certbot with apt 9 | when: ansible_pkg_mgr == 'apt' 10 | become: true 11 | become_user: root 12 | apt: name=certbot state=present 13 | 14 | - name: install http-server npm package used to bootstrap certbot 15 | become: true 16 | become_user: "{{ app_user }}" 17 | npm: 18 | name: http-server 19 | path: "/home/{{ app_user }}/{{ app_certs_dir }}" 20 | production: yes 21 | state: present 22 | -------------------------------------------------------------------------------- /deploy/ansible/roles/web_certs/tasks/files.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: create certbot non-confidential directories 3 | become: true 4 | become_user: "{{ app_user }}" 5 | file: path=/home/{{ app_user }}/{{ item }} state=directory mode=0755 6 | with_items: 7 | - "{{ app_certs_dir }}" 8 | - "{{ app_certs_www_dir }}" 9 | 10 | - name: create certbot confidential directories 11 | become: true 12 | become_user: "{{ app_user }}" 13 | file: path=/home/{{ app_user }}/{{ item }} state=directory mode=0750 14 | with_items: 15 | - "{{ app_certs_config_dir }}" 16 | - "{{ app_certs_logs_dir }}" 17 | - "{{ app_certs_work_dir }}" 18 | -------------------------------------------------------------------------------- /deploy/ansible/roles/web_certs/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - include: config.yml 3 | - include: files.yml 4 | - include: deps.yml 5 | - include: systemd.yml 6 | - include: bootstrap.yml 7 | - include: surrogate.yml 8 | 9 | - name: enable and start systemd units for certificate update timer 10 | become: true 11 | become_user: root 12 | service: name={{ app_certbot_service }}.timer enabled=yes state=started 13 | -------------------------------------------------------------------------------- /deploy/ansible/roles/web_certs/templates/certbot.timer.j2: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Renew certificates for {{ app_name }} every day 3 | 4 | [Timer] 5 | OnCalendar=daily 6 | RandomizedDelaySec=1day 7 | Persistent=true 8 | -------------------------------------------------------------------------------- /deploy/ansible/roles/web_db/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: create the igor_web postgresql role 3 | become: true 4 | become_user: postgres 5 | postgresql_user: 6 | name: igor_web 7 | role_attr_flags: CREATEDB,NOSUPERUSER 8 | state: present 9 | 10 | - name: create the igor_web user database 11 | become: true 12 | become_user: igor_web 13 | postgresql_db: name=igor_web login_user=igor_web state=present 14 | 15 | - name: create the igor database 16 | become: true 17 | become_user: igor_web 18 | postgresql_db: 19 | name: igor_production 20 | login_user: igor_web 21 | state: present 22 | lc_collate: en_US.UTF-8 23 | lc_ctype: en_US.UTF-8 24 | -------------------------------------------------------------------------------- /deploy/ansible/roles/web_frontend/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart nginx daemon 3 | become: true 4 | become_user: root 5 | service: name=nginx state=restarted 6 | 7 | - name: reload systemd configuration 8 | command: systemctl daemon-reload 9 | become: true 10 | become_user: root 11 | 12 | - name: restart frontend main service 13 | become: true 14 | become_user: root 15 | service: name={{ app_main_service }} state=restarted 16 | 17 | - name: restart frontend job queue service 18 | become: true 19 | become_user: root 20 | service: name={{ app_queue_service }} state=restarted 21 | -------------------------------------------------------------------------------- /deploy/ansible/roles/web_frontend/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependencies: 3 | - role: ruby_bundler 4 | - role: nodejs_npm 5 | -------------------------------------------------------------------------------- /deploy/ansible/roles/web_frontend_motd/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependencies: 3 | - role: web_frontend 4 | -------------------------------------------------------------------------------- /deploy/ansible/roles/web_frontend_motd/templates/motd-tail.sh.j2: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # If /etc/motd.tail exists, adds its contents to motd. 4 | 5 | [ -r /etc/motd.tail ] && cat /etc/motd.tail 6 | -------------------------------------------------------------------------------- /deploy/ansible/roles/web_user/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: create the igor_web user 3 | become: true 4 | become_user: root 5 | user: 6 | name: igor_web 7 | createhome: yes 8 | state: present 9 | -------------------------------------------------------------------------------- /deploy/ansible/web_update.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This playbook only deploys new code in Igor's Web tier. It is significantly 3 | # faster than prod.yml, but is exposed to the risks of version skew and 4 | # configuration drift. 5 | - hosts: "{{ prod_master_group_name }}" 6 | vars_files: 7 | - ../openstack_vars.yml 8 | vars: 9 | ansible_ssh_user: "{{ os_image_user }}" 10 | roles: 11 | - sys_facts 12 | - web_certs 13 | - nginx 14 | - pgsql 15 | - web_user 16 | - web_db 17 | - ruby_bundler 18 | - nodejs_npm 19 | - web_certs 20 | - web_frontend 21 | -------------------------------------------------------------------------------- /doc/docker_benchmark.md: -------------------------------------------------------------------------------- 1 | # Benchmarking Docker Overheads 2 | 3 | To measure the time overhead of managing Docker containers when analyzing 4 | student homework submissions, we can generate analyses for code submissions with 5 | negligible run times, such that most of the processing time can be attributed to 6 | creating/destroying Docker containers. 7 | 8 | ## Usage 9 | 10 | To run the benchmark against `JOBS` x 10 Docker containers: 11 | 12 | ```bash 13 | rake db:migrate:reset docker:bm JOBS=3 14 | ``` 15 | 16 | The `docker:bm` task consists of the `docker:build_db` task, followed by the 17 | `docker:benchmark` task. 18 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:2.7 2 | 3 | RUN mkdir -p /usr/testhost && chmod 700 /usr/testhost && \ 4 | mkdir /usr/testguest && chmod 777 /usr/testguest 5 | 6 | COPY . /usr/testhost/ 7 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/1.in: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/1.out: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/10.in: -------------------------------------------------------------------------------- 1 | 25 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/10.out: -------------------------------------------------------------------------------- 1 | 75025 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/11.in: -------------------------------------------------------------------------------- 1 | 30 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/11.out: -------------------------------------------------------------------------------- 1 | 832040 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/12.in: -------------------------------------------------------------------------------- 1 | 100 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/12.out: -------------------------------------------------------------------------------- 1 | 354224848179261915075 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/13.in: -------------------------------------------------------------------------------- 1 | 1000 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/13.out: -------------------------------------------------------------------------------- 1 | 43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/14.in: -------------------------------------------------------------------------------- 1 | 0 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/14.out: -------------------------------------------------------------------------------- 1 | 0 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/2.in: -------------------------------------------------------------------------------- 1 | 2 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/2.out: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/3.in: -------------------------------------------------------------------------------- 1 | 3 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/3.out: -------------------------------------------------------------------------------- 1 | 2 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/4.in: -------------------------------------------------------------------------------- 1 | 4 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/4.out: -------------------------------------------------------------------------------- 1 | 3 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/5.in: -------------------------------------------------------------------------------- 1 | 5 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/5.out: -------------------------------------------------------------------------------- 1 | 5 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/6.in: -------------------------------------------------------------------------------- 1 | 6 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/6.out: -------------------------------------------------------------------------------- 1 | 8 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/7.in: -------------------------------------------------------------------------------- 1 | 12 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/7.out: -------------------------------------------------------------------------------- 1 | 144 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/8.in: -------------------------------------------------------------------------------- 1 | 16 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/8.out: -------------------------------------------------------------------------------- 1 | 987 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/9.in: -------------------------------------------------------------------------------- 1 | 20 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/cases/9.out: -------------------------------------------------------------------------------- 1 | 6765 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib/mapper.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | os.rename('/usr/testhost/cases/' + os.environ['ITEM'] + '.in', './input') 5 | os.environ['ITEM'] = '0' 6 | os.environ['ITEMS'] = '0' 7 | os.chmod('./input', 0o777) 8 | os.chmod('./code.py', 0o777) 9 | os.setgid(65534) 10 | os.setuid(65534) 11 | sys.path.insert(0, os.getcwd()) 12 | 13 | 14 | # DO NOT MOVE THE IMPORT STATEMENT TO THE TOP OF THE FILE! 15 | from code import Fib 16 | 17 | with open('input', 'r') as f: 18 | n = int(f.readline()) 19 | result = Fib.fib(n) 20 | with open('output', 'w') as f: 21 | f.write(str(result) + "\n") 22 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib_small/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:2.7 2 | 3 | RUN mkdir -p /usr/testhost && chmod 700 /usr/testhost && \ 4 | mkdir /usr/testguest && chmod 777 /usr/testguest 5 | 6 | COPY . /usr/testhost/ 7 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib_small/cases/1.in: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib_small/cases/1.out: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib_small/cases/2.in: -------------------------------------------------------------------------------- 1 | 6 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib_small/cases/2.out: -------------------------------------------------------------------------------- 1 | 8 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib_small/cases/3.in: -------------------------------------------------------------------------------- 1 | 100 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib_small/cases/3.out: -------------------------------------------------------------------------------- 1 | 354224848179261915075 2 | -------------------------------------------------------------------------------- /lib/analyzer_sources/fib_small/mapper.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | os.rename('/usr/testhost/cases/' + os.environ['ITEM'] + '.in', './input') 5 | os.environ['ITEM'] = '0' 6 | os.environ['ITEMS'] = '0' 7 | os.chmod('./input', 0o777) 8 | os.chmod('./code.py', 0o777) 9 | os.setgid(65534) 10 | os.setuid(65534) 11 | sys.path.insert(0, os.getcwd()) 12 | 13 | 14 | # DO NOT MOVE THE IMPORT STATEMENT TO THE TOP OF THE FILE! 15 | from code import Fib 16 | 17 | with open('input', 'r') as f: 18 | n = int(f.readline()) 19 | result = Fib.fib(n) 20 | with open('output', 'w') as f: 21 | f.write(str(result) + "\n") 22 | -------------------------------------------------------------------------------- /lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/lib/assets/.keep -------------------------------------------------------------------------------- /lib/tasks/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/lib/tasks/.gitkeep -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/lib/tasks/.keep -------------------------------------------------------------------------------- /log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/log/.keep -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "igor-node-deps", 3 | "requires": true, 4 | "lockfileVersion": 1, 5 | "dependencies": { 6 | "bower": { 7 | "version": "https://registry.npmjs.org/bower/-/bower-1.7.9.tgz", 8 | "integrity": "sha1-tylsI5Pg117apso5ZIEy3SVYErA=" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "igor-node-deps", 3 | "description": "node.js dependencies for Igor", 4 | "private": true, 5 | "license": "MIT", 6 | "engines": { 7 | "node": ">= 4.0" 8 | }, 9 | "dependencies": { 10 | "bower": ">= 1.7.9" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /public/_static_images/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/public/_static_images/404.png -------------------------------------------------------------------------------- /public/_static_images/500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/public/_static_images/500.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /test/controllers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/test/controllers/.keep -------------------------------------------------------------------------------- /test/controllers/analyzers_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class AnalyzersControllerTest < ActionController::TestCase 4 | fixtures :users 5 | 6 | before do 7 | @user = users(:admin) 8 | set_session_current_user users(:admin) 9 | end 10 | 11 | it "must not crash on /analyzers/help" do 12 | get :help, params: { course_id: courses(:main).to_param } 13 | assert_response :success, response.body 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /test/controllers/api_docs_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ApiDocsControllerTest < ActionController::TestCase 4 | fixtures :users 5 | 6 | before do 7 | @user = users(:deedee) 8 | set_session_current_user users(:deedee) 9 | end 10 | 11 | it "must not crash on /api_docs" do 12 | get :index 13 | assert_response :success, response.body 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /test/fixtures/collaborations.yml: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: collaborations 4 | # 5 | # id :integer not null, primary key 6 | # submission_id :integer not null 7 | # collaborator_id :integer not null 8 | # 9 | 10 | # NOTE: Do not create a collaboration for the following: 11 | # { submission: dexter_assessment, collaborator: solo } 12 | 13 | deedee_on_dexter_assessment: 14 | submission: dexter_assessment 15 | collaborator: deedee 16 | 17 | deedee_on_dexter_assessment_v2: 18 | submission: dexter_assessment_v2 19 | collaborator: deedee 20 | -------------------------------------------------------------------------------- /test/fixtures/exams.yml: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: exams 4 | # 5 | # id :integer not null, primary key 6 | # assignment_id :integer not null 7 | # requires_confirmation :boolean not null 8 | # 9 | 10 | # NOTE: Do not create exams for the following: 11 | # { assignment: main_exam_2 } 12 | 13 | main_exam: 14 | assignment: main_exam 15 | requires_confirmation: true # do not change 16 | 17 | main_exam_3: 18 | assignment: main_exam_3 19 | requires_confirmation: false 20 | 21 | not_main_exam: 22 | assignment: not_main_exam 23 | requires_confirmation: false 24 | -------------------------------------------------------------------------------- /test/fixtures/file_blobs.yml: -------------------------------------------------------------------------------- 1 | small_pdf: 2 | id: <%= file_blob_id 'files/submission/small.pdf' %> 3 | data: <%= file_blob_data 'files/submission/small.pdf' %> 4 | 5 | truncated_pdf: 6 | id: <%= file_blob_id 'files/submission/truncated.pdf' %> 7 | data: <%= file_blob_data 'files/submission/truncated.pdf' %> 8 | 9 | good_fib_py: 10 | id: <%= file_blob_id 'files/submission/good_fib.py' %> 11 | data: <%= file_blob_data 'files/submission/good_fib.py' %> 12 | 13 | fib_small_zip: 14 | id: <%= file_blob_id 'files/analyzer/fib_small.zip' %> 15 | data: <%= file_blob_data 'files/analyzer/fib_small.zip' %> 16 | -------------------------------------------------------------------------------- /test/fixtures/files/analyzer/fib.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/test/fixtures/files/analyzer/fib.zip -------------------------------------------------------------------------------- /test/fixtures/files/analyzer/fib_bench.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/test/fixtures/files/analyzer/fib_bench.zip -------------------------------------------------------------------------------- /test/fixtures/files/analyzer/fib_small.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/test/fixtures/files/analyzer/fib_small.zip -------------------------------------------------------------------------------- /test/fixtures/files/pics/costan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/test/fixtures/files/pics/costan.png -------------------------------------------------------------------------------- /test/fixtures/files/pics/costan_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/test/fixtures/files/pics/costan_profile.png -------------------------------------------------------------------------------- /test/fixtures/files/pics/costan_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/test/fixtures/files/pics/costan_thumb.png -------------------------------------------------------------------------------- /test/fixtures/files/submission/deadlock_fib.py: -------------------------------------------------------------------------------- 1 | import Queue 2 | 3 | class Fib(object): 4 | @staticmethod 5 | def fib(n): 6 | q = Queue.PriorityQueue() 7 | q.get() 8 | -------------------------------------------------------------------------------- /test/fixtures/files/submission/good_fib.py: -------------------------------------------------------------------------------- 1 | class Fib(object): 2 | values = {0: 0, 1: 1} 3 | 4 | @staticmethod 5 | def fib(n): 6 | if n not in Fib.values: 7 | Fib.values[n] = Fib.fib(n - 1) + Fib.fib(n - 2) 8 | return Fib.values[n] 9 | -------------------------------------------------------------------------------- /test/fixtures/files/submission/slow_fib.py: -------------------------------------------------------------------------------- 1 | class Fib(object): 2 | @staticmethod 3 | def fib(n): 4 | if n <= 1: 5 | return n 6 | return Fib.fib(n - 1) + Fib.fib(n - 2) 7 | -------------------------------------------------------------------------------- /test/fixtures/files/submission/small.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/test/fixtures/files/submission/small.pdf -------------------------------------------------------------------------------- /test/fixtures/photo_blobs.yml: -------------------------------------------------------------------------------- 1 | dexter: 2 | profile_photo_id: <%= ActiveRecord::FixtureSet.identify(:dexter) %> 3 | style: original 4 | file_contents: <%= binary_file('files/pics/costan.png') %> 5 | 6 | dexter: 7 | profile_photo_id: <%= ActiveRecord::FixtureSet.identify(:dexter) %> 8 | style: thumb 9 | file_contents: <%= binary_file('files/pics/costan_thumb.png') %> 10 | 11 | dexter: 12 | profile_photo_id: <%= ActiveRecord::FixtureSet.identify(:dexter) %> 13 | style: profile 14 | file_contents: <%= binary_file('files/pics/costan_profile.png') %> 15 | -------------------------------------------------------------------------------- /test/fixtures/profile_photos.yml: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: profile_photos 4 | # 5 | # id :integer not null, primary key 6 | # profile_id :integer not null 7 | # created_at :datetime not null 8 | # updated_at :datetime not null 9 | # pic_file_name :string 10 | # pic_content_type :string 11 | # pic_file_size :integer 12 | # pic_updated_at :datetime 13 | # 14 | -------------------------------------------------------------------------------- /test/fixtures/recitation_partitions.yml: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: recitation_partitions 4 | # 5 | # id :integer not null, primary key 6 | # course_id :integer not null 7 | # section_size :integer not null 8 | # section_count :integer not null 9 | # created_at :datetime 10 | # 11 | 12 | main: 13 | course: main 14 | section_size: 20 15 | section_count: 2 16 | -------------------------------------------------------------------------------- /test/fixtures/role_requests.yml: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: role_requests 4 | # 5 | # id :integer not null, primary key 6 | # user_id :integer not null 7 | # name :string(8) not null 8 | # course_id :integer 9 | # created_at :datetime not null 10 | # updated_at :datetime not null 11 | # 12 | 13 | solo_wants_to_admin: 14 | user: solo 15 | name: admin 16 | 17 | dexter_wants_to_grade: 18 | user: dexter 19 | name: grader 20 | course: main 21 | -------------------------------------------------------------------------------- /test/fixtures/survey_answers.yml: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: survey_answers 4 | # 5 | # id :integer not null, primary key 6 | # question_id :integer not null 7 | # response_id :integer not null 8 | # number :decimal(7, 2) 9 | # comment :string(1024) 10 | # created_at :datetime not null 11 | # updated_at :datetime not null 12 | # 13 | 14 | dexter_coding_amount: 15 | question: coding_amount 16 | response: dexter_ps1 17 | number: 3 18 | comment: Much code 19 | 20 | dexter_prepared: 21 | question: prepared 22 | response: dexter_project 23 | number: 0 24 | comment: Very prepared 25 | -------------------------------------------------------------------------------- /test/fixtures/teams.yml: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: teams 4 | # 5 | # id :integer not null, primary key 6 | # partition_id :integer not null 7 | # name :string(64) not null 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # 11 | 12 | awesome_pset: 13 | partition: psets 14 | name: "Team Awesome" 15 | 16 | boo_pset: 17 | partition: psets 18 | name: "Team Boo" 19 | 20 | awesome_project: 21 | partition: project 22 | name: "Team Awesome" 23 | 24 | boo_project: 25 | partition: project 26 | name: "Team Boo" 27 | 28 | not_main_lab: 29 | partition: labs 30 | name: "Team Not Main" 31 | -------------------------------------------------------------------------------- /test/fixtures/time_slot_allotments.yml: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: time_slot_allotments 4 | # 5 | # id :integer not null, primary key 6 | # time_slot_id :integer not null 7 | # recitation_section_id :integer not null 8 | # 9 | 10 | r01_m14to15: 11 | time_slot: m14to15 12 | recitation_section: r01 13 | -------------------------------------------------------------------------------- /test/functional/courses_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class CoursesControllerTest < ActionController::TestCase 4 | #test "user should not get index" do 5 | # get :index 6 | # assert_response :redirect 7 | #end 8 | 9 | #test "admin should get index" do 10 | # session[:user_id] = users(:admin).id 11 | # get :index 12 | # assert_response :success 13 | # assert_not_nil assigns(:courses) 14 | #end 15 | end 16 | -------------------------------------------------------------------------------- /test/helpers/application_helper_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ApplicationHelperTest < ActionView::TestCase 4 | include ApplicationHelper 5 | 6 | describe '#main_section_width_class' do 7 | before { @view_flow = ActionView::OutputFlow.new } 8 | 9 | it 'returns a 7-column style when the template has a sidebar' do 10 | content_for :sidebar, 'sidebar' 11 | assert_equal 'small-7', main_section_width_class 12 | end 13 | 14 | it 'returns a 10-column style when the template has no sidebar' do 15 | assert_nil content_for(:sidebar) 16 | assert_equal 'small-10', main_section_width_class 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /test/helpers/surveys_helper_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class SurveyResponsesHelperTest < ActionView::TestCase 4 | include SurveysHelper 5 | 6 | describe '#survey_release_text' do 7 | it "returns 'Pull release' if the survey is released" do 8 | survey = surveys(:ps1) 9 | assert_equal true, survey.released? 10 | assert_equal 'Pull release', survey_release_text(survey) 11 | end 12 | 13 | it "returns 'Release' if the survey is not released" do 14 | survey = surveys(:project) 15 | assert_equal false, survey.released? 16 | assert_equal 'Release', survey_release_text(survey) 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /test/integration/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/test/integration/.keep -------------------------------------------------------------------------------- /test/jobs/submission_analysis_job_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class SubmissionAnalysisJobTest < ActiveJob::TestCase 4 | before { submission.update! analysis: nil } 5 | 6 | let(:submission) { submissions(:dexter_ps1) } 7 | 8 | describe '.perform_later' do 9 | it 'sets the analysis status of queued submissions to :queued' do 10 | SubmissionAnalysisJob.perform_later submission 11 | assert_equal :queued, submission.analysis.reload.status 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /test/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/test/mailers/.keep -------------------------------------------------------------------------------- /test/mailers/previews/session_mailer_preview.rb: -------------------------------------------------------------------------------- 1 | # Preview all emails at http://localhost:3000/rails/mailers/session_mailer 2 | class SessionMailerPreview < ActionMailer::Preview 3 | def email_verification 4 | user = User.last 5 | SessionMailer.email_verification_email( 6 | Tokens::EmailVerification.random_for(user.email_credential), 7 | 'http://test.host/') 8 | end 9 | 10 | def reset_password 11 | user = User.last 12 | SessionMailer.reset_password_email user.email, 13 | Tokens::PasswordReset.random_for(user), 14 | 'http://test.host/' 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /test/models/file_blob_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class FileBlobTest < ActiveSupport::TestCase 4 | test 'blob_owner_classes all use has_file_blob' do 5 | FileBlob.blob_owner_classes.each do |klass| 6 | assert klass.respond_to?(:file_blob_eligible_for_garbage_collection?), klass.name 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test/support/user_session.rb: -------------------------------------------------------------------------------- 1 | class ActionDispatch::IntegrationTest 2 | 3 | end 4 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV["RAILS_ENV"] ||= "test" 2 | require File.expand_path('../../config/environment', __FILE__) 3 | require 'rails/test_help' 4 | require 'mocha/mini_test' 5 | 6 | class ActiveSupport::TestCase 7 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. 8 | fixtures :all 9 | 10 | # Add more helper methods to be used by all tests here... 11 | end 12 | 13 | # The 'test/support/' directory contains helper methods for writing tests. 14 | Dir[Rails.root.join('test', 'support', '*.rb')].each { |file| require file } 15 | -------------------------------------------------------------------------------- /vendor/assets/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /vendor/assets/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dsl-generated-dependencies", 3 | "dependencies": { 4 | "clipboard": "1.5.12", 5 | "es6-promise": "3.2.2", 6 | "fetch": "0.11.1", 7 | "motion-ui": "1.2.2" 8 | }, 9 | "resolutions": { 10 | "jquery": "2.2.4" 11 | } 12 | } -------------------------------------------------------------------------------- /vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/vendor/assets/javascripts/.keep -------------------------------------------------------------------------------- /vendor/assets/javascripts/es6-promise-install.js: -------------------------------------------------------------------------------- 1 | ES6Promise.polyfill(); 2 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwnall/igor/623611d007591c8051bab29c8379cc0ca21ef498/vendor/assets/stylesheets/.keep --------------------------------------------------------------------------------